From 58912f68c2489bcee787599837447e0d64dfd61a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Wed, 24 May 2017 21:03:56 +0200 Subject: New upstream version 1.0.27 --- backend/Makefile.am | 78 +- backend/Makefile.in | 172 +-- backend/agfafocus.c | 4 +- backend/apple.c | 4 +- backend/artec.c | 9 +- backend/artec_eplus48u.c | 18 +- backend/as6e.c | 4 +- backend/avision.c | 44 +- backend/avision.h | 1 + backend/bh.h | 2 +- backend/canon-sane.c | 19 +- backend/canon-scsi.c | 4 +- backend/canon.h | 6 - backend/canon630u-common.c | 10 +- backend/canon630u.c | 3 +- backend/canon_dr.c | 1655 +++++++--------------------- backend/canon_dr.conf.in | 5 + backend/canon_dr.h | 58 +- backend/cardscan.c | 24 +- backend/cardscan.conf.in | 3 + backend/coolscan.c | 24 +- backend/coolscan2.c | 3 +- backend/coolscan3.c | 18 +- backend/dc210.c | 3 - backend/dc240.c | 21 +- backend/dc240.h | 6 - backend/dc25.c | 18 +- backend/dc25.h | 6 - backend/dell1600n_net.c | 17 +- backend/dll.c | 30 +- backend/dll.conf.in | 10 +- backend/dmc.c | 3 +- backend/epjitsu-cmd.h | 70 +- backend/epjitsu.c | 324 ++++-- backend/epjitsu.conf.in | 15 +- backend/epjitsu.h | 16 +- backend/epson.c | 9 +- backend/epson2-io.c | 48 +- backend/epson2-ops.c | 17 - backend/epson2.h | 7 - backend/epson2_net.c | 4 +- backend/epson2_scsi.c | 2 +- backend/epsonds-cmd.c | 53 +- backend/epsonds-io.c | 35 +- backend/epsonds-io.h | 2 +- backend/epsonds-jpeg.c | 6 +- backend/epsonds-jpeg.h | 2 - backend/epsonds-net.c | 278 +++++ backend/epsonds-net.h | 16 + backend/epsonds-ops.c | 23 +- backend/epsonds-ops.h | 4 +- backend/epsonds.c | 178 +++- backend/epsonds.conf.in | 4 + backend/epsonds.h | 13 +- backend/fujitsu-scsi.h | 55 +- backend/fujitsu.c | 629 ++++++----- backend/fujitsu.conf.in | 110 +- backend/fujitsu.h | 10 +- backend/genesys.c | 104 +- backend/genesys.conf.in | 2 +- backend/genesys_conv.c | 30 +- backend/genesys_devices.c | 2428 +++++++++++++++++++++--------------------- backend/genesys_gl124.c | 460 +++++--- backend/genesys_gl124.h | 284 ++--- backend/genesys_gl646.c | 29 +- backend/genesys_gl646.h | 10 +- backend/genesys_gl841.c | 125 +-- backend/genesys_gl841.h | 2 +- backend/genesys_gl843.c | 127 +-- backend/genesys_gl843.h | 6 +- backend/genesys_gl846.c | 115 +- backend/genesys_gl846.h | 2 +- backend/genesys_gl847.c | 151 ++- backend/genesys_gl847.h | 2 +- backend/genesys_low.c | 68 +- backend/genesys_low.h | 17 +- backend/gphoto2.c | 38 +- backend/gphoto2.h | 6 - backend/gt68xx.c | 2 +- backend/gt68xx_low.h | 5 +- backend/hp-accessor.c | 8 +- backend/hp-device.c | 2 - backend/hp-handle.c | 2 +- backend/hp-option.c | 94 +- backend/hp-scl.c | 10 +- backend/hp.c | 6 +- backend/hp.h | 6 - backend/hp3500.c | 836 +++++++++++---- backend/hp3900_sane.c | 2 +- backend/hp4200.c | 9 +- backend/hp5400.c | 3 + backend/hp5400_internal.c | 4 +- backend/hp5590.c | 59 +- backend/hp5590_cmds.c | 86 +- backend/hp5590_low.c | 106 +- backend/hpsj5s.c | 2 - backend/hs2p-saneopts.h | 2 +- backend/hs2p-scsi.c | 2 +- backend/kodak.c | 11 +- backend/kodakaio.c | 56 +- backend/kodakaio.h | 6 - backend/kvs1025.conf.in | 2 + backend/kvs20xx.c | 9 +- backend/kvs20xx.h | 6 + backend/kvs20xx_cmd.c | 27 +- backend/kvs20xx_cmd.h | 4 + backend/kvs20xx_opt.c | 1 + backend/kvs40xx.h | 15 + backend/kvs40xx_cmd.c | 26 +- backend/kvs40xx_opt.c | 53 +- backend/lexmark_low.c | 3 + backend/ma1509.c | 3 - backend/magicolor.c | 11 +- backend/magicolor.h | 7 - backend/microtek2.c | 40 +- backend/microtek2.h | 2 +- backend/mustek.c | 16 +- backend/mustek_pp.c | 2 +- backend/mustek_pp_cis.c | 4 +- backend/mustek_usb.c | 2 +- backend/mustek_usb2.c | 11 - backend/mustek_usb2_asic.c | 20 +- backend/mustek_usb2_high.c | 2 - backend/nec.c | 3 +- backend/net.c | 6 +- backend/niash.c | 2 +- backend/niash_core.c | 7 +- backend/p5_device.c | 24 +- backend/pie.c | 6 +- backend/pieusb.c | 89 +- backend/pieusb.conf.in | 19 +- backend/pieusb.h | 1 + backend/pieusb_buffer.c | 11 +- backend/pieusb_scancmd.c | 120 +-- backend/pieusb_scancmd.h | 2 +- backend/pieusb_specific.c | 48 +- backend/pieusb_specific.h | 11 +- backend/pixma.c | 31 +- backend/pixma.conf.in | 15 +- backend/pixma.h | 12 +- backend/pixma_bjnp.c | 183 +++- backend/pixma_bjnp.h | 7 +- backend/pixma_bjnp_private.h | 4 +- backend/pixma_common.c | 18 +- backend/pixma_common.h | 3 +- backend/pixma_imageclass.c | 170 ++- backend/pixma_io.h | 4 +- backend/pixma_io_sanei.c | 2 +- backend/pixma_mp150.c | 46 +- backend/pixma_mp730.c | 56 +- backend/pixma_mp750.c | 2 +- backend/pixma_mp810.c | 9 +- backend/pixma_sane_options.c | 17 + backend/pixma_sane_options.h | 1 + backend/plustek.c | 10 +- backend/plustek_pp.c | 8 +- backend/pnm.c | 2 +- backend/rts8891.c | 12 +- backend/rts88xx_lib.c | 4 +- backend/sharp.c | 7 +- backend/sm3600.c | 9 +- backend/sm3840.c | 0 backend/sm3840.h | 0 backend/sm3840_lib.c | 32 +- backend/sm3840_lib.h | 0 backend/sm3840_scan.c | 70 +- backend/snapscan-mutex.c | 4 +- backend/snapscan-sources.c | 24 +- backend/snapscan.c | 20 +- backend/sp15c.c | 2 +- backend/stv680.conf.in | 0 backend/stv680.h | 0 backend/tamarack.c | 4 +- backend/test.c | 6 +- backend/u12-hw.c | 2 - backend/u12.c | 10 +- backend/umax.c | 14 +- backend/umax1220u.c | 3 +- backend/umax_pp.c | 8 +- backend/umax_pp.h | 9 +- backend/umax_pp_low.c | 123 +-- backend/v4l.c | 18 +- backend/xerox_mfp-tcp.c | 132 +-- backend/xerox_mfp-usb.c | 126 +-- backend/xerox_mfp.c | 2236 ++++++++++++++++++++------------------ backend/xerox_mfp.conf.in | 36 + backend/xerox_mfp.h | 215 ++-- 187 files changed, 7408 insertions(+), 6470 deletions(-) create mode 100644 backend/epsonds-net.c create mode 100644 backend/epsonds-net.h create mode 100644 backend/kvs1025.conf.in mode change 100755 => 100644 backend/sm3840.c mode change 100755 => 100644 backend/sm3840.h mode change 100755 => 100644 backend/sm3840_lib.c mode change 100755 => 100644 backend/sm3840_lib.h mode change 100755 => 100644 backend/sm3840_scan.c mode change 100755 => 100644 backend/stv680.conf.in mode change 100755 => 100644 backend/stv680.h (limited to 'backend') diff --git a/backend/Makefile.am b/backend/Makefile.am index b672490..f7fb403 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -4,33 +4,9 @@ ## This file is part of the "Sane" build infra-structure. See ## included LICENSE file for license information. -INSTALL_LOCKPATH = @INSTALL_LOCKPATH@ -LOCKPATH_GROUP = @LOCKPATH_GROUP@ - -BACKEND_LIBS_ENABLED=@BACKEND_LIBS_ENABLED@ -BACKEND_CONFS_ENABLED=@BACKEND_CONFS_ENABLED@ - -DL_LIBS = @DL_LIBS@ -LIBV4L_LIBS = @LIBV4L_LIBS@ -MATH_LIB = @MATH_LIB@ -IEEE1284_LIBS = @IEEE1284_LIBS@ -TIFF_LIBS = @TIFF_LIBS@ -JPEG_LIBS = @JPEG_LIBS@ -GPHOTO2_LIBS = @GPHOTO2_LIBS@ -GPHOTO2_LDFLAGS = @GPHOTO2_LDFLAGS@ -SOCKET_LIBS = @SOCKET_LIBS@ -AVAHI_LIBS = @AVAHI_LIBS@ -USB_LIBS = @USB_LIBS@ -SCSI_LIBS = @SCSI_LIBS@ -PTHREAD_LIBS = @PTHREAD_LIBS@ - -AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include -DLIBDIR="\"$(libdir)/sane\"" - -V_MAJOR = @V_MAJOR@ -V_MINOR = @V_MINOR@ -V_REV = @V_REV@ - -AM_LDFLAGS = @STRICT_LDFLAGS@ +AM_CPPFLAGS += -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include $(USB_CFLAGS) -DLIBDIR="\"$(libdir)/sane\"" + +AM_LDFLAGS += $(STRICT_LDFLAGS) # The -rpath option is added because we are creating _LTLIBRARIES based # on configure substitution. This causes automake to not know the # correct $libdir and must be added here. @@ -38,7 +14,7 @@ DIST_SANELIBS_LDFLAGS = $(AM_LDFLAGS) -rpath '$(libdir)/sane' -version-number $( DIST_LIBS_LDFLAGS = $(AM_LDFLAGS) -rpath '$(libdir)' -version-number $(V_MAJOR):$(V_MINOR):$(V_REV) # LIBTOOL install is a little to noisy for my liking. -LIBTOOL = @LIBTOOL@ --silent +LIBTOOL += --silent FIRMWARE_DIRS = artec_eplus48u gt68xx snapscan epjitsu EXTRA_DIST = sane_strstatus.c @@ -50,15 +26,15 @@ EXTRA_DIST += stubs.c # FIXME: % is a GNU extension... This is only thing left requiring # use to use GNU make. %-s.c: $(srcdir)/stubs.c - rm -f $@ - $(LN_S) $(srcdir)/stubs.c $@ + $(AM_V_at)rm -f $@ + $(AM_V_at)$(LN_S) $(srcdir)/stubs.c $@ dll-preload.h: - rm -f $@ - list="$(PRELOADABLE_BACKENDS)"; for be in $$list; do \ + $(AM_V_at)rm -f $@ + $(AM_V_at)list="$(PRELOADABLE_BACKENDS)"; for be in $$list; do \ echo "PRELOAD_DECL($$be)" >> $@; \ - done - echo "static struct backend preloaded_backends[] = {" >> $@ + done; \ + echo "static struct backend preloaded_backends[] = {" >> $@; \ sep=""; \ list="$(PRELOADABLE_BACKENDS)"; \ if test -z "$${list}"; then \ @@ -68,7 +44,7 @@ dll-preload.h: echo "$${sep}PRELOAD_DEFN($$be)" >> $@; \ sep=","; \ done; \ - fi + fi; \ echo "};" >> $@ # TODO: This really belongs together with the saned sources and @@ -86,6 +62,7 @@ BACKEND_CONFS= abaton.conf agfafocus.conf apple.conf artec.conf \ epson.conf epsonds.conf fujitsu.conf genesys.conf gphoto2.conf \ gt68xx.conf hp3900.conf hp4200.conf hp5400.conf \ hp.conf hpsj5s.conf hs2p.conf ibm.conf kodak.conf kodakaio.conf\ + kvs1025.conf \ leo.conf lexmark.conf ma1509.conf magicolor.conf \ matsushita.conf microtek2.conf microtek.conf mustek.conf \ mustek_pp.conf mustek_usb.conf nec.conf net.conf \ @@ -351,7 +328,7 @@ libcanon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c libsane_canon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) +libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) EXTRA_DIST += canon_dr.conf.in libcanon_pp_la_SOURCES = canon_pp.c canon_pp.h canon_pp-io.c canon_pp-io.h canon_pp-dev.c canon_pp-dev.h @@ -414,7 +391,7 @@ libdc210_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc210 nodist_libsane_dc210_la_SOURCES = dc210-s.c libsane_dc210_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc210 libsane_dc210_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dc210_la_LIBADD = $(COMMON_LIBS) libdc210.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) +libsane_dc210_la_LIBADD = $(COMMON_LIBS) libdc210.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) EXTRA_DIST += dc210.conf.in libdc240_la_SOURCES = dc240.c dc240.h @@ -423,7 +400,7 @@ libdc240_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc240 nodist_libsane_dc240_la_SOURCES = dc240-s.c libsane_dc240_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc240 libsane_dc240_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dc240_la_LIBADD = $(COMMON_LIBS) libdc240.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) +libsane_dc240_la_LIBADD = $(COMMON_LIBS) libdc240.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) EXTRA_DIST += dc240.conf.in libdell1600n_net_la_SOURCES = dell1600n_net.c @@ -472,7 +449,8 @@ libsane_epson2_la_LIBADD = $(COMMON_LIBS) libepson2.la ../sanei/sanei_init_debug EXTRA_DIST += epson2.conf.in libepsonds_la_SOURCES = epsonds.c epsonds.h epsonds-usb.c epsonds-usb.h epsonds-io.c epsonds-io.h \ - epsonds-cmd.c epsonds-cmd.h epsonds-ops.c epsonds-ops.h epsonds-jpeg.c epsonds-jpeg.h + epsonds-cmd.c epsonds-cmd.h epsonds-ops.c epsonds-ops.h epsonds-jpeg.c epsonds-jpeg.h \ + epsonds-net.c epsonds-net.h libepsonds_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epsonds nodist_libsane_epsonds_la_SOURCES = epsonds-s.c @@ -481,7 +459,8 @@ libsane_epsonds_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_epsonds_la_LIBADD = $(COMMON_LIBS) libepsonds.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo \ ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) $(USB_LIBS) $(MATH_LIB) $(RESMGR_LIBS) + ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo \ + $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(USB_LIBS) $(MATH_LIB) $(RESMGR_LIBS) $(SOCKET_LIBS) EXTRA_DIST += epsonds.conf.in libfujitsu_la_SOURCES = fujitsu.c fujitsu.h fujitsu-scsi.h @@ -505,12 +484,12 @@ EXTRA_DIST += genesys.conf.in EXTRA_DIST += genesys_conv.c genesys_conv_hlp.c genesys_devices.c libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h -libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) @GPHOTO2_CPPFLAGS@ -DBACKEND_NAME=gphoto2 +libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2 nodist_libsane_gphoto2_la_SOURCES = gphoto2-s.c libsane_gphoto2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gphoto2 libsane_gphoto2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_gphoto2_la_LIBADD = $(GPHOTO2_LDFLAGS) $(COMMON_LIBS) libgphoto2_i.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(GPHOTO2_LIBS) $(JPEG_LIBS) +libsane_gphoto2_la_LIBADD = $(GPHOTO2_LDFLAGS) $(COMMON_LIBS) libgphoto2_i.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(GPHOTO2_LIBS) $(JPEG_LIBS) EXTRA_DIST += gphoto2.conf.in libgt68xx_la_SOURCES = gt68xx.c gt68xx.h @@ -541,7 +520,7 @@ libhp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500 nodist_libsane_hp3500_la_SOURCES = hp3500-s.c libsane_hp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500 libsane_hp3500_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) libhp3900_la_SOURCES = hp3900.c libhp3900_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3900 @@ -651,6 +630,7 @@ nodist_libsane_kvs1025_la_SOURCES = kvs1025-s.c libsane_kvs1025_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs1025 libsane_kvs1025_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_kvs1025_la_LIBADD = $(COMMON_LIBS) libkvs1025.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) +EXTRA_DIST += kvs1025.conf.in libkvs20xx_la_SOURCES = kvs20xx.c kvs20xx_cmd.c kvs20xx_opt.c \ kvs20xx_cmd.h kvs20xx.h @@ -788,10 +768,10 @@ libsane_nec_la_LIBADD = $(COMMON_LIBS) libnec.la ../sanei/sanei_init_debug.lo .. EXTRA_DIST += nec.conf.in libnet_la_SOURCES = net.c net.h -libnet_la_CPPFLAGS = $(AM_CPPFLAGS) @AVAHI_CFLAGS@ -DBACKEND_NAME=net +libnet_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=net nodist_libsane_net_la_SOURCES = net-s.c -libsane_net_la_CPPFLAGS = $(AM_CPPFLAGS) @AVAHI_CFLAGS@ -DBACKEND_NAME=net +libsane_net_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=net libsane_net_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_net_la_LIBADD = $(COMMON_LIBS) libnet.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo $(AVAHI_LIBS) $(SOCKET_LIBS) EXTRA_DIST += net.conf.in @@ -1088,7 +1068,7 @@ libsane_umax_pp_la_LIBADD = $(COMMON_LIBS) libumax_pp.la ../sanei/sanei_init_deb EXTRA_DIST += umax_pp.conf.in libv4l_la_SOURCES = v4l.c v4l.h v4l-frequencies.h -libv4l_la_CPPFLAGS = $(AM_CPPFLAGS) @LIBV4L_CFLAGS@ -DBACKEND_NAME=v4l +libv4l_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBV4L_CFLAGS) -DBACKEND_NAME=v4l nodist_libsane_v4l_la_SOURCES = v4l-s.c libsane_v4l_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=v4l @@ -1102,7 +1082,7 @@ libxerox_mfp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=xerox_mfp nodist_libsane_xerox_mfp_la_SOURCES = xerox_mfp-s.c libsane_xerox_mfp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=xerox_mfp libsane_xerox_mfp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_xerox_mfp_la_LIBADD = $(COMMON_LIBS) libxerox_mfp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_tcp.lo $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(RESMGR_LIBS) +libsane_xerox_mfp_la_LIBADD = $(COMMON_LIBS) libxerox_mfp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) ../sanei/sanei_usb.lo ../sanei/sanei_tcp.lo $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(RESMGR_LIBS) EXTRA_DIST += xerox_mfp.conf.in libdll_preload_la_SOURCES = dll.c @@ -1142,7 +1122,7 @@ EXTRA_DIST += dll.aliases nodist_libsane_la_SOURCES = dll-s.c libsane_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll libsane_la_LDFLAGS = $(DIST_LIBS_LDFLAGS) -libsane_la_LIBADD = $(COMMON_LIBS) @PRELOADABLE_BACKENDS_ENABLED@ libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(DL_LIBS) $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_la_LIBADD = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(DL_LIBS) $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) # WARNING: Automake is getting this wrong so have to do it ourselves. -libsane_la_DEPENDENCIES = $(COMMON_LIBS) @PRELOADABLE_BACKENDS_ENABLED@ libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo @SANEI_SANEI_JPEG_LO@ +libsane_la_DEPENDENCIES = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(SANEI_SANEI_JPEG_LO) diff --git a/backend/Makefile.in b/backend/Makefile.in index 1860295..4e070f0 100644 --- a/backend/Makefile.in +++ b/backend/Makefile.in @@ -82,11 +82,16 @@ subdir = backend DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/ltoptions.m4 \ +am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ + $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ + $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ + $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/ltoptions.m4 \ $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ - $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/acinclude.m4 \ - $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/byteorder.m4 \ - $(top_srcdir)/m4/stdint.m4 $(top_srcdir)/configure.in + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/m4/libtool.m4 \ + $(top_srcdir)/m4/byteorder.m4 $(top_srcdir)/m4/stdint.m4 \ + $(top_srcdir)/configure.ac am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ $(ACLOCAL_M4) mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs @@ -215,7 +220,7 @@ libepsonds_la_LIBADD = am_libepsonds_la_OBJECTS = libepsonds_la-epsonds.lo \ libepsonds_la-epsonds-usb.lo libepsonds_la-epsonds-io.lo \ libepsonds_la-epsonds-cmd.lo libepsonds_la-epsonds-ops.lo \ - libepsonds_la-epsonds-jpeg.lo + libepsonds_la-epsonds-jpeg.lo libepsonds_la-epsonds-net.lo libepsonds_la_OBJECTS = $(am_libepsonds_la_OBJECTS) libfujitsu_la_LIBADD = am_libfujitsu_la_OBJECTS = libfujitsu_la-fujitsu.lo @@ -491,8 +496,9 @@ libsane_canon_dr_la_DEPENDENCIES = $(COMMON_LIBS) libcanon_dr.la \ ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ + ../sanei/sanei_magic.lo $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) nodist_libsane_canon_dr_la_OBJECTS = \ libsane_canon_dr_la-canon_dr-s.lo libsane_canon_dr_la_OBJECTS = $(nodist_libsane_canon_dr_la_OBJECTS) @@ -567,7 +573,7 @@ libsane_coolscan3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ libsane_dc210_la_DEPENDENCIES = $(COMMON_LIBS) libdc210.la \ ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) nodist_libsane_dc210_la_OBJECTS = libsane_dc210_la-dc210-s.lo libsane_dc210_la_OBJECTS = $(nodist_libsane_dc210_la_OBJECTS) libsane_dc210_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @@ -577,7 +583,7 @@ libsane_dc210_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ libsane_dc240_la_DEPENDENCIES = $(COMMON_LIBS) libdc240.la \ ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) nodist_libsane_dc240_la_OBJECTS = libsane_dc240_la-dc240-s.lo libsane_dc240_la_OBJECTS = $(nodist_libsane_dc240_la_OBJECTS) libsane_dc240_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @@ -669,6 +675,8 @@ libsane_epsonds_la_DEPENDENCIES = $(COMMON_LIBS) libepsonds.la \ ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ + ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) nodist_libsane_epsonds_la_OBJECTS = libsane_epsonds_la-epsonds-s.lo @@ -704,7 +712,8 @@ libsane_genesys_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ libsane_gphoto2_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(COMMON_LIBS) \ libgphoto2_i.la ../sanei/sanei_init_debug.lo \ ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo \ - sane_strstatus.lo $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + sane_strstatus.lo $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) nodist_libsane_gphoto2_la_OBJECTS = libsane_gphoto2_la-gphoto2-s.lo libsane_gphoto2_la_OBJECTS = $(nodist_libsane_gphoto2_la_OBJECTS) libsane_gphoto2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @@ -739,7 +748,7 @@ libsane_hp3500_la_DEPENDENCIES = $(COMMON_LIBS) libhp3500.la \ ../sanei/sanei_config.lo sane_strstatus.lo \ ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) nodist_libsane_hp3500_la_OBJECTS = libsane_hp3500_la-hp3500-s.lo libsane_hp3500_la_OBJECTS = $(nodist_libsane_hp3500_la_OBJECTS) libsane_hp3500_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ @@ -1421,9 +1430,10 @@ libsane_v4l_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ libsane_xerox_mfp_la_DEPENDENCIES = $(COMMON_LIBS) libxerox_mfp.la \ ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_tcp.lo \ + $(am__DEPENDENCIES_1) ../sanei/sanei_usb.lo \ + ../sanei/sanei_tcp.lo $(am__DEPENDENCIES_1) \ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) + $(am__DEPENDENCIES_1) nodist_libsane_xerox_mfp_la_OBJECTS = \ libsane_xerox_mfp_la-xerox_mfp-s.lo libsane_xerox_mfp_la_OBJECTS = $(nodist_libsane_xerox_mfp_la_OBJECTS) @@ -1740,7 +1750,12 @@ DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) ACLOCAL = @ACLOCAL@ ALLOCA = @ALLOCA@ AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ -I. -I$(srcdir) -I$(top_builddir)/include \ + -I$(top_srcdir)/include $(USB_CFLAGS) \ + -DLIBDIR="\"$(libdir)/sane\"" AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_LDFLAGS = @AM_LDFLAGS@ $(STRICT_LDFLAGS) AR = @AR@ AS = @AS@ AUTOCONF = @AUTOCONF@ @@ -1761,9 +1776,9 @@ CPPFLAGS = @CPPFLAGS@ CYGPATH_W = @CYGPATH_W@ DEFS = @DEFS@ DEPDIR = @DEPDIR@ -DISTCLEAN_FILES = @DISTCLEAN_FILES@ +DLH = @DLH@ DLLTOOL = @DLLTOOL@ -DL_LIBS = @DL_LIBS@ +DL_LIBS = @DL_LIBS@ DSYMUTIL = @DSYMUTIL@ DUMPBIN = @DUMPBIN@ DVIPS = @DVIPS@ @@ -1774,48 +1789,56 @@ ECHO_T = @ECHO_T@ EGREP = @EGREP@ EXEEXT = @EXEEXT@ FGREP = @FGREP@ +FIG2DEV = @FIG2DEV@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ GPHOTO2_CPPFLAGS = @GPHOTO2_CPPFLAGS@ GPHOTO2_LDFLAGS = @GPHOTO2_LDFLAGS@ GPHOTO2_LIBS = @GPHOTO2_LIBS@ GREP = @GREP@ +GS = @GS@ HAVE_GPHOTO2 = @HAVE_GPHOTO2@ -IEEE1284_LIBS = @IEEE1284_LIBS@ -INCLUDES = @INCLUDES@ +IEEE1284_LIBS = @IEEE1284_LIBS@ INSTALL = @INSTALL@ INSTALL_DATA = @INSTALL_DATA@ INSTALL_LOCKPATH = @INSTALL_LOCKPATH@ INSTALL_PROGRAM = @INSTALL_PROGRAM@ INSTALL_SCRIPT = @INSTALL_SCRIPT@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -JPEG_LIBS = @JPEG_LIBS@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +JPEG_LIBS = @JPEG_LIBS@ LATEX = @LATEX@ LD = @LD@ LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ LIBOBJS = @LIBOBJS@ LIBS = @LIBS@ # LIBTOOL install is a little to noisy for my liking. LIBTOOL = @LIBTOOL@ --silent -LIBUSB_1_0_CFLAGS = @LIBUSB_1_0_CFLAGS@ -LIBUSB_1_0_LIBS = @LIBUSB_1_0_LIBS@ LIBV4L_CFLAGS = @LIBV4L_CFLAGS@ -LIBV4L_LIBS = @LIBV4L_LIBS@ -LINKER_RPATH = @LINKER_RPATH@ +LIBV4L_LIBS = @LIBV4L_LIBS@ LIPO = @LIPO@ LN_S = @LN_S@ LOCKPATH_GROUP = @LOCKPATH_GROUP@ +LTALLOCA = @LTALLOCA@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ LTLIBOBJS = @LTLIBOBJS@ MAINT = @MAINT@ MAKEINDEX = @MAKEINDEX@ MAKEINFO = @MAKEINFO@ MANIFEST_TOOL = @MANIFEST_TOOL@ -MATH_LIB = @MATH_LIB@ +MATH_LIB = @MATH_LIB@ MKDIR_P = @MKDIR_P@ MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ MSGMERGE = @MSGMERGE@ NM = @NM@ NMEDIT = @NMEDIT@ -NUMBER_VERSION = @NUMBER_VERSION@ OBJDUMP = @OBJDUMP@ OBJEXT = @OBJEXT@ OTOOL = @OTOOL@ @@ -1828,10 +1851,13 @@ PACKAGE_TARNAME = @PACKAGE_TARNAME@ PACKAGE_URL = @PACKAGE_URL@ PACKAGE_VERSION = @PACKAGE_VERSION@ PATH_SEPARATOR = @PATH_SEPARATOR@ +PDFLATEX = @PDFLATEX@ PKG_CONFIG = @PKG_CONFIG@ PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ PNG_LIBS = @PNG_LIBS@ +POSUB = @POSUB@ +PPMTOGIF = @PPMTOGIF@ PRELOADABLE_BACKENDS = @PRELOADABLE_BACKENDS@ PRELOADABLE_BACKENDS_ENABLED = @PRELOADABLE_BACKENDS_ENABLED@ PTHREAD_LIBS = @PTHREAD_LIBS@ @@ -1846,19 +1872,23 @@ SHELL = @SHELL@ SNMP_CFLAGS = @SNMP_CFLAGS@ SNMP_CONFIG_PATH = @SNMP_CONFIG_PATH@ SNMP_LIBS = @SNMP_LIBS@ -SOCKET_LIBS = @SOCKET_LIBS@ +SOCKET_LIBS = @SOCKET_LIBS@ STRICT_LDFLAGS = @STRICT_LDFLAGS@ STRIP = @STRIP@ SYSLOG_LIBS = @SYSLOG_LIBS@ SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ SYSTEMD_LIBS = @SYSTEMD_LIBS@ -TIFF_LIBS = @TIFF_LIBS@ -USB_LIBS = @USB_LIBS@ +TIFF_LIBS = @TIFF_LIBS@ +USB_CFLAGS = @USB_CFLAGS@ +USB_LIBS = @USB_LIBS@ +USE_NLS = @USE_NLS@ VERSION = @VERSION@ V_MAJOR = @V_MAJOR@ V_MINOR = @V_MINOR@ V_REV = @V_REV@ XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ abs_builddir = @abs_builddir@ abs_srcdir = @abs_srcdir@ abs_top_builddir = @abs_top_builddir@ @@ -1914,8 +1944,6 @@ target_alias = @target_alias@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ -AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_builddir)/include -I$(top_srcdir)/include -DLIBDIR="\"$(libdir)/sane\"" -AM_LDFLAGS = @STRICT_LDFLAGS@ # The -rpath option is added because we are creating _LTLIBRARIES based # on configure substitution. This causes automake to not know the # correct $libdir and must be added here. @@ -1978,16 +2006,16 @@ EXTRA_DIST = sane_strstatus.c stubs.c saned.conf.in abaton.conf.in \ hp5590_cmds.c hp5590_cmds.h hp5590_low.c hp5590_low.h \ hpsj5s.conf.in hs2p.conf.in hs2p-scsi.c hs2p-scsi.h \ ibm.conf.in ibm-scsi.c kodak.conf.in kodakaio.conf.in \ - leo.conf.in lexmark.conf.in lexmark_models.c lexmark_sensors.c \ - ma1509.conf.in magicolor.conf.in matsushita.conf.in \ - microtek.conf.in microtek2.conf.in mustek.conf.in \ - mustek_scsi_pp.c mustek_scsi_pp.h mustek_pp.conf.in \ - mustek_pp_ccd300.c mustek_pp_ccd300.h mustek_pp_cis.c \ - mustek_pp_cis.h mustek_pp_null.c mustek_usb.conf.in \ - mustek_usb_high.c mustek_usb_high.h mustek_usb_low.c \ - mustek_usb_low.h mustek_usb_mid.c mustek_usb_mid.h \ - mustek_usb2_asic.c mustek_usb2_asic.h mustek_usb2_high.c \ - mustek_usb2_high.h mustek_usb2_reflective.c \ + kvs1025.conf.in leo.conf.in lexmark.conf.in lexmark_models.c \ + lexmark_sensors.c ma1509.conf.in magicolor.conf.in \ + matsushita.conf.in microtek.conf.in microtek2.conf.in \ + mustek.conf.in mustek_scsi_pp.c mustek_scsi_pp.h \ + mustek_pp.conf.in mustek_pp_ccd300.c mustek_pp_ccd300.h \ + mustek_pp_cis.c mustek_pp_cis.h mustek_pp_null.c \ + mustek_usb.conf.in mustek_usb_high.c mustek_usb_high.h \ + mustek_usb_low.c mustek_usb_low.h mustek_usb_mid.c \ + mustek_usb_mid.h mustek_usb2_asic.c mustek_usb2_asic.h \ + mustek_usb2_high.c mustek_usb2_high.h mustek_usb2_reflective.c \ mustek_usb2_transparent.c nec.conf.in net.conf.in niash_core.c \ niash_core.h niash_xfer.c niash_xfer.h pie.conf.in \ pieusb.conf.in p5.conf.in p5_device.c pixma.conf.in \ @@ -2035,6 +2063,7 @@ BACKEND_CONFS = abaton.conf agfafocus.conf apple.conf artec.conf \ epson.conf epsonds.conf fujitsu.conf genesys.conf gphoto2.conf \ gt68xx.conf hp3900.conf hp4200.conf hp5400.conf \ hp.conf hpsj5s.conf hs2p.conf ibm.conf kodak.conf kodakaio.conf\ + kvs1025.conf \ leo.conf lexmark.conf ma1509.conf magicolor.conf \ matsushita.conf microtek2.conf microtek.conf mustek.conf \ mustek_pp.conf mustek_usb.conf nec.conf net.conf \ @@ -2213,7 +2242,7 @@ libcanon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c libsane_canon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) +libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) libcanon_pp_la_SOURCES = canon_pp.c canon_pp.h canon_pp-io.c canon_pp-io.h canon_pp-dev.c canon_pp-dev.h libcanon_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_pp nodist_libsane_canon_pp_la_SOURCES = canon_pp-s.c @@ -2255,13 +2284,13 @@ libdc210_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc210 nodist_libsane_dc210_la_SOURCES = dc210-s.c libsane_dc210_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc210 libsane_dc210_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dc210_la_LIBADD = $(COMMON_LIBS) libdc210.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) +libsane_dc210_la_LIBADD = $(COMMON_LIBS) libdc210.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) libdc240_la_SOURCES = dc240.c dc240.h libdc240_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc240 nodist_libsane_dc240_la_SOURCES = dc240-s.c libsane_dc240_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc240 libsane_dc240_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dc240_la_LIBADD = $(COMMON_LIBS) libdc240.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) +libsane_dc240_la_LIBADD = $(COMMON_LIBS) libdc240.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) libdell1600n_net_la_SOURCES = dell1600n_net.c libdell1600n_net_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dell1600n_net nodist_libsane_dell1600n_net_la_SOURCES = dell1600n_net-s.c @@ -2293,7 +2322,8 @@ libsane_epson2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epson2 libsane_epson2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_epson2_la_LIBADD = $(COMMON_LIBS) libepson2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo $(SCSI_LIBS) $(USB_LIBS) $(SOCKET_LIBS) $(MATH_LIB) $(RESMGR_LIBS) libepsonds_la_SOURCES = epsonds.c epsonds.h epsonds-usb.c epsonds-usb.h epsonds-io.c epsonds-io.h \ - epsonds-cmd.c epsonds-cmd.h epsonds-ops.c epsonds-ops.h epsonds-jpeg.c epsonds-jpeg.h + epsonds-cmd.c epsonds-cmd.h epsonds-ops.c epsonds-ops.h epsonds-jpeg.c epsonds-jpeg.h \ + epsonds-net.c epsonds-net.h libepsonds_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epsonds nodist_libsane_epsonds_la_SOURCES = epsonds-s.c @@ -2302,7 +2332,8 @@ libsane_epsonds_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_epsonds_la_LIBADD = $(COMMON_LIBS) libepsonds.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo \ ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) $(USB_LIBS) $(MATH_LIB) $(RESMGR_LIBS) + ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo \ + $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(USB_LIBS) $(MATH_LIB) $(RESMGR_LIBS) $(SOCKET_LIBS) libfujitsu_la_SOURCES = fujitsu.c fujitsu.h fujitsu-scsi.h libfujitsu_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=fujitsu @@ -2317,11 +2348,11 @@ libsane_genesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys libsane_genesys_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h -libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) @GPHOTO2_CPPFLAGS@ -DBACKEND_NAME=gphoto2 +libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2 nodist_libsane_gphoto2_la_SOURCES = gphoto2-s.c libsane_gphoto2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gphoto2 libsane_gphoto2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_gphoto2_la_LIBADD = $(GPHOTO2_LDFLAGS) $(COMMON_LIBS) libgphoto2_i.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(GPHOTO2_LIBS) $(JPEG_LIBS) +libsane_gphoto2_la_LIBADD = $(GPHOTO2_LDFLAGS) $(COMMON_LIBS) libgphoto2_i.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(GPHOTO2_LIBS) $(JPEG_LIBS) libgt68xx_la_SOURCES = gt68xx.c gt68xx.h libgt68xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gt68xx nodist_libsane_gt68xx_la_SOURCES = gt68xx-s.c @@ -2339,7 +2370,7 @@ libhp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500 nodist_libsane_hp3500_la_SOURCES = hp3500-s.c libsane_hp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500 libsane_hp3500_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) libhp3900_la_SOURCES = hp3900.c libhp3900_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3900 nodist_libsane_hp3900_la_SOURCES = hp3900-s.c @@ -2497,9 +2528,9 @@ libsane_nec_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=nec libsane_nec_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_nec_la_LIBADD = $(COMMON_LIBS) libnec.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(RESMGR_LIBS) libnet_la_SOURCES = net.c net.h -libnet_la_CPPFLAGS = $(AM_CPPFLAGS) @AVAHI_CFLAGS@ -DBACKEND_NAME=net +libnet_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=net nodist_libsane_net_la_SOURCES = net-s.c -libsane_net_la_CPPFLAGS = $(AM_CPPFLAGS) @AVAHI_CFLAGS@ -DBACKEND_NAME=net +libsane_net_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=net libsane_net_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_net_la_LIBADD = $(COMMON_LIBS) libnet.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo $(AVAHI_LIBS) $(SOCKET_LIBS) libniash_la_SOURCES = niash.c @@ -2683,7 +2714,7 @@ libsane_umax_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax_pp libsane_umax_pp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_umax_pp_la_LIBADD = $(COMMON_LIBS) libumax_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(MATH_LIB) libv4l_la_SOURCES = v4l.c v4l.h v4l-frequencies.h -libv4l_la_CPPFLAGS = $(AM_CPPFLAGS) @LIBV4L_CFLAGS@ -DBACKEND_NAME=v4l +libv4l_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBV4L_CFLAGS) -DBACKEND_NAME=v4l nodist_libsane_v4l_la_SOURCES = v4l-s.c libsane_v4l_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=v4l libsane_v4l_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) @@ -2693,7 +2724,7 @@ libxerox_mfp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=xerox_mfp nodist_libsane_xerox_mfp_la_SOURCES = xerox_mfp-s.c libsane_xerox_mfp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=xerox_mfp libsane_xerox_mfp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_xerox_mfp_la_LIBADD = $(COMMON_LIBS) libxerox_mfp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_tcp.lo $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(RESMGR_LIBS) +libsane_xerox_mfp_la_LIBADD = $(COMMON_LIBS) libxerox_mfp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) ../sanei/sanei_usb.lo ../sanei/sanei_tcp.lo $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(RESMGR_LIBS) libdll_preload_la_SOURCES = dll.c libdll_preload_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll -DENABLE_PRELOAD libdll_la_SOURCES = dll.c @@ -2726,10 +2757,10 @@ libsane_dll_la_LIBADD = $(COMMON_LIBS) libdll.la ../sanei/sanei_init_debug.lo .. nodist_libsane_la_SOURCES = dll-s.c libsane_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll libsane_la_LDFLAGS = $(DIST_LIBS_LDFLAGS) -libsane_la_LIBADD = $(COMMON_LIBS) @PRELOADABLE_BACKENDS_ENABLED@ libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(DL_LIBS) $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_la_LIBADD = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(DL_LIBS) $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) # WARNING: Automake is getting this wrong so have to do it ourselves. -libsane_la_DEPENDENCIES = $(COMMON_LIBS) @PRELOADABLE_BACKENDS_ENABLED@ libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo @SANEI_SANEI_JPEG_LO@ +libsane_la_DEPENDENCIES = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(SANEI_SANEI_JPEG_LO) all: $(BUILT_SOURCES) $(MAKE) $(AM_MAKEFLAGS) all-am @@ -3428,6 +3459,7 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-cmd.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-io.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-jpeg.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-net.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-ops.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-usb.Plo@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds.Plo@am__quote@ @@ -3626,22 +3658,25 @@ distclean-compile: @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxerox_mfp_la-xerox_mfp.Plo@am__quote@ .c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< .c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ +@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` .c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ +@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ +@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo @AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< @@ -3947,6 +3982,13 @@ libepsonds_la-epsonds-jpeg.lo: epsonds-jpeg.c @AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ @am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds-jpeg.lo `test -f 'epsonds-jpeg.c' || echo '$(srcdir)/'`epsonds-jpeg.c +libepsonds_la-epsonds-net.lo: epsonds-net.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepsonds_la-epsonds-net.lo -MD -MP -MF $(DEPDIR)/libepsonds_la-epsonds-net.Tpo -c -o libepsonds_la-epsonds-net.lo `test -f 'epsonds-net.c' || echo '$(srcdir)/'`epsonds-net.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepsonds_la-epsonds-net.Tpo $(DEPDIR)/libepsonds_la-epsonds-net.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds-net.c' object='libepsonds_la-epsonds-net.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds-net.lo `test -f 'epsonds-net.c' || echo '$(srcdir)/'`epsonds-net.c + libfujitsu_la-fujitsu.lo: fujitsu.c @am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfujitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libfujitsu_la-fujitsu.lo -MD -MP -MF $(DEPDIR)/libfujitsu_la-fujitsu.Tpo -c -o libfujitsu_la-fujitsu.lo `test -f 'fujitsu.c' || echo '$(srcdir)/'`fujitsu.c @am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfujitsu_la-fujitsu.Tpo $(DEPDIR)/libfujitsu_la-fujitsu.Plo @@ -5526,15 +5568,15 @@ all: becfg # FIXME: % is a GNU extension... This is only thing left requiring # use to use GNU make. %-s.c: $(srcdir)/stubs.c - rm -f $@ - $(LN_S) $(srcdir)/stubs.c $@ + $(AM_V_at)rm -f $@ + $(AM_V_at)$(LN_S) $(srcdir)/stubs.c $@ dll-preload.h: - rm -f $@ - list="$(PRELOADABLE_BACKENDS)"; for be in $$list; do \ + $(AM_V_at)rm -f $@ + $(AM_V_at)list="$(PRELOADABLE_BACKENDS)"; for be in $$list; do \ echo "PRELOAD_DECL($$be)" >> $@; \ - done - echo "static struct backend preloaded_backends[] = {" >> $@ + done; \ + echo "static struct backend preloaded_backends[] = {" >> $@; \ sep=""; \ list="$(PRELOADABLE_BACKENDS)"; \ if test -z "$${list}"; then \ @@ -5544,7 +5586,7 @@ dll-preload.h: echo "$${sep}PRELOAD_DEFN($$be)" >> $@; \ sep=","; \ done; \ - fi + fi; \ echo "};" >> $@ becfg: $(BACKEND_CONFS) .conf.in.conf: diff --git a/backend/agfafocus.c b/backend/agfafocus.c index 45d103f..c2c5664 100644 --- a/backend/agfafocus.c +++ b/backend/agfafocus.c @@ -947,7 +947,7 @@ do_cancel (AgfaFocus_Scanner * s) do_eof (s); - if (s->reader_pid != -1) + if (sanei_thread_is_valid (s->reader_pid)) { int exit_status; @@ -2054,7 +2054,7 @@ sane_cancel (SANE_Handle handle) { AgfaFocus_Scanner *s = handle; - if (s->reader_pid != -1) + if (sanei_thread_is_valid (s->reader_pid)) sanei_thread_kill (s->reader_pid); s->scanning = SANE_FALSE; } diff --git a/backend/apple.c b/backend/apple.c index a8e9979..487d743 100644 --- a/backend/apple.c +++ b/backend/apple.c @@ -2634,7 +2634,7 @@ sane_cancel (SANE_Handle handle) if (s->AbortedByUser) { DBG (FLOW_CONTROL, - "sane_cancel: Allready Aborted. Please Wait...\n"); + "sane_cancel: Already Aborted. Please Wait...\n"); } else { @@ -2648,7 +2648,7 @@ sane_cancel (SANE_Handle handle) if (s->AbortedByUser) { DBG (FLOW_CONTROL, "sane_cancel: Scan has not been Initiated yet, " - "or it is allready aborted.\n"); + "or it is already aborted.\n"); s->AbortedByUser = SANE_FALSE; sanei_scsi_cmd (s->fd, test_unit_ready, sizeof (test_unit_ready), 0, 0); diff --git a/backend/artec.c b/backend/artec.c index 46aa8b6..2d564a5 100644 --- a/backend/artec.c +++ b/backend/artec.c @@ -1711,7 +1711,6 @@ static SANE_Status artec_get_cap_data (ARTEC_Device * dev, int fd) { int cap_model, loop; - SANE_Status status; u_char cap_buf[256]; /* buffer for cap data */ DBG (7, "artec_get_cap_data()\n"); @@ -1746,11 +1745,11 @@ artec_get_cap_data (ARTEC_Device * dev, int fd) dev->height = cap_data[cap_model].height; - status = artec_str_list_to_word_list (&dev->horz_resolution_list, - cap_data[cap_model].horz_resolution_str); + artec_str_list_to_word_list (&dev->horz_resolution_list, + cap_data[cap_model].horz_resolution_str); - status = artec_str_list_to_word_list (&dev->vert_resolution_list, - cap_data[cap_model].vert_resolution_str); + artec_str_list_to_word_list (&dev->vert_resolution_list, + cap_data[cap_model].vert_resolution_str); dev->contrast_range.min = 0; dev->contrast_range.max = 255; diff --git a/backend/artec_eplus48u.c b/backend/artec_eplus48u.c index bc3b2f8..f31bf5c 100644 --- a/backend/artec_eplus48u.c +++ b/backend/artec_eplus48u.c @@ -1785,14 +1785,14 @@ artec48u_device_read_prepare (Artec48U_Device * dev, size_t expected_count) return SANE_STATUS_GOOD; } -static RETSIGTYPE +static void reader_process_sigterm_handler (int signal) { XDBG ((1, "reader_process: terminated by signal %d\n", signal)); _exit (SANE_STATUS_GOOD); } -static RETSIGTYPE +static void usb_reader_process_sigterm_handler (int signal) { XDBG ((1, "reader_process (usb): terminated by signal %d\n", signal)); @@ -3372,12 +3372,10 @@ close_pipe (Artec48U_Scanner * s) } return SANE_STATUS_EOF; } -static RETSIGTYPE -sigalarm_handler (int signal) +static void +sigalarm_handler (int __sane_unused__ signal) { - int dummy; /*Henning doesn't like warnings :-) */ XDBG ((1, "ALARM!!!\n")); - dummy = signal; cancelRead = SANE_TRUE; } @@ -3483,7 +3481,7 @@ do_cancel (Artec48U_Scanner * s, SANE_Bool closepipe) s->scanning = SANE_FALSE; - if (s->reader_pid != -1) + if (sanei_thread_is_valid (s->reader_pid)) { /*parent */ XDBG ((1, "killing reader_process\n")); @@ -3906,17 +3904,15 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) void sane_close (SANE_Handle handle) { - Artec48U_Scanner *prev, *s; + Artec48U_Scanner *s; XDBG ((5, "sane_close: start\n")); /* remove handle from list of open handles: */ - prev = 0; for (s = first_handle; s; s = s->next) { if (s == handle) break; - prev = s; } if (!s) { @@ -4301,7 +4297,7 @@ sane_start (SANE_Handle handle) s->reader_pipe = fds[1]; s->reader_pid = sanei_thread_begin (reader_process, s); cancelRead = SANE_FALSE; - if (s->reader_pid == -1) + if (!sanei_thread_is_valid (s->reader_pid)) { s->scanning = SANE_FALSE; XDBG ((2, "sane_start: sanei_thread_begin failed (%s)\n", strerror (errno))); diff --git a/backend/as6e.c b/backend/as6e.c index 0fb9e31..76241fb 100644 --- a/backend/as6e.c +++ b/backend/as6e.c @@ -576,8 +576,8 @@ as6e_open (AS6E_Scan * s) execlp ("as6edriver", "as6edriver", "-s", inpipe_desc, outpipe_desc, datapipe_desc, (char *) 0); DBG (1, "The SANE backend was unable to start \"as6edriver\".\n"); - DBG (1, "This must be installed in a driectory in your PATH.\n"); - DBG (1, "To aquire the as6edriver program,\n"); + DBG (1, "This must be installed in a directory in your PATH.\n"); + DBG (1, "To acquire the as6edriver program,\n"); DBG (1, "go to http://as6edriver.sourceforge.net.\n"); write (ctlinpipe[WRITEPIPE], &exec_result, sizeof (exec_result)); exit (-1); diff --git a/backend/avision.c b/backend/avision.c index 146125c..61491a2 100644 --- a/backend/avision.c +++ b/backend/avision.c @@ -1277,6 +1277,9 @@ static SANE_Bool force_calibration = SANE_FALSE; static SANE_Bool force_a4 = SANE_FALSE; static SANE_Bool force_a3 = SANE_FALSE; +/* trust ADF-presence flag, even if ADF model is nonzero */ +static SANE_Bool skip_adf = SANE_FALSE; + /* hardware resolutions to interpolate from */ static const int hw_res_list_c5[] = { @@ -2736,7 +2739,7 @@ wait_4_light (Avision_Scanner* s) struct command_read rcmd; char* light_status[] = { "off", "on", "warming up", "needs warm up test", - "light check error", "RESERVED" }; + "light check error", "backlight on", "RESERVED" }; SANE_Status status; uint8_t result; @@ -2753,6 +2756,11 @@ wait_4_light (Avision_Scanner* s) set_triple (rcmd.transferlen, size); for (try = 0; try < 90; ++ try) { + + if (s->cancelled) { + DBG (3, "wait_4_light: cancelled\n"); + return SANE_STATUS_CANCELLED; + } DBG (5, "wait_4_light: read bytes %lu\n", (u_long) size); status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, &result, &size); @@ -2762,10 +2770,10 @@ wait_4_light (Avision_Scanner* s) return status; } - DBG (3, "wait_4_light: command is %d. Result is %s\n", - status, light_status[(result>4)?5:result]); + DBG (3, "wait_4_light: command is %d. Result is %d (%s)\n", + status, result, light_status[(result>5)?6:result]); - if (result == 1) { + if (result == 1 || result == 5) { return SANE_STATUS_GOOD; } else if (dev->hw->feature_type & AV_LIGHT_CHECK_BOGUS) { @@ -3218,11 +3226,13 @@ get_accessories_info (Avision_Scanner* s) { dev->inquiry_duplex = 1; dev->inquiry_duplex_interlaced = 0; - } else if (result[0] == 0 && result[2] != 0) { + } else if (result[0] == 0 && result[2] != 0 && !skip_adf) { /* Sometimes the scanner will report that there is no ADF attached, yet * an ADF model number will still be reported. This happens on the * HP8200 series and possibly others. In this case we need to reset the - * the adf and try reading it again. + * the adf and try reading it again. Skip this if the configuration says + * to do so, so that we don't fail out the scanner as being broken and + * unsupported if there isn't actually an ADF present. */ DBG (3, "get_accessories_info: Found ADF model number but the ADF-present flag is not set. Trying to recover...\n"); status = adf_reset (s); @@ -4641,7 +4651,6 @@ set_calib_data (Avision_Scanner* s, struct calibration_format* format, struct command_send scmd; int i; - size_t out_size; DBG (3, "set_calib_data:\n"); @@ -4679,8 +4688,6 @@ set_calib_data (Avision_Scanner* s, struct calibration_format* format, } } - out_size = format->pixel_per_line * 2; - /* send data in one command? */ /* FR: HP5370 reports one-pass, but needs multi (or other format in single) */ if (format->channels == 1 || @@ -6215,8 +6222,9 @@ do_cancel (Avision_Scanner* s) s->prepared = s->scanning = SANE_FALSE; s->duplex_rear_valid = SANE_FALSE; s->page = 0; + s->cancelled = 1; - if (s->reader_pid != -1) { + if (sanei_thread_is_valid (s->reader_pid)) { int exit_status; /* ensure child knows it's time to stop: */ @@ -7630,6 +7638,11 @@ sane_reload_devices (void) linenumber); force_a3 = SANE_TRUE; } + else if (strcmp (word, "skip-adf") == 0) { + DBG (3, "sane_reload_devices: config file line %d: enabling skip-adf\n", + linenumber); + skip_adf = SANE_TRUE; + } else if (strcmp (word, "static-red-calib") == 0) { DBG (3, "sane_reload_devices: config file line %d: static red calibration\n", linenumber); @@ -8313,6 +8326,9 @@ sane_start (SANE_Handle handle) /* Make sure there is no scan running!!! */ if (s->scanning) return SANE_STATUS_DEVICE_BUSY; + + /* Clear cancellation status */ + s->cancelled = 0; /* Make sure we have a current parameter set. Some of the parameters will be overwritten below, but that's OK. */ @@ -8365,6 +8381,14 @@ sane_start (SANE_Handle handle) sane_strstatus (status)); goto stop_scanner_and_return; } + /* Re-check the light, as setting the window may have changed + * which light is to be turned on. */ + if (s->prepared == SANE_FALSE && dev->inquiry_light_control) { + status = wait_4_light (s); + if (status != SANE_STATUS_GOOD) { + return status; + } + } } #ifdef DEBUG_TEST diff --git a/backend/avision.h b/backend/avision.h index 2122e09..b26907f 100644 --- a/backend/avision.h +++ b/backend/avision.h @@ -444,6 +444,7 @@ typedef struct Avision_Scanner SANE_Bool prepared; /* first page marker */ SANE_Bool scanning; /* scan in progress */ unsigned int page; /* page counter, 0: uninitialized, 1: scanning 1st page, ... */ + int cancelled; SANE_Parameters params; /* scan window */ Avision_Dimensions avdimen; /* scan window - detailed internals */ diff --git a/backend/bh.h b/backend/bh.h index 62115c6..545ffb1 100644 --- a/backend/bh.h +++ b/backend/bh.h @@ -652,7 +652,7 @@ _4btol(SANE_Byte *bytes) #define SANE_NAME_BARCODE_HMIN "barcode-hmin" #define SANE_TITLE_BARCODE_HMIN "Barcode Minimum Height" -#define SANE_DESC_BARCODE_HMIN "Sets the Barcode Minimun Height (larger values increase recognition speed)" +#define SANE_DESC_BARCODE_HMIN "Sets the Barcode Minimum Height (larger values increase recognition speed)" #define SANE_NAME_BARCODE_SEARCH_MODE "barcode-search-mode" #define SANE_TITLE_BARCODE_SEARCH_MODE "Barcode Search Mode" diff --git a/backend/canon-sane.c b/backend/canon-sane.c index 79ce0ba..a8efc7a 100644 --- a/backend/canon-sane.c +++ b/backend/canon-sane.c @@ -1,5 +1,5 @@ SANE_Status -sane_init (SANE_Int * version_code, SANE_Auth_Callback UNUSEDARG authorize) +sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize) { char devnam[PATH_MAX] = "/dev/scanner"; FILE *fp; @@ -107,7 +107,7 @@ sane_exit (void) SANE_Status sane_get_devices (const SANE_Device *** device_list, -SANE_Bool UNUSEDARG local_only) +SANE_Bool __sane_unused__ local_only) { static const SANE_Device **devlist = 0; CANON_Device *dev; @@ -1104,7 +1104,6 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) SANE_Status sane_start (SANE_Handle handle) { - int mode; char *mode_str; CANON_Scanner *s = handle; SANE_Status status; @@ -1301,33 +1300,27 @@ sane_start (SANE_Handle handle) if (!strcmp (mode_str, SANE_VALUE_SCAN_MODE_LINEART)) { - mode = 4; s->image_composition = 0; } else if (!strcmp (mode_str, SANE_VALUE_SCAN_MODE_HALFTONE)) { - mode = 4; s->image_composition = 1; } else if (!strcmp (mode_str, SANE_VALUE_SCAN_MODE_GRAY)) { - mode = 5; s->image_composition = 2; } else if (!strcmp (mode_str, SANE_VALUE_SCAN_MODE_COLOR) || !strcmp (mode_str, SANE_I18N("Fine color"))) { - mode = 6; s->image_composition = 5; } else if (!strcmp (mode_str, SANE_I18N("Raw"))) { - mode = 6; s->image_composition = 5; } else { - mode = 6; s->image_composition = 5; } @@ -2206,8 +2199,8 @@ sane_cancel (SANE_Handle handle) /**************************************************************************/ SANE_Status -sane_set_io_mode (SANE_Handle UNUSEDARG handle, -SANE_Bool UNUSEDARG non_blocking) +sane_set_io_mode (SANE_Handle __sane_unused__ handle, +SANE_Bool __sane_unused__ non_blocking) { DBG (1, ">> sane_set_io_mode\n"); DBG (1, "<< sane_set_io_mode\n"); @@ -2217,8 +2210,8 @@ SANE_Bool UNUSEDARG non_blocking) /**************************************************************************/ SANE_Status -sane_get_select_fd (SANE_Handle UNUSEDARG handle, -SANE_Int UNUSEDARG * fd) +sane_get_select_fd (SANE_Handle __sane_unused__ handle, +SANE_Int __sane_unused__ * fd) { DBG (1, ">> sane_get_select_fd\n"); DBG (1, "<< sane_get_select_fd\n"); diff --git a/backend/canon-scsi.c b/backend/canon-scsi.c index 423a07e..a83e518 100644 --- a/backend/canon-scsi.c +++ b/backend/canon-scsi.c @@ -688,7 +688,7 @@ static SANE_Status set_parameters_fs2710 (SANE_Handle handle) { CANON_Scanner *s = handle; - int i, j, invert, shadow[4], hilite[4]; + int i, j, shadow[4], hilite[4]; double x, b, c; shadow[1] = s->ShadowR << 4; @@ -700,8 +700,6 @@ set_parameters_fs2710 (SANE_Handle handle) c = ((double) s->contrast) / 128.0; b = ((double) (s->brightness - 128)) / 128.0; - invert = strcmp (filmtype_list[1], s->val[OPT_NEGATIVE].s); - for (i = 1; i < 4; i++) { for (j = 0; j < 4096; j++) diff --git a/backend/canon.h b/backend/canon.h index 34f527b..c4dc9a8 100644 --- a/backend/canon.h +++ b/backend/canon.h @@ -46,12 +46,6 @@ #ifndef canon_h #define canon_h 1 -#ifdef __GNUC__ -#define UNUSEDARG __attribute__ ((unused)) -#else -#define UNUSEDARG -#endif - /* all the different possible model names. */ #define FB1200S "IX-12015E " #define FB620S "IX-06035E " diff --git a/backend/canon630u-common.c b/backend/canon630u-common.c index 4417141..a46424a 100644 --- a/backend/canon630u-common.c +++ b/backend/canon630u-common.c @@ -295,7 +295,7 @@ write_word (int fd, unsigned int addr, unsigned int data) /* write multiple bytes, one at a time (non-bulk) */ static SANE_Status -write_many (int fd, unsigned int addr, void *src, size_t count) +write_many (int fd, unsigned int addr, const byte *src, size_t count) { SANE_Status status; size_t i; @@ -303,8 +303,8 @@ write_many (int fd, unsigned int addr, void *src, size_t count) DBG (14, "multi write %lu\n", (u_long) count); for (i = 0; i < count; i++) { - DBG (15, " %04lx:%02x", (u_long) (addr + i), ((byte *) src)[i]); - status = write_byte (fd, addr + i, ((byte *) src)[i]); + DBG (15, " %04lx:%02x", (u_long) (addr + i), src[i]); + status = write_byte (fd, addr + i, src[i]); if (status != SANE_STATUS_GOOD) { DBG (15, "\n"); @@ -741,9 +741,9 @@ plugin_cal (CANON_Handle * s) /* parallel port setting */ write_byte (fd, PARALLEL_PORT, 0x06); - write_many (fd, 0x08, (byte *) seq002, sizeof (seq002)); + write_many (fd, 0x08, seq002, sizeof (seq002)); /* addr 0x28 isn't written */ - write_many (fd, 0x29, (byte *) seq003, sizeof (seq003)); + write_many (fd, 0x29, seq003, sizeof (seq003)); /* Verification */ buf = malloc (0x400); read_many (fd, 0x08, buf, sizeof (seq002)); diff --git a/backend/canon630u.c b/backend/canon630u.c index 6bd3431..5c1a711 100644 --- a/backend/canon630u.c +++ b/backend/canon630u.c @@ -873,7 +873,6 @@ void sane_close (SANE_Handle handle) { Canon_Scanner *prev, *scanner; - SANE_Status res; DBG (3, "sane_close\n"); @@ -906,7 +905,7 @@ sane_close (SANE_Handle handle) else first_handle = scanner->next; - res = CANON_close_device (&scanner->scan); + CANON_close_device (&scanner->scan); free (scanner); } diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 381cfd6..3c058ab 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -3,7 +3,7 @@ This file is part of the SANE package, and implements a SANE backend for various Canon DR-series scanners. - Copyright (C) 2008-2010 m. allan noah + Copyright (C) 2008-2016 m. allan noah Yabarana Corp. www.yabarana.com provided significant funding EvriChart, Inc. www.evrichart.com provided funding and loaned equipment @@ -314,8 +314,27 @@ v50 2015-08-23, MAN - DR-C125 adds duplex padding on back side - initial support for DR-C225 - v51 2015-08-25, MAN + v51 2015-08-25, MAN (SANE 1.0.25) - DR-C125 does not invert_tly, does need sw_lut + v52 2015-11-03, MAN + - set can_color=1 by default (recent models dont have 'C' in name) + - enable jpeg for DR-6080 + - add must_downsample and must_fully_buffer + - improve dropout option handling + - add software dropout implementation for downsampled modes + v53 2015-11-06, MAN + - replace image processing methods with sanei_magic + - add swskip option + - reorder geometry group options + - use bg_color to fill missing image data + v54 2015-11-21, MAN + - br_x and br_y locked to page_width/height until changed + v55 2016-03-19, MAN + - fixed-width scanners were calculating left-side offset incorrectly in color + - initial support for DR-F120 + - rename all DUPLEX_INTERLACE_* to indicate start and end of line + v56 2016-08-23, MAN + - initial support for P-150 SANE FLOW DIAGRAM @@ -360,12 +379,13 @@ #include "../include/sane/sanei_usb.h" #include "../include/sane/saneopts.h" #include "../include/sane/sanei_config.h" +#include "../include/sane/sanei_magic.h" #include "canon_dr-cmd.h" #include "canon_dr.h" #define DEBUG 1 -#define BUILD 51 +#define BUILD 56 /* values for SANE_DEBUG_CANON_DR env var: - errors 5 @@ -618,7 +638,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) global_extra_status = buf; } - /* DUPLEXOFFSET: < 1200 */ + /* DUPLEXOFFSET: < 2400 */ else if (!strncmp (lp, "duplex-offset", 13) && isspace (lp[13])) { int buf; @@ -626,9 +646,9 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - if (buf > 1200) { + if (buf > 2400) { DBG (5, "sane_get_devices: config option \"duplex-offset\" " - "(%d) is > 1200, ignoring!\n", buf); + "(%d) is > 2400, ignoring!\n", buf); continue; } @@ -1262,18 +1282,21 @@ init_model (struct scanner *s) s->max_x_fb = s->max_x; s->max_y_fb = s->max_y; - /* generic settings missing from vpd */ - if (strstr (s->model_name,"C")){ - s->can_color = 1; - } + /* missing from vpd- we will unset this for b&w machines below */ + s->can_color = 1; /* specific settings missing from vpd */ - if (strstr (s->model_name,"DR-9080") - || strstr (s->model_name,"DR-7580")){ + if (strstr (s->model_name,"DR-9080")){ s->has_comp_JPEG = 1; s->rgb_format = 2; } + else if (strstr (s->model_name,"DR-6080") + || strstr (s->model_name,"DR-7580")){ + s->has_comp_JPEG = 1; + s->can_color = 0; + } + else if (strstr (s->model_name,"DR-7090")){ s->has_flatbed = 1; } @@ -1318,7 +1341,7 @@ init_model (struct scanner *s) s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_RRGGBB; s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_rRgGbB; s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_gG; - s->duplex_interlace = DUPLEX_INTERLACE_FBFB; + s->duplex_interlace = DUPLEX_INTERLACE_FBfb; s->need_ccal = 1; s->need_fcal = 1; /*s->duplex_offset = 432; now set in config file*/ @@ -1398,7 +1421,7 @@ init_model (struct scanner *s) s->even_Bpl = 1; s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_RRGGBB; s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_RRGGBB; - s->duplex_interlace = DUPLEX_INTERLACE_FBFB; + s->duplex_interlace = DUPLEX_INTERLACE_FBfb; s->need_fcal_buffer = 1; s->bg_color = 0x08; /*s->duplex_offset = 840; now set in config file*/ @@ -1422,6 +1445,7 @@ init_model (struct scanner *s) s->ppl_mod = 32; s->reverse_by_mode[MODE_LINEART] = 0; s->reverse_by_mode[MODE_HALFTONE] = 0; + s->can_color = 0; } else if (strstr (s->model_name,"DR-5020")){ @@ -1432,16 +1456,33 @@ init_model (struct scanner *s) s->ppl_mod = 32; s->reverse_by_mode[MODE_LINEART] = 0; s->reverse_by_mode[MODE_HALFTONE] = 0; + s->can_color = 0; + } + + /* all copied from P-215 */ + else if (strstr (s->model_name, "P-150")) { + s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_rRgGbB; + s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_RRGGBB; + s->gray_interlace[SIDE_FRONT] = GRAY_INTERLACE_gG; + s->duplex_interlace = DUPLEX_INTERLACE_FBfb; + s->need_ccal = 1; + s->invert_tly = 1; + s->unknown_byte2 = 0x88; + s->rgb_format = 1; + s->has_ssm_pay_head_len = 1; + s->ppl_mod = 8; + s->ccal_version = 3; + s->can_read_sensors = 1; + s->has_card = 1; } else if (strstr (s->model_name, "P-208")) { s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_RRGGBB; s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_rRgGbB; s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_gG; - s->duplex_interlace = DUPLEX_INTERLACE_FBFB; + s->duplex_interlace = DUPLEX_INTERLACE_FBfb; s->need_ccal = 1; s->invert_tly = 1; - s->can_color = 1; s->unknown_byte2 = 0x88; s->rgb_format = 1; s->has_ssm_pay_head_len = 1; @@ -1454,10 +1495,9 @@ init_model (struct scanner *s) s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_rRgGbB; s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_RRGGBB; s->gray_interlace[SIDE_FRONT] = GRAY_INTERLACE_gG; - s->duplex_interlace = DUPLEX_INTERLACE_FBFB; + s->duplex_interlace = DUPLEX_INTERLACE_FBfb; s->need_ccal = 1; s->invert_tly = 1; - s->can_color = 1; s->unknown_byte2 = 0x88; s->rgb_format = 1; s->has_ssm_pay_head_len = 1; @@ -1485,7 +1525,6 @@ init_model (struct scanner *s) s->has_comp_JPEG = 1; s->rgb_format = 1; - s->can_color = 1; s->has_df_ultra = 1; s->color_inter_by_res[DPI_100] = COLOR_INTERLACE_GBR; @@ -1500,7 +1539,7 @@ init_model (struct scanner *s) s->can_write_panel = 0; s->has_ssm = 0; s->has_ssm2 = 1; - s->duplex_interlace = DUPLEX_INTERLACE_FFBB; + s->duplex_interlace = DUPLEX_INTERLACE_FfBb; s->duplex_offset_side = SIDE_FRONT; /*lies*/ @@ -1526,7 +1565,6 @@ init_model (struct scanner *s) s->has_comp_JPEG = 1; s->rgb_format = 1; - s->can_color = 1; s->has_df_ultra = 1; s->color_inter_by_res[DPI_100] = COLOR_INTERLACE_GBR; @@ -1541,7 +1579,7 @@ init_model (struct scanner *s) s->can_write_panel = 0; s->has_ssm = 0; s->has_ssm2 = 1; - s->duplex_interlace = DUPLEX_INTERLACE_FFBB; + s->duplex_interlace = DUPLEX_INTERLACE_FfBb; s->duplex_offset_side = SIDE_BACK; /*lies*/ @@ -1563,7 +1601,6 @@ init_model (struct scanner *s) s->ccal_version = 3; s->need_fcal = 1; s->sw_lut = 1; - s->can_color = 1; s->rgb_format = 1; /*s->duplex_offset = 400; now set in config file*/ @@ -1585,14 +1622,13 @@ init_model (struct scanner *s) s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_RRGGBB; s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_rRgGbB; s->gray_interlace[SIDE_BACK] = GRAY_INTERLACE_gG; - s->duplex_interlace = DUPLEX_INTERLACE_FBFB; + s->duplex_interlace = DUPLEX_INTERLACE_FBfb; s->unknown_byte2 = 0x88; s->need_ccal = 1; s->ccal_version = 3; s->need_fcal = 1; s->invert_tly = 1; - s->can_color = 1; s->rgb_format = 1; /*s->duplex_offset = 400; now set in config file*/ @@ -1609,6 +1645,51 @@ init_model (struct scanner *s) s->valid_x = 8.5 * 1200; } + else if (strstr (s->model_name,"DR-F120")){ + /* TODO items: + * * has_rif = 0 ? is this correct + * * has_comp_JPEG = 0 ? is this correct + * * need_ccal = need_fcal = need_fcal_buffer = ccal_version = 0 ? is this correct + */ + + /* Required for USB coms */ + s->has_ssm = 0; + s->has_ssm2 = 1; + + /*missing*/ + s->std_res_x[DPI_100] = 1; + s->std_res_y[DPI_100] = 1; + // DPI_150 not supported + s->std_res_x[DPI_200] = 1; + s->std_res_y[DPI_200] = 1; + s->std_res_x[DPI_300] = 1; + s->std_res_y[DPI_300] = 1; + // DPI_400 not supported + s->std_res_x[DPI_600]= 1; + s->std_res_y[DPI_600] = 1; + // DPI_1200 not supported + // NOTE: This scanner supports higher resolutions + // in the Y direction, but 600 is maximum in X + + // This is true however only the ADF is ever selected in hardware + // FIXME: What extra option is needed to select this in the USB comms + s->has_flatbed = 1; + + /* duplex */ + s->duplex_interlace = DUPLEX_INTERLACE_fFBb; + s->color_interlace[SIDE_FRONT] = COLOR_INTERLACE_GBR; + s->color_interlace[SIDE_BACK] = COLOR_INTERLACE_GBR; + s->color_inter_by_res[DPI_100] = COLOR_INTERLACE_RGB; + s->color_inter_by_res[DPI_600] = COLOR_INTERLACE_RGB; + s->duplex_offset_side = SIDE_BACK; + + /* weirdness */ + s->fixed_width = 1; + + /* lies */ + s->can_halftone = 0; + } + DBG (10, "init_model: finish\n"); return SANE_STATUS_GOOD; @@ -2239,7 +2320,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if (i > 1){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if (s->u.mode != MODE_COLOR && s->u.mode != MODE_GRAYSCALE){ + if ( must_downsample(s) || s->s.mode < MODE_GRAYSCALE ){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -2361,6 +2442,24 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->cap = SANE_CAP_INACTIVE; } + /* Software blank page skip */ + if(option==OPT_SWSKIP){ + + opt->name = "swskip"; + opt->title = SANE_I18N ("Software blank skip percentage"); + opt->desc = SANE_I18N("Request driver to discard pages with low percentage of dark pixels"); + opt->type = SANE_TYPE_FIXED; + opt->unit = SANE_UNIT_PERCENT; + opt->constraint_type = SANE_CONSTRAINT_RANGE; + opt->constraint.range = &s->swskip_range; + + s->swskip_range.quant=SANE_FIX(0.10001); + s->swskip_range.min=SANE_FIX(0); + s->swskip_range.max=SANE_FIX(100); + + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } + /*staple detection*/ if(option==OPT_STAPLEDETECT){ opt->name = "stapledetect"; @@ -2751,12 +2850,16 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *val_p = s->swcrop; return SANE_STATUS_GOOD; + case OPT_SWSKIP: + *val_p = SANE_FIX(s->swskip); + return SANE_STATUS_GOOD; + case OPT_STAPLEDETECT: *val_p = s->stapledetect; return SANE_STATUS_GOOD; case OPT_DROPOUT_COLOR_F: - switch (s->dropout_color_f) { + switch (s->dropout_color[SIDE_FRONT]) { case COLOR_NONE: strcpy (val, STRING_NONE); break; @@ -2782,7 +2885,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, return SANE_STATUS_GOOD; case OPT_DROPOUT_COLOR_B: - switch (s->dropout_color_b) { + switch (s->dropout_color[SIDE_BACK]) { case COLOR_NONE: strcpy (val, STRING_NONE); break; @@ -3003,6 +3106,14 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (s->u.page_x == FIXED_MM_TO_SCANNER_UNIT(val_c)) return SANE_STATUS_GOOD; + /* if full width image, and paper size is changed, + change the image size to match new paper */ + if (s->u.tl_x == 0 && s->u.br_x == s->u.page_x){ + DBG (20, "sane_control_option: br_x tracking page_width\n"); + s->u.br_x = FIXED_MM_TO_SCANNER_UNIT(val_c); + *info |= SANE_INFO_RELOAD_PARAMS; + } + s->u.page_x = FIXED_MM_TO_SCANNER_UNIT(val_c); *info |= SANE_INFO_RELOAD_OPTIONS; @@ -3012,6 +3123,14 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (s->u.page_y == FIXED_MM_TO_SCANNER_UNIT(val_c)) return SANE_STATUS_GOOD; + /* if full height image, and paper size is changed, + change the image size to match new paper */ + if (s->u.tl_y == 0 && s->u.br_y == s->u.page_y){ + DBG (20, "sane_control_option: br_y tracking page_height\n"); + s->u.br_y = FIXED_MM_TO_SCANNER_UNIT(val_c); + *info |= SANE_INFO_RELOAD_PARAMS; + } + s->u.page_y = FIXED_MM_TO_SCANNER_UNIT(val_c); *info |= SANE_INFO_RELOAD_OPTIONS; @@ -3072,42 +3191,46 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->swcrop = val_c; return SANE_STATUS_GOOD; + case OPT_SWSKIP: + s->swskip = SANE_UNFIX(val_c); + return SANE_STATUS_GOOD; + case OPT_STAPLEDETECT: s->stapledetect = val_c; return SANE_STATUS_GOOD; case OPT_DROPOUT_COLOR_F: if (!strcmp(val, STRING_NONE)) - s->dropout_color_f = COLOR_NONE; + s->dropout_color[SIDE_FRONT] = COLOR_NONE; else if (!strcmp(val, STRING_RED)) - s->dropout_color_f = COLOR_RED; + s->dropout_color[SIDE_FRONT] = COLOR_RED; else if (!strcmp(val, STRING_GREEN)) - s->dropout_color_f = COLOR_GREEN; + s->dropout_color[SIDE_FRONT] = COLOR_GREEN; else if (!strcmp(val, STRING_BLUE)) - s->dropout_color_f = COLOR_BLUE; + s->dropout_color[SIDE_FRONT] = COLOR_BLUE; else if (!strcmp(val, STRING_EN_RED)) - s->dropout_color_f = COLOR_EN_RED; + s->dropout_color[SIDE_FRONT] = COLOR_EN_RED; else if (!strcmp(val, STRING_EN_GREEN)) - s->dropout_color_f = COLOR_EN_GREEN; + s->dropout_color[SIDE_FRONT] = COLOR_EN_GREEN; else if (!strcmp(val, STRING_EN_BLUE)) - s->dropout_color_f = COLOR_EN_BLUE; + s->dropout_color[SIDE_FRONT] = COLOR_EN_BLUE; return SANE_STATUS_GOOD; case OPT_DROPOUT_COLOR_B: if (!strcmp(val, STRING_NONE)) - s->dropout_color_b = COLOR_NONE; + s->dropout_color[SIDE_BACK] = COLOR_NONE; else if (!strcmp(val, STRING_RED)) - s->dropout_color_b = COLOR_RED; + s->dropout_color[SIDE_BACK] = COLOR_RED; else if (!strcmp(val, STRING_GREEN)) - s->dropout_color_b = COLOR_GREEN; + s->dropout_color[SIDE_BACK] = COLOR_GREEN; else if (!strcmp(val, STRING_BLUE)) - s->dropout_color_b = COLOR_BLUE; + s->dropout_color[SIDE_BACK] = COLOR_BLUE; else if (!strcmp(val, STRING_EN_RED)) - s->dropout_color_b = COLOR_EN_RED; + s->dropout_color[SIDE_BACK] = COLOR_EN_RED; else if (!strcmp(val, STRING_EN_GREEN)) - s->dropout_color_b = COLOR_EN_GREEN; + s->dropout_color[SIDE_BACK] = COLOR_EN_GREEN; else if (!strcmp(val, STRING_EN_BLUE)) - s->dropout_color_b = COLOR_EN_BLUE; + s->dropout_color[SIDE_BACK] = COLOR_EN_BLUE; return SANE_STATUS_GOOD; case OPT_BUFFERMODE: @@ -3344,6 +3467,11 @@ ssm_do (struct scanner *s) return ret; } + if(s->s.mode == MODE_COLOR){ + DBG (10, "ssm_do: unneeded, finishing\n"); + return ret; + } + if(s->has_ssm){ unsigned char cmd[SET_SCAN_MODE_len]; @@ -3366,7 +3494,7 @@ ssm_do (struct scanner *s) set_SSM_DO_unk1(out, 0x03); - switch(s->dropout_color_f){ + switch(s->dropout_color[SIDE_FRONT]){ case COLOR_RED: set_SSM_DO_unk2(out, 0x05); set_SSM_DO_f_do(out,SSM_DO_red); @@ -3393,7 +3521,7 @@ ssm_do (struct scanner *s) break; } - switch(s->dropout_color_b){ + switch(s->dropout_color[SIDE_BACK]){ case COLOR_RED: set_SSM_DO_unk2(out, 0x05); set_SSM_DO_b_do(out,SSM_DO_red); @@ -3444,7 +3572,7 @@ ssm_do (struct scanner *s) memset(out,0,outLen); - switch(s->dropout_color_f){ + switch(s->dropout_color[SIDE_FRONT]){ case COLOR_RED: set_SSM2_DO_do(out,SSM_DO_red); break; @@ -4138,9 +4266,7 @@ sane_start (SANE_Handle handle) * tell the user the size of the image. the sane * API has no way to inform the frontend of this, * so we block and buffer. yuck */ - if( (s->swdeskew || s->swdespeck || s->swcrop) - && s->s.format != SANE_FRAME_JPEG - ){ + if(must_fully_buffer(s)){ /* get image */ while(!s->s.eof[s->side] && !ret){ @@ -4166,7 +4292,16 @@ sane_start (SANE_Handle handle) if(s->swdespeck){ buffer_despeck(s,s->side); } - + if(s->swskip){ + /* Skipping means throwing out this image. + * Pretend the user read the whole thing + * and call sane_start again. + * This assumes we are running in batch mode. */ + if(buffer_isblank(s,s->side)){ + s->u.eof[s->side] = 1; + return sane_start(handle); + } + } } ret = check_for_cancel(s); @@ -4752,23 +4887,7 @@ read_from_scanner(struct scanner *s, int side, int exact) /* this is non-jpeg data, fill remainder, change rx'd size */ else{ - - DBG (15, "read_from_scanner: eof: %d %d\n", s->i.bytes_tot[side], s->i.bytes_sent[side]); - - /* clone the last line repeatedly until the end */ - while(s->i.bytes_tot[side] > s->i.bytes_sent[side]){ - memcpy( - s->buffers[side]+s->i.bytes_sent[side]-s->i.Bpl, - s->buffers[side]+s->i.bytes_sent[side], - s->i.Bpl - ); - s->i.bytes_sent[side] += s->i.Bpl; - } - - DBG (15, "read_from_scanner: eof2: %d %d\n", s->i.bytes_tot[side], s->i.bytes_sent[side]); - - /* pretend we got all the data from scanner */ - s->s.bytes_sent[side] = s->s.bytes_tot[side]; + fill_image(s,side); } s->i.eof[side] = 1; @@ -4890,40 +5009,8 @@ read_from_scanner_duplex(struct scanner *s,int exact) /* this is non-jpeg data, fill remainder, change rx'd size */ else{ - - DBG (15, "read_from_scanner_duplex: eof: %d %d %d %d\n", - s->i.bytes_tot[SIDE_FRONT], s->i.bytes_sent[SIDE_FRONT], - s->i.bytes_tot[SIDE_BACK], s->i.bytes_sent[SIDE_BACK] - ); - - /* clone the last line repeatedly until the end */ - while(s->i.bytes_tot[SIDE_FRONT] > s->i.bytes_sent[SIDE_FRONT]){ - memcpy( - s->buffers[SIDE_FRONT]+s->i.bytes_sent[SIDE_FRONT]-s->i.Bpl, - s->buffers[SIDE_FRONT]+s->i.bytes_sent[SIDE_FRONT], - s->i.Bpl - ); - s->i.bytes_sent[SIDE_FRONT] += s->i.Bpl; - } - - /* clone the last line repeatedly until the end */ - while(s->i.bytes_tot[SIDE_BACK] > s->i.bytes_sent[SIDE_BACK]){ - memcpy( - s->buffers[SIDE_BACK]+s->i.bytes_sent[SIDE_BACK]-s->i.Bpl, - s->buffers[SIDE_BACK]+s->i.bytes_sent[SIDE_BACK], - s->i.Bpl - ); - s->i.bytes_sent[SIDE_BACK] += s->i.Bpl; - } - - DBG (15, "read_from_scanner_duplex: eof2: %d %d %d %d\n", - s->i.bytes_tot[SIDE_FRONT], s->i.bytes_sent[SIDE_FRONT], - s->i.bytes_tot[SIDE_BACK], s->i.bytes_sent[SIDE_BACK] - ); - - /* pretend we got all the data from scanner */ - s->s.bytes_sent[SIDE_FRONT] = s->s.bytes_tot[SIDE_FRONT]; - s->s.bytes_sent[SIDE_BACK] = s->s.bytes_tot[SIDE_BACK]; + fill_image(s,SIDE_FRONT); + fill_image(s,SIDE_BACK); } s->i.eof[SIDE_FRONT] = 1; @@ -5222,16 +5309,20 @@ copy_duplex(struct scanner *s, unsigned char * buf, int len) } /* full line of front, then full line of back */ - else if(s->duplex_interlace == DUPLEX_INTERLACE_FFBB){ + else if(s->duplex_interlace == DUPLEX_INTERLACE_FfBb || s->duplex_interlace == DUPLEX_INTERLACE_fFBb){ for(i=0; iduplex_interlace == DUPLEX_INTERLACE_FfBb){ + memcpy(front+flen,buf+i,bwidth); + }else{ + rmemcpy(front+flen,buf+i,bwidth,3); // only 24bit color is supported + } flen+=bwidth; memcpy(back+blen,buf+i+bwidth,bwidth); blen+=bwidth; } } - /*just alternating bytes, FBFBFB*/ + /*just alternating bytes, FBfb*/ else { for(i=0; is.mode) { case MODE_COLOR: - memcpy(line, buff, sbwidth); + if(must_downsample(s) && s->dropout_color[side]){ + switch(s->dropout_color[side]){ + case COLOR_RED: + for(i=0;ii.mode) { case MODE_COLOR: - memcpy(s->buffers[side]+s->i.bytes_sent[side], line+offset, ibwidth); + memcpy(s->buffers[side]+s->i.bytes_sent[side], line+(offset*3), ibwidth); s->i.bytes_sent[side] += ibwidth; break; @@ -5410,6 +5556,43 @@ read_from_buffer(struct scanner *s, SANE_Byte * buf, SANE_Int max_len, return ret; } +/* fill remainder of buffer with background if scanner stops early */ +static SANE_Status +fill_image(struct scanner *s,int side) +{ + SANE_Status ret=SANE_STATUS_GOOD; + + unsigned char bg_color = calc_bg_color(s); + int fill_bytes = s->i.bytes_tot[side]-s->i.bytes_sent[side]; + + if(!fill_bytes){ + return ret; + } + + DBG (15, "fill_image: side:%d bytes:%d bg_color:%02x\n", side, fill_bytes, bg_color); + + /* fill the rest with bg_color */ + memset(s->buffers[side]+s->i.bytes_sent[side],bg_color,fill_bytes); + + /* pretend we got all the data from scanner */ + s->i.bytes_sent[side] = s->i.bytes_tot[side]; + s->s.bytes_sent[side] = s->s.bytes_tot[side]; + + return ret; +} + +/* return the bg color based on scanner settings */ +static unsigned char +calc_bg_color(struct scanner *s) +{ + unsigned char bg_color = s->lut[s->bg_color]; + + if(s->u.mode <= MODE_HALFTONE) + bg_color = (bg_colorthreshold)?0xff:0x00; + + return bg_color; +} + /* * @@ Section 5 - calibration functions */ @@ -7144,18 +7327,20 @@ wait_scanner(struct scanner *s) NULL, 0, NULL, NULL ); - + + // some scanners (such as DR-F120) are OK but will not respond to commands + // when in sleep mode. By checking the sense it wakes them up. if (ret != SANE_STATUS_GOOD) { - DBG(5,"WARNING: Brain-dead scanner. Hitting with stick\n"); + DBG(5,"WARNING: Brain-dead scanner. Hitting with request sense.\n"); ret = do_cmd ( - s, 0, 1, + s, 1, 1, cmd, cmdLen, NULL, 0, NULL, NULL ); } if (ret != SANE_STATUS_GOOD) { - DBG(5,"WARNING: Brain-dead scanner. Hitting with stick again\n"); + DBG(5,"WARNING: Brain-dead scanner. Hitting with stick instead.\n"); ret = do_cmd ( s, 0, 1, cmd, cmdLen, @@ -7168,7 +7353,7 @@ wait_scanner(struct scanner *s) DBG (5, "wait_scanner: error '%s'\n", sane_strstatus (ret)); } - DBG (10, "wait_scanner: finish\n"); + DBG (10, "wait_scanner: finish (status=%d)\n", ret); return ret; } @@ -7350,102 +7535,40 @@ buffer_deskew(struct scanner *s, int side) { SANE_Status ret = SANE_STATUS_GOOD; - int pwidth = s->i.width; - int width = s->i.Bpl; - int height = s->i.height; - - double TSlope = 0; - int TXInter = 0; - int TYInter = 0; - double TSlopeHalf = 0; - int TOffsetHalf = 0; - - double LSlope = 0; - int LXInter = 0; - int LYInter = 0; - double LSlopeHalf = 0; - int LOffsetHalf = 0; - - int rotateX = 0; - int rotateY = 0; - - int * topBuf = NULL, * botBuf = NULL; + unsigned char bg_color = calc_bg_color(s); DBG (10, "buffer_deskew: start\n"); - /* get buffers for edge detection */ - topBuf = getTransitionsY(s,side,1); - if(!topBuf){ - DBG (5, "buffer_deskew: cant gTY\n"); - ret = SANE_STATUS_NO_MEM; - goto cleanup; - } - - if(0){ - int i; - for(i=0;i=0 && topBuf[i] < height) - s->buffers[side][topBuf[i]*width+i] = 0; - } - } + ret = sane_get_parameters((SANE_Handle) s, &s->s_params); - botBuf = getTransitionsY(s,side,0); - if(!botBuf){ - DBG (5, "buffer_deskew: cant gTY\n"); - ret = SANE_STATUS_NO_MEM; - goto cleanup; - } + /*only find skew on first image from a page, or if first image had error */ + if(s->side == SIDE_FRONT || s->u.source == SOURCE_ADF_BACK || s->deskew_stat){ - /* find best top line */ - ret = getEdgeIterate (pwidth, height, s->i.dpi_y, topBuf, - &TSlope, &TXInter, &TYInter); - if(ret){ - DBG(5,"buffer_deskew: gEI error: %d",ret); - goto cleanup; - } - DBG(15,"top: %04.04f %d %d\n",TSlope,TXInter,TYInter); + s->deskew_stat = sanei_magic_findSkew( + &s->s_params,s->buffers[side],s->u.dpi_x,s->u.dpi_y, + &s->deskew_vals[0],&s->deskew_vals[1],&s->deskew_slope); - /* slope is too shallow, don't want to divide by 0 */ - if(fabs(TSlope) < 0.0001){ - DBG(15,"buffer_deskew: slope too shallow: %0.08f\n",TSlope); - goto cleanup; + if(s->deskew_stat){ + DBG (5, "buffer_deskew: bad findSkew, bailing\n"); + goto cleanup; + } } - - /* find best left line, perpendicular to top line */ - LSlope = (double)-1/TSlope; - ret = getEdgeSlope (pwidth, height, topBuf, botBuf, LSlope, - &LXInter, &LYInter); - if(ret){ - DBG(5,"buffer_deskew: gES error: %d",ret); - goto cleanup; + /* backside images can use a 'flipped' version of frontside data */ + else{ + s->deskew_slope *= -1; + s->deskew_vals[0] = s->s_params.pixels_per_line - s->deskew_vals[0]; } - DBG(15,"buffer_deskew: left: %04.04f %d %d\n",LSlope,LXInter,LYInter); - - /* find point about which to rotate */ - TSlopeHalf = tan(atan(TSlope)/2); - TOffsetHalf = LYInter; - DBG(15,"buffer_deskew: top half: %04.04f %d\n",TSlopeHalf,TOffsetHalf); - - LSlopeHalf = tan((atan(LSlope) + ((LSlope < 0)?-M_PI_2:M_PI_2))/2); - LOffsetHalf = - LSlopeHalf * TXInter; - DBG(15,"buffer_deskew: left half: %04.04f %d\n",LSlopeHalf,LOffsetHalf); - rotateX = (LOffsetHalf-TOffsetHalf) / (TSlopeHalf-LSlopeHalf); - rotateY = TSlopeHalf * rotateX + TOffsetHalf; - DBG(15,"buffer_deskew: rotate: %d %d\n",rotateX,rotateY); + ret = sanei_magic_rotate(&s->s_params,s->buffers[side], + s->deskew_vals[0],s->deskew_vals[1],s->deskew_slope,bg_color); - ret = rotateOnCenter (s, side, rotateX, rotateY, TSlope); if(ret){ - DBG(5,"buffer_deskew: gES error: %d",ret); + DBG(5,"buffer_deskew: rotate error: %d",ret); + ret = SANE_STATUS_GOOD; goto cleanup; } cleanup: - if(topBuf) - free(topBuf); - if(botBuf) - free(botBuf); - DBG (10, "buffer_deskew: finish\n"); return ret; } @@ -7458,173 +7581,50 @@ buffer_crop(struct scanner *s, int side) { SANE_Status ret = SANE_STATUS_GOOD; - int bwidth = s->i.Bpl; - int width = s->i.width; - int height = s->i.height; - - int top = 0; - int bot = 0; - int left = width; - int right = 0; - - int * topBuf = NULL, * botBuf = NULL; - int * leftBuf = NULL, * rightBuf = NULL; - int leftCount = 0, rightCount = 0, botCount = 0; - int i; - DBG (10, "buffer_crop: start\n"); - /* get buffers to find sides and bottom */ - topBuf = getTransitionsY(s,side,1); - if(!topBuf){ - DBG (5, "buffer_crop: no topBuf\n"); - ret = SANE_STATUS_NO_MEM; - goto cleanup; - } - - botBuf = getTransitionsY(s,side,0); - if(!botBuf){ - DBG (5, "buffer_crop: no botBuf\n"); - ret = SANE_STATUS_NO_MEM; - goto cleanup; - } + ret = sane_get_parameters((SANE_Handle) s, &s->s_params); - leftBuf = getTransitionsX(s,side,1); - if(!leftBuf){ - DBG (5, "buffer_crop: no leftBuf\n"); - ret = SANE_STATUS_NO_MEM; - goto cleanup; - } + ret = sanei_magic_findEdges( + &s->s_params,s->buffers[side],s->u.dpi_x,s->u.dpi_y, + &s->crop_vals[0],&s->crop_vals[1],&s->crop_vals[2],&s->crop_vals[3]); - rightBuf = getTransitionsX(s,side,0); - if(!rightBuf){ - DBG (5, "buffer_crop: no rightBuf\n"); - ret = SANE_STATUS_NO_MEM; + if(ret){ + DBG (5, "buffer_crop: bad edges, bailing\n"); + ret = SANE_STATUS_GOOD; goto cleanup; } - /* loop thru top and bottom lists, look for l and r extremes */ - for(i=0; i topBuf[i]){ - if(left > i){ - left = i; - } - - leftCount++; - if(leftCount > 3){ - break; - } - } - else{ - leftCount = 0; - left = width; - } - } - - for(i=width-1; i>=0; i--){ - if(botBuf[i] > topBuf[i]){ - if(right < i){ - right = i; - } - - rightCount++; - if(rightCount > 3){ - break; - } - } - else{ - rightCount = 0; - right = -1; - } - } - - /* loop thru left and right lists, look for bottom extreme */ - for(i=height-1; i>=0; i--){ - if(rightBuf[i] > leftBuf[i]){ - if(bot < i){ - bot = i; - } + DBG (15, "buffer_crop: t:%d b:%d l:%d r:%d\n", + s->crop_vals[0],s->crop_vals[1],s->crop_vals[2],s->crop_vals[3]); - botCount++; - if(botCount > 3){ - break; - } - } - else{ - botCount = 0; - bot = -1; - } + /* if we will later binarize this image, make sure the width + * is a multiple of 8 pixels, by adjusting the right side */ + if ( must_downsample(s) && s->u.mode < MODE_GRAYSCALE ){ + s->crop_vals[3] -= (s->crop_vals[3]-s->crop_vals[2]) % 8; } - DBG (15, "buffer_crop: t:%d b:%d l:%d r:%d\n",top,bot,left,right); - /* now crop the image */ - /*FIXME: crop duplex backside at same time?*/ - if(left < right && top < bot){ - - int pixels = 0; - int bytes = 0; - unsigned char * line = NULL; - - /*convert left and right to bytes, figure new byte and pixel width */ - switch (s->i.mode) { - - case MODE_COLOR: - pixels = right-left; - bytes = pixels * 3; - left *= 3; - right *= 3; - break; - - case MODE_GRAYSCALE: - pixels = right-left; - bytes = right-left; - break; - - case MODE_LINEART: - case MODE_HALFTONE: - left /= 8; - right = (right+7)/8; - bytes = right-left; - pixels = bytes * 8; - break; - } - - DBG (15, "buffer_crop: l:%d r:%d p:%d b:%d\n",left,right,pixels,bytes); - - line = malloc(bytes); - if(!line){ - DBG (5, "buffer_crop: no line\n"); - ret = SANE_STATUS_NO_MEM; - goto cleanup; - } - - s->i.bytes_sent[side] = 0; - - for(i=top; ibuffers[side] + i*bwidth + left, bytes); - memcpy(s->buffers[side] + s->i.bytes_sent[side], line, bytes); - s->i.bytes_sent[side] += bytes; - } + ret = sanei_magic_crop(&s->s_params,s->buffers[side], + s->crop_vals[0],s->crop_vals[1],s->crop_vals[2],s->crop_vals[3]); - s->i.bytes_tot[side] = s->i.bytes_sent[side]; - s->i.width = pixels; - s->i.height = bot-top; - s->i.Bpl = bytes; - - free(line); + if(ret){ + DBG (5, "buffer_crop: bad crop, bailing\n"); + ret = SANE_STATUS_GOOD; + goto cleanup; } - cleanup: - if(topBuf) - free(topBuf); - if(botBuf) - free(botBuf); - if(leftBuf) - free(leftBuf); - if(rightBuf) - free(rightBuf); - + /* need to update user with new size */ + s->i.width = s->s_params.pixels_per_line; + s->i.height = s->s_params.lines; + s->i.Bpl = s->s_params.bytes_per_line; + + /* update image size counter to new, smaller size */ + s->i.bytes_tot[side] = s->s_params.lines * s->s_params.bytes_per_line; + s->i.bytes_sent[side] = s->i.bytes_tot[side]; + s->u.bytes_sent[side] = 0; + + cleanup: DBG (10, "buffer_crop: finish\n"); return ret; } @@ -7636,938 +7636,77 @@ static SANE_Status buffer_despeck(struct scanner *s, int side) { SANE_Status ret = SANE_STATUS_GOOD; - int i,j,k,l,n; - int w = s->i.Bpl; - int pw = s->i.width; - int h = s->i.height; - int t = w*h; - int d = s->swdespeck; DBG (10, "buffer_despeck: start\n"); - switch (s->i.mode){ + ret = sane_get_parameters((SANE_Handle) s, &s->s_params); - case MODE_COLOR: - for(i=w; ibuffers[side][i + j*3 + k*w + l*3 + n]; - } - - if(tmp < thresh) - thresh = tmp; - } - } + ret = sanei_magic_despeck(&s->s_params,s->buffers[side],s->swdespeck); + if(ret){ + DBG (5, "buffer_despeck: bad despeck, bailing\n"); + ret = SANE_STATUS_GOOD; + goto cleanup; + } - thresh = (thresh + 255*3 + 255*3)/3; - - /*loop over rows and columns around window */ - for(k=-1; kbuffers[side][i + j*3 + k*w + l*3 + n]; - outer[n] += tmp[n]; - } - if(tmp[0]+tmp[1]+tmp[2] < thresh){ - hits++; - break; - } - } - } +/* Look if image has too few dark pixels.*/ +static int +buffer_isblank(struct scanner *s, int side) +{ + SANE_Status ret = SANE_STATUS_GOOD; + int status = 0; - for(n=0; n<3; n++){ - outer[n] /= (4*d + 4); - } + DBG (10, "buffer_isblank: start\n"); - /*no hits, overwrite with avg surrounding color*/ - if(!hits){ - for(k=0; kbuffers[side][i + j*3 + k*w + l*3 + n] = outer[n]; - } - } - } - } + ret = sane_get_parameters((SANE_Handle) s, &s->s_params); - } - } - break; + ret = sanei_magic_isBlank2(&s->s_params, s->buffers[side], + s->u.dpi_x, s->u.dpi_y, s->swskip); - case MODE_GRAYSCALE: - for(i=w; ibuffers[side][i + j + k*w + l] < thresh) - thresh = s->buffers[side][i + j + k*w + l]; - } - } +/* certain options require the entire image to + * be collected from the scanner before we can + * tell the user the size of the image. */ +static int +must_fully_buffer(struct scanner *s) +{ - thresh = (thresh + 255 + 255)/3; - - /*loop over rows and columns around window */ - for(k=-1; kswdeskew || s->swdespeck || s->swcrop) + && s->s.format != SANE_FRAME_JPEG + ){ + return 1; + } - int tmp = 0; + return 0; +} - /* dont count pixels in the window */ - if(k != -1 && k != d && l != -1 && l != d) - continue; - - tmp = s->buffers[side][i + j + k*w + l]; - - if(tmp < thresh){ - hits++; - break; - } - - outer += tmp; - } - } - - outer /= (4*d + 4); - - /*no hits, overwrite with avg surrounding color*/ - if(!hits){ - for(k=0; kbuffers[side][i + j + k*w + l] = outer; - } - } - } - - } - } - break; - - case MODE_LINEART: - case MODE_HALFTONE: - for(i=w; ibuffers[side][i + k*w + (j+l)/8] >> (7-(j+l)%8) & 1; - } - } - - if(!curr) - continue; - - /*loop over rows and columns around window */ - for(k=-1; kbuffers[side][i + k*w + (j+l)/8] >> (7-(j+l)%8) & 1; - - if(hits) - break; - } - } - - /*no hits, overwrite with white*/ - if(!hits){ - for(k=0; kbuffers[side][i + k*w + (j+l)/8] &= ~(1 << (7-(j+l)%8)); - } - } - } - - } - } - break; - - default: - break; - } - - DBG (10, "buffer_despeck: finish\n"); - return ret; -} - -/* Loop thru the image width and look for first color change in each column. - * Return a malloc'd array. Caller is responsible for freeing. */ -int * -getTransitionsY (struct scanner *s, int side, int top) -{ - int * buff; - - int i, j, k; - int near, far; - int winLen = 9; - - int width = s->i.width; - int height = s->i.height; - int depth = 1; - - /* defaults for bottom-up */ - int firstLine = height-1; - int lastLine = -1; - int direction = -1; - - DBG (10, "getTransitionsY: start\n"); - - buff = calloc(width,sizeof(int)); - if(!buff){ - DBG (5, "getTransitionsY: no buff\n"); - return NULL; - } - - /* override for top-down */ - if(top){ - firstLine = 0; - lastLine = height; - direction = 1; - } - - /* load the buff array with y value for first color change from edge - * gray/color uses a different algo from binary/halftone */ - switch (s->i.mode) { - - case MODE_COLOR: - depth = 3; - - case MODE_GRAYSCALE: - - for(i=0; ibuffers[side][(firstLine*width+i) * depth + k]; - } - near *= winLen; - far = near; - - /* move windows, check delta */ - for(j=firstLine+direction; j!=lastLine; j+=direction){ - - int farLine = j-winLen*2*direction; - int nearLine = j-winLen*direction; - - if(farLine < 0 || farLine >= height){ - farLine = firstLine; - } - if(nearLine < 0 || nearLine >= height){ - nearLine = firstLine; - } - - for(k=0; kbuffers[side][(farLine*width+i)*depth+k]; - far += s->buffers[side][(nearLine*width+i)*depth+k]; - - near -= s->buffers[side][(nearLine*width+i)*depth+k]; - near += s->buffers[side][(j*width+i)*depth+k]; - } - - if(abs(near - far) > winLen*depth*9){ - buff[i] = j; - break; - } - } - } - break; - - case MODE_LINEART: - case MODE_HALFTONE: - for(i=0; ibuffers[side][(firstLine*width+i)/8] >> (7-(i%8)) & 1; - - /* move */ - for(j=firstLine+direction; j!=lastLine; j+=direction){ - if((s->buffers[side][(j*width+i)/8] >> (7-(i%8)) & 1) != near){ - buff[i] = j; - break; - } - } - } - break; - - } - - /* blast any stragglers with no neighbors within .5 inch */ - for(i=0;ii.dpi_y/2) - sum++; - } - if(sum < 2) - buff[i] = lastLine; - } - - DBG (10, "getTransitionsY: finish\n"); - - return buff; -} - -/* Loop thru the image height and look for first color change in each row. - * Return a malloc'd array. Caller is responsible for freeing. */ -int * -getTransitionsX (struct scanner *s, int side, int left) -{ - int * buff; - - int i, j, k; - int near, far; - int winLen = 9; - - int bwidth = s->i.Bpl; - int width = s->i.width; - int height = s->i.height; - int depth = 1; - - /* defaults for right-first */ - int firstCol = width-1; - int lastCol = -1; - int direction = -1; - - DBG (10, "getTransitionsX: start\n"); - - buff = calloc(height,sizeof(int)); - if(!buff){ - DBG (5, "getTransitionsY: no buff\n"); - return NULL; - } - - /* override for left-first*/ - if(left){ - firstCol = 0; - lastCol = width; - direction = 1; - } - - /* load the buff array with x value for first color change from edge - * gray/color uses a different algo from binary/halftone */ - switch (s->i.mode) { - - case MODE_COLOR: - depth = 3; - - case MODE_GRAYSCALE: - - for(i=0; ibuffers[side][i*bwidth + k]; - } - near *= winLen; - far = near; - - /* move windows, check delta */ - for(j=firstCol+direction; j!=lastCol; j+=direction){ - - int farCol = j-winLen*2*direction; - int nearCol = j-winLen*direction; - - if(farCol < 0 || farCol >= width){ - farCol = firstCol; - } - if(nearCol < 0 || nearCol >= width){ - nearCol = firstCol; - } - - for(k=0; kbuffers[side][i*bwidth + farCol*depth + k]; - far += s->buffers[side][i*bwidth + nearCol*depth + k]; - - near -= s->buffers[side][i*bwidth + nearCol*depth + k]; - near += s->buffers[side][i*bwidth + j*depth + k]; - } - - if(abs(near - far) > winLen*depth*9){ - buff[i] = j; - break; - } - } - } - break; - - case MODE_LINEART: - case MODE_HALFTONE: - for(i=0; ibuffers[side][i*bwidth + firstCol/8] >> (7-(firstCol%8)) & 1; - - /* move */ - for(j=firstCol+direction; j!=lastCol; j+=direction){ - if((s->buffers[side][i*bwidth + j/8] >> (7-(j%8)) & 1) != near){ - buff[i] = j; - break; - } - } - } - break; - - } - - /* blast any stragglers with no neighbors within .5 inch */ - for(i=0;ii.dpi_x/2) - sum++; - } - if(sum < 2) - buff[i] = lastCol; - } - - DBG (10, "getTransitionsX: finish\n"); - - return buff; -} - -/* Loop thru a getTransitions array, and use a simplified Hough transform - * to divide likely edges into a 2-d array of bins. Then weight each - * bin based on its angle and offset. Return the 'best' bin. */ -static SANE_Status -getLine (int height, int width, int * buff, - int slopes, double minSlope, double maxSlope, - int offsets, int minOffset, int maxOffset, - double * finSlope, int * finOffset, int * finDensity) -{ - SANE_Status ret = 0; - - int ** lines = NULL; - int i, j; - int rise, run; - double slope; - int offset; - int sIndex, oIndex; - int hWidth = width/2; - - double * slopeCenter = NULL; - int * slopeScale = NULL; - double * offsetCenter = NULL; - int * offsetScale = NULL; - - int maxDensity = 1; - double absMaxSlope = fabs(maxSlope); - double absMinSlope = fabs(minSlope); - int absMaxOffset = abs(maxOffset); - int absMinOffset = abs(minOffset); - - DBG(10,"getLine: start %+0.4f %+0.4f %d %d\n", - minSlope,maxSlope,minOffset,maxOffset); - - /*silence compiler*/ - height = height; - - if(absMaxSlope < absMinSlope) - absMaxSlope = absMinSlope; - - if(absMaxOffset < absMinOffset) - absMaxOffset = absMinOffset; - - /* build an array of pretty-print values for slope */ - slopeCenter = calloc(slopes,sizeof(double)); - if(!slopeCenter){ - DBG(5,"getLine: cant load slopeCenter\n"); - ret = SANE_STATUS_NO_MEM; - goto cleanup; - } - - /* build an array of scaling factors for slope */ - slopeScale = calloc(slopes,sizeof(int)); - if(!slopeScale){ - DBG(5,"getLine: cant load slopeScale\n"); - ret = SANE_STATUS_NO_MEM; - goto cleanup; - } - - for(j=0;j= maxSlope || slope < minSlope) - continue; - - /* offset in center of width, not y intercept! */ - offset = slope * hWidth + buff[i] - slope * i; - if(offset >= maxOffset || offset < minOffset) - continue; - - sIndex = (slope - minSlope) * slopes/(maxSlope-minSlope); - if(sIndex >= slopes) - continue; - - oIndex = (offset - minOffset) * offsets/(maxOffset-minOffset); - if(oIndex >= offsets) - continue; - - lines[sIndex][oIndex]++; - } - } - - /* go thru array, and find most dense line (highest number) */ - for(i=0;i maxDensity) - maxDensity = lines[i][j]; - } - } - - DBG(15,"getLine: maxDensity %d\n",maxDensity); - - *finSlope = 0; - *finOffset = 0; - *finDensity = 0; - - /* go thru array, and scale densities to % of maximum, plus adjust for - * prefered (smaller absolute value) slope and offset */ - for(i=0;i *finDensity){ - *finDensity = lines[i][j]; - *finSlope = slopeCenter[i]; - *finOffset = offsetCenter[j]; - } - } - } - - if(0){ - DBG(15,"offsetCenter: "); - for(j=0;j topDensity){ - topSlope = slope; - topOffset = offset; - topDensity = density; - } - } - } - - DBG(15,"getEdgeIterate: ok %+0.4f %d %d\n",topSlope,topOffset,topDensity); - - /* did not find anything promising on first pass, - * give up instead of fixating on some small, pointless feature */ - if(pass == 1 && topDensity < width/5){ - DBG(5,"getEdgeIterate: density too small %d %d\n",topDensity,width); - topOffset = 0; - topSlope = 0; - break; - } - - /* if slope can zoom in some more, do so. */ - if(sStep >= 0.0001){ - minSlope = topSlope - sStep; - maxSlope = topSlope + sStep; - go = 1; - } - - /* if offset can zoom in some more, do so. */ - if(oStep){ - minOffset = topOffset - oStep; - maxOffset = topOffset + oStep; - go = 1; - } - - /* cannot zoom in more, bail out */ - if(!go){ - break; - } - - DBG(15,"getEdgeIterate: zoom: %+0.4f %+0.4f %d %d\n", - minSlope,maxSlope,minOffset,maxOffset); - } - - /* topOffset is in the center of the image, - * convert to x and y intercept */ - if(topSlope != 0){ - *finYInter = topOffset - topSlope * width/2; - *finXInter = *finYInter / -topSlope; - *finSlope = topSlope; - } - else{ - *finYInter = 0; - *finXInter = 0; - *finSlope = 0; - } - - DBG(10,"getEdgeIterate: finish\n"); - - return 0; -} - -/* find the left side of paper by moving a line - * perpendicular to top slope across the image - * the 'left-most' point on the paper is the - * one with the smallest X intercept - * return x and y intercepts */ -SANE_Status -getEdgeSlope (int width, int height, int * top, int * bot, - double slope, int * finXInter, int * finYInter) -{ - - int i; - int topXInter, topYInter; - int botXInter, botYInter; - int leftCount; - - DBG(10,"getEdgeSlope: start\n"); - - topXInter = width; - topYInter = 0; - leftCount = 0; - - for(i=0;i txi){ - topXInter = txi; - topYInter = tyi; - } - - leftCount++; - if(leftCount > 5){ - break; - } - } - else{ - topXInter = width; - topYInter = 0; - leftCount = 0; - } - } - - botXInter = width; - botYInter = 0; - leftCount = 0; - - for(i=0;i -1){ - - int byi = bot[i] - (slope * i); - int bxi = byi/-slope; - - if(botXInter > bxi){ - botXInter = bxi; - botYInter = byi; - } - - leftCount++; - if(leftCount > 5){ - break; - } - } - else{ - botXInter = width; - botYInter = 0; - leftCount = 0; - } - } - - if(botXInter < topXInter){ - *finXInter = botXInter; - *finYInter = botYInter; - } - else{ - *finXInter = topXInter; - *finYInter = topYInter; - } - - DBG(10,"getEdgeSlope: finish\n"); - - return 0; -} - -/* function to do a simple rotation by a given slope, around - * a given point. The point can be outside of image to get - * proper edge alignment. Unused areas filled with bg color - * FIXME: Do in-place rotation to save memory */ -SANE_Status -rotateOnCenter (struct scanner *s, int side, - int centerX, int centerY, double slope) +/* certain scanners require the mode of the + * image to be changed in software. */ +static int +must_downsample(struct scanner *s) { - double slopeRad = -atan(slope); - double slopeSin = sin(slopeRad); - double slopeCos = cos(slopeRad); - - int bwidth = s->i.Bpl; - int pwidth = s->i.width; - int height = s->i.height; - int depth = 1; - int bg_color = s->lut[s->bg_color]; - - unsigned char * outbuf; - int i, j, k; - - DBG(10,"rotateOnCenter: start: %d %d\n",centerX,centerY); - - outbuf = malloc(s->i.bytes_tot[side]); - if(!outbuf){ - DBG(15,"rotateOnCenter: no outbuf\n"); - return SANE_STATUS_NO_MEM; - } - - switch (s->i.mode){ - - case MODE_COLOR: - depth = 3; - - case MODE_GRAYSCALE: - memset(outbuf,bg_color,s->i.bytes_tot[side]); - - for (i=0; i= pwidth) - continue; - - sourceY = centerY + (int)(-shiftY * slopeCos + shiftX * slopeSin); - if (sourceY < 0 || sourceY >= height) - continue; - - for (k=0; kbuffers[side][sourceY*bwidth+sourceX*depth+k]; - } - } - } - break; - - case MODE_LINEART: - case MODE_HALFTONE: - memset(outbuf,(bg_colorthreshold)?0xff:0x00,s->i.bytes_tot[side]); - - for (i=0; i= pwidth) - continue; - - sourceY = centerY + (int)(-shiftY * slopeCos + shiftX * slopeSin); - if (sourceY < 0 || sourceY >= height) - continue; - - /* wipe out old bit */ - outbuf[i*bwidth + j/8] &= ~(1 << (7-(j%8))); - - /* fill in new bit */ - outbuf[i*bwidth + j/8] |= - ((s->buffers[side][sourceY*bwidth + sourceX/8] - >> (7-(sourceX%8))) & 1) << (7-(j%8)); - } - } - break; + if(s->s.mode != s->i.mode + && s->compress != COMP_JPEG + ){ + return 1; } - memcpy(s->buffers[side],outbuf,s->i.bytes_tot[side]); - - free(outbuf); - - DBG(10,"rotateOnCenter: finish\n"); - return 0; } diff --git a/backend/canon_dr.conf.in b/backend/canon_dr.conf.in index 453065b..29b6db1 100644 --- a/backend/canon_dr.conf.in +++ b/backend/canon_dr.conf.in @@ -74,6 +74,7 @@ option duplex-offset 432 usb 0x04a9 0x1608 # DR-3080CII +option padded-read 1 usb 0x04a9 0x1609 # DR-2050C/SP (uses weird protocol) @@ -133,6 +134,9 @@ usb 0x1083 0x1626 # CR-190i usb 0x1083 0x162b +# P-150M +usb 0x1083 0x162c + # DR-6030C usb 0x1083 0x1638 @@ -186,6 +190,7 @@ usb 0x1083 0x1651 usb 0x1083 0x1652 # DR-F120 +option duplex-offset 1640 usb 0x1083 0x1654 # DR-M1060 diff --git a/backend/canon_dr.h b/backend/canon_dr.h index 4a19f55..d96fbba 100644 --- a/backend/canon_dr.h +++ b/backend/canon_dr.h @@ -21,12 +21,12 @@ enum scanner_Option OPT_RES, /*a range or a list*/ OPT_GEOMETRY_GROUP, + OPT_PAGE_WIDTH, + OPT_PAGE_HEIGHT, OPT_TL_X, OPT_TL_Y, OPT_BR_X, OPT_BR_Y, - OPT_PAGE_WIDTH, - OPT_PAGE_HEIGHT, OPT_ENHANCEMENT_GROUP, OPT_BRIGHTNESS, @@ -43,6 +43,7 @@ enum scanner_Option OPT_SWDESKEW, OPT_SWDESPECK, OPT_SWCROP, + OPT_SWSKIP, OPT_STAPLEDETECT, OPT_DROPOUT_COLOR_F, OPT_DROPOUT_COLOR_B, @@ -253,6 +254,7 @@ struct scanner SANE_String_Const compress_list[3]; SANE_Range compress_arg_range; SANE_Range swdespeck_range; + SANE_Range swskip_range; SANE_String_Const do_color_list[8]; /*sensor group*/ @@ -276,13 +278,13 @@ struct scanner int compress_arg; int df_length; int df_thickness; - int dropout_color_f; - int dropout_color_b; + int dropout_color[2]; int buffermode; int rollerdeskew; int swdeskew; int swdespeck; int swcrop; + int swskip; int stapledetect; /* --------------------------------------------------------------------- */ @@ -298,6 +300,24 @@ struct scanner /* the brightness/contrast LUT for dumb scanners */ unsigned char lut[256]; + /* --------------------------------------------------------------------- */ + /* values used by the software enhancment code (deskew, crop, etc) */ + SANE_Status deskew_stat; + int deskew_vals[2]; + double deskew_slope; + + int crop_vals[4]; + + /* this is defined in sane spec as a struct containing: + SANE_Frame format; + SANE_Bool last_frame; + SANE_Int lines; + SANE_Int depth; ( binary=1, gray=8, color=8 (!24) ) + SANE_Int pixels_per_line; + SANE_Int bytes_per_line; + */ + SANE_Parameters s_params; + /* --------------------------------------------------------------------- */ /* values which are set by calibration functions */ int c_res; @@ -429,9 +449,10 @@ enum { #define COLOR_INTERLACE_2510 7 #define DUPLEX_INTERLACE_NONE 0 -#define DUPLEX_INTERLACE_FFBB 1 -#define DUPLEX_INTERLACE_FBFB 2 +#define DUPLEX_INTERLACE_FfBb 1 +#define DUPLEX_INTERLACE_FBfb 2 #define DUPLEX_INTERLACE_2510 3 +#define DUPLEX_INTERLACE_fFBb 4 #define JPEG_INTERLACE_ALT 0 #define JPEG_INTERLACE_NONE 1 @@ -563,27 +584,16 @@ static SANE_Status read_from_scanner_duplex(struct scanner *s, int exact); static SANE_Status copy_simplex(struct scanner *s, unsigned char * buf, int len, int side); static SANE_Status copy_duplex(struct scanner *s, unsigned char * buf, int len); static SANE_Status copy_line(struct scanner *s, unsigned char * buf, int side); +static SANE_Status fill_image(struct scanner *s,int side); + +static int must_downsample (struct scanner *s); +static int must_fully_buffer (struct scanner *s); +static unsigned char calc_bg_color(struct scanner *s); static SANE_Status buffer_despeck(struct scanner *s, int side); static SANE_Status buffer_deskew(struct scanner *s, int side); static SANE_Status buffer_crop(struct scanner *s, int side); - -int * getTransitionsY (struct scanner *s, int side, int top); -int * getTransitionsX (struct scanner *s, int side, int top); - -SANE_Status getEdgeIterate (int width, int height, int resolution, - int * buff, double * finSlope, int * finXInter, int * finYInter); - -SANE_Status getEdgeSlope (int width, int height, int * top, int * bot, - double slope, int * finXInter, int * finYInter); - -SANE_Status rotateOnCenter (struct scanner *s, int side, - int centerX, int centerY, double slope); - -static SANE_Status getLine (int height, int width, int * buff, - int slopes, double minSlope, double maxSlope, - int offsets, int minOffset, int maxOffset, - double * finSlope, int * finOffset, int * finDensity); +static int buffer_isblank(struct scanner *s, int side); static SANE_Status load_lut (unsigned char * lut, int in_bits, int out_bits, int out_min, int out_max, int slope, int offset); @@ -606,4 +616,6 @@ static void default_globals (void); static size_t maxStringSize (const SANE_String_Const strings[]); +static void rmemcpy(void* dest, const void* src, size_t count, size_t stride); + #endif /* CANON_DR_H */ diff --git a/backend/cardscan.c b/backend/cardscan.c index 6442458..eab6500 100644 --- a/backend/cardscan.c +++ b/backend/cardscan.c @@ -3,7 +3,9 @@ This file is part of the SANE package, and implements a SANE backend for various Corex Cardscan scanners. - Copyright (C) 2007-2010 m. allan noah + Copyright (C) 2007-2015 m. allan noah + + -------------------------------------------------------------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -43,8 +45,6 @@ -------------------------------------------------------------------------- - This file implements a SANE backend for the Corex Cardscan 800C - The source code is divided in sections which you can easily find by searching for the tag "@@". @@ -65,6 +65,8 @@ - add has_cal_buffer config option - basic support for 600c - clean #include lines + v3, 2015-11-04, MAN + - add USB IDs for newer model 800c ################################################## DATA FROM TRACE OF WINDOWS DRIVER: @@ -224,7 +226,7 @@ four times { #include "cardscan.h" #define DEBUG 1 -#define BUILD 2 +#define BUILD 3 /* values for SANE_DEBUG_CARDSCAN env var: - errors 5 @@ -490,6 +492,16 @@ attach_one (const char *device_name) s->product_name = "Unknown"; } } + else if(vid == 0x0451){ + s->vendor_name = "Sanford"; + if(pid == 0x6250){ + s->product_name = "800c"; + } + else{ + DBG (5, "Unknown product, using default settings\n"); + s->product_name = "Unknown"; + } + } else{ DBG (5, "Unknown vendor/product, using default settings\n"); s->vendor_name = "Unknown"; @@ -862,7 +874,6 @@ sane_control_option (SANE_Handle handle, SANE_Int option, } else if (action == SANE_ACTION_SET_VALUE) { int tmp; - SANE_Word val_c; SANE_Status status; DBG (20, "sane_control_option: set value for '%s' (%d)\n", s->opt[option].name,option); @@ -883,9 +894,6 @@ sane_control_option (SANE_Handle handle, SANE_Int option, return status; } - /* may have been changed by constrain, so dont copy until now */ - val_c = *(SANE_Word *)val; - /* * Note - for those options which can assume one of a list of * valid values, we can safely assume that they will have diff --git a/backend/cardscan.conf.in b/backend/cardscan.conf.in index 3c49f26..a978e0d 100644 --- a/backend/cardscan.conf.in +++ b/backend/cardscan.conf.in @@ -11,6 +11,9 @@ # Corex Cardscan 800c usb 0x08f0 0x0005 +# Sanford Cardscan 800c +usb 0x0451 0x6250 + # Corex Cardscan 600c has_cal_buffer 0 lines_per_block 1 diff --git a/backend/coolscan.c b/backend/coolscan.c index 6828a16..239b546 100644 --- a/backend/coolscan.c +++ b/backend/coolscan.c @@ -238,7 +238,7 @@ request_sense_parse (unsigned char *sensed_data) case 0x6: if ((0x29 == asc) && (0x0 == ascq)) - DBG (1, "\t%d/%d/%d: Power On, Reset, or Bus Device Reset Occured\n", sense, asc, ascq); + DBG (1, "\t%d/%d/%d: Power On, Reset, or Bus Device Reset Occurred\n", sense, asc, ascq); else if ((0x2a == asc) && (0x1 == ascq)) DBG (1, "\t%d/%d/%d: Mode Parameters Changed\n", sense, asc, ascq); else @@ -1465,21 +1465,20 @@ static int get_inquiery_part_LS30 (Coolscan_t * s, unsigned char part) { int size; - int ret; /* Get length of reponse */ inquiry.cmd[1]=0x01; inquiry.cmd[2]=part; size=4; set_inquiry_return_size (inquiry.cmd, size); - ret = do_scsi_cmd (s->sfd, inquiry.cmd, inquiry.size, - s->buffer, size); + do_scsi_cmd (s->sfd, inquiry.cmd, inquiry.size, + s->buffer, size); size=get_inquiry_length(s->buffer); size+=4; /* then get inquiry with actual size */ set_inquiry_return_size (inquiry.cmd, size); - ret = do_scsi_cmd (s->sfd, inquiry.cmd, inquiry.size, - s->buffer, size); + do_scsi_cmd (s->sfd, inquiry.cmd, inquiry.size, + s->buffer, size); return size; } @@ -1511,18 +1510,17 @@ get_inquiery_LS30 (Coolscan_t * s) { unsigned char part; unsigned char parts[5]; - int size; int i; /* Get vector of inquiery parts */ - size=get_inquiery_part_LS30(s, (unsigned char) 0); + get_inquiery_part_LS30(s, (unsigned char) 0); /* Get the parts of inquiery */ for(i=0;i<5;i++) { parts[i]=((unsigned char *)s->buffer)[4+11+i]; } for(i=0;i<5;i++) { part=parts[i]; - size=get_inquiery_part_LS30 (s, part); + get_inquiery_part_LS30 (s, part); switch(part) { case 0x0c1:/* max size and resolution */ s->adbits = 8; @@ -2029,7 +2027,7 @@ do_cancel (Coolscan_t * scanner) do_eof (scanner); /* close pipe and reposition scanner */ - if (scanner->reader_pid != -1) + if (sanei_thread_is_valid (scanner->reader_pid)) { int exit_status; @@ -2156,7 +2154,7 @@ attach_one (const char *devName) return attach_scanner(devName, 0); } -static RETSIGTYPE +static void sigterm_handler (int signal) { signal = signal; @@ -4093,7 +4091,7 @@ sane_start (SANE_Handle handle) scanner->pipe = fds[0]; scanner->reader_fds = fds[1]; scanner->reader_pid = sanei_thread_begin( reader_process, (void*)scanner ); - if (scanner->reader_pid == -1) + if (!sanei_thread_is_valid (scanner->reader_pid)) { DBG (1, "sane_start: sanei_thread_begin failed (%s)\n", strerror (errno)); @@ -4153,7 +4151,7 @@ sane_cancel (SANE_Handle handle) { Coolscan_t *s = handle; - if (s->reader_pid != -1) + if (sanei_thread_is_valid (s->reader_pid)) { sanei_thread_kill ( s->reader_pid ); sanei_thread_waitpid( s->reader_pid, NULL ); diff --git a/backend/coolscan2.c b/backend/coolscan2.c index 9f9efde..d54bf39 100644 --- a/backend/coolscan2.c +++ b/backend/coolscan2.c @@ -1755,7 +1755,8 @@ cs2_open (const char *device, cs2_interface_t interface, cs2_t ** sp) { SANE_Status status; cs2_t *s; - char *prefix = NULL, *line, *device2; + char *prefix = NULL, *line; + const char *device2; int i; int alloc_failed = 0; SANE_Device **device_list_new; diff --git a/backend/coolscan3.c b/backend/coolscan3.c index a1d6fe6..42814d1 100644 --- a/backend/coolscan3.c +++ b/backend/coolscan3.c @@ -290,7 +290,7 @@ static SANE_Status cs3_convert_options(cs3_t * s); static SANE_Status cs3_scan(cs3_t * s, cs3_scan_t type); static void *cs3_xmalloc(size_t size); static void *cs3_xrealloc(void *p, size_t size); -static void cs3_xfree(const void *p); +static void cs3_xfree(void *p); /* ========================================================================= */ @@ -332,9 +332,9 @@ sane_exit(void) DBG(10, "%s\n", __func__); for (i = 0; i < n_device_list; i++) { - cs3_xfree(device_list[i]->name); - cs3_xfree(device_list[i]->vendor); - cs3_xfree(device_list[i]->model); + cs3_xfree((void *)device_list[i]->name); + cs3_xfree((void *)device_list[i]->vendor); + cs3_xfree((void *)device_list[i]->model); cs3_xfree(device_list[i]); } cs3_xfree(device_list); @@ -1969,9 +1969,9 @@ cs3_open(const char *device, cs3_interface_t interface, cs3_t ** sp) device_list[n_device_list]->type = "film scanner"; if (alloc_failed) { - cs3_xfree(device_list[n_device_list]->name); - cs3_xfree(device_list[n_device_list]->vendor); - cs3_xfree(device_list[n_device_list]->model); + cs3_xfree((void *)device_list[n_device_list]->name); + cs3_xfree((void *)device_list[n_device_list]->vendor); + cs3_xfree((void *)device_list[n_device_list]->model); cs3_xfree(device_list[n_device_list]); } else n_device_list++; @@ -3181,8 +3181,8 @@ cs3_xrealloc(void *p, size_t size) } static void -cs3_xfree(const void *p) +cs3_xfree(void *p) { if (p) - free(p); + free(p); } diff --git a/backend/dc210.c b/backend/dc210.c index acfe99a..32da710 100644 --- a/backend/dc210.c +++ b/backend/dc210.c @@ -1232,7 +1232,6 @@ sane_start (SANE_Handle handle) my_src_ptr src; struct jpeg_error_mgr jerr; - int row_stride; pic_pck[3] = (unsigned char) Camera.current_picture_number - 1; @@ -1263,8 +1262,6 @@ sane_start (SANE_Handle handle) (void) jpeg_read_header (&cinfo, TRUE); dest_mgr = sanei_jpeg_jinit_write_ppm (&cinfo); (void) jpeg_start_decompress (&cinfo); - row_stride = cinfo.output_width * cinfo.output_components; - } Camera.scanning = SANE_TRUE; /* don't overlap scan requests */ diff --git a/backend/dc240.c b/backend/dc240.c index 001a937..74ab2e0 100644 --- a/backend/dc240.c +++ b/backend/dc240.c @@ -810,7 +810,7 @@ change_res (SANE_Int fd, SANE_Byte res) } SANE_Status -sane_init (SANE_Int * version_code, SANE_Auth_Callback UNUSEDARG authorize) +sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize) { SANE_Char f[] = "sane_init"; @@ -962,7 +962,7 @@ static const SANE_Device *devlist[] = { SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool - UNUSEDARG local_only) + __sane_unused__ local_only) { DBG (127, "sane_get_devices called\n"); @@ -1290,7 +1290,7 @@ my_source_mgr; typedef my_source_mgr *my_src_ptr; METHODDEF (void) -jpeg_init_source (j_decompress_ptr UNUSEDARG cinfo) +jpeg_init_source (j_decompress_ptr __sane_unused__ cinfo) { /* nothing to do */ } @@ -1336,7 +1336,7 @@ static SANE_Int linebuffer_index = 0; METHODDEF (void) -jpeg_term_source (j_decompress_ptr UNUSEDARG cinfo) +jpeg_term_source (j_decompress_ptr __sane_unused__ cinfo) { /* no work necessary here */ } @@ -1417,7 +1417,7 @@ sane_start (SANE_Handle handle) my_src_ptr src; struct jpeg_error_mgr jerr; - SANE_Int row_stride, n; + SANE_Int n; SANE_Char f[] = "sane_start"; SANE_Char path[256]; struct cam_dirlist *e; @@ -1476,7 +1476,6 @@ sane_start (SANE_Handle handle) (void) jpeg_read_header (&cinfo, TRUE); dest_mgr = sanei_jpeg_jinit_write_ppm (&cinfo); (void) jpeg_start_decompress (&cinfo); - row_stride = cinfo.output_width * cinfo.output_components; linebuffer_size = 0; linebuffer_index = 0; @@ -1488,7 +1487,7 @@ sane_start (SANE_Handle handle) } SANE_Status -sane_read (SANE_Handle UNUSEDARG handle, SANE_Byte * data, +sane_read (SANE_Handle __sane_unused__ handle, SANE_Byte * data, SANE_Int max_length, SANE_Int * length) { SANE_Int lines = 0; @@ -1582,7 +1581,7 @@ sane_read (SANE_Handle UNUSEDARG handle, SANE_Byte * data, } void -sane_cancel (SANE_Handle UNUSEDARG handle) +sane_cancel (SANE_Handle __sane_unused__ handle) { unsigned char cancel_byte[] = { 0xe4 }; @@ -1621,8 +1620,8 @@ sane_cancel (SANE_Handle UNUSEDARG handle) } SANE_Status -sane_set_io_mode (SANE_Handle UNUSEDARG handle, SANE_Bool - UNUSEDARG non_blocking) +sane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool + __sane_unused__ non_blocking) { /* sane_set_io_mode() is only valid during a scan */ if (Camera.scanning) @@ -1644,7 +1643,7 @@ sane_set_io_mode (SANE_Handle UNUSEDARG handle, SANE_Bool } SANE_Status -sane_get_select_fd (SANE_Handle UNUSEDARG handle, SANE_Int * UNUSEDARG fd) +sane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd) { return SANE_STATUS_UNSUPPORTED; } diff --git a/backend/dc240.h b/backend/dc240.h index 3323fed..fae3628 100644 --- a/backend/dc240.h +++ b/backend/dc240.h @@ -203,12 +203,6 @@ struct cam_dirent long size; }; -#ifdef __GNUC__ -#define UNUSEDARG __attribute__ ((unused)) -#else -#define UNUSEDARG -#endif - #ifdef OLD /* This is the layout of the directory in the camera - Unfortunately, diff --git a/backend/dc25.c b/backend/dc25.c index 2c9e78c..fd7a0db 100644 --- a/backend/dc25.c +++ b/backend/dc25.c @@ -1308,7 +1308,7 @@ convert_pic (char *base_name, int format) { FILE *ifp; unsigned char pic[MAX_IMAGE_SIZE]; - int res, image_size, image_width, net_width, camera_header, components; + int res, image_width, net_width, components; struct pixmap *pp2; DBG (127, "convert_pic() called\n"); @@ -1374,10 +1374,8 @@ convert_pic (char *base_name, int format) * Setup image size with resolution */ - image_size = IMAGE_SIZE (res); image_width = WIDTH (res); net_width = image_width - LEFT_MARGIN - RIGHT_MARGIN (res); - camera_header = CAMERA_HEADER (res); components = (format & SAVE_24BITS) ? 3 : 1; /* @@ -1833,7 +1831,7 @@ change_res (int fd, unsigned char res) } SANE_Status -sane_init (SANE_Int * version_code, SANE_Auth_Callback UNUSEDARG authorize) +sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize) { char dev_name[PATH_MAX], *p; size_t len; @@ -1980,7 +1978,7 @@ static const SANE_Device dev[] = { SANE_Status sane_get_devices (const SANE_Device *** device_list, - SANE_Bool UNUSEDARG local_only) + SANE_Bool __sane_unused__ local_only) { static const SANE_Device *devlist[] = { dev + 0, 0 @@ -2555,7 +2553,7 @@ sane_start (SANE_Handle handle) SANE_Status -sane_read (SANE_Handle UNUSEDARG handle, SANE_Byte * data, +sane_read (SANE_Handle __sane_unused__ handle, SANE_Byte * data, SANE_Int max_length, SANE_Int * length) { DBG (127, "sane_read called, maxlen=%d\n", max_length); @@ -2724,15 +2722,15 @@ sane_read (SANE_Handle UNUSEDARG handle, SANE_Byte * data, } void -sane_cancel (SANE_Handle UNUSEDARG handle) +sane_cancel (SANE_Handle __sane_unused__ handle) { DBG (127, "sane_cancel() called\n"); started = SANE_FALSE; } SANE_Status -sane_set_io_mode (SANE_Handle UNUSEDARG handle, - SANE_Bool UNUSEDARG non_blocking) +sane_set_io_mode (SANE_Handle __sane_unused__ handle, + SANE_Bool __sane_unused__ non_blocking) { /* sane_set_io_mode() is only valid during a scan */ if (started) @@ -2754,7 +2752,7 @@ sane_set_io_mode (SANE_Handle UNUSEDARG handle, } SANE_Status -sane_get_select_fd (SANE_Handle UNUSEDARG handle, SANE_Int UNUSEDARG * fd) +sane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd) { return SANE_STATUS_UNSUPPORTED; } diff --git a/backend/dc25.h b/backend/dc25.h index df95271..fe12f74 100644 --- a/backend/dc25.h +++ b/backend/dc25.h @@ -211,12 +211,6 @@ struct pixmap { unsigned char *planes; }; -#ifdef __GNUC__ -#define UNUSEDARG __attribute__ ((unused)) -#else -#define UNUSEDARG -#endif - /* * Rotations */ diff --git a/backend/dell1600n_net.c b/backend/dell1600n_net.c index d19059b..3586215 100644 --- a/backend/dell1600n_net.c +++ b/backend/dell1600n_net.c @@ -929,6 +929,7 @@ HexDump (int debugLevel, const unsigned char *buf, size_t bufSize) { unsigned int i, j; + size_t lineBufFree; char itemBuf[16] = { 0 }, lineBuf[256] = { 0 }; @@ -943,7 +944,8 @@ HexDump (int debugLevel, const unsigned char *buf, size_t bufSize) sprintf (itemBuf, "%02x ", (const unsigned int) buf[i]); - strncat (lineBuf, itemBuf, sizeof (lineBuf)); + lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1; + strncat (lineBuf, itemBuf, lineBufFree); if ((i + 1) % 16) continue; @@ -960,7 +962,8 @@ HexDump (int debugLevel, const unsigned char *buf, size_t bufSize) { sprintf (itemBuf, "."); } - strncat (lineBuf, itemBuf, sizeof (lineBuf)); + lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1; + strncat (lineBuf, itemBuf, lineBufFree); } /* for j */ @@ -974,7 +977,8 @@ HexDump (int debugLevel, const unsigned char *buf, size_t bufSize) for (j = (i % 16); j < 16; ++j) { - strncat (lineBuf, " ", sizeof (lineBuf)); + lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1; + strncat (lineBuf, " ", lineBufFree); } for (j = 1 + i - ((i + 1) % 16); j < i; ++j) { @@ -986,7 +990,8 @@ HexDump (int debugLevel, const unsigned char *buf, size_t bufSize) { strcpy (itemBuf, "."); } - strncat (lineBuf, itemBuf, sizeof (lineBuf)); + lineBufFree = sizeof (lineBuf) - strlen (lineBuf) - 1; + strncat (lineBuf, itemBuf, lineBufFree); } DBG (debugLevel, "%s\n", lineBuf); } @@ -1335,7 +1340,7 @@ ProcessUdpResponse (unsigned char *pData, size_t size, { unsigned short messageSize, nameSize, valueSize; - unsigned char *pItem, *pEnd, *pValue; + unsigned char *pItem, *pEnd; char sockBuf[SOCK_BUF_SIZE], *pName; struct ComBuf tcpBuf; int nread; @@ -1376,8 +1381,6 @@ ProcessUdpResponse (unsigned char *pData, size_t size, valueSize = (((unsigned short) pItem[0]) << 8) | pItem[1]; pItem += 2; - pValue = pItem; - pItem += valueSize; /* process the item */ diff --git a/backend/dll.c b/backend/dll.c index 5264f11..5eaa046 100644 --- a/backend/dll.c +++ b/backend/dll.c @@ -69,6 +69,26 @@ #if defined(HAVE_DLOPEN) && defined(HAVE_DLFCN_H) # include + /* This works around a pedantic GCC compiler warning. The ISO C + standard says that the behaviour of converting an object pointer + like the void * returned by dlsym() to a function pointer like + void *(*)() is implementation defined. POSIX though guarantees + that this works fine. + + Workaround based on http://stackoverflow.com/a/36385690. Turns + off pedantic warnings for the duration of the definition only. + */ +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wpedantic" +typedef void *(*func_ptr)(void); + +func_ptr +posix_dlsym (void *handle, const char *func) +{ + return dlsym (handle, func); +} +# pragma GCC diagnostic pop + /* Older versions of dlopen() don't define RTLD_NOW and RTLD_LAZY. They all seem to use a mode of 1 to indicate RTLD_NOW and some do not support RTLD_LAZY at all. Hence, unless defined, we define @@ -430,15 +450,17 @@ load (struct backend *be) if (path) { - src_len = strlen (path) + strlen (LIBDIR) + 1 + 1; + src_len = strlen (path) + strlen (DIR_SEP) + strlen(LIBDIR) + 1; src = malloc (src_len); if (!src) { DBG (1, "load: malloc failed: %s\n", strerror (errno)); return SANE_STATUS_NO_MEM; } + if (orig_src) + free (orig_src); orig_src = src; - snprintf (src, src_len, "%s:%s", path, LIBDIR); + snprintf (src, src_len, "%s%s%s", path, DIR_SEP, LIBDIR); } else { @@ -534,7 +556,7 @@ load (struct backend *be) /* First try looking up the symbol without a leading underscore. */ #ifdef HAVE_DLOPEN - op = (void *(*)(void)) dlsym (be->handle, funcname + 1); + op = posix_dlsym (be->handle, funcname + 1); #elif defined(HAVE_SHL_LOAD) shl_findsym ((shl_t *) & (be->handle), funcname + 1, TYPE_UNDEFINED, &op); @@ -559,7 +581,7 @@ load (struct backend *be) { /* Try again, with an underscore prepended. */ #ifdef HAVE_DLOPEN - op = (void *(*)(void)) dlsym (be->handle, funcname); + op = posix_dlsym (be->handle, funcname); #elif defined(HAVE_SHL_LOAD) shl_findsym (be->handle, funcname, TYPE_UNDEFINED, &op); #elif defined(HAVE_NSLINKMODULE) diff --git a/backend/dll.conf.in b/backend/dll.conf.in index ee6f2f1..3ee5428 100644 --- a/backend/dll.conf.in +++ b/backend/dll.conf.in @@ -1,4 +1,12 @@ -# enable the next line if you want to allow access through the network: +# dll.conf - Configuration file for the SANE dynamic backend loader +# +# Backends can also be enabled by configuration snippets under the dll.d/ +# directory -- third party backends can drop their configuration file in +# this in this directory, named after the backend. +# +# The next line enables the network backend; comment it out if you don't +# need to use a remote SANE scanner over the network -- see sane-net(5) +# and saned(8) for details. net abaton agfafocus diff --git a/backend/dmc.c b/backend/dmc.c index 7fc2ae9..c5c57c4 100644 --- a/backend/dmc.c +++ b/backend/dmc.c @@ -1030,7 +1030,6 @@ sane_control_option(SANE_Handle handle, SANE_Int option, { DMC_Camera *c; SANE_Word cap; - SANE_Status status; int i; if (info) *info = 0; @@ -1069,7 +1068,7 @@ sane_control_option(SANE_Handle handle, SANE_Int option, case OPT_IMAGE_MODE: for (i=0; ival[OPT_IMAGE_MODE].s = (SANE_String) ValidModes[i]; if (info) *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; diff --git a/backend/epjitsu-cmd.h b/backend/epjitsu-cmd.h index 77793df..40a5c1a 100644 --- a/backend/epjitsu-cmd.h +++ b/backend/epjitsu-cmd.h @@ -47,40 +47,36 @@ static unsigned char coarseCalData_S1100[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -/*************** fi-60F 150dpi *************/ -/* 1b d1 (set window) before coarse cal (read 1 line of 0x1c20 bytes) */ -static unsigned char setWindowCoarseCal_FI60F_150[] = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, -0x00, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/*************** fi-60F 300dpi gray *************/ +#if 0 +static unsigned char setWindowScan_FI60F_300_g[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x2c, 0x01, 0x2c, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x06, 0xd5, 0x00, 0x00, +0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x80, 0x80, 0x01, 0x6c, 0x01, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -/* 1b d1 (set window) before fine cal (read 16 lines of 0x1c20 bytes) */ -static unsigned char setWindowFineCal_FI60F_150[] = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x2c, 0x03, 0x20, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, -0x00, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x80, 0x80, 0x00, 0x10, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +/*************** fi-60F 400dpi gray *************/ +static unsigned char setWindowScan_FI60F_400_g[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58, 0x01, 0x90, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x09, 0x1c, 0x00, 0x00, +0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x80, 0x80, 0x01, 0xca, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -/* 1b d1 (set window) before gain/offset tables (write 1 line of 0x3840 bytes) */ -static unsigned char setWindowSendCal_FI60F_150[] = { -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x2c, 0x03, 0x20, 0x00, 0x00, -0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, -0x00, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -0x00, 0x00, 0x00, 0x01, 0x10, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + +/*************** fi-60F 600dpi gray *************/ +static unsigned char setWindowScan_FI60F_600_g[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58, 0x02, 0x58, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x60, 0x00, 0x00, 0x0d, 0xaa, 0x00, 0x00, +0x00, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x80, 0x80, 0x01, 0xca, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; -/* 1b c3 (gain?) command header */ -static unsigned char sendCal1Header_FI60F_150[] = { /* plus 0x3840 data bytes */ -0x8c, 0x0f, 0x8c, 0x0f, 0x8c, 0x0f, 0x8c, 0x0f, 0x8c, 0x0f, 0x8c, 0x0f, 0x00, 0x04 -}; -/* 1b c4 (offset?) command header */ -static unsigned char sendCal2Header_FI60F_150[] = { -0x39, 0x3f, 0x39, 0x3f, 0x39, 0x3f, 0x07 -}; -/* 1b d1 (set window) before scan */ +#endif + +/*************** fi-60F 150dpi *************/ static unsigned char setWindowScan_FI60F_150[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x2c, 0x00, 0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x03, 0x6b, 0x00, 0x00, @@ -89,6 +85,15 @@ static unsigned char setWindowScan_FI60F_150[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/*************** fi-60F 200dpi *************/ +static unsigned char setWindowScan_FI60F_200[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x01, 0x2c, 0x00, 0xc8, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x60, 0x00, 0x00, 0x04, 0x8e, 0x00, 0x00, +0x00, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x80, 0x80, 0x01, 0x48, 0x00, 0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + /*************** fi-60F 300dpi *************/ /* 1b d1 (set window) before coarse cal (read 1 line of 0x1c20 bytes) */ static unsigned char setWindowCoarseCal_FI60F_300[] = { @@ -131,6 +136,15 @@ static unsigned char setWindowScan_FI60F_300[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/*************** fi-60F 400dpi *************/ +static unsigned char setWindowScan_FI60F_400[] = { +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x02, 0x58, 0x01, 0x90, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x20, 0x00, 0x00, 0x09, 0x1c, 0x00, 0x00, +0x00, 0x05, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x80, 0x80, 0x01, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + /*************** fi-60F 600dpi *************/ /* 1b d1 (set window) before coarse cal (read 1 line of 0x2160 bytes) */ static unsigned char setWindowCoarseCal_FI60F_600[] = { diff --git a/backend/epjitsu.c b/backend/epjitsu.c index 7d987dc..ce79a20 100644 --- a/backend/epjitsu.c +++ b/backend/epjitsu.c @@ -1,6 +1,14 @@ /* sane - Scanner Access Now Easy. - This file is part of the SANE package. + This file implements a SANE backend for the Fujitsu fi-60F, the + ScanSnap S300/S1300, and (hopefully) other Epson-based scanners. + + Copyright 2007-2015 by m. allan noah + Copyright 2009 by Richard Goedeken + + Development funded by Microdea, Inc., TrueCheck, Inc. and Archivista, GmbH + + -------------------------------------------------------------------------- This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -40,16 +48,6 @@ -------------------------------------------------------------------------- - This file implements a SANE backend for the Fujitsu fi-60F, the - ScanSnap S300/S1300, and (hopefully) other Epson-based scanners. - - Copyright 2007-2010 by m. allan noah - Copyright 2009 by Richard Goedeken - - Development funded by Microdea, Inc., TrueCheck, Inc. and Archivista, GmbH - - -------------------------------------------------------------------------- - The source code is divided in sections which you can easily find by searching for the tag "@@". @@ -151,6 +149,14 @@ - call change_params after changing page_width v28 2015-03-23, MAN - call get_hardware_status before starting scan + v29 2017-03-18, MAN + - fix infinite loop when scaling in Y direction + v30 2017-03-21, MAN + - fix image truncation when using 150 DPI in Y direction + - add 200 and 400 DPI Y direction support for fi-60F/65F + v31 2017-04-09, MAN + - hardware gray support for fi-60F/65F (disabled pending calibration) + - merge fi-60F/65F settings SANE FLOW DIAGRAM @@ -199,7 +205,7 @@ #include "epjitsu-cmd.h" #define DEBUG 1 -#define BUILD 28 +#define BUILD 31 #ifndef MAX3 #define MAX3(a,b,c) ((a) > (b) ? ((a) > (c) ? a : c) : ((b) > (c) ? b : c)) @@ -1770,6 +1776,7 @@ update_transfer_totals(struct transfer * t) /* we hard-code the list (determined from usb snoops) here */ struct model_res { int model; + int mode; int x_res; int y_res; int usb_power; @@ -1802,141 +1809,153 @@ struct model_res { static struct model_res settings[] = { /*S300 AC*/ -/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ - { MODEL_S300, 150, 150, 0, 1296, 32, 2662, 32, 4256*3, 1480*3, 1296, 41, 8512*3, 2960*3, 2592, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S300, MODE_COLOR, 150, 150, 0, 1296, 32, 2662, 32, 4256*3, 1480*3, 1296, 41, 8512*3, 2960*3, 2592, setWindowCoarseCal_S300_150, setWindowFineCal_S300_150, setWindowSendCal_S300_150, sendCal1Header_S300_150, sendCal2Header_S300_150, setWindowScan_S300_150 }, - { MODEL_S300, 225, 200, 0, 1944, 32, 3993, 32, 6144*3, 2100*3, 1944, 28, 8192*3, 2800*3, 2592, + { MODEL_S300, MODE_COLOR, 225, 200, 0, 1944, 32, 3993, 32, 6144*3, 2100*3, 1944, 28, 8192*3, 2800*3, 2592, setWindowCoarseCal_S300_225, setWindowFineCal_S300_225, setWindowSendCal_S300_225, sendCal1Header_S300_225, sendCal2Header_S300_225, setWindowScan_S300_225 }, - { MODEL_S300, 300, 300, 0, 2592, 32, 5324, 32, 8192*3, 2800*3, 2592, 21, 8192*3, 2800*3, 2592, + { MODEL_S300, MODE_COLOR, 300, 300, 0, 2592, 32, 5324, 32, 8192*3, 2800*3, 2592, 21, 8192*3, 2800*3, 2592, setWindowCoarseCal_S300_300, setWindowFineCal_S300_300, setWindowSendCal_S300_300, sendCal1Header_S300_300, sendCal2Header_S300_300, setWindowScan_S300_300 }, - { MODEL_S300, 600, 600, 0, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, + { MODEL_S300, MODE_COLOR, 600, 600, 0, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, setWindowCoarseCal_S300_600, setWindowFineCal_S300_600, setWindowSendCal_S300_600, sendCal1Header_S300_600, sendCal2Header_S300_600, setWindowScan_S300_600 }, /*S300 USB*/ -/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ - { MODEL_S300, 150, 150, 1, 1296, 32, 2662, 32, 7216*3, 2960*3, 1296, 24, 14432*3, 5920*3, 2592, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S300, MODE_COLOR, 150, 150, 1, 1296, 32, 2662, 32, 7216*3, 2960*3, 1296, 24, 14432*3, 5920*3, 2592, setWindowCoarseCal_S300_150_U, setWindowFineCal_S300_150_U, setWindowSendCal_S300_150_U, sendCal1Header_S300_150_U, sendCal2Header_S300_150_U, setWindowScan_S300_150_U }, - { MODEL_S300, 225, 200, 1, 1944, 32, 3993, 32, 10584*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592, + { MODEL_S300, MODE_COLOR, 225, 200, 1, 1944, 32, 3993, 32, 10584*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592, setWindowCoarseCal_S300_225_U, setWindowFineCal_S300_225_U, setWindowSendCal_S300_225_U, sendCal1Header_S300_225_U, sendCal2Header_S300_225_U, setWindowScan_S300_225_U }, - { MODEL_S300, 300, 300, 1, 2592, 32, 5324, 32, 15872*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592, + { MODEL_S300, MODE_COLOR, 300, 300, 1, 2592, 32, 5324, 32, 15872*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592, setWindowCoarseCal_S300_300_U, setWindowFineCal_S300_300_U, setWindowSendCal_S300_300_U, sendCal1Header_S300_300_U, sendCal2Header_S300_300_U, setWindowScan_S300_300_U }, - { MODEL_S300, 600, 600, 1, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, + { MODEL_S300, MODE_COLOR, 600, 600, 1, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, setWindowCoarseCal_S300_600, setWindowFineCal_S300_600, setWindowSendCal_S300_600, sendCal1Header_S300_600, sendCal2Header_S300_600, setWindowScan_S300_600 }, /*S1300i AC*/ -/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ - { MODEL_S1300i, 150, 150, 0, 1296, 32, 2662, 32, 4016*3, 1360*3, 1296, 43, 8032*3, 2720*3, 2592, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S1300i, MODE_COLOR, 150, 150, 0, 1296, 32, 2662, 32, 4016*3, 1360*3, 1296, 43, 8032*3, 2720*3, 2592, setWindowCoarseCal_S1300i_150, setWindowFineCal_S1300i_150, setWindowSendCal_S1300i_150, sendCal1Header_S1300i_150, sendCal2Header_S1300i_150, setWindowScan_S1300i_150 }, - { MODEL_S1300i, 225, 200, 0, 1944, 32, 3993, 32, 6072*3, 2063*3, 1944, 28, 8096*3, 2752*3, 2592, + { MODEL_S1300i, MODE_COLOR, 225, 200, 0, 1944, 32, 3993, 32, 6072*3, 2063*3, 1944, 28, 8096*3, 2752*3, 2592, setWindowCoarseCal_S1300i_225, setWindowFineCal_S1300i_225, setWindowSendCal_S1300i_225, sendCal1Header_S1300i_225, sendCal2Header_S1300i_225, setWindowScan_S1300i_225 }, - { MODEL_S1300i, 300, 300, 0, 2592, 32, 5324, 32, 8096*3, 2751*3, 2592, 21, 8096*3, 2752*3, 2592, + { MODEL_S1300i, MODE_COLOR, 300, 300, 0, 2592, 32, 5324, 32, 8096*3, 2751*3, 2592, 21, 8096*3, 2752*3, 2592, setWindowCoarseCal_S1300i_300, setWindowFineCal_S1300i_300, setWindowSendCal_S1300i_300, sendCal1Header_S1300i_300, sendCal2Header_S1300i_300, setWindowScan_S1300i_300 }, /*NOTE: S1300i uses S300 data blocks for remainder*/ - { MODEL_S1300i, 600, 600, 0, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, + { MODEL_S1300i, MODE_COLOR, 600, 600, 0, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, setWindowCoarseCal_S300_600, setWindowFineCal_S300_600, setWindowSendCal_S300_600, sendCal1Header_S300_600, sendCal2Header_S300_600, setWindowScan_S300_600 }, /*S1300i USB*/ -/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ - { MODEL_S1300i, 150, 150, 1, 1296, 32, 2662, 32, 7216*3, 2960*3, 1296, 24, 14432*3, 5920*3, 2592, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S1300i, MODE_COLOR, 150, 150, 1, 1296, 32, 2662, 32, 7216*3, 2960*3, 1296, 24, 14432*3, 5920*3, 2592, setWindowCoarseCal_S300_150_U, setWindowFineCal_S300_150_U, setWindowSendCal_S300_150_U, sendCal1Header_S1300i_USB, sendCal2Header_S1300i_USB, setWindowScan_S300_150_U }, - { MODEL_S1300i, 225, 200, 1, 1944, 32, 3993, 32, 10584*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592, + { MODEL_S1300i, MODE_COLOR, 225, 200, 1, 1944, 32, 3993, 32, 10584*3, 4320*3, 1944, 16, 14112*3, 5760*3, 2592, setWindowCoarseCal_S300_225_U, setWindowFineCal_S300_225_U, setWindowSendCal_S300_225_U, sendCal1Header_S1300i_USB, sendCal2Header_S1300i_USB, setWindowScan_S300_225_U }, - { MODEL_S1300i, 300, 300, 1, 2592, 32, 5324, 32, 15872*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592, + { MODEL_S1300i, MODE_COLOR, 300, 300, 1, 2592, 32, 5324, 32, 15872*3, 6640*3, 2592, 11, 15872*3, 6640*3, 2592, setWindowCoarseCal_S300_300_U, setWindowFineCal_S300_300_U, setWindowSendCal_S300_300_U, sendCal1Header_S1300i_USB, sendCal2Header_S1300i_USB, setWindowScan_S300_300_U }, - { MODEL_S1300i, 600, 600, 1, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, + { MODEL_S1300i, MODE_COLOR, 600, 600, 1, 5184, 32, 10648, 32, 16064*3, 5440*3, 5184, 10, 16064*3, 5440*3, 5184, setWindowCoarseCal_S300_600, setWindowFineCal_S300_600, setWindowSendCal_S300_600, sendCal1Header_S1300i_USB, sendCal2Header_S1300i_USB, setWindowScan_S300_600 }, - /*fi-60F*/ -/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ - { MODEL_FI60F, 300, 150, 0, 1296, 32, 875, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, - setWindowCoarseCal_FI60F_150, setWindowFineCal_FI60F_150, - setWindowSendCal_FI60F_150, sendCal1Header_FI60F_150, - sendCal2Header_FI60F_150, setWindowScan_FI60F_150 }, - - { MODEL_FI60F, 300, 300, 0, 1296, 32, 1749, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, + /*fi-60F/65F GRAY */ +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ +/* disabled until calibration code supports grayscale + { MODEL_FI60F | MODEL_FI65F, MODE_GRAYSCALE, 300, 300, 0, 1296, 32, 1749, 32, 1440, 480, 432, 364, 2400*3, 958*3, 432, setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, - sendCal2Header_FI60F_300, setWindowScan_FI60F_300 }, + sendCal2Header_FI60F_300, setWindowScan_FI60F_300_g }, - { MODEL_FI60F, 600, 600, 0, 2592, 32, 3498, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864, + { MODEL_FI60F | MODEL_FI65F, MODE_GRAYSCALE, 600, 400, 0, 2592, 32, 2332, 32, 2592, 864, 864, 202, 2848*3, 978*3, 864, setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, - sendCal2Header_FI60F_600, setWindowScan_FI60F_600 }, + sendCal2Header_FI60F_600, setWindowScan_FI60F_400_g }, - /*fi-65F*/ -/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ - { MODEL_FI65F, 300, 150, 0, 1296, 32, 875, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, - setWindowCoarseCal_FI60F_150, setWindowFineCal_FI60F_150, - setWindowSendCal_FI60F_150, sendCal1Header_FI60F_150, - sendCal2Header_FI60F_150, setWindowScan_FI60F_150 }, + { MODEL_FI60F | MODEL_FI65F, MODE_GRAYSCALE, 600, 600, 0, 2592, 32, 3498, 32, 2592, 864, 864, 202, 2848*3, 978*3, 864, + setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, + setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, + sendCal2Header_FI60F_600, setWindowScan_FI60F_600_g }, +*/ + + /*fi-60F/65F*/ +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 300, 150, 0, 1296, 32, 875, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, + setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, + setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, + sendCal2Header_FI60F_300, setWindowScan_FI60F_150 }, - { MODEL_FI65F, 300, 300, 0, 1296, 32, 1749, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 300, 200, 0, 1296, 32, 1166, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, + setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, + setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, + sendCal2Header_FI60F_300, setWindowScan_FI60F_200 }, + + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 300, 300, 0, 1296, 32, 1749, 32, 2400*3, 958*3, 432, 72, 2400*3, 958*3, 432, setWindowCoarseCal_FI60F_300, setWindowFineCal_FI60F_300, setWindowSendCal_FI60F_300, sendCal1Header_FI60F_300, sendCal2Header_FI60F_300, setWindowScan_FI60F_300 }, - { MODEL_FI65F, 600, 600, 0, 2592, 32, 3498, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864, + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 600, 400, 0, 2592, 32, 2332, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864, + setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, + setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, + sendCal2Header_FI60F_600, setWindowScan_FI60F_400 }, + + { MODEL_FI60F | MODEL_FI65F, MODE_COLOR, 600, 600, 0, 2592, 32, 3498, 32, 2848*3, 978*3, 864, 61, 2848*3, 978*3, 864, setWindowCoarseCal_FI60F_600, setWindowFineCal_FI60F_600, setWindowSendCal_FI60F_600, sendCal1Header_FI60F_600, sendCal2Header_FI60F_600, setWindowScan_FI60F_600 }, /*S1100 USB*/ -/* model xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ - { MODEL_S1100, 300, 300, 1, 2592, 32, 5324, 32, 8912, 3160, 2592, 58, 8912, 3160, 2592, +/* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ + { MODEL_S1100, MODE_COLOR, 300, 300, 1, 2592, 32, 5324, 32, 8912, 3160, 2592, 58, 8912, 3160, 2592, setWindowCoarseCal_S1100_300_U, setWindowFineCal_S1100_300_U, setWindowSendCal_S1100_300_U, sendCal1Header_S1100_300_U, sendCal2Header_S1100_300_U, setWindowScan_S1100_300_U }, - { MODEL_S1100, 600, 600, 1, 5184, 32, 10648, 32, 15904, 5360, 5184, 32, 15904, 5360, 5184, + { MODEL_S1100, MODE_COLOR, 600, 600, 1, 5184, 32, 10648, 32, 15904, 5360, 5184, 32, 15904, 5360, 5184, setWindowCoarseCal_S1100_600_U, setWindowFineCal_S1100_600_U, setWindowSendCal_S1100_600_U, sendCal1Header_S1100_600_U, sendCal2Header_S1100_600_U, setWindowScan_S1100_600_U }, - { MODEL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + { MODEL_NONE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL }, }; @@ -1955,7 +1974,8 @@ change_params(struct scanner *s) DBG (10, "change_params: start\n"); do { - if(settings[i].model == s->model + if(settings[i].model & s->model + && settings[i].mode <= s->mode && settings[i].x_res >= s->resolution && settings[i].y_res >= s->resolution && settings[i].usb_power == s->usb_power @@ -2038,11 +2058,12 @@ change_params(struct scanner *s) s->br_x = (s->max_x + s->page_width)/2; /*=============================================================*/ - /* set up the calibration structs */ + /* set up the calibration scan structs */ /* generally full width, short height, full resolution */ s->cal_image.line_stride = settings[i].cal_line_stride; s->cal_image.plane_stride = settings[i].cal_plane_stride; s->cal_image.plane_width = settings[i].cal_plane_width; + s->cal_image.mode = MODE_COLOR; s->cal_image.x_res = settings[i].x_res; s->cal_image.y_res = settings[i].y_res; s->cal_image.raw_data = NULL; @@ -2052,38 +2073,19 @@ change_params(struct scanner *s) s->cal_data.line_stride = settings[i].cal_line_stride * 2; s->cal_data.plane_stride = settings[i].cal_plane_stride * 2; s->cal_data.plane_width = settings[i].cal_plane_width; + s->cal_data.mode = MODE_COLOR; s->cal_data.x_res = settings[i].x_res; s->cal_data.y_res = settings[i].y_res; s->cal_data.raw_data = NULL; s->cal_data.image = &s->sendcal; /*=============================================================*/ - /* set up the input scan structs */ - s->block_xfr.line_stride = settings[i].line_stride; - s->block_xfr.plane_stride = settings[i].plane_stride; - s->block_xfr.plane_width = settings[i].plane_width; - s->block_xfr.x_res = settings[i].x_res; - s->block_xfr.y_res = settings[i].y_res; - s->block_xfr.raw_data = NULL; - s->block_xfr.image = &s->block_img; - - /* set up the block image used during scanning operation */ - /* note that this is the same width/x_res as the final output image */ - /* but the height/y_res are the same as block_xfr */ - width = (s->block_xfr.plane_width*s->resolution/settings[i].x_res) * img_heads; - s->block_img.width_pix = width; - s->block_img.width_bytes = width * 3; - s->block_img.height = settings[i].block_height; - s->block_img.x_res = s->resolution; - s->block_img.y_res = settings[i].y_res; - s->block_img.pages = img_pages; - s->block_img.buffer = NULL; - /* set up the calibration image blocks */ width = s->cal_image.plane_width * img_heads; s->coarsecal.width_pix = s->darkcal.width_pix = s->lightcal.width_pix = width; s->coarsecal.width_bytes = s->darkcal.width_bytes = s->lightcal.width_bytes = width * 3; s->coarsecal.height = 1; + s->coarsecal.mode = MODE_COLOR; s->coarsecal.x_res = s->darkcal.x_res = s->lightcal.x_res = settings[i].x_res; s->coarsecal.y_res = s->darkcal.y_res = s->lightcal.y_res = settings[i].y_res; s->darkcal.height = s->lightcal.height = 16; @@ -2095,13 +2097,18 @@ change_params(struct scanner *s) s->sendcal.width_pix = width; s->sendcal.width_bytes = width * 6; /* 2 bytes of cal data per pixel component */ s->sendcal.height = 1; + s->sendcal.mode = MODE_COLOR; s->sendcal.x_res = settings[i].x_res; s->sendcal.y_res = settings[i].y_res; s->sendcal.pages = img_pages; s->sendcal.buffer = NULL; + /*=============================================================*/ /* set up the fullscan parameters */ - s->fullscan.width_bytes = s->block_xfr.line_stride; + /* this is bookkeeping for what we actually pull from the scanner */ + /* note that this has no image, just dimensions and counters */ + s->fullscan.width_bytes = settings[i].line_stride; + s->fullscan.mode = settings[i].mode; s->fullscan.x_res = settings[i].x_res; s->fullscan.y_res = settings[i].y_res; if(s->source == SOURCE_FLATBED || !s->page_height) @@ -2115,9 +2122,35 @@ change_params(struct scanner *s) s->fullscan.height = SCANNER_UNIT_TO_PIX((s->page_height + s->tl_y + s->adf_height_padding), s->fullscan.y_res); } + /*=============================================================*/ + /* set up the input block raw struct */ + /* this holds up to 512k of raw scan data */ + s->block_xfr.line_stride = settings[i].line_stride; + s->block_xfr.plane_stride = settings[i].plane_stride; + s->block_xfr.plane_width = settings[i].plane_width; + s->block_xfr.mode = settings[i].mode; + s->block_xfr.x_res = settings[i].x_res; + s->block_xfr.y_res = settings[i].y_res; + s->block_xfr.raw_data = NULL; + s->block_xfr.image = &s->block_img; + + /* set up the input block image struct */ + /* note that this is the same width/x_res as the final output image */ + /* but the mode, height and y_res are the same as block_xfr */ + width = (settings[i].max_x * s->resolution / settings[i].x_res); + s->block_img.width_pix = width; + s->block_img.width_bytes = width * (settings[i].mode == MODE_COLOR ? 3 : 1); + s->block_img.height = settings[i].block_height; + s->block_img.mode = settings[i].mode; + s->block_img.x_res = s->resolution; + s->block_img.y_res = settings[i].y_res; + s->block_img.pages = img_pages; + s->block_img.buffer = NULL; + /*=============================================================*/ /* set up the output image structs */ /* output image might be different from scan due to interpolation */ + s->front.mode = s->mode; s->front.x_res = s->resolution; s->front.y_res = s->resolution; if(s->source == SOURCE_FLATBED) @@ -2170,6 +2203,7 @@ change_params(struct scanner *s) /* back settings always same as front settings */ s->back.width_pix = s->front.width_pix; s->back.width_bytes = s->front.width_bytes; + s->back.mode = s->front.mode; s->back.x_res = s->front.x_res; s->back.y_res = s->front.y_res; s->back.height = s->front.height; @@ -2182,6 +2216,7 @@ change_params(struct scanner *s) /* dynamic threshold temp buffer, in gray */ s->dt.width_pix = s->front.width_pix; s->dt.width_bytes = s->front.width_pix; + s->dt.mode = MODE_GRAYSCALE; s->dt.x_res = s->front.x_res; s->dt.y_res = s->front.y_res; s->dt.height = 1; @@ -3955,7 +3990,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len { DBG (15, "sane_read: block buffer full\n"); - /* convert the raw data into normal packed pixel data */ + /* convert the raw color data into normal packed pixel data */ descramble_raw(s, &s->block_xfr); s->block_xfr.done = 0; @@ -4095,6 +4130,8 @@ six5 (struct scanner *s) /* de-scrambles the raw data from the scanner into the image buffer */ /* the output image might be lower dpi than input image, so we scale horizontally */ +/* if the input image is mirrored left to right, we do not correct it here */ +/* if the input image has padding (at the end or between heads), it is removed here */ static SANE_Status descramble_raw(struct scanner *s, struct transfer * tp) { @@ -4103,6 +4140,13 @@ descramble_raw(struct scanner *s, struct transfer * tp) int height = tp->total_bytes / tp->line_stride; int i, j, k; + /* raw gray data handled in another function */ + if(tp->mode == MODE_GRAYSCALE){ + return descramble_raw_gray(s, tp); + } + + DBG(15, "descramble_raw: start\n"); + if (s->model == MODEL_S300 || s->model == MODEL_S1300i) { for (i = 0; i < 2; i++){ /* page, front/back */ for (j = 0; j < height; j++){ /* row (y)*/ @@ -4233,6 +4277,47 @@ descramble_raw(struct scanner *s, struct transfer * tp) } } + DBG(15, "descramble_raw: finish %d\n", ret); + + return ret; +} + +/* de-scrambles the raw gray data from the scanner into the image buffer */ +/* the output image might be lower dpi than input image, so we scale horizontally */ +/* if the input image is mirrored left to right, we do not correct it here */ +/* if the input image has padding (at the end or between heads), it is removed here */ +static SANE_Status +descramble_raw_gray(struct scanner *s, struct transfer * tp) +{ + SANE_Status ret = SANE_STATUS_GOOD; + int height = tp->total_bytes / tp->line_stride; + int row, col_out; + + DBG(15, "descramble_raw_gray: start\n"); + + if (s->model == MODEL_FI60F || s->model == MODEL_FI65F) { + for (row = 0; row < height; row++){ + + unsigned char *p_in = tp->raw_data + row * tp->line_stride; + unsigned char *p_out = tp->image->buffer + row * tp->image->width_pix; + + for (col_out = 0; col_out < tp->image->width_pix; col_out++){ + int col_in = col_out * tp->x_res/tp->image->x_res; + int offset = col_in%tp->plane_width; + int step = col_in/tp->plane_width; + + *p_out = *(p_in + offset*3 + step); + p_out++; + } + } + } + + else{ + DBG(5, "internal error: descramble_raw_gray not supported\n"); + ret = SANE_STATUS_INVAL; + } + + DBG(15, "descramble_raw_gray: finish %d\n", ret); return ret; } @@ -4313,8 +4398,10 @@ read_from_scanner(struct scanner *s, struct transfer * tp) } /* copies block buffer into front or back image buffer */ -/* converts pixel data from RGB Color to the output format */ +/* converts pixel data from input mode (color/gray) to output mode (color/gray/binary) */ /* the output image might be lower dpi than input image, so we scale vertically */ +/* the input is already scaled horizontally and padding skipped if required */ +/* if the input is mirrored left to right, we fix it here */ static SANE_Status copy_block_to_page(struct scanner *s,int side) { @@ -4322,11 +4409,10 @@ copy_block_to_page(struct scanner *s,int side) struct transfer * block = &s->block_xfr; struct page * page = &s->pages[side]; int image_height = block->total_bytes / block->line_stride; - int page_height = SCANNER_UNIT_TO_PIX(s->page_height, s->resolution); int page_width = page->image->width_pix; int block_page_stride = block->image->width_bytes * block->image->height; int line_reverse = (side == SIDE_BACK) || (s->model == MODEL_FI60F) || (s->model == MODEL_FI65F); - int i,j,k=0,l=0; + int i,j,k=0; int curr_in_row = s->fullscan.rx_bytes/s->fullscan.width_bytes; int last_out_row = (page->bytes_scanned / page->image->width_bytes) - 1; @@ -4334,7 +4420,7 @@ copy_block_to_page(struct scanner *s,int side) DBG (10, "copy_block_to_page: start\n"); /* skip padding and tl_y */ - if (s->fullscan.rx_bytes + s->block_xfr.rx_bytes < block->line_stride * page->image->y_skip_offset) + if (s->fullscan.rx_bytes + s->block_xfr.rx_bytes <= block->line_stride * page->image->y_skip_offset) { DBG (10, "copy_block_to_page: before the start? %d\n", side); return ret; @@ -4345,25 +4431,8 @@ copy_block_to_page(struct scanner *s,int side) DBG (10, "copy_block_to_page: k start? %d\n", k); } - /* skip trailer */ - if (s->page_height) - { - DBG (10, "copy_block_to_page: ph %d\n", s->page_height); - if (s->fullscan.rx_bytes > block->line_stride * page->image->y_skip_offset + page_height * block->line_stride) - { - DBG (10, "copy_block_to_page: off the end? %d\n", side); - return ret; - } - else if (s->fullscan.rx_bytes + s->block_xfr.rx_bytes - > block->line_stride * page->image->y_skip_offset + page_height * block->line_stride) - { - l = (s->fullscan.rx_bytes + s->block_xfr.rx_bytes) / block->line_stride - - page_height - page->image->y_skip_offset; - } - } - /* loop over all the lines in the block */ - for (i = k; i < image_height-l; i++) + for (i = k; i < image_height; i++) { /* determine source and dest rows (dpi scaling) */ int this_in_row = curr_in_row + i; @@ -4389,13 +4458,15 @@ copy_block_to_page(struct scanner *s,int side) last_out_row = this_out_row; - /* reverse order for back side or FI-60F scanner */ - if (line_reverse) + if (block->mode == MODE_COLOR){ + + /* reverse order for back side or FI-60F scanner */ + if (line_reverse) p_in += (page_width - 1) * 3; - - /* convert all of the pixels in this row */ - for (j = 0; j < page_width; j++) - { + + /* convert all of the pixels in this row */ + for (j = 0; j < page_width; j++) + { unsigned char r, g, b; if (s->model == MODEL_S300 || s->model == MODEL_S1300i) { r = p_in[1]; g = p_in[2]; b = p_in[0]; } @@ -4413,12 +4484,41 @@ copy_block_to_page(struct scanner *s,int side) } else if (s->mode == MODE_LINEART) { - s->dt.buffer[j] = (r + g + b) / 3; /* stores dt temp image buffer and binarize afterword */ + s->dt.buffer[j] = (r + g + b) / 3; /* stores dt temp image buffer and binarize afterward */ } if (line_reverse) p_in -= 3; else p_in += 3; + } + } + + /* grayscale input */ + else{ + unsigned char * p_in = block->image->buffer + (side * block_page_stride) + + (i * block->image->width_bytes) + page->image->x_start_offset; + + /* reverse order for back side or FI-60F scanner */ + if (line_reverse) + p_in += (page_width - 1); + + //memcpy(p_out,p_in,page->image->width_bytes); + + for (j = 0; j < page_width; j++) + { + if (s->mode == MODE_GRAYSCALE) + { + *p_out++ = *p_in; + } + else if (s->mode == MODE_LINEART) + { + s->dt.buffer[j] = *p_in; /* stores dt temp image buffer and binarize afterward */ + } + if (line_reverse) + p_in--; + else + p_in++; + } } /* skip non-transfer pixels in block image buffer */ @@ -4576,13 +4676,13 @@ destroy(struct scanner *s) teardown_buffers(s); if(s->sane.name){ - free(s->sane.name); + free((void *) s->sane.name); } if(s->sane.vendor){ - free(s->sane.vendor); + free((void *) s->sane.vendor); } if(s->sane.model){ - free(s->sane.model); + free((void *) s->sane.model); } free(s); diff --git a/backend/epjitsu.conf.in b/backend/epjitsu.conf.in index 155befc..3ba1c15 100644 --- a/backend/epjitsu.conf.in +++ b/backend/epjitsu.conf.in @@ -61,14 +61,23 @@ usb 0x04c5 0x1156 firmware @DATADIR@/sane/epjitsu/300M_0C00.nal usb 0x04c5 0x117f -# Fujitsu S1100 -firmware @DATADIR@/sane/epjitsu/1100_0B00.nal -usb 0x04c5 0x1200 +# Fujitsu fi-65F +firmware @DATADIR@/sane/epjitsu/65f_0A01.nal +usb 0x04c5 0x11bd # Fujitsu S1300 firmware @DATADIR@/sane/epjitsu/1300_0C26.nal usb 0x04c5 0x11ed +# Fujitsu S1100 +firmware @DATADIR@/sane/epjitsu/1100_0B00.nal +usb 0x04c5 0x1200 + # Fujitsu S1300i firmware @DATADIR@/sane/epjitsu/1300i_0D12.nal usb 0x04c5 0x128d + +# Fujitsu S1100i +firmware @DATADIR@/sane/epjitsu/1100i_0A00.nal +usb 0x04c5 0x1447 + diff --git a/backend/epjitsu.h b/backend/epjitsu.h index 7bb1ccc..6dfaf67 100644 --- a/backend/epjitsu.h +++ b/backend/epjitsu.h @@ -55,6 +55,7 @@ struct image { int width_bytes; int height; int pages; + int mode; int x_res; int y_res; int x_start_offset; @@ -71,6 +72,7 @@ struct transfer { int total_bytes; int rx_bytes; int done; + int mode; int x_res; int y_res; @@ -216,6 +218,7 @@ struct scanner /* the scan struct holds these larger numbers, but image buffer is unused */ struct { int done; + int mode; int x_res; int y_res; int height; @@ -259,12 +262,12 @@ struct scanner int hw_sleep; }; -#define MODEL_NONE 0 -#define MODEL_S300 1 -#define MODEL_FI60F 2 -#define MODEL_S1100 3 -#define MODEL_S1300i 4 -#define MODEL_FI65F 5 +#define MODEL_NONE (1<<0) +#define MODEL_S300 (1<<1) +#define MODEL_FI60F (1<<2) +#define MODEL_S1100 (1<<3) +#define MODEL_S1300i (1<<4) +#define MODEL_FI65F (1<<5) #define USB_COMMAND_TIME 10000 #define USB_DATA_TIME 10000 @@ -378,6 +381,7 @@ static SANE_Status set_window(struct scanner *s, int window); static SANE_Status scan(struct scanner *s); static SANE_Status read_from_scanner(struct scanner *s, struct transfer *tp); +static SANE_Status descramble_raw_gray(struct scanner *s, struct transfer * tp); static SANE_Status descramble_raw(struct scanner *s, struct transfer * tp); static SANE_Status copy_block_to_page(struct scanner *s, int side); static SANE_Status binarize_line(struct scanner *s, unsigned char *lineOut, int width); diff --git a/backend/epson.c b/backend/epson.c index 6b111f2..3fc264f 100644 --- a/backend/epson.c +++ b/backend/epson.c @@ -4232,7 +4232,7 @@ SANE_Status sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) { Epson_Scanner *s = (Epson_Scanner *) handle; - int ndpi, max_x, max_y; + int ndpi; int bytes_per_pixel; DBG (5, "sane_get_parameters()\n"); @@ -4270,8 +4270,6 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) ndpi = s->val[OPT_RESOLUTION].w; - max_x = max_y = 0; - s->params.pixels_per_line = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w) / 25.4 * ndpi + 0.5; s->params.lines = @@ -5271,7 +5269,6 @@ sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, int index = 0; SANE_Bool reorder = SANE_FALSE; SANE_Bool needStrangeReorder = SANE_FALSE; - int bytes_to_process = 0; START_READ: DBG (5, "sane_read: begin\n"); @@ -5447,9 +5444,7 @@ START_READ: reorder = SANE_TRUE; } - bytes_to_process = receive (s, s->buf, buf_len, &status); - - /* bytes_to_process = buf_len; */ + receive (s, s->buf, buf_len, &status); if (SANE_STATUS_GOOD != status) { diff --git a/backend/epson2-io.c b/backend/epson2-io.c index 4477963..9d23e2a 100644 --- a/backend/epson2-io.c +++ b/backend/epson2-io.c @@ -113,32 +113,37 @@ ssize_t e2_recv(Epson_Scanner *s, void *buf, ssize_t buf_size, SANE_Status *status) { - ssize_t n = 0; + ssize_t n = buf_size; /* network interface needs to read header back even data is 0.*/ DBG(15, "%s: size = %ld, buf = %p\n", __func__, (long) buf_size, buf); + *status = SANE_STATUS_GOOD; if (s->hw->connection == SANE_EPSON_NET) { n = sanei_epson_net_read(s, buf, buf_size, status); } else if (s->hw->connection == SANE_EPSON_SCSI) { - n = sanei_epson2_scsi_read(s->fd, buf, buf_size, status); + if (buf_size) + n = sanei_epson2_scsi_read(s->fd, buf, buf_size, status); } else if (s->hw->connection == SANE_EPSON_PIO) { - if (buf_size == - (n = sanei_pio_read(s->fd, buf, (size_t) buf_size))) - *status = SANE_STATUS_GOOD; - else - *status = SANE_STATUS_INVAL; + if (buf_size) { + if (buf_size == + (n = sanei_pio_read(s->fd, buf, (size_t) buf_size))) + *status = SANE_STATUS_GOOD; + else + *status = SANE_STATUS_INVAL; + } } else if (s->hw->connection == SANE_EPSON_USB) { /* !!! only report an error if we don't read anything */ - n = buf_size; /* buf_size gets overwritten */ - *status = - sanei_usb_read_bulk(s->fd, (SANE_Byte *) buf, - (size_t *) & n); - r_cmd_count += (n + 63) / 64; /* add # of packets, rounding up */ - DBG(20, "%s: cmd count, r = %d, w = %d\n", - __func__, r_cmd_count, w_cmd_count); - - if (n > 0) - *status = SANE_STATUS_GOOD; + if (n) { + *status = + sanei_usb_read_bulk(s->fd, (SANE_Byte *) buf, + (size_t *) & n); + r_cmd_count += (n + 63) / 64; /* add # of packets, rounding up */ + DBG(20, "%s: cmd count, r = %d, w = %d\n", + __func__, r_cmd_count, w_cmd_count); + + if (n > 0) + *status = SANE_STATUS_GOOD; + } } if (n < buf_size) { @@ -170,18 +175,23 @@ e2_txrx(Epson_Scanner * s, unsigned char *txbuf, size_t txlen, unsigned char *rxbuf, size_t rxlen) { SANE_Status status; + size_t done; - e2_send(s, txbuf, txlen, rxlen, &status); + done = e2_send(s, txbuf, txlen, rxlen, &status); if (status != SANE_STATUS_GOOD) { DBG(1, "%s: tx err, %s\n", __func__, sane_strstatus(status)); return status; } + if (done != txlen) { + DBG(1, "%s: tx err, short write\n", __func__); + return SANE_STATUS_IO_ERROR; + } e2_recv(s, rxbuf, rxlen, &status); if (status != SANE_STATUS_GOOD) { DBG(1, "%s: rx err, %s\n", __func__, sane_strstatus(status)); } - + DBG(1, "%s: eds_recv status, %s\n", __func__, sane_strstatus(status)); return status; } diff --git a/backend/epson2-ops.c b/backend/epson2-ops.c index eac01b0..1ba2292 100644 --- a/backend/epson2-ops.c +++ b/backend/epson2-ops.c @@ -2087,7 +2087,6 @@ e2_block_read(struct Epson_Scanner *s) { SANE_Status status; SANE_Bool reorder = SANE_FALSE; - SANE_Bool needStrangeReorder = SANE_FALSE; START_READ: DBG(18, "%s: begin\n", __func__); @@ -2149,22 +2148,6 @@ e2_block_read(struct Epson_Scanner *s) * are doing this here: */ - /* - * Some scanners (e.g. the Perfection 1640 and GT-2200) seem - * to have the R and G channels swapped. - * The GT-8700 is the Asian version of the Perfection 1640. - * If the scanner name is one of these and the scan mode is - * RGB then swap the colors. - */ - - /* never used, beta testers required */ - needStrangeReorder = - (strstr(s->hw->model, "GT-2200") || - ((strstr(s->hw->model, "1640") - && strstr(s->hw->model, "Perfection")) - || strstr(s->hw->model, "GT-8700"))) - && s->params.format == SANE_FRAME_RGB; - /* * Certain Perfection 1650 also need this re-ordering of the two * color channels. These scanners are identified by the problem diff --git a/backend/epson2.h b/backend/epson2.h index 8650f01..773c7de 100644 --- a/backend/epson2.h +++ b/backend/epson2.h @@ -45,13 +45,6 @@ #include "sane/sanei_backend.h" #include "sane/sanei_debug.h" -#ifdef __GNUC__ -#define __func__ __FUNCTION__ -#else -#define __func__ "(undef)" -/* I cast my vote for C99... :) */ -#endif - #define EPSON2_CONFIG_FILE "epson2.conf" #ifndef PATH_MAX diff --git a/backend/epson2_net.c b/backend/epson2_net.c index 911ce62..4b3e7e9 100644 --- a/backend/epson2_net.c +++ b/backend/epson2_net.c @@ -104,7 +104,7 @@ sanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, size = be32atoh(&header[6]); - DBG(23, "%s: wanted = %lu, available = %lu\n", __FUNCTION__, + DBG(23, "%s: wanted = %lu, available = %lu\n", __func__, (u_long) wanted, (u_long) size); *status = SANE_STATUS_GOOD; @@ -170,7 +170,7 @@ sanei_epson_net_write(Epson_Scanner *s, unsigned int cmd, const unsigned char *b } DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n", - __FUNCTION__, cmd, buf, (u_long) buf_size, (u_long) reply_len); + __func__, cmd, buf, (u_long) buf_size, (u_long) reply_len); memset(h1, 0x00, 12); memset(h2, 0x00, 8); diff --git a/backend/epson2_scsi.c b/backend/epson2_scsi.c index 89394cd..8e95c6f 100644 --- a/backend/epson2_scsi.c +++ b/backend/epson2_scsi.c @@ -32,7 +32,7 @@ sanei_epson2_scsi_sense_handler(int scsi_fd, if (result[0] && result[0] != 0x70) { DBG(2, "%s: sense code = 0x%02x\n", - __FUNCTION__, result[0]); + __func__, result[0]); return SANE_STATUS_IO_ERROR; } else { return SANE_STATUS_GOOD; diff --git a/backend/epsonds-cmd.c b/backend/epsonds-cmd.c index b91f3f1..9a4db30 100644 --- a/backend/epsonds-cmd.c +++ b/backend/epsonds-cmd.c @@ -21,6 +21,7 @@ #include "epsonds-io.h" #include "epsonds-cmd.h" #include "epsonds-ops.h" +#include "epsonds-net.h" static SANE_Status esci2_parse_block(char *buf, int len, void *userdata, SANE_Status (*cb)(void *userdata, char *token, int len)) @@ -132,49 +133,39 @@ static SANE_Status esci2_cmd(epsonds_scanner* s, { SANE_Status status; unsigned int more; - char rbuf[64]; + char header[13], rbuf[64]; /* add one more byte for header buffer to correct buffer overflow issue,*/ DBG(8, "%s: %4s len %lu, payload len: %lu\n", __func__, cmd, len, plen); - if (len < 12) { - DBG(1, "%s: command is too short (%lu)\n", __func__, len); + memset(header, 0x00, sizeof(header)); + memset(rbuf, 0x00, sizeof(rbuf)); + + // extra safety check, will not happen + if (len != 12) { + DBG(1, "%s: command has wrong size (%lu != 12)\n", __func__, len); return SANE_STATUS_INVAL; } - /* merge the payload size and send the RequestBlock */ - if (payload && plen) { - - sprintf(rbuf, "%4.4sx%07x", cmd, (unsigned int)plen); - - DBG(8, " %s (%lu)\n", rbuf, plen); - - eds_send(s, rbuf, 12, &status); - - } else { - eds_send(s, cmd, len, &status); - } + // merge ParameterBlock size + sprintf(header, "%4.4sx%07x", cmd, (unsigned int)plen); + // send RequestBlock, request immediate response if there's no payload + status = eds_txrx(s, header, len, rbuf, (plen > 0) ? 0 : 64); if (status != SANE_STATUS_GOOD) { return status; } - /* send ParameterBlock */ - if (payload && plen) { + /* send ParameterBlock, request response */ + if (plen) { + + DBG(8, " %12.12s (%lu)\n", header, plen); - eds_send(s, payload, plen, &status); + status = eds_txrx(s, payload, plen, rbuf, 64); if (status != SANE_STATUS_GOOD) { return status; } } - /* receive DataHeaderBlock */ - memset(rbuf, 0x00, sizeof(rbuf)); - - eds_recv(s, rbuf, 64, &status); - if (status != SANE_STATUS_GOOD) { - return status; - } - /* rxbuf holds the DataHeaderBlock, which should be * parsed to know if we need to read more data */ @@ -196,6 +187,10 @@ static SANE_Status esci2_cmd(epsonds_scanner* s, char *pbuf = malloc(more); if (pbuf) { + if (s->hw->connection == SANE_EPSONDS_NET) { + epsonds_net_request_read(s, more); + } + ssize_t read = eds_recv(s, pbuf, more, &status); if (read != more) { } @@ -853,7 +848,7 @@ esci2_img(struct epsonds_scanner *s, SANE_Int *length) return SANE_STATUS_CANCELLED; /* request image data */ - eds_send(s, "IMG x0000000", 12, &status); + eds_send(s, "IMG x0000000", 12, &status, 64); if (status != SANE_STATUS_GOOD) { return status; } @@ -882,6 +877,10 @@ esci2_img(struct epsonds_scanner *s, SANE_Int *length) } /* ALWAYS read image data */ + if (s->hw->connection == SANE_EPSONDS_NET) { + epsonds_net_request_read(s, more); + } + read = eds_recv(s, s->buf, more, &status); if (status != SANE_STATUS_GOOD) { return status; diff --git a/backend/epsonds-io.c b/backend/epsonds-io.c index 28bacfc..e153ad4 100644 --- a/backend/epsonds-io.c +++ b/backend/epsonds-io.c @@ -16,11 +16,19 @@ #include "sane/config.h" #include #include /* sleep */ +#ifdef HAVE_SYS_TYPES_H +#include +#endif #include "epsonds.h" #include "epsonds-io.h" +#include "epsonds-net.h" -size_t eds_send(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status) +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +size_t eds_send(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status, size_t reply_len) { DBG(32, "%s: size = %lu\n", __func__, (u_long) length); @@ -36,7 +44,9 @@ size_t eds_send(epsonds_scanner *s, void *buf, size_t length, SANE_Status *statu } if (s->hw->connection == SANE_EPSONDS_NET) { - /* XXX */ + + return epsonds_net_write(s, 0x2000, buf, length, reply_len, status); + } else if (s->hw->connection == SANE_EPSONDS_USB) { size_t n = length; @@ -55,21 +65,23 @@ size_t eds_send(epsonds_scanner *s, void *buf, size_t length, SANE_Status *statu size_t eds_recv(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status) { - size_t n = 0; + size_t n = length; /* network interface needs to read header back even data is 0.*/ DBG(30, "%s: size = %ld, buf = %p\n", __func__, (long) length, buf); + *status = SANE_STATUS_GOOD; + if (s->hw->connection == SANE_EPSONDS_NET) { - /* XXX */ + n = epsonds_net_read(s, buf, length, status); } else if (s->hw->connection == SANE_EPSONDS_USB) { /* !!! only report an error if we don't read anything */ - - n = length; - *status = sanei_usb_read_bulk(s->fd, (SANE_Byte *)buf, - (size_t *) &n); - if (n > 0) - *status = SANE_STATUS_GOOD; + if (n) { + *status = sanei_usb_read_bulk(s->fd, (SANE_Byte *)buf, + (size_t *) &n); + if (n > 0) + *status = SANE_STATUS_GOOD; + } } if (n < length) { @@ -90,7 +102,7 @@ SANE_Status eds_txrx(epsonds_scanner* s, char *txbuf, size_t txlen, SANE_Status status; size_t done; - done = eds_send(s, txbuf, txlen, &status); + done = eds_send(s, txbuf, txlen, &status, rxlen); if (status != SANE_STATUS_GOOD) { DBG(1, "%s: tx err, %s\n", __func__, sane_strstatus(status)); return status; @@ -147,6 +159,7 @@ SANE_Status eds_fsy(epsonds_scanner *s) SANE_Status eds_fsx(epsonds_scanner *s) { +// SANE_Status status = eds_control(s, "\x1CZ", 2); SANE_Status status = eds_control(s, "\x1CX", 2); if (status == SANE_STATUS_GOOD) { s->locked = 1; diff --git a/backend/epsonds-io.h b/backend/epsonds-io.h index 1a1b2b7..1bb67c6 100644 --- a/backend/epsonds-io.h +++ b/backend/epsonds-io.h @@ -17,7 +17,7 @@ #define USB_TIMEOUT (6 * 1000) #define USB_SHORT_TIMEOUT (1 * 800) -size_t eds_send(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status); +size_t eds_send(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status, size_t reply_len); size_t eds_recv(epsonds_scanner *s, void *buf, size_t length, SANE_Status *status); SANE_Status eds_txrx(epsonds_scanner *s, char *txbuf, size_t txlen, diff --git a/backend/epsonds-jpeg.c b/backend/epsonds-jpeg.c index 76a52cb..62e8bb5 100644 --- a/backend/epsonds-jpeg.c +++ b/backend/epsonds-jpeg.c @@ -13,6 +13,8 @@ #define DEBUG_DECLARE_ONLY +#include "sane/config.h" + #include #include "epsonds.h" @@ -35,12 +37,12 @@ typedef struct epsonds_src_mgr; METHODDEF(void) -jpeg_init_source(j_decompress_ptr UNUSEDARG cinfo) +jpeg_init_source(j_decompress_ptr __sane_unused__ cinfo) { } METHODDEF(void) -jpeg_term_source(j_decompress_ptr UNUSEDARG cinfo) +jpeg_term_source(j_decompress_ptr __sane_unused__ cinfo) { } diff --git a/backend/epsonds-jpeg.h b/backend/epsonds-jpeg.h index c54208e..a804dec 100644 --- a/backend/epsonds-jpeg.h +++ b/backend/epsonds-jpeg.h @@ -11,8 +11,6 @@ * published by the Free Software Foundation, version 2. */ -#define UNUSEDARG __attribute__ ((unused)) - SANE_Status eds_jpeg_start(epsonds_scanner *s); void eds_jpeg_finish(epsonds_scanner *s); SANE_Status eds_jpeg_read_header(epsonds_scanner *s); diff --git a/backend/epsonds-net.c b/backend/epsonds-net.c new file mode 100644 index 0000000..8ea236b --- /dev/null +++ b/backend/epsonds-net.c @@ -0,0 +1,278 @@ +/* + * epsonds-net.c - SANE library for Epson scanners. + * + * Copyright (C) 2006-2016 Tower Technologies + * Author: Alessandro Zummo + * + * 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, version 2. + */ + +#define DEBUG_DECLARE_ONLY + +#include "sane/config.h" + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#include "sane/sane.h" +#include "sane/saneopts.h" +#include "sane/sanei_tcp.h" +#include "sane/sanei_config.h" +#include "sane/sanei_backend.h" + +#include "epsonds.h" +#include "epsonds-net.h" + +#include "byteorder.h" + +#include "sane/sanei_debug.h" + +static int +epsonds_net_read_raw(epsonds_scanner *s, unsigned char *buf, ssize_t wanted, + SANE_Status *status) +{ + int ready, read = -1; + fd_set readable; + struct timeval tv; + + tv.tv_sec = 10; + tv.tv_usec = 0; + + FD_ZERO(&readable); + FD_SET(s->fd, &readable); + + ready = select(s->fd + 1, &readable, NULL, NULL, &tv); + if (ready > 0) { + read = sanei_tcp_read(s->fd, buf, wanted); + } else { + DBG(15, "%s: select failed: %d\n", __func__, ready); + } + + *status = SANE_STATUS_GOOD; + + if (read < wanted) { + *status = SANE_STATUS_IO_ERROR; + } + + return read; +} + +int +epsonds_net_read(epsonds_scanner *s, unsigned char *buf, ssize_t wanted, + SANE_Status * status) +{ + ssize_t size; + ssize_t read = 0; + unsigned char header[12]; + + /* read from buffer, if available */ + if (wanted && s->netptr != s->netbuf) { + DBG(23, "reading %lu from buffer at %p, %lu available\n", + (u_long) wanted, s->netptr, (u_long) s->netlen); + + memcpy(buf, s->netptr, wanted); + read = wanted; + + s->netlen -= wanted; + + if (s->netlen == 0) { + DBG(23, "%s: freeing %p\n", __func__, s->netbuf); + free(s->netbuf); + s->netbuf = s->netptr = NULL; + s->netlen = 0; + } + + return read; + } + + /* receive net header */ + size = epsonds_net_read_raw(s, header, 12, status); + if (size != 12) { + return 0; + } + + if (header[0] != 'I' || header[1] != 'S') { + DBG(1, "header mismatch: %02X %02x\n", header[0], header[1]); + *status = SANE_STATUS_IO_ERROR; + return 0; + } + + // incoming payload size + size = be32atoh(&header[6]); + + DBG(23, "%s: wanted = %lu, available = %lu\n", __func__, + (u_long) wanted, (u_long) size); + + *status = SANE_STATUS_GOOD; + + if (size == wanted) { + + DBG(15, "%s: full read\n", __func__); + + if (size) { + read = epsonds_net_read_raw(s, buf, size, status); + } + + if (s->netbuf) { + free(s->netbuf); + s->netbuf = NULL; + s->netlen = 0; + } + + if (read < 0) { + return 0; + } + + } else if (wanted < size) { + + DBG(23, "%s: long tail\n", __func__); + + read = epsonds_net_read_raw(s, s->netbuf, size, status); + if (read != size) { + return 0; + } + + memcpy(buf, s->netbuf, wanted); + read = wanted; + + free(s->netbuf); + s->netbuf = NULL; + s->netlen = 0; + + } else { + + DBG(23, "%s: partial read\n", __func__); + + read = epsonds_net_read_raw(s, s->netbuf, size, status); + if (read != size) { + return 0; + } + + s->netlen = size - wanted; + s->netptr += wanted; + read = wanted; + + DBG(23, "0,4 %02x %02x\n", s->netbuf[0], s->netbuf[4]); + DBG(23, "storing %lu to buffer at %p, next read at %p, %lu bytes left\n", + (u_long) size, s->netbuf, s->netptr, (u_long) s->netlen); + + memcpy(buf, s->netbuf, wanted); + } + + return read; +} + +SANE_Status +epsonds_net_request_read(epsonds_scanner *s, size_t len) +{ + SANE_Status status; + epsonds_net_write(s, 0x2000, NULL, 0, len, &status); + return status; +} + +int +epsonds_net_write(epsonds_scanner *s, unsigned int cmd, const unsigned char *buf, + size_t buf_size, size_t reply_len, SANE_Status *status) +{ + unsigned char *h1, *h2; + unsigned char *packet = malloc(12 + 8); + + /* XXX check allocation failure */ + + h1 = packet; // packet header + h2 = packet + 12; // data header + + if (reply_len) { + s->netbuf = s->netptr = malloc(reply_len); + s->netlen = reply_len; + DBG(24, "allocated %lu bytes at %p\n", + (u_long) reply_len, s->netbuf); + } + + DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n", + __func__, cmd, buf, (u_long) buf_size, (u_long) reply_len); + + memset(h1, 0x00, 12); + memset(h2, 0x00, 8); + + h1[0] = 'I'; + h1[1] = 'S'; + + h1[2] = cmd >> 8; // packet type + h1[3] = cmd; // data type + + h1[4] = 0x00; + h1[5] = 0x0C; // data offset + + DBG(24, "H1[0]: %02x %02x %02x %02x\n", h1[0], h1[1], h1[2], h1[3]); + + // 0x20 passthru + // 0x21 job control + + if (buf_size) { + htobe32a(&h1[6], buf_size); + } + + if((cmd >> 8) == 0x20) { + + htobe32a(&h1[6], buf_size + 8); // data size (data header + payload) + + htobe32a(&h2[0], buf_size); // payload size + htobe32a(&h2[4], reply_len); // expected answer size + + DBG(24, "H1[6]: %02x %02x %02x %02x (%lu)\n", h1[6], h1[7], h1[8], h1[9], (u_long) (buf_size + 8)); + DBG(24, "H2[0]: %02x %02x %02x %02x (%lu)\n", h2[0], h2[1], h2[2], h2[3], (u_long) buf_size); + DBG(24, "H2[4]: %02x %02x %02x %02x (%lu)\n", h2[4], h2[5], h2[6], h2[7], (u_long) reply_len); + } + + if ((cmd >> 8) == 0x20 && (buf_size || reply_len)) { + + // send header + data header + sanei_tcp_write(s->fd, packet, 12 + 8); + + } else { + sanei_tcp_write(s->fd, packet, 12); + } + + // send payload + if (buf_size) + sanei_tcp_write(s->fd, buf, buf_size); + + free(packet); + + *status = SANE_STATUS_GOOD; + return buf_size; +} + +SANE_Status +epsonds_net_lock(struct epsonds_scanner *s) +{ + SANE_Status status; + unsigned char buf[7] = "\x01\xa0\x04\x00\x00\x01\x2c"; + + DBG(1, "%s\n", __func__); + + epsonds_net_write(s, 0x2100, buf, 7, 0, &status); + epsonds_net_read(s, buf, 1, &status); + + // buf[0] should be ACK, 0x06 + + return status; +} + +SANE_Status +epsonds_net_unlock(struct epsonds_scanner *s) +{ + SANE_Status status; + + DBG(1, "%s\n", __func__); + + epsonds_net_write(s, 0x2101, NULL, 0, 0, &status); +/* epsonds_net_read(s, buf, 1, &status); */ + return status; +} diff --git a/backend/epsonds-net.h b/backend/epsonds-net.h new file mode 100644 index 0000000..f7b173e --- /dev/null +++ b/backend/epsonds-net.h @@ -0,0 +1,16 @@ +#ifndef _EPSONDS_NET_H_ +#define _EPSONDS_NET_H_ + +#include +#include "../include/sane/sane.h" + +extern int epsonds_net_read(struct epsonds_scanner *s, unsigned char *buf, ssize_t buf_size, + SANE_Status *status); +extern int epsonds_net_write(struct epsonds_scanner *s, unsigned int cmd, const unsigned char *buf, + size_t buf_size, size_t reply_len, + SANE_Status *status); +extern SANE_Status epsonds_net_lock(struct epsonds_scanner *s); +extern SANE_Status epsonds_net_unlock(struct epsonds_scanner *s); +extern SANE_Status epsonds_net_request_read(epsonds_scanner *s, size_t len); + +#endif diff --git a/backend/epsonds-ops.c b/backend/epsonds-ops.c index 403cd58..f7a07fb 100644 --- a/backend/epsonds-ops.c +++ b/backend/epsonds-ops.c @@ -72,6 +72,18 @@ eds_dev_post_init(struct epsonds_device *dev) return SANE_STATUS_GOOD; } +SANE_Bool +eds_is_model(epsonds_device *dev, const char *model) +{ + if (dev->model == NULL) + return SANE_FALSE; + + if (strncmp(dev->model, model, strlen(model)) == 0) + return SANE_TRUE; + + return SANE_FALSE; +} + SANE_Status eds_add_resolution(epsonds_device *dev, int r) { @@ -199,6 +211,12 @@ eds_init_parameters(epsonds_scanner *s) s->dummy = 0; + /* setup depth according to our mode table */ + if (mode_params[s->val[OPT_MODE].w].depth == 1) + s->params.depth = 1; + else + s->params.depth = s->val[OPT_DEPTH].w; + dpi = s->val[OPT_RESOLUTION].w; if (SANE_UNFIX(s->val[OPT_BR_Y].w) == 0 || @@ -246,11 +264,6 @@ eds_init_parameters(epsonds_scanner *s) * The default color depth is stored in mode_params.depth: */ - if (mode_params[s->val[OPT_MODE].w].depth == 1) - s->params.depth = 1; - else - s->params.depth = s->val[OPT_DEPTH].w; - /* this works because it can only be set to 1, 8 or 16 */ bytes_per_pixel = s->params.depth / 8; if (s->params.depth % 8) { /* just in case ... */ diff --git a/backend/epsonds-ops.h b/backend/epsonds-ops.h index 3f45393..ac5e71b 100644 --- a/backend/epsonds-ops.h +++ b/backend/epsonds-ops.h @@ -11,11 +11,11 @@ * published by the Free Software Foundation, version 2. */ -#define e2_model(s,m) e2_dev_model((s)->hw,(m)) - extern void eds_dev_init(epsonds_device *dev); extern SANE_Status eds_dev_post_init(struct epsonds_device *dev); +extern SANE_Bool eds_is_model(epsonds_device *dev, const char *model); + extern SANE_Status eds_add_resolution(epsonds_device *dev, int r); extern SANE_Status eds_set_resolution_range(epsonds_device *dev, int min, int max); extern void eds_set_fbf_area(epsonds_device *dev, int x, int y, int unit); diff --git a/backend/epsonds.c b/backend/epsonds.c index 2f85312..218e08c 100644 --- a/backend/epsonds.c +++ b/backend/epsonds.c @@ -12,8 +12,8 @@ */ #define EPSONDS_VERSION 1 -#define EPSONDS_REVISION 0 -#define EPSONDS_BUILD 35 +#define EPSONDS_REVISION 1 +#define EPSONDS_BUILD 0 /* debugging levels: * @@ -41,9 +41,12 @@ #include "sane/config.h" #include +#include #include "sane/saneopts.h" #include "sane/sanei_config.h" +#include "sane/sanei_tcp.h" +#include "sane/sanei_udp.h" #include "epsonds.h" #include "epsonds-usb.h" @@ -51,6 +54,8 @@ #include "epsonds-cmd.h" #include "epsonds-ops.h" #include "epsonds-jpeg.h" +#include "epsonds-net.h" + /* * Definition of the mode_param struct, that is used to @@ -115,6 +120,7 @@ max_string_size(const SANE_String_Const strings[]) } static SANE_Status attach_one_usb(SANE_String_Const devname); +static SANE_Status attach_one_net(SANE_String_Const devname); static void print_params(const SANE_Parameters params) @@ -140,7 +146,10 @@ close_scanner(epsonds_scanner *s) esci2_fin(s); } - if (s->hw->connection == SANE_EPSONDS_USB) { + if (s->hw->connection == SANE_EPSONDS_NET) { + epsonds_net_unlock(s); + sanei_tcp_close(s->fd); + } else if (s->hw->connection == SANE_EPSONDS_USB) { sanei_usb_close(s->fd); } @@ -154,6 +163,49 @@ free: DBG(7, "%s: ZZZ\n", __func__); } +static void +e2_network_discovery(void) +{ + fd_set rfds; + int fd, len; + SANE_Status status; + + char *ip, *query = "EPSONP\x00\xff\x00\x00\x00\x00\x00\x00\x00"; + unsigned char buf[76]; + + struct timeval to; + + status = sanei_udp_open_broadcast(&fd); + if (status != SANE_STATUS_GOOD) + return; + + sanei_udp_write_broadcast(fd, 3289, (unsigned char *) query, 15); + + DBG(5, "%s, sent discovery packet\n", __func__); + + to.tv_sec = 1; + to.tv_usec = 0; + + FD_ZERO(&rfds); + FD_SET(fd, &rfds); + + sanei_udp_set_nonblock(fd, SANE_TRUE); + while (select(fd + 1, &rfds, NULL, NULL, &to) > 0) { + if ((len = sanei_udp_recvfrom(fd, buf, 76, &ip)) == 76) { + DBG(5, " response from %s\n", ip); + + /* minimal check, protocol unknown */ + if (strncmp((char *) buf, "EPSON", 5) == 0) + attach_one_net(ip); + } + } + + DBG(5, "%s, end\n", __func__); + + sanei_udp_close(fd); +} + + static SANE_Status open_scanner(epsonds_scanner *s) { @@ -166,10 +218,59 @@ open_scanner(epsonds_scanner *s) return SANE_STATUS_GOOD; /* no need to open the scanner */ } - if (s->hw->connection == SANE_EPSONDS_USB) { + if (s->hw->connection == SANE_EPSONDS_NET) { + unsigned char buf[5]; + + /* device name has the form net:ipaddr */ + status = sanei_tcp_open(&s->hw->sane.name[4], 1865, &s->fd); + if (status == SANE_STATUS_GOOD) { + + ssize_t read; + struct timeval tv; + + tv.tv_sec = 5; + tv.tv_usec = 0; + + setsockopt(s->fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); + + s->netlen = 0; + + DBG(32, "awaiting welcome message\n"); + + /* the scanner sends a kind of welcome msg */ + // XXX check command type, answer to connect is 0x80 + read = eds_recv(s, buf, 3, &status); + if (read != 3) { + sanei_tcp_close(s->fd); + s->fd = -1; + return SANE_STATUS_IO_ERROR; + } + + DBG(32, "welcome message received, locking the scanner...\n"); + + /* lock the scanner for use by sane */ + status = epsonds_net_lock(s); + if (status != SANE_STATUS_GOOD) { + DBG(1, "%s cannot lock scanner: %s\n", s->hw->sane.name, + sane_strstatus(status)); + + sanei_tcp_close(s->fd); + s->fd = -1; + + return status; + } + + DBG(32, "scanner locked\n"); + } + + } else if (s->hw->connection == SANE_EPSONDS_USB) { status = sanei_usb_open(s->hw->sane.name, &s->fd); - sanei_usb_set_timeout(USB_TIMEOUT); + + if (status == SANE_STATUS_GOOD) { + sanei_usb_set_timeout(USB_TIMEOUT); + sanei_usb_clear_halt(s->fd); + } } else { DBG(1, "unknown connection type: %d\n", s->hw->connection); @@ -220,12 +321,20 @@ device_detect(const char *name, int type, SANE_Status *status) struct epsonds_scanner *s; struct epsonds_device *dev; - DBG(1, "%s\n", __func__); + DBG(1, "%s, %s, type: %d\n", __func__, name, type); /* try to find the device in our list */ for (dev = first_dev; dev; dev = dev->next) { + if (strcmp(dev->sane.name, name) == 0) { + DBG(1, " found cached device\n"); + + // the device might have been just probed, sleep a bit. + if (dev->connection == SANE_EPSONDS_NET) { + sleep(1); + } + return scanner_create(dev, status); } } @@ -250,8 +359,9 @@ device_detect(const char *name, int type, SANE_Status *status) dev->connection = type; dev->model = strdup("(undetermined)"); + dev->name = strdup(name); - dev->sane.name = name; + dev->sane.name = dev->name; dev->sane.vendor = "Epson"; dev->sane.model = dev->model; dev->sane.type = "ESC/I-2"; @@ -283,11 +393,11 @@ device_detect(const char *name, int type, SANE_Status *status) if (*status != SANE_STATUS_GOOD) goto close; - /* assume 1 and 8 bit are always supported */ + // assume 1 and 8 bit are always supported eds_add_depth(s->hw, 1); eds_add_depth(s->hw, 8); - /* setup area according to available options */ + // setup area according to available options if (s->hw->has_fb) { dev->x_range = &dev->fbf_x_range; @@ -349,6 +459,19 @@ attach_one_usb(const char *dev) return attach(dev, SANE_EPSONDS_USB); } +static SANE_Status +attach_one_net(const char *dev) +{ + char name[39 + 4]; + + DBG(7, "%s: dev = %s\n", __func__, dev); + + strcpy(name, "net:"); + strcat(name, dev); + return attach(name, SANE_EPSONDS_NET); +} + + static SANE_Status attach_one_config(SANEI_Config __sane_unused__ *config, const char *line) { @@ -380,6 +503,16 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line) epsonds_usb_product_ids[i], attach_one_usb); } + } else if (strncmp(line, "net", 3) == 0) { + + /* remove the "net" sub string */ + const char *name = sanei_config_skip_whitespace(line + 3); + + if (strncmp(name, "autodiscovery", 13) == 0) + e2_network_discovery(); + else + attach_one_net(name); + } else { DBG(0, "unable to parse config line: %s\n", line); } @@ -669,7 +802,11 @@ sane_open(SANE_String_Const name, SANE_Handle *handle) } else { - if (strncmp(name, "libusb:", 7) == 0) { + if (strncmp(name, "net:", 4) == 0) { + s = device_detect(name, SANE_EPSONDS_NET, &status); + if (s == NULL) + return status; + } else if (strncmp(name, "libusb:", 7) == 0) { s = device_detect(name, SANE_EPSONDS_USB, &status); if (s == NULL) return status; @@ -1041,7 +1178,7 @@ SANE_Status sane_start(SANE_Handle handle) { epsonds_scanner *s = (epsonds_scanner *)handle; - char buf[64]; + char buf[65]; /* add one more byte to correct buffer overflow issue */ char cmd[100]; /* take care not to overflow */ SANE_Status status = 0; @@ -1112,10 +1249,17 @@ sane_start(SANE_Handle handle) s->val[OPT_ADF_MODE].w ? "DPLX" : "", s->val[OPT_ADF_SKEW].w ? "SKEW" : ""); - if (s->hw->adf_has_dfd == 2) { - strcat(buf, "DFL2"); - } else if (s->hw->adf_has_dfd == 1) { - strcat(buf, "DFL1"); + /* it seems that DFL only works in duplex mode, but it's + * also required to be enabled or duplex will be rejected. + */ + + if (s->val[OPT_ADF_MODE].w) { + + if (s->hw->adf_has_dfd == 2) { + strcat(buf, "DFL2"); + } else if (s->hw->adf_has_dfd == 1) { + strcat(buf, "DFL1"); + } } } else if (strcmp(source_list[s->val[OPT_SOURCE].w], FBF_STR) == 0) { @@ -1148,9 +1292,9 @@ sane_start(SANE_Handle handle) /* resolution (RSMi not always supported) */ if (s->val[OPT_RESOLUTION].w > 999) { - sprintf(buf, "#RSMi%07d", s->val[OPT_RESOLUTION].w); + sprintf(buf, "#RSMi%07d#RSSi%07d", s->val[OPT_RESOLUTION].w, s->val[OPT_RESOLUTION].w); } else { - sprintf(buf, "#RSMd%03d", s->val[OPT_RESOLUTION].w); + sprintf(buf, "#RSMd%03d#RSSd%03d", s->val[OPT_RESOLUTION].w, s->val[OPT_RESOLUTION].w); } strcat(cmd, buf); diff --git a/backend/epsonds.conf.in b/backend/epsonds.conf.in index 23dc461..b8b3623 100644 --- a/backend/epsonds.conf.in +++ b/backend/epsonds.conf.in @@ -10,3 +10,7 @@ usb # e.g.: # usb 0x4b8 0x14c +# Network +# +# net 192.168.1.123 +net autodiscovery diff --git a/backend/epsonds.h b/backend/epsonds.h index 024773b..0427ef3 100644 --- a/backend/epsonds.h +++ b/backend/epsonds.h @@ -43,13 +43,6 @@ #include "sane/sanei_usb.h" #include "sane/sanei_jpeg.h" -#ifdef __GNUC__ -#define __func__ __FUNCTION__ -#else -#define __func__ "(undef)" -/* I cast my vote for C99... :) */ -#endif - #define EPSONDS_CONFIG_FILE "epsonds.conf" #ifndef PATH_MAX @@ -94,7 +87,7 @@ typedef enum { /* hardware connection to the scanner */ SANE_EPSONDS_NODEV, /* default, no HW specified yet */ SANE_EPSONDS_USB, /* USB interface */ - SANE_EPSONDS_NET /* network interface (unsupported)*/ + SANE_EPSONDS_NET /* network interface */ } epsonds_conn_type; /* hardware description */ @@ -180,6 +173,10 @@ struct epsonds_scanner struct jpeg_decompress_struct jpeg_cinfo; struct jpeg_error_mgr jpeg_err; SANE_Bool jpeg_header_seen; + + /* network buffers */ + unsigned char *netbuf, *netptr; + size_t netlen; }; typedef struct epsonds_scanner epsonds_scanner; diff --git a/backend/fujitsu-scsi.h b/backend/fujitsu-scsi.h index de6652c..42598cb 100644 --- a/backend/fujitsu-scsi.h +++ b/backend/fujitsu-scsi.h @@ -377,6 +377,10 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_IN_read_size(in) getbitfield(in+0x78, 1, 6) #define get_IN_start_end_ms(in) getbitfield(in+0x78, 1, 5) +#define get_IN_battery(in) getbitfield(in+0x79, 1, 7) +#define get_IN_battery_save(in) getbitfield(in+0x79, 1, 6) +#define get_IN_op_reverse(in) getbitfield(in+0x79, 1, 1) + #define get_IN_op_halt(in) getbitfield(in+0x7a, 1, 7) /* some scanners need evpd inquiry data manipulated */ @@ -616,12 +620,13 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define SEND_len 10 #define set_S_xfer_datatype(sb, val) sb[0x02] = (unsigned char)val -/*#define S_datatype_imagedatai 0x00 #define S_datatype_halftone_mask 0x02 -#define S_datatype_gamma_function 0x03*/ +#define S_datatype_gamma_function 0x03 #define S_datatype_lut_data 0x83 +#define S_datatype_lut_dropout 0x84 #define S_datatype_jpg_q_table 0x88 #define S_datatype_endorser_data 0x90 +#define S_datatype_sendto_name 0xa0 /*#define S_EX_datatype_lut 0x01 #define S_EX_datatype_shading_data 0xa0 #define S_user_reg_gamma 0xc0 @@ -747,6 +752,8 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define GHS_data_len 12 #define get_GHS_top(in) getbitfield(in+0x02, 1, 7) +#define get_GHS_fedalm(in) getbitfield(in+0x02, 1, 5) +#define get_GHS_adjalm(in) getbitfield(in+0x02, 1, 4) #define get_GHS_A3(in) getbitfield(in+0x02, 1, 3) #define get_GHS_B4(in) getbitfield(in+0x02, 1, 2) #define get_GHS_A4(in) getbitfield(in+0x02, 1, 1) @@ -762,12 +769,14 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_GHS_sleep(in) getbitfield(in+0x04, 1, 7) #define get_GHS_clean(in) getbitfield(in+0x04, 1, 6) +#define get_GHS_scan_sw_long(in) getbitfield(in+0x04, 1, 5) +#define get_GHS_hpos(in) getbitfield(in+0x04, 1, 4) #define get_GHS_send_sw(in) getbitfield(in+0x04, 1, 2) #define get_GHS_manual_feed(in) getbitfield(in+0x04, 1, 1) #define get_GHS_scan_sw(in) getbitfield(in+0x04, 1, 0) #define get_GHS_picalm(in) getbitfield(in+0x05, 1, 7) -#define get_GHS_fadalm(in) getbitfield(in+0x05, 1, 6) +#define get_GHS_padalm(in) getbitfield(in+0x05, 1, 6) #define get_GHS_brkalm(in) getbitfield(in+0x05, 1, 5) #define get_GHS_sepalm(in) getbitfield(in+0x05, 1, 4) #define get_GHS_function(in) getbitfield(in+0x05, 0x0f, 0) @@ -783,10 +792,34 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_GHS_error_code(in) in[0x07] -#define get_GHS_skew_angle(in) getnbyte(in+0x08, 2) +#define get_GHS_skew_angle(in) in[0x09] #define get_GHS_ink_remain(in) in[0x0a] +#define get_GHS_lang_code(in) getnbyte(in+0x0c, 2) + +#define get_GHS_adjalm_fed(in) getbitfield(in+0x0e, 1, 7) +#define get_GHS_non_sep(in) getbitfield(in+0x0e, 1, 4) +#define get_GHS_ext_sendto(in) getbitfield(in+0x0e, 1, 2) +#define get_GHS_rq_hldimg(in) getbitfield(in+0x0e, 1, 1) +#define get_GHS_pacnt(in) getbitfield(in+0x0e, 1, 0) + +#define get_GHS_wifi_sw(in) getbitfield(in+0x10, 1, 7) +#define get_GHS_w_use(in) getbitfield(in+0x10, 1, 6) +#define get_GHS_w_use2(in) getbitfield(in+0x10, 1, 5) +#define get_GHS_w_use3(in) getbitfield(in+0x10, 1, 4) +#define get_GHS_w_use4(in) getbitfield(in+0x10, 1, 3) + +#define get_GHS_battery(in) getbitfield(in+0x11, 1, 7) +#define get_GHS_btr_charge(in) getbitfield(in+0x11, 1, 6) +#define get_GHS_btr_chg_tmp_stp(in) getbitfield(in+0x11, 1, 5) +#define get_GHS_ibtr_ene_sav(in) getbitfield(in+0x11, 1, 4) +#define get_GHS_fngr_caut(in) getbitfield(in+0x11, 1, 2) +#define get_GHS_trnpg_l(in) getbitfield(in+0x11, 1, 1) +#define get_GHS_trnpg_r(in) getbitfield(in+0x11, 1, 0) + +#define get_GHS_btr_power(in) in[0x12] + /* ==================================================================== */ /* SCANNER_CONTROL */ #define SCANNER_CONTROL_code 0xf1 @@ -807,6 +840,12 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define SC_function_eject_complete 0x0a #define SC_function_manual_feed 0x0c +/* used with SC_function_panel */ +#define set_SC_led_eb(icb, val) setbitfield(icb + 5, 1, 7, val) +#define set_SC_led(icb, val) setbitfield(icb + 5, 1, 6, val) +#define set_SC_fcno_eb(icb, val) setbitfield(icb + 5, 1, 4, val) +#define set_SC_fcno(icb, val) setbitfield(icb + 5, 0xf, 0, val) + #define set_SC_ric_dtq(sb, val) sb[2] = val #define set_SC_ric_len(sb, val) putnbyte(sb + 0x06, val, 3) @@ -1024,12 +1063,12 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) /* DTC also called Auto-I mode?*/ /*warning: filtering uses inverse logic*/ -#define set_WD_filtering(sb, val) setbitfield(sb + 0x2f, 1, 7, val) -#define get_WD_filtering(sb) getbitfield(sb + 0x2f, 1, 7) +#define set_WD_filtering(sb, val) setbitfield(sb + 0x2f, 1, 7, !val) +#define get_WD_filtering(sb) !getbitfield(sb + 0x2f, 1, 7) /*warning: smoothing uses inverse logic*/ -#define set_WD_smoothing(sb, val) setbitfield(sb + 0x2f, 3, 5, val) -#define get_WD_smoothing(sb) getbitfield(sb + 0x2f, 3, 5) +#define set_WD_smoothing(sb, val) setbitfield(sb + 0x2f, 3, 5, !val) +#define get_WD_smoothing(sb) !getbitfield(sb + 0x2f, 3, 5) #define set_WD_gamma_curve(sb, val) setbitfield(sb + 0x2f, 3, 3, val) #define get_WD_gamma_curve(sb) getbitfield(sb + 0x2f, 3, 3) diff --git a/backend/fujitsu.c b/backend/fujitsu.c index 9fddb1c..433f75a 100644 --- a/backend/fujitsu.c +++ b/backend/fujitsu.c @@ -6,7 +6,7 @@ Copyright (C) 2000 Randolph Bentson Copyright (C) 2001 Frederik Ramm Copyright (C) 2001-2004 Oliver Schirrmeister - Copyright (C) 2003-2014 m. allan noah + Copyright (C) 2003-2016 m. allan noah JPEG output and low memory usage support funded by: Archivista GmbH, www.archivista.ch @@ -574,9 +574,32 @@ v126 2015-08-23, MAN - initial support for iX100 - add late_lut support for iX500/iX100 - v127 2015-08-25, MAN + v127 2015-08-25, MAN (SANE 1.0.25) - separate iX100 from iX500 settings - iX100 has gray and lineart + v128 2015-11-08, MAN + - do not ask fi-4340 for serial number + v129 2015-11-21, MAN + - br_x and br_y locked to page_width/height until changed + v130 2016-02-23, MAN + - run init_model before init_ms so some scanners can override + - set all M309x and M409x scanners s->broken_diag_serial = 1 + v131 2016-06-06, MAN + - hide compression-arg option when jpeg disabled + - add Send/SC/GHS macros for recent scanners + - add initial support for fi-74x0 + - add initial support for fi-7030 + - set has_MS_lamp=0 for fi-71x0 + - add I18N macros to all option titles and descriptions + v132 2016-10-07, MAN + - remove ipc_mode option and variables + - set ipc mode based on other options + - cleanup inverted logic DTC options + - fixes threshold option reported in #315069 + v133 2017-04-08, MAN + - initial support for fi-7600/7700 + - autodetect various double feed capabilities using VPD + - call send_lut if we are using a downloaded gamma table SANE FLOW DIAGRAM @@ -626,7 +649,7 @@ #include "fujitsu.h" #define DEBUG 1 -#define BUILD 127 +#define BUILD 133 /* values for SANE_DEBUG_FUJITSU env var: - errors 5 @@ -990,22 +1013,22 @@ attach_one (const char *device_name, int connType) return ret; } - /* see what mode pages device supports */ - ret = init_ms (s); + /* clean up the scanner struct based on model */ + /* this is the only piece of model specific code */ + ret = init_model (s); if (ret != SANE_STATUS_GOOD) { disconnect_fd(s); free (s); - DBG (5, "attach_one: ms failed\n"); + DBG (5, "attach_one: model failed\n"); return ret; } - /* clean up the scanner struct based on model */ - /* this is the only piece of model specific code */ - ret = init_model (s); + /* see what mode pages device supports */ + ret = init_ms (s); if (ret != SANE_STATUS_GOOD) { disconnect_fd(s); free (s); - DBG (5, "attach_one: model failed\n"); + DBG (5, "attach_one: ms failed\n"); return ret; } @@ -1682,6 +1705,9 @@ init_vpd (struct fujitsu *s) DBG (15, " skew check: %d\n", get_IN_skew_check(in)); DBG (15, " new feed roller: %d\n", get_IN_new_fd_roll(in)); + + s->has_adv_paper_prot = get_IN_paper_prot_2(in); + DBG (15, " paper protection: %d\n", s->has_adv_paper_prot); } if (get_IN_page_length (in) > 0x70-5) { @@ -1689,7 +1715,10 @@ init_vpd (struct fujitsu *s) DBG (15, " paper count: %d\n", get_IN_paper_count(in)); DBG (15, " paper number: %d\n", get_IN_paper_number(in)); DBG (15, " ext send to: %d\n", get_IN_ext_send_to(in)); - DBG (15, " staple det: %d\n", get_IN_staple_det(in)); + + s->has_staple_detect = get_IN_staple_det(in); + DBG (15, " staple det: %d\n", s->has_staple_detect); + DBG (15, " pause host: %d\n", get_IN_pause_host(in)); DBG (15, " pause panel: %d\n", get_IN_pause_panel(in)); DBG (15, " pause conf: %d\n", get_IN_pause_conf(in)); @@ -1701,7 +1730,9 @@ init_vpd (struct fujitsu *s) DBG (15, " imprint chk b: %d\n", get_IN_imprint_chk_b(in)); DBG (15, " imprint chk f: %d\n", get_IN_imprint_chk_f(in)); DBG (15, " force w bg: %d\n", get_IN_force_w_bg(in)); - DBG (15, " mf recover lvl: %d\n", get_IN_mf_recover_lvl(in)); + + s->has_df_recovery = get_IN_mf_recover_lvl(in); + DBG (15, " mf recover lvl: %d\n", s->has_df_recovery); DBG (15, " first read time: %d\n", get_IN_first_read_time(in)); DBG (15, " div scanning: %d\n", get_IN_div_scanning(in)); @@ -1720,7 +1751,7 @@ init_vpd (struct fujitsu *s) DBG (15, " sync next feed: %d\n", get_IN_sync_next_feed(in)); s->has_op_halt = get_IN_op_halt(in); - DBG (15, " object postion halt: %d\n", s->has_op_halt); + DBG (15, " object position halt: %d\n", s->has_op_halt); } ret = SANE_STATUS_GOOD; @@ -2014,19 +2045,12 @@ init_model (struct fujitsu *s) /* if scanner has built-in gamma tables, we use the first one (0) */ /* otherwise, we use the first downloaded one (0x80) */ - /* note that you may NOT need to send the table to use it? */ + /* note that you may NOT need to send the table to use it, */ + /* the scanner will fall back to the brightness/contrast LUT */ if (!s->num_internal_gamma && s->num_download_gamma){ s->window_gamma = 0x80; } - /* older scanners would enable their highest */ - /* IPC mode by default. Newer scanners don't, */ - /* so we go ahead and turn it on. */ - if (s->has_sdtc) - s->ipc_mode = WD_ipc_SDTC; - else if (s->has_dtc) - s->ipc_mode = WD_ipc_DTC; - /* endorser type tells string length (among other things) */ if(s->has_endorser_b){ /*old-style is 40 bytes*/ @@ -2141,6 +2165,9 @@ init_model (struct fujitsu *s) else if ( strstr (s->model_name, "M309") || strstr (s->model_name, "M409")){ + /* weirdness */ + s->broken_diag_serial = 1; + /* lies */ s->adbits = 8; } @@ -2160,7 +2187,8 @@ init_model (struct fujitsu *s) s->max_y_fb = 14032; } - else if (strstr (s->model_name, "fi-4750") ) { + else if (strstr (s->model_name,"fi-4340") + || strstr (s->model_name, "fi-4750") ) { /* weirdness */ s->broken_diag_serial = 1; } @@ -2265,10 +2293,8 @@ init_model (struct fujitsu *s) } else if (strstr (s->model_name,"fi-6800") - || strstr (s->model_name,"fi-5900")){ /* guessing this scanner too */ - /* missing from vpd */ - s->has_staple_detect=1; /* may not actually work? */ - s->has_df_recovery=1; + || strstr (s->model_name,"fi-5900")){ + /* do not need overrides */ } else if (strstr (s->model_name,"iX500")){ @@ -2316,6 +2342,8 @@ init_model (struct fujitsu *s) else if (strstr (s->model_name,"fi-7180") || strstr (s->model_name,"fi-7160")){ + /* locks up scanner if we try to auto detect */ + s->has_MS_lamp = 0; /* weirdness */ /* these machines have longer max paper at lower res */ @@ -2325,10 +2353,6 @@ init_model (struct fujitsu *s) s->max_y_by_res[2].len = 260268; s->max_y_by_res[3].res = 200; s->max_y_by_res[3].len = 266268; - - /* missing from vpd */ - s->has_df_recovery=1; - s->has_adv_paper_prot=1; } else if (strstr (s->model_name,"fi-7280") @@ -2344,12 +2368,48 @@ init_model (struct fujitsu *s) s->max_y_by_res[3].len = 266268; /* missing from vpd */ - s->has_df_recovery=1; - s->has_adv_paper_prot=1; s->max_x_fb = 10764; s->max_y_fb = 14032; /* some scanners can be slightly more? */ } + else if (strstr (s->model_name,"fi-7480") + || strstr (s->model_name,"fi-7460")){ + + /* weirdness */ + /* these machines have longer max paper at lower res */ + s->max_y_by_res[1].res = 400; + s->max_y_by_res[1].len = 194268; + s->max_y_by_res[2].res = 300; + s->max_y_by_res[2].len = 260268; + s->max_y_by_res[3].res = 200; + s->max_y_by_res[3].len = 266268; + } + + else if (strstr (s->model_name,"fi-7030")){ + + /* weirdness */ + /* these machines have longer max paper at lower res */ + s->max_y_by_res[1].res = 400; + s->max_y_by_res[1].len = 192000; + s->max_y_by_res[2].res = 300; + s->max_y_by_res[2].len = 258000; + s->max_y_by_res[3].res = 200; + s->max_y_by_res[3].len = 264000; + } + + else if (strstr (s->model_name,"fi-7700") + || strstr (s->model_name,"fi-7600")){ + + /* weirdness */ + /* these machines have longer max paper at lower res */ + s->max_y_by_res[1].res = 400; + s->max_y_by_res[1].len = 192000; + s->max_y_by_res[2].res = 300; + s->max_y_by_res[2].len = 258000; + s->max_y_by_res[3].res = 200; + s->max_y_by_res[3].len = 264000; + } + DBG (10, "init_model: finish\n"); return SANE_STATUS_GOOD; @@ -2439,11 +2499,6 @@ init_user (struct fujitsu *s) s->u_endorser_dir=DIR_TTB; strcpy((char *)s->u_endorser_string,"%05ud"); - /* inverted logic ipc settings */ - s->noise_removal = 1; - s->bp_filter = 1; - s->smoothing = 1; - /* more recent machines default to this being 'on', * * which causes the scanner to ingest multiple pages * * even when the user only wants one */ @@ -3039,8 +3094,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /* gamma */ if(option==OPT_GAMMA){ opt->name = "gamma"; - opt->title = "Gamma function exponent"; - opt->desc = "Changes intensity of midtones"; + opt->title = SANE_I18N ("Gamma function exponent"); + opt->desc = SANE_I18N ("Changes intensity of midtones"); opt->type = SANE_TYPE_FIXED; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3089,8 +3144,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /* =============== common ipc params ================================ */ if(option==OPT_RIF){ opt->name = "rif"; - opt->title = "RIF"; - opt->desc = "Reverse image format"; + opt->title = SANE_I18N ("RIF"); + opt->desc = SANE_I18N ("Reverse image format"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_rif) @@ -3107,8 +3162,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->ht_type_list[i]=NULL; opt->name = "ht-type"; - opt->title = "Halftone type"; - opt->desc = "Control type of halftone filter"; + opt->title = SANE_I18N ("Halftone type"); + opt->desc = SANE_I18N ("Control type of halftone filter"); opt->type = SANE_TYPE_STRING; opt->unit = SANE_UNIT_NONE; @@ -3128,8 +3183,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_HT_PATTERN){ opt->name = "ht-pattern"; - opt->title = "Halftone pattern"; - opt->desc = "Control pattern of halftone filter"; + opt->title = SANE_I18N ("Halftone pattern"); + opt->desc = SANE_I18N ("Control pattern of halftone filter"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; @@ -3151,8 +3206,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_OUTLINE){ opt->name = "outline"; - opt->title = "Outline"; - opt->desc = "Perform outline extraction"; + opt->title = SANE_I18N ("Outline"); + opt->desc = SANE_I18N ("Perform outline extraction"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_outline) @@ -3163,8 +3218,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_EMPHASIS){ opt->name = "emphasis"; - opt->title = "Emphasis"; - opt->desc = "Negative to smooth or positive to sharpen image"; + opt->title = SANE_I18N ("Emphasis"); + opt->desc = SANE_I18N ("Negative to smooth or positive to sharpen image"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; @@ -3182,8 +3237,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_SEPARATION){ opt->name = "separation"; - opt->title = "Separation"; - opt->desc = "Enable automatic separation of image and text"; + opt->title = SANE_I18N ("Separation"); + opt->desc = SANE_I18N ("Enable automatic separation of image and text"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_autosep) @@ -3194,8 +3249,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_MIRRORING){ opt->name = "mirroring"; - opt->title = "Mirroring"; - opt->desc = "Reflect output image horizontally"; + opt->title = SANE_I18N ("Mirroring"); + opt->desc = SANE_I18N ("Reflect output image horizontally"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_mirroring) @@ -3212,8 +3267,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->wl_follow_list[i]=NULL; opt->name = "wl-follow"; - opt->title = "White level follower"; - opt->desc = "Control white level follower"; + opt->title = SANE_I18N ("White level follower"); + opt->desc = SANE_I18N ("Control white level follower"); opt->type = SANE_TYPE_STRING; opt->unit = SANE_UNIT_NONE; @@ -3227,50 +3282,18 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->cap = SANE_CAP_INACTIVE; } - if(option==OPT_IPC_MODE){ - i=0; - s->ipc_mode_list[i++]=STRING_DEFAULT; - if(s->has_dtc){ - s->ipc_mode_list[i++]=STRING_DTC; - } - if(s->has_sdtc){ - s->ipc_mode_list[i++]=STRING_SDTC; - } - s->ipc_mode_list[i]=NULL; - - opt->name = "ipc-mode"; - opt->title = "IPC mode"; - opt->desc = "Image processing mode, enables additional options"; - opt->type = SANE_TYPE_STRING; - opt->unit = SANE_UNIT_NONE; - - opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; - opt->constraint.string_list = s->ipc_mode_list; - opt->size = maxStringSize (opt->constraint.string_list); - - if ( i > 2 ){ - opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if(s->s_mode != MODE_HALFTONE && s->s_mode != MODE_LINEART){ - opt->cap |= SANE_CAP_INACTIVE; - } - } - else - opt->cap = SANE_CAP_INACTIVE; - } - /* =============== DTC params ================================ */ /* enabled when in dtc mode (manually or by default) */ if(option==OPT_BP_FILTER){ opt->name = "bp-filter"; - opt->title = "BP filter"; - opt->desc = "Improves quality of high resolution ball-point pen text"; + opt->title = SANE_I18N ("BP filter"); + opt->desc = SANE_I18N ("Improves quality of high resolution ball-point pen text"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if(s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(get_ipc_mode(s) == WD_ipc_SDTC){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3280,15 +3303,14 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_SMOOTHING){ opt->name = "smoothing"; - opt->title = "Smoothing"; - opt->desc = "Enable smoothing for improved OCR"; + opt->title = SANE_I18N ("Smoothing"); + opt->desc = SANE_I18N ("Enable smoothing for improved OCR"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if(s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(get_ipc_mode(s) == WD_ipc_SDTC){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3298,9 +3320,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_GAMMA_CURVE){ opt->name = "gamma-curve"; - opt->title = "Gamma curve"; - opt->desc = "Gamma curve"; - opt->desc = "Gamma curve, from light to dark, but upper two may not work"; + opt->title = SANE_I18N ("Gamma curve"); + opt->desc = SANE_I18N ("Gamma curve, from light to dark, but upper two may not work"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; @@ -3312,8 +3333,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if(s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(get_ipc_mode(s) == WD_ipc_SDTC){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3323,8 +3343,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_THRESHOLD_CURVE){ opt->name = "threshold-curve"; - opt->title = "Threshold curve"; - opt->desc = "Threshold curve, from light to dark, but upper two may not be linear"; + opt->title = SANE_I18N ("Threshold curve"); + opt->desc = SANE_I18N ("Threshold curve, from light to dark, but upper two may not be linear"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; @@ -3336,8 +3356,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if(s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(get_ipc_mode(s) == WD_ipc_SDTC){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3347,15 +3366,14 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_THRESHOLD_WHITE){ opt->name = "threshold-white"; - opt->title = "Threshold white"; - opt->desc = "Set pixels equal to threshold to white instead of black"; + opt->title = SANE_I18N ("Threshold white"); + opt->desc = SANE_I18N ("Set pixels equal to threshold to white instead of black"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if(s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(get_ipc_mode(s) == WD_ipc_SDTC){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3365,15 +3383,14 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_NOISE_REMOVAL){ opt->name = "noise-removal"; - opt->title = "Noise removal"; - opt->desc = "Noise removal"; + opt->title = SANE_I18N ("Noise removal"); + opt->desc = SANE_I18N ("Noise removal"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if(s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(get_ipc_mode(s) == WD_ipc_SDTC){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3383,16 +3400,14 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_MATRIX_5){ opt->name = "matrix-5x5"; - opt->title = "Matrix 5x5"; - opt->desc = "Remove 5 pixel square noise"; + opt->title = SANE_I18N ("Matrix 5x5"); + opt->desc = SANE_I18N ("Remove 5 pixel square noise"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if( !s->noise_removal - || s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(!s->noise_removal){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3402,16 +3417,14 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_MATRIX_4){ opt->name = "matrix-4x4"; - opt->title = "Matrix 4x4"; - opt->desc = "Remove 4 pixel square noise"; + opt->title = SANE_I18N ("Matrix 4x4"); + opt->desc = SANE_I18N ("Remove 4 pixel square noise"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if( !s->noise_removal - || s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(!s->noise_removal){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3421,16 +3434,14 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_MATRIX_3){ opt->name = "matrix-3x3"; - opt->title = "Matrix 3x3"; - opt->desc = "Remove 3 pixel square noise"; + opt->title = SANE_I18N ("Matrix 3x3"); + opt->desc = SANE_I18N ("Remove 3 pixel square noise"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if( !s->noise_removal - || s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(!s->noise_removal){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3440,16 +3451,14 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_MATRIX_2){ opt->name = "matrix-2x2"; - opt->title = "Matrix 2x2"; - opt->desc = "Remove 2 pixel square noise"; + opt->title = SANE_I18N ("Matrix 2x2"); + opt->desc = SANE_I18N ("Remove 2 pixel square noise"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if ( s->has_dtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if( !s->noise_removal - || s->ipc_mode == WD_ipc_SDTC - || (s->has_sdtc && s->ipc_mode == WD_ipc_DEFAULT)){ + if(!s->noise_removal){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3462,8 +3471,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /* called variance with ipc2, sensitivity with ipc3 */ if(option==OPT_VARIANCE){ opt->name = "variance"; - opt->title = "Variance"; - opt->desc = "Set SDTC variance rate (sensitivity), 0 equals 127"; + opt->title = SANE_I18N ("Variance"); + opt->desc = SANE_I18N ("Set SDTC variance rate (sensitivity), 0 equals 127"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; @@ -3475,7 +3484,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if ( s->has_sdtc ){ opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - if (s->ipc_mode == WD_ipc_DTC){ + if(get_ipc_mode(s) == WD_ipc_DTC){ opt->cap |= SANE_CAP_INACTIVE; } } @@ -3496,8 +3505,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_AWD){ opt->name = "awd"; - opt->title = "Auto width detection"; - opt->desc = "Scanner detects paper sides. May reduce scanning speed."; + opt->title = SANE_I18N ("Auto width detection"); + opt->desc = SANE_I18N ("Scanner detects paper sides. May reduce scanning speed."); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_NONE; @@ -3514,8 +3523,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ALD){ opt->name = "ald"; - opt->title = "Auto length detection"; - opt->desc = "Scanner detects paper lower edge. May confuse some frontends."; + opt->title = SANE_I18N ("Auto length detection"); + opt->desc = SANE_I18N ("Scanner detects paper lower edge. May confuse some frontends."); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_NONE; @@ -3541,8 +3550,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->compress_list[i]=NULL; opt->name = "compression"; - opt->title = "Compression"; - opt->desc = "Enable compressed data. May crash your front-end program"; + opt->title = SANE_I18N ("Compression"); + opt->desc = SANE_I18N ("Enable compressed data. May crash your front-end program"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->compress_list; @@ -3562,8 +3571,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_COMPRESS_ARG){ opt->name = "compression-arg"; - opt->title = "Compression argument"; - opt->desc = "Level of JPEG compression. 1 is small file, 7 is large file. 0 (default) is same as 4"; + opt->title = SANE_I18N ("Compression argument"); + opt->desc = SANE_I18N ("Level of JPEG compression. 1 is small file, 7 is large file. 0 (default) is same as 4"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3573,7 +3582,9 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(s->has_comp_JPG1){ s->compress_arg_range.min=0; s->compress_arg_range.max=7; +#ifndef SANE_JPEG_DISABLED opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; +#endif if(s->compress != COMP_JPEG){ opt->cap |= SANE_CAP_INACTIVE; @@ -3591,8 +3602,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->df_action_list[3] = NULL; opt->name = "df-action"; - opt->title = "DF action"; - opt->desc = "Action following double feed error"; + opt->title = SANE_I18N ("DF action"); + opt->desc = SANE_I18N ("Action following double feed error"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->df_action_list; @@ -3608,8 +3619,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_DF_SKEW){ opt->name = "df-skew"; - opt->title = "DF skew"; - opt->desc = "Enable double feed error due to skew"; + opt->title = SANE_I18N ("DF skew"); + opt->desc = SANE_I18N ("Enable double feed error due to skew"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_NONE; @@ -3627,8 +3638,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_DF_THICKNESS){ opt->name = "df-thickness"; - opt->title = "DF thickness"; - opt->desc = "Enable double feed error due to paper thickness"; + opt->title = SANE_I18N ("DF thickness"); + opt->desc = SANE_I18N ("Enable double feed error due to paper thickness"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_NONE; @@ -3646,8 +3657,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_DF_LENGTH){ opt->name = "df-length"; - opt->title = "DF length"; - opt->desc = "Enable double feed error due to paper length"; + opt->title = SANE_I18N ("DF length"); + opt->desc = SANE_I18N ("Enable double feed error due to paper length"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_NONE; @@ -3670,8 +3681,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->df_diff_list[4] = NULL; opt->name = "df-diff"; - opt->title = "DF length difference"; - opt->desc = "Difference in page length to trigger double feed error"; + opt->title = SANE_I18N ("DF length difference"); + opt->desc = SANE_I18N ("Difference in page length to trigger double feed error"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->df_diff_list; @@ -3694,8 +3705,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->df_recovery_list[3] = NULL; opt->name = "df-recovery"; - opt->title = "DF recovery mode"; - opt->desc = "Request scanner to reverse feed on paper jam"; + opt->title = SANE_I18N ("DF recovery mode"); + opt->desc = SANE_I18N ("Request scanner to reverse feed on paper jam"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->df_recovery_list; @@ -3714,8 +3725,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->paper_protect_list[3] = NULL; opt->name = "paper-protect"; - opt->title = "Paper protection"; - opt->desc = "Request scanner to predict jams in the ADF"; + opt->title = SANE_I18N ("Paper protection"); + opt->desc = SANE_I18N ("Request scanner to predict jams in the ADF"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->paper_protect_list; @@ -3734,8 +3745,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->adv_paper_prot_list[3] = NULL; opt->name = "adv-paper-protect"; - opt->title = "Advanced paper protection"; - opt->desc = "Request scanner to predict jams in the ADF using improved sensors"; + opt->title = SANE_I18N ("Advanced paper protection"); + opt->desc = SANE_I18N ("Request scanner to predict jams in the ADF using improved sensors"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->adv_paper_prot_list; @@ -3754,8 +3765,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->staple_detect_list[3] = NULL; opt->name = "staple-detect"; - opt->title = "Staple detection"; - opt->desc = "Request scanner to detect jams in the ADF caused by staples"; + opt->title = SANE_I18N ("Staple detection"); + opt->desc = SANE_I18N ("Request scanner to detect jams in the ADF caused by staples"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->staple_detect_list; @@ -3774,8 +3785,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->bg_color_list[3] = NULL; opt->name = "bgcolor"; - opt->title = "Background color"; - opt->desc = "Set color of background for scans. May conflict with overscan option"; + opt->title = SANE_I18N ("Background color"); + opt->desc = SANE_I18N ("Set color of background for scans. May conflict with overscan option"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->bg_color_list; @@ -3795,8 +3806,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->do_color_list[4] = NULL; opt->name = "dropoutcolor"; - opt->title = "Dropout color"; - opt->desc = "One-pass scanners use only one color during gray or binary scanning, useful for colored paper or ink"; + opt->title = SANE_I18N ("Dropout color"); + opt->desc = SANE_I18N ("One-pass scanners use only one color during gray or binary scanning, useful for colored paper or ink"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->do_color_list; @@ -3819,8 +3830,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->buff_mode_list[3] = NULL; opt->name = "buffermode"; - opt->title = "Buffer mode"; - opt->desc = "Request scanner to read pages quickly from ADF into internal memory"; + opt->title = SANE_I18N ("Buffer mode"); + opt->desc = SANE_I18N ("Request scanner to read pages quickly from ADF into internal memory"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->buff_mode_list; @@ -3839,8 +3850,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->prepick_list[3] = NULL; opt->name = "prepick"; - opt->title = "Prepick"; - opt->desc = "Request scanner to grab next page from ADF"; + opt->title = SANE_I18N ("Prepick"); + opt->desc = SANE_I18N ("Request scanner to grab next page from ADF"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->prepick_list; @@ -3859,8 +3870,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->overscan_list[3] = NULL; opt->name = "overscan"; - opt->title = "Overscan"; - opt->desc = "Collect a few mm of background on top side of scan, before paper enters ADF, and increase maximum scan area beyond paper size, to allow collection on remaining sides. May conflict with bgcolor option"; + opt->title = SANE_I18N ("Overscan"); + opt->desc = SANE_I18N ("Collect a few mm of background on top side of scan, before paper enters ADF, and increase maximum scan area beyond paper size, to allow collection on remaining sides. May conflict with bgcolor option"); opt->type = SANE_TYPE_STRING; opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; opt->constraint.string_list = s->overscan_list; @@ -3878,8 +3889,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->sleep_time_range.quant = 1; opt->name = "sleeptimer"; - opt->title = "Sleep timer"; - opt->desc = "Time in minutes until the internal power supply switches to sleep mode"; + opt->title = SANE_I18N ("Sleep timer"); + opt->desc = SANE_I18N ("Time in minutes until the internal power supply switches to sleep mode"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3897,8 +3908,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->off_time_range.quant = 1; opt->name = "offtimer"; - opt->title = "Off timer"; - opt->desc = "Time in minutes until the internal power supply switches the scanner off. Will be rounded to nearest 15 minutes. Zero means never power off."; + opt->title = SANE_I18N ("Off timer"); + opt->desc = SANE_I18N ("Time in minutes until the internal power supply switches the scanner off. Will be rounded to nearest 15 minutes. Zero means never power off."); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3916,8 +3927,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->duplex_offset_range.quant = 1; opt->name = "duplexoffset"; - opt->title = "Duplex offset"; - opt->desc = "Adjust front/back offset"; + opt->title = SANE_I18N ("Duplex offset"); + opt->desc = SANE_I18N ("Adjust front/back offset"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3934,8 +3945,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->green_offset_range.quant = 1; opt->name = "greenoffset"; - opt->title = "Green offset"; - opt->desc = "Adjust green/red offset"; + opt->title = SANE_I18N ("Green offset"); + opt->desc = SANE_I18N ("Adjust green/red offset"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3952,8 +3963,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->blue_offset_range.quant = 1; opt->name = "blueoffset"; - opt->title = "Blue offset"; - opt->desc = "Adjust blue/red offset"; + opt->title = SANE_I18N ("Blue offset"); + opt->desc = SANE_I18N ("Adjust blue/red offset"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3966,8 +3977,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_LOW_MEM){ opt->name = "lowmemory"; - opt->title = "Low Memory"; - opt->desc = "Limit driver memory usage for use in embedded systems. Causes some duplex transfers to alternate sides on each call to sane_read. Value of option 'side' can be used to determine correct image. This option should only be used with custom front-end software."; + opt->title = SANE_I18N ("Low Memory"); + opt->desc = SANE_I18N ("Limit driver memory usage for use in embedded systems. Causes some duplex transfers to alternate sides on each call to sane_read. Value of option 'side' can be used to determine correct image. This option should only be used with custom front-end software."); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; opt->size = sizeof(SANE_Word); @@ -3982,8 +3993,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_SIDE){ opt->name = "side"; - opt->title = "Duplex side"; - opt->desc = "Tells which side (0=front, 1=back) of a duplex scan the next call to sane_read will return."; + opt->title = SANE_I18N ("Duplex side"); + opt->desc = SANE_I18N ("Tells which side (0=front, 1=back) of a duplex scan the next call to sane_read will return."); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; opt->size = sizeof(SANE_Word); @@ -3994,8 +4005,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*deskew and crop by hardware*/ if(option==OPT_HWDESKEWCROP){ opt->name = "hwdeskewcrop"; - opt->title = "Hardware deskew and crop"; - opt->desc = "Request scanner to rotate and crop pages digitally."; + opt->title = SANE_I18N ("Hardware deskew and crop"); + opt->desc = SANE_I18N ("Request scanner to rotate and crop pages digitally."); opt->type = SANE_TYPE_BOOL; if (s->has_hybrid_crop_deskew) opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; @@ -4006,8 +4017,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*deskew by software*/ if(option==OPT_SWDESKEW){ opt->name = "swdeskew"; - opt->title = "Software deskew"; - opt->desc = "Request driver to rotate skewed pages digitally."; + opt->title = SANE_I18N ("Software deskew"); + opt->desc = SANE_I18N ("Request driver to rotate skewed pages digitally."); opt->type = SANE_TYPE_BOOL; if (1) opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; @@ -4019,8 +4030,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_SWDESPECK){ opt->name = "swdespeck"; - opt->title = "Software despeckle diameter"; - opt->desc = "Maximum diameter of lone dots to remove from scan."; + opt->title = SANE_I18N ("Software despeckle diameter"); + opt->desc = SANE_I18N ("Maximum diameter of lone dots to remove from scan."); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -4039,8 +4050,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*crop by software*/ if(option==OPT_SWCROP){ opt->name = "swcrop"; - opt->title = "Software crop"; - opt->desc = "Request driver to remove border from pages digitally."; + opt->title = SANE_I18N ("Software crop"); + opt->desc = SANE_I18N ("Request driver to remove border from pages digitally."); opt->type = SANE_TYPE_BOOL; if (1) opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; @@ -4069,8 +4080,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*halt scanner feeder when cancelling*/ if(option==OPT_HALT_ON_CANCEL){ opt->name = "halt-on-cancel"; - opt->title = "Halt on Cancel"; - opt->desc = "Request driver to halt the paper feed instead of eject during a cancel."; + opt->title = SANE_I18N ("Halt on Cancel"); + opt->desc = SANE_I18N ("Request driver to halt the paper feed instead of eject during a cancel."); opt->type = SANE_TYPE_BOOL; if (s->has_op_halt) opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; @@ -4081,8 +4092,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /* "Endorser" group ------------------------------------------------------ */ if(option==OPT_ENDORSER_GROUP){ opt->name = "endorser-options"; - opt->title = "Endorser Options"; - opt->desc = "Controls for endorser unit"; + opt->title = SANE_I18N ("Endorser Options"); + opt->desc = SANE_I18N ("Controls for endorser unit"); opt->type = SANE_TYPE_GROUP; opt->constraint_type = SANE_CONSTRAINT_NONE; @@ -4093,8 +4104,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER){ opt->name = "endorser"; - opt->title = "Endorser"; - opt->desc = "Enable endorser unit"; + opt->title = SANE_I18N ("Endorser"); + opt->desc = SANE_I18N ("Enable endorser unit"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; opt->size = sizeof(SANE_Word); @@ -4109,8 +4120,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER_BITS){ opt->name = "endorser-bits"; - opt->title = "Endorser bits"; - opt->desc = "Determines maximum endorser counter value."; + opt->title = SANE_I18N ("Endorser bits"); + opt->desc = SANE_I18N ("Determines maximum endorser counter value."); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->size = sizeof(SANE_Word); @@ -4135,8 +4146,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER_VAL){ opt->name = "endorser-val"; - opt->title = "Endorser value"; - opt->desc = "Initial endorser counter value."; + opt->title = SANE_I18N ("Endorser value"); + opt->desc = SANE_I18N ("Initial endorser counter value."); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->size = sizeof(SANE_Word); @@ -4159,8 +4170,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER_STEP){ opt->name = "endorser-step"; - opt->title = "Endorser step"; - opt->desc = "Change endorser counter value by this much for each page."; + opt->title = SANE_I18N ("Endorser step"); + opt->desc = SANE_I18N ("Change endorser counter value by this much for each page."); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->size = sizeof(SANE_Word); @@ -4183,8 +4194,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER_Y){ opt->name = "endorser-y"; - opt->title = "Endorser Y"; - opt->desc = "Endorser print offset from top of paper."; + opt->title = SANE_I18N ("Endorser Y"); + opt->desc = SANE_I18N ("Endorser print offset from top of paper."); opt->type = SANE_TYPE_FIXED; opt->unit = SANE_UNIT_MM; opt->size = sizeof(SANE_Word); @@ -4209,8 +4220,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER_FONT){ opt->name = "endorser-font"; - opt->title = "Endorser font"; - opt->desc = "Endorser printing font."; + opt->title = SANE_I18N ("Endorser font"); + opt->desc = SANE_I18N ("Endorser printing font."); opt->type = SANE_TYPE_STRING; opt->unit = SANE_UNIT_NONE; @@ -4239,8 +4250,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER_DIR){ opt->name = "endorser-dir"; - opt->title = "Endorser direction"; - opt->desc = "Endorser printing direction."; + opt->title = SANE_I18N ("Endorser direction"); + opt->desc = SANE_I18N ("Endorser printing direction."); opt->type = SANE_TYPE_STRING; opt->unit = SANE_UNIT_NONE; @@ -4264,8 +4275,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER_SIDE){ opt->name = "endorser-side"; - opt->title = "Endorser side"; - opt->desc = "Endorser printing side, requires hardware support to change"; + opt->title = SANE_I18N ("Endorser side"); + opt->desc = SANE_I18N ("Endorser printing side, requires hardware support to change"); opt->type = SANE_TYPE_STRING; opt->unit = SANE_UNIT_NONE; @@ -4290,8 +4301,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ENDORSER_STRING){ opt->name = "endorser-string"; - opt->title = "Endorser string"; - opt->desc = "Endorser alphanumeric print format. %05ud or %08ud at the end will be replaced by counter value."; + opt->title = SANE_I18N ("Endorser string"); + opt->desc = SANE_I18N ("Endorser alphanumeric print format. %05ud or %08ud at the end will be replaced by counter value."); opt->type = SANE_TYPE_STRING; opt->unit = SANE_UNIT_NONE; opt->size = s->endorser_string_len + 1; @@ -4318,8 +4329,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_TOP){ opt->name = "top-edge"; - opt->title = "Top edge"; - opt->desc = "Paper is pulled partly into adf"; + opt->title = SANE_I18N ("Top edge"); + opt->desc = SANE_I18N ("Paper is pulled partly into adf"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) @@ -4330,8 +4341,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_A3){ opt->name = "a3-paper"; - opt->title = "A3 paper"; - opt->desc = "A3 paper detected"; + opt->title = SANE_I18N ("A3 paper"); + opt->desc = SANE_I18N ("A3 paper detected"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4342,8 +4353,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_B4){ opt->name = "b4-paper"; - opt->title = "B4 paper"; - opt->desc = "B4 paper detected"; + opt->title = SANE_I18N ("B4 paper"); + opt->desc = SANE_I18N ("B4 paper detected"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4354,8 +4365,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_A4){ opt->name = "a4-paper"; - opt->title = "A4 paper"; - opt->desc = "A4 paper detected"; + opt->title = SANE_I18N ("A4 paper"); + opt->desc = SANE_I18N ("A4 paper detected"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4366,8 +4377,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_B5){ opt->name = "b5-paper"; - opt->title = "B5 paper"; - opt->desc = "B5 paper detected"; + opt->title = SANE_I18N ("B5 paper"); + opt->desc = SANE_I18N ("B5 paper detected"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4390,8 +4401,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_OMR){ opt->name = "omr-df"; - opt->title = "OMR or DF"; - opt->desc = "OMR or double feed detected"; + opt->title = SANE_I18N ("OMR or DF"); + opt->desc = SANE_I18N ("OMR or double feed detected"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4414,8 +4425,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_SLEEP){ opt->name = "power-save"; - opt->title = "Power saving"; - opt->desc = "Scanner in power saving mode"; + opt->title = SANE_I18N ("Power saving"); + opt->desc = SANE_I18N ("Scanner in power saving mode"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4438,8 +4449,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_MANUAL_FEED){ opt->name = "manual-feed"; - opt->title = "Manual feed"; - opt->desc = "Manual feed selected"; + opt->title = SANE_I18N ("Manual feed"); + opt->desc = SANE_I18N ("Manual feed selected"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4462,8 +4473,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_FUNCTION){ opt->name = "function"; - opt->title = "Function"; - opt->desc = "Function character on screen"; + opt->title = SANE_I18N ("Function"); + opt->desc = SANE_I18N ("Function character on screen"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) @@ -4474,8 +4485,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_INK_EMPTY){ opt->name = "ink-low"; - opt->title = "Ink low"; - opt->desc = "Imprinter ink running low"; + opt->title = SANE_I18N ("Ink low"); + opt->desc = SANE_I18N ("Imprinter ink running low"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status && (s->has_endorser_f || s->has_endorser_b)) @@ -4486,8 +4497,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_DOUBLE_FEED){ opt->name = "double-feed"; - opt->title = "Double feed"; - opt->desc = "Double feed detected"; + opt->title = SANE_I18N ("Double feed"); + opt->desc = SANE_I18N ("Double feed detected"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) @@ -4498,8 +4509,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_ERROR_CODE){ opt->name = "error-code"; - opt->title = "Error code"; - opt->desc = "Hardware error code"; + opt->title = SANE_I18N ("Error code"); + opt->desc = SANE_I18N ("Hardware error code"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4510,8 +4521,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_SKEW_ANGLE){ opt->name = "skew-angle"; - opt->title = "Skew angle"; - opt->desc = "Requires black background for scanning"; + opt->title = SANE_I18N ("Skew angle"); + opt->desc = SANE_I18N ("Requires black background for scanning"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) @@ -4522,8 +4533,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_INK_REMAIN){ opt->name = "ink-remain"; - opt->title = "Ink remaining"; - opt->desc = "Imprinter ink level"; + opt->title = SANE_I18N ("Ink remaining"); + opt->desc = SANE_I18N ("Imprinter ink level"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status && (s->has_endorser_f || s->has_endorser_b)) @@ -4534,8 +4545,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_DENSITY_SW){ opt->name = "density"; - opt->title = "Density"; - opt->desc = "Density dial"; + opt->title = SANE_I18N ("Density"); + opt->desc = SANE_I18N ("Density dial"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; if (s->ghs_in_rs) @@ -4546,8 +4557,8 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_DUPLEX_SW){ opt->name = "duplex"; - opt->title = "Duplex switch"; - opt->desc = "Duplex switch"; + opt->title = SANE_I18N ("Duplex switch"); + opt->desc = SANE_I18N ("Duplex switch"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->ghs_in_rs) @@ -4749,18 +4760,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, } return SANE_STATUS_GOOD; - case OPT_IPC_MODE: - if(s->ipc_mode == WD_ipc_DEFAULT){ - strcpy (val, STRING_DEFAULT); - } - else if(s->ipc_mode == WD_ipc_DTC){ - strcpy (val, STRING_DTC); - } - else if(s->ipc_mode == WD_ipc_SDTC){ - strcpy (val, STRING_SDTC); - } - return SANE_STATUS_GOOD; - + /* DTC params*/ case OPT_BP_FILTER: *val_p = s->bp_filter; return SANE_STATUS_GOOD; @@ -4801,6 +4801,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *val_p = s->matrix_2; return SANE_STATUS_GOOD; + /* SDTC params*/ case OPT_VARIANCE: *val_p = s->variance; return SANE_STATUS_GOOD; @@ -5357,6 +5358,14 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (s->page_width == FIXED_MM_TO_SCANNER_UNIT(val_c)) return SANE_STATUS_GOOD; + /* if full width image, and paper size is changed, + change the image size to match new paper */ + if (s->tl_x == 0 && s->br_x == s->page_width){ + DBG (20, "sane_control_option: br_x tracking page_width\n"); + s->br_x = FIXED_MM_TO_SCANNER_UNIT(val_c); + *info |= SANE_INFO_RELOAD_PARAMS; + } + s->page_width = FIXED_MM_TO_SCANNER_UNIT(val_c); *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; @@ -5365,6 +5374,14 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (s->page_height == FIXED_MM_TO_SCANNER_UNIT(val_c)) return SANE_STATUS_GOOD; + /* if full height image, and paper size is changed, + change the image size to match new paper */ + if (s->tl_y == 0 && s->br_y == s->page_height){ + DBG (20, "sane_control_option: br_y tracking page_height\n"); + s->br_y = FIXED_MM_TO_SCANNER_UNIT(val_c); + *info |= SANE_INFO_RELOAD_PARAMS; + } + s->page_height = FIXED_MM_TO_SCANNER_UNIT(val_c); *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; @@ -5429,48 +5446,35 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->wl_follow = WD_wl_follow_OFF; return SANE_STATUS_GOOD; - case OPT_IPC_MODE: - if (!strcmp (val, STRING_DEFAULT)) { - tmp = WD_ipc_DEFAULT; - } - else if (!strcmp (val, STRING_DTC)) { - tmp = WD_ipc_DTC; - } - else { - tmp = WD_ipc_SDTC; - } - - if (tmp != s->ipc_mode) - *info |= SANE_INFO_RELOAD_OPTIONS; - - s->ipc_mode = tmp; - return SANE_STATUS_GOOD; - + /* DTC params*/ case OPT_BP_FILTER: s->bp_filter = val_c; + *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; case OPT_SMOOTHING: s->smoothing = val_c; + *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; case OPT_GAMMA_CURVE: s->gamma_curve = val_c; + *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; case OPT_THRESHOLD_CURVE: s->threshold_curve = val_c; + *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; case OPT_THRESHOLD_WHITE: s->threshold_white = val_c; + *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; case OPT_NOISE_REMOVAL: - if (val_c != s->noise_removal) - *info |= SANE_INFO_RELOAD_OPTIONS; - s->noise_removal = val_c; + *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; case OPT_MATRIX_5: @@ -5489,8 +5493,10 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->matrix_2 = val_c; return SANE_STATUS_GOOD; + /* SDTC params*/ case OPT_VARIANCE: s->variance = val_c; + *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; /* Advanced Group */ @@ -6681,7 +6687,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) return ret; } -/* set s_param and u_param data based on user settings +/* set s_params and u_params data based on user settings * and scanner capabilities. */ SANE_Status update_params (struct fujitsu * s) @@ -6926,8 +6932,9 @@ sane_start (SANE_Handle handle) if (ret != SANE_STATUS_GOOD) DBG (5, "sane_start: WARNING: cannot send_endorser %d\n", ret); - /* send lut if scanner has no hardware brightness/contrast */ - if (!s->late_lut && (!s->brightness_steps || !s->contrast_steps)){ + /* send lut if scanner has no hardware brightness/contrast, + * or we are going to ask it to use a downloaded gamma table */ + if (!s->late_lut && (!s->brightness_steps || !s->contrast_steps || s->window_gamma & 0x80)){ ret = send_lut(s); if (ret != SANE_STATUS_GOOD) DBG (5, "sane_start: WARNING: cannot early send_lut %d\n", ret); @@ -6940,8 +6947,9 @@ sane_start (SANE_Handle handle) goto errors; } - /* send lut if scanner has no hardware brightness/contrast */ - if (s->late_lut && (!s->brightness_steps || !s->contrast_steps)){ + /* send lut if scanner has no hardware brightness/contrast, + * or we are going to ask it to use a downloaded gamma table */ + if (s->late_lut && (!s->brightness_steps || !s->contrast_steps || s->window_gamma & 0x80)){ ret = send_lut(s); if (ret != SANE_STATUS_GOOD) DBG (5, "sane_start: WARNING: cannot late send_lut %d\n", ret); @@ -7573,15 +7581,15 @@ set_window (struct fujitsu *s) set_WD_separation(desc1,s->separation); set_WD_mirroring(desc1,s->mirroring); - if (s->has_sdtc && s->ipc_mode != WD_ipc_DTC) + if (get_ipc_mode(s) == WD_ipc_SDTC) set_WD_variance(desc1,s->variance); - if ((s->has_dtc && !s->has_sdtc) || s->ipc_mode == WD_ipc_DTC){ - set_WD_filtering(desc1,!s->bp_filter); - set_WD_smoothing(desc1,!s->smoothing); + else if (get_ipc_mode(s) == WD_ipc_DTC){ + set_WD_filtering(desc1,s->bp_filter); + set_WD_smoothing(desc1,s->smoothing); set_WD_gamma_curve(desc1,s->gamma_curve); set_WD_threshold_curve(desc1,s->threshold_curve); - set_WD_noise_removal(desc1,!s->noise_removal); + set_WD_noise_removal(desc1,s->noise_removal); if(s->noise_removal){ set_WD_matrix5x5(desc1,s->matrix_5); set_WD_matrix4x4(desc1,s->matrix_4); @@ -7593,7 +7601,7 @@ set_window (struct fujitsu *s) set_WD_wl_follow(desc1,s->wl_follow); set_WD_subwindow_list(desc1,0); - set_WD_ipc_mode(desc1,s->ipc_mode); + set_WD_ipc_mode(desc1,get_ipc_mode(s)); } else{ @@ -7691,8 +7699,8 @@ get_pixelsize(struct fujitsu *s, int actual) /* when we are called post-scan, the scanner may give * more accurate data in other fields */ if(actual && !s->has_short_pixelsize && get_PSIZE_paper_w(in)){ + DBG(5,"get_pixelsize: Actual width %d -> %d\n", s->s_params.pixels_per_line, get_PSIZE_paper_w(in)); s->s_params.pixels_per_line = get_PSIZE_paper_w(in); - DBG(5,"get_pixelsize: Actual width\n"); } else{ s->s_params.pixels_per_line = get_PSIZE_num_x(in); @@ -7707,8 +7715,8 @@ get_pixelsize(struct fujitsu *s, int actual) /* when we are called post-scan, the scanner may give * more accurate data in other fields */ else if(actual && !s->has_short_pixelsize && get_PSIZE_paper_l(in)){ + DBG(5,"get_pixelsize: Actual length %d -> %d\n", s->s_params.lines, get_PSIZE_paper_l(in)); s->s_params.lines = get_PSIZE_paper_l(in); - DBG(5,"get_pixelsize: Actual length\n"); } else{ s->s_params.lines = get_PSIZE_num_y(in); @@ -9867,6 +9875,43 @@ get_page_height(struct fujitsu *s) return height; } +/* scanners have two different possible IPC + * modes, which enable a different series of + * subordinate options. Rather than provide + * the user with an option to pick the IPC + * mode, we show them the subordinate ones, + * and pick the right mode to match. + */ +static int +get_ipc_mode(struct fujitsu *s) +{ + if ( s->bp_filter + || s->smoothing + || s->gamma_curve + || s->threshold_curve + || s->threshold_white + || s->noise_removal + || s->matrix_5 + || s->matrix_4 + || s->matrix_3 + || s->matrix_2 + ) + return WD_ipc_DTC; + + if(s->variance) + return WD_ipc_SDTC; + + /* special case: 0 threshold should activate IPC */ + if(!s->threshold){ + if(s->has_sdtc) + return WD_ipc_SDTC; + if(s->has_dtc) + return WD_ipc_DTC; + } + + return WD_ipc_DEFAULT; +} + /* s->max_y gives the maximum height of paper which can be scanned * this actually varies by resolution, so a helper to change it */ static int diff --git a/backend/fujitsu.conf.in b/backend/fujitsu.conf.in index b3895ea..5fa0003 100644 --- a/backend/fujitsu.conf.in +++ b/backend/fujitsu.conf.in @@ -121,7 +121,13 @@ usb 0x04c5 0x119e #S1500 & S1500M usb 0x04c5 0x11a2 -#fi-6140Z +#fi-6125 +usb 0x04c5 0x11ee + +#fi-6225 +usb 0x04c5 0x11ef + +#fi-6140Z/fi-6160ZLA usb 0x04c5 0x11f1 #fi-6240Z @@ -157,6 +163,108 @@ usb 0x04c5 0x132e #fi-7260 usb 0x04c5 0x132f +#ScanSnap iX500EE +usb 0x04c5 0x13f3 + #ScanSnap iX100 usb 0x04c5 0x13f4 +#ScanPartner SP25 +usb 0x04c5 0x1409 + +#ScanPartner SP30 +usb 0x04c5 0x140a + +#ScanPartner SP30F +usb 0x04c5 0x140c + +#fi-6140ZLA +usb 0x04c5 0x145f + +#fi-6240ZLA +usb 0x04c5 0x1460 + +#fi-6130ZLA +usb 0x04c5 0x1461 + +#fi-6230ZLA +usb 0x04c5 0x1462 + +#fi-6125ZLA +usb 0x04c5 0x1463 + +#fi-6225ZLA +usb 0x04c5 0x1464 + +#fi-6135ZLA +usb 0x04c5 0x146b + +#fi-6235ZLA +usb 0x04c5 0x146c + +#fi-6120ZLA +usb 0x04c5 0x146d + +#fi-6220ZLA +usb 0x04c5 0x146e + +#N7100 +usb 0x04c5 0x146f + +#fi-6400 +usb 0x04c5 0x14ac + +#fi-7480 +usb 0x04c5 0x14b8 + +#fi-6420 +usb 0x04c5 0x14bd + +#fi-7460 +usb 0x04c5 0x14be + +#fi-7140 +usb 0x04c5 0x14df + +#fi-7240 +usb 0x04c5 0x14e0 + +#fi-7135 +usb 0x04c5 0x14e1 + +#fi-7235 +usb 0x04c5 0x14e2 + +#fi-7130 +usb 0x04c5 0x14e3 + +#fi-7230 +usb 0x04c5 0x14e4 + +#fi-7125 +usb 0x04c5 0x14e5 + +#fi-7225 +usb 0x04c5 0x14e6 + +#fi-7120 +usb 0x04c5 0x14e7 + +#fi-7220 +usb 0x04c5 0x14e8 + +#fi-400F +usb 0x04c5 0x151e + +#fi-7030 +usb 0x04c5 0x151f + +#fi-7700 +usb 0x04c5 0x1520 + +#fi-7600 +usb 0x04c5 0x1521 + +#fi-7700S +usb 0x04c5 0x1522 + diff --git a/backend/fujitsu.h b/backend/fujitsu.h index 6ce1a56..916f069 100644 --- a/backend/fujitsu.h +++ b/backend/fujitsu.h @@ -43,7 +43,6 @@ enum fujitsu_Option OPT_SEPARATION, OPT_MIRRORING, OPT_WL_FOLLOW, - OPT_IPC_MODE, /*IPC/DTC*/ OPT_BP_FILTER, @@ -386,7 +385,6 @@ struct fujitsu SANE_Range ht_pattern_range; SANE_Range emphasis_range; SANE_String_Const wl_follow_list[4]; - SANE_String_Const ipc_mode_list[4]; SANE_Range gamma_curve_range; SANE_Range threshold_curve_range; SANE_Range variance_range; @@ -456,7 +454,6 @@ struct fujitsu int separation; int mirroring; int wl_follow; - int ipc_mode; /* ipc_mode=DTC */ int bp_filter; @@ -534,12 +531,6 @@ struct fujitsu SANE_Parameters u_params; SANE_Parameters s_params; - /* also keep a backup copy, in case the software enhancement code overwrites*/ - /* - SANE_Parameters u_params_bk; - SANE_Parameters s_params_bk; - */ - /* --------------------------------------------------------------------- */ /* values which are set by scanning functions to keep track of pages, etc */ int started; @@ -821,6 +812,7 @@ static int must_downsample (struct fujitsu *s); static int must_fully_buffer (struct fujitsu *s); static int get_page_width (struct fujitsu *s); static int get_page_height (struct fujitsu *s); +static int get_ipc_mode (struct fujitsu *s); static int set_max_y (struct fujitsu *s); static SANE_Status send_lut (struct fujitsu *s); diff --git a/backend/genesys.c b/backend/genesys.c index 984cead..db0a2b2 100644 --- a/backend/genesys.c +++ b/backend/genesys.c @@ -2,7 +2,7 @@ Copyright (C) 2003, 2004 Henning Meier-Geinitz Copyright (C) 2004, 2005 Gerhard Jaeger - Copyright (C) 2004-2015 Stéphane Voltz + Copyright (C) 2004-2016 Stéphane Voltz Copyright (C) 2005-2009 Pierre Willenbrock Copyright (C) 2006 Laurent Charpentier Copyright (C) 2007 Luke @@ -58,7 +58,7 @@ * SANE backend for Genesys Logic GL646/GL841/GL842/GL843/GL846/GL847/GL124 based scanners */ -#define BUILD 2508 +#define BUILD 2511 #define BACKEND_NAME genesys #include "genesys.h" @@ -387,7 +387,7 @@ sanei_genesys_create_slope_table3 (Genesys_Device * dev, DBG (DBG_proc, "%s: step_type = %d, " - "exposure_time = %d, yres = %g, power_mode = %d\n", __FUNCTION__, step_type, + "exposure_time = %d, yres = %g, power_mode = %d\n", __func__, step_type, exposure_time, yres, power_mode); /* final speed */ @@ -792,7 +792,7 @@ sanei_genesys_exposure_time2 (Genesys_Device * dev, float ydpi, exposure = exposure_by_led; DBG (DBG_info, "%s: ydpi=%d, step=%d, endpixel=%d led=%d, power=%d => exposure=%d\n", - __FUNCTION__, (int)ydpi, step_type, endpixel, exposure_by_led, power_mode, exposure); + __func__, (int)ydpi, step_type, endpixel, exposure_by_led, power_mode, exposure); return exposure; } @@ -928,7 +928,7 @@ genesys_send_offset_and_shading (Genesys_Device * dev, uint8_t * data, int start_address; SANE_Status status; - DBG (DBG_proc, "%s: (size = %d)\n", __FUNCTION__, size); + DBG (DBG_proc, "%s: (size = %d)\n", __func__, size); /* ASIC higher than gl843 doesn't have register 2A/2B, so we route to * a per ASIC shading data loading function if available. @@ -978,7 +978,7 @@ genesys_send_offset_and_shading (Genesys_Device * dev, uint8_t * data, status = sanei_genesys_set_buffer_address (dev, start_address); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to set buffer address: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus (status)); return status; } @@ -986,7 +986,7 @@ genesys_send_offset_and_shading (Genesys_Device * dev, uint8_t * data, status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to send shading table: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to send shading table: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1046,7 +1046,7 @@ sanei_genesys_init_shading_data (Genesys_Device * dev, int pixels_per_line) free (shading_data); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to send shading data: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to send shading data: %s\n", __func__, sane_strstatus (status)); } @@ -1489,7 +1489,7 @@ genesys_coarse_calibration (Genesys_Device * dev) status = dev->model->cmd_set->set_fe (dev, AFE_INIT); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to set frontend: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus (status)); free(all_data); free(calibration_data); @@ -2069,9 +2069,12 @@ genesys_white_shading_calibration (Genesys_Device * dev) /* turn on motor and lamp power */ dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE); dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); - if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) + + /* if needed, go back before doin next scan, by using rewind, registers and + * slopes table are kept intact from previous scan */ + if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK && dev->model->cmd_set->rewind) { - status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); + status = dev->model->cmd_set->rewind (dev); } status = @@ -2180,7 +2183,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev) SANE_Bool motor; - DBG (DBG_proc, "%s: (lines = %d)\n", __FUNCTION__, (unsigned int)dev->calib_lines); + DBG (DBG_proc, "%s: (lines = %d)\n", __func__, (unsigned int)dev->calib_lines); pixels_per_line = dev->calib_pixels; channels = dev->calib_channels; @@ -2193,7 +2196,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev) dev->white_average_data = malloc (dev->average_size); if (!dev->white_average_data) { - DBG (DBG_error, "%s: failed to allocate white average memory\n", __FUNCTION__); + DBG (DBG_error, "%s: failed to allocate white average memory\n", __func__); return SANE_STATUS_NO_MEM; } @@ -2203,7 +2206,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev) dev->dark_average_data = malloc (channels * 2 * pixels_per_line); if (!dev->dark_average_data) { - DBG (DBG_error, "%s: failed to allocate dark average memory\n", __FUNCTION__); + DBG (DBG_error, "%s: failed to allocate dark average memory\n", __func__); return SANE_STATUS_NO_MEM; } @@ -2212,7 +2215,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev) calibration_data = malloc (size); if (!calibration_data) { - DBG (DBG_error, "%s: failed to allocate calibration memory\n", __FUNCTION__); + DBG (DBG_error, "%s: failed to allocate calibration memory\n", __func__); return SANE_STATUS_NO_MEM; } @@ -2233,7 +2236,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { free (calibration_data); - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2243,7 +2246,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { free (calibration_data); - DBG (DBG_error, "%s: failed to begin scan: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2252,7 +2255,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { free (calibration_data); - DBG (DBG_error, "%s: failed to read data: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2261,7 +2264,7 @@ genesys_dark_white_shading_calibration (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { free (calibration_data); - DBG (DBG_error, "%s: Failed to end scan: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: Failed to end scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2434,7 +2437,7 @@ compute_averaged_planar (Genesys_Device * dev, unsigned int x, i, j, br, dk, res, avgpixels, basepixels, val; unsigned int fill,factor; - DBG (DBG_info, "%s: pixels=%d, offset=%d\n", __FUNCTION__, pixels_per_line, o); + DBG (DBG_info, "%s: pixels=%d, offset=%d\n", __func__, pixels_per_line, o); /* initialize result */ memset (shading_data, 0xff, words_per_color * 3 * 2); @@ -2504,9 +2507,9 @@ compute_averaged_planar (Genesys_Device * dev, fill=1; } - DBG (DBG_info, "%s: averaging over %d pixels\n", __FUNCTION__, avgpixels); - DBG (DBG_info, "%s: packing factor is %d\n", __FUNCTION__, factor); - DBG (DBG_info, "%s: fill length is %d\n", __FUNCTION__, fill); + DBG (DBG_info, "%s: averaging over %d pixels\n", __func__, avgpixels); + DBG (DBG_info, "%s: packing factor is %d\n", __func__, factor); + DBG (DBG_info, "%s: fill length is %d\n", __func__, fill); for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) { @@ -2903,7 +2906,7 @@ genesys_send_shading_coefficient (Genesys_Device * dev) shading_data = malloc (length); if (!shading_data) { - DBG (DBG_error, "%s: failed to allocate memory\n", __FUNCTION__); + DBG (DBG_error, "%s: failed to allocate memory\n", __func__); return SANE_STATUS_NO_MEM; } memset (shading_data, 0, length); @@ -3071,7 +3074,7 @@ genesys_send_shading_coefficient (Genesys_Device * dev) shading_data = malloc (length); if (!shading_data) { - DBG (DBG_error, "%s: failed to allocate memory\n", __FUNCTION__); + DBG (DBG_error, "%s: failed to allocate memory\n", __func__); return SANE_STATUS_NO_MEM; } memset (shading_data, 0, length); @@ -3121,7 +3124,7 @@ genesys_send_shading_coefficient (Genesys_Device * dev) 256); /* patch_size: contigous extent */ break; default: - DBG (DBG_error, "%s: sensor %d not supported\n", __FUNCTION__, dev->model->ccd_type); + DBG (DBG_error, "%s: sensor %d not supported\n", __func__, dev->model->ccd_type); return SANE_STATUS_UNSUPPORTED; break; } @@ -3131,7 +3134,7 @@ genesys_send_shading_coefficient (Genesys_Device * dev) free (shading_data); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to send shading data: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to send shading data: %s\n", __func__, sane_strstatus (status)); } @@ -3689,7 +3692,7 @@ genesys_sheetfed_calibration (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { dev->model->cmd_set->eject_document (dev); - DBG (DBG_error, "%s: failed eject target: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed eject target: %s\n", __func__, sane_strstatus (status)); return status; } @@ -3821,7 +3824,7 @@ genesys_warmup_lamp (Genesys_Device * dev) /* check if the current chipset implements warmup */ if(dev->model->cmd_set->init_regs_for_warmup==NULL) { - DBG (DBG_error, "%s: init_regs_for_warmup not implemented\n", __FUNCTION__); + DBG (DBG_error, "%s: init_regs_for_warmup not implemented\n", __func__); return status; } @@ -4346,7 +4349,7 @@ genesys_fill_line_interp_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read %lu bytes (%s)\n", __FUNCTION__, + "%s: failed to read %lu bytes (%s)\n", __func__, (u_long) dev->oe_buffer.size, sane_strstatus (status)); return SANE_STATUS_IO_ERROR; } @@ -4383,7 +4386,7 @@ genesys_fill_line_interp_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read %lu bytes (%s)\n", __FUNCTION__, + "%s: failed to read %lu bytes (%s)\n", __func__, (u_long) dev->oe_buffer.size, sane_strstatus (status)); return SANE_STATUS_IO_ERROR; } @@ -4417,7 +4420,7 @@ genesys_fill_segmented_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, s if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read %lu bytes (%s)\n", __FUNCTION__, + "%s: failed to read %lu bytes (%s)\n", __func__, (u_long) dev->oe_buffer.size, sane_strstatus (status)); return SANE_STATUS_IO_ERROR; } @@ -4508,7 +4511,7 @@ genesys_fill_segmented_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, s if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read %lu bytes (%s)\n", __FUNCTION__, + "%s: failed to read %lu bytes (%s)\n", __func__, (u_long) dev->oe_buffer.size, sane_strstatus (status)); return SANE_STATUS_IO_ERROR; } @@ -5496,7 +5499,7 @@ GENESYS_STATIC char *calibration_filename(Genesys_Device *currdev) snprintf (tmpstr, PATH_MAX, "%s%c.sane%c%s", ptr, PATH_SEP, PATH_SEP, filename); } - DBG (DBG_info, "%s: calibration filename >%s<\n", __FUNCTION__, tmpstr); + DBG (DBG_info, "%s: calibration filename >%s<\n", __func__, tmpstr); return tmpstr; } @@ -5893,7 +5896,7 @@ init_options (Genesys_Scanner * s) DISABLE (OPT_COLOR_FILTER); } - /* calibration stor file name */ + /* calibration store file name */ s->opt[OPT_CALIBRATION_FILE].name = "calibration-file"; s->opt[OPT_CALIBRATION_FILE].title = SANE_I18N ("Calibration file"); s->opt[OPT_CALIBRATION_FILE].desc = SANE_I18N ("Specify the calibration file to use"); @@ -6330,7 +6333,7 @@ probe_genesys_devices (void) free (new_dev); } - DBG(DBG_info, "%s: %d devices currently attached\n", __FUNCTION__, num_devices); + DBG(DBG_info, "%s: %d devices currently attached\n", __func__, num_devices); DBGCOMPLETED; @@ -6545,7 +6548,7 @@ genesys_buffer_image(Genesys_Scanner *s) lines = (SANE_UNFIX (dev->model->y_size) * dev->settings.yres) / MM_PER_INCH; } - DBG (DBG_info, "%s: buffering %d lines of %d bytes\n", __FUNCTION__, lines, + DBG (DBG_info, "%s: buffering %d lines of %d bytes\n", __func__, lines, s->params.bytes_per_line); /* maximum bytes to read */ @@ -6568,7 +6571,7 @@ genesys_buffer_image(Genesys_Scanner *s) { DBG (DBG_error, "%s: digital processing requires too much memory.\nConsider disabling it\n", - __FUNCTION__); + __func__); return SANE_STATUS_NO_MEM; } @@ -6585,7 +6588,7 @@ genesys_buffer_image(Genesys_Scanner *s) if (status != SANE_STATUS_EOF && status != SANE_STATUS_GOOD) { free (s->dev->img_buffer); - DBG (DBG_error, "%s: %s buffering failed\n", __FUNCTION__, + DBG (DBG_error, "%s: %s buffering failed\n", __func__, sane_strstatus (status)); return status; } @@ -6600,7 +6603,7 @@ genesys_buffer_image(Genesys_Scanner *s) { DBG (DBG_error0, "%s: digital processing requires too much memory.\nConsider disabling it\n", - __FUNCTION__); + __func__); return SANE_STATUS_NO_MEM; } } @@ -6627,7 +6630,7 @@ genesys_buffer_image(Genesys_Scanner *s) { DBG (DBG_error0, "%s: digital processing requires too much memory.\nConsider disabling it\n", - __FUNCTION__); + __func__); return SANE_STATUS_NO_MEM; } genesys_gray_lineart (dev, @@ -6669,10 +6672,10 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) DBG_INIT (); DBG (DBG_init, "SANE Genesys backend version %d.%d build %d from %s\n", SANE_CURRENT_MAJOR, V_MINOR, BUILD, PACKAGE_STRING); -#ifdef HAVE_LIBUSB_1_0 +#ifdef HAVE_LIBUSB DBG (DBG_init, "SANE Genesys backend built with libusb-1.0\n"); #endif -#ifdef HAVE_LIBUSB +#ifdef HAVE_LIBUSB_LEGACY DBG (DBG_init, "SANE Genesys backend built with libusb\n"); #endif @@ -6942,8 +6945,8 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) tmpstr=calibration_filename(s->dev); s->val[OPT_CALIBRATION_FILE].s = strdup (tmpstr); s->dev->calib_file = strdup (tmpstr); - DBG (DBG_info, "%s: Calibration filename set to:\n", __FUNCTION__); - DBG (DBG_info, "%s: >%s<\n", __FUNCTION__, s->dev->calib_file); + DBG (DBG_info, "%s: Calibration filename set to:\n", __func__); + DBG (DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file); free(tmpstr); /* now open file, fetch calibration records */ @@ -7033,7 +7036,9 @@ sane_close (SANE_Handle handle) FREE_IFNOT_NULL (s->dev->sensor.gamma_table[1]); FREE_IFNOT_NULL (s->dev->sensor.gamma_table[2]); - /* for an handful of bytes .. */ + s->dev->already_initialized = SANE_FALSE; + + /* for an handful of bytes .. */ free ((void *)(size_t)s->opt[OPT_RESOLUTION].constraint.word_list); free (s->val[OPT_SOURCE].s); free (s->val[OPT_MODE].s); @@ -7125,6 +7130,7 @@ get_option_value (Genesys_Scanner * s, int option, void *val) case OPT_DESPECK: case OPT_CONTRAST: case OPT_BRIGHTNESS: + case OPT_EXPIRATION_TIME: *(SANE_Word *) val = s->val[option].w; break; case OPT_CUSTOM_GAMMA: @@ -7245,8 +7251,8 @@ static SANE_Status set_calibration_value (Genesys_Scanner * s, int option, void if (tmp) free (tmp); dev->calib_file = strdup (val); - DBG (DBG_info, "%s: Calibration filename set to:\n", __FUNCTION__); - DBG (DBG_info, "%s: >%s<\n", __FUNCTION__, s->dev->calib_file); + DBG (DBG_info, "%s: Calibration filename set to:\n", __func__); + DBG (DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file); DBGCOMPLETED; return SANE_STATUS_GOOD; @@ -7536,7 +7542,7 @@ set_option_value (Genesys_Scanner * s, int option, void *val, { DBG (DBG_error, "%s: failed to disable power saving mode: %s\n", - __FUNCTION__, sane_strstatus (status)); + __func__, sane_strstatus (status)); } else status = genesys_scanner_calibration (s->dev); diff --git a/backend/genesys.conf.in b/backend/genesys.conf.in index 7899455..5273d51 100644 --- a/backend/genesys.conf.in +++ b/backend/genesys.conf.in @@ -2,7 +2,7 @@ # # scanners that are not yet supported -# uncomment them only for developpment purpose +# uncomment them only for development purpose # # UMAX Astra 4500 and Avision iVina 1600 diff --git a/backend/genesys_conv.c b/backend/genesys_conv.c index 0346ad6..61f466e 100644 --- a/backend/genesys_conv.c +++ b/backend/genesys_conv.c @@ -1,7 +1,7 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2005, 2006 Pierre Willenbrock - Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2010-2013 Stéphane Voltz This file is part of the SANE package. @@ -295,7 +295,7 @@ genesys_shrink_lines_1 ( else { /* TODO: since depth is 1, we must interpolate bit within bytes */ - DBG (DBG_warn, "%s: inaccurate bit expansion!\n", __FUNCTION__); + DBG (DBG_warn, "%s: inaccurate bit expansion!\n", __func__); cnt = dst_pixels / 2; dst_x = 0; for (src_x = 0; src_x < src_pixels; src_x++) @@ -332,7 +332,7 @@ genesys_crop(Genesys_Scanner *s) int left = 0; int right = 0; - DBG (DBG_proc, "%s: start\n", __FUNCTION__); + DBG (DBG_proc, "%s: start\n", __func__); /* first find edges if any */ status = sanei_magic_findEdges (&s->params, @@ -345,10 +345,10 @@ genesys_crop(Genesys_Scanner *s) &right); if (status != SANE_STATUS_GOOD) { - DBG (DBG_info, "%s: bad or no edges, bailing\n", __FUNCTION__); + DBG (DBG_info, "%s: bad or no edges, bailing\n", __func__); goto cleanup; } - DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __FUNCTION__, top, bottom, left, + DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __func__, top, bottom, left, right); /* now crop the image */ @@ -356,7 +356,7 @@ genesys_crop(Genesys_Scanner *s) sanei_magic_crop (&(s->params), dev->img_buffer, top, bottom, left, right); if (status) { - DBG (DBG_warn, "%s: failed to crop\n", __FUNCTION__); + DBG (DBG_warn, "%s: failed to crop\n", __func__); goto cleanup; } @@ -364,7 +364,7 @@ genesys_crop(Genesys_Scanner *s) dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; cleanup: - DBG (DBG_proc, "%s: completed\n", __FUNCTION__); + DBG (DBG_proc, "%s: completed\n", __func__); return SANE_STATUS_GOOD; } @@ -382,7 +382,7 @@ genesys_deskew(Genesys_Scanner *s) int x = 0, y = 0, bg; double slope = 0; - DBG (DBG_proc, "%s: start\n", __FUNCTION__); + DBG (DBG_proc, "%s: start\n", __func__); bg=0; if(s->params.format==SANE_FRAME_GRAY && s->params.depth == 1) @@ -398,10 +398,10 @@ genesys_deskew(Genesys_Scanner *s) &slope); if (status!=SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: bad findSkew, bailing\n", __FUNCTION__); + DBG (DBG_error, "%s: bad findSkew, bailing\n", __func__); return SANE_STATUS_GOOD; } - DBG(DBG_info, "%s: slope=%f => %f\n",__FUNCTION__,slope, (slope/M_PI_2)*90); + DBG(DBG_info, "%s: slope=%f => %f\n",__func__,slope, (slope/M_PI_2)*90); /* rotate image slope is in [-PI/2,PI/2] * positive values rotate trigonometric direction wise */ status = sanei_magic_rotate (&s->params, @@ -412,10 +412,10 @@ genesys_deskew(Genesys_Scanner *s) bg); if (status!=SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: rotate error: %s", __FUNCTION__, sane_strstatus(status)); + DBG (DBG_error, "%s: rotate error: %s", __func__, sane_strstatus(status)); } - DBG (DBG_proc, "%s: completed\n", __FUNCTION__); + DBG (DBG_proc, "%s: completed\n", __func__); return SANE_STATUS_GOOD; } @@ -430,7 +430,7 @@ genesys_despeck(Genesys_Scanner *s) s->dev->img_buffer, s->val[OPT_DESPECK].w)!=SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: bad despeck, bailing\n",__FUNCTION__); + DBG (DBG_error, "%s: bad despeck, bailing\n",__func__); } return SANE_STATUS_GOOD; @@ -454,7 +454,7 @@ genesys_derotate (Genesys_Scanner * s) if (status) { - DBG (DBG_warn, "%s: failed : %d\n", __FUNCTION__, status); + DBG (DBG_warn, "%s: failed : %d\n", __func__, status); DBGCOMPLETED; return SANE_STATUS_GOOD; } @@ -463,7 +463,7 @@ genesys_derotate (Genesys_Scanner * s) status = sanei_magic_turn (&s->params, s->dev->img_buffer, angle); if (status) { - DBG (DBG_warn, "%s: failed : %d\n", __FUNCTION__, status); + DBG (DBG_warn, "%s: failed : %d\n", __func__, status); DBGCOMPLETED; return SANE_STATUS_GOOD; } diff --git a/backend/genesys_devices.c b/backend/genesys_devices.c index 775ffb6..11f2579 100644 --- a/backend/genesys_devices.c +++ b/backend/genesys_devices.c @@ -3,12 +3,12 @@ Copyright (C) 2003 Oliver Rauch Copyright (C) 2003-2005 Henning Meier-Geinitz Copyright (C) 2004, 2005 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2004-2013 Stéphane Voltz Copyright (C) 2005-2009 Pierre Willenbrock Copyright (C) 2007 Luke Copyright (C) 2010 Jack McGill Copyright (C) 2010 Andrey Loginov , - xerox travelscan device entry + xerox travelscan device entry Copyright (C) 2010 Chris Berry and Michael Rickmann for Plustek Opticbook 3600 support @@ -64,28 +64,28 @@ static Genesys_Frontend Wolfson[] = { , {0x02, 0x02, 0x02} , {0x00, 0x00, 0x00} } - , /* 0: UMAX */ + , /* 0: UMAX */ {DAC_WOLFSON_ST12, {0x00, 0x03, 0x05, 0x03} , {0x00, 0x00, 0x00} , {0xc8, 0xc8, 0xc8} , {0x04, 0x04, 0x04} , {0x00, 0x00, 0x00} } - , /* 1: ST12 */ + , /* 1: ST12 */ {DAC_WOLFSON_ST24,{0x00, 0x03, 0x05, 0x21} , {0x00, 0x00, 0x00} , {0xc8, 0xc8, 0xc8} , {0x06, 0x06, 0x06} , {0x00, 0x00, 0x00} } - , /* 2: ST24 */ + , /* 2: ST24 */ {DAC_WOLFSON_5345,{0x00, 0x03, 0x05, 0x12} , {0x00, 0x00, 0x00} , {0xb8, 0xb8, 0xb8} , {0x04, 0x04, 0x04} , {0x00, 0x00, 0x00} } - , /* 3: MD6228/MD6471 */ + , /* 3: MD6228/MD6471 */ {DAC_WOLFSON_HP2400, /* reg0 reg1 reg2 reg3 */ {0x00, 0x03, 0x05, 0x02} /* reg3=0x02 for 50-600 dpi, 0x32 (0x12 also works well) at 1200 */ @@ -94,7 +94,7 @@ static Genesys_Frontend Wolfson[] = { , {0x06, 0x09, 0x08} , {0x00, 0x00, 0x00} } - , /* 4: HP2400c */ + , /* 4: HP2400c */ {DAC_WOLFSON_HP2300, {0x00, 0x03, 0x04, 0x02} , {0x00, 0x00, 0x00} @@ -102,16 +102,16 @@ static Genesys_Frontend Wolfson[] = { , {0x04, 0x04, 0x04} , {0x00, 0x00, 0x00} } - , /* 5: HP2300c */ + , /* 5: HP2300c */ {DAC_CANONLIDE35,{0x00, 0x3d, 0x08, 0x00} , {0x00, 0x00, 0x00} , {0xe1, 0xe1, 0xe1} , {0x93, 0x93, 0x93} , {0x00, 0x19, 0x06} } - , /* 6: CANONLIDE35 */ + , /* 6: CANONLIDE35 */ {DAC_AD_XP200, - {0x58, 0x80, 0x00, 0x00} /* reg1=0x80 ? */ + {0x58, 0x80, 0x00, 0x00} /* reg1=0x80 ? */ , {0x00, 0x00, 0x00} , {0x09, 0x09, 0x09} , {0x09, 0x09, 0x09} @@ -124,7 +124,7 @@ static Genesys_Frontend Wolfson[] = { , {0x93, 0x93, 0x93} , {0x07, 0x00, 0x00} } - , /* 8: HP3670 */ + , /* 8: HP3670 */ {DAC_WOLFSON_HP3670, /* reg0 reg1 reg2 reg3 */ {0x00, 0x03, 0x05, 0x32} /* reg3=0x32 for 100-300 dpi, 0x12 at 1200 */ @@ -156,7 +156,7 @@ static Genesys_Frontend Wolfson[] = { , {0x2f, 0x04, 0x00} , {0x00, 0x00, 0x00} } - , /* KV-SS080 */ + , /* KV-SS080 */ {DAC_KVSS080, {0x00, 0x23, 0x24, 0x0f} , {0x00, 0x00, 0x00} @@ -168,7 +168,7 @@ static Genesys_Frontend Wolfson[] = { {DAC_G4050, {0x00, 0x23, 0x24, 0x1f} , {0x00, 0x00, 0x00} - , {0x45, 0x45, 0x45} /* 0x20, 0x21, 0x22 */ + , {0x45, 0x45, 0x45} /* 0x20, 0x21, 0x22 */ , {0x4b, 0x4b, 0x4b} /* 0x28, 0x29, 0x2a */ , {0x00,0x00,0x00} } @@ -181,6 +181,22 @@ static Genesys_Frontend Wolfson[] = { , {0x00, 0x00, 0x00} } , + /** @brief GL124 special case + * for GL124 based scanners, this struct is "abused" + * in fact the fields are map like below to AFE registers + * (from Texas Instrument or alike ?) + */ + {DAC_CANONLIDE120, + {0x80, + /* 0001 0002 0003 */ + 0xa3, 0x2b, 0x4c} + /* 0005 0006 0007 */ + , {0x00, 0xca, 0x95} + , {0x00, 0x00, 0x00} + , {0x00, 0x00, 0x00} + , {0x00, 0x00, 0x00} + } + , {DAC_PLUSTEK_3600, {0x70, 0x80, 0x00, 0x00} , {0x00, 0x00, 0x00} @@ -192,7 +208,7 @@ static Genesys_Frontend Wolfson[] = { {DAC_CS8400F, {0x00, 0x23, 0x24, 0x0f} , {0x00, 0x00, 0x00} - , {0x60, 0x5c, 0x6c} /* 0x20, 0x21, 0x22 */ + , {0x60, 0x5c, 0x6c} /* 0x20, 0x21, 0x22 */ , {0x8a, 0x9f, 0xc2} /* 0x28, 0x29, 0x2a */ , {0x00, 0x00, 0x00} } @@ -200,7 +216,7 @@ static Genesys_Frontend Wolfson[] = { {DAC_IMG101, {0x78, 0xf0, 0x00, 0x00} , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} /* 0x20, 0x21, 0x22 */ + , {0x00, 0x00, 0x00} /* 0x20, 0x21, 0x22 */ , {0x00, 0x00, 0x00} /* 0x28, 0x29, 0x2a */ , {0x00, 0x00, 0x00} } @@ -208,7 +224,7 @@ static Genesys_Frontend Wolfson[] = { {DAC_PLUSTEK3800, {0x78, 0xf0, 0x00, 0x00} , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} /* 0x20, 0x21, 0x22 */ + , {0x00, 0x00, 0x00} /* 0x20, 0x21, 0x22 */ , {0x00, 0x00, 0x00} /* 0x28, 0x29, 0x2a */ , {0x00, 0x00, 0x00} }, @@ -296,7 +312,7 @@ static Genesys_Sensor Sensor[] = { {CCD_HP2300, 600, 48, - 20, 0, 5368, 180, 180, /* 5376 */ + 20, 0, 5368, 180, 180, /* 5376 */ {0x16, 0x00, 0x01, 0x03} , {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x0a, 0x20, 0x2a, 0x6a, 0x8a, 0x00, 0x05} , {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83, 0x00, 0xc1, 0x06, 0x0b, 0x10, 0x16} , @@ -307,21 +323,21 @@ static Genesys_Sensor Sensor[] = { /* CANOLIDE35 */ {CCD_CANONLIDE35, 1200, - 87, /* (black) */ - 87, /* (dummy) */ - 0, /* (startxoffset) */ - 10400, /* sensor_pixels */ + 87, /* (black) */ + 87, /* (dummy) */ + 0, /* (startxoffset) */ + 10400, /* sensor_pixels */ 0, 0, {0x00, 0x00, 0x00, 0x00}, {0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x50, - 0x00, 0x00, 0x00, 0x02 /* TODO(these do no harm, but may be neccessery for CCD) */ + 0x00, 0x00, 0x00, 0x02 /* TODO(these do no harm, but may be neccessery for CCD) */ }, {0x05, 0x07, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ + 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ 0x3a, 0x03, - 0x40, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x00 /*TODO (these do no harm, but may be neccessery for CCD) */ + 0x40, /*TODO: bit7 */ + 0x00, 0x00, 0x00, 0x00 /*TODO (these do no harm, but may be neccessery for CCD) */ } , {1.0, 1.0, 1.0}, @@ -353,10 +369,10 @@ static Genesys_Sensor Sensor[] = { , /* Syscan DP 665 */ {CCD_DP665, 600, - 27, /*(black) */ - 27, /* (dummy) */ - 0, /* (startxoffset) */ - 2496, /*sensor_pixels */ + 27, /*(black) */ + 27, /* (dummy) */ + 0, /* (startxoffset) */ + 2496, /*sensor_pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -364,10 +380,10 @@ static Genesys_Sensor Sensor[] = { 0x10, 0x00, 0x20, 0x02 }, {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ + 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ + 0x00, /*TODO: bit7 */ + 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ } , {1.0, 1.0, 1.0}, @@ -376,10 +392,10 @@ static Genesys_Sensor Sensor[] = { , /* Visioneer Roadwarrior */ {CCD_ROADWARRIOR, 600, - 27, /*(black) */ - 27, /* (dummy) */ - 0, /* (startxoffset) */ - 5200, /*sensor_pixels */ + 27, /*(black) */ + 27, /* (dummy) */ + 0, /* (startxoffset) */ + 5200, /*sensor_pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -387,10 +403,10 @@ static Genesys_Sensor Sensor[] = { 0x10, 0x00, 0x20, 0x02 }, {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ + 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ + 0x00, /*TODO: bit7 */ + 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ } , {1.0, 1.0, 1.0}, @@ -399,10 +415,10 @@ static Genesys_Sensor Sensor[] = { , /* Pentax DS Mobile 600 */ {CCD_DSMOBILE600, 600, - 28, /*(black) */ - 28, /* (dummy) */ - 0, /* (startxoffset) */ - 5200, /*sensor_pixels */ + 28, /*(black) */ + 28, /* (dummy) */ + 0, /* (startxoffset) */ + 5200, /*sensor_pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -410,10 +426,10 @@ static Genesys_Sensor Sensor[] = { 0x10, 0x00, 0x20, 0x02 }, {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ + 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ + 0x00, /*TODO: bit7 */ + 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ } , {1.0, 1.0, 1.0}, @@ -422,10 +438,10 @@ static Genesys_Sensor Sensor[] = { , /* 13: Strobe XP300 */ {CCD_XP300, 600, - 27, /*(black) */ - 27, /* (dummy) */ - 0, /* (startxoffset) */ - 10240, /*sensor_pixels */ + 27, /*(black) */ + 27, /* (dummy) */ + 0, /* (startxoffset) */ + 10240, /*sensor_pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -433,10 +449,10 @@ static Genesys_Sensor Sensor[] = { 0x10, 0x00, 0x20, 0x02 }, {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ + 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ + 0x00, /*TODO: bit7 */ + 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ } , {1.0, 1.0, 1.0}, @@ -445,10 +461,10 @@ static Genesys_Sensor Sensor[] = { , /* 13: Strobe XP300 */ {CCD_DP685, 600, - 27, /*(black) */ - 27, /* (dummy) */ - 0, /* (startxoffset) */ - 5020, /*sensor_pixels */ + 27, /*(black) */ + 27, /* (dummy) */ + 0, /* (startxoffset) */ + 5020, /*sensor_pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -456,10 +472,10 @@ static Genesys_Sensor Sensor[] = { 0x10, 0x00, 0x20, 0x02 }, {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ + 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ + 0x00, /*TODO: bit7 */ + 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ } , {1.0, 1.0, 1.0}, @@ -468,10 +484,10 @@ static Genesys_Sensor Sensor[] = { , /* CANONLIDE200 */ {CIS_CANONLIDE200, - 4800, /* optical resolution */ - 87*4, /* black pixels */ - 16*4, /* dummy pixels */ - 320*8, /* CCD_startx_offset 323 */ + 4800, /* optical resolution */ + 87*4, /* black pixels */ + 16*4, /* dummy pixels */ + 320*8, /* CCD_startx_offset 323 */ 5136*8, 210, 200, @@ -494,11 +510,11 @@ static Genesys_Sensor Sensor[] = { , /* CANONLIDE700 */ {CIS_CANONLIDE700, - 4800, /* optical resolution */ - 73*8, /* black pixels 73 at 600 dpi */ - 16*8, /* dummy pixels */ - 384*8, /* CCD_startx_offset 384 at 600 dpi */ - 5188*8, /* 8x5570 segments , 5187+1 for rounding */ + 4800, /* optical resolution */ + 73*8, /* black pixels 73 at 600 dpi */ + 16*8, /* dummy pixels */ + 384*8, /* CCD_startx_offset 384 at 600 dpi */ + 5188*8, /* 8x5570 segments , 5187+1 for rounding */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -520,10 +536,10 @@ static Genesys_Sensor Sensor[] = { , /* CANONLIDE100 */ {CIS_CANONLIDE100, - 2400, /* optical resolution */ - 87*4, /* black pixels */ - 16*4, /* dummy pixels 16 */ - 320*4, /* 323 */ + 2400, /* optical resolution */ + 87*4, /* black pixels */ + 16*4, /* dummy pixels 16 */ + 320*4, /* 323 */ 5136*4, /* 10272 */ 210, 200, @@ -565,8 +581,8 @@ static Genesys_Sensor Sensor[] = { , {CCD_G4050, 4800, - 50*8, /* black_pixels */ - 58, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ + 50*8, /* black_pixels */ + 58, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ 152, 5360*8, /* 5360 max at 600 dpi */ 160, @@ -583,8 +599,8 @@ static Genesys_Sensor Sensor[] = { , {CCD_CS4400F, 4800, - 50*8, /* black_pixels */ - 20, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ + 50*8, /* black_pixels */ + 20, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ 152, 5360*8, /* 5360 max at 600 dpi */ 160, @@ -601,8 +617,8 @@ static Genesys_Sensor Sensor[] = { , {CCD_CS8400F, 4800, - 50*8, /* black_pixels */ - 20, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ + 50*8, /* black_pixels */ + 20, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ 152, 5360*8, /* 5360 max at 600 dpi */ 160, @@ -639,11 +655,11 @@ static Genesys_Sensor Sensor[] = { /* CANONLIDE110 */ {CIS_CANONLIDE110, - 2400, /* optical resolution */ - 87, /* black pixels */ - 16, /* dummy pixels 16 */ - 303, /* 303 */ - 5168*4, /* total pixels */ + 2400, /* optical resolution */ + 87, /* black pixels */ + 16, /* dummy pixels 16 */ + 303, /* 303 */ + 5168*4, /* total pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -663,22 +679,25 @@ static Genesys_Sensor Sensor[] = { /* CANONLIDE120 */ {CIS_CANONLIDE120, - 2400, /* optical resolution */ - 87, /* black pixels */ - 16, /* dummy pixels 16 */ - 303, /* 303 */ - 5168*4, /* total pixels */ + 2400, /* optical resolution */ + 87, /* black pixels */ + 16, /* dummy pixels 16 */ + 303, + /* SEGCNT at 600 DPI by number of segments */ + 5104*4, /* total pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, /* reg 0x10 - 0x15 : EXPR, EXPG and EXPB */ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* reg 0x16 - 0x1d */ - 0x10, 0x04, 0x00, 0x01, 0x30, 0x00, 0x02, 0x01 }, + 0x15, 0x04, 0x00, 0x01, 0x30, 0x00, 0x02, 0x01 }, /* reg 0x52 - 0x5e */ { - 0x00, 0x02, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, - 0x1a, 0x00, 0xc0, 0x00, 0x00 + /* 52 53 54 55 56 57 58 59 */ + 0x04, 0x06, 0x00, 0x02, 0x04, 0x04, 0x04, 0x04, + /* 5a 5b 5c 5d 5e */ + 0x3a, 0x00, 0x00, 0x00, 0x1f } , {2.1, 2.1, 2.1}, @@ -686,11 +705,11 @@ static Genesys_Sensor Sensor[] = { , /* CANON LIDE 210 sensor */ {CIS_CANONLIDE210, - 2400, /* optical resolution */ - 87, /* black pixels */ - 16, /* dummy pixels 16 */ - 303, /* 303 */ - 5168*4, /* total pixels */ + 2400, /* optical resolution */ + 87, /* black pixels */ + 16, /* dummy pixels 16 */ + 303, /* 303 */ + 5168*4, /* total pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -709,11 +728,11 @@ static Genesys_Sensor Sensor[] = { , /* CANON LIDE 220 sensor */ {CIS_CANONLIDE220, - 2400, /* optical resolution */ - 87, /* black pixels */ - 16, /* dummy pixels 16 */ - 303, /* 303 */ - 5168*4, /* total pixels */ + 2400, /* optical resolution */ + 87, /* black pixels */ + 16, /* dummy pixels 16 */ + 303, /* 303 */ + 5168*4, /* total pixels */ 210, 200, {0x00, 0x00, 0x00, 0x00}, @@ -732,21 +751,21 @@ static Genesys_Sensor Sensor[] = { , {CCD_PLUSTEK_3600, 1200, - 87, /*(black) */ - 87, /* (dummy) */ - 0, /* (startxoffset) */ - 10100, /*sensor_pixels */ + 87, /*(black) */ + 87, /* (dummy) */ + 0, /* (startxoffset) */ + 10100, /*sensor_pixels */ 210, 230, {0x00, 0x00, 0x00, 0x00}, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x0b, 0x11, 0x2a, - 0x00, 0x00, 0x00, 0xc4 /* TODO(these do no harm, but may be neccessery for CCD) */ + 0x00, 0x00, 0x00, 0xc4 /* TODO(these do no harm, but may be neccessery for CCD) */ }, {0x07, 0x0a, - 0x0c, 0x00, 0x02, 0x06, /*[GB](HI|LOW) not needed for cis */ + 0x0c, 0x00, 0x02, 0x06, /*[GB](HI|LOW) not needed for cis */ 0x22, 0x69, - 0x40, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x02 /*TODO (these do no harm, but may be neccessery for CCD) */ + 0x40, /*TODO: bit7 */ + 0x00, 0x00, 0x00, 0x02 /*TODO (these do no harm, but may be neccessery for CCD) */ } , {1.0, 1.0, 1.0}, @@ -754,7 +773,7 @@ static Genesys_Sensor Sensor[] = { , /* Canon Image formula 101 */ {CCD_IMG101, - 1200, /* optical resolution */ + 1200, /* optical resolution */ 31, 31, 0, @@ -781,7 +800,7 @@ static Genesys_Sensor Sensor[] = { , /* Plustek OpticBook 3800 */ {CCD_PLUSTEK3800, - 1200, /* optical resolution */ + 1200, /* optical resolution */ 31, 31, 0, @@ -857,7 +876,7 @@ static Genesys_Gpo Gpo[] = { /* MD5345/MD6471 */ {GPO_5345, {0x30, 0x18} - , /* bits 11-12 are for bipolar V-ref input voltage */ + , /* bits 11-12 are for bipolar V-ref input voltage */ {0xa0, 0x18} , } @@ -921,7 +940,7 @@ static Genesys_Gpo Gpo[] = { }, /* CANONLIDE200 */ {GPO_CANONLIDE200, - {0xfb, 0x20}, /* 0xfb when idle , 0xf9/0xe9 (1200) when scanning */ + {0xfb, 0x20}, /* 0xfb when idle , 0xf9/0xe9 (1200) when scanning */ {0xff, 0x00}, }, /* CANONLIDE700 */ @@ -951,6 +970,12 @@ static Genesys_Gpo Gpo[] = { {0xff, 0x00}, } , + /* CANONLIDE120 */ + {GPO_CANONLIDE120, + {0xfb, 0x20}, + {0xff, 0x00}, + } + , /* CANONLIDE210 */ {GPO_CANONLIDE210, {0xfb, 0x20}, @@ -997,15 +1022,15 @@ static Genesys_Gpo Gpo[] = { static Genesys_Motor Motor[] = { /* UMAX */ {MOTOR_UMAX, - 1200, /* motor base steps */ - 2400, /* maximum motor resolution */ - 1, /* maximum step mode */ + 1200, /* motor base steps */ + 2400, /* maximum motor resolution */ + 1, /* maximum step mode */ 1, /* number of power modes*/ {{{ - 11000, /* maximum start speed */ - 3000, /* maximum end speed */ - 128, /* step count */ - 1.0, /* nonlinearity */ + 11000, /* maximum start speed */ + 3000, /* maximum end speed */ + 128, /* step count */ + 1.0, /* nonlinearity */ }, { 11000, @@ -1014,7 +1039,7 @@ static Genesys_Motor Motor[] = { 1.0, },},}, }, - {MOTOR_5345, /* MD5345/6228/6471 */ + {MOTOR_5345, /* MD5345/6228/6471 */ 1200, 2400, 1, @@ -1032,7 +1057,7 @@ static Genesys_Motor Motor[] = { 0.5, },},}, }, - {MOTOR_ST24, /* ST24 */ + {MOTOR_ST24, /* ST24 */ 2400, 2400, 1, @@ -1050,15 +1075,15 @@ static Genesys_Motor Motor[] = { 0.3, },},}, }, - {MOTOR_HP3670, /* HP 3670 */ + {MOTOR_HP3670, /* HP 3670 */ 1200, 2400, 1, 1, {{{ - 11000, /* start speed */ - 3000, /* max speed */ - 128, /* min steps */ + 11000, /* start speed */ + 3000, /* max speed */ + 128, /* min steps */ 0.25, }, { @@ -1068,15 +1093,15 @@ static Genesys_Motor Motor[] = { 0.5, },},}, }, - {MOTOR_HP2400, /* HP 2400c */ + {MOTOR_HP2400, /* HP 2400c */ 1200, 1200, 1, 1, {{{ - 11000, /* start speed */ - 3000, /* max speed */ - 128, /* min steps */ + 11000, /* start speed */ + 3000, /* max speed */ + 128, /* min steps */ 0.25, }, { @@ -1086,7 +1111,7 @@ static Genesys_Motor Motor[] = { 0.5, },},}, }, - {MOTOR_HP2300, /* HP 2300c */ + {MOTOR_HP2300, /* HP 2300c */ 600, /* 600/1200 */ 1200, 1, @@ -1104,7 +1129,7 @@ static Genesys_Motor Motor[] = { 0.5, },},}, }, - {MOTOR_CANONLIDE35, /* Canon LiDE 35 */ + {MOTOR_CANONLIDE35, /* Canon LiDE 35 */ 1200, 2400, 1, @@ -1112,7 +1137,7 @@ static Genesys_Motor Motor[] = { {{{ 3500, 1300, 60, 0.8, }, { 3500, 1400, 60, 0.8, },},}, }, - {MOTOR_XP200, /* Strobe XP200 */ + {MOTOR_XP200, /* Strobe XP200 */ 600, 600, 1, @@ -1130,7 +1155,7 @@ static Genesys_Motor Motor[] = { 0.5, },},}, }, - {MOTOR_XP300, /* 7: Visioneer Strobe XP300 */ + {MOTOR_XP300, /* 7: Visioneer Strobe XP300 */ 300, 600, 1, @@ -1148,7 +1173,7 @@ static Genesys_Motor Motor[] = { 0.8, },},}, }, - {MOTOR_DP665, /* Syscan DP 665 */ + {MOTOR_DP665, /* Syscan DP 665 */ 750, 1500, 1, @@ -1166,7 +1191,7 @@ static Genesys_Motor Motor[] = { 0.8, },},}, }, - {MOTOR_ROADWARRIOR, /* Visioneer Roadwarrior */ + {MOTOR_ROADWARRIOR, /* Visioneer Roadwarrior */ 750, 1500, 1, @@ -1184,7 +1209,7 @@ static Genesys_Motor Motor[] = { 0.8, },},}, }, - {MOTOR_DSMOBILE_600, /* Pentax DSmobile 600 */ + {MOTOR_DSMOBILE_600, /* Pentax DSmobile 600 */ 750, 1500, 2, @@ -1202,7 +1227,7 @@ static Genesys_Motor Motor[] = { 0.8, },},}, }, - {MOTOR_CANONLIDE100, /* Canon LiDE 100 */ + {MOTOR_CANONLIDE100, /* Canon LiDE 100 */ 1200, 6400, 2, /* maximum step type count */ @@ -1210,12 +1235,12 @@ static Genesys_Motor Motor[] = { { /* motor slopes */ { /* power mode 0 */ { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ + { 3000, 1500, 127, 0.50}, /* half step */ + { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ }, }, }, - {MOTOR_CANONLIDE200, /* Canon LiDE 200 */ + {MOTOR_CANONLIDE200, /* Canon LiDE 200 */ 1200, 6400, 2, @@ -1223,12 +1248,12 @@ static Genesys_Motor Motor[] = { { /* motor slopes */ { /* power mode 0 */ { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ + { 3000, 1500, 127, 0.50}, /* half step */ + { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ }, }, }, - {MOTOR_CANONLIDE700, /* Canon LiDE 700 */ + {MOTOR_CANONLIDE700, /* Canon LiDE 700 */ 1200, 6400, 2, @@ -1236,8 +1261,8 @@ static Genesys_Motor Motor[] = { { /* motor slopes */ { /* power mode 0 */ { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ + { 3000, 1500, 127, 0.50}, /* half step */ + { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ }, }, }, @@ -1248,10 +1273,10 @@ static Genesys_Motor Motor[] = { 1, { /* motor slopes */ { /* power mode 0 */ - { 22222, 500, 246, 0.5 }, /* max speed / dpi * base dpi => exposure */ - { 22222, 500, 246, 0.5 }, - { 22222, 500, 246, 0.5 }, - }, + { 22222, 500, 246, 0.5 }, /* max speed / dpi * base dpi => exposure */ + { 22222, 500, 246, 0.5 }, + { 22222, 500, 246, 0.5 }, + }, }, }, {MOTOR_G4050, @@ -1261,10 +1286,10 @@ static Genesys_Motor Motor[] = { 1, { /* motor slopes */ { /* power mode 0 */ - { 3961, 240, 246, 0.8 }, /* full step */ - { 3961, 240, 246, 0.8 }, /* half step */ - { 3961, 240, 246, 0.8 }, /* quarter step */ - }, + { 3961, 240, 246, 0.8 }, /* full step */ + { 3961, 240, 246, 0.8 }, /* half step */ + { 3961, 240, 246, 0.8 }, /* quarter step */ + }, }, }, {MOTOR_CS8400F, @@ -1274,13 +1299,13 @@ static Genesys_Motor Motor[] = { 1, { /* motor slopes */ { /* power mode 0 */ - { 3961, 240, 246, 0.8 }, /* full step */ - { 3961, 240, 246, 0.8 }, /* half step */ - { 3961, 240, 246, 0.8 }, /* quarter step */ - }, + { 3961, 240, 246, 0.8 }, /* full step */ + { 3961, 240, 246, 0.8 }, /* half step */ + { 3961, 240, 246, 0.8 }, /* quarter step */ + }, }, }, - {MOTOR_CANONLIDE110, /* Canon LiDE 110 */ + {MOTOR_CANONLIDE110, /* Canon LiDE 110 */ 4800, 9600, 1, /* maximum step type count */ @@ -1291,7 +1316,7 @@ static Genesys_Motor Motor[] = { }, }, }, - {MOTOR_CANONLIDE210, /* Canon LiDE 210 */ + {MOTOR_CANONLIDE120, /* Canon LiDE 120 */ 4800, 9600, 1, /* maximum step type count */ @@ -1302,7 +1327,18 @@ static Genesys_Motor Motor[] = { }, }, }, - {MOTOR_PLUSTEK_3600, /* PLUSTEK 3600 */ + {MOTOR_CANONLIDE210, /* Canon LiDE 210 */ + 4800, + 9600, + 1, /* maximum step type count */ + 1, /* maximum power modes count */ + { /* motor slopes */ + { /* power mode 0 */ + { 3000, 1000, 256, 0.50}, /* full step */ + }, + }, + }, + {MOTOR_PLUSTEK_3600, /* PLUSTEK 3600 */ 1200, 2400, 1, @@ -1313,7 +1349,7 @@ static Genesys_Motor Motor[] = { { 3500, 3250, 60, 0.8 }, }, },}, - {MOTOR_IMG101, /* Canon Image Formula 101 */ + {MOTOR_IMG101, /* Canon Image Formula 101 */ 600, 1200, 1, @@ -1324,7 +1360,7 @@ static Genesys_Motor Motor[] = { { 3500, 3250, 60, 0.8 }, }, },}, - {MOTOR_PLUSTEK3800, /* Plustek OpticBook 3800 */ + {MOTOR_PLUSTEK3800, /* Plustek OpticBook 3800 */ 600, 1200, 1, @@ -1338,8 +1374,8 @@ static Genesys_Motor Motor[] = { {MOTOR_CANONLIDE80, 2400, /* 2400 ???? */ 4800, /* 9600 ???? */ - 1, /* max step type */ - 1, /* power mode count */ + 1, /* max step type */ + 1, /* power mode count */ { { /* start speed, max end speed, step number */ /* maximum speed (second field) is used to compute exposure as seen by motor */ @@ -1355,48 +1391,48 @@ static Genesys_Motor Motor[] = { /* here we have the various device settings... */ static Genesys_Model umax_astra_4500_model = { - "umax-astra-4500", /* Name */ - "UMAX", /* Device vendor string */ - "Astra 4500", /* Device model name */ + "umax-astra-4500", /* Name */ + "UMAX", /* Device vendor string */ + "Astra 4500", /* Device model name */ GENESYS_GL646, NULL, - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + SANE_FIX (3.5), /* Start of scan area in mm (x) */ + SANE_FIX (7.5), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ + 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ + COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_UMAX, DAC_WOLFSON_UMAX, GPO_UMAX, MOTOR_UMAX, - GENESYS_FLAG_UNTESTED, /* Which flags are needed for this scanner? */ + GENESYS_FLAG_UNTESTED, /* Which flags are needed for this scanner? */ /* untested, values set by hmg */ GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ 20, @@ -1404,48 +1440,48 @@ static Genesys_Model umax_astra_4500_model = { }; static Genesys_Model canon_lide_50_model = { - "canon-lide-50", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 35/40/50", /* Device model name */ + "canon-lide-50", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 35/40/50", /* Device model name */ GENESYS_GL841, NULL, - { 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + { 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.42), /* Start of scan area in mm (x) */ - SANE_FIX (7.9), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + SANE_FIX (0.42), /* Start of scan area in mm (x) */ + SANE_FIX (7.9), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (6.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (6.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_CANONLIDE35, DAC_CANONLIDE35, GPO_CANONLIDE35, MOTOR_CANONLIDE35, - GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_DARK_WHITE_CALIBRATION | @@ -1460,43 +1496,43 @@ static Genesys_Model canon_lide_50_model = { }; static Genesys_Model panasonic_kvss080_model = { - "panasonic-kv-ss080", /* Name */ - "Panasonic", /* Device vendor string */ - "KV-SS080", /* Device model name */ + "panasonic-kv-ss080", /* Name */ + "Panasonic", /* Device vendor string */ + "KV-SS080", /* Device model name */ GENESYS_GL843, NULL, - { 600, /* 500, 400,*/ 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - { 1200, 600, /* 500, 400, */ 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + { 600, /* 500, 400,*/ 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + { 1200, 600, /* 500, 400, */ 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ + SANE_FIX (7.2), /* Start of scan area in mm (x) */ + SANE_FIX (14.7), /* Start of scan area in mm (y) */ + SANE_FIX (217.7), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (9.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ + 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_KVSS080, DAC_KVSS080, GPO_KVSS080, @@ -1511,45 +1547,45 @@ static Genesys_Model panasonic_kvss080_model = { }; static Genesys_Model hp4850c_model = { - "hewlett-packard-scanjet-4850c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 4850C", /* Device model name */ + "hewlett-packard-scanjet-4850c", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet 4850C", /* Device model name */ GENESYS_GL843, NULL, {2400, 1200, 600, 400, 300, 200, 150, 100, 0}, {2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ SANE_FIX (7.9), /* Start of scan area in mm (x) */ SANE_FIX (5.9), /* Start of scan area in mm (y) */ SANE_FIX (219.6), /* Size of scan area in mm (x) */ SANE_FIX (314.5), /* Size of scan area in mm (y) */ - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_G4050, DAC_G4050, GPO_G4050, @@ -1566,45 +1602,45 @@ static Genesys_Model hp4850c_model = { }; static Genesys_Model hpg4010_model = { - "hewlett-packard-scanjet-g4010", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet G4010", /* Device model name */ + "hewlett-packard-scanjet-g4010", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet G4010", /* Device model name */ GENESYS_GL843, NULL, { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (8.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ + SANE_FIX (8.0), /* Start of scan area in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (315.0), /* Size of scan area in mm (y) */ - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_G4050, DAC_G4050, GPO_G4050, @@ -1621,45 +1657,45 @@ static Genesys_Model hpg4010_model = { }; static Genesys_Model hpg4050_model = { - "hewlett-packard-scanjet-g4050", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet G4050", /* Device model name */ + "hewlett-packard-scanjet-g4050", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet G4050", /* Device model name */ GENESYS_GL843, NULL, { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (8.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ + SANE_FIX (8.0), /* Start of scan area in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (315.0), /* Size of scan area in mm (y) */ - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_G4050, DAC_G4050, GPO_G4050, @@ -1677,45 +1713,45 @@ static Genesys_Model hpg4050_model = { static Genesys_Model canon_4400f_model = { - "canon-canoscan-4400f", /* Name */ - "Canon", /* Device vendor string */ - "Canoscan 4400f", /* Device model name */ + "canon-canoscan-4400f", /* Name */ + "Canon", /* Device vendor string */ + "Canoscan 4400f", /* Device model name */ GENESYS_GL843, NULL, { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (6.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ + SANE_FIX (6.0), /* Start of scan area in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (315.0), /* Size of scan area in mm (y) */ - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_CS4400F, DAC_G4050, GPO_CS4400F, @@ -1727,7 +1763,7 @@ static Genesys_Model canon_4400f_model = { GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_DARK_CALIBRATION | GENESYS_FLAG_FULL_HWDPI_MODE | - GENESYS_FLAG_HALF_CCD_MODE | /* actually quarter CCD mode ... */ + GENESYS_FLAG_HALF_CCD_MODE | /* actually quarter CCD mode ... */ GENESYS_FLAG_CUSTOM_GAMMA, GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, 100, @@ -1736,45 +1772,45 @@ static Genesys_Model canon_4400f_model = { static Genesys_Model canon_8400f_model = { - "canon-canoscan-8400f", /* Name */ - "Canon", /* Device vendor string */ - "Canoscan 8400f", /* Device model name */ + "canon-canoscan-8400f", /* Name */ + "Canon", /* Device vendor string */ + "Canoscan 8400f", /* Device model name */ GENESYS_GL843, NULL, { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (4.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ + SANE_FIX (4.0), /* Start of scan area in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (315.0), /* Size of scan area in mm (y) */ - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_CS8400F, DAC_CS8400F, GPO_CS8400F, @@ -1795,43 +1831,43 @@ static Genesys_Model canon_8400f_model = { static Genesys_Model canon_lide_100_model = { - "canon-lide-100", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 100", /* Device model name */ + "canon-lide-100", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 100", /* Device model name */ GENESYS_GL847, NULL, - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + SANE_FIX (1.1), /* Start of scan area in mm (x) */ + SANE_FIX (8.3), /* Start of scan area in mm (y) */ + SANE_FIX (216.07), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (1.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE100, DAC_CANONLIDE200, GPO_CANONLIDE200, @@ -1849,43 +1885,43 @@ static Genesys_Model canon_lide_100_model = { }; static Genesys_Model canon_lide_110_model = { - "canon-lide-110", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 110", /* Device model name */ + "canon-lide-110", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 110", /* Device model name */ GENESYS_GL124, NULL, - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (9.0), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ + SANE_FIX (2.2), /* Start of scan area in mm (x) */ + SANE_FIX (9.0), /* Start of scan area in mm (y) */ + SANE_FIX (216.70), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (1.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE110, DAC_CANONLIDE110, GPO_CANONLIDE110, @@ -1902,47 +1938,47 @@ static Genesys_Model canon_lide_110_model = { }; static Genesys_Model canon_lide_120_model = { - "canon-lide-120", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 120", /* Device model name */ + "canon-lide-120", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 120", /* Device model name */ GENESYS_GL124, NULL, - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (9.0), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (8.0), /* Start of scan area in mm (y) */ + SANE_FIX (216.0), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (1.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE120, - DAC_CANONLIDE110, - GPO_CANONLIDE110, - MOTOR_CANONLIDE110, + DAC_CANONLIDE120, + GPO_CANONLIDE120, + MOTOR_CANONLIDE120, GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_DARK_CALIBRATION @@ -1956,43 +1992,43 @@ static Genesys_Model canon_lide_120_model = { static Genesys_Model canon_lide_210_model = { - "canon-lide-210", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 210", /* Device model name */ + "canon-lide-210", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 210", /* Device model name */ GENESYS_GL124, NULL, - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (8.7), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (297.5), /* Size of scan area in mm (y) */ + SANE_FIX (2.2), /* Start of scan area in mm (x) */ + SANE_FIX (8.7), /* Start of scan area in mm (y) */ + SANE_FIX (216.70), /* Size of scan area in mm (x) */ + SANE_FIX (297.5), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE210, DAC_CANONLIDE110, GPO_CANONLIDE210, @@ -2009,43 +2045,43 @@ static Genesys_Model canon_lide_210_model = { }; static Genesys_Model canon_lide_220_model = { - "canon-lide-220", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 220", /* Device model name */ + "canon-lide-220", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 220", /* Device model name */ GENESYS_GL124, /* or a compatible one */ NULL, - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (8.7), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (297.5), /* Size of scan area in mm (y) */ + SANE_FIX (2.2), /* Start of scan area in mm (x) */ + SANE_FIX (8.7), /* Start of scan area in mm (y) */ + SANE_FIX (216.70), /* Size of scan area in mm (x) */ + SANE_FIX (297.5), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE220, DAC_CANONLIDE110, GPO_CANONLIDE210, @@ -2062,48 +2098,48 @@ static Genesys_Model canon_lide_220_model = { }; static Genesys_Model canon_5600f_model = { - "canon-5600f", /* Name */ - "Canon", /* Device vendor string */ - "5600F", /* Device model name */ + "canon-5600f", /* Name */ + "Canon", /* Device vendor string */ + "5600F", /* Device model name */ GENESYS_GL847, NULL, - {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + SANE_FIX (1.1), /* Start of scan area in mm (x) */ + SANE_FIX (8.3), /* Start of scan area in mm (y) */ + SANE_FIX (216.07), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE200, DAC_CANONLIDE200, GPO_CANONLIDE200, MOTOR_CANONLIDE200, - GENESYS_FLAG_UNTESTED /* not working yet */ + GENESYS_FLAG_UNTESTED /* not working yet */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_SIS_SENSOR | GENESYS_FLAG_DARK_CALIBRATION @@ -2115,43 +2151,43 @@ static Genesys_Model canon_5600f_model = { }; static Genesys_Model canon_lide_700f_model = { - "canon-lide-700f", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 700F", /* Device model name */ + "canon-lide-700f", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 700F", /* Device model name */ GENESYS_GL847, NULL, - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (3.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.1), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (297.0), /* Size of scan area in mm (y) */ + SANE_FIX (3.1), /* Start of scan area in mm (x) */ + SANE_FIX (8.1), /* Start of scan area in mm (y) */ + SANE_FIX (216.07), /* Size of scan area in mm (x) */ + SANE_FIX (297.0), /* Size of scan area in mm (y) */ - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (1.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE700, DAC_CANONLIDE700, GPO_CANONLIDE700, @@ -2170,43 +2206,43 @@ static Genesys_Model canon_lide_700f_model = { static Genesys_Model canon_lide_200_model = { - "canon-lide-200", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 200", /* Device model name */ + "canon-lide-200", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 200", /* Device model name */ GENESYS_GL847, NULL, - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + SANE_FIX (1.1), /* Start of scan area in mm (x) */ + SANE_FIX (8.3), /* Start of scan area in mm (y) */ + SANE_FIX (216.07), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE200, DAC_CANONLIDE200, GPO_CANONLIDE200, @@ -2224,48 +2260,48 @@ static Genesys_Model canon_lide_200_model = { static Genesys_Model canon_lide_60_model = { - "canon-lide-60", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 60", /* Device model name */ + "canon-lide-60", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 60", /* Device model name */ GENESYS_GL841, NULL, - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.42), /* Start of scan area in mm (x) */ - SANE_FIX (7.9), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + SANE_FIX (0.42), /* Start of scan area in mm (x) */ + SANE_FIX (7.9), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (6.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (6.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_CANONLIDE35, DAC_CANONLIDE35, GPO_CANONLIDE35, MOTOR_CANONLIDE35, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_DARK_WHITE_CALIBRATION @@ -2275,50 +2311,50 @@ static Genesys_Model canon_lide_60_model = { GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ 300, 400 -}; /* this is completely untested -- hmg */ +}; /* this is completely untested -- hmg */ static Genesys_Model canon_lide_80_model = { - "canon-lide-80", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 80", /* Device model name */ + "canon-lide-80", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 80", /* Device model name */ GENESYS_GL841, NULL, - { 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.42), /* Start of scan area in mm (x) 0.42 */ - SANE_FIX (7.90), /* Start of scan area in mm (y) 7.90 */ - SANE_FIX (216.07), /* Size of scan area in mm (x) 218.00 */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + { 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + SANE_FIX (0.42), /* Start of scan area in mm (x) 0.42 */ + SANE_FIX (7.90), /* Start of scan area in mm (y) 7.90 */ + SANE_FIX (216.07), /* Size of scan area in mm (x) 218.00 */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (4.5), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (4.5), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CIS_CANONLIDE80, DAC_CANONLIDE80, GPO_CANONLIDE80, MOTOR_CANONLIDE80, - GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_DARK_WHITE_CALIBRATION | @@ -2334,43 +2370,43 @@ static Genesys_Model canon_lide_80_model = { static Genesys_Model hp2300c_model = { - "hewlett-packard-scanjet-2300c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 2300c", /* Device model name */ + "hewlett-packard-scanjet-2300c", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet 2300c", /* Device model name */ GENESYS_GL646, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions, motor can go up to 1200 dpi */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions, motor can go up to 1200 dpi */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (2.0), /* Start of scan area in mm (x_offset) */ - SANE_FIX (7.5), /* Start of scan area in mm (y_offset) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (295.0), /* Size of scan area in mm (y) */ + SANE_FIX (2.0), /* Start of scan area in mm (x_offset) */ + SANE_FIX (7.5), /* Start of scan area in mm (y_offset) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (295.0), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 16, 8, 0, /* RGB CCD Line-distance correction in pixel */ + 16, 8, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_HP2300, DAC_WOLFSON_HP2300, GPO_HP2300, @@ -2390,43 +2426,43 @@ static Genesys_Model hp2300c_model = { static Genesys_Model hp2400c_model = { - "hewlett-packard-scanjet-2400c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 2400c", /* Device model name */ + "hewlett-packard-scanjet-2400c", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet 2400c", /* Device model name */ GENESYS_GL646, NULL, - {1200, 600, 300, 150, 100, 50, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 300, 150, 100, 50, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 100, 50, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (6.5), /* Start of scan area in mm (x) */ - SANE_FIX (2.5), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (297.2), /* Size of scan area in mm (y) */ + SANE_FIX (6.5), /* Start of scan area in mm (x) */ + SANE_FIX (2.5), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (297.2), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_HP2400, DAC_WOLFSON_HP2400, GPO_HP2400, @@ -2445,45 +2481,45 @@ Genesys_Model hp2400c_model = { static Genesys_Model visioneer_xp200_model = { - "visioneer-strobe-xp200", /* Name */ - "Visioneer", /* Device vendor string */ - "Strobe XP200", /* Device model name */ + "visioneer-strobe-xp200", /* Name */ + "Visioneer", /* Device vendor string */ + "Strobe XP200", /* Device model name */ GENESYS_GL646, NULL, - {600, 300, 200, 100, 75, 0}, /* possible x-resolutions */ - {600, 300, 200, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 200, 100, 75, 0}, /* possible x-resolutions */ + {600, 300, 200, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.5), /* Start of scan area in mm (x) */ - SANE_FIX (16.0), /* Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (297.2), /* Size of scan area in mm (y) */ + SANE_FIX (0.5), /* Start of scan area in mm (x) */ + SANE_FIX (16.0), /* Start of scan area in mm (y) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (297.2), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CIS_XP200, - DAC_AD_XP200, /* Analog Device frontend */ + DAC_AD_XP200, /* Analog Device frontend */ GPO_XP200, MOTOR_XP200, GENESYS_FLAG_14BIT_GAMMA @@ -2498,43 +2534,43 @@ Genesys_Model visioneer_xp200_model = { }; static Genesys_Model hp3670c_model = { - "hewlett-packard-scanjet-3670c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 3670c", /* Device model name */ + "hewlett-packard-scanjet-3670c", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet 3670c", /* Device model name */ GENESYS_GL646, NULL, - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (8.5), /* Start of scan area in mm (x) */ - SANE_FIX (11.0), /* Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ + SANE_FIX (8.5), /* Start of scan area in mm (x) */ + SANE_FIX (11.0), /* Start of scan area in mm (y) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ - SANE_FIX (104.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (55.6), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (25.6), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (78.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (104.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (55.6), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (25.6), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (78.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (76.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (76.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_HP3670, DAC_WOLFSON_HP3670, GPO_HP3670, @@ -2552,91 +2588,91 @@ static Genesys_Model hp3670c_model = { }; static Genesys_Model plustek_st12_model = { - "plustek-opticpro-st12", /* Name */ - "Plustek", /* Device vendor string */ - "OpticPro ST12", /* Device model name */ + "plustek-opticpro-st12", /* Name */ + "Plustek", /* Device vendor string */ + "OpticPro ST12", /* Device model name */ GENESYS_GL646, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + SANE_FIX (3.5), /* Start of scan area in mm (x) */ + SANE_FIX (7.5), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ + 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ + COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_ST12, DAC_WOLFSON_ST12, GPO_ST12, MOTOR_UMAX, - GENESYS_FLAG_UNTESTED | GENESYS_FLAG_14BIT_GAMMA, /* Which flags are needed for this scanner? */ + GENESYS_FLAG_UNTESTED | GENESYS_FLAG_14BIT_GAMMA, /* Which flags are needed for this scanner? */ GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ 20, 200 }; static Genesys_Model plustek_st24_model = { - "plustek-opticpro-st24", /* Name */ - "Plustek", /* Device vendor string */ - "OpticPro ST24", /* Device model name */ + "plustek-opticpro-st24", /* Name */ + "Plustek", /* Device vendor string */ + "OpticPro ST24", /* Device model name */ GENESYS_GL646, NULL, - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ + SANE_FIX (3.5), /* Start of scan area in mm (x) */ + SANE_FIX (7.5), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ + 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ + COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_ST24, DAC_WOLFSON_ST24, GPO_ST24, @@ -2653,42 +2689,42 @@ static Genesys_Model plustek_st24_model = { }; static Genesys_Model medion_md5345_model = { - "medion-md5345-model", /* Name */ - "Medion", /* Device vendor string */ - "MD5345/MD6228/MD6471", /* Device model name */ + "medion-md5345-model", /* Name */ + "Medion", /* Device vendor string */ + "MD5345/MD6228/MD6471", /* Device model name */ GENESYS_GL646, NULL, - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX ( 0.30), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ + SANE_FIX ( 0.30), /* Start of scan area in mm (x) */ + SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (296.4), /* Size of scan area in mm (y) */ - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ + SANE_FIX (0.00), /* Start of white strip in mm (y) */ + SANE_FIX (0.00), /* Start of black mark in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_5345, DAC_WOLFSON_5345, GPO_5345, @@ -2708,49 +2744,49 @@ static Genesys_Model medion_md5345_model = { }; static Genesys_Model visioneer_xp300_model = { - "visioneer-strobe-xp300", /* Name */ - "Visioneer", /* Device vendor string */ - "Strobe XP300", /* Device model name */ + "visioneer-strobe-xp300", /* Name */ + "Visioneer", /* Device vendor string */ + "Strobe XP300", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (1.0), /* Start of scan area in mm (y) */ + SANE_FIX (435.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (26.5), /* Size of scan area after paper sensor stops + SANE_FIX (26.5), /* Size of scan area after paper sensor stops sensing document in mm */ /* this is larger than needed -- accounts for second sensor head, which is a calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_XP300, DAC_WOLFSON_XP300, GPO_XP300, MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_DARK_CALIBRATION @@ -2761,48 +2797,48 @@ static Genesys_Model visioneer_xp300_model = { }; static Genesys_Model syscan_docketport_665_model = { - "syscan-docketport-665", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 665", /* Device model name */ + "syscan-docketport-665", /* Name */ + "Syscan/Ambir", /* Device vendor string */ + "DocketPORT 665", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (108.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (108.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (17.5), /* Size of scan area after paper sensor stops + SANE_FIX (17.5), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_DP665, DAC_WOLFSON_XP300, GPO_DP665, MOTOR_DP665, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_DARK_CALIBRATION @@ -2813,48 +2849,48 @@ static Genesys_Model syscan_docketport_665_model = { }; static Genesys_Model visioneer_roadwarrior_model = { - "visioneer-roadwarrior", /* Name */ - "Visioneer", /* Device vendor string */ - "Readwarrior", /* Device model name */ + "visioneer-roadwarrior", /* Name */ + "Visioneer", /* Device vendor string */ + "Readwarrior", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (16.0), /* Size of scan area after paper sensor stops + SANE_FIX (16.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_ROADWARRIOR, DAC_WOLFSON_XP300, GPO_DP665, MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA @@ -2865,48 +2901,48 @@ static Genesys_Model visioneer_roadwarrior_model = { }; static Genesys_Model syscan_docketport_465_model = { - "syscan-docketport-465", /* Name */ - "Syscan", /* Device vendor string */ - "DocketPORT 465", /* Device model name */ + "syscan-docketport-465", /* Name */ + "Syscan", /* Device vendor string */ + "DocketPORT 465", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (16.0), /* Size of scan area after paper sensor stops + SANE_FIX (16.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_ROADWARRIOR, DAC_WOLFSON_XP300, GPO_DP665, MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_NO_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA @@ -2917,48 +2953,48 @@ static Genesys_Model syscan_docketport_465_model = { }; static Genesys_Model visioneer_xp100_r3_model = { - "visioneer-xp100-revision3", /* Name */ - "Visioneer", /* Device vendor string */ - "XP100 Revision 3", /* Device model name */ + "visioneer-xp100-revision3", /* Name */ + "Visioneer", /* Device vendor string */ + "XP100 Revision 3", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (16.0), /* Size of scan area after paper sensor stops + SANE_FIX (16.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_ROADWARRIOR, DAC_WOLFSON_XP300, GPO_DP665, MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA @@ -2969,48 +3005,48 @@ static Genesys_Model visioneer_xp100_r3_model = { }; static Genesys_Model pentax_dsmobile_600_model = { - "pentax-dsmobile-600", /* Name */ - "Pentax", /* Device vendor string */ - "DSmobile 600", /* Device model name */ + "pentax-dsmobile-600", /* Name */ + "Pentax", /* Device vendor string */ + "DSmobile 600", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (16.0), /* Size of scan area after paper sensor stops + SANE_FIX (16.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_DSMOBILE600, DAC_WOLFSON_DSM600, GPO_DP665, MOTOR_DSMOBILE_600, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA @@ -3021,48 +3057,48 @@ static Genesys_Model pentax_dsmobile_600_model = { }; static Genesys_Model syscan_docketport_467_model = { - "syscan-docketport-467", /* Name */ - "Syscan", /* Device vendor string */ - "DocketPORT 467", /* Device model name */ + "syscan-docketport-467", /* Name */ + "Syscan", /* Device vendor string */ + "DocketPORT 467", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (16.0), /* Size of scan area after paper sensor stops + SANE_FIX (16.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_DSMOBILE600, DAC_WOLFSON_DSM600, GPO_DP665, MOTOR_DSMOBILE_600, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA @@ -3073,49 +3109,49 @@ static Genesys_Model syscan_docketport_467_model = { }; static Genesys_Model syscan_docketport_685_model = { - "syscan-docketport-685", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 685", /* Device model name */ + "syscan-docketport-685", /* Name */ + "Syscan/Ambir", /* Device vendor string */ + "DocketPORT 685", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (212.0), /* Size of scan area in mm (x) */ - SANE_FIX (500), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (1.0), /* Start of scan area in mm (y) */ + SANE_FIX (212.0), /* Size of scan area in mm (x) */ + SANE_FIX (500), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (26.5), /* Size of scan area after paper sensor stops + SANE_FIX (26.5), /* Size of scan area after paper sensor stops sensing document in mm */ /* this is larger than needed -- accounts for second sensor head, which is a calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_DP685, DAC_WOLFSON_DSM600, GPO_DP685, MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA @@ -3126,49 +3162,49 @@ static Genesys_Model syscan_docketport_685_model = { }; static Genesys_Model syscan_docketport_485_model = { - "syscan-docketport-485", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 485", /* Device model name */ + "syscan-docketport-485", /* Name */ + "Syscan/Ambir", /* Device vendor string */ + "DocketPORT 485", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (1.0), /* Start of scan area in mm (y) */ + SANE_FIX (435.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (26.5), /* Size of scan area after paper sensor stops + SANE_FIX (26.5), /* Size of scan area after paper sensor stops sensing document in mm */ /* this is larger than needed -- accounts for second sensor head, which is a calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_XP300, DAC_WOLFSON_XP300, GPO_XP300, MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA @@ -3179,49 +3215,49 @@ static Genesys_Model syscan_docketport_485_model = { }; static Genesys_Model dct_docketport_487_model = { - "dct-docketport-487", /* Name */ - "DCT", /* Device vendor string */ - "DocketPORT 487", /* Device model name */ + "dct-docketport-487", /* Name */ + "DCT", /* Device vendor string */ + "DocketPORT 487", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (1.0), /* Start of scan area in mm (y) */ + SANE_FIX (435.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (26.5), /* Size of scan area after paper sensor stops + SANE_FIX (26.5), /* Size of scan area after paper sensor stops sensing document in mm */ /* this is larger than needed -- accounts for second sensor head, which is a calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_XP300, DAC_WOLFSON_XP300, GPO_XP300, MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_DARK_CALIBRATION @@ -3233,43 +3269,43 @@ static Genesys_Model dct_docketport_487_model = { }; static Genesys_Model visioneer_7100_model = { - "visioneer-7100-model", /* Name */ - "Visioneer", /* Device vendor string */ - "OneTouch 7100", /* Device model name */ + "visioneer-7100-model", /* Name */ + "Visioneer", /* Device vendor string */ + "OneTouch 7100", /* Device model name */ GENESYS_GL646, NULL, - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ + SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ + SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (296.4), /* Size of scan area in mm (y) */ - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ + SANE_FIX (0.00), /* Start of white strip in mm (y) */ + SANE_FIX (0.00), /* Start of black mark in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ + 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ /* 48, 24, 0, */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_5345, DAC_WOLFSON_5345, GPO_5345, @@ -3288,43 +3324,43 @@ static Genesys_Model visioneer_7100_model = { }; static Genesys_Model xerox_2400_model = { - "xerox-2400-model", /* Name */ - "Xerox", /* Device vendor string */ - "OneTouch 2400", /* Device model name */ + "xerox-2400-model", /* Name */ + "Xerox", /* Device vendor string */ + "OneTouch 2400", /* Device model name */ GENESYS_GL646, NULL, - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ + SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ + SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (296.4), /* Size of scan area in mm (y) */ - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ + SANE_FIX (0.00), /* Start of white strip in mm (y) */ + SANE_FIX (0.00), /* Start of black mark in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ + 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ /* 48, 24, 0, */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_5345, DAC_WOLFSON_5345, GPO_5345, @@ -3344,48 +3380,48 @@ static Genesys_Model xerox_2400_model = { static Genesys_Model xerox_travelscanner_model = { - "xerox-travelscanner", /* Name */ - "Xerox", /* Device vendor string */ - "Travelscanner 100", /* Device model name */ + "xerox-travelscanner", /* Name */ + "Xerox", /* Device vendor string */ + "Travelscanner 100", /* Device model name */ GENESYS_GL841, NULL, - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (4.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (4.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (16.0), /* Size of scan area after paper sensor stops + SANE_FIX (16.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ CCD_ROADWARRIOR, DAC_WOLFSON_XP300, GPO_DP665, MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA @@ -3396,53 +3432,53 @@ static Genesys_Model xerox_travelscanner_model = { }; static Genesys_Model plustek_3600_model = { - "plustek-opticbook-3600", /* Name */ - "PLUSTEK", /* Device vendor string */ - "OpticBook 3600", /* Device model name */ + "plustek-opticbook-3600", /* Name */ + "PLUSTEK", /* Device vendor string */ + "OpticBook 3600", /* Device model name */ GENESYS_GL841, NULL, - {/*1200,*/ 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {/*2400,*/ 1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {/*1200,*/ 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {/*2400,*/ 1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.42),/*SANE_FIX (0.42), Start of scan area in mm (x) */ - SANE_FIX (6.75),/*SANE_FIX (7.9), Start of scan area in mm (y) */ - SANE_FIX (216.0),/*SANE_FIX (216.0), Size of scan area in mm (x) */ - SANE_FIX (297.0),/*SANE_FIX (297.0), Size of scan area in mm (y) */ + SANE_FIX (0.42),/*SANE_FIX (0.42), Start of scan area in mm (x) */ + SANE_FIX (6.75),/*SANE_FIX (7.9), Start of scan area in mm (y) */ + SANE_FIX (216.0),/*SANE_FIX (216.0), Size of scan area in mm (x) */ + SANE_FIX (297.0),/*SANE_FIX (297.0), Size of scan area in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_PLUSTEK_3600, DAC_PLUSTEK_3600, GPO_PLUSTEK_3600, MOTOR_PLUSTEK_3600, - GENESYS_FLAG_UNTESTED /* not fully working yet */ + GENESYS_FLAG_UNTESTED /* not fully working yet */ | GENESYS_FLAG_CUSTOM_GAMMA | GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_DARK_CALIBRATION | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_HALF_CCD_MODE,/* + | GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_HALF_CCD_MODE,/* | GENESYS_FLAG_NO_CALIBRATION,*/ GENESYS_HAS_NO_BUTTONS, 7, @@ -3450,49 +3486,49 @@ static Genesys_Model plustek_3600_model = { }; static Genesys_Model hpn6310_model = { - "hewlett-packard-scanjet-N6310", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet N6310", /* Device model name */ + "hewlett-packard-scanjet-N6310", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet N6310", /* Device model name */ GENESYS_GL847, NULL, { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 0}, { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (6), /* Start of scan area in mm (x) */ - SANE_FIX (2), /* Start of scan area in mm (y) */ - SANE_FIX (216), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (511), /* Size of scan area in mm (y) */ + SANE_FIX (6), /* Start of scan area in mm (x) */ + SANE_FIX (2), /* Start of scan area in mm (y) */ + SANE_FIX (216), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (511), /* Size of scan area in mm (y) */ - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0), /* Size of scan area after paper sensor stops + SANE_FIX (0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0), /* Amount of feeding needed to eject document + SANE_FIX (0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_HP_N6310, DAC_CANONLIDE200, /*Not defined yet for N6310 */ GPO_HP_N6310, MOTOR_CANONLIDE200, /*Not defined yet for N6310 */ - GENESYS_FLAG_UNTESTED /* not fully working yet */ + GENESYS_FLAG_UNTESTED /* not fully working yet */ | GENESYS_FLAG_LAZY_INIT | GENESYS_FLAG_14BIT_GAMMA | GENESYS_FLAG_DARK_CALIBRATION @@ -3509,43 +3545,43 @@ static Genesys_Model hpn6310_model = { static Genesys_Model plustek_3800_model = { - "plustek-opticbook-3800", /* Name */ - "PLUSTEK", /* Device vendor string */ - "OpticBook 3800", /* Device model name */ + "plustek-opticbook-3800", /* Name */ + "PLUSTEK", /* Device vendor string */ + "OpticBook 3800", /* Device model name */ GENESYS_GL845, NULL, - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ + SANE_FIX (7.2), /* Start of scan area in mm (x) */ + SANE_FIX (14.7), /* Start of scan area in mm (y) */ + SANE_FIX (217.7), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (9.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_PLUSTEK3800, DAC_PLUSTEK3800, GPO_PLUSTEK3800, @@ -3554,50 +3590,50 @@ static Genesys_Model plustek_3800_model = { GENESYS_FLAG_SKIP_WARMUP | GENESYS_FLAG_OFFSET_CALIBRATION | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_NO_BUTTONS, /* TODO there are 4 buttons to support */ + GENESYS_HAS_NO_BUTTONS, /* TODO there are 4 buttons to support */ 100, 100 }; static Genesys_Model canon_formula101_model = { - "canon-image-formula-101", /* Name */ - "Canon", /* Device vendor string */ - "Image Formula 101", /* Device model name */ + "canon-image-formula-101", /* Name */ + "Canon", /* Device vendor string */ + "Image Formula 101", /* Device model name */ GENESYS_GL846, NULL, - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ + SANE_FIX (7.2), /* Start of scan area in mm (x) */ + SANE_FIX (14.7), /* Start of scan area in mm (y) */ + SANE_FIX (217.7), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ + SANE_FIX (9.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area after paper sensor stops + SANE_FIX (0.0), /* Size of scan area after paper sensor stops sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document + SANE_FIX (0.0), /* Amount of feeding needed to eject document after finishing scanning in mm */ - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ CCD_IMG101, DAC_IMG101, GPO_IMG101, diff --git a/backend/genesys_gl124.c b/backend/genesys_gl124.c index eaac873..a98d3d4 100644 --- a/backend/genesys_gl124.c +++ b/backend/genesys_gl124.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2010-2016 Stéphane Voltz This file is part of the SANE package. @@ -112,7 +112,7 @@ gl124_bulk_read_data (Genesys_Device * dev, uint8_t addr, if (status != SANE_STATUS_GOOD) { DBG (DBG_error, "%s failed while writing command: %s\n", - __FUNCTION__, sane_strstatus (status)); + __func__, sane_strstatus (status)); return status; } @@ -154,7 +154,7 @@ gl124_bulk_read_data (Genesys_Device * dev, uint8_t addr, } } - DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __FUNCTION__, + DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __func__, (u_long) size, (u_long) (target - size)); target -= size; @@ -294,7 +294,7 @@ static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi, int half_ccd /* default fallback */ if(idx<0) { - DBG (DBG_warn,"%s: using default sensor profile\n",__FUNCTION__); + DBG (DBG_warn,"%s: using default sensor profile\n",__func__); idx=0; } @@ -356,10 +356,18 @@ gl124_init_registers (Genesys_Device * dev) SETREG (0x01,0xa2); /* + REG01_SHDAREA */ SETREG (0x02,0x90); SETREG (0x03,0x50); - SETREG (0x03,0x50 & ~REG03_AVEENB); SETREG (0x04,0x03); SETREG (0x05,0x00); - SETREG (0x06,0x50 | REG06_GAIN4); + if(dev->model->ccd_type==CIS_CANONLIDE120) + { + SETREG (0x06,0x50); + SETREG (0x07,0x00); + } + else + { + SETREG (0x03,0x50 & ~REG03_AVEENB); + SETREG (0x06,0x50 | REG06_GAIN4); + } SETREG (0x09,0x00); SETREG (0x0a,0xc0); SETREG (0x0b,0x2a); @@ -381,7 +389,14 @@ gl124_init_registers (Genesys_Device * dev) SETREG (0x1f,0x00); SETREG (0x20,0x15); SETREG (0x21,0x00); - SETREG (0x22,0x02); + if(dev->model->ccd_type!=CIS_CANONLIDE120) + { + SETREG (0x22,0x02); + } + else + { + SETREG (0x22,0x14); + } SETREG (0x23,0x00); SETREG (0x24,0x00); SETREG (0x25,0x00); @@ -434,11 +449,19 @@ gl124_init_registers (Genesys_Device * dev) SETREG (0x6a,0x00); SETREG (0x6b,0x00); SETREG (0x6c,0x00); - SETREG (0x6d,0xd0); SETREG (0x6e,0x00); SETREG (0x6f,0x00); - SETREG (0x70,0x06); - SETREG (0x71,0x08); + if(dev->model->ccd_type!=CIS_CANONLIDE120) + { + SETREG (0x6d,0xd0); + SETREG (0x71,0x08); + } + else + { + SETREG (0x6d,0x00); + SETREG (0x71,0x1f); + } + SETREG (0x70,0x00); SETREG (0x72,0x08); SETREG (0x73,0x0a); @@ -456,8 +479,16 @@ gl124_init_registers (Genesys_Device * dev) SETREG (0x7d,0x00); SETREG (0x7e,0x08); SETREG (0x7f,0x58); - SETREG (0x80,0x00); - SETREG (0x81,0x14); + if(dev->model->ccd_type!=CIS_CANONLIDE120) + { + SETREG (0x80,0x00); + SETREG (0x81,0x14); + } + else + { + SETREG (0x80,0x00); + SETREG (0x81,0x10); + } /* STRPIXEL */ SETREG (0x82,0x00); @@ -536,6 +567,15 @@ gl124_init_registers (Genesys_Device * dev) SETREG (0xcd,0x00); SETREG (0xce,0x00); */ + if(dev->model->ccd_type==CIS_CANONLIDE120) + { + SETREG (0xc5,0x20); + SETREG (0xc6,0xeb); + SETREG (0xc7,0x20); + SETREG (0xc8,0xeb); + SETREG (0xc9,0x20); + SETREG (0xca,0xeb); + } /* memory layout SETREG (0xd0,0x0a); @@ -624,13 +664,13 @@ gl124_send_slope_table (Genesys_Device * dev, int table_nr, int i; char msg[10000]; - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __FUNCTION__, + DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, table_nr, steps); /* sanity check */ if(table_nr<0 || table_nr>4) { - DBG (DBG_error, "%s: invalid table number %d!\n", __FUNCTION__, table_nr); + DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); return SANE_STATUS_INVAL; } @@ -648,7 +688,7 @@ gl124_send_slope_table (Genesys_Device * dev, int table_nr, { sprintf (msg+strlen(msg), ",%d", slope_table[i]); } - DBG (DBG_io, "%s: %s\n", __FUNCTION__, msg); + DBG (DBG_io, "%s: %s\n", __func__, msg); } /* slope table addresses are fixed */ @@ -658,7 +698,7 @@ gl124_send_slope_table (Genesys_Device * dev, int table_nr, { DBG (DBG_error, "%s: write to AHB failed writing slope table %d (%s)\n", - __FUNCTION__, table_nr, sane_strstatus (status)); + __func__, table_nr, sane_strstatus (status)); } free (table); @@ -666,8 +706,11 @@ gl124_send_slope_table (Genesys_Device * dev, int table_nr, return status; } -/** - * Set register values of 'special' type frontend +/** @brief * Set register values of 'special' ti type frontend + * Registers value are taken from the frontend register data + * set. + * @param dev device owning the AFE + * @param set flag AFE_INIT to specify the AFE must be reset before writing data * */ static SANE_Status gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) @@ -679,8 +722,7 @@ gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) DBGSTART; if (set == AFE_INIT) { - DBG (DBG_proc, "%s: setting DAC %u\n", __FUNCTION__, - dev->model->dac_type); + DBG (DBG_proc, "%s: setting DAC %u\n", __func__, dev->model->dac_type); /* sets to default values */ sanei_genesys_init_fe (dev); @@ -690,7 +732,7 @@ gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) status = sanei_genesys_fe_write_data (dev, 0x00, 0x80); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus (status)); return status; } @@ -703,7 +745,7 @@ gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to write reg %d: %s\n", __FUNCTION__, i, + "%s: failed to write reg %d: %s\n", __func__, i, sane_strstatus (status)); return status; } @@ -712,12 +754,12 @@ gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) status = sanei_genesys_fe_write_data (dev, 0x04, 0x00); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to write reg4: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to write reg4: %s\n", __func__, sane_strstatus (status)); return status; } - /* these are not really sign */ + /* these are not really sign for this AFE */ for (i = 0; i < 3; i++) { val = dev->frontend.sign[i]; @@ -725,17 +767,24 @@ gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to write reg %d: %s\n", __FUNCTION__, i+5, + "%s: failed to write reg %d: %s\n", __func__, i+5, sane_strstatus (status)); return status; } } /* close writing to DAC */ - status = sanei_genesys_fe_write_data (dev, 0x00, 0x11); + if(dev->model->dac_type == DAC_CANONLIDE120) + { + status = sanei_genesys_fe_write_data (dev, 0x00, 0x01); + } + else + { + status = sanei_genesys_fe_write_data (dev, 0x00, 0x11); + } if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus (status)); return status; } @@ -781,7 +830,7 @@ gl124_set_fe (Genesys_Device * dev, uint8_t set) case 1: case 2: default: - DBG (DBG_error, "%s: unsupported analog FE 0x%02x\n",__FUNCTION__,val); + DBG (DBG_error, "%s: unsupported analog FE 0x%02x\n",__func__,val); status=SANE_STATUS_INVAL; break; } @@ -852,10 +901,17 @@ gl124_init_motor_regs_scan (Genesys_Device * dev, } else { - min_speed = 900; - if(dev->model->ccd_type==MOTOR_CANONLIDE110) + switch(dev->model->motor_type) { - min_speed = 300; + case MOTOR_CANONLIDE110: + min_speed = 600; + break; + case MOTOR_CANONLIDE120: + min_speed = 900; + break; + default: + min_speed = 900; + break; } } @@ -864,6 +920,12 @@ gl124_init_motor_regs_scan (Genesys_Device * dev, { yres=min_speed; linesel=yres/scan_yres-1; + /* limit case, we need a linesel > 0 */ + if(linesel==0) + { + linesel=1; + yres=scan_yres*2; + } } else { @@ -871,11 +933,11 @@ gl124_init_motor_regs_scan (Genesys_Device * dev, linesel=0; } - DBG (DBG_io2, "%s: linesel=%d\n", __FUNCTION__, linesel); + DBG (DBG_io2, "%s: final yres=%f, linesel=%d\n", __func__, yres, linesel); lincnt=scan_lines*(linesel+1); sanei_genesys_set_triple(reg,REG_LINCNT,lincnt); - DBG (DBG_io, "%s: lincnt=%d\n", __FUNCTION__, lincnt); + DBG (DBG_io, "%s: lincnt=%d\n", __func__, lincnt); /* compute register 02 value */ r = sanei_genesys_get_address (reg, REG02); @@ -954,7 +1016,7 @@ gl124_init_motor_regs_scan (Genesys_Device * dev, { dist += fast_steps*2; } - DBG (DBG_io2, "%s: acceleration distance=%d\n", __FUNCTION__, dist); + DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); /* get sure we don't use insane value */ if(distvalue = dev->sensor.regs_0x10_0x1d[i]; + { + r->value = dev->sensor.regs_0x10_0x1d[i]; + } } + /* skip writing 5d,5e which is AFE address because + * they are not deifned in register set */ for (i = 0; i < 11; i++) { r = sanei_genesys_get_address (regs, 0x52 + i); if (r) - r->value = dev->sensor.regs_0x52_0x5e[i]; + { + r->value = dev->sensor.regs_0x52_0x5e[i]; + } } /* set EXPDUMMY and CKxMAP */ @@ -1054,6 +1127,23 @@ gl124_setup_sensor (Genesys_Device * dev, Genesys_Register_Set * regs, int dpi, r->value = sensor->reg98; } + if(sensor->reg16!=0) + { + r = sanei_genesys_get_address (regs, 0x16); + if (r) + { + r->value = sensor->reg16; + } + } + if(sensor->reg70!=0) + { + r = sanei_genesys_get_address (regs, 0x70); + if (r) + { + r->value = sensor->reg70; + } + } + sanei_genesys_set_triple(regs,REG_SEGCNT,sensor->segcnt); sanei_genesys_set_double(regs,REG_TG0CNT,sensor->tg0cnt); sanei_genesys_set_double(regs,REG_EXPDMY,sensor->expdummy); @@ -1131,19 +1221,19 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, DBG (DBG_proc, "%s : exposure_time=%d, " "used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", __FUNCTION__, exposure_time, + "half_ccd=%d, flags=%x\n", __func__, exposure_time, used_res, start, pixels, channels, depth, half_ccd, flags); /* resolution is divided according to CKSEL */ r = sanei_genesys_get_address (reg, REG18); cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __FUNCTION__, cksel); + DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); /* to manage high resolution device while keeping good * low resolution scanning speed, we make hardware dpi vary */ dpihw=sanei_genesys_compute_dpihw(dev, used_res * cksel); factor=dev->sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __FUNCTION__, dpihw, factor); + DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); /* sensor parameters */ gl124_setup_sensor (dev, reg, dpihw, half_ccd); @@ -1163,7 +1253,7 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, status = gl124_set_fe (dev, AFE_SET); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to set frontend: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1183,7 +1273,16 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, r->value &= ~REG01_SCAN; r = sanei_genesys_get_address (reg, REG03); - r->value &= ~REG03_AVEENB; + if((dev->model->ccd_type!=CIS_CANONLIDE120)&&(used_res>=600)) + { + r->value &= ~REG03_AVEENB; + DBG (DBG_io, "%s: disabling AVEENB\n", __func__); + } + else + { + r->value |= ~REG03_AVEENB; + DBG (DBG_io, "%s: enabling AVEENB\n", __func__); + } if (flags & OPTICAL_FLAG_DISABLE_LAMP) r->value &= ~REG03_LAMPPWR; @@ -1217,13 +1316,13 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, switch (color_filter) { case 0: - r->value |= 0x10; /* red filter */ + r->value |= 0x10; /* red filter */ break; case 2: - r->value |= 0x30; /* blue filter */ + r->value |= 0x30; /* blue filter */ break; default: - r->value |= 0x20; /* green filter */ + r->value |= 0x20; /* green filter */ break; } } @@ -1258,12 +1357,12 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, if(half_ccd) { sanei_genesys_set_double(reg,REG_DPISET,dpiset*2); - DBG (DBG_io2, "%s: dpiset used=%d\n", __FUNCTION__, dpiset*2); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset*2); } else { sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __FUNCTION__, dpiset); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); } r = sanei_genesys_get_address (reg, REG06); @@ -1310,14 +1409,14 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, segnb = r->value & 0x0f; sanei_genesys_set_triple(reg,REG_STRPIXEL,startx/segnb); - DBG (DBG_io2, "%s: strpixel used=%d\n", __FUNCTION__, startx/segnb); + DBG (DBG_io2, "%s: strpixel used=%d\n", __func__, startx/segnb); sanei_genesys_get_triple(reg,REG_SEGCNT,&segcnt); if(endx/segnb==segcnt) { endx=0; } sanei_genesys_set_triple(reg,REG_ENDPIXEL,endx/segnb); - DBG (DBG_io2, "%s: endpixel used=%d\n", __FUNCTION__, endx/segnb); + DBG (DBG_io2, "%s: endpixel used=%d\n", __func__, endx/segnb); /* words(16bit) before gamma, conversion to 8 bit or lineart */ words_per_line = (used_pixels * dpiset) / dpihw; @@ -1340,13 +1439,13 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, dev->line_count = 0; dev->line_interp = 0; - DBG (DBG_io2, "%s: used_pixels =%d\n", __FUNCTION__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __FUNCTION__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __FUNCTION__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __FUNCTION__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __FUNCTION__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __FUNCTION__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->line_interp=%lu\n", __FUNCTION__, (unsigned long)dev->line_interp); + DBG (DBG_io2, "%s: used_pixels =%d\n", __func__, used_pixels); + DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); + DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); + DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); + DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); + DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); + DBG (DBG_io2, "%s: dev->line_interp=%lu\n", __func__, (unsigned long)dev->line_interp); words_per_line *= channels; dev->wpl = words_per_line; @@ -1360,10 +1459,10 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, /* MAXWD is expressed in 2 words unit */ sanei_genesys_set_triple(reg,REG_MAXWD,(words_per_line)); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __FUNCTION__, words_per_line); + DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); sanei_genesys_set_triple(reg,REG_LPERIOD,exposure_time); - DBG (DBG_io2, "%s: exposure_time used=%d\n", __FUNCTION__, exposure_time); + DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); sanei_genesys_set_double(reg,REG_DUMMY,dev->sensor.dummy_pixel); @@ -1371,7 +1470,7 @@ gl124_init_optical_regs_scan (Genesys_Device * dev, return SANE_STATUS_GOOD; } -/* set up registers for an actual scan +/** set up registers for an actual scan * * this function sets up the scanner to scan in normal or single line mode */ @@ -1379,10 +1478,10 @@ GENESYS_STATIC SANE_Status gl124_init_scan_regs (Genesys_Device * dev, Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ + float xres, /*dpi */ + float yres, /*dpi */ + float startx, /*optical_res, from dummy_pixel+1 */ + float starty, /*base_ydpi, from home! */ float pixels, float lines, unsigned int depth, @@ -1407,7 +1506,7 @@ gl124_init_scan_regs (Genesys_Device * dev, int max_shift; size_t requested_buffer_size, read_buffer_size; - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ + SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ int optical_res; SANE_Status status; @@ -1427,7 +1526,7 @@ gl124_init_scan_regs (Genesys_Device * dev, optical_res = dev->sensor.optical_res; if (half_ccd) optical_res /= 2; - DBG (DBG_info, "%s: optical_res=%d\n", __FUNCTION__, optical_res); + DBG (DBG_info, "%s: optical_res=%d\n", __func__, optical_res); /* stagger */ if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) @@ -1463,7 +1562,7 @@ gl124_init_scan_regs (Genesys_Device * dev, /* compute correct pixels number */ used_pixels = (pixels * optical_res) / xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __FUNCTION__, used_pixels); + DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); /* round up pixels number if needed */ if (used_pixels * xres < pixels * optical_res) @@ -1607,7 +1706,7 @@ gl124_init_scan_regs (Genesys_Device * dev, dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __FUNCTION__, dev->current_setup.pixels); + DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); dev->current_setup.lines = lincnt; dev->current_setup.depth = depth; dev->current_setup.channels = channels; @@ -1642,9 +1741,9 @@ gl124_calculate_current_setup (Genesys_Device * dev) int depth; int start; - float xres; /*dpi */ - float yres; /*dpi */ - float startx; /*optical_res, from dummy_pixel+1 */ + float xres; /*dpi */ + float yres; /*dpi */ + float startx; /*optical_res, from dummy_pixel+1 */ float pixels; float lines; @@ -1672,7 +1771,7 @@ gl124_calculate_current_setup (Genesys_Device * dev) dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); /* channels */ - if (dev->settings.scan_mode == 4) /* single pass color */ + if (dev->settings.scan_mode == 4) /* single pass color */ channels = 3; else channels = 1; @@ -1720,11 +1819,11 @@ gl124_calculate_current_setup (Genesys_Device * dev) /* compute correct pixels number */ used_pixels = (pixels * optical_res) / xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __FUNCTION__, used_pixels); + DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); /* exposure */ exposure_time = gl124_compute_exposure (dev, xres, half_ccd); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __FUNCTION__, exposure_time); + DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); /* max_shift */ max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); @@ -1740,13 +1839,13 @@ gl124_calculate_current_setup (Genesys_Device * dev) stagger = (4 * yres) / dev->motor.base_ydpi; else stagger = 0; - DBG (DBG_info, "%s: stagger=%d lines\n", __FUNCTION__, stagger); + DBG (DBG_info, "%s: stagger=%d lines\n", __func__, stagger); /* lincnt */ lincnt = lines + max_shift + stagger; dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __FUNCTION__, dev->current_setup.pixels); + DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); dev->current_setup.lines = lincnt; dev->current_setup.depth = depth; dev->current_setup.channels = channels; @@ -1878,7 +1977,7 @@ gl124_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read reg100: %s\n", __FUNCTION__, + "%s: failed to read reg100: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -1887,7 +1986,7 @@ gl124_stop_action (Genesys_Device * dev) /* only stop action if needed */ if (!(val40 & REG100_DATAENB) && !(val40 & REG100_MOTMFLG)) { - DBG (DBG_info, "%s: already stopped\n", __FUNCTION__); + DBG (DBG_info, "%s: already stopped\n", __func__); DBGCOMPLETED; return SANE_STATUS_GOOD; } @@ -1900,7 +1999,7 @@ gl124_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to write register 01: %s\n", __FUNCTION__, + "%s: failed to write register 01: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1918,7 +2017,7 @@ gl124_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -1941,6 +2040,13 @@ gl124_stop_action (Genesys_Device * dev) } +/** @brief setup GPIOs for scan + * Setup GPIO values to drive motor (or light) needed for the + * target resolution + * @param *dev device to set up + * @param resolution dpi of the target scan + * @return SANE_STATUS_GOOD unless REG32 cannot be read + */ static SANE_Status gl124_setup_scan_gpio(Genesys_Device *dev, int resolution) { @@ -1949,17 +2055,43 @@ uint8_t val; DBGSTART; RIE (sanei_genesys_read_register (dev, REG32, &val)); - if(resolution>=dev->motor.base_ydpi/2) - { - val &= 0xf7; - } - else if(resolution>=dev->motor.base_ydpi/4) + + /* LiDE 110, 210 and 220 cases */ + if(dev->model->gpo_type != GPO_CANONLIDE120) { - val &= 0xef; + if(resolution>=dev->motor.base_ydpi/2) + { + val &= 0xf7; + } + else if(resolution>=dev->motor.base_ydpi/4) + { + val &= 0xef; + } + else + { + val |= 0x10; + } } + /* 120 : <=300 => 0x53 */ else - { - val |= 0x10; + { /* base_ydpi is 4800 */ + if(resolution<=300) + { + val &= 0xf7; + } + else if(resolution<=600) + { + val |= 0x08; + } + else if(resolution<=1200) + { + val &= 0xef; + val |= 0x08; + } + else + { + val &= 0xf7; + } } val |= 0x02; RIE (sanei_genesys_write_register (dev, REG32, val)); @@ -2026,7 +2158,7 @@ gl124_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, { status = SANE_STATUS_GOOD; } - else /* flat bed scanners */ + else /* flat bed scanners */ { status = gl124_stop_action (dev); if (status != SANE_STATUS_GOOD) @@ -2043,12 +2175,51 @@ gl124_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, } -/** @brief Moves the slider to the home (top) position slowly - * */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status +/** rewind scan + * Move back by the same amount of distance than previous scan. + * @param dev device to rewind + * @returns SANE_STATUS_GOOD on success + */ +GENESYS_STATIC +SANE_Status gl124_rewind(Genesys_Device * dev) +{ + SANE_Status status; + uint8_t byte; + + DBGSTART; + + /* set motor reverse */ + RIE (sanei_genesys_read_register (dev, 0x02, &byte)); + byte |= 0x04; + RIE (sanei_genesys_write_register(dev, 0x02, byte)); + + /* and start scan, then wait completion */ + RIE (gl124_begin_scan (dev, dev->reg, SANE_TRUE)); + do + { + usleep(100*1000); + RIE (sanei_genesys_read_register (dev, REG100, &byte)); + } + while(byte & REG100_MOTMFLG); + RIE (gl124_end_scan (dev, dev->reg, SANE_TRUE)); + + /* restore direction */ + RIE (sanei_genesys_read_register (dev, 0x02, &byte)); + byte &= 0xfb; + RIE (sanei_genesys_write_register(dev, 0x02, byte)); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** Park head + * Moves the slider to the home (top) position slowly + * @param dev device to park + * @param wait_until_home true to make the function waiting for head + * to be home before returning, if fals returne immediately + * @returns SANE_STATUS_GOO on success */ +GENESYS_STATIC +SANE_Status gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) { Genesys_Register_Set local_reg[GENESYS_GL124_MAX_REGS]; @@ -2083,7 +2254,7 @@ gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) { sanei_genesys_print_status (val); } - usleep (100000); /* sleep 100 ms */ + usleep (100000); /* sleep 100 ms */ /* second is reliable */ status = sanei_genesys_get_status (dev, &val); @@ -2102,7 +2273,7 @@ gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) /* is sensor at home? */ if (val & HOMESNR) { - DBG (DBG_info, "%s: already at home, completed\n", __FUNCTION__); + DBG (DBG_info, "%s: already at home, completed\n", __func__); dev->scanhead_position_in_steps = 0; DBGCOMPLETED; return SANE_STATUS_GOOD; @@ -2114,7 +2285,7 @@ gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) status = gl124_feed (dev, 20, SANE_TRUE); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to do initial feed: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to do initial feed: %s\n", __func__, sane_strstatus (status)); return status; } } @@ -2176,7 +2347,7 @@ gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) if (wait_until_home) { - while (loop < 300) /* do not wait longer then 30 seconds */ + while (loop < 300) /* do not wait longer then 30 seconds */ { status = sanei_genesys_get_status (dev, &val); if (status != SANE_STATUS_GOOD) @@ -2187,14 +2358,14 @@ gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) return status; } - if (val & HOMESNR) /* home sensor */ + if (val & HOMESNR) /* home sensor */ { DBG (DBG_info, "gl124_slow_back_home: reached home position\n"); DBGCOMPLETED; dev->scanhead_position_in_steps = 0; return SANE_STATUS_GOOD; } - usleep (100000); /* sleep 100 ms */ + usleep (100000); /* sleep 100 ms */ ++loop; } @@ -2228,7 +2399,7 @@ gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse) uint8_t val; DBGSTART; - DBG (DBG_io, "%s: steps=%d\n", __FUNCTION__, steps); + DBG (DBG_io, "%s: steps=%d\n", __func__, steps); /* prepare local registers */ memcpy (local_reg, dev->reg, GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); @@ -2254,7 +2425,7 @@ gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse) SCAN_FLAG_IGNORE_LINE_DISTANCE); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to set up registers: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; } @@ -2273,7 +2444,7 @@ gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse) r->value &= ~REG01_SCAN; /* set up for reverse if needed */ - if(reverse) + if(reverse) { r = sanei_genesys_get_address (local_reg, REG02); r->value |= REG02_MTRREV; @@ -2285,7 +2456,7 @@ gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse) status = gl124_start_action (dev); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to start motor: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); gl124_stop_action (dev); /* restore original registers */ @@ -2336,14 +2507,14 @@ gl124_search_start_position (Genesys_Device * dev) dpi, dpi, 0, - 0, /*we should give a small offset here~60 steps */ + 0, /*we should give a small offset here~60 steps */ 600, dev->model->search_lines, 8, 1, dev->settings.scan_method, SCAN_MODE_GRAY, - 1, /*green */ + 1, /*green */ SCAN_FLAG_DISABLE_SHADING | SCAN_FLAG_DISABLE_GAMMA | SCAN_FLAG_IGNORE_LINE_DISTANCE | @@ -2351,7 +2522,7 @@ gl124_search_start_position (Genesys_Device * dev) if (status!=SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to init scan registers: %s\n", __FUNCTION__, + "%s: failed to init scan registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2448,10 +2619,10 @@ gl124_init_regs_for_coarse_calibration (Genesys_Device * dev) uint8_t cksel; DBGSTART; - cksel = (dev->calib_reg[reg_0x18].value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ + cksel = (dev->calib_reg[reg_0x18].value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ /* set line size */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ + if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ channels = 3; else channels = 1; @@ -2540,7 +2711,7 @@ gl124_init_regs_for_shading (Genesys_Device * dev) move = SANE_UNFIX (dev->model->y_offset_calib); move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; } - DBG (DBG_io, "%s: move=%d steps\n", __FUNCTION__, move); + DBG (DBG_io, "%s: move=%d steps\n", __func__, move); status = gl124_init_scan_regs (dev, dev->calib_reg, @@ -2563,7 +2734,7 @@ gl124_init_regs_for_shading (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2574,7 +2745,7 @@ gl124_init_regs_for_shading (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to bulk write registers: %s\n", __FUNCTION__, + "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2613,14 +2784,14 @@ gl124_init_regs_for_scan (Genesys_Device * dev) status = sanei_genesys_get_status (dev, &val); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to read status: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; } status = sanei_genesys_read_register (dev, REG100, &val40); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to read reg100: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to read reg100: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; } @@ -2632,14 +2803,14 @@ gl124_init_regs_for_scan (Genesys_Device * dev) status = sanei_genesys_get_status (dev, &val); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to read status: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; } status = sanei_genesys_read_register (dev, REG100, &val40); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to read reg100: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to read reg100: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; } @@ -2666,14 +2837,14 @@ gl124_init_regs_for_scan (Genesys_Device * dev) move = SANE_UNFIX (dev->model->y_offset); move += dev->settings.tl_y; move = (move * move_dpi) / MM_PER_INCH; - DBG (DBG_info, "%s: move=%f steps\n", __FUNCTION__, move); + DBG (DBG_info, "%s: move=%f steps\n", __func__, move); if(channels*dev->settings.yres>=600 && move>700) { status = gl124_feed (dev, move-500, SANE_FALSE); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to move to scan area\n",__FUNCTION__); + DBG (DBG_error, "%s: failed to move to scan area\n",__func__); return status; } move=500; @@ -2737,7 +2908,7 @@ gl124_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) uint8_t val,*buffer,*ptr,*src; DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__FUNCTION__,size); + DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); /* logical size of a color as seen by generic code of the frontend */ length = (uint32_t) (size / 3); @@ -2748,13 +2919,13 @@ gl124_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) { endpixel=segcnt; } - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, SEGCNT=%d\n",__FUNCTION__,strpixel,endpixel,endpixel-strpixel,segcnt); + DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, SEGCNT=%d\n",__func__,strpixel,endpixel,endpixel-strpixel,segcnt); /* compute deletion factor */ sanei_genesys_get_double(dev->reg,REG_DPISET,&dpiset); dpihw=sanei_genesys_compute_dpihw(dev,dpiset); factor=dpihw/dpiset; - DBG( DBG_io2, "%s: factor=%d\n",__FUNCTION__,factor); + DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); /* binary data logging */ if(DBG_LEVEL>=DBG_data) @@ -2774,7 +2945,7 @@ gl124_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) segcnt*=2*2; pixels=endpixel-strpixel; - DBG( DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__FUNCTION__,length, length/4); + DBG( DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__func__,length, length/4); buffer=(uint8_t *)malloc(pixels*dev->segnb); memset(buffer,0,pixels*dev->segnb); @@ -2892,7 +3063,7 @@ move_to_calibration_area (Genesys_Device * dev) SCAN_FLAG_IGNORE_LINE_DISTANCE); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2904,7 +3075,7 @@ move_to_calibration_area (Genesys_Device * dev) /* write registers and scan data */ RIEF (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS), line); - DBG (DBG_info, "%s: starting line reading\n", __FUNCTION__); + DBG (DBG_info, "%s: starting line reading\n", __func__); RIEF (gl124_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); RIEF (sanei_genesys_read_data_from_scanner (dev, line, size), line); @@ -2992,11 +3163,11 @@ gl124_led_calibration (Genesys_Device * dev) SCAN_FLAG_IGNORE_LINE_DISTANCE); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } - total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ + total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ line = malloc (total_size); if (!line) return SANE_STATUS_NO_MEM; @@ -3190,7 +3361,7 @@ gl124_offset_calibration (Genesys_Device * dev) gl124_set_motor_power (dev->calib_reg, SANE_FALSE); /* allocate memory for scans */ - total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ + total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ first_line = malloc (total_size); if (!first_line) @@ -3503,7 +3674,7 @@ gl124_init_regs_for_warmup (Genesys_Device * dev, num_pixels = dev->current_setup.pixels; - *total_size = num_pixels * 3 * 1; /* colors * bytes_per_color * scan lines */ + *total_size = num_pixels * 3 * 1; /* colors * bytes_per_color * scan lines */ gl124_set_motor_power (reg, SANE_FALSE); RIE (dev->model->cmd_set->bulk_write_register (dev, reg, GENESYS_GL124_MAX_REGS)); @@ -3512,12 +3683,10 @@ gl124_init_regs_for_warmup (Genesys_Device * dev, return SANE_STATUS_GOOD; } -/** +/** @brief default GPIO values * set up GPIO/GPOE for idle state -WRITE GPIO[17-21]= GPIO19 -WRITE GPOE[17-21]= GPOE21 GPOE20 GPOE19 GPOE18 -genesys_write_register(0xa8,0x3e) -GPIO(0xa8)=0x3e + * @param dev device to set up + * @return SANE_STATUS_GOOD unless a GPIO register cannot be written */ static SANE_Status gl124_init_gpio (Genesys_Device * dev) @@ -3528,13 +3697,16 @@ gl124_init_gpio (Genesys_Device * dev) DBGSTART; /* per model GPIO layout */ - if ((strcmp (dev->model->name, "canon-lide-110") == 0) - ||(strcmp (dev->model->name, "canon-lide-120") == 0)) + if (strcmp (dev->model->name, "canon-lide-110") == 0) { idx = 0; } + else if (strcmp (dev->model->name, "canon-lide-110") == 0) + { + idx = 2; + } else - { /* canon LiDE 210 and 220 case */ + { /* canon LiDE 210 and 220 case */ idx = 1; } @@ -3568,7 +3740,7 @@ gl124_init_memory_layout (Genesys_Device * dev) idx = 0; } else - { /* canon LiDE 210 and 220 case */ + { /* canon LiDE 210 and 220 case */ idx = 1; } @@ -3587,18 +3759,18 @@ gl124_init_memory_layout (Genesys_Device * dev) /* size for each buffer is 0x16d*1k word */ sanei_genesys_write_register (dev, 0xe0, layouts[idx].re0); sanei_genesys_write_register (dev, 0xe1, layouts[idx].re1); -/* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ + /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ sanei_genesys_write_register (dev, 0xe2, layouts[idx].re2); sanei_genesys_write_register (dev, 0xe3, layouts[idx].re3); /* R-Channel EVEN image buffer 0x0292 */ sanei_genesys_write_register (dev, 0xe4, layouts[idx].re4); sanei_genesys_write_register (dev, 0xe5, layouts[idx].re5); -/* R-Channel EVEN image buffer end-address 0x03ff*/ + /* R-Channel EVEN image buffer end-address 0x03ff*/ sanei_genesys_write_register (dev, 0xe6, layouts[idx].re6); sanei_genesys_write_register (dev, 0xe7, layouts[idx].re7); -/* same for green, since CIS, same addresses */ + /* same for green, since CIS, same addresses */ sanei_genesys_write_register (dev, 0xe8, layouts[idx].re0); sanei_genesys_write_register (dev, 0xe9, layouts[idx].re1); sanei_genesys_write_register (dev, 0xea, layouts[idx].re2); @@ -3725,7 +3897,8 @@ gl124_update_hardware_sensors (Genesys_Scanner * s) * add another per scanner button profile struct to avoid growing * hard-coded button mapping here. */ - if(s->dev->model->gpo_type == GPO_CANONLIDE110) + if((s->dev->model->gpo_type == GPO_CANONLIDE110) + ||(s->dev->model->gpo_type == GPO_CANONLIDE120)) { if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) s->val[OPT_SCAN_SW].b = (val & 0x01) == 0; @@ -3755,7 +3928,7 @@ gl124_update_hardware_sensors (Genesys_Scanner * s) /** the gl124 command set */ static Genesys_Command_Set gl124_cmd_set = { - "gl124-generic", /* the name of this set */ + "gl124-generic", /* the name of this set */ gl124_init, gl124_init_regs_for_warmup, @@ -3792,6 +3965,7 @@ static Genesys_Command_Set gl124_cmd_set = { gl124_led_calibration, gl124_slow_back_home, + gl124_rewind, sanei_genesys_bulk_write_register, NULL, diff --git a/backend/genesys_gl124.h b/backend/genesys_gl124.h index 25f99c3..9ca6afd 100644 --- a/backend/genesys_gl124.h +++ b/backend/genesys_gl124.h @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2010-2016 Stéphane Voltz This file is part of the SANE package. @@ -44,71 +44,71 @@ #include "genesys.h" #define REG01 0x01 -#define REG01_CISSET 0x80 -#define REG01_DOGENB 0x40 -#define REG01_DVDSET 0x20 +#define REG01_CISSET 0x80 +#define REG01_DOGENB 0x40 +#define REG01_DVDSET 0x20 #define REG01_STAGGER 0x10 -#define REG01_COMPENB 0x08 +#define REG01_COMPENB 0x08 #define REG01_TRUEGRAY 0x04 -#define REG01_SHDAREA 0x02 -#define REG01_SCAN 0x01 - -#define REG02 0x02 -#define REG02_NOTHOME 0x80 -#define REG02_ACDCDIS 0x40 -#define REG02_AGOHOME 0x20 -#define REG02_MTRPWR 0x10 -#define REG02_FASTFED 0x08 -#define REG02_MTRREV 0x04 -#define REG02_HOMENEG 0x02 -#define REG02_LONGCURV 0x01 +#define REG01_SHDAREA 0x02 +#define REG01_SCAN 0x01 + +#define REG02 0x02 +#define REG02_NOTHOME 0x80 +#define REG02_ACDCDIS 0x40 +#define REG02_AGOHOME 0x20 +#define REG02_MTRPWR 0x10 +#define REG02_FASTFED 0x08 +#define REG02_MTRREV 0x04 +#define REG02_HOMENEG 0x02 +#define REG02_LONGCURV 0x01 #define REG03 0x03 -#define REG03_LAMPDOG 0x80 -#define REG03_AVEENB 0x40 -#define REG03_XPASEL 0x20 -#define REG03_LAMPPWR 0x10 -#define REG03_LAMPTIM 0x0f - -#define REG04 0x04 -#define REG04_LINEART 0x80 -#define REG04_BITSET 0x40 -#define REG04_FILTER 0x30 +#define REG03_LAMPDOG 0x80 +#define REG03_AVEENB 0x40 +#define REG03_XPASEL 0x20 +#define REG03_LAMPPWR 0x10 +#define REG03_LAMPTIM 0x0f + +#define REG04 0x04 +#define REG04_LINEART 0x80 +#define REG04_BITSET 0x40 +#define REG04_FILTER 0x30 #define REG04_AFEMOD 0x07 -#define REG05 0x05 -#define REG05_DPIHW 0xc0 -#define REG05_DPIHW_600 0x00 -#define REG05_DPIHW_1200 0x40 -#define REG05_DPIHW_2400 0x80 -#define REG05_DPIHW_4800 0xc0 -#define REG05_MTLLAMP 0x30 -#define REG05_GMMENB 0x08 -#define REG05_ENB20M 0x04 -#define REG05_MTLBASE 0x03 - -#define REG06 0x06 -#define REG06_SCANMOD 0xe0 -#define REG06S_SCANMOD 5 -#define REG06_PWRBIT 0x10 -#define REG06_GAIN4 0x08 -#define REG06_OPTEST 0x07 - -#define REG07_LAMPSIM 0x80 - -#define REG08_DRAM2X 0x80 +#define REG05 0x05 +#define REG05_DPIHW 0xc0 +#define REG05_DPIHW_600 0x00 +#define REG05_DPIHW_1200 0x40 +#define REG05_DPIHW_2400 0x80 +#define REG05_DPIHW_4800 0xc0 +#define REG05_MTLLAMP 0x30 +#define REG05_GMMENB 0x08 +#define REG05_ENB20M 0x04 +#define REG05_MTLBASE 0x03 + +#define REG06 0x06 +#define REG06_SCANMOD 0xe0 +#define REG06S_SCANMOD 5 +#define REG06_PWRBIT 0x10 +#define REG06_GAIN4 0x08 +#define REG06_OPTEST 0x07 + +#define REG07_LAMPSIM 0x80 + +#define REG08_DRAM2X 0x80 #define REG08_MPENB 0x20 #define REG08_CIS_LINE 0x10 #define REG08_IR2_ENB 0x08 #define REG08_IR1_ENB 0x04 #define REG08_ENB24M 0x01 -#define REG09_MCNTSET 0xc0 +#define REG09_MCNTSET 0xc0 #define REG09_EVEN1ST 0x20 #define REG09_BLINE1ST 0x10 -#define REG09_BACKSCAN 0x08 -#define REG09_OUTINV 0x04 -#define REG09_SHORTTG 0x02 +#define REG09_BACKSCAN 0x08 +#define REG09_OUTINV 0x04 +#define REG09_SHORTTG 0x02 #define REG09S_MCNTSET 6 #define REG09S_CLKSET 4 @@ -136,55 +136,55 @@ #define REG0B_48MHZ 0x60 #define REG0B_60MHZ 0x80 -#define REG0D 0x0d +#define REG0D 0x0d #define REG0D_MTRP_RDY 0x80 #define REG0D_FULLSTP 0x10 #define REG0D_CLRMCNT 0x04 #define REG0D_CLRDOCJM 0x02 -#define REG0D_CLRLNCNT 0x01 - -#define REG0F 0x0f - -#define REG16_CTRLHI 0x80 -#define REG16_TOSHIBA 0x40 -#define REG16_TGINV 0x20 -#define REG16_CK1INV 0x10 -#define REG16_CK2INV 0x08 -#define REG16_CTRLINV 0x04 -#define REG16_CKDIS 0x02 -#define REG16_CTRLDIS 0x01 - -#define REG17_TGMODE 0xc0 -#define REG17_SNRSYN 0x0f - -#define REG18 0x18 -#define REG18_CNSET 0x80 -#define REG18_DCKSEL 0x60 -#define REG18_CKTOGGLE 0x10 -#define REG18_CKDELAY 0x0c -#define REG18_CKSEL 0x03 - -#define REG1A_SW2SET 0x80 -#define REG1A_SW1SET 0x40 -#define REG1A_MANUAL3 0x02 -#define REG1A_MANUAL1 0x01 -#define REG1A_CK4INV 0x08 -#define REG1A_CK3INV 0x04 -#define REG1A_LINECLP 0x02 +#define REG0D_CLRLNCNT 0x01 + +#define REG0F 0x0f + +#define REG16_CTRLHI 0x80 +#define REG16_TOSHIBA 0x40 +#define REG16_TGINV 0x20 +#define REG16_CK1INV 0x10 +#define REG16_CK2INV 0x08 +#define REG16_CTRLINV 0x04 +#define REG16_CKDIS 0x02 +#define REG16_CTRLDIS 0x01 + +#define REG17_TGMODE 0xc0 +#define REG17_SNRSYN 0x0f + +#define REG18 0x18 +#define REG18_CNSET 0x80 +#define REG18_DCKSEL 0x60 +#define REG18_CKTOGGLE 0x10 +#define REG18_CKDELAY 0x0c +#define REG18_CKSEL 0x03 + +#define REG1A_SW2SET 0x80 +#define REG1A_SW1SET 0x40 +#define REG1A_MANUAL3 0x02 +#define REG1A_MANUAL1 0x01 +#define REG1A_CK4INV 0x08 +#define REG1A_CK3INV 0x04 +#define REG1A_LINECLP 0x02 #define REG1C_TBTIME 0x07 -#define REG1D 0x1d -#define REG1D_CK4LOW 0x80 -#define REG1D_CK3LOW 0x40 -#define REG1D_CK1LOW 0x20 -#define REG1D_LINESEL 0x1f +#define REG1D 0x1d +#define REG1D_CK4LOW 0x80 +#define REG1D_CK3LOW 0x40 +#define REG1D_CK1LOW 0x20 +#define REG1D_LINESEL 0x1f #define REG1DS_LINESEL 0 #define REG1E 0x1e -#define REG1E_WDTIME 0xf0 +#define REG1E_WDTIME 0xf0 #define REG1ES_WDTIME 4 -#define REG1E_WDTIME 0xf0 +#define REG1E_WDTIME 0xf0 #define REG30 0x30 #define REG31 0x31 @@ -243,18 +243,18 @@ #define REGB1 0xb1 #define REGB2 0xb2 -#define REGB2_Z1MOD 0x1f +#define REGB2_Z1MOD 0x1f #define REGB3 0xb3 -#define REGB3_Z1MOD 0xff +#define REGB3_Z1MOD 0xff #define REGB4 0xb4 -#define REGB4_Z1MOD 0xff +#define REGB4_Z1MOD 0xff #define REGB5 0xb5 -#define REGB5_Z2MOD 0x1f +#define REGB5_Z2MOD 0x1f #define REGB6 0xb6 -#define REGB6_Z2MOD 0xff +#define REGB6_Z2MOD 0xff #define REGB7 0xb7 -#define REGB7_Z2MOD 0xff +#define REGB7_Z2MOD 0xff #define REG100 0x100 #define REG100_DOCSNR 0x80 @@ -537,6 +537,7 @@ typedef struct /** @brief gpio layout * describes initial gpio settings for a given model + * registers 0x31 to 0x38 */ static Gpio_layout gpios[]={ /* LiDE 110 */ @@ -547,6 +548,10 @@ static Gpio_layout gpios[]={ { 0x9f, 0x59, 0x01, 0x80, 0x5f, 0x01, 0x00 }, + /* LiDE 120 */ + { + 0x9f, 0x53, 0x01, 0x80, 0x5f, 0x01, 0x00 + }, }; typedef struct @@ -565,12 +570,13 @@ typedef struct } Memory_layout; static Memory_layout layouts[]={ - /* LIDE 110 */ - { + /* LIDE 110, 120 */ + { /* 0xd0 0xd1 0xd2 */ 0x0a, 0x15, 0x20, + /* 0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 */ 0x00, 0xac, 0x08, 0x55, 0x08, 0x56, 0x0f, 0xff }, - /* LIDE 210 */ + /* LIDE 210, 220 */ { 0x0a, 0x1f, 0x34, 0x01, 0x24, 0x08, 0x91, 0x08, 0x92, 0x0f, 0xff @@ -590,8 +596,8 @@ typedef struct { int half_ccd; /**> half ccd mode */ int exposure; /**> exposure */ int ck1map; /**> CK1MAP */ - int ck3map; /**> CK2MAP */ - int ck4map; /**> CK3MAP */ + int ck3map; /**> CK3MAP */ + int ck4map; /**> CK4MAP */ int segcnt; /**> SEGCNT */ int tg0cnt; /**> TG0CNT */ int expdummy; /**> exposure dummy */ @@ -603,6 +609,8 @@ typedef struct { uint8_t reg20; /**> register 0x20 value */ uint8_t reg61; /**> register 0x61 value */ uint8_t reg98; /**> register 0x98 value */ + uint8_t reg16; /**> register 0x16 value */ + uint8_t reg70; /**> register 0x70 value */ } Sensor_Profile; static size_t order_01[]={0,1}; @@ -610,58 +618,68 @@ static size_t order_0213[]={0,2,1,3}; /* *INDENT-OFF* */ -/** - * database of sensor profiles +/** @brief database of sensor profiles + * database of sensor profiles giving for each sensor and a given resolution, the period, and timings + * to setup the sensor for the scan. */ static Sensor_Profile sensors[]={ /* LiDE 110 */ - {CIS_CANONLIDE110, 600, 1, 2768, 0x1e, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21}, - {CIS_CANONLIDE110, 600, 0, 5360, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21}, - {CIS_CANONLIDE110, 1200, 0, 10528, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22}, - {CIS_CANONLIDE110, 2400, 0, 20864, 0x1e, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24}, + {CIS_CANONLIDE110, 600, 1, 2768, 0x1e, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21, 0x00, 0x00}, + {CIS_CANONLIDE110, 600, 0, 5360, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21, 0x00, 0x00}, + {CIS_CANONLIDE110, 1200, 0, 10528, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22, 0x00, 0x00}, + {CIS_CANONLIDE110, 2400, 0, 20864, 0x1e, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24, 0x00, 0x00}, - /* LiDE 120 */ - {CIS_CANONLIDE120, 600, 1, 2768, 0x0f, 0x9f, 0x55, 2552, 112, 94, 388, 574, 393, NULL , 0x00, 0x02, 0x20, 0x21}, - {CIS_CANONLIDE120, 600, 0, 5360, 0x0f, 0x9f, 0x55, 5168, 163, 94, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21}, - {CIS_CANONLIDE120, 1200, 0, 10528, 0x0f, 0x9f, 0x55, 5168, 163, 94, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22}, - {CIS_CANONLIDE120, 2400, 0, 20864, 0x0f, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24}, + /* LiDE 120 */ + {CIS_CANONLIDE120, 600, 1, 4608, 0x0f, 0x00, 0x55, 2552, 112, 94, 894, 1044, 994, NULL , 0x00, 0x02, 0x20, 0x21, 0x15, 0x00}, + {CIS_CANONLIDE120, 600, 0, 5360, 0x0f, 0x00, 0x55, 5104, 139, 94, 1644, 1994, 1844, NULL , 0x00, 0x02, 0x20, 0x21, 0x11, 0x1f}, + {CIS_CANONLIDE120, 1200, 0, 10528, 0x0f, 0x00, 0x55,10208, 192, 94, 3194, 3794, 3594, NULL , 0x00, 0x02, 0x20, 0x21, 0x15, 0x1f}, + {CIS_CANONLIDE120, 2400, 0, 20864, 0x0f, 0x00, 0x55,20416, 298, 94, 6244, 7544, 7094, NULL , 0x00, 0x02, 0x20, 0x21, 0x11, 0x00}, /* LiDE 210 */ - {CIS_CANONLIDE210, 600, 1, 2768, 0x1e, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21}, - {CIS_CANONLIDE210, 600, 0, 5360, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21}, - {CIS_CANONLIDE210, 1200, 0, 10528, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22}, - {CIS_CANONLIDE210, 2400, 0, 20864, 0x1e, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24}, + {CIS_CANONLIDE210, 600, 1, 2768, 0x1e, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21, 0x00, 0x00}, + {CIS_CANONLIDE210, 600, 0, 5360, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21, 0x00, 0x00}, + {CIS_CANONLIDE210, 1200, 0, 10528, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22, 0x00, 0x00}, + {CIS_CANONLIDE210, 2400, 0, 20864, 0x1e, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24, 0x00, 0x00}, /* LiDE 220 */ - {CIS_CANONLIDE220, 600, 1, 2768, 0x0f, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21}, - {CIS_CANONLIDE220, 600, 0, 5360, 0x0f, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21}, - {CIS_CANONLIDE220, 1200, 0, 10528, 0x0f, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22}, - {CIS_CANONLIDE220, 2400, 0, 20864, 0x0f, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24}, + {CIS_CANONLIDE220, 600, 1, 2768, 0x0f, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21, 0x00, 0x00}, + {CIS_CANONLIDE220, 600, 0, 5360, 0x0f, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21, 0x00, 0x00}, + {CIS_CANONLIDE220, 1200, 0, 10528, 0x0f, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22, 0x00, 0x00}, + {CIS_CANONLIDE220, 2400, 0, 20864, 0x0f, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24, 0x00, 0x00}, }; #define MOVE_DPI 200 #define MOVE_EXPOSURE 2304 - +/** @brief reference slope tables + * slope table directly extracted from USB logs, with a 'termination' value of 0. + */ static uint32_t lide210_fast[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2051, 1432, 1372, 1323, 1280, 1246, 1216, 1188, 1163, 1142, 1121, 1101, 1084, 1068, 1051, 1036, 1020, 1007, 995, 983, 971, 959, 949, 938, 929, 917, 908, 900, 891, 882, 874, 866, 857, 849, 843, 835, 829, 821, 816, 808, 802, 795, 789, 784, 778, 773, 765, 760, 755, 749, 744, 739, 734, 731, 726, 721, 716, 711, 707, 702, 698, 693, 690, 685, 682, 677, 672, 669, 665, 662, 657, 654, 650, 647, 644, 639, 637, 632, 629, 626, 622, 619, 617, 614, 610, 607, 604, 601, 599, 595, 592, 589, 587, 584, 581, 579, 576, 572, 570, 567, 564, 562, 559, 557, 554, 552, 549, 547, 544, 542, 539, 538, 536, 533, 531, 529, 526, 524, 522, 519, 518, 516, 513, 511, 509, 506, 505, 503, 501, 498, 497, 495, 493, 491, 490, 487, 485, 483, 482, 480, 477, 476, 474, 472, 470, 469, 467, 465, 464, 462, 460, 458, 456, 455, 453, 451, 450, 448, 447, 445, 444, 442, 440, 439, 437, 436, 434, 433, 431, 430, 428, 427, 425, 423, 422, 420, 419, 417, 417, 415, 414, 413, 411, 410, 408, 407, 405, 404, 402, 401, 400, 399, 398, 396, 395, 393, 392, 391, 390, 389, 387, 386, 385, 383, 382, 381, 380, 379, 377, 376, 375, 374, 373, 371, 370, 369, 368, 367, 366, 364, 363, 363, 361, 360, 359, 358, 357, 356, 355, 353, 352, 352, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 335, 335, 0}; -static uint32_t lide110_ok[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2051, 1961, 1901, 1852, 1809, 1775, 1745, 1717, 1692, 1671, 1650, 1630, 1613, 1597,1580,1565,1549,1536,1524,1512,1500,1488,1478,1467,1458,1446,1437,1429,1420,1411,1403,1395,1386,1378,1372,1364,1358,1350,1345,1337,1331,1324,1318,1313,1307,1302,1294,1289,1284,1278,1273,1268,1263,1260,1255,1250,1245,1240,1236,1231,1227,1222,1219,1214,1211,1206,1201,1198,1194,1191,1186,1183,1179,1176,1173,1168,1166,1161,1158,1155,1151,1148,1146,1143,1139,1136,1133,1130,1128,1124,1121,1118,1116,1113,1110,1108,1105,1101,1099,1096,1093,1091,1088,1086,1083,1081,1078,1076,1073,1071,1068,1067,1065,1062,1060,1058,1055,1053,1051,1048,1047,1045,1042,1040,1038,1035,1034,1032,1030,1027,1026,1024,1022,1020,1019,1016,1014,1012,1011,1009,1006,1005,1003,1001,999,998,996,994,993,991,989,987,985,984,982,980,979,977,976,974,973,971,969,968,966,965,963,962,960,959,957,956,954,952,951,949,948,946,946,944,943,942,940,939,937,936,934,933,931,930,929,928,927,925,924,922,921,920,919,918,916,915,914,912,911,910,909,908,906,905,904,903,902,900,899,898,897,896,895,893,892,892,890,889,888,887,886,885,884,882,881,881,879,878,877,876,875,874,873,872,871,870,869,868,867,864,857, 849, 843, 835, 829, 821, 816, 808, 802, 795, 789, 784, 778, 773, 765, 760, 755, 749, 744, 739, 734, 731, 726, 721, 716, 711, 707, 702, 698, 693, 690, 685, 682, 677, 672, 669, 665, 662, 657, 654, 650, 647, 644, 639, 637, 632, 629, 626, 622, 619, 617, 614, 610, 607, 604, 601, 599, 595, 592, 589, 587, 584, 581, 579, 576, 572, 570, 567, 564, 562, 559, 557, 554, 552, 549, 547, 544, 542, 539, 538, 536, 533, 531, 529, 526, 524, 522, 519, 518, 516, 513, 511, 509, 506, 505, 503, 501, 498, 497, 495, 493, 491, 490, 487, 485, 483, 482, 480, 477, 476, 474, 472, 470, 469, 467, 465, 464, 462, 460, 458, 456, 455, 453, 451, 450, 448, 447, 445, 444, 442, 440, 439, 437, 436, 434, 433, 431, 430, 428, 427, 425, 423, 422, 420, 419, 417, 417, 415, 414, 413, 411, 410, 408, 407, 405, 404, 402, 401, 400, 399, 398, 396, 395, 393, 392, 391, 390, 389, 387, 386, 385, 383, 382, 381, 380, 379, 377, 376, 375, 374, 373, 371, 370, 369, 368, 367, 366, 364, 363, 363, 361, 360, 359, 358, 357, 356, 355, 353, 352, 352, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 335, 335, 0}; +static uint32_t lide110_ok[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2051, 1961, 1901, 1852, 1809, 1775, 1745, 1717, 1692, 1671, 1650, 1630, 1613, 1597, 1580, 1565, 1549, 1536, 1524, 1512, 1500, 1488, 1478, 1467, 1458, 1446, 1437, 1429, 1420, 1411, 1403, 1395, 1386, 1378, 1372, 1364, 1358, 1350, 1345, 1337, 1331, 1324, 1318, 1313, 1307, 1302, 1294, 1289, 1284, 1278, 1273, 1268, 1263, 1260, 1255, 1250, 1245, 1240, 1236, 1231, 1227, 1222, 1219, 1214, 1211, 1206, 1201, 1198, 1194, 1191, 1186, 1183, 1179, 1176, 1173, 1168, 1166, 1161, 1158, 1155, 1151, 1148, 1146, 1143, 1139, 1136, 1133, 1130, 1128, 1124, 1121, 1118, 1116, 1113, 1110, 1108, 1105, 1101, 1099, 1096, 1093, 1091, 1088, 1086, 1083, 1081, 1078, 1076, 1073, 1071, 1068, 1067, 1065, 1062, 1060, 1058, 1055, 1053, 1051, 1048, 1047, 1045, 1042, 1040, 1038, 1035, 1034, 1032, 1030, 1027, 1026, 1024, 1022, 1020, 1019, 1016, 1014, 1012, 1011, 1009, 1006, 1005, 1003, 1001, 999, 998, 996, 994, 993, 991, 989, 987, 985, 984, 982, 980, 979, 977, 976, 974, 973, 971, 969, 968, 966, 965, 963, 962, 960, 959, 957, 956, 954, 952, 951, 949, 948, 946, 946, 944, 943, 942, 940, 939, 937, 936, 934, 933, 931, 930, 929, 928, 927, 925, 924, 922, 921, 920, 919, 918, 916, 915, 914, 912, 911, 910, 909, 908, 906, 905, 904, 903, 902, 900, 899, 898, 897, 896, 895, 893, 892, 892, 890, 889, 888, 887, 886, 885, 884, 882, 881, 881, 879, 878, 877, 876, 875, 874, 873, 872, 871, 870, 869, 868, 867, 864, 857, 849, 843, 835, 829, 821, 816, 808, 802, 795, 789, 784, 778, 773, 765, 760, 755, 749, 744, 739, 734, 731, 726, 721, 716, 711, 707, 702, 698, 693, 690, 685, 682, 677, 672, 669, 665, 662, 657, 654, 650, 647, 644, 639, 637, 632, 629, 626, 622, 619, 617, 614, 610, 607, 604, 601, 599, 595, 592, 589, 587, 584, 581, 579, 576, 572, 570, 567, 564, 562, 559, 557, 554, 552, 549, 547, 544, 542, 539, 538, 536, 533, 531, 529, 526, 524, 522, 519, 518, 516, 513, 511, 509, 506, 505, 503, 501, 498, 497, 495, 493, 491, 490, 487, 485, 483, 482, 480, 477, 476, 474, 472, 470, 469, 467, 465, 464, 462, 460, 458, 456, 455, 453, 451, 450, 448, 447, 445, 444, 442, 440, 439, 437, 436, 434, 433, 431, 430, 428, 427, 425, 423, 422, 420, 419, 417, 417, 415, 414, 413, 411, 410, 408, 407, 405, 404, 402, 401, 400, 399, 398, 396, 395, 393, 392, 391, 390, 389, 387, 386, 385, 383, 382, 381, 380, 379, 377, 376, 375, 374, 373, 371, 370, 369, 368, 367, 366, 364, 363, 363, 361, 360, 359, 358, 357, 356, 355, 353, 352, 352, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 335, 335, 0}; +static uint32_t lide120_fast[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 1957, 1845, 1768, 1710, 1665, 1624, 1588, 1557, 1529, 1504, 1481, 1458, 1440, 1420, 1403, 1386, 1370, 1356, 1343, 1329, 1316, 1303, 1293, 1280, 1270, 1260, 1250, 1241, 1231, 1222, 1214, 1206, 1197, 1189, 1182, 1174, 1167, 1160, 1153, 1147, 1140, 1133, 1128, 1121, 1116, 1110, 1104, 1099, 1093, 1088, 1082, 1077, 1072, 1067, 1062, 1058, 1053, 1049, 1045, 1040, 1035, 1032, 1027, 1023, 1020, 1015, 1012, 1008, 1004, 1000, 997, 993, 989, 985, 982, 979, 975, 972, 969, 966, 963, 959, 956, 953, 950, 947, 945, 942, 939, 936, 933, 930, 928, 925, 922, 920, 917, 914, 911, 909, 907, 904, 902, 899, 897, 895, 892, 890, 888, 886, 883, 881, 879, 876, 874, 872, 870, 864, 864, 0}; +static uint32_t lide120_ok[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2286, 2264, 2248, 2232, 2221, 2211, 2205, 2195, 2190, 2180, 2175, 2170, 2160, 2155, 2150, 2145, 2140, 2135, 2130, 2125, 2121, 2116, 2111, 2106, 2106, 2102, 2097, 2092, 2087, 2087, 2083, 2078, 2074, 2074, 2069, 2064, 2064, 2060, 2055, 2055, 2051, 2051, 2046, 2042, 2042, 2038, 2038, 2033, 2029, 2029, 2024, 2024, 2020, 2010, 2010, 670*2, 0}; static uint32_t lide110_slow[] = { 62496, 7896, 2632, 0}; +static uint32_t lide120_slow[] = { 62464, 7896, 2632, 0}; static uint32_t lide110_max[] = { 62496, 31296, 10432, 0}; +static uint32_t lide120_max[] = { 62592, 62592, 41728, 31296, 10432, 0}; static uint32_t lide210_max[] = { 62496, 31296, 20864, 10432, 0}; -/** - * database of motor profiles - */ - - /* NEXT LPERIOD=PREVIOUS*2-192 */ +/** @brief database of motor profiles + * database of motor profiles, for each exposure deigned for the sensor, gives the reference slope table to use + * for scan. + */ static Motor_Profile motors[]={ {MOTOR_CANONLIDE110, 2768, 0, lide210_fast}, - {MOTOR_CANONLIDE110, 5360, 0, lide110_ok}, + {MOTOR_CANONLIDE110, 5360, 1, lide110_ok}, {MOTOR_CANONLIDE110, 10528, 1, lide110_slow}, {MOTOR_CANONLIDE110, 20864, 2, lide110_max}, + {MOTOR_CANONLIDE120, 4608, 0, lide120_fast}, + {MOTOR_CANONLIDE120, 5360, 1, lide120_ok}, + {MOTOR_CANONLIDE120, 10528, 2, lide120_slow}, + {MOTOR_CANONLIDE120, 20864, 2, lide120_max}, {MOTOR_CANONLIDE210, 2768, 0, lide210_fast}, - {MOTOR_CANONLIDE210, 5360, 0, lide110_ok}, + {MOTOR_CANONLIDE210, 5360, 1, lide110_ok}, {MOTOR_CANONLIDE210, 10528, 1, lide110_slow}, {MOTOR_CANONLIDE210, 20864, 2, lide210_max}, {0, 0, 0, NULL}, @@ -670,10 +688,10 @@ static Motor_Profile motors[]={ GENESYS_STATIC SANE_Status gl124_init_scan_regs (Genesys_Device * dev, Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ + float xres, /*dpi */ + float yres, /*dpi */ + float startx, /*optical_res, from dummy_pixel+1 */ + float starty, /*base_ydpi, from home! */ float pixels, float lines, unsigned int depth, diff --git a/backend/genesys_gl646.c b/backend/genesys_gl646.c index 19b4585..58952fb 100644 --- a/backend/genesys_gl646.c +++ b/backend/genesys_gl646.c @@ -3,7 +3,7 @@ Copyright (C) 2003 Oliver Rauch Copyright (C) 2003, 2004 Henning Meier-Geinitz Copyright (C) 2004 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2004-2013 Stéphane Voltz Copyright (C) 2005-2009 Pierre Willenbrock Copyright (C) 2007 Luke Copyright (C) 2011 Alexey Osipov for HP2400 description @@ -1999,7 +1999,7 @@ gl646_set_fe (Genesys_Device * dev, uint8_t set, int dpi) /* Wolfson type frontend */ if ((dev->reg[reg_0x04].value & REG04_FESET) != 0x03) { - DBG (DBG_proc, "gl646_set_fe(): unspported frontend type %d\n", + DBG (DBG_proc, "gl646_set_fe(): unsupported frontend type %d\n", dev->reg[reg_0x04].value & REG04_FESET); return SANE_STATUS_UNSUPPORTED; } @@ -3066,7 +3066,7 @@ gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to setup for scan: %s\n", __FUNCTION__, + "%s: failed to setup for scan: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -3082,7 +3082,7 @@ gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to set frontend: %s\n", __FUNCTION__, + "%s: failed to set frontend: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -3429,7 +3429,7 @@ setup_for_scan (Genesys_Device * dev, DBG (DBG_info, "%s settings:\nResolution: %ux%uDPI\n" "Lines : %u\nPixels : %u\nStartpos : %.3f/%.3f\nScan mode : %d\nScan method: %s\n\n", - __FUNCTION__, + __func__, settings.xres, settings.yres, settings.lines, settings.pixels, settings.tl_x, settings.tl_y, settings.scan_mode, settings.scan_method == SCAN_METHOD_FLATBED ? "flatbed" : "XPA"); @@ -3482,16 +3482,16 @@ setup_for_scan (Genesys_Device * dev, move += (settings.tl_y * dev->motor.optical_ydpi) / MM_PER_INCH; } - DBG (DBG_info, "%s: move=%d steps\n", __FUNCTION__, move); + DBG (DBG_info, "%s: move=%d steps\n", __func__, move); /* security check */ if (move < 0) { - DBG (DBG_error, "%s: overriding negative move value %d\n", __FUNCTION__, move); + DBG (DBG_error, "%s: overriding negative move value %d\n", __func__, move); move = 0; } } - DBG (DBG_info, "%s: move=%d steps\n", __FUNCTION__, move); + DBG (DBG_info, "%s: move=%d steps\n", __func__, move); /* pixels are allways given at full CCD optical resolution */ /* use detected left margin and fixed value */ @@ -3550,7 +3550,7 @@ setup_for_scan (Genesys_Device * dev, depth); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed setup registers: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed setup registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -3585,7 +3585,7 @@ setup_for_scan (Genesys_Device * dev, sanei_genesys_read_reg_from_set (regs, 0x21)); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to send slope table 0: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to send slope table 0: %s\n", __func__, sane_strstatus (status)); return status; } @@ -3594,7 +3594,7 @@ setup_for_scan (Genesys_Device * dev, sanei_genesys_read_reg_from_set (regs, 0x6b)); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to send slope table 1: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus (status)); return status; } @@ -4414,7 +4414,7 @@ gl646_coarse_gain_calibration (Genesys_Device * dev, int dpi) if (status != SANE_STATUS_GOOD) { free(line); - DBG (DBG_error, "%s: failed to scan first line\n", __FUNCTION__); + DBG (DBG_error, "%s: failed to scan first line\n", __func__); return status; } @@ -4472,7 +4472,7 @@ gl646_coarse_gain_calibration (Genesys_Device * dev, int dpi) dev->frontend.gain[k]++; DBG (DBG_proc, - "%s: channel %d, average = %.2f, gain = %d\n", __FUNCTION__, + "%s: channel %d, average = %.2f, gain = %d\n", __func__, k, average[k], dev->frontend.gain[k]); } free (line); @@ -4484,7 +4484,7 @@ gl646_coarse_gain_calibration (Genesys_Device * dev, int dpi) dev->frontend.gain[2] = dev->frontend.gain[0]; } - DBG (DBG_info, "%s: gains=(%d,%d,%d)\n", __FUNCTION__, + DBG (DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, dev->frontend.gain[0], dev->frontend.gain[1], dev->frontend.gain[2]); DBGCOMPLETED; return status; @@ -5767,6 +5767,7 @@ static Genesys_Command_Set gl646_cmd_set = { gl646_led_calibration, gl646_slow_back_home, + NULL, gl646_bulk_write_register, gl646_bulk_write_data, diff --git a/backend/genesys_gl646.h b/backend/genesys_gl646.h index 9e328c5..4c47d03 100644 --- a/backend/genesys_gl646.h +++ b/backend/genesys_gl646.h @@ -2,7 +2,7 @@ Copyright (C) 2003-2004 Henning Meier-Geinitz Copyright (C) 2004-2005 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2004-2013 Stéphane Voltz Copyright (C) 2005-2009 Pierre Willenbrock This file is part of the SANE package. @@ -276,10 +276,10 @@ gl646_move_to_ta (Genesys_Device * dev); /** * sets up the scanner for a scan, registers, gamma tables, shading tables * and slope tables, based on the parameter struct. - * @param device device to set up - * @param regs registers to set up - * @param settings settings of the scan - * @param split true if move before scan has to be done + * @param dev device to set up + * @param regs registers to set up + * @param settings settings of the scan + * @param split true if move before scan has to be done * @param xcorrection true if scanner's X geometry must be taken into account to * compute X, ie add left margins * @param ycorrection true if scanner's Y geometry must be taken into account to diff --git a/backend/genesys_gl841.c b/backend/genesys_gl841.c index 2b16c67..43c01ff 100644 --- a/backend/genesys_gl841.c +++ b/backend/genesys_gl841.c @@ -3,7 +3,7 @@ Copyright (C) 2003 Oliver Rauch Copyright (C) 2003, 2004 Henning Meier-Geinitz Copyright (C) 2004 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2004-2013 Stéphane Voltz Copyright (C) 2005 Philipp Schmid Copyright (C) 2005-2009 Pierre Willenbrock Copyright (C) 2006 Laurent Charpentier @@ -204,7 +204,7 @@ printtime(char *p) { gettimeofday(&t,NULL); dif = t.tv_sec - start_time.tv_sec; dif = dif*1000000 + t.tv_usec - start_time.tv_usec; - fprintf(stderr,"%s %lluµs\n",p,dif); + fprintf(stderr,"%s %lluµs\n",p,dif); } */ @@ -1158,7 +1158,7 @@ gl841_send_slope_table (Genesys_Device * dev, int table_nr, { sprintf (msg+strlen(msg), ",%d", slope_table[i]); } - DBG (DBG_io, "%s: %s\n", __FUNCTION__, msg); + DBG (DBG_io, "%s: %s\n", __func__, msg); } status = @@ -1204,7 +1204,7 @@ gl841_set_lide80_fe (Genesys_Device * dev, uint8_t set) if (set == AFE_INIT) { - DBG (DBG_proc, "%s(): setting DAC %u\n", __FUNCTION__, + DBG (DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); /* sets to default values */ @@ -1214,21 +1214,21 @@ gl841_set_lide80_fe (Genesys_Device * dev, uint8_t set) status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: writing reg 0x00 failed: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus (status)); return status; } status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.reg[1]); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: writing reg 0x03 failed: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: writing reg 0x03 failed: %s\n", __func__, sane_strstatus (status)); return status; } status = sanei_genesys_fe_write_data (dev, 0x06, dev->frontend.reg[2]); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: writing reg 0x06 failed: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: writing reg 0x06 failed: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1239,21 +1239,21 @@ gl841_set_lide80_fe (Genesys_Device * dev, uint8_t set) status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: writing reg 0x00 failed: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus (status)); return status; } status = sanei_genesys_fe_write_data (dev, 0x06, dev->frontend.offset[0]); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: writing offset failed: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: writing offset failed: %s\n", __func__, sane_strstatus (status)); return status; } status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.gain[0]); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: writing gain failed: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: writing gain failed: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1734,7 +1734,7 @@ gl841_init_motor_regs(Genesys_Device * dev, 0, 0, &scan_power_mode); - DBG (DBG_info, "%s : fast_exposure=%d pixels\n", __FUNCTION__, fast_exposure); + DBG (DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); } if (action == MOTOR_ACTION_HOME_FREE) { @@ -1911,7 +1911,7 @@ gl841_init_motor_regs_scan(Genesys_Device * dev, 0, &dummy_power_mode); - DBG (DBG_info, "%s : fast_exposure=%d pixels\n", __FUNCTION__, fast_exposure); + DBG (DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); memset(slow_slope_table,0xff,512); @@ -2453,7 +2453,7 @@ gl841_init_optical_regs_scan(Genesys_Device * dev, sanei_genesys_set_double(reg, REG_DPISET, dpiset); sanei_genesys_set_double(reg, REG_STRPIXEL, start); sanei_genesys_set_double(reg, REG_ENDPIXEL, end); - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d\n",__FUNCTION__,start,end); + DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d\n",__func__,start,end); /* words(16bit) before gamma, conversion to 8 bit or lineart*/ words_per_line = (pixels * dpiset) / gl841_get_dpihw(dev); @@ -2794,7 +2794,7 @@ dummy \ scanned lines start, used_pixels, &scan_power_mode); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __FUNCTION__, exposure_time); + DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); /*** optical parameters ***/ /* in case of dynamic lineart, we use an internal 8 bit gray scan @@ -3160,7 +3160,7 @@ dummy \ scanned lines start, used_pixels, &scan_power_mode); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __FUNCTION__, exposure_time); + DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); /* scanned area must be enlarged by max color shift needed */ max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); @@ -3451,7 +3451,7 @@ gl841_stop_action (Genesys_Device * dev) uint8_t val40, val; unsigned int loop; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); status = sanei_genesys_get_status (dev, &val); if (DBG_LEVEL >= DBG_io) @@ -3463,7 +3463,7 @@ gl841_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n",__FUNCTION__, + "%s: failed to read home sensor: %s\n",__func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -3472,7 +3472,7 @@ gl841_stop_action (Genesys_Device * dev) /* only stop action if needed */ if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) { - DBG (DBG_info, "%s: already stopped\n", __FUNCTION__); + DBG (DBG_info, "%s: already stopped\n", __func__); DBGCOMPLETED; return SANE_STATUS_GOOD; } @@ -3485,7 +3485,7 @@ gl841_stop_action (Genesys_Device * dev) status = gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -3505,7 +3505,7 @@ gl841_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n",__FUNCTION__, + "%s: failed to read home sensor: %s\n",__func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -3557,7 +3557,7 @@ gl841_eject_document (Genesys_Device * dev) DBG (DBG_proc, "gl841_eject_document\n"); - if (!dev->model->is_sheetfed == SANE_TRUE) + if (dev->model->is_sheetfed == SANE_FALSE) { DBG (DBG_proc, "gl841_eject_document: there is no \"eject sheet\"-concept for non sheet fed\n"); DBG (DBG_proc, "gl841_eject_document: finished\n"); @@ -3762,14 +3762,14 @@ gl841_detect_document_end (Genesys_Device * dev) uint8_t val; size_t total_bytes_to_read; - DBG (DBG_proc, "%s: begin\n", __FUNCTION__); + DBG (DBG_proc, "%s: begin\n", __func__); RIE (gl841_get_paper_sensor (dev, &paper_loaded)); /* sheetfed scanner uses home sensor as paper present */ if ((dev->document == SANE_TRUE) && !paper_loaded) { - DBG (DBG_info, "%s: no more document\n", __FUNCTION__); + DBG (DBG_info, "%s: no more document\n", __func__); dev->document = SANE_FALSE; /* we can't rely on total_bytes_to_read since the frontend @@ -3781,14 +3781,14 @@ gl841_detect_document_end (Genesys_Device * dev) { dev->total_bytes_to_read = dev->total_bytes_read; dev->read_bytes_left = 0; - DBG (DBG_proc, "%s: finished\n", __FUNCTION__); + DBG (DBG_proc, "%s: finished\n", __func__); return SANE_STATUS_GOOD; } if (dev->settings.scan_mode == SCAN_MODE_COLOR && dev->model->is_cis) { scancnt/=3; } - DBG (DBG_io, "%s: scancnt=%u lines\n",__FUNCTION__, scancnt); + DBG (DBG_io, "%s: scancnt=%u lines\n",__func__, scancnt); RIE(sanei_genesys_read_register(dev, 0x25, &val)); lincnt=65536*val; @@ -3796,26 +3796,26 @@ gl841_detect_document_end (Genesys_Device * dev) lincnt+=256*val; RIE(sanei_genesys_read_register(dev, 0x27, &val)); lincnt+=val; - DBG (DBG_io, "%s: lincnt=%u lines\n",__FUNCTION__, lincnt); + DBG (DBG_io, "%s: lincnt=%u lines\n",__func__, lincnt); postcnt=(SANE_UNFIX(dev->model->post_scan)/MM_PER_INCH)*dev->settings.yres; - DBG (DBG_io, "%s: postcnt=%u lines\n",__FUNCTION__, postcnt); + DBG (DBG_io, "%s: postcnt=%u lines\n",__func__, postcnt); /* the current scancnt is also the final one, so we use it to * compute total bytes to read. We also add the line count to eject document */ total_bytes_to_read=(scancnt+postcnt)*dev->wpl; - DBG (DBG_io, "%s: old total_bytes_to_read=%u\n",__FUNCTION__,(unsigned int)dev->total_bytes_to_read); - DBG (DBG_io, "%s: new total_bytes_to_read=%u\n",__FUNCTION__,(unsigned int)total_bytes_to_read); + DBG (DBG_io, "%s: old total_bytes_to_read=%u\n",__func__,(unsigned int)dev->total_bytes_to_read); + DBG (DBG_io, "%s: new total_bytes_to_read=%u\n",__func__,(unsigned int)total_bytes_to_read); /* assign new end value */ if(dev->total_bytes_to_read>total_bytes_to_read) { - DBG (DBG_io, "%s: scan shorten\n",__FUNCTION__); + DBG (DBG_io, "%s: scan shorten\n",__func__); dev->total_bytes_to_read=total_bytes_to_read; } } - DBG (DBG_proc, "%s: finished\n", __FUNCTION__); + DBG (DBG_proc, "%s: finished\n", __func__); return SANE_STATUS_GOOD; } @@ -4184,7 +4184,7 @@ gl841_search_start_position (Genesys_Device * dev) SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE); if(status!=SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to init scan registers: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to init scan registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -4194,7 +4194,7 @@ gl841_search_start_position (Genesys_Device * dev) gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -4346,7 +4346,7 @@ gl841_init_regs_for_shading (Genesys_Device * dev) float starty=0; DBGSTART; - DBG (DBG_proc, "%s: lines = %d\n", __FUNCTION__, (int)(dev->calib_lines)); + DBG (DBG_proc, "%s: lines = %d\n", __func__, (int)(dev->calib_lines)); /* initial calibration reg values */ memcpy (dev->calib_reg, dev->reg, GENESYS_GL841_MAX_REGS * sizeof (Genesys_Register_Set)); @@ -4383,7 +4383,7 @@ gl841_init_regs_for_shading (Genesys_Device * dev) SCAN_FLAG_IGNORE_LINE_DISTANCE); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -4393,7 +4393,7 @@ gl841_init_regs_for_shading (Genesys_Device * dev) status = gl841_bulk_write_register (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -4491,7 +4491,7 @@ gl841_init_regs_for_scan (Genesys_Device * dev) if(dev->model->is_cis && dev->settings.true_gray && dev->settings.scan_mode != SCAN_MODE_COLOR) { - DBG (DBG_io, "%s: activating LEDADD\n", __FUNCTION__); + DBG (DBG_io, "%s: activating LEDADD\n", __func__); flags |= SCAN_FLAG_ENABLE_LEDADD; } @@ -4610,11 +4610,11 @@ gl841_led_calibration (Genesys_Device * dev) { move = SANE_UNFIX (dev->model->y_offset_calib); move = (move * (dev->motor.base_ydpi)) / MM_PER_INCH; - DBG (DBG_io, "%s: move=%d lines\n", __FUNCTION__, move); + DBG (DBG_io, "%s: move=%d lines\n", __func__, move); status = gl841_feed(dev, move); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to feed: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to feed: %s\n", __func__, sane_strstatus (status)); return status; } @@ -4644,7 +4644,7 @@ gl841_led_calibration (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to setup scan: %s\n", __FUNCTION__, + "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -4694,7 +4694,7 @@ gl841_led_calibration (Genesys_Device * dev) RIE (gl841_bulk_write_register (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS)); - DBG (DBG_info, "%s: starting line reading\n", __FUNCTION__); + DBG (DBG_info, "%s: starting line reading\n", __func__); RIE (gl841_begin_scan (dev, dev->calib_reg, SANE_TRUE)); RIE (sanei_genesys_read_data_from_scanner (dev, line, total_size)); @@ -4727,7 +4727,7 @@ gl841_led_calibration (Genesys_Device * dev) avg[j] /= num_pixels; } - DBG(DBG_info,"%s: average: %d,%d,%d\n", __FUNCTION__, avg[0], avg[1], avg[2]); + DBG(DBG_info,"%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); acceptable = SANE_TRUE; @@ -4798,7 +4798,7 @@ gl841_led_calibration (Genesys_Device * dev) } while (!acceptable && turn < 100); - DBG(DBG_info,"%s: acceptable exposure: %d,%d,%d\n", __FUNCTION__, exp[0],exp[1],exp[2]); + DBG(DBG_info,"%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0],exp[1],exp[2]); /* cleanup before return */ free (line); @@ -4891,7 +4891,7 @@ ad_fe_offset_calibration (Genesys_Device * dev) dev->frontend.offset[2] = (top+bottom)/2; /* scan line */ - DBG (DBG_info, "%s: starting line reading\n",__FUNCTION__); + DBG (DBG_info, "%s: starting line reading\n",__func__); gl841_bulk_write_register (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS); gl841_set_fe(dev, AFE_SET); gl841_begin_scan (dev, dev->calib_reg, SANE_TRUE); @@ -4909,7 +4909,7 @@ ad_fe_offset_calibration (Genesys_Device * dev) average+=line[i]; } average/=total_size; - DBG (DBG_data, "%s: average=%d\n", __FUNCTION__, average); + DBG (DBG_data, "%s: average=%d\n", __func__, average); /* if min value is above target, the current value becomes the new top * else it is the new bottom */ @@ -4928,7 +4928,7 @@ ad_fe_offset_calibration (Genesys_Device * dev) dev->frontend.offset[1]=0; dev->frontend.offset[2]=0; free(line); - DBG (DBG_info, "%s: offset=(%d,%d,%d)\n", __FUNCTION__, + DBG (DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, dev->frontend.offset[0], dev->frontend.offset[1], dev->frontend.offset[2]); @@ -5374,18 +5374,18 @@ gl841_coarse_gain_calibration (Genesys_Device * dev, int dpi) int lines=1; int move; - DBG (DBG_proc, "%s: dpi=%d\n", __FUNCTION__, dpi); + DBG (DBG_proc, "%s: dpi=%d\n", __func__, dpi); /* feed to white strip if needed */ if (dev->model->y_offset_calib>0) { move = SANE_UNFIX (dev->model->y_offset_calib); move = (move * (dev->motor.base_ydpi)) / MM_PER_INCH; - DBG (DBG_io, "%s: move=%d lines\n", __FUNCTION__, move); + DBG (DBG_io, "%s: move=%d lines\n", __func__, move); status = gl841_feed(dev, move); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to feed: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to feed: %s\n", __func__, sane_strstatus (status)); return status; } @@ -5414,7 +5414,7 @@ gl841_coarse_gain_calibration (Genesys_Device * dev, int dpi) if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -5475,7 +5475,7 @@ gl841_coarse_gain_calibration (Genesys_Device * dev, int dpi) dev->frontend.gain[j] = gain[j]*12; } - DBG (DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __FUNCTION__, + DBG (DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j],dev->frontend.gain[j]); } @@ -5516,7 +5516,7 @@ gl841_coarse_gain_calibration (Genesys_Device * dev, int dpi) } free (line); - DBG (DBG_info, "%s: gain=(%d,%d,%d)\n", __FUNCTION__, + DBG (DBG_info, "%s: gain=(%d,%d,%d)\n", __func__, dev->frontend.gain[0], dev->frontend.gain[1], dev->frontend.gain[2]); @@ -5663,7 +5663,7 @@ gl841_is_compatible_calibration (Genesys_Device * dev, if ((time.tv_sec - cache->last_calibration > 30 * 60) && (dev->model->is_sheetfed == SANE_FALSE)) { - DBG (DBG_proc, "%s: expired entry, non compatible cache\n",__FUNCTION__); + DBG (DBG_proc, "%s: expired entry, non compatible cache\n",__func__); return SANE_STATUS_UNSUPPORTED; } } @@ -5969,7 +5969,7 @@ gl841_search_strip (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black) if (status != SANE_STATUS_GOOD) { free(data); - DBG (DBG_error, "%s: failed to setup for scan: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -6208,7 +6208,7 @@ gl841_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) uint8_t *buffer,*ptr,*src; DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__FUNCTION__,size); + DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); /* old method if no SHDAREA */ if((dev->reg[reg_0x01].value & REG01_SHDAREA) == 0) @@ -6217,7 +6217,7 @@ gl841_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) status = sanei_genesys_set_buffer_address (dev, 0x0000); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to set buffer address: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus (status)); return status; } @@ -6226,7 +6226,7 @@ gl841_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to send shading table: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to send shading table: %s\n", __func__, sane_strstatus (status)); return status; } @@ -6238,14 +6238,14 @@ gl841_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) length = (uint32_t) (size / 3); sanei_genesys_get_double(dev->reg,REG_STRPIXEL,&strpixel); sanei_genesys_get_double(dev->reg,REG_ENDPIXEL,&endpixel); - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d\n",__FUNCTION__,strpixel,endpixel,endpixel-strpixel); + DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d\n",__func__,strpixel,endpixel,endpixel-strpixel); /* compute deletion/average factor */ sanei_genesys_get_double(dev->reg,REG_DPISET,&dpiset); dpihw = gl841_get_dpihw(dev); half=dev->current_setup.half_ccd+1; factor=dpihw/dpiset; - DBG( DBG_io2, "%s: dpihw=%d, dpiset=%d, half_ccd=%d, factor=%d\n",__FUNCTION__,dpihw,dpiset,half-1,factor); + DBG( DBG_io2, "%s: dpihw=%d, dpiset=%d, half_ccd=%d, factor=%d\n",__func__,dpihw,dpiset,half-1,factor); /* binary data logging */ if(DBG_LEVEL>=DBG_data) @@ -6269,11 +6269,11 @@ gl841_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) */ beginpixel = dev->sensor.CCD_start_xoffset / half; beginpixel += dev->sensor.dummy_pixel + 1; - DBG(DBG_io2, "%s: ORIGIN PIXEL=%d\n", __FUNCTION__, beginpixel); + DBG(DBG_io2, "%s: ORIGIN PIXEL=%d\n", __func__, beginpixel); beginpixel = (strpixel-beginpixel*2*2)/factor; - DBG(DBG_io2, "%s: BEGIN PIXEL=%d\n",__FUNCTION__,beginpixel/4); + DBG(DBG_io2, "%s: BEGIN PIXEL=%d\n",__func__,beginpixel/4); - DBG(DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__FUNCTION__,length, length/4); + DBG(DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__func__,length, length/4); buffer=(uint8_t *)malloc(pixels); memset(buffer,0,pixels); @@ -6352,6 +6352,7 @@ static Genesys_Command_Set gl841_cmd_set = { gl841_led_calibration, gl841_slow_back_home, + NULL, gl841_bulk_write_register, gl841_bulk_write_data, diff --git a/backend/genesys_gl841.h b/backend/genesys_gl841.h index bbb79f1..d1bd07e 100644 --- a/backend/genesys_gl841.h +++ b/backend/genesys_gl841.h @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2011-2013 Stéphane Voltz + Copyright (C) 2011-2013 Stéphane Voltz This file is part of the SANE package. diff --git a/backend/genesys_gl843.c b/backend/genesys_gl843.c index 2b0d8fa..b47fb7e 100644 --- a/backend/genesys_gl843.c +++ b/backend/genesys_gl843.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2010-2013 Stéphane Voltz This file is part of the SANE package. @@ -376,7 +376,7 @@ gl843_get_step_multiplier (Genesys_Register_Set * regs) value = 1; } } - DBG (DBG_io, "%s: step multiplier is %d\n", __FUNCTION__, value); + DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); return value; } @@ -452,7 +452,7 @@ static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi, int flags) /* default fallback */ if(idx<0) { - DBG (DBG_warn,"%s: using default sensor profile\n",__FUNCTION__); + DBG (DBG_warn,"%s: using default sensor profile\n",__func__); idx=0; } @@ -790,7 +790,7 @@ gl843_send_slope_table (Genesys_Device * dev, int table_nr, int i; char msg[10000]; - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __FUNCTION__, + DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, table_nr, steps); table = (uint8_t *) malloc (steps * 2); @@ -807,7 +807,7 @@ gl843_send_slope_table (Genesys_Device * dev, int table_nr, { sprintf (msg+strlen(msg), "%d", slope_table[i]); } - DBG (DBG_io, "%s: %s\n", __FUNCTION__, msg); + DBG (DBG_io, "%s: %s\n", __func__, msg); } @@ -818,7 +818,7 @@ gl843_send_slope_table (Genesys_Device * dev, int table_nr, { DBG (DBG_error, "%s: write data failed writing slope table %d (%s)\n", - __FUNCTION__, table_nr, sane_strstatus (status)); + __func__, table_nr, sane_strstatus (status)); } free (table); @@ -957,7 +957,7 @@ gl843_init_motor_regs_scan (Genesys_Device * dev, lincnt=scan_lines; sanei_genesys_set_triple(reg,REG_LINCNT,lincnt); - DBG (DBG_io, "%s: lincnt=%d\n", __FUNCTION__, lincnt); + DBG (DBG_io, "%s: lincnt=%d\n", __func__, lincnt); /* compute register 02 value */ r = sanei_genesys_get_address (reg, REG02); @@ -1036,7 +1036,7 @@ gl843_init_motor_regs_scan (Genesys_Device * dev, { dist += fast_steps*2; } - DBG (DBG_io2, "%s: acceleration distance=%d\n", __FUNCTION__, dist); + DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); /* get sure when don't insane value : XXX STEF XXX in this case we should * fall back to single table move */ @@ -1046,7 +1046,7 @@ gl843_init_motor_regs_scan (Genesys_Device * dev, feedl = 1; sanei_genesys_set_triple(reg,REG_FEEDL,feedl); - DBG (DBG_io, "%s: feedl=%d\n", __FUNCTION__, feedl); + DBG (DBG_io, "%s: feedl=%d\n", __func__, feedl); /* doesn't seem to matter that much */ sanei_genesys_calculate_zmode2 (use_fast_fed, @@ -1179,13 +1179,13 @@ gl843_init_optical_regs_scan (Genesys_Device * dev, { tgtime=2; } - DBG (DBG_io2, "%s: tgtime=%d\n", __FUNCTION__, tgtime); + DBG (DBG_io2, "%s: tgtime=%d\n", __func__, tgtime); /* to manage high resolution device while keeping good * low resolution scanning speed, we make hardware dpi vary */ dpihw=sanei_genesys_compute_dpihw(dev, used_res); factor=dev->sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __FUNCTION__, dpihw, factor); + DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); /* sensor parameters */ gl843_setup_sensor (dev, reg, dpihw, flags); @@ -1193,7 +1193,7 @@ gl843_init_optical_regs_scan (Genesys_Device * dev, /* resolution is divided according to CKSEL which is known once sensor is set up */ r = sanei_genesys_get_address (reg, REG18); cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __FUNCTION__, cksel); + DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); dpiset = used_res * cksel; /* start and end coordinate in optical dpi coordinates */ @@ -1218,7 +1218,7 @@ gl843_init_optical_regs_scan (Genesys_Device * dev, status = gl843_set_fe (dev, AFE_SET); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to set frontend: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1329,12 +1329,12 @@ gl843_init_optical_regs_scan (Genesys_Device * dev, if(half_ccd) { sanei_genesys_set_double(reg,REG_DPISET,dpiset*4); - DBG (DBG_io2, "%s: dpiset used=%d\n", __FUNCTION__, dpiset*4); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset*4); } else { sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __FUNCTION__, dpiset); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); } sanei_genesys_set_double(reg,REG_STRPIXEL,startx/tgtime); @@ -1355,22 +1355,22 @@ gl843_init_optical_regs_scan (Genesys_Device * dev, dev->wpl = words_per_line; dev->bpl = words_per_line; - DBG (DBG_io2, "%s: used_pixels=%d\n", __FUNCTION__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __FUNCTION__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __FUNCTION__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __FUNCTION__, (unsigned long) dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __FUNCTION__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __FUNCTION__, (unsigned long)dev->dist); + DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); + DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); + DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); + DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long) dev->bpl); + DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); + DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); words_per_line *= channels; /* MAXWD is expressed in 2 words unit */ /* nousedspace = (mem_bank_range * 1024 / 256 -1 ) * 4; */ sanei_genesys_set_triple(reg,REG_MAXWD,(words_per_line)>>1); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __FUNCTION__, words_per_line); + DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); sanei_genesys_set_double(reg,REG_LPERIOD,exposure/tgtime); - DBG (DBG_io2, "%s: exposure used=%d\n", __FUNCTION__, exposure/tgtime); + DBG (DBG_io2, "%s: exposure used=%d\n", __func__, exposure/tgtime); r = sanei_genesys_get_address (reg, REG_DUMMY); r->value = dev->sensor.dummy_pixel * tgtime; @@ -1456,7 +1456,7 @@ gl843_init_scan_regs (Genesys_Device * dev, { stagger = (4 * yres) / dev->motor.base_ydpi; } - DBG (DBG_info, "%s : stagger=%d lines\n", __FUNCTION__, stagger); + DBG (DBG_info, "%s : stagger=%d lines\n", __func__, stagger); /* we enable true gray for cis scanners only, and just when doing * scan since color calibration is OK for this mode @@ -1498,7 +1498,7 @@ gl843_init_scan_regs (Genesys_Device * dev, /* compute correct pixels number */ used_pixels = (pixels * optical_res) / xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __FUNCTION__, used_pixels); + DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); /* round up pixels number if needed */ if (used_pixels * xres < pixels * optical_res) @@ -1531,8 +1531,8 @@ gl843_init_scan_regs (Genesys_Device * dev, scan_step_type = sanei_genesys_compute_step_type(gl843_motors, dev->model->motor_type, exposure); } - DBG (DBG_info, "%s : exposure=%d pixels\n", __FUNCTION__, exposure); - DBG (DBG_info, "%s : scan_step_type=%d\n", __FUNCTION__, scan_step_type); + DBG (DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); + DBG (DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); /*** optical parameters ***/ /* in case of dynamic lineart, we use an internal 8 bit gray scan @@ -1652,7 +1652,7 @@ gl843_init_scan_regs (Genesys_Device * dev, dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __FUNCTION__, dev->current_setup.pixels); + DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); dev->current_setup.lines = lincnt; dev->current_setup.depth = depth; dev->current_setup.channels = channels; @@ -1777,7 +1777,7 @@ gl843_calculate_current_setup (Genesys_Device * dev) stagger = (4 * yres) / dev->motor.base_ydpi; else stagger = 0; - DBG (DBG_info, "%s: stagger=%d lines\n", __FUNCTION__, stagger); + DBG (DBG_info, "%s: stagger=%d lines\n", __func__, stagger); if(xres<=optical_res) used_res = xres; @@ -1790,11 +1790,11 @@ gl843_calculate_current_setup (Genesys_Device * dev) /* compute correct pixels number */ used_pixels = (pixels * optical_res) / xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __FUNCTION__, used_pixels); + DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); /* exposure */ exposure = gl843_compute_exposure (dev, used_res, oflags); - DBG (DBG_info, "%s : exposure=%d pixels\n", __FUNCTION__, exposure); + DBG (DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); /* it seems base_dpi of the G4050 motor is changed above 600 dpi*/ if (dev->model->motor_type == MOTOR_G4050 && yres>600) @@ -1817,7 +1817,7 @@ gl843_calculate_current_setup (Genesys_Device * dev) lincnt = lines + max_shift + stagger; dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __FUNCTION__, dev->current_setup.pixels); + DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); dev->current_setup.lines = lincnt; dev->current_setup.depth = depth; dev->current_setup.channels = channels; @@ -1944,7 +1944,7 @@ gl843_stop_action (Genesys_Device * dev) uint8_t val40, val; unsigned int loop; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); status = sanei_genesys_get_status (dev, &val); if (DBG_LEVEL >= DBG_io) @@ -1957,17 +1957,17 @@ gl843_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); - DBG (DBG_proc, "%s: completed\n", __FUNCTION__); + DBG (DBG_proc, "%s: completed\n", __func__); return status; } /* only stop action if needed */ if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) { - DBG (DBG_info, "%s: already stopped\n", __FUNCTION__); - DBG (DBG_proc, "%s: completed\n", __FUNCTION__); + DBG (DBG_info, "%s: already stopped\n", __func__); + DBG (DBG_proc, "%s: completed\n", __func__); return SANE_STATUS_GOOD; } @@ -1978,7 +1978,7 @@ gl843_stop_action (Genesys_Device * dev) status = sanei_genesys_write_register (dev, REG01, val); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to write register 01: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1997,7 +1997,7 @@ gl843_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -2042,7 +2042,7 @@ gl843_get_paper_sensor (Genesys_Device * dev, SANE_Bool * paper_loaded) static SANE_Status gl843_eject_document (Genesys_Device * dev) { - DBG (DBG_proc, "%s: not implemented \n", __FUNCTION__); + DBG (DBG_proc, "%s: not implemented \n", __func__); if (dev == NULL) return SANE_STATUS_INVAL; return SANE_STATUS_GOOD; @@ -2052,7 +2052,7 @@ gl843_eject_document (Genesys_Device * dev) static SANE_Status gl843_load_document (Genesys_Device * dev) { - DBG (DBG_proc, "%s: not implemented \n", __FUNCTION__); + DBG (DBG_proc, "%s: not implemented \n", __func__); if (dev == NULL) return SANE_STATUS_INVAL; return SANE_STATUS_GOOD; @@ -2071,14 +2071,14 @@ gl843_detect_document_end (Genesys_Device * dev) unsigned int scancnt = 0; int flines, channels, depth, bytes_remain, sublines, bytes_to_flush, lines, sub_bytes, tmp, read_bytes_left; - DBG (DBG_proc, "%s: begin\n", __FUNCTION__); + DBG (DBG_proc, "%s: begin\n", __func__); RIE (gl843_get_paper_sensor (dev, &paper_loaded)); /* sheetfed scanner uses home sensor as paper present */ if ((dev->document == SANE_TRUE) && !paper_loaded) { - DBG (DBG_info, "%s: no more document\n", __FUNCTION__); + DBG (DBG_info, "%s: no more document\n", __func__); dev->document = SANE_FALSE; channels = dev->current_setup.channels; @@ -2193,7 +2193,7 @@ gl843_detect_document_end (Genesys_Device * dev) } } - DBG (DBG_proc, "%s: finished\n", __FUNCTION__); + DBG (DBG_proc, "%s: finished\n", __func__); return SANE_STATUS_GOOD; } @@ -2483,7 +2483,7 @@ static SANE_Status gl843_park_xpa_lamp (Genesys_Device * dev) status = gl843_start_action (dev); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to start motor: %s\n",__FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to start motor: %s\n",__func__, sane_strstatus (status)); gl843_stop_action (dev); /* restore original registers */ dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL843_MAX_REGS); @@ -2496,7 +2496,7 @@ static SANE_Status gl843_park_xpa_lamp (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n",__FUNCTION__, + "%s: failed to read home sensor: %s\n",__func__, sane_strstatus (status)); return status; } @@ -2507,8 +2507,8 @@ static SANE_Status gl843_park_xpa_lamp (Genesys_Device * dev) if (val & REG41_HOMESNR) /* home sensor */ { - DBG (DBG_info, "%s: reached home position\n",__FUNCTION__); - DBG (DBG_proc, "%s: finished\n",__FUNCTION__); + DBG (DBG_info, "%s: reached home position\n",__func__); + DBG (DBG_proc, "%s: finished\n",__func__); /* clear GPOADF to avoid reparking again */ sanei_genesys_read_register (dev, REG6B, &val); @@ -2524,7 +2524,7 @@ static SANE_Status gl843_park_xpa_lamp (Genesys_Device * dev) } /* we are not parked here.... should we fail ? */ - DBG (DBG_info, "%s: XPA lamp is not parked\n", __FUNCTION__); + DBG (DBG_info, "%s: XPA lamp is not parked\n", __func__); DBGCOMPLETED; return SANE_STATUS_GOOD; } @@ -2564,7 +2564,7 @@ gl843_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) status = sanei_genesys_get_status (dev, &val); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to read home sensor: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); return status; } usleep (100000); /* sleep 100 ms */ @@ -2674,7 +2674,7 @@ gl843_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) return SANE_STATUS_IO_ERROR; } - DBG (DBG_info, "%s: scanhead is still moving\n", __FUNCTION__); + DBG (DBG_info, "%s: scanhead is still moving\n", __func__); DBGCOMPLETED; return SANE_STATUS_GOOD; } @@ -2926,7 +2926,7 @@ gl843_feed (Genesys_Device * dev, unsigned int steps) status = gl843_start_action (dev); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to start motor: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); gl843_stop_action (dev); /* restore original registers */ @@ -3000,7 +3000,7 @@ gl843_init_regs_for_shading (Genesys_Device * dev) dev->scanhead_position_in_steps += dev->calib_lines + move; sanei_genesys_get_double(dev->calib_reg,REG_STRPIXEL,&strpixel); - DBG (DBG_info, "%s: STRPIXEL=%d\n", __FUNCTION__, strpixel); + DBG (DBG_info, "%s: STRPIXEL=%d\n", __func__, strpixel); status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS); if (status != SANE_STATUS_GOOD) @@ -3380,9 +3380,9 @@ dark_average_channel (uint8_t * data, unsigned int pixels, unsigned int lines, } if (count) avg[k] /= count; - DBG (DBG_info, "%s: avg[%d] = %d\n", __FUNCTION__, k, avg[k]); + DBG (DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); } - DBG (DBG_info, "%s: average = %d\n", __FUNCTION__, avg[channel]); + DBG (DBG_info, "%s: average = %d\n", __func__, avg[channel]); return avg[channel]; } @@ -3786,7 +3786,7 @@ gl843_init_regs_for_warmup (Genesys_Device * dev, if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -3875,7 +3875,7 @@ gl843_boot (Genesys_Device * dev, SANE_Bool cold) { RIE (sanei_genesys_read_register (dev, 0x00, &val)); DBG (DBG_info, - "%s: reported version for genesys chip is 0x%02x\n", __FUNCTION__, + "%s: reported version for genesys chip is 0x%02x\n", __func__, val); } @@ -3998,7 +3998,7 @@ SANE_Status gl843_move_to_ta (Genesys_Device * dev) status = gl843_feed (dev, feed); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to move to XPA calibration area\n", __FUNCTION__); + DBG (DBG_error, "%s: failed to move to XPA calibration area\n", __func__); return status; } @@ -4357,16 +4357,16 @@ gl843_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) /* 16 bit words, 2 words per color, 3 color channels */ offset=(strpixel-startx)*2*2*3; length=(endpixel-strpixel)*2*2*3; - DBG (DBG_info, "%s: STRPIXEL=%d, ENDPIXEL=%d, startx=%d\n", __FUNCTION__, strpixel, endpixel, startx); + DBG (DBG_info, "%s: STRPIXEL=%d, ENDPIXEL=%d, startx=%d\n", __func__, strpixel, endpixel, startx); } /* compute and allocate size for final data */ final_size = ((length+251) / 252) * 256; - DBG (DBG_io, "%s: final shading size=%04x (length=%d)\n", __FUNCTION__, final_size, length); + DBG (DBG_io, "%s: final shading size=%04x (length=%d)\n", __func__, final_size, length); final_data = (uint8_t *) malloc (final_size); if(final_data==NULL) { - DBG (DBG_error, "%s: failed to allocate memory for shading data\n", __FUNCTION__); + DBG (DBG_error, "%s: failed to allocate memory for shading data\n", __func__); return SANE_STATUS_NO_MEM; } memset(final_data,0x00,final_size); @@ -4390,7 +4390,7 @@ gl843_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) status = sanei_genesys_set_buffer_address (dev, 0); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to set buffer address: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus (status)); free(final_data); return status; } @@ -4398,7 +4398,7 @@ gl843_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, final_data, count); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to send shading table: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to send shading table: %s\n", __func__, sane_strstatus (status)); } free(final_data); @@ -4446,6 +4446,7 @@ static Genesys_Command_Set gl843_cmd_set = { gl843_led_calibration, gl843_slow_back_home, + NULL, sanei_genesys_bulk_write_register, gl843_bulk_write_data, diff --git a/backend/genesys_gl843.h b/backend/genesys_gl843.h index f31f0ee..4be46cc 100644 --- a/backend/genesys_gl843.h +++ b/backend/genesys_gl843.h @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2010-2013 Stéphane Voltz This file is part of the SANE package. @@ -73,8 +73,8 @@ SANE_Status gl843_xpa_motor_off (Genesys_Device * dev); SANE_Status gl843_move_to_ta (Genesys_Device * dev); #endif -#define DBGSTART DBG (DBG_proc, "%s start\n", __FUNCTION__); -#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __FUNCTION__); +#define DBGSTART DBG (DBG_proc, "%s start\n", __func__); +#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __func__); #define REG01 0x01 #define REG01_CISSET 0x80 diff --git a/backend/genesys_gl846.c b/backend/genesys_gl846.c index 3991693..0716c17 100644 --- a/backend/genesys_gl846.c +++ b/backend/genesys_gl846.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2012-2013 Stéphane Voltz + Copyright (C) 2012-2013 Stéphane Voltz This file is part of the SANE package. @@ -117,7 +117,7 @@ gl846_bulk_read_data (Genesys_Device * dev, uint8_t addr, if (status != SANE_STATUS_GOOD) { DBG (DBG_error, "%s failed while writing command: %s\n", - __FUNCTION__, sane_strstatus (status)); + __func__, sane_strstatus (status)); return status; } @@ -162,7 +162,7 @@ gl846_bulk_read_data (Genesys_Device * dev, uint8_t addr, DBG (DBG_io2, "gl846_bulk_read_data: %lu bytes of data read\n", (u_long) done); } - DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __FUNCTION__, + DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __func__, (u_long) size, (u_long) (target - size)); target -= size; @@ -269,7 +269,7 @@ gl846_get_step_multiplier (Genesys_Register_Set * regs) value = (r->value & 0x0f)>>1; value = 1 << value; } - DBG (DBG_io, "%s: step multiplier is %d\n", __FUNCTION__, value); + DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); return value; } @@ -317,7 +317,7 @@ static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi) /* default fallback */ if(idx<0) { - DBG (DBG_warn,"%s: using default sensor profile\n",__FUNCTION__); + DBG (DBG_warn,"%s: using default sensor profile\n",__func__); idx=0; } @@ -577,13 +577,13 @@ gl846_send_slope_table (Genesys_Device * dev, int table_nr, int i; char msg[10000]; - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __FUNCTION__, + DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, table_nr, steps); /* sanity check */ if(table_nr<0 || table_nr>4) { - DBG (DBG_error, "%s: invalid table number %d!\n", __FUNCTION__, table_nr); + DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); return SANE_STATUS_INVAL; } @@ -601,7 +601,7 @@ gl846_send_slope_table (Genesys_Device * dev, int table_nr, { sprintf (msg+strlen(msg), "%d", slope_table[i]); } - DBG (DBG_io, "%s: %s\n", __FUNCTION__, msg); + DBG (DBG_io, "%s: %s\n", __func__, msg); } /* slope table addresses are fixed */ @@ -610,7 +610,7 @@ gl846_send_slope_table (Genesys_Device * dev, int table_nr, { DBG (DBG_error, "%s: write to AHB failed writing slope table %d (%s)\n", - __FUNCTION__, table_nr, sane_strstatus (status)); + __func__, table_nr, sane_strstatus (status)); } free (table); @@ -641,7 +641,7 @@ gl846_set_adi_fe (Genesys_Device * dev, uint8_t set) if (set == AFE_INIT) { - DBG (DBG_proc, "%s(): setting DAC %u\n", __FUNCTION__, dev->model->dac_type); + DBG (DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); /* sets to default values */ sanei_genesys_init_fe (dev); @@ -652,7 +652,7 @@ gl846_set_adi_fe (Genesys_Device * dev, uint8_t set) status = sanei_genesys_fe_write_data (dev, 0x00, val); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus (status)); return status; } @@ -660,7 +660,7 @@ gl846_set_adi_fe (Genesys_Device * dev, uint8_t set) status = sanei_genesys_fe_write_data (dev, 0x01, val); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to write reg1: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to write reg1: %s\n", __func__, sane_strstatus (status)); return status; } @@ -672,7 +672,7 @@ gl846_set_adi_fe (Genesys_Device * dev, uint8_t set) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to write gain %d: %s\n", __FUNCTION__, i, + "%s: failed to write gain %d: %s\n", __func__, i, sane_strstatus (status)); return status; } @@ -684,7 +684,7 @@ gl846_set_adi_fe (Genesys_Device * dev, uint8_t set) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to write offset %d: %s\n", __FUNCTION__, i, + "%s: failed to write offset %d: %s\n", __func__, i, sane_strstatus (status)); return status; } @@ -781,10 +781,10 @@ gl846_init_motor_regs_scan (Genesys_Device * dev, { use_fast_fed=1; } - DBG (DBG_io, "%s: use_fast_fed=%d\n", __FUNCTION__, use_fast_fed); + DBG (DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); sanei_genesys_set_triple(reg, REG_LINCNT, scan_lines); - DBG (DBG_io, "%s: lincnt=%d\n", __FUNCTION__, scan_lines); + DBG (DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); /* compute register 02 value */ r = sanei_genesys_get_address (reg, REG02); @@ -863,8 +863,8 @@ gl846_init_motor_regs_scan (Genesys_Device * dev, if (flags & MOTOR_FLAG_FEED) dist *=2; } - DBG (DBG_io2, "%s: scan steps=%d\n", __FUNCTION__, scan_steps); - DBG (DBG_io2, "%s: acceleration distance=%d\n", __FUNCTION__, dist); + DBG (DBG_io2, "%s: scan steps=%d\n", __func__, scan_steps); + DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); /* check for overflow */ if(distvalue & REG0C_CCDLMT)+1; @@ -1024,13 +1024,13 @@ gl846_init_optical_regs_scan (Genesys_Device * dev, /* resolution is divided according to CKSEL */ r = sanei_genesys_get_address (reg, REG18); cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __FUNCTION__, cksel); + DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); /* to manage high resolution device while keeping good * low resolution scanning speed, we make hardware dpi vary */ dpihw=sanei_genesys_compute_dpihw(dev, used_res * cksel); factor=dev->sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __FUNCTION__, dpihw, factor); + DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); /* sensor parameters */ sensor=get_sensor_profile(dev->model->ccd_type, dpihw); @@ -1215,20 +1215,20 @@ gl846_init_optical_regs_scan (Genesys_Device * dev, dev->line_interp = 0; sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __FUNCTION__, dpiset); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); sanei_genesys_set_double(reg,REG_STRPIXEL,startx); sanei_genesys_set_double(reg,REG_ENDPIXEL,endx); - DBG (DBG_io2, "%s: startx=%d\n", __FUNCTION__, startx); - DBG (DBG_io2, "%s: endx =%d\n", __FUNCTION__, endx); + DBG (DBG_io2, "%s: startx=%d\n", __func__, startx); + DBG (DBG_io2, "%s: endx =%d\n", __func__, endx); - DBG (DBG_io2, "%s: used_pixels=%d\n", __FUNCTION__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __FUNCTION__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __FUNCTION__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __FUNCTION__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __FUNCTION__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __FUNCTION__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->segnb =%lu\n", __FUNCTION__, (unsigned long)dev->segnb); + DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); + DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); + DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); + DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); + DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); + DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); + DBG (DBG_io2, "%s: dev->segnb =%lu\n", __func__, (unsigned long)dev->segnb); words_per_line *= channels; dev->wpl = words_per_line; @@ -1241,10 +1241,10 @@ gl846_init_optical_regs_scan (Genesys_Device * dev, /* MAXWD is expressed in 4 words unit */ sanei_genesys_set_triple(reg, REG_MAXWD, (words_per_line >> 2)); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __FUNCTION__, words_per_line); + DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); - DBG (DBG_io2, "%s: exposure_time used=%d\n", __FUNCTION__, exposure_time); + DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); r = sanei_genesys_get_address (reg, 0x34); r->value = dev->sensor.dummy_pixel; @@ -1645,7 +1645,7 @@ gl846_calculate_current_setup (Genesys_Device * dev) slope_dpi = slope_dpi * (1 + dummy); exposure_time = gl846_compute_exposure (dev, used_res); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __FUNCTION__, exposure_time); + DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); /* max_shift */ max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); @@ -1761,7 +1761,7 @@ gl846_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -1770,7 +1770,7 @@ gl846_stop_action (Genesys_Device * dev) /* only stop action if needed */ if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) { - DBG (DBG_info, "%s: already stopped\n", __FUNCTION__); + DBG (DBG_info, "%s: already stopped\n", __func__); DBGCOMPLETED; return SANE_STATUS_GOOD; } @@ -1783,7 +1783,7 @@ gl846_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to write register 01: %s\n", __FUNCTION__, + "%s: failed to write register 01: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1801,7 +1801,7 @@ gl846_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -1962,7 +1962,7 @@ gl846_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) /* is sensor at home? */ if (val & HOMESNR) { - DBG (DBG_info, "%s: already at home, completed\n", __FUNCTION__); + DBG (DBG_info, "%s: already at home, completed\n", __func__); dev->scanhead_position_in_steps = 0; DBGCOMPLETED; return SANE_STATUS_GOOD; @@ -2257,7 +2257,7 @@ gl846_feed (Genesys_Device * dev, unsigned int steps) uint8_t val; DBGSTART; - DBG (DBG_io, "%s: steps=%d\n", __FUNCTION__, steps); + DBG (DBG_io, "%s: steps=%d\n", __func__, steps); /* prepare local registers */ memcpy (local_reg, dev->reg, GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); @@ -2306,7 +2306,7 @@ gl846_feed (Genesys_Device * dev, unsigned int steps) status = gl846_start_action (dev); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to start motor: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); gl846_stop_action (dev); /* restore original registers */ @@ -2348,8 +2348,8 @@ gl846_init_regs_for_shading (Genesys_Device * dev) if(dev->calib_resolution==4800) dev->calib_lines *= 2; dev->calib_pixels = (dev->sensor.sensor_pixels*dev->calib_resolution)/dev->sensor.optical_res; - DBG (DBG_io, "%s: calib_lines = %d\n", __FUNCTION__, (unsigned int)dev->calib_lines); - DBG (DBG_io, "%s: calib_pixels = %d\n", __FUNCTION__, (unsigned int)dev->calib_pixels); + DBG (DBG_io, "%s: calib_lines = %d\n", __func__, (unsigned int)dev->calib_lines); + DBG (DBG_io, "%s: calib_pixels = %d\n", __func__, (unsigned int)dev->calib_pixels); /* this is aworkaround insufficent distance for slope * motor acceleration TODO special motor slope for shading */ @@ -2377,14 +2377,14 @@ gl846_init_regs_for_shading (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL846_MAX_REGS); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2452,7 +2452,7 @@ gl846_init_regs_for_scan (Genesys_Device * dev) move += dev->settings.tl_y; move = (move * move_dpi) / MM_PER_INCH; move -= dev->scanhead_position_in_steps; - DBG (DBG_info, "%s: move=%f steps\n",__FUNCTION__, move); + DBG (DBG_info, "%s: move=%f steps\n",__func__, move); /* fast move to scan area */ /* we don't move fast the whole distance since it would involve @@ -2464,14 +2464,14 @@ gl846_init_regs_for_scan (Genesys_Device * dev) status = gl846_feed (dev, move-500); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to move to scan area\n",__FUNCTION__); + DBG (DBG_error, "%s: failed to move to scan area\n",__func__); return status; } move=500; } DBG (DBG_info, "gl846_init_regs_for_scan: move=%f steps\n", move); - DBG (DBG_info, "%s: move=%f steps\n", __FUNCTION__, move); + DBG (DBG_info, "%s: move=%f steps\n", __func__, move); /* start */ start = SANE_UNFIX (dev->model->x_offset); @@ -2526,7 +2526,7 @@ gl846_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) uint8_t val,*buffer,*ptr,*src; DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__FUNCTION__,size); + DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); /* shading data is plit in 3 (up to 5 with IR) areas write(0x10014000,0x00000dd8) @@ -2543,10 +2543,10 @@ gl846_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) /* compute deletion factor */ sanei_genesys_get_double(dev->reg,REG_DPISET,&tempo); dpiset=tempo; - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n",__FUNCTION__,strpixel,endpixel,endpixel-strpixel,dpiset); + DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n",__func__,strpixel,endpixel,endpixel-strpixel,dpiset); dpihw=sanei_genesys_compute_dpihw(dev,dpiset); factor=dpihw/dpiset; - DBG( DBG_io2, "%s: factor=%d\n",__FUNCTION__,factor); + DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); if(DBG_LEVEL>=DBG_data) { @@ -2571,7 +2571,7 @@ gl846_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) /* allocate temporary buffer */ buffer=(uint8_t *)malloc(pixels); memset(buffer,0,pixels); - DBG( DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n",__FUNCTION__,pixels,pixels); + DBG( DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n",__func__,pixels,pixels); /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address * is 8192*reg value */ @@ -2649,7 +2649,7 @@ gl846_led_calibration (Genesys_Device * dev) { RIE(gl846_feed (dev, move)); } - DBG (DBG_io, "%s: move=%f steps\n", __FUNCTION__, move); + DBG (DBG_io, "%s: move=%f steps\n", __func__, move); /* offset calibration is always done in color mode */ channels = 3; @@ -2679,7 +2679,7 @@ gl846_led_calibration (Genesys_Device * dev) SCAN_FLAG_IGNORE_LINE_DISTANCE); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2816,7 +2816,7 @@ gl846_init_gpio (Genesys_Device * dev) } if(gpios[idx].sensor_id==0) { - DBG (DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __FUNCTION__, dev->model->ccd_type); + DBG (DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __func__, dev->model->ccd_type); return SANE_STATUS_INVAL; } @@ -2857,7 +2857,7 @@ gl846_init_memory_layout (Genesys_Device * dev) } if(layouts[idx].model==NULL) { - DBG(DBG_error, "%s: failed to find memory layout for model %s!\n", __FUNCTION__, dev->model->name); + DBG(DBG_error, "%s: failed to find memory layout for model %s!\n", __func__, dev->model->name); return SANE_STATUS_INVAL; } @@ -2915,7 +2915,7 @@ gl846_boot (Genesys_Device * dev, SANE_Bool cold) if (val & REG40_CHKVER) { RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG (DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __FUNCTION__, val); + DBG (DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); } /* Set default values for registers */ @@ -3680,6 +3680,7 @@ static Genesys_Command_Set gl846_cmd_set = { gl846_led_calibration, gl846_slow_back_home, + NULL, sanei_genesys_bulk_write_register, NULL, diff --git a/backend/genesys_gl846.h b/backend/genesys_gl846.h index d57f149..e1dc711 100644 --- a/backend/genesys_gl846.h +++ b/backend/genesys_gl846.h @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2012-2013 Stéphane Voltz + Copyright (C) 2012-2013 Stéphane Voltz This file is part of the SANE package. diff --git a/backend/genesys_gl847.c b/backend/genesys_gl847.c index 7c4d19c..a3b35a2 100644 --- a/backend/genesys_gl847.c +++ b/backend/genesys_gl847.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2010-2013 Stéphane Voltz This file is part of the SANE package. @@ -113,7 +113,7 @@ gl847_bulk_read_data (Genesys_Device * dev, uint8_t addr, if (status != SANE_STATUS_GOOD) { DBG (DBG_error, "%s failed while writing command: %s\n", - __FUNCTION__, sane_strstatus (status)); + __func__, sane_strstatus (status)); return status; } @@ -158,7 +158,7 @@ gl847_bulk_read_data (Genesys_Device * dev, uint8_t addr, DBG (DBG_io2, "gl847_bulk_read_data: %lu bytes of data read\n", (u_long) done); } - DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __FUNCTION__, + DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __func__, (u_long) size, (u_long) (target - size)); target -= size; @@ -265,7 +265,7 @@ gl847_get_step_multiplier (Genesys_Register_Set * regs) value = (r->value & 0x0f)>>1; value = 1 << value; } - DBG (DBG_io, "%s: step multiplier is %d\n", __FUNCTION__, value); + DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); return value; } @@ -313,7 +313,7 @@ static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi) /* default fallback */ if(idx<0) { - DBG (DBG_warn,"%s: using default sensor profile\n",__FUNCTION__); + DBG (DBG_warn,"%s: using default sensor profile\n",__func__); idx=0; } @@ -600,13 +600,13 @@ gl847_send_slope_table (Genesys_Device * dev, int table_nr, int i; char msg[10000]; - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __FUNCTION__, + DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, table_nr, steps); /* sanity check */ if(table_nr<0 || table_nr>4) { - DBG (DBG_error, "%s: invalid table number %d!\n", __FUNCTION__, table_nr); + DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); return SANE_STATUS_INVAL; } @@ -624,7 +624,7 @@ gl847_send_slope_table (Genesys_Device * dev, int table_nr, { sprintf (msg+strlen(msg), "%d", slope_table[i]); } - DBG (DBG_io, "%s: %s\n", __FUNCTION__, msg); + DBG (DBG_io, "%s: %s\n", __func__, msg); } /* slope table addresses are fixed */ @@ -634,7 +634,7 @@ gl847_send_slope_table (Genesys_Device * dev, int table_nr, { DBG (DBG_error, "%s: write to AHB failed writing slope table %d (%s)\n", - __FUNCTION__, table_nr, sane_strstatus (status)); + __func__, table_nr, sane_strstatus (status)); } free (table); @@ -824,10 +824,10 @@ gl847_init_motor_regs_scan (Genesys_Device * dev, { use_fast_fed=1; } - DBG (DBG_io, "%s: use_fast_fed=%d\n", __FUNCTION__, use_fast_fed); + DBG (DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); sanei_genesys_set_triple(reg, REG_LINCNT, scan_lines); - DBG (DBG_io, "%s: lincnt=%d\n", __FUNCTION__, scan_lines); + DBG (DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); /* compute register 02 value */ r = sanei_genesys_get_address (reg, REG02); @@ -906,8 +906,8 @@ gl847_init_motor_regs_scan (Genesys_Device * dev, if (flags & MOTOR_FLAG_FEED) dist *=2; } - DBG (DBG_io2, "%s: scan steps=%d\n", __FUNCTION__, scan_steps); - DBG (DBG_io2, "%s: acceleration distance=%d\n", __FUNCTION__, dist); + DBG (DBG_io2, "%s: scan steps=%d\n", __func__, scan_steps); + DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); /* check for overflow */ if(distvalue & REG0C_CCDLMT)+1; @@ -1048,13 +1048,13 @@ gl847_init_optical_regs_scan (Genesys_Device * dev, /* resolution is divided according to CKSEL */ r = sanei_genesys_get_address (reg, REG18); cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __FUNCTION__, cksel); + DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); /* to manage high resolution device while keeping good * low resolution scanning speed, we make hardware dpi vary */ dpihw=sanei_genesys_compute_dpihw(dev, used_res * cksel); factor=dev->sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __FUNCTION__, dpihw, factor); + DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); /* sensor parameters */ sensor=get_sensor_profile(dev->model->ccd_type, dpihw); @@ -1239,20 +1239,20 @@ gl847_init_optical_regs_scan (Genesys_Device * dev, dev->line_interp = 0; sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __FUNCTION__, dpiset); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); sanei_genesys_set_double(reg,REG_STRPIXEL,startx); sanei_genesys_set_double(reg,REG_ENDPIXEL,endx); - DBG (DBG_io2, "%s: startx=%d\n", __FUNCTION__, startx); - DBG (DBG_io2, "%s: endx =%d\n", __FUNCTION__, endx); + DBG (DBG_io2, "%s: startx=%d\n", __func__, startx); + DBG (DBG_io2, "%s: endx =%d\n", __func__, endx); - DBG (DBG_io2, "%s: used_pixels=%d\n", __FUNCTION__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __FUNCTION__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __FUNCTION__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __FUNCTION__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __FUNCTION__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __FUNCTION__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->segnb =%lu\n", __FUNCTION__, (unsigned long)dev->segnb); + DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); + DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); + DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); + DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); + DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); + DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); + DBG (DBG_io2, "%s: dev->segnb =%lu\n", __func__, (unsigned long)dev->segnb); words_per_line *= channels; dev->wpl = words_per_line; @@ -1265,10 +1265,10 @@ gl847_init_optical_regs_scan (Genesys_Device * dev, /* MAXWD is expressed in 4 words unit */ sanei_genesys_set_triple(reg, REG_MAXWD, (words_per_line >> 2)); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __FUNCTION__, words_per_line); + DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); - DBG (DBG_io2, "%s: exposure_time used=%d\n", __FUNCTION__, exposure_time); + DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); r = sanei_genesys_get_address (reg, 0x34); r->value = dev->sensor.dummy_pixel; @@ -1669,7 +1669,7 @@ gl847_calculate_current_setup (Genesys_Device * dev) slope_dpi = slope_dpi * (1 + dummy); exposure_time = gl847_compute_exposure (dev, used_res); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __FUNCTION__, exposure_time); + DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); /* max_shift */ max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); @@ -1785,7 +1785,7 @@ gl847_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -1794,7 +1794,7 @@ gl847_stop_action (Genesys_Device * dev) /* only stop action if needed */ if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) { - DBG (DBG_info, "%s: already stopped\n", __FUNCTION__); + DBG (DBG_info, "%s: already stopped\n", __func__); DBGCOMPLETED; return SANE_STATUS_GOOD; } @@ -1807,7 +1807,7 @@ gl847_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to write register 01: %s\n", __FUNCTION__, + "%s: failed to write register 01: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1825,7 +1825,7 @@ gl847_stop_action (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); DBGCOMPLETED; return status; @@ -1929,10 +1929,50 @@ gl847_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, return status; } -/* Moves the slider to the home (top) postion slowly */ -#ifndef UNIT_TESTING -static -#endif +/** rewind scan + * Move back by the same amount of distance than previous scan. + * @param dev device to rewind + * @returns SANE_STATUS_GOOD on success + */ +GENESYS_STATIC +SANE_Status gl847_rewind(Genesys_Device * dev) +{ + SANE_Status status; + uint8_t byte; + + DBGSTART; + + /* set motor reverse */ + RIE (sanei_genesys_read_register (dev, 0x02, &byte)); + byte |= 0x04; + RIE (sanei_genesys_write_register(dev, 0x02, byte)); + + /* and start scan, then wait completion */ + RIE (gl847_begin_scan (dev, dev->reg, SANE_TRUE)); + do + { + usleep(100*1000); + RIE (sanei_genesys_read_register (dev, REG40, &byte)); + } + while(byte & REG40_MOTMFLG); + RIE (gl847_end_scan (dev, dev->reg, SANE_TRUE)); + + /* restore direction */ + RIE (sanei_genesys_read_register (dev, 0x02, &byte)); + byte &= 0xfb; + RIE (sanei_genesys_write_register(dev, 0x02, byte)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** Park head + * Moves the slider to the home (top) position slowly + * @param dev device to park + * @param wait_until_home true to make the function waiting for head + * to be home before returning, if fals returne immediately + * @returns SANE_STATUS_GOO on success */ +GENESYS_STATIC SANE_Status gl847_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) { @@ -1982,7 +2022,7 @@ gl847_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) /* is sensor at home? */ if (val & HOMESNR) { - DBG (DBG_info, "%s: already at home, completed\n", __FUNCTION__); + DBG (DBG_info, "%s: already at home, completed\n", __func__); dev->scanhead_position_in_steps = 0; DBGCOMPLETED; return SANE_STATUS_GOOD; @@ -2279,7 +2319,7 @@ gl847_feed (Genesys_Device * dev, unsigned int steps) uint8_t val; DBGSTART; - DBG (DBG_io, "%s: steps=%d\n", __FUNCTION__, steps); + DBG (DBG_io, "%s: steps=%d\n", __func__, steps); /* prepare local registers */ memcpy (local_reg, dev->reg, GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); @@ -2328,7 +2368,7 @@ gl847_feed (Genesys_Device * dev, unsigned int steps) status = gl847_start_action (dev); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to start motor: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); gl847_stop_action (dev); /* restore original registers */ @@ -2370,8 +2410,8 @@ gl847_init_regs_for_shading (Genesys_Device * dev) if(dev->calib_resolution==4800) dev->calib_lines *= 2; dev->calib_pixels = (dev->sensor.sensor_pixels*dev->calib_resolution)/dev->sensor.optical_res; - DBG (DBG_io, "%s: calib_lines = %d\n", __FUNCTION__, (int)dev->calib_lines); - DBG (DBG_io, "%s: calib_pixels = %d\n", __FUNCTION__, (int)dev->calib_pixels); + DBG (DBG_io, "%s: calib_lines = %d\n", __func__, (int)dev->calib_lines); + DBG (DBG_io, "%s: calib_pixels = %d\n", __func__, (int)dev->calib_pixels); /* this is aworkaround insufficent distance for slope * motor acceleration TODO special motor slope for shading */ @@ -2399,14 +2439,14 @@ gl847_init_regs_for_shading (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL847_MAX_REGS); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2474,7 +2514,7 @@ gl847_init_regs_for_scan (Genesys_Device * dev) move += dev->settings.tl_y; move = (move * move_dpi) / MM_PER_INCH; move -= dev->scanhead_position_in_steps; - DBG (DBG_info, "%s: move=%f steps\n",__FUNCTION__, move); + DBG (DBG_info, "%s: move=%f steps\n",__func__, move); /* fast move to scan area */ /* we don't move fast the whole distance since it would involve @@ -2486,14 +2526,14 @@ gl847_init_regs_for_scan (Genesys_Device * dev) status = gl847_feed (dev, move-500); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to move to scan area\n",__FUNCTION__); + DBG (DBG_error, "%s: failed to move to scan area\n",__func__); return status; } move=500; } DBG (DBG_info, "gl124_init_regs_for_scan: move=%f steps\n", move); - DBG (DBG_info, "%s: move=%f steps\n", __FUNCTION__, move); + DBG (DBG_info, "%s: move=%f steps\n", __func__, move); /* start */ start = SANE_UNFIX (dev->model->x_offset); @@ -2548,7 +2588,7 @@ gl847_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) uint8_t val,*buffer,*ptr,*src; DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__FUNCTION__,size); + DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); /* shading data is plit in 3 (up to 5 with IR) areas write(0x10014000,0x00000dd8) @@ -2565,10 +2605,10 @@ gl847_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) /* compute deletion factor */ sanei_genesys_get_double(dev->reg,REG_DPISET,&tempo); dpiset=tempo; - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n",__FUNCTION__,strpixel,endpixel,endpixel-strpixel,dpiset); + DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n",__func__,strpixel,endpixel,endpixel-strpixel,dpiset); dpihw=sanei_genesys_compute_dpihw(dev,dpiset); factor=dpihw/dpiset; - DBG( DBG_io2, "%s: factor=%d\n",__FUNCTION__,factor); + DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); if(DBG_LEVEL>=DBG_data) { @@ -2593,7 +2633,7 @@ gl847_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) /* allocate temporary buffer */ buffer=(uint8_t *)malloc(pixels); memset(buffer,0,pixels); - DBG( DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n",__FUNCTION__,pixels,pixels); + DBG( DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n",__func__,pixels,pixels); /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address * is 8192*reg value */ @@ -2670,7 +2710,7 @@ gl847_led_calibration (Genesys_Device * dev) { RIE(gl847_feed (dev, move)); } - DBG (DBG_io, "%s: move=%f steps\n", __FUNCTION__, move); + DBG (DBG_io, "%s: move=%f steps\n", __func__, move); /* offset calibration is always done in color mode */ channels = 3; @@ -2700,7 +2740,7 @@ gl847_led_calibration (Genesys_Device * dev) SCAN_FLAG_IGNORE_LINE_DISTANCE); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __FUNCTION__, sane_strstatus (status)); + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); return status; } @@ -2837,7 +2877,7 @@ gl847_init_gpio (Genesys_Device * dev) } if(gpios[idx].sensor_id==0) { - DBG (DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __FUNCTION__, dev->model->ccd_type); + DBG (DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __func__, dev->model->ccd_type); return SANE_STATUS_INVAL; } @@ -2972,7 +3012,7 @@ gl847_boot (Genesys_Device * dev, SANE_Bool cold) if (val & REG40_CHKVER) { RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG (DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __FUNCTION__, val); + DBG (DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); } /* Set default values for registers */ @@ -3753,6 +3793,7 @@ static Genesys_Command_Set gl847_cmd_set = { gl847_led_calibration, gl847_slow_back_home, + gl847_rewind, sanei_genesys_bulk_write_register, NULL, diff --git a/backend/genesys_gl847.h b/backend/genesys_gl847.h index 9901e23..1da2065 100644 --- a/backend/genesys_gl847.h +++ b/backend/genesys_gl847.h @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2010-2013 Stéphane Voltz This file is part of the SANE package. diff --git a/backend/genesys_low.c b/backend/genesys_low.c index f28b72c..4cbd75d 100644 --- a/backend/genesys_low.c +++ b/backend/genesys_low.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2010-2013 Stéphane Voltz + Copyright (C) 2010-2013 Stéphane Voltz This file is part of the SANE package. @@ -516,7 +516,7 @@ sanei_genesys_set_buffer_address (Genesys_Device * dev, uint32_t addr) return status; } -/** read data for analog frontend +/**@brief read data from analog frontend (AFE) * @param dev device owning the AFE * @param addr register address to read * @param data placeholder for the result @@ -558,7 +558,13 @@ sanei_genesys_fe_read_data (Genesys_Device * dev, uint8_t addr, return status; } -/* Write data for analog frontend */ +/*@brief write data to analog frontend + * writes data to analog frontend to set it up accordingly + * to the sensor settings (exposure, timings, color, bit depth, ...) + * @param dev devie owning the AFE to write to + * @param addr AFE rister address + * @param data value to write to AFE register + **/ SANE_Status sanei_genesys_fe_write_data (Genesys_Device * dev, uint8_t addr, uint16_t data) @@ -737,7 +743,7 @@ sanei_genesys_read_valid_words (Genesys_Device * dev, unsigned int *words) *words += ((value & 0x0f) * 256 * 256); } - DBG (DBG_proc, "%s: %d words\n", __FUNCTION__, *words); + DBG (DBG_proc, "%s: %d words\n", __func__, *words); DBGCOMPLETED; return SANE_STATUS_GOOD; } @@ -1098,7 +1104,7 @@ sanei_genesys_bulk_write_register (Genesys_Device * dev, } } - DBG (DBG_io, "%s: wrote %lu registers\n", __FUNCTION__, (u_long) elems); + DBG (DBG_io, "%s: wrote %lu registers\n", __func__, (u_long) elems); return status; } @@ -1136,8 +1142,8 @@ sanei_genesys_write_ahb (SANE_Int dn, int usb_mode, uint32_t addr, uint32_t size { sprintf (msg+strlen(msg), " 0x%02x", outdata[i]); } - DBG (DBG_io, "%s: write(0x%08x,0x%08x)\n", __FUNCTION__, addr,size); - DBG (DBG_io, "%s: %s\n", __FUNCTION__, msg); + DBG (DBG_io, "%s: write(0x%08x,0x%08x)\n", __func__, addr,size); + DBG (DBG_io, "%s: %s\n", __func__, msg); } /* no effective write if fake USB */ @@ -1315,7 +1321,7 @@ sanei_genesys_send_gamma_table (Genesys_Device * dev) { free (gamma); DBG (DBG_error, - "%s: write to AHB failed writing table %d (%s)\n", __FUNCTION__, + "%s: write to AHB failed writing table %d (%s)\n", __func__, i, sane_strstatus (status)); } } @@ -1352,12 +1358,12 @@ sanei_genesys_asic_init (Genesys_Device * dev, int max_regs) status = sanei_usb_control_msg (dev->dn, REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_GET_REGISTER, 0x00, 1, &val); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: request register failed %s\n", __FUNCTION__, + DBG (DBG_error, "%s: request register failed %s\n", __func__, sane_strstatus (status)); return status; } - DBG (DBG_io2, "%s: value=0x%02x\n", __FUNCTION__, val); - DBG (DBG_info, "%s: device is %s\n", __FUNCTION__, (val & 0x08) ? "USB 1.0" : "USB2.0"); + DBG (DBG_io2, "%s: value=0x%02x\n", __func__, val); + DBG (DBG_info, "%s: device is %s\n", __func__, (val & 0x08) ? "USB 1.0" : "USB2.0"); if (val & 0x08) { dev->usb_mode = 1; @@ -1377,7 +1383,7 @@ sanei_genesys_asic_init (Genesys_Device * dev, int max_regs) if (dev->sensor.gamma_table[i] == NULL) { DBG (DBG_error, "%s: could not allocate memory for gamma table %d\n", - __FUNCTION__, i); + __func__, i); return SANE_STATUS_NO_MEM; } sanei_genesys_create_gamma_table (dev->sensor.gamma_table[i], @@ -1397,13 +1403,13 @@ sanei_genesys_asic_init (Genesys_Device * dev, int max_regs) { cold = SANE_FALSE; } - DBG (DBG_info, "%s: device is %s\n", __FUNCTION__, cold ? "cold" : "warm"); + DBG (DBG_info, "%s: device is %s\n", __func__, cold ? "cold" : "warm"); /* don't do anything if backend is initialized and hardware hasn't been * replug */ if (dev->already_initialized && !cold) { - DBG (DBG_info, "%s: already initialized, nothing to do\n", __FUNCTION__); + DBG (DBG_info, "%s: already initialized, nothing to do\n", __func__); return SANE_STATUS_GOOD; } @@ -1459,7 +1465,7 @@ sanei_genesys_wait_for_home (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1468,7 +1474,7 @@ sanei_genesys_wait_for_home (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1477,7 +1483,7 @@ sanei_genesys_wait_for_home (Genesys_Device * dev) if(val & HOMESNR) { DBG (DBG_info, - "%s: already at home\n", __FUNCTION__); + "%s: already at home\n", __func__); return status; } @@ -1491,7 +1497,7 @@ sanei_genesys_wait_for_home (Genesys_Device * dev) if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __FUNCTION__, + "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); return status; } @@ -1506,7 +1512,7 @@ sanei_genesys_wait_for_home (Genesys_Device * dev) /* if after the timeout, head is still not parked, error out */ if(loop >= max && !(val & HOMESNR) && status == SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to reach park position %ds\n", __FUNCTION__, max/10); + DBG (DBG_error, "%s: failed to reach park position %ds\n", __func__, max/10); return SANE_STATUS_IO_ERROR; } @@ -1597,7 +1603,7 @@ Motor_Profile *sanei_genesys_get_motor_profile(Motor_Profile *motors, int motor_ /* default fallback */ if(idx<0) { - DBG (DBG_warn,"%s: using default motor profile\n",__FUNCTION__); + DBG (DBG_warn,"%s: using default motor profile\n",__func__); idx=0; } @@ -1654,7 +1660,7 @@ Motor_Profile *profile; /* required speed */ target=((exposure * dpi) / base_dpi)>>step_type; - DBG (DBG_io2, "%s: exposure=%d, dpi=%d, target=%d\n", __FUNCTION__, exposure, dpi, target); + DBG (DBG_io2, "%s: exposure=%d, dpi=%d, target=%d\n", __func__, exposure, dpi, target); /* fill result with target speed */ for(i=0;itable[i]==0 && DBG_LEVEL >= DBG_warn && current>target) { - DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too low ?\n",__FUNCTION__,target); + DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too low ?\n",__func__,target); } if(i<3 && DBG_LEVEL >= DBG_warn) { - DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too high ?\n",__FUNCTION__,target); + DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too high ?\n",__func__,target); } /* align on factor */ @@ -1791,20 +1797,20 @@ sanei_genesys_is_compatible_calibration (Genesys_Device * dev, if(dev->model->cmd_set->calculate_current_setup==NULL) { - DBG (DBG_proc, "%s: no calculate_setup, non compatible cache\n", __FUNCTION__); + DBG (DBG_proc, "%s: no calculate_setup, non compatible cache\n", __func__); return SANE_STATUS_UNSUPPORTED; } status = dev->model->cmd_set->calculate_current_setup (dev); if (status != SANE_STATUS_GOOD) { - DBG (DBG_error, "%s: failed to calculate current setup: %s\n", __FUNCTION__, + DBG (DBG_error, "%s: failed to calculate current setup: %s\n", __func__, sane_strstatus (status)); return status; } dev->current_setup.scan_method = dev->settings.scan_method; - DBG (DBG_proc, "%s: checking\n", __FUNCTION__); + DBG (DBG_proc, "%s: checking\n", __func__); /* a calibration cache is compatible if color mode and x dpi match the user * requested scan. In the case of CIS scanners, dpi isn't a criteria */ @@ -1822,22 +1828,22 @@ sanei_genesys_is_compatible_calibration (Genesys_Device * dev, resolution=sanei_genesys_compute_dpihw(dev,dev->settings.xres); compatible = (resolution == ((int) sanei_genesys_compute_dpihw(dev,cache->used_setup.xres))); } - DBG (DBG_io, "%s: after resolution check current compatible=%d\n", __FUNCTION__, compatible); + DBG (DBG_io, "%s: after resolution check current compatible=%d\n", __func__, compatible); if (dev->current_setup.half_ccd != cache->used_setup.half_ccd) { - DBG (DBG_io, "%s: half_ccd=%d, used=%d\n", __FUNCTION__, + DBG (DBG_io, "%s: half_ccd=%d, used=%d\n", __func__, dev->current_setup.half_ccd, cache->used_setup.half_ccd); compatible = 0; } if (dev->current_setup.scan_method != cache->used_setup.scan_method) { - DBG (DBG_io, "%s: current method=%d, used=%d\n", __FUNCTION__, + DBG (DBG_io, "%s: current method=%d, used=%d\n", __func__, dev->current_setup.scan_method, cache->used_setup.scan_method); compatible = 0; } if (!compatible) { - DBG (DBG_proc, "%s: completed, non compatible cache\n", __FUNCTION__); + DBG (DBG_proc, "%s: completed, non compatible cache\n", __func__); return SANE_STATUS_UNSUPPORTED; } @@ -1851,7 +1857,7 @@ sanei_genesys_is_compatible_calibration (Genesys_Device * dev, && (dev->model->is_sheetfed == SANE_FALSE) && (dev->settings.scan_method == SCAN_METHOD_FLATBED)) { - DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __FUNCTION__); + DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __func__); return SANE_STATUS_UNSUPPORTED; } } diff --git a/backend/genesys_low.h b/backend/genesys_low.h index b5a0a8f..56627b4 100644 --- a/backend/genesys_low.h +++ b/backend/genesys_low.h @@ -3,7 +3,7 @@ Copyright (C) 2003 Oliver Rauch Copyright (C) 2003, 2004 Henning Meier-Geinitz Copyright (C) 2004, 2005 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2004-2013 Stéphane Voltz Copyright (C) 2005-2009 Pierre Willenbrock Copyright (C) 2006 Laurent Charpentier Parts of the structs have been taken from the gt68xx backend by @@ -104,7 +104,7 @@ do { status = function; \ if (status != SANE_STATUS_GOOD) \ { \ - DBG(DBG_error, "%s: %s\n", __FUNCTION__, sane_strstatus (status)); \ + DBG(DBG_error, "%s: %s\n", __func__, sane_strstatus (status)); \ return status; \ } \ } while (SANE_FALSE) @@ -114,7 +114,7 @@ if (status != SANE_STATUS_GOOD) \ { \ free(mem); \ - DBG(DBG_error, "%s: %s\n", __FUNCTION__, sane_strstatus (status)); \ + DBG(DBG_error, "%s: %s\n", __func__, sane_strstatus (status)); \ return status; \ } \ } while (SANE_FALSE) @@ -129,8 +129,8 @@ } \ } while (SANE_FALSE) -#define DBGSTART DBG (DBG_proc, "%s start\n", __FUNCTION__); -#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __FUNCTION__); +#define DBGSTART DBG (DBG_proc, "%s start\n", __func__); +#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __func__); #define FREE_IFNOT_NULL(x) if(x!=NULL) { free(x); x=NULL;} @@ -352,6 +352,7 @@ Genesys_Color_Order; #define DAC_IMG101 18 #define DAC_PLUSTEK3800 19 #define DAC_CANONLIDE80 20 +#define DAC_CANONLIDE120 21 #define CCD_UMAX 0 #define CCD_ST12 1 /* SONY ILX548: 5340 Pixel ??? */ @@ -410,6 +411,7 @@ Genesys_Color_Order; #define GPO_IMG101 22 #define GPO_PLUSTEK3800 23 #define GPO_CANONLIDE80 24 +#define GPO_CANONLIDE120 25 #define MOTOR_UMAX 0 #define MOTOR_5345 1 @@ -435,6 +437,7 @@ Genesys_Color_Order; #define MOTOR_PLUSTEK3800 22 #define MOTOR_CANONLIDE210 23 #define MOTOR_CANONLIDE80 24 +#define MOTOR_CANONLIDE120 25 /* Forward typedefs */ @@ -506,8 +509,8 @@ typedef struct Genesys_Command_Set SANE_Status (*coarse_gain_calibration) (Genesys_Device * dev, int dpi); SANE_Status (*led_calibration) (Genesys_Device * dev); - SANE_Status (*slow_back_home) (Genesys_Device * dev, - SANE_Bool wait_until_home); + SANE_Status (*slow_back_home) (Genesys_Device * dev, SANE_Bool wait_until_home); + SANE_Status (*rewind) (Genesys_Device * dev); SANE_Status (*bulk_write_register) (Genesys_Device * dev, Genesys_Register_Set * reg, diff --git a/backend/gphoto2.c b/backend/gphoto2.c index 7b297c4..c8af306 100644 --- a/backend/gphoto2.c +++ b/backend/gphoto2.c @@ -353,14 +353,23 @@ static const SANE_Device *devlist[] = { * debug_func - called for gphoto2 debugging output (if enabled) */ static void +#ifdef GPLOGFUNC_NO_VARGS +debug_func (GPLogLevel level, const char *domain, const char *message, + void __sane_unused__ * data) +#else debug_func (GPLogLevel level, const char *domain, const char *format, - va_list args, void UNUSEDARG * data) + va_list args, void __sane_unused__ * data) +#endif { if (level == GP_LOG_ERROR) DBG (0, "%s(ERROR): ", domain); else DBG (0, "%s(%i): ", domain, level); +#ifdef GPLOGFUNC_NO_VARGS + DBG (0, "%s", message); +#else sanei_debug_msg (0, DBG_LEVEL, STRINGIFY (BACKEND_NAME), format, args); +#endif DBG (0, "\n"); } @@ -650,7 +659,7 @@ change_res (SANE_Byte res) * is present, and initialize gphoto2 */ SANE_Status -sane_init (SANE_Int * version_code, SANE_Auth_Callback UNUSEDARG authorize) +sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize) { SANE_Int n, entries; SANE_Char f[] = "sane_init"; @@ -940,7 +949,7 @@ sane_exit (void) */ SANE_Status sane_get_devices (const SANE_Device *** device_list, SANE_Bool - UNUSEDARG local_only) + __sane_unused__ local_only) { DBG (127, "sane_get_devices called\n"); @@ -1314,7 +1323,7 @@ my_source_mgr; typedef my_source_mgr *my_src_ptr; METHODDEF (void) -jpeg_init_source (j_decompress_ptr UNUSEDARG cinfo) +jpeg_init_source (j_decompress_ptr __sane_unused__ cinfo) { /* nothing to do */ } @@ -1361,7 +1370,7 @@ METHODDEF (void) jpeg_skip_input_data (j_decompress_ptr cinfo, long num_bytes) } METHODDEF (void) -jpeg_term_source (j_decompress_ptr UNUSEDARG cinfo) +jpeg_term_source (j_decompress_ptr __sane_unused__ cinfo) { /* no work necessary here */ } @@ -1476,7 +1485,7 @@ sane_start (SANE_Handle handle) * sane_read() - From SANE API */ SANE_Status -sane_read (SANE_Handle UNUSEDARG handle, SANE_Byte * data, +sane_read (SANE_Handle __sane_unused__ handle, SANE_Byte * data, SANE_Int max_length, SANE_Int * length) { if (Cam_data.scanning == SANE_FALSE) @@ -1530,7 +1539,7 @@ sane_read (SANE_Handle UNUSEDARG handle, SANE_Byte * data, * sane_cancel() - From SANE API */ void -sane_cancel (SANE_Handle UNUSEDARG handle) +sane_cancel (SANE_Handle __sane_unused__ handle) { if (Cam_data.scanning) { @@ -1544,8 +1553,8 @@ sane_cancel (SANE_Handle UNUSEDARG handle) * sane_set_io_mode() - From SANE API */ SANE_Status -sane_set_io_mode (SANE_Handle UNUSEDARG handle, SANE_Bool - UNUSEDARG non_blocking) +sane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool + __sane_unused__ non_blocking) { /* sane_set_io_mode() is only valid during a scan */ if (Cam_data.scanning) @@ -1570,7 +1579,7 @@ sane_set_io_mode (SANE_Handle UNUSEDARG handle, SANE_Bool * sane_get_select_fd() - From SANE API */ SANE_Status -sane_get_select_fd (SANE_Handle UNUSEDARG handle, SANE_Int UNUSEDARG * fd) +sane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd) { return SANE_STATUS_UNSUPPORTED; } @@ -1738,13 +1747,13 @@ read_dir (SANE_String dir, SANE_Bool read_files) { if (gp_list_free (dir_list) < 0) { - DBG (0, "%s: errror: gp_list_free failed\n", f); + DBG (0, "%s: error: gp_list_free failed\n", f); } dir_list = NULL; } if (gp_list_new (&dir_list) < 0) { - DBG (0, "%s: errror: gp_list_new failed\n", f); + DBG (0, "%s: error: gp_list_new failed\n", f); } if (read_files) @@ -1783,7 +1792,7 @@ read_info (SANE_String_Const fname) * set_res - set picture size depending on resolution settings */ static void -set_res (SANE_Int UNUSEDARG lowres) +set_res (SANE_Int __sane_unused__ lowres) { if (gphoto2_opt_thumbnails) { @@ -1943,7 +1952,6 @@ converter_scan_complete (void) static SANE_Status converter_init (SANE_Handle handle) { - SANE_Int row_stride; struct jpeg_error_mgr jerr; my_src_ptr src; @@ -1982,8 +1990,6 @@ exit(1); dest_mgr = sanei_jpeg_jinit_write_ppm (&cinfo); (void) jpeg_start_decompress (&cinfo); - row_stride = cinfo.output_width * cinfo.output_components; - parms.bytes_per_line = cinfo.output_width * 3; /* 3 colors */ parms.pixels_per_line = cinfo.output_width; parms.lines = cinfo.output_height; diff --git a/backend/gphoto2.h b/backend/gphoto2.h index 4ef953b..60591cf 100644 --- a/backend/gphoto2.h +++ b/backend/gphoto2.h @@ -155,12 +155,6 @@ struct cam_dirent long size; }; -#ifdef __GNUC__ -#define UNUSEDARG __attribute__ ((unused)) -#else -#define UNUSEDARG -#endif - struct cam_dirlist { SANE_Char name[48]; diff --git a/backend/gt68xx.c b/backend/gt68xx.c index ea71d91..13efe91 100644 --- a/backend/gt68xx.c +++ b/backend/gt68xx.c @@ -2346,7 +2346,7 @@ sane_cancel (SANE_Handle handle) else { DBG (4, "sane_cancel: scan has not been initiated yet, " - "or it is allready aborted\n"); + "or it is already aborted\n"); } DBG (5, "sane_cancel: exit\n"); diff --git a/backend/gt68xx_low.h b/backend/gt68xx_low.h index 68cd7c5..0743230 100644 --- a/backend/gt68xx_low.h +++ b/backend/gt68xx_low.h @@ -73,9 +73,6 @@ /* return if an error occured while the function was called */ #ifdef MAX_DEBUG -# ifndef __FUNCTION__ -# define __FUNCTION__ "somewhere" -# endif # define RIE(function) \ do \ @@ -83,7 +80,7 @@ status = function; \ if (status != SANE_STATUS_GOOD) \ { \ - DBG (7, "%s: %s: %s\n", __FUNCTION__, STRINGIFY(function), \ + DBG (7, "%s: %s: %s\n", __func__, STRINGIFY(function), \ sane_strstatus (status)); \ return status; \ } \ diff --git a/backend/hp-accessor.c b/backend/hp-accessor.c index b1acd7c..8b79ad4 100644 --- a/backend/hp-accessor.c +++ b/backend/hp-accessor.c @@ -687,20 +687,20 @@ sanei_hp_accessor_vector_new (HpData data, unsigned length, unsigned depth) } static unsigned short -_gamma_vector_unscale (HpAccessorVector UNUSEDARG this, SANE_Fixed fval) +_gamma_vector_unscale (HpAccessorVector __sane_unused__ this, SANE_Fixed fval) { unsigned short unscaled = fval / SANE_FIX(1.0); if (unscaled > 255) unscaled = 255; - unscaled = 255 - unscaled; /* Dont know why. But this is how it works */ + unscaled = 255 - unscaled; /* Don't know why. But this is how it works. */ return unscaled; } static SANE_Fixed -_gamma_vector_scale (HpAccessorVector UNUSEDARG this, unsigned short val) +_gamma_vector_scale (HpAccessorVector __sane_unused__ this, unsigned short val) { SANE_Fixed scaled; - val = 255-val; /* Dont know why. But this is how it works */ + val = 255-val; /* Don't know why. But this is how it works. */ scaled = val * SANE_FIX(1.0); return scaled; diff --git a/backend/hp-device.c b/backend/hp-device.c index 2b96ad6..6a50f84 100644 --- a/backend/hp-device.c +++ b/backend/hp-device.c @@ -249,7 +249,6 @@ sanei_hp_device_probe_model (enum hp_device_compat_e *compat, HpScsi scsi, }; int i; char buf[8]; - size_t len; SANE_Status status; static char *last_device = NULL; static enum hp_device_compat_e last_compat; @@ -279,7 +278,6 @@ sanei_hp_device_probe_model (enum hp_device_compat_e *compat, HpScsi scsi, { DBG(1,"probing %s\n",probes[i].model); - len = sizeof(buf); if (!FAILED( status = sanei_hp_scl_upload(scsi, probes[i].cmd, buf, sizeof(buf)) )) { diff --git a/backend/hp-handle.c b/backend/hp-handle.c index d9be2d5..ec8adbc 100644 --- a/backend/hp-handle.c +++ b/backend/hp-handle.c @@ -192,7 +192,7 @@ hp_handle_startReader (HpHandle this, HpScsi scsi) this->pipe_write_fd = -1; } - if (this->reader_pid == -1) /* Creating child failed ? Clean up pipe */ + if (!sanei_thread_is_valid (this->reader_pid)) { if ( !this->child_forked ) { diff --git a/backend/hp-option.c b/backend/hp-option.c index 10bcb3e..ba799b7 100644 --- a/backend/hp-option.c +++ b/backend/hp-option.c @@ -114,7 +114,7 @@ static SANE_Status hp_probe_parameter_support_table (enum hp_device_compat_e #define HP_EOL -9999 -/* Dont need requiries for commands that are probed */ +/* Don't need requiries for commands that are probed */ #define HP_PROBE_SCL_COMMAND 1 /* Scale factor for vectors (gtk seems not to like vectors/curves @@ -298,15 +298,15 @@ sanei_hp_choice_isEnabled (HpChoice this, HpOptSet optset, HpData data, } static hp_bool_t -_cenable_incolor (HpChoice UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_cenable_incolor (HpChoice __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) { return sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_COLOR; } static hp_bool_t -_cenable_notcolor (HpChoice UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_cenable_notcolor (HpChoice __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) { return sanei_hp_optset_scanmode(optset, data) != HP_SCANMODE_COLOR; } @@ -744,7 +744,7 @@ _set_size (HpOption opt, HpData data, SANE_Int size) /* #ifdef HP_EXPERIMENTAL */ static SANE_Status -_probe_int (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, HpData data) +_probe_int (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { HpScl scl = this->descriptor->scl_command; int minval, maxval; @@ -770,7 +770,7 @@ _probe_int (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, HpData data) /* #endif */ static SANE_Status -_probe_int_brightness (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_int_brightness (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { HpScl scl = this->descriptor->scl_command; @@ -811,7 +811,7 @@ _probe_int_brightness (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, } static SANE_Status -_probe_resolution (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_resolution (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { int minval, maxval, min2, max2; @@ -868,7 +868,7 @@ _probe_resolution (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, } static SANE_Status -_probe_bool (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_bool (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { HpScl scl = this->descriptor->scl_command; @@ -891,7 +891,7 @@ _probe_bool (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, static SANE_Status -_probe_change_doc (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_change_doc (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) {SANE_Status status; @@ -927,7 +927,7 @@ _probe_change_doc (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, * _probe_change_doc(), to hide the unnecessary "Unload" button on * non-ADF OfficeJets. */ static SANE_Status -_probe_unload (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_unload (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) {SANE_Status status; @@ -959,7 +959,7 @@ _probe_unload (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, } static SANE_Status -_probe_calibrate (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_calibrate (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { int val = 0; /* Always false */ @@ -1144,7 +1144,7 @@ _probe_choice (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) } static SANE_Status -_probe_each_choice (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_each_choice (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { HpScl scl = this->descriptor->scl_command; @@ -1194,7 +1194,7 @@ _probe_each_choice (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, /* pseudo probe for exposure times in Photosmart */ static SANE_Status -_probe_ps_exposure_time (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_ps_exposure_time (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { int minval = 0, maxval = 9, val = 0; @@ -1229,7 +1229,7 @@ _probe_ps_exposure_time (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, /* probe scan type (normal, adf, xpa) */ static SANE_Status -_probe_scan_type (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_scan_type (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { int val; @@ -1300,7 +1300,7 @@ _probe_scan_type (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, } static SANE_Status -_probe_mirror_horiz (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_mirror_horiz (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { HpScl scl = this->descriptor->scl_command; @@ -1345,7 +1345,7 @@ _probe_mirror_horiz (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, } static SANE_Status -_probe_mirror_vert (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_mirror_vert (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { int minval = HP_MIRROR_VERT_OFF, @@ -1390,7 +1390,7 @@ _probe_mirror_vert (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, static SANE_Status _probe_front_button(_HpOption this, HpScsi scsi, - HpOptSet UNUSEDARG optset, HpData data) + HpOptSet __sane_unused__ optset, HpData data) { int val = 0; @@ -1501,7 +1501,7 @@ _probe_download_type (HpScl scl, HpScsi scsi) } static SANE_Status -_probe_custom_gamma (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_custom_gamma (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { HpScl scl = this->descriptor->scl_command; @@ -1694,8 +1694,8 @@ _probe_matrix (_HpOption this, HpScsi scsi, HpOptSet optset, HpData data) } static SANE_Status -_probe_num_options (_HpOption this, HpScsi UNUSEDARG scsi, - HpOptSet UNUSEDARG optset, HpData data) +_probe_num_options (_HpOption this, HpScsi __sane_unused__ scsi, + HpOptSet __sane_unused__ optset, HpData data) { /* If we dont have an accessor, get one */ if (!this->data_acsr) @@ -1708,7 +1708,7 @@ _probe_num_options (_HpOption this, HpScsi UNUSEDARG scsi, } static SANE_Status -_probe_devpix (_HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_probe_devpix (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { HpScl scl = this->descriptor->scl_command; @@ -2102,7 +2102,7 @@ _program_matrix (HpOption this, HpScsi scsi, HpOptSet optset, HpData data) } static SANE_Status -_program_resolution (HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_program_resolution (HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { @@ -2326,7 +2326,7 @@ _program_media (HpOption this, HpScsi scsi, HpOptSet optset, HpData data) static SANE_Status _program_unload_after_scan (HpOption this, HpScsi scsi, - HpOptSet UNUSEDARG optset, HpData data) + HpOptSet __sane_unused__ optset, HpData data) { HpDeviceInfo *info; info = sanei_hp_device_info_get ( sanei_hp_scsi_devicename (scsi) ); @@ -2340,8 +2340,8 @@ _program_unload_after_scan (HpOption this, HpScsi scsi, } static SANE_Status -_program_lamp_off (HpOption UNUSEDARG this, HpScsi scsi, - HpOptSet UNUSEDARG optset, HpData UNUSEDARG data) +_program_lamp_off (HpOption __sane_unused__ this, HpScsi scsi, + HpOptSet __sane_unused__ optset, HpData __sane_unused__ data) { DBG(3,"program_lamp_off: shut off lamp\n"); @@ -2436,8 +2436,8 @@ _program_scan_type (HpOption this, HpScsi scsi, HpOptSet optset, HpData data) } static SANE_Status -_program_change_doc (HpOption UNUSEDARG this, HpScsi scsi, - HpOptSet UNUSEDARG optset, HpData UNUSEDARG data) +_program_change_doc (HpOption __sane_unused__ this, HpScsi scsi, + HpOptSet __sane_unused__ optset, HpData __sane_unused__ data) { int istat; @@ -2492,8 +2492,8 @@ _program_unload (HpOption this, HpScsi scsi, HpOptSet optset, HpData data) } static SANE_Status -_program_calibrate (HpOption UNUSEDARG this, HpScsi scsi, - HpOptSet UNUSEDARG optset, HpData UNUSEDARG data) +_program_calibrate (HpOption __sane_unused__ this, HpScsi scsi, + HpOptSet __sane_unused__ optset, HpData __sane_unused__ data) { struct passwd *pw; SANE_Status status = SANE_STATUS_GOOD; @@ -2525,7 +2525,7 @@ _program_calibrate (HpOption UNUSEDARG this, HpScsi scsi, * speed for higher exposure times */ static SANE_Status _program_ps_exposure_time (HpOption this, HpScsi scsi, - HpOptSet UNUSEDARG optset, HpData data) + HpOptSet __sane_unused__ optset, HpData data) { SANE_Status status = SANE_STATUS_GOOD; size_t calib_size = 0; @@ -2650,7 +2650,7 @@ _program_scanmode (HpOption this, HpScsi scsi, HpOptSet optset, HpData data) } static SANE_Status -_program_mirror_horiz (HpOption this, HpScsi scsi, HpOptSet UNUSEDARG optset, +_program_mirror_horiz (HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, HpData data) { int sec_dir, mirror = hp_option_getint(this, data); @@ -2695,8 +2695,8 @@ _enable_rgb_maps (HpOption this, HpOptSet optset, HpData data, #endif static hp_bool_t -_enable_mono_map (HpOption UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_enable_mono_map (HpOption __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) { HpOption cgam = hp_optset_get(optset, CUSTOM_GAMMA); @@ -2706,8 +2706,8 @@ _enable_mono_map (HpOption UNUSEDARG this, HpOptSet optset, HpData data, } static hp_bool_t -_enable_rgb_matrix (HpOption UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_enable_rgb_matrix (HpOption __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) { HpOption type = hp_optset_get(optset, MATRIX_TYPE); @@ -2746,8 +2746,8 @@ _enable_brightness (HpOption this, HpOptSet optset, HpData data, } static hp_bool_t -_enable_autoback (HpOption UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_enable_autoback (HpOption __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) { return sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_LINEART; } @@ -2788,15 +2788,15 @@ _enable_custom_gamma (HpOption this, HpOptSet optset, HpData data, } static hp_bool_t -_enable_halftone (HpOption UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_enable_halftone (HpOption __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) { return sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_HALFTONE; } static hp_bool_t -_enable_halftonevec (HpOption UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_enable_halftonevec (HpOption __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) { if (sanei_hp_optset_scanmode(optset, data) == HP_SCANMODE_HALFTONE) { @@ -2808,8 +2808,8 @@ _enable_halftonevec (HpOption UNUSEDARG this, HpOptSet optset, HpData data, } static hp_bool_t -_enable_data_width (HpOption UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_enable_data_width (HpOption __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) {enum hp_scanmode_e mode; mode = sanei_hp_optset_scanmode (optset, data); @@ -2817,7 +2817,7 @@ _enable_data_width (HpOption UNUSEDARG this, HpOptSet optset, HpData data, } static hp_bool_t -_enable_out8 (HpOption UNUSEDARG this, HpOptSet optset, HpData data, +_enable_out8 (HpOption __sane_unused__ this, HpOptSet optset, HpData data, const HpDeviceInfo *info) { if (hp_optset_isEnabled (optset, data, SANE_NAME_BIT_DEPTH, info)) @@ -2829,8 +2829,8 @@ _enable_out8 (HpOption UNUSEDARG this, HpOptSet optset, HpData data, } static hp_bool_t -_enable_calibrate (HpOption UNUSEDARG this, HpOptSet optset, HpData data, - const HpDeviceInfo UNUSEDARG *info) +_enable_calibrate (HpOption __sane_unused__ this, HpOptSet optset, HpData data, + const HpDeviceInfo __sane_unused__ *info) { HpOption media = hp_optset_get(optset, MEDIA); diff --git a/backend/hp-scl.c b/backend/hp-scl.c index e58508b..f1813c7 100644 --- a/backend/hp-scl.c +++ b/backend/hp-scl.c @@ -339,7 +339,7 @@ hp_nonscsi_write (HpScsi this, hp_byte_t *data, size_t len, HpConnect connect) static SANE_Status hp_nonscsi_read (HpScsi this, hp_byte_t *data, size_t *len, HpConnect connect, - int UNUSEDARG isResponse) + int __sane_unused__ isResponse) {int n = -1; static int retries = -1; @@ -905,7 +905,7 @@ hp_scsi_scl(HpScsi this, HpScl scl, int val) RETURN_IF_FAIL( hp_scsi_need(this, 10) ); - /* Dont try to optimize SCL-commands like using *a1b0c5T */ + /* Don't try to optimize SCL-commands like using *a1b0c5T */ /* Some scanners have problems with it (e.g. HP Photosmart Photoscanner */ /* with window position/extent, resolution) */ count = sprintf((char *)this->bufp, "\033*%c%d%c", group, val, param); @@ -1011,7 +1011,7 @@ hp_scsi_read (HpScsi this, void * dest, size_t *len, int isResponse) static int signal_caught = 0; -static RETSIGTYPE +static void signal_catcher (int sig) { DBG(1,"signal_catcher(sig=%d): old signal_caught=%d\n",sig,signal_caught); @@ -1338,13 +1338,11 @@ static SANE_Status process_data (PROCDATA_HANDLE *ph, unsigned char *read_ptr, int nread) {int bytes_left; - HpProcessData *procdata; if (nread <= 0) return SANE_STATUS_GOOD; if (ph == NULL) return SANE_STATUS_INVAL; - procdata = &(ph->procdata); if ( ph->tmp_buf_len > 0 ) /* Something left ? */ { bytes_left = ph->tmp_buf_size - ph->tmp_buf_len; @@ -2083,7 +2081,7 @@ hp_scl_strerror (int errnum) case 1024: return "ADF Paper Jam"; case 1025: return "Home Position Missing"; case 1026: return "Paper Not Loaded"; - default: return "??Unkown Error??"; + default: return "??Unknown Error??"; } } diff --git a/backend/hp.c b/backend/hp.c index c85e40c..f00b82d 100644 --- a/backend/hp.c +++ b/backend/hp.c @@ -468,13 +468,11 @@ static void hp_device_info_remove (void) { HpDeviceInfoList next, infolistelement = global.infolist; - HpDeviceInfo *info; if (!global.is_up) return; while (infolistelement) { - info = &(infolistelement->info); next = infolistelement->next; sanei_hp_free (infolistelement); infolistelement = next; @@ -811,7 +809,7 @@ hp_update_devlist (void) */ SANE_Status -sane_init (SANE_Int *version_code, SANE_Auth_Callback UNUSEDARG authorize) +sane_init (SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize) {SANE_Status status; DBG_INIT(); @@ -839,7 +837,7 @@ sane_exit (void) SANE_Status sane_get_devices (const SANE_Device ***device_list, - SANE_Bool UNUSEDARG local_only) + SANE_Bool __sane_unused__ local_only) { DBG(3, "sane_get_devices called\n"); diff --git a/backend/hp.h b/backend/hp.h index b86ee04..42b3be5 100644 --- a/backend/hp.h +++ b/backend/hp.h @@ -53,12 +53,6 @@ #define DEBUG_NOT_STATIC #include "../include/sane/sanei_debug.h" -#ifdef __GNUC__ -#define UNUSEDARG __attribute__ ((unused)) -#else -#define UNUSEDARG -#endif - /* FIXME: these should be options? */ #undef ENABLE_7x12_TONEMAPS #define ENABLE_16x16_DITHERS diff --git a/backend/hp3500.c b/backend/hp3500.c index 48a8035..26fe071 100644 --- a/backend/hp3500.c +++ b/backend/hp3500.c @@ -84,6 +84,7 @@ #include #include #include +#include #include #include @@ -145,6 +146,7 @@ enum hp3500_option OPT_MODE, OPT_BRIGHTNESS, OPT_CONTRAST, + OPT_GAMMA, NUM_OPTIONS }; @@ -189,6 +191,8 @@ struct hp3500_data int brightness; int contrast; + double gamma; + SANE_Option_Descriptor opt[NUM_OPTIONS]; SANE_Device sane; }; @@ -218,6 +222,8 @@ static const SANE_Range range_brightness = { 0, 255, 0 }; static const SANE_Range range_contrast = { 0, 255, 0 }; +static const SANE_Range range_gamma = + { SANE_FIX (0.2), SANE_FIX(4.0), SANE_FIX(0.01) }; #define HP3500_COLOR_SCAN 0 @@ -233,6 +239,7 @@ static int reader_process (void *); static void calculateDerivedValues (struct hp3500_data *scanner); static void do_reset (struct hp3500_data *scanner); static void do_cancel (struct hp3500_data *scanner); +static size_t max_string_size(char const **); /* * used by sane_get_devices @@ -382,6 +389,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) scanner->mode = 0; scanner->brightness = 128; scanner->contrast = 64; + scanner->gamma = 2.2; calculateDerivedValues (scanner); return SANE_STATUS_GOOD; @@ -536,6 +544,10 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *(SANE_Word *) val = scanner->contrast; return SANE_STATUS_GOOD; + case OPT_GAMMA: + *(SANE_Word *) val = SANE_FIX(scanner->gamma); + return SANE_STATUS_GOOD; + case OPT_BRIGHTNESS: *(SANE_Word *) val = scanner->brightness; return SANE_STATUS_GOOD; @@ -649,6 +661,10 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_CONTRAST: scanner->contrast = *(SANE_Word *) val; return SANE_STATUS_GOOD; + + case OPT_GAMMA: + scanner->gamma = SANE_UNFIX(*(SANE_Word *) val); + return SANE_STATUS_GOOD; } /* switch */ } /* else */ return SANE_STATUS_INVAL; @@ -703,7 +719,7 @@ sane_start (SANE_Handle handle) scanner->reader_pid = sanei_thread_begin (reader_process, scanner); time (&scanner->last_scan); - if (scanner->reader_pid == -1) + if (!sanei_thread_is_valid (scanner->reader_pid)) { DBG (MSG_ERR, "cannot fork reader process.\n"); DBG (MSG_ERR, "%s", strerror (errno)); @@ -952,7 +968,7 @@ attachScanner (const char *devicename) dev->devicename = strdup (devicename); dev->sfd = -1; dev->last_scan = 0; - dev->reader_pid = -1; + dev->reader_pid = (SANE_Pid) -1; dev->pipe_r = dev->pipe_w = -1; dev->sane.name = dev->devicename; @@ -1064,8 +1080,9 @@ init_options (struct hp3500_data *scanner) opt->title = SANE_TITLE_SCAN_MODE; opt->desc = SANE_DESC_SCAN_MODE; opt->type = SANE_TYPE_STRING; + opt->size = max_string_size(scan_mode_list); opt->constraint_type = SANE_CONSTRAINT_STRING_LIST; - opt->constraint.string_list = scan_mode_list; + opt->constraint.string_list = (SANE_String_Const *) scan_mode_list; opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; opt = scanner->opt + OPT_BRIGHTNESS; @@ -1086,6 +1103,16 @@ init_options (struct hp3500_data *scanner) opt->constraint.range = &range_contrast; opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + opt = scanner->opt + OPT_GAMMA; + opt->name = SANE_NAME_ANALOG_GAMMA; + opt->title = SANE_TITLE_ANALOG_GAMMA; + opt->desc = SANE_DESC_ANALOG_GAMMA; + opt->type = SANE_TYPE_FIXED; + opt->unit = SANE_UNIT_NONE; + opt->constraint_type = SANE_CONSTRAINT_RANGE; + opt->constraint.range = &range_gamma; + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + return SANE_STATUS_GOOD; } @@ -1098,7 +1125,7 @@ do_reset (struct hp3500_data *scanner) static void do_cancel (struct hp3500_data *scanner) { - if (scanner->reader_pid != -1) + if (sanei_thread_is_valid (scanner->reader_pid)) { if (sanei_thread_kill (scanner->reader_pid) == 0) @@ -1749,14 +1776,14 @@ rt_set_basic_calibration (unsigned char *regs, int greengain, int blueoffset1, int blueoffset2, int bluegain) { - regs[0x05] = redoffset1; - regs[0x02] = redoffset2; + regs[0x02] = redoffset1; + regs[0x05] = redoffset2; regs[0x08] = redgain; - regs[0x06] = greenoffset1; - regs[0x03] = greenoffset2; + regs[0x03] = greenoffset1; + regs[0x06] = greenoffset2; regs[0x09] = greengain; - regs[0x07] = blueoffset1; - regs[0x04] = blueoffset2; + regs[0x04] = blueoffset1; + regs[0x07] = blueoffset2; regs[0x0a] = bluegain; return 0; } @@ -1765,13 +1792,36 @@ static int rt_set_calibration_addresses (unsigned char *regs, unsigned redaddr, unsigned greenaddr, - unsigned blueaddr, unsigned endaddr) + unsigned blueaddr, + unsigned endaddr, + unsigned width) { + unsigned endpage = (endaddr + 31) / 32; + unsigned scanline_pages = ((width + 1) * 3 + 31) / 32; + + /* Red, green and blue detailed calibration addresses */ + regs[0x84] = redaddr; regs[0x8e] = (regs[0x8e] & 0x0f) | ((redaddr >> 4) & 0xf0); rt_set_value_lsbfirst (regs, 0x85, 2, greenaddr); rt_set_value_lsbfirst (regs, 0x87, 2, blueaddr); - rt_set_value_lsbfirst (regs, 0x89, 2, (endaddr + 31) / 32); + + /* I don't know what the next three are used for, but each buffer commencing + * at 0x80 and 0x82 needs to hold a full scan line. + */ + + rt_set_value_lsbfirst (regs, 0x80, 2, endpage); + rt_set_value_lsbfirst (regs, 0x82, 2, endpage + scanline_pages); + rt_set_value_lsbfirst (regs, 0x89, 2, endpage + scanline_pages * 2); + + /* I don't know what this is, but it seems to be a number of pages that can hold + * 16 complete scan lines, but not calculated as an offset from any other page + */ + + rt_set_value_lsbfirst (regs, 0x51, 2, (48 * (width + 1) + 31) / 32); + + /* I don't know what this is either, but this is what the Windows driver does */ + rt_set_value_lsbfirst (regs, 0x8f, 2, 0x1c00); return 0; } @@ -1797,6 +1847,13 @@ rt_set_data_feed_on (unsigned char *regs) return 0; } +static int +rt_set_data_feed_off (unsigned char *regs) +{ + regs[0xb2] |= 0x04; + return 0; +} + static int rt_enable_ccd (unsigned char *regs, int enable) { @@ -2245,10 +2302,14 @@ rt_nvram_read (int block, int location, unsigned char *data, int bytes) return 0; } +/* This is what we want as the initial registers, not what they + * are at power on time. In particular 13 bytes at 0x10 are + * different, and the byte at 0x94 is different. + */ static unsigned char initial_regs[] = { /* 0x00 */ 0xf5, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x08 */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x00, 0x00, 0x00, - /* 0x10 */ 0xe1, 0xfc, 0xff, 0xff, 0x00, 0x00, 0x00, 0xfc, + /* 0x10 */ 0x81, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, /* 0x18 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, /* 0x20 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x28 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x19, @@ -2264,7 +2325,7 @@ static unsigned char initial_regs[] = { /* 0x78 */ 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0x80 */ 0x0f, 0x02, 0x4b, 0x02, 0x00, 0xec, 0x19, 0xd8, /* 0x88 */ 0x2d, 0x87, 0x02, 0xff, 0x3f, 0x78, 0x60, 0x00, - /* 0x90 */ 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + /* 0x90 */ 0x1c, 0x00, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, /* 0x98 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* 0xa0 */ 0x00, 0x00, 0x00, 0x0c, 0x27, 0x64, 0x00, 0x00, /* 0xa8 */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, @@ -2363,14 +2424,14 @@ static struct resolution_parameters resparms[] = { /* My values - all work */ /*res r39 rC3 rC6 freq cph0s rgo gbo intra mmcm d3 tg stepsz */ {1200, 3, 6, 4, 2, 1, 22, 22, 4, 2, 1, RT_NORMAL_TG, 0x157b}, - {600, 15, 6, 4, 1, 0, 9, 10, 0, 2, 1, RT_NORMAL_TG, 0x055e}, + {600, 15, 6, 4, 1, 1, 9, 10, 0, 2, 1, RT_NORMAL_TG, 0x055e}, {400, 3, 1, 4, 1, 1, 6, 6, 1, 2, 1, RT_NORMAL_TG, 0x157b}, - {300, 15, 3, 4, 1, 0, 5, 4, 0, 2, 1, RT_NORMAL_TG, 0x02af}, - {200, 7, 1, 4, 1, 0, 3, 3, 0, 2, 1, RT_NORMAL_TG, 0x055e}, - {150, 15, 3, 1, 1, 0, 2, 2, 0, 2, 1, RT_NORMAL_TG, 0x02af}, - {100, 3, 1, 3, 1, 0, 1, 1, 0, 2, 1, RT_NORMAL_TG, 0x0abd}, - {75, 15, 3, 3, 1, 0, 1, 1, 0, 2, 1, RT_NORMAL_TG, 0x02af}, - {50, 15, 1, 1, 1, 0, 0, 0, 0, 2, 1, RT_NORMAL_TG, 0x055e}, + {300, 15, 3, 4, 1, 1, 5, 4, 0, 2, 1, RT_NORMAL_TG, 0x02af}, + {200, 7, 1, 4, 1, 1, 3, 3, 0, 2, 1, RT_NORMAL_TG, 0x055e}, + {150, 15, 3, 1, 1, 1, 2, 2, 0, 2, 1, RT_NORMAL_TG, 0x02af}, + {100, 3, 1, 3, 1, 1, 1, 1, 0, 2, 1, RT_NORMAL_TG, 0x0abd}, + {75, 15, 3, 3, 1, 1, 1, 1, 0, 2, 1, RT_NORMAL_TG, 0x02af}, + {50, 15, 1, 1, 1, 1, 0, 0, 0, 2, 1, RT_NORMAL_TG, 0x055e}, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} }; @@ -2597,6 +2658,90 @@ constrain (int val, int min, int max) return val; } +#if 0 +static void +sram_dump_byte(FILE *fp, + unsigned char const *left, + unsigned leftstart, + unsigned leftlimit, + unsigned char const *right, + unsigned rightstart, + unsigned rightlimit, + unsigned idx) +{ + unsigned ridx = rightstart + idx; + unsigned lidx = leftstart + idx; + + putc(' ', fp); + if (rightstart < rightlimit && leftstart < leftlimit && left[lidx] != right[ridx]) + fputs("", fp); + if (leftstart < leftlimit) + fprintf(fp, "%02x", left[lidx]); + else + fputs(" ", fp); + if (rightstart < rightlimit && leftstart < leftlimit && left[lidx] != right[ridx]) + fputs("", fp); +} + +static void +dump_sram_to_file(char const *fname, + unsigned char const *expected, + unsigned end_calibration_offset) +{ + FILE *fp = fopen(fname, "w"); + rt_set_sram_page(0); + + if (fp) + { + unsigned char buf[1024]; + unsigned loc = 0; + + fprintf(fp, "
\n");
+      while (loc < end_calibration_offset)
+        {
+          unsigned byte = 0;
+
+          rt_read_sram(1024, buf);
+
+          while (byte < 1024)
+            {
+              unsigned idx = 0;
+
+              fprintf(fp, "%06x:", loc);
+              do
+                {
+		  sram_dump_byte(fp, buf, byte, 1024, expected, loc, end_calibration_offset, idx);
+                } while (++idx & 0x7);
+              fprintf(fp, " -");
+              do
+                {
+		  sram_dump_byte(fp, buf, byte, 1024, expected, loc, end_calibration_offset, idx);
+                } while (++idx & 0x7);
+
+              idx = 0;
+              fputs("     ", fp);
+
+              do
+                {
+                  sram_dump_byte(fp, expected, loc, end_calibration_offset, buf, byte, 1024, idx);
+                } while (++idx & 0x7);
+              fprintf(fp, " -");
+              do
+                {
+                  sram_dump_byte(fp, expected, loc, end_calibration_offset, buf, byte, 1024, idx);
+                } while (++idx & 0x7);
+
+
+              fputs("\n", fp);
+              byte += 16;
+              loc += 16;
+            }
+        }
+      fprintf(fp, "
"); + fclose(fp); + } +} +#endif static int rts8801_doscan (unsigned width, @@ -2610,13 +2755,13 @@ rts8801_doscan (unsigned width, int oddfirst, unsigned char const *calib_info, int merged_channels, - detailed_calibration_data const *detailed_calib_data) + double *postprocess_offsets, + double *postprocess_gains) { unsigned rowbytes = 0; unsigned output_rowbytes = 0; unsigned channels = 0; unsigned total_rows = 0; - unsigned bytesperchannel; unsigned char *row_buffer; unsigned char *output_buffer; unsigned buffered_rows; @@ -2638,7 +2783,7 @@ rts8801_doscan (unsigned width, channels = 3; rowbytes = width * 3; - bytesperchannel = width; + switch (colour) { case HP3500_GRAY_SCAN: @@ -2710,32 +2855,27 @@ rts8801_doscan (unsigned width, if (!rows_to_begin || !--rows_to_begin) { unsigned char *outnow = output_buffer; + unsigned x; - for (i = 0; - i < (merged_channels ? rowbytes : width); - i += merged_channels ? channels : 1) + for (i = x = 0; + x < width; + ++x, i += merged_channels ? channels : 1) { for (j = 0; j < channels; ++j) { unsigned pix = (unsigned char) channel_data[j][i & 1][i]; - if (detailed_calib_data) - { - unsigned char const *calib_start = - detailed_calib_data->channeldata[j] + - 2 * - detailed_calib_data-> - resolution_divisor * i / - (merged_channels ? channels : 1); - pix = - constrain ((int) pix - - (int) calib_start[0], 0, - 255); - pix = - constrain (pix * calib_start[1] / - 0x40, 0, 255); - } + if (postprocess_gains && postprocess_offsets) + { + int ppidx = j * width + x; + + pix = constrain ( pix + * postprocess_gains[ppidx] + - postprocess_offsets[ppidx], + 0, + 255); + } *outnow++ = pix; } } @@ -2818,6 +2958,9 @@ static unsigned local_sram_size; static unsigned char r93setting; #define RTS8801_F_SUPPRESS_MOVEMENT 1 +#define RTS8801_F_LAMP_OFF 2 +#define RTS8801_F_NO_DISPLACEMENTS 4 +#define RTS8801_F_ODDX 8 static int find_resolution_index (unsigned resolution) @@ -2848,7 +2991,8 @@ rts8801_fullscan (unsigned x, int green_calib_offset, int blue_calib_offset, int end_calib_offset, - detailed_calibration_data const *detailed_calib_data) + double *postprocess_offsets, + double *postprocess_gains) { int ires, jres; int tg_setting; @@ -2856,6 +3000,10 @@ rts8801_fullscan (unsigned x, unsigned char offdutytime; int result; int scan_frequency; + unsigned intra_channel_offset; + unsigned red_green_offset; + unsigned green_blue_offset; + unsigned total_offsets; ires = find_resolution_index (xresolution); jres = find_resolution_index (yresolution); @@ -2889,47 +3037,32 @@ rts8801_fullscan (unsigned x, rt_set_movement_pattern (regs, 0x800000); - - tg_setting = resparms[jres].tg; - rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p); - rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp); - rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp); - - - rt_set_one_register (0xc6, 0); - rt_set_one_register (0xc6, 0); - - rt_set_step_size (regs, resparms[jres].step_size); - rt_set_direction_forwards (regs); - rt_set_stop_when_rewound (regs, 0); - rt_set_data_feed_on (regs); - rt_set_calibration_addresses (regs, 0, 0, 0, 0); + rt_set_calibration_addresses (regs, 0, 0, 0, 0, 0); rt_set_basic_calibration (regs, calib_info[0], calib_info[1], calib_info[2], calib_info[3], calib_info[4], calib_info[5], calib_info[6], calib_info[7], calib_info[8]); regs[0x0b] = 0x70; /* If set to 0x71, the alternative, all values are low */ + regs[0x40] &= 0xc0; if (red_calib_offset >= 0 && green_calib_offset >= 0 - && blue_calib_offset >= 0 && - yresolution < 400) + && blue_calib_offset >= 0) { rt_set_calibration_addresses (regs, red_calib_offset, green_calib_offset, blue_calib_offset, - end_calib_offset); + end_calib_offset, + w); regs[0x40] |= 0x2f; - detailed_calib_data = 0; } else if (end_calib_offset >= 0) { rt_set_calibration_addresses (regs, 0x600, 0x600, 0x600, - end_calib_offset); - regs[0x40] &= 0xc0; + end_calib_offset, w); } rt_set_channel (regs, RT_CHANNEL_ALL); @@ -2937,23 +3070,9 @@ rts8801_fullscan (unsigned x, rt_set_merge_channels (regs, 1); rt_set_colour_mode (regs, 1); - rt_set_motor_movement_clock_multiplier (regs, - resparms[jres]. - motor_movement_clock_multiplier); - - rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1, - tg_info[tg_setting].tg_cdss2); - rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1, - tg_info[tg_setting].tg_cdsc2); - rt_update_after_setting_cdss2 (regs); - rt_set_last_sram_page (regs, (local_sram_size - 1) >> 5); - regs[0x39] = resparms[jres].reg_39_value; - regs[0xc3] = (regs[0xc3] & 0xf8) | resparms[jres].reg_c3_value; - regs[0xc6] = (regs[0xc6] & 0xf8) | resparms[jres].reg_c6_value; scan_frequency = resparms[jres].scan_frequency; - rt_set_scan_frequency (regs, scan_frequency); rt_set_cph0s (regs, resparms[ires].cph0s); if (resparms[ires].d3_bit_3_value) regs[0xd3] |= 0x08; @@ -2962,15 +3081,10 @@ rts8801_fullscan (unsigned x, if (flags & RTS8801_F_SUPPRESS_MOVEMENT) regs[0xc3] &= 0x7f; - rt_set_horizontal_resolution (regs, xresolution); - rt_set_noscan_distance (regs, y * scan_frequency - 1); - rt_set_total_distance (regs, scan_frequency * - (y + - h + - resparms[jres].red_green_offset + - resparms[jres].green_blue_offset + - resparms[jres].intra_channel_offset) - 1); + regs[0xb2] &= 0xf7; + + rt_set_horizontal_resolution (regs, xresolution); rt_set_scanline_start (regs, x * (1200 / xresolution) / @@ -2982,6 +3096,118 @@ rts8801_fullscan (unsigned x, (resparms[ires].cph0s ? 1 : 2) / (resparms[ires].d3_bit_3_value ? 1 : 2)); + if (flags & RTS8801_F_NO_DISPLACEMENTS) + { + red_green_offset = green_blue_offset = intra_channel_offset = 0; + } + else + { + red_green_offset = resparms[jres].red_green_offset; + green_blue_offset = resparms[jres].green_blue_offset; + intra_channel_offset = resparms[jres].intra_channel_offset; + } + total_offsets = red_green_offset + green_blue_offset + intra_channel_offset; + if (y > total_offsets + 2) + y -= total_offsets; + h += total_offsets; + + if (yresolution > 75 && !(flags & RTS8801_F_SUPPRESS_MOVEMENT)) + { + int rmres = find_resolution_index (50); + + if (rmres >= 0) + { + int factor = yresolution / 50; + int fastres = y / factor; + int remainder = y % factor; + + while (remainder < 2) + { + --fastres; + remainder += factor; + } + + if (fastres >= 3) + { + y = remainder; + + rt_set_noscan_distance(regs, fastres * resparms[rmres].scan_frequency - 2); + rt_set_total_distance(regs, fastres * resparms[rmres].scan_frequency - 1); + + rt_set_scan_frequency(regs, 1); + + tg_setting = resparms[rmres].tg; + rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p); + rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp); + rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp); + + rt_set_one_register (0xc6, 0); + rt_set_one_register (0xc6, 0); + + rt_set_step_size (regs, resparms[rmres].step_size); + + rt_set_motor_movement_clock_multiplier (regs, + resparms[rmres]. + motor_movement_clock_multiplier); + + rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1, + tg_info[tg_setting].tg_cdss2); + rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1, + tg_info[tg_setting].tg_cdsc2); + rt_update_after_setting_cdss2 (regs); + + regs[0x39] = resparms[rmres].reg_39_value; + regs[0xc3] = (regs[0xc3] & 0xf8) | resparms[rmres].reg_c3_value; + regs[0xc6] = (regs[0xc6] & 0xf8) | resparms[rmres].reg_c6_value; + + rt_set_data_feed_off (regs); + + rt_set_all_registers (regs); + + rt_set_one_register (0x2c, regs[0x2c]); + + if (DBG_LEVEL >= 5) + dump_registers (regs); + + rt_start_moving (); + while (rt_is_moving ()); + } + } + } + + + rt_set_noscan_distance (regs, y * scan_frequency - 1); + rt_set_total_distance (regs, scan_frequency * (y + h) - 1); + + rt_set_scan_frequency (regs, scan_frequency); + + tg_setting = resparms[jres].tg; + + rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p); + rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp); + rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp); + + rt_set_one_register (0xc6, 0); + rt_set_one_register (0xc6, 0); + + rt_set_step_size (regs, resparms[jres].step_size); + + rt_set_motor_movement_clock_multiplier (regs, + resparms[jres]. + motor_movement_clock_multiplier); + + rt_set_cdss (regs, tg_info[tg_setting].tg_cdss1, + tg_info[tg_setting].tg_cdss2); + rt_set_cdsc (regs, tg_info[tg_setting].tg_cdsc1, + tg_info[tg_setting].tg_cdsc2); + rt_update_after_setting_cdss2 (regs); + + regs[0x39] = resparms[jres].reg_39_value; + regs[0xc3] = (regs[0xc3] & 0xf8) | resparms[jres].reg_c3_value; + regs[0xc6] = (regs[0xc6] & 0xf8) | resparms[jres].reg_c6_value; + + rt_set_data_feed_on (regs); + rt_set_all_registers (regs); rt_set_one_register (0x2c, regs[0x2c]); @@ -2992,12 +3218,13 @@ rts8801_fullscan (unsigned x, result = rts8801_doscan (w, h, colour, - resparms[jres].red_green_offset, - resparms[jres].green_blue_offset, - resparms[jres].intra_channel_offset, + red_green_offset, + green_blue_offset, + intra_channel_offset, cbfunc, param, (x & 1), calib_info, - (regs[0x2f] & 0x04) != 0, detailed_calib_data); - + (regs[0x2f] & 0x04) != 0, + postprocess_offsets, + postprocess_gains); return result; } @@ -3080,6 +3307,11 @@ sum_channel (unsigned char *p, int n, int bytwo) static int do_warmup = 1; +#define DETAILED_PASS_COUNT 3 +#define DETAILED_PASS_OFFSETS 0 +#define DETAILED_PASS_GAINS_FIRSTPASS 1 +#define DETAILED_PASS_GAINS_SECONDPASS 2 + static int rts8801_scan (unsigned x, unsigned y, @@ -3090,26 +3322,22 @@ rts8801_scan (unsigned x, unsigned brightness, unsigned contrast, rts8801_callback cbfunc, - void *param) + void *param, + double gamma) { unsigned char calib_info[9]; unsigned char calibbuf[2400]; struct dcalibdata dcd; struct calibdata cd; unsigned char *detail_buffer = 0; - int iCalibOffset; - int iCalibX; int iCalibY; - int iCalibWidth; int iCalibTarget; - int iCalibPixels; int iMoveFlags = 0; - unsigned int aiLow[3] = { 0, 0, 0 }; - unsigned int aiHigh[3] = { 256, 256, 256 }; - unsigned aiBestOffset[3]; + unsigned aiBestOffset[6]; + int aiPassed[6]; int i; unsigned j; - int anychanged; + int k; int calibration_size; unsigned char *pDetailedCalib; int red_calibration_offset; @@ -3121,7 +3349,13 @@ rts8801_scan (unsigned x, int resolution_index; int detailed_calibration_rows = 50; unsigned char *tdetail_buffer; - detailed_calibration_data detailed_calib_data; + int pass; + int onechanged; + double *postprocess_gains; + double *postprocess_offsets; + int needs_postprocessed_calibration = 0; + double contrast_adjust = (double) contrast / 64; + int brightness_adjust = brightness - 0x80; /* Initialise and power up */ @@ -3150,99 +3384,101 @@ rts8801_scan (unsigned x, calib_info[2] = calib_info[5] = calib_info[8] = 1; - calib_info[0] = calib_info[1] = calib_info[3] = calib_info[4] = - calib_info[6] = calib_info[7] = 0xb4; - - iCalibOffset = 0; /* Note that horizontal resolution is always 600dpi for calibration. 330 is 110 dots in (for R,G,B channels) */ - iCalibX = 1; - iCalibPixels = 50; - iCalibY = (resolution == 25) ? 1 : 2; /* Was 1200 / resolution, which would take us past the calibration area for 50dpi */ - iCalibWidth = 100; + iCalibY = (resolution == 25) ? 1 : 2; iCalibTarget = 550; + + rt_turn_off_lamp(); - for (i = 0; i < 3; ++i) - aiBestOffset[i] = 0xb4; - + for (i = 0; i < 6; ++i) + { + aiBestOffset[i] = 0xbf; + aiPassed[i] = 0; + } + do { DBG (30, "Initial calibration pass commences\n"); - anychanged = 0; - - for (i = 0; i < 3; ++i) - { - aiBestOffset[i] = (aiHigh[i] + aiLow[i] + 1) / 2; - } + onechanged = 0; for (i = 0; i < 3; ++i) - calib_info[i * 3] = calib_info[i * 3 + 1] = aiBestOffset[i]; - + { + calib_info[i * 3] = aiBestOffset[i]; + calib_info[i * 3 + 1] = aiBestOffset[i + 3]; + } + cd.buffer = calibbuf; cd.space = sizeof (calibbuf); DBG (30, "Commencing scan for initial calibration pass\n"); - rts8801_fullscan (iCalibX, iCalibY, iCalibWidth, 2, 600, resolution, + rts8801_fullscan (1401, iCalibY, 100, 2, 400, resolution, HP3500_COLOR_SCAN, (rts8801_callback) storefunc, &cd, - calib_info, iMoveFlags, -1, -1, -1, -1, 0); + calib_info, iMoveFlags, -1, -1, -1, -1, 0, 0); DBG (30, "Completed scan for initial calibration pass\n"); - iMoveFlags = RTS8801_F_SUPPRESS_MOVEMENT; + iMoveFlags = RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS; + iCalibY = 2; - for (i = 0; i < 3; ++i) + for (i = 0; i < 6; ++i) { int sum; - if (aiBestOffset[i] >= 255) + if (aiBestOffset[i] >= 255 || aiPassed[i] > 2) continue; - sum = sum_channel (calibbuf + iCalibOffset + i, iCalibPixels, 0); + sum = sum_channel (calibbuf + i, 50, 1); DBG (20, "channel[%d] sum = %d (target %d)\n", i, sum, iCalibTarget); - if (sum >= iCalibTarget) - aiHigh[i] = aiBestOffset[i]; - else - aiLow[i] = aiBestOffset[i]; + if (sum < iCalibTarget) + { + onechanged = 1; + ++aiBestOffset[i]; + } + else + { + ++aiPassed[i]; + } } DBG (30, "Initial calibration pass completed\n"); } - while (aiLow[0] < aiHigh[0] - 1 && aiLow[1] < aiHigh[1] - 1 - && aiLow[1] < aiHigh[1] + 1); + while (onechanged); DBG (20, "Offsets calculated\n"); - cd.buffer = calibbuf; - cd.space = sizeof (calibbuf); - DBG (20, "Scanning for part 2 of initial calibration\n"); - rts8801_fullscan (iCalibX + 2100, iCalibY, iCalibWidth, 2, 600, resolution, - HP3500_COLOR_SCAN, (rts8801_callback) storefunc, &cd, - calib_info, RTS8801_F_SUPPRESS_MOVEMENT, -1, -1, -1, -1, - 0); - DBG (20, "Scan for part 2 of initial calibration completed\n"); - DBG (20, "Initial calibration completed\n"); + rt_turn_on_lamp(); + usleep(500000); tdetail_buffer = (unsigned char *) malloc (w * 3 * detailed_calibration_rows); - aiLow[0] = aiLow[1] = aiLow[2] = 1; - aiHigh[0] = aiHigh[1] = aiHigh[2] = 64; + for (i = 0; i < 3; ++i) + { + calib_info[i * 3 + 2] = 1; + aiPassed[i] = 0; + } + do { struct dcalibdata dcdt; - for (i = 0; i < 3; ++i) - calib_info[i * 3 + 2] = (aiLow[i] + aiHigh[i]) / 2; - dcdt.buffers[0] = tdetail_buffer; dcdt.buffers[1] = (tdetail_buffer + w * detailed_calibration_rows); dcdt.buffers[2] = (dcdt.buffers[1] + w * detailed_calibration_rows); dcdt.pixelsperrow = w; dcdt.pixelnow = dcdt.channelnow = dcdt.firstrowdone = 0; + DBG (20, "Scanning for part 2 of initial calibration\n"); rts8801_fullscan (x, 4, w, detailed_calibration_rows + 1, resolution, resolution, HP3500_COLOR_SCAN, (rts8801_callback) accumfunc, &dcdt, calib_info, - RTS8801_F_SUPPRESS_MOVEMENT, -1, -1, -1, -1, 0); + RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS, -1, -1, -1, -1, 0, 0); + DBG (20, "Scan for part 2 of initial calibration completed\n"); + + onechanged = 0; for (i = 0; i < 3; ++i) { int largest = 1; - for (j = 0; j < w; ++j) + if (aiPassed[i] > 2 || calib_info[i * 3 + 2] >= 63) + continue; + + for (j = 0; j < w; ++j) { int val = calcmedian (dcdt.buffers[i], j, w, detailed_calibration_rows); @@ -3252,16 +3488,17 @@ rts8801_scan (unsigned x, } if (largest < 0xe0) - aiLow[i] = calib_info[i * 3 + 2]; - else - aiHigh[i] = calib_info[i * 3 + 2]; + { + ++calib_info[i * 3 + 2]; + onechanged = 1; + } + else + { + ++aiPassed[i]; + } } } - while (aiLow[0] < aiHigh[0] - 1 && aiLow[1] < aiHigh[1] - 1 - && aiLow[1] < aiHigh[1] + 1); - - for (i = 0; i < 3; ++i) - calib_info[i * 3 + 2] = aiLow[i]; + while (onechanged); for (i = 0; i < 3; ++i) { @@ -3282,15 +3519,7 @@ rts8801_scan (unsigned x, dcd.buffers[1] = (detail_buffer + w * detailed_calibration_rows); dcd.buffers[2] = (dcd.buffers[1] + w * detailed_calibration_rows); dcd.pixelsperrow = w; - dcd.pixelnow = dcd.channelnow = dcd.firstrowdone = 0; - - DBG (10, "Performing detailed calibration scan\n"); - rts8801_fullscan (x, iCalibY, w, detailed_calibration_rows + 1, - resolution, resolution, HP3500_COLOR_SCAN, - (rts8801_callback) accumfunc, &dcd, calib_info, - RTS8801_F_SUPPRESS_MOVEMENT, -1, -1, -1, -1, 0); - DBG (10, "Detailed calibration scan completed\n"); /* And now for the detailed calibration */ resolution_index = find_resolution_index (resolution); @@ -3301,101 +3530,221 @@ rts8801_scan (unsigned x, base_resolution *= 2; resolution_divisor = base_resolution / resolution; - calibration_size = w * resolution_divisor * 6 + 1536; - red_calibration_offset = 1536; - blue_calibration_offset = - red_calibration_offset + w * resolution_divisor * 2; + calibration_size = w * resolution_divisor * 6 + 1568 + 96; + red_calibration_offset = 0x600; green_calibration_offset = - blue_calibration_offset + w * resolution_divisor * 2; - end_calibration_offset = + red_calibration_offset + w * resolution_divisor * 2; + blue_calibration_offset = green_calibration_offset + w * resolution_divisor * 2; + end_calibration_offset = + blue_calibration_offset + w * resolution_divisor * 2; pDetailedCalib = (unsigned char *) malloc (calibration_size); memset (pDetailedCalib, 0, calibration_size); + for (i = 0; i < 3; ++i) { int idx = - (i == 0) ? red_calibration_offset : (i == - 1) ? green_calibration_offset : - blue_calibration_offset; - double g = calib_info[i * 3 + 2]; + (i == 0) ? red_calibration_offset : + (i == 1) ? green_calibration_offset : + blue_calibration_offset; for (j = 0; j < 256; j++) - { - int val = j; - - if (val < 0) - val = 0; - if (val > 255) - val = 255; - pDetailedCalib[i * 512 + j * 2] = val; - pDetailedCalib[i * 512 + j * 2 + 1] = val; - } + { + /* Gamma table - appears to be 256 byte pairs for each input + * range (so the first entry cover inputs in the range 0 to 1, + * the second 1 to 2, and so on), mapping that input range + * (including the fractional parts within it) to an output + * range. + */ + pDetailedCalib[i * 512 + j * 2] = j; + pDetailedCalib[i * 512 + j * 2 + 1] = j; + } for (j = 0; j < w; ++j) - { - int multnow; - int offnow; - - /* This seems to be the approach for reg 0x40 & 0x3f == 0x27, which allows detailed - * calibration to return either higher or lower values. - */ - int k; - - { - double denom1 = - calcmedian (dcd.buffers[i], j, w, detailed_calibration_rows); - double f = 0xff / (denom1 - 2 * g); - double contrast_adjust = (double) (contrast + 1) / 64; - - multnow = f * 64 * contrast_adjust; - offnow = 4 * g + 128 - brightness; - } - if (multnow < 0) - multnow = 0; - if (multnow > 255) - multnow = 255; - if (offnow < 0) - offnow = 0; - if (offnow > 255) - offnow = 255; - - for (k = 0; k < resolution_divisor; ++k) - { - /*multnow = j * resolution_divisor + k; */ - pDetailedCalib[idx++] = offnow; /* Subtract this value from the result */ - pDetailedCalib[idx++] = multnow; /* Then multiply by this value divided by 0x40 */ - } - } + { + for (k = 0; k < resolution_divisor; ++k) + { + pDetailedCalib[idx++] = 0; + pDetailedCalib[idx++] = 0x80; + } + } } - DBG (10, "\n"); - rt_set_sram_page (0); rt_set_one_register (0x93, r93setting); rt_write_sram (calibration_size, pDetailedCalib); - /* And finally, perform the scan */ + postprocess_gains = (double *) malloc(sizeof(double) * 3 * w); + postprocess_offsets = (double *) malloc(sizeof(double) * 3 * w); + + for (pass = 0; pass < DETAILED_PASS_COUNT; ++pass) + { + int ppidx = 0; + + DBG (10, "Performing detailed calibration scan %d\n", pass); + + switch (pass) + { + case DETAILED_PASS_OFFSETS: + rt_turn_off_lamp(); + usleep(500000); /* To be sure it has gone off */ + break; + + case DETAILED_PASS_GAINS_FIRSTPASS: + rt_turn_on_lamp(); + usleep(500000); /* Give the lamp time to settle */ + break; + } + + dcd.pixelnow = dcd.channelnow = dcd.firstrowdone = 0; + rts8801_fullscan (x, iCalibY, w, detailed_calibration_rows + 1, + resolution, resolution, HP3500_COLOR_SCAN, + (rts8801_callback) accumfunc, &dcd, + calib_info, + RTS8801_F_SUPPRESS_MOVEMENT | RTS8801_F_NO_DISPLACEMENTS, + red_calibration_offset, + green_calibration_offset, + blue_calibration_offset, + end_calibration_offset, + 0, 0); + + DBG (10, " Detailed calibration scan %d completed\n", pass); + + for (i = 0; i < 3; ++i) + { + int idx = + (i == 0) ? red_calibration_offset : + (i == 1) ? green_calibration_offset : + blue_calibration_offset; + + for (j = 0; j < w; ++j) + { + double multnow = 0x80; + int offnow = 0; + + /* This seems to be the approach for reg 0x40 & 0x3f == 0x27, which allows detailed + * calibration to return either higher or lower values. + */ + + { + double denom1 = + calcmedian (dcd.buffers[i], j, w, detailed_calibration_rows); + + switch (pass) + { + case DETAILED_PASS_OFFSETS: + /* The offset is the number needed to be subtracted from "black" at detailed gain = 0x80, + * which is the value we started with. For the next round, pull the gain down to 0x20. Our + * next scan is a test scan to confirm the offset works. + */ + multnow = 0x20; + offnow = denom1; + break; + + case DETAILED_PASS_GAINS_FIRSTPASS: + multnow = 128.0 / denom1 * 0x20; /* Then bring it up to whatever we need to hit 192 */ + if (multnow > 255) + multnow = 255; + offnow = pDetailedCalib[idx]; + break; + + case DETAILED_PASS_GAINS_SECONDPASS: + multnow = 255.0 / denom1 * contrast_adjust * pDetailedCalib[idx+1]; /* And finally to 255 */ + offnow = pDetailedCalib[idx] - brightness_adjust * 0x80 / multnow; + + if (offnow < 0) + { + postprocess_offsets[ppidx] = multnow * offnow / 0x80; + offnow = 0; + needs_postprocessed_calibration = 1; + } + else if (offnow > 255) + { + postprocess_offsets[ppidx] = multnow * (offnow - 255) / 0x80; + offnow = 255; + needs_postprocessed_calibration = 1; + } + else + { + postprocess_offsets[ppidx] = 0; + } + if (multnow > 255) + { + postprocess_gains[ppidx] = multnow / 255; + multnow = 255; + needs_postprocessed_calibration = 1; + } + else + { + postprocess_gains[ppidx] = 1.0; + } + break; + } + } + if (offnow > 255) + offnow = 255; + + for (k = 0; k < resolution_divisor; ++k) + { + pDetailedCalib[idx++] = offnow; /* Subtract this value from the result at gains = 0x80*/ + pDetailedCalib[idx++] = multnow; /* Then multiply by this value divided by 0x80 */ + } + ++ppidx; + } + } + + if (pass == DETAILED_PASS_GAINS_SECONDPASS) + { + /* Build gamma table */ + unsigned char *redgamma = pDetailedCalib; + unsigned char *greengamma = redgamma + 512; + unsigned char *bluegamma = greengamma + 512; + double val; + double invgamma = 1.0l / gamma; + + *redgamma++ = *bluegamma++ = *greengamma++ = 0; + + /* The windows driver does a linear interpolation for the next 19 boundaries */ + val = pow (20.0l / 255, invgamma) * 255; + + for (j = 1; j <= 20; ++j) + { + *redgamma++ = *bluegamma++ = *greengamma++ = val * j / 20 + 0.5; + *redgamma++ = *bluegamma++ = *greengamma++ = val * j / 20 + 0.5; + } + + for (; j <= 255; ++j) + { + val = pow((double) j / 255, invgamma) * 255; + + *redgamma++ = *bluegamma++ = *greengamma++ = val + 0.5; + *redgamma++ = *bluegamma++ = *greengamma++ = val + 0.5; + } + *redgamma++ = *bluegamma++ = *greengamma++ = 255; + } + + DBG (10, "\n"); + + rt_set_sram_page (0); + rt_set_one_register (0x93, r93setting); + rt_write_sram (calibration_size, pDetailedCalib); + } + /* And finally, perform the scan */ DBG (10, "Scanning\n"); rts8801_rewind (); - detailed_calib_data.channeldata[0] = - pDetailedCalib + red_calibration_offset; - detailed_calib_data.channeldata[1] = - pDetailedCalib + green_calibration_offset; - detailed_calib_data.channeldata[2] = - pDetailedCalib + blue_calibration_offset; - detailed_calib_data.resolution_divisor = resolution_divisor; - rts8801_fullscan (x, y, w, h, resolution, resolution, colour, cbfunc, param, calib_info, 0, red_calibration_offset, green_calibration_offset, blue_calibration_offset, end_calibration_offset, - &detailed_calib_data); + needs_postprocessed_calibration ? postprocess_offsets : 0, + needs_postprocessed_calibration ? postprocess_gains : 0); rt_turn_off_lamp (); + rts8801_rewind (); rt_set_powersave_mode (1); @@ -3403,6 +3752,12 @@ rts8801_scan (unsigned x, free (pDetailedCalib); if (detail_buffer) free (detail_buffer); + if (tdetail_buffer) + free(tdetail_buffer); + if (postprocess_gains) + free(postprocess_gains); + if (postprocess_offsets) + free(postprocess_offsets); return 0; } @@ -3466,7 +3821,6 @@ reader_process (void *pv) sigaction (SIGTERM, &act, 0); } - /* Warm up the lamp again if our last scan ended more than 5 minutes ago. */ time (&t); do_warmup = (t - scanner->last_scan) > 300; @@ -3498,9 +3852,25 @@ reader_process (void *pv) scanner->actres_pixels.right - scanner->actres_pixels.left, scanner->actres_pixels.bottom - scanner->actres_pixels.top, scanner->resolution, scanner->mode, scanner->brightness, - scanner->contrast, (rts8801_callback) writefunc, &winfo) >= 0) + scanner->contrast, (rts8801_callback) writefunc, &winfo, + scanner->gamma) >= 0) status = SANE_STATUS_GOOD; status = SANE_STATUS_IO_ERROR; close (scanner->pipe_w); return status; } + +static size_t +max_string_size (char const **strings) +{ + size_t size, max_size = 0; + SANE_Int i; + + for (i = 0; strings[i]; ++i) + { + size = strlen (strings[i]) + 1; + if (size > max_size) + max_size = size; + } + return max_size; +} diff --git a/backend/hp3900_sane.c b/backend/hp3900_sane.c index b815572..410e35e 100644 --- a/backend/hp3900_sane.c +++ b/backend/hp3900_sane.c @@ -1159,7 +1159,7 @@ options_init (TScanner * scanner) TOptionValue *pVal; /* set gamma */ - gamma_create (scanner, 2.2); + gamma_create (scanner, 1.0); /* color convertion */ scanner->cnv.colormode = -1; diff --git a/backend/hp4200.c b/backend/hp4200.c index a069be6..589157d 100644 --- a/backend/hp4200.c +++ b/backend/hp4200.c @@ -698,7 +698,6 @@ compute_first_gain_offset (int target, int max, int min, int *gain, static int write_gamma (HP4200_Scanner * s) { - SANE_Status status; int color; int i; unsigned char gamma[1024]; @@ -728,7 +727,7 @@ write_gamma (HP4200_Scanner * s) sanei_pv8630_write_byte (s->fd, PV8630_REPPADDRESS, 0x06); sanei_pv8630_prep_bulkread (s->fd, sizeof (read_gamma)); to_read = sizeof (read_gamma); - status = sanei_usb_read_bulk (s->fd, read_gamma, &to_read); + sanei_usb_read_bulk (s->fd, read_gamma, &to_read); retval = memcmp (read_gamma, gamma, sizeof (read_gamma)); if (retval != 0) { @@ -1047,7 +1046,6 @@ do_coarse_calibration (HP4200_Scanner * s, struct coarse_t *coarse) int step_size; int ff_step_size; char steps_to_reverse; - char hdpi_div; char line_rate_color; int vdpi; /* vertical dots per inch */ int hdpi_code; @@ -1085,7 +1083,6 @@ do_coarse_calibration (HP4200_Scanner * s, struct coarse_t *coarse) vdpi = 150; hdpi_code = 0; - hdpi_div = hdpi_mapping[hdpi_code]; active_pixels_start = 0x40; line_end = 0x2ee0; s->mclk_div = 2; @@ -1395,7 +1392,6 @@ do_fine_calibration (HP4200_Scanner * s, struct coarse_t *coarse) int vdpi; /* vertical dots per inch */ int hdpi_code; int calibrated; - int first_time; int lines_to_process; static char me[] = "do_fine_calibration"; @@ -1495,7 +1491,6 @@ do_fine_calibration (HP4200_Scanner * s, struct coarse_t *coarse) cache_write (s); calibrated = 0; - first_time = 1; cal_line = malloc (cal_line_size + 1024); average = malloc (sizeof (int) * line_length * 3); memset (average, 0, sizeof (int) * line_length * 3); @@ -2437,7 +2432,7 @@ sane_exit (void) } if (device->dev.name) { - free (device->dev.name); + free ((void *) device->dev.name); } free (device); } diff --git a/backend/hp5400.c b/backend/hp5400.c index 61de3db..cfa2dc9 100644 --- a/backend/hp5400.c +++ b/backend/hp5400.c @@ -67,6 +67,9 @@ #include /* malloc, free */ #include /* memcpy */ #include +#ifdef HAVE_SYS_TYPES_H +#include +#endif #define HP5400_CONFIG_FILE "hp5400.conf" diff --git a/backend/hp5400_internal.c b/backend/hp5400_internal.c index d7e2325..65a434f 100644 --- a/backend/hp5400_internal.c +++ b/backend/hp5400_internal.c @@ -282,7 +282,9 @@ SetCalibration (int iHandle, int numPixels, unsigned int *low_vals[3], cmd[3] = 0x00; cmd[4] = 0x54; cmd[5] = 0x02; - cmd[6] = 0x80; + cmd[6] = -128; // 0x80; fixes compiler warning (for + // signed char implementations), see + // also comment above cmd[7] = 0x00; hp5400_bulk_command_write (iHandle, 0xE603, cmd, 8, calSize, calSize, diff --git a/backend/hp5590.c b/backend/hp5590.c index 7b1cd60..fabf40a 100644 --- a/backend/hp5590.c +++ b/backend/hp5590.c @@ -48,6 +48,9 @@ #include #include #include +#ifdef HAVE_SYS_TYPES_H +#include +#endif #include "../include/sane/sane.h" #define BACKEND_NAME hp5590 @@ -168,7 +171,7 @@ calc_image_params (struct hp5590_scanner *scanner, unsigned int _image_size; float var; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); if (!scanner) return SANE_STATUS_INVAL; @@ -196,7 +199,7 @@ calc_image_params (struct hp5590_scanner *scanner, DBG (DBG_verbose, "%s: pixel_bits: %u, pixels_per_line: %u, " "bytes_per_line: %u, lines: %u, image_size: %u\n", - __FUNCTION__, + __func__, _pixel_bits, _pixels_per_line, _bytes_per_line, _lines, _image_size); if (pixel_bits) @@ -229,10 +232,10 @@ attach_usb_device (SANE_String_Const devname, SANE_Status ret; const struct hp5590_model *hp5590_model; - DBG (DBG_proc, "%s: Opening USB device\n", __FUNCTION__); + DBG (DBG_proc, "%s: Opening USB device\n", __func__); if (sanei_usb_open (devname, &dn) != SANE_STATUS_GOOD) return SANE_STATUS_IO_ERROR; - DBG (DBG_proc, "%s: USB device opened\n", __FUNCTION__); + DBG (DBG_proc, "%s: USB device opened\n", __func__); ret = hp5590_model_def (hp_scanner_type, &hp5590_model); if (ret != SANE_STATUS_GOOD) @@ -243,19 +246,19 @@ attach_usb_device (SANE_String_Const devname, return SANE_STATUS_IO_ERROR; DBG (1, "%s: found HP%s scanner at '%s'\n", - __FUNCTION__, info->model, devname); + __func__, info->model, devname); - DBG (DBG_verbose, "%s: Reading max scan count\n", __FUNCTION__); + DBG (DBG_verbose, "%s: Reading max scan count\n", __func__); if (hp5590_read_max_scan_count (dn, hp5590_model->proto_flags, &max_count) != 0) return SANE_STATUS_IO_ERROR; - DBG (DBG_verbose, "%s: Max Scanning count %u\n", __FUNCTION__, max_count); + DBG (DBG_verbose, "%s: Max Scanning count %u\n", __func__, max_count); - DBG (DBG_verbose, "%s: Reading scan count\n", __FUNCTION__); + DBG (DBG_verbose, "%s: Reading scan count\n", __func__); if (hp5590_read_scan_count (dn, hp5590_model->proto_flags, &count) != 0) return SANE_STATUS_IO_ERROR; - DBG (DBG_verbose, "%s: Scanning count %u\n", __FUNCTION__, count); + DBG (DBG_verbose, "%s: Scanning count %u\n", __func__, count); ret = hp5590_read_part_number (dn, hp5590_model->proto_flags); if (ret != SANE_STATUS_GOOD) @@ -381,7 +384,7 @@ void sane_exit (void) { struct hp5590_scanner *ptr, *pnext; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); for (ptr = scanners_list; ptr; ptr = pnext) { @@ -399,7 +402,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) struct hp5590_scanner *ptr; unsigned int found, i; - DBG (DBG_proc, "%s, local only: %u\n", __FUNCTION__, local_only); + DBG (DBG_proc, "%s, local only: %u\n", __func__, local_only); if (!device_list) return SANE_STATUS_INVAL; @@ -431,7 +434,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) SANE_String_Const *sources_list; unsigned int source_idx; - DBG (DBG_proc, "%s: device name: %s\n", __FUNCTION__, devicename); + DBG (DBG_proc, "%s: device name: %s\n", __func__, devicename); if (!handle) return SANE_STATUS_INVAL; @@ -623,7 +626,7 @@ sane_close (SANE_Handle handle) { struct hp5590_scanner *scanner = handle; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); sanei_usb_close (scanner->dn); scanner->dn = -1; @@ -635,7 +638,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) { struct hp5590_scanner *scanner = handle; - DBG (DBG_proc, "%s, option: %u\n", __FUNCTION__, option); + DBG (DBG_proc, "%s, option: %u\n", __func__, option); if (option >= HP5590_OPT_LAST) return NULL; @@ -664,7 +667,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { if (option == HP5590_OPT_NUM) { - DBG(3, "%s: get total number of options - %u\n", __FUNCTION__, HP5590_OPT_LAST); + DBG(3, "%s: get total number of options - %u\n", __func__, HP5590_OPT_LAST); *((SANE_Int *) value) = HP5590_OPT_LAST; return SANE_STATUS_GOOD; } @@ -672,7 +675,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (!scanner->opts) return SANE_STATUS_INVAL; - DBG (DBG_proc, "%s: get option '%s' value\n", __FUNCTION__, scanner->opts[option].name); + DBG (DBG_proc, "%s: get option '%s' value\n", __func__, scanner->opts[option].name); if (option == HP5590_OPT_BR_X) { @@ -923,7 +926,7 @@ SANE_Status sane_get_parameters (SANE_Handle handle, SANE_Status ret; unsigned int pixel_bits; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); if (!params) return SANE_STATUS_INVAL; @@ -961,7 +964,7 @@ SANE_Status sane_get_parameters (SANE_Handle handle, params->format = SANE_FRAME_RGB; break; default: - DBG(0, "%s: Unknown depth\n", __FUNCTION__); + DBG(0, "%s: Unknown depth\n", __func__); return SANE_STATUS_INVAL; } @@ -983,7 +986,7 @@ sane_start (SANE_Handle handle) SANE_Status ret; unsigned int bytes_per_line; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); if (!scanner) return SANE_STATUS_INVAL; @@ -993,11 +996,11 @@ sane_start (SANE_Handle handle) || scanner->source == SOURCE_ADF_DUPLEX)) { DBG (DBG_verbose, "%s: Scanner is scanning, check if more data is available\n", - __FUNCTION__); + __func__); ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags); if (ret == SANE_STATUS_GOOD) { - DBG (DBG_verbose, "%s: More data is available\n", __FUNCTION__); + DBG (DBG_verbose, "%s: More data is available\n", __func__); scanner->transferred_image_size = scanner->image_size; return SANE_STATUS_GOOD; } @@ -1147,7 +1150,7 @@ convert_lineart (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size) { SANE_Int i; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_assert (scanner != NULL); hp5590_assert (data != NULL); @@ -1182,7 +1185,7 @@ convert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size) || scanner->depth == DEPTH_GRAY) return SANE_STATUS_GOOD; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); #ifndef HAS_WORKING_COLOR_48 if (scanner->depth == DEPTH_COLOR_48) @@ -1263,7 +1266,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Status ret; DBG (DBG_proc, "%s, length %u, left %u\n", - __FUNCTION__, + __func__, max_length, scanner->transferred_image_size); @@ -1282,7 +1285,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, if (ret != SANE_STATUS_GOOD) return ret; - /* Dont free bulk read state, some bytes could be left + /* Don't free bulk read state, some bytes could be left * for the next images from ADF */ return SANE_STATUS_EOF; @@ -1350,7 +1353,7 @@ sane_cancel (SANE_Handle handle) struct hp5590_scanner *scanner = handle; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); scanner->scanning = SANE_FALSE; @@ -1370,7 +1373,7 @@ SANE_Status sane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ non_blocking) { - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); return SANE_STATUS_UNSUPPORTED; } @@ -1380,7 +1383,7 @@ SANE_Status sane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd) { - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); return SANE_STATUS_UNSUPPORTED; } diff --git a/backend/hp5590_cmds.c b/backend/hp5590_cmds.c index 894101b..06fd91a 100644 --- a/backend/hp5590_cmds.c +++ b/backend/hp5590_cmds.c @@ -483,7 +483,7 @@ hp5590_init_scanner (SANE_Int dn, * 09 60 4F B0 6D E0 00 00 00 00 00 00 00 00 00 64 ..O.m..........d * 03 E8 .. */ - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (init_resp) == 50); @@ -512,7 +512,7 @@ hp5590_init_scanner (SANE_Int dn, { DBG (DBG_err, "%s: Vendor id mismatch for scanner HP%s - " "required '%s', got '%s'\n", - __FUNCTION__, + __func__, hp5590_models[i].model, hp5590_models[i].vendor_id, id_buf); return SANE_STATUS_INVAL; @@ -593,10 +593,10 @@ hp5590_init_scanner (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: scanner reports non-zero status: %s\n", - __FUNCTION__, sane_strstatus (ret)); + __func__, sane_strstatus (ret)); return ret; } - DBG (DBG_cmds, "%s: scanner status OK\n", __FUNCTION__); + DBG (DBG_cmds, "%s: scanner status OK\n", __func__); return SANE_STATUS_GOOD; } @@ -614,7 +614,7 @@ hp5590_read_eeprom (SANE_Int dn, hp5590_cmds_assert (data != NULL); hp5590_cmds_assert (sizeof (eeprom_addr) == 1); - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); DBG (DBG_proc, "Reading EEPROM: addr %04x, size %u\n", addr, size); ret = hp5590_cmd (dn, @@ -649,7 +649,7 @@ hp5590_write_eeprom (SANE_Int dn, hp5590_cmds_assert (data != NULL); hp5590_cmds_assert (sizeof (eeprom_addr) == 1); - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); DBG (DBG_proc, "Writing EEPROM: addr %04x, size: %u\n", addr, size); ret = hp5590_cmd (dn, @@ -683,7 +683,7 @@ hp5590_read_scan_count (SANE_Int dn, hp5590_cmds_assert (count != NULL); hp5590_cmds_assert (sizeof (scan_count) == 4); - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); DBG (DBG_proc, "Reading scan count\n"); ret = hp5590_read_eeprom (dn, @@ -713,7 +713,7 @@ hp5590_inc_scan_count (SANE_Int dn, unsigned int new_count; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (scan_count) == 4); ret = hp5590_read_scan_count (dn, proto_flags, &count); @@ -756,7 +756,7 @@ hp5590_read_max_scan_count (SANE_Int dn, hp5590_cmds_assert (max_count != NULL); hp5590_cmds_assert (sizeof (max_scan_count) == 3); - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); DBG (DBG_proc, "Reading max scan count\n"); ret = hp5590_read_eeprom (dn, @@ -811,7 +811,7 @@ hp5590_read_eeprom_all_cmd (SANE_Int dn, uint8_t eeprom[255]; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); ret = hp5590_read_eeprom (dn, proto_flags, @@ -835,7 +835,7 @@ hp5590_read_part_number (SANE_Int dn, unsigned char part_number[PART_NUMBER_LEN + 1]; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); memset (part_number, 0, sizeof (part_number)); ret = hp5590_read_eeprom (dn, @@ -859,7 +859,7 @@ hp5590_is_data_available (SANE_Int dn, SANE_Status ret; SANE_Bool data_available; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (data_status) == 1); data_available = SANE_FALSE; @@ -873,13 +873,13 @@ hp5590_is_data_available (SANE_Int dn, if (ret != SANE_STATUS_GOOD) return ret; - DBG (DBG_cmds, "%s: Data status: %02x\n", __FUNCTION__, data_status); + DBG (DBG_cmds, "%s: Data status: %02x\n", __func__, data_status); if (data_status == 0x40) data_available = SANE_TRUE; DBG (DBG_cmds, "%s: Data is %s\n", - __FUNCTION__, + __func__, data_available == SANE_TRUE ? "available" : "not available"); return data_available == SANE_TRUE ? SANE_STATUS_GOOD : SANE_STATUS_NO_DOCS; @@ -893,7 +893,7 @@ hp5590_stop_scan (SANE_Int dn, uint8_t reg_011b = 0x40; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (reg_011b) == 1); @@ -920,7 +920,7 @@ hp5590_turnon_lamp (SANE_Int dn, struct lamp_state lamp_state; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (lamp_state) == 4); @@ -930,7 +930,7 @@ hp5590_turnon_lamp (SANE_Int dn, lamp_state.unk1 = 0x02; lamp_state.flag = 0x01; lamp_state.turnoff_time = htons (0x0a0a); - DBG (DBG_cmds, "%s: turning lamp on\n", __FUNCTION__); + DBG (DBG_cmds, "%s: turning lamp on\n", __func__); } if (state == LAMP_STATE_TURNOFF) @@ -939,7 +939,7 @@ hp5590_turnon_lamp (SANE_Int dn, lamp_state.unk1 = 0x02; lamp_state.flag = 0x02; lamp_state.turnoff_time = htons (0x0a0a); - DBG (DBG_cmds, "%s: turning lamp off\n", __FUNCTION__); + DBG (DBG_cmds, "%s: turning lamp off\n", __func__); } if (state == LAMP_STATE_SET_TURNOFF_TIME) @@ -948,7 +948,7 @@ hp5590_turnon_lamp (SANE_Int dn, lamp_state.unk1 = 0x02; lamp_state.flag = 0x03; lamp_state.turnoff_time = htons (0x0336); - DBG (DBG_cmds, "%s: setting turnoff time\n", __FUNCTION__); + DBG (DBG_cmds, "%s: setting turnoff time\n", __func__); } if (state == LAMP_STATE_SET_TURNOFF_TIME_LONG) @@ -957,7 +957,7 @@ hp5590_turnon_lamp (SANE_Int dn, lamp_state.unk1 = 0x02; lamp_state.flag = 0x03; lamp_state.turnoff_time = htons (0x0f36); - DBG (DBG_cmds, "%s: setting long turnoff time\n", __FUNCTION__); + DBG (DBG_cmds, "%s: setting long turnoff time\n", __func__); } ret = hp5590_cmd (dn, @@ -987,7 +987,7 @@ hp5590_power_status (SANE_Int dn, struct power_resp power_resp; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (power_resp) == 3); @@ -1023,7 +1023,7 @@ hp5590_read_error_code (SANE_Int dn, struct reg_03 reg_03; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (reg_03) == 3); hp5590_cmds_assert (adf_flags != NULL); @@ -1040,9 +1040,9 @@ hp5590_read_error_code (SANE_Int dn, if (ret != SANE_STATUS_GOOD) return ret; - DBG (DBG_cmds, "%s: adf_flags: %04x\n", __FUNCTION__, reg_03.adf_flags); - DBG (DBG_cmds, "%s: unk1 : %04x\n", __FUNCTION__, reg_03.unk1); - DBG (DBG_cmds, "%s: unk2 : %04x\n", __FUNCTION__, reg_03.unk2); + DBG (DBG_cmds, "%s: adf_flags: %04x\n", __func__, reg_03.adf_flags); + DBG (DBG_cmds, "%s: unk1 : %04x\n", __func__, reg_03.unk1); + DBG (DBG_cmds, "%s: unk2 : %04x\n", __func__, reg_03.unk2); *adf_flags = reg_03.adf_flags; @@ -1056,7 +1056,7 @@ hp5590_reset_scan_head (SANE_Int dn, { SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); ret = hp5590_turnon_lamp (dn, proto_flags, LAMP_STATE_TURNOFF); if (ret != SANE_STATUS_GOOD) @@ -1082,7 +1082,7 @@ hp5590_select_source_and_wakeup (SANE_Int dn, SANE_Status ret; unsigned int adf_flags; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (reg_d6) == 1); @@ -1161,7 +1161,7 @@ hp5590_lock_unlock_scanner (SANE_Int dn, unsigned int adf_flags; unsigned int waiting; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (reg_00) == 1); for (waiting = 0; waiting < WAKEUP_TIMEOUT; waiting++, sleep (1)) @@ -1206,7 +1206,7 @@ hp5590_set_base_dpi (SANE_Int dn, uint16_t _base_dpi; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (scanner_info != NULL); hp5590_cmds_assert (base_dpi != 0); @@ -1246,7 +1246,7 @@ hp5590_set_color_map (SANE_Int dn, struct color_map color_map; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (color_map) == 18); hp5590_cmds_assert (base_dpi != 0); @@ -1301,7 +1301,7 @@ static SANE_Status calc_base_dpi (unsigned int dpi, unsigned int *base_dpi) { - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (base_dpi != NULL); hp5590_cmds_assert (dpi != 0); @@ -1346,7 +1346,7 @@ calc_base_dpi (unsigned int dpi, unsigned int *base_dpi) static SANE_Status calc_scanner_dpi (unsigned int dpi, unsigned int *scanner_dpi) { - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (scanner_dpi != NULL); hp5590_cmds_assert (dpi != 0); @@ -1399,7 +1399,7 @@ hp5590_calc_pixel_bits (unsigned int dpi, enum color_depths color_depth, unsigned int scanner_dpi; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (pixel_bits != NULL); hp5590_cmds_assert (dpi != 0); @@ -1465,7 +1465,7 @@ hp5590_set_scan_area (SANE_Int dn, unsigned int pixels_y; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (scan_params) == 37); hp5590_cmds_assert (dpi != 0); @@ -1579,14 +1579,14 @@ hp5590_set_scan_area (SANE_Int dn, if (top_x + pixels_x > max_pixels_x_current_dpi) { - DBG (DBG_err, "Top X (%u) + pixels X (%u) exceedes max X %u\n", + DBG (DBG_err, "Top X (%u) + pixels X (%u) exceeds max X %u\n", top_x, pixels_x, max_pixels_x_current_dpi); return SANE_STATUS_INVAL; } if (top_y + pixels_y > max_pixels_y_current_dpi) { - DBG (DBG_err, "Top Y (%u) + pixels Y (%u) exceedes max Y %u\n", + DBG (DBG_err, "Top Y (%u) + pixels Y (%u) exceeds max Y %u\n", top_y, pixels_y, max_pixels_y_current_dpi); return SANE_STATUS_INVAL; } @@ -1628,7 +1628,7 @@ hp5590_read_image_params (SANE_Int dn, struct image_params image_params; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (image_params) == 16); @@ -1676,7 +1676,7 @@ hp5590_set_scan_params (SANE_Int dn, unsigned int base_dpi; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (scanner_info != NULL); hp5590_cmds_assert (dpi != 0); @@ -1754,7 +1754,7 @@ hp5590_send_reverse_calibration_map (SANE_Int dn, unsigned int len; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); DBG (DBG_proc, "Preparing reverse calibration map\n"); val = 0xffff; len = reverse_map_size / 4; @@ -1805,7 +1805,7 @@ hp5590_send_forward_calibration_maps (SANE_Int dn, unsigned int i; uint16_t val; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); DBG (DBG_proc, "Preparing forward calibration map\n"); val = 0x0000; for (i = 0; i < forward_map_size; i++) @@ -1852,7 +1852,7 @@ hp5590_read (SANE_Int dn, { SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (bytes != NULL); hp5590_cmds_assert (state != NULL); @@ -1872,7 +1872,7 @@ hp5590_start_scan (SANE_Int dn, uint8_t reg_051b = 0x40; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (reg_051b) == 1); @@ -1897,7 +1897,7 @@ hp5590_read_buttons (SANE_Int dn, uint16_t button_status; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (status != NULL); hp5590_cmds_assert (sizeof (button_status) == 2); diff --git a/backend/hp5590_low.c b/backend/hp5590_low.c index 51da01a..4961fd7 100644 --- a/backend/hp5590_low.c +++ b/backend/hp5590_low.c @@ -143,7 +143,7 @@ hp5590_get_ack (SANE_Int dn, if (proto_flags & PF_NO_USB_IN_USB_ACK) return SANE_STATUS_GOOD; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); /* Check if USB-in-USB operation was accepted */ ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, @@ -152,17 +152,17 @@ hp5590_get_ack (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error getting acknowledge\n", - __FUNCTION__); + __func__); return ret; } - DBG (DBG_usb, "%s: USB-in-USB: accepted\n", __FUNCTION__); + DBG (DBG_usb, "%s: USB-in-USB: accepted\n", __func__); /* Check if we received correct acknowledgement */ if (status != 0x01) { DBG (DBG_err, "%s: USB-in-USB: not accepted (status %u)\n", - __FUNCTION__, status); + __func__, status); return SANE_STATUS_DEVICE_BUSY; } @@ -186,7 +186,7 @@ hp5590_get_status (SANE_Int dn, uint8_t status; SANE_Status ret; - DBG (DBG_proc, "%s\n", __FUNCTION__); + DBG (DBG_proc, "%s\n", __func__); ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, 0x0c, 0x8e, 0x00, @@ -194,7 +194,7 @@ hp5590_get_status (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error getting device status\n", - __FUNCTION__); + __func__); return ret; } @@ -202,7 +202,7 @@ hp5590_get_status (SANE_Int dn, if (status != 0x00) { DBG (DBG_err, "%s: USB-in-USB: got non-zero device status (status %u)\n", - __FUNCTION__, status); + __func__, status); return SANE_STATUS_DEVICE_BUSY; } @@ -244,7 +244,7 @@ hp5590_control_msg (SANE_Int dn, unsigned int needed_response; DBG (DBG_proc, "%s: USB-in-USB: core data: %s\n", - __FUNCTION__, core_flags & CORE_DATA ? "yes" : "no"); + __func__, core_flags & CORE_DATA ? "yes" : "no"); hp5590_low_assert (bytes != NULL); @@ -259,7 +259,7 @@ hp5590_control_msg (SANE_Int dn, ctrl.wIndex = htons (index); ctrl.wLength = htole16 (size); - DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __FUNCTION__); + DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __func__); /* Send USB-in-USB control message */ ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 0x04, 0x8f, 0x00, @@ -267,7 +267,7 @@ hp5590_control_msg (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error sending control message\n", - __FUNCTION__); + __func__); return ret; } @@ -292,7 +292,7 @@ hp5590_control_msg (SANE_Int dn, 0x90, 0x00, next_packet_size, ptr); if (ret != SANE_STATUS_GOOD) { - DBG (DBG_err, "%s: USB-in-USB: error reading data\n", __FUNCTION__); + DBG (DBG_err, "%s: USB-in-USB: error reading data\n", __func__); return ret; } @@ -308,7 +308,7 @@ hp5590_control_msg (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error confirming data reception\n", - __FUNCTION__); + __func__); return -1; } @@ -329,7 +329,7 @@ hp5590_control_msg (SANE_Int dn, ctrl.wIndex = htons (index); ctrl.wLength = htole16 (size); - DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __FUNCTION__); + DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __func__); /* Send USB-in-USB control message */ ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 0x04, 0x8f, 0x00, @@ -337,7 +337,7 @@ hp5590_control_msg (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error sending control message\n", - __FUNCTION__); + __func__); return ret; } @@ -362,7 +362,7 @@ hp5590_control_msg (SANE_Int dn, 0x8f, 0x00, next_packet_size, ptr); if (ret != SANE_STATUS_GOOD) { - DBG (DBG_err, "%s: USB-in-USB: error sending data\n", __FUNCTION__); + DBG (DBG_err, "%s: USB-in-USB: error sending data\n", __func__); return ret; } @@ -389,13 +389,13 @@ hp5590_control_msg (SANE_Int dn, } /* Getting response after data transmission */ - DBG (DBG_usb, "%s: USB-in-USB: getting response\n", __FUNCTION__); + DBG (DBG_usb, "%s: USB-in-USB: getting response\n", __func__); ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, 0x0c, 0x90, 0x00, sizeof (response), &response); if (ret != SANE_STATUS_GOOD) { - DBG (DBG_err, "%s: USB-in-USB: error getting response\n", __FUNCTION__); + DBG (DBG_err, "%s: USB-in-USB: error getting response\n", __func__); return ret; } @@ -405,14 +405,14 @@ hp5590_control_msg (SANE_Int dn, needed_response = core_flags & CORE_BULK_OUT ? 0x24 : 0x00; if (response == needed_response) DBG (DBG_usb, "%s: USB-in-USB: got correct response\n", - __FUNCTION__); + __func__); if (response != needed_response) { DBG (DBG_err, "%s: USB-in-USB: invalid response received " "(needed %04x, got %04x)\n", - __FUNCTION__, needed_response, response); + __func__, needed_response, response); return SANE_STATUS_IO_ERROR; } @@ -421,7 +421,7 @@ hp5590_control_msg (SANE_Int dn, { uint8_t bulk_flags = 0x24; DBG (DBG_usb, "%s: USB-in-USB: sending bulk flags\n", - __FUNCTION__); + __func__); ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 0x0c, 0x83, 0x00, @@ -429,7 +429,7 @@ hp5590_control_msg (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n", - __FUNCTION__); + __func__); return ret; } @@ -467,7 +467,7 @@ hp5590_verify_last_cmd (SANE_Int dn, SANE_Status ret; DBG (3, "%s: USB-in-USB: command verification requested\n", - __FUNCTION__); + __func__); /* Read last command along with CORE status */ ret = hp5590_control_msg (dn, @@ -489,17 +489,17 @@ hp5590_verify_last_cmd (SANE_Int dn, /* Verify last command */ DBG (DBG_usb, "%s: USB-in-USB: command verification %04x, " "last command: %04x, core status: %04x\n", - __FUNCTION__, verify_cmd, last_cmd, core_status); + __func__, verify_cmd, last_cmd, core_status); if ((cmd & 0x00ff) != last_cmd) { DBG (DBG_err, "%s: USB-in-USB: command verification failed: " "expected 0x%04x, got 0x%04x\n", - __FUNCTION__, cmd, last_cmd); + __func__, cmd, last_cmd); return SANE_STATUS_IO_ERROR; } DBG (DBG_usb, "%s: USB-in-USB: command verified successfully\n", - __FUNCTION__); + __func__); /* Return value depends on CORE status */ return core_status & CORE_FLAG_NOT_READY ? @@ -534,7 +534,7 @@ hp5590_cmd (SANE_Int dn, { SANE_Status ret; - DBG (3, "%s: USB-in-USB: command : %04x\n", __FUNCTION__, cmd); + DBG (3, "%s: USB-in-USB: command : %04x\n", __func__, cmd); ret = hp5590_control_msg (dn, proto_flags, @@ -568,7 +568,7 @@ hp5590_low_init_bulk_read_state (void **state) { struct bulk_read_state *bulk_read_state; - DBG (3, "%s: USB-in-USB: initializing bulk read state\n", __FUNCTION__); + DBG (3, "%s: USB-in-USB: initializing bulk read state\n", __func__); hp5590_low_assert (state != NULL); @@ -582,7 +582,7 @@ hp5590_low_init_bulk_read_state (void **state) if (!bulk_read_state->buffer) { DBG (DBG_err, "%s: Memory allocation failed for %u bytes\n", - __FUNCTION__, ALLOCATE_BULK_READ_PAGES * BULK_READ_PAGE_SIZE); + __func__, ALLOCATE_BULK_READ_PAGES * BULK_READ_PAGE_SIZE); return SANE_STATUS_NO_MEM; } bulk_read_state->buffer_size = ALLOCATE_BULK_READ_PAGES @@ -613,7 +613,7 @@ hp5590_low_free_bulk_read_state (void **state) { struct bulk_read_state *bulk_read_state; - DBG (3, "%s\n", __FUNCTION__); + DBG (3, "%s\n", __func__); hp5590_low_assert (state != NULL); /* Just return if NULL bulk read state was given */ @@ -622,7 +622,7 @@ hp5590_low_free_bulk_read_state (void **state) bulk_read_state = *state; - DBG (3, "%s: USB-in-USB: freeing bulk read state\n", __FUNCTION__); + DBG (3, "%s: USB-in-USB: freeing bulk read state\n", __func__); free (bulk_read_state->buffer); bulk_read_state->buffer = NULL; @@ -656,7 +656,7 @@ hp5590_bulk_read (SANE_Int dn, struct bulk_read_state *bulk_read_state; unsigned int bytes_until_buffer_end; - DBG (3, "%s\n", __FUNCTION__); + DBG (3, "%s\n", __func__); hp5590_low_assert (state != NULL); hp5590_low_assert (bytes != NULL); @@ -665,7 +665,7 @@ hp5590_bulk_read (SANE_Int dn, if (bulk_read_state->initialized == 0) { DBG (DBG_err, "%s: USB-in-USB: bulk read state not initialized\n", - __FUNCTION__); + __func__); return SANE_STATUS_INVAL; } @@ -685,7 +685,7 @@ hp5590_bulk_read (SANE_Int dn, { DBG (DBG_usb, "%s: USB-in-USB: not enough data in buffer available " "(available: %u, requested: %u)\n", - __FUNCTION__, bulk_read_state->bytes_available, size); + __func__, bulk_read_state->bytes_available, size); /* IMPORTANT! 'next_pages' means 'request and receive next_pages pages in * one bulk transfer request '. Windows driver uses 4 pages between each @@ -703,7 +703,7 @@ hp5590_bulk_read (SANE_Int dn, */ bulk_read_state->total_pages++; DBG (DBG_usb, "%s: USB-in-USB: total pages done: %u\n", - __FUNCTION__, bulk_read_state->total_pages); + __func__, bulk_read_state->total_pages); /* Send another bulk request for 'next_pages' before first * page or next necessary one @@ -713,7 +713,7 @@ hp5590_bulk_read (SANE_Int dn, { /* Send bulk flags */ DBG (DBG_usb, "%s: USB-in-USB: sending USB-in-USB bulk flags\n", - __FUNCTION__); + __func__); bulk_flags = 0x24; ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 0x0c, 0x83, 0x00, @@ -721,7 +721,7 @@ hp5590_bulk_read (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n", - __FUNCTION__); + __func__); return ret; } @@ -738,7 +738,7 @@ hp5590_bulk_read (SANE_Int dn, /* Send bulk read request */ DBG (DBG_usb, "%s: USB-in-USB: sending control msg for bulk\n", - __FUNCTION__); + __func__); ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, 0x04, 0x82, 0x00, sizeof (ctrl), @@ -746,7 +746,7 @@ hp5590_bulk_read (SANE_Int dn, if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error sending control msg\n", - __FUNCTION__); + __func__); return ret; } @@ -761,13 +761,13 @@ hp5590_bulk_read (SANE_Int dn, if (bulk_read_state->buffer_size - bulk_read_state->bytes_available < next_portion) { - DBG (DBG_err, "%s: USB-in-USB: buffer too small\n", __FUNCTION__); + DBG (DBG_err, "%s: USB-in-USB: buffer too small\n", __func__); return SANE_STATUS_NO_MEM; } /* Bulk read next page */ DBG (DBG_usb, "%s: USB-in-USB: bulk reading %lu bytes\n", - __FUNCTION__, (u_long) next_portion); + __func__, (u_long) next_portion); ret = sanei_usb_read_bulk (dn, bulk_read_state->buffer_in_ptr, &next_portion); @@ -776,7 +776,7 @@ hp5590_bulk_read (SANE_Int dn, if (ret == SANE_STATUS_EOF) return ret; DBG (DBG_err, "%s: USB-in-USB: error during bulk read: %s\n", - __FUNCTION__, sane_strstatus (ret)); + __func__, sane_strstatus (ret)); return ret; } @@ -785,7 +785,7 @@ hp5590_bulk_read (SANE_Int dn, { DBG (DBG_err, "%s: USB-in-USB: incomplete bulk read " "(requested %u bytes, got %lu bytes)\n", - __FUNCTION__, BULK_READ_PAGE_SIZE, (u_long) next_portion); + __func__, BULK_READ_PAGE_SIZE, (u_long) next_portion); return SANE_STATUS_IO_ERROR; } @@ -798,7 +798,7 @@ hp5590_bulk_read (SANE_Int dn, DBG (DBG_err, "%s: USB-in-USB: attempted to access over the end of buffer " "(in_ptr: %p, end_ptr: %p, ptr: %p, buffer size: %u\n", - __FUNCTION__, bulk_read_state->buffer_in_ptr, + __func__, bulk_read_state->buffer_in_ptr, bulk_read_state->buffer_end_ptr, bulk_read_state->buffer, bulk_read_state->buffer_size); return SANE_STATUS_NO_MEM; @@ -808,7 +808,7 @@ hp5590_bulk_read (SANE_Int dn, if (bulk_read_state->buffer_in_ptr == bulk_read_state->buffer_end_ptr) { DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while writing\n", - __FUNCTION__); + __func__); bulk_read_state->buffer_in_ptr = bulk_read_state->buffer; } @@ -819,7 +819,7 @@ hp5590_bulk_read (SANE_Int dn, /* Transfer requested amount of data to the caller */ DBG (DBG_usb, "%s: USB-in-USB: data in bulk buffer is available " "(requested %u bytes, available %u bytes)\n", - __FUNCTION__, size, bulk_read_state->bytes_available); + __func__, size, bulk_read_state->bytes_available); /* Check for buffer pointer wrapping */ bytes_until_buffer_end = bulk_read_state->buffer_end_ptr @@ -827,13 +827,13 @@ hp5590_bulk_read (SANE_Int dn, if (bytes_until_buffer_end <= size) { /* First buffer part */ - DBG (DBG_usb, "%s: USB-in-USB: reached bulk read buffer end\n", __FUNCTION__); + DBG (DBG_usb, "%s: USB-in-USB: reached bulk read buffer end\n", __func__); memcpy (bytes, bulk_read_state->buffer_out_ptr, bytes_until_buffer_end); bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; /* And second part (if any) */ if (bytes_until_buffer_end < size) { - DBG (DBG_usb, "%s: USB-in-USB: giving 2nd buffer part\n", __FUNCTION__); + DBG (DBG_usb, "%s: USB-in-USB: giving 2nd buffer part\n", __func__); memcpy (bytes + bytes_until_buffer_end, bulk_read_state->buffer_out_ptr, size - bytes_until_buffer_end); @@ -848,7 +848,7 @@ hp5590_bulk_read (SANE_Int dn, if (bulk_read_state->buffer_out_ptr == bulk_read_state->buffer_end_ptr) { DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while reading\n", - __FUNCTION__); + __func__); bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; } } @@ -886,7 +886,7 @@ hp5590_bulk_write (SANE_Int dn, unsigned char *ptr; size_t next_portion; - DBG (3, "%s: USB-in-USB: command: %04x, size %u\n", __FUNCTION__, cmd, + DBG (3, "%s: USB-in-USB: command: %04x, size %u\n", __func__, cmd, size); hp5590_low_assert (bytes != NULL); @@ -898,7 +898,7 @@ hp5590_bulk_write (SANE_Int dn, /* Send bulk write request */ DBG (3, "%s: USB-in-USB: total %u pages (each of %u bytes)\n", - __FUNCTION__, bulk_size.size, BULK_WRITE_PAGE_SIZE); + __func__, bulk_size.size, BULK_WRITE_PAGE_SIZE); ret = hp5590_control_msg (dn, proto_flags, USB_DIR_OUT, @@ -919,7 +919,7 @@ hp5590_bulk_write (SANE_Int dn, next_portion = len; DBG (3, "%s: USB-in-USB: next portion %lu bytes\n", - __FUNCTION__, (u_long) next_portion); + __func__, (u_long) next_portion); /* Prepare bulk write request */ memset (&ctrl, 0, sizeof (ctrl)); @@ -941,7 +941,7 @@ hp5590_bulk_write (SANE_Int dn, /* Write bulk data */ DBG (3, "%s: USB-in-USB: bulk writing %lu bytes\n", - __FUNCTION__, (u_long) next_portion); + __func__, (u_long) next_portion); ret = sanei_usb_write_bulk (dn, ptr, &next_portion); if (ret != SANE_STATUS_GOOD) { @@ -949,7 +949,7 @@ hp5590_bulk_write (SANE_Int dn, if (ret == SANE_STATUS_EOF) break; DBG (DBG_err, "%s: USB-in-USB: error during bulk write: %s\n", - __FUNCTION__, sane_strstatus (ret)); + __func__, sane_strstatus (ret)); return ret; } diff --git a/backend/hpsj5s.c b/backend/hpsj5s.c index 75f3526..9c6ad79 100644 --- a/backend/hpsj5s.c +++ b/backend/hpsj5s.c @@ -161,7 +161,6 @@ SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { char line[PATH_MAX]; /*Line from config file */ - int len; /*Length of string from config file */ FILE *config_file; /*Handle to config file of this backend */ DBG_INIT (); @@ -189,7 +188,6 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { if ((line[0] == '#') || (line[0] == '\0')) /*comment line or empty line */ continue; - len = strlen (line); /*sanei_config_read guaranty, it's not more then PATH_MAX-1 */ strcpy (scanner_path, line); /*so, we choose last in file (uncommented) */ } diff --git a/backend/hs2p-saneopts.h b/backend/hs2p-saneopts.h index 7ea50c2..0e712a3 100644 --- a/backend/hs2p-saneopts.h +++ b/backend/hs2p-saneopts.h @@ -110,7 +110,7 @@ #define SANE_NAME_BARCODE_HMIN "barcode-hmin" #define SANE_TITLE_BARCODE_HMIN "Barcode Minimum Height" -#define SANE_DESC_BARCODE_HMIN "Sets the Barcode Minimun Height (larger values increase recognition speed)" +#define SANE_DESC_BARCODE_HMIN "Sets the Barcode Minimum Height (larger values increase recognition speed)" #define SANE_NAME_BARCODE_SEARCH_MODE "barcode-search-mode" #define SANE_TITLE_BARCODE_SEARCH_MODE "Barcode Search Mode" diff --git a/backend/hs2p-scsi.c b/backend/hs2p-scsi.c index a14e6cb..431ba9d 100644 --- a/backend/hs2p-scsi.c +++ b/backend/hs2p-scsi.c @@ -373,7 +373,7 @@ print_sense_data (int dbg_level, SENSE_DATA * data) (data->sense_key & 0x0F)); DBG (dbg_level, "Information Byte = %lu\n", _4btol (data->information)); DBG (dbg_level, "Additional Sense Length = %d\n", data->sense_length); - DBG (dbg_level, "Command Specific Infomation = %lu\n", + DBG (dbg_level, "Command Specific Information = %lu\n", _4btol (data->command_specific_information)); DBG (dbg_level, "Additional Sense Code = %#x\n", data->sense_code); DBG (dbg_level, "Additional Sense Code Qualifier = %#x\n", diff --git a/backend/kodak.c b/backend/kodak.c index 80a5700..73243db 100644 --- a/backend/kodak.c +++ b/backend/kodak.c @@ -1,5 +1,12 @@ /* sane - Scanner Access Now Easy. + This file is part of the SANE package, and implements a SANE backend + for various large Kodak scanners. + + Copyright (C) 2008-2010 m. allan noah + + -------------------------------------------------------------------------- + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -40,8 +47,6 @@ -------------------------------------------------------------------------- - This file implements a SANE backend for various large Kodak scanners. - The source code is divided in sections which you can easily find by searching for the tag "@@". @@ -2749,7 +2754,6 @@ do_cmd(struct scanner *s, int runRS, int shortTime, ) { SANE_Status ret = SANE_STATUS_GOOD; - size_t actLen = 0; /*shut up compiler*/ runRS=runRS; @@ -2766,7 +2770,6 @@ do_cmd(struct scanner *s, int runRS, int shortTime, } if (inBuff && inLen){ DBG(25, "in: reading %d bytes\n", (int)*inLen); - actLen = *inLen; } ret = sanei_scsi_cmd2(s->fd, cmdBuff, cmdLen, outBuff, outLen, inBuff, inLen); diff --git a/backend/kodakaio.c b/backend/kodakaio.c index 42b59a5..a9bec7b 100644 --- a/backend/kodakaio.c +++ b/backend/kodakaio.c @@ -1,7 +1,7 @@ /* * kodakaio.c - SANE library for Kodak ESP Aio scanners. * - * Copyright (C) 2011-2015 Paul Newall + * Copyright (C) 2011-2017 Paul Newall * * Based on the Magicolor sane backend: * Based on the epson2 sane backend: @@ -19,6 +19,7 @@ * 01/01/13 Now with adf, the scan can be padded to make up the full page length, * or the page can terminate at the end of the paper. This is a selectable option. * 25/11/12 Using avahi now for net autodiscovery. Use configure option --enable-avahi + * 1/5/17 patched to use local pointer for avahi callback */ /* @@ -31,13 +32,13 @@ convenient lines to paste export SANE_DEBUG_KODAKAIO=20 for ubuntu prior to 12.10 -./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-avahi --disable-latex BACKENDS="kodakaio test" +./configure --prefix=/usr --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test" for ubuntu 12.10 -./configure --prefix=/usr --libdir=/usr/lib/i386-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi --disable-latex BACKENDS="kodakaio test" +./configure --prefix=/usr --libdir=/usr/lib/i386-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test" -for ubuntu 14.10 -./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi --disable-latex BACKENDS="kodakaio test" +for ubuntu 14.10 up to at least 17.04 +./configure --prefix=/usr --libdir=/usr/lib/x86_64-linux-gnu --sysconfdir=/etc --localstatedir=/var --enable-avahi --without-api-spec BACKENDS="kodakaio test" If you want to use the test backend, for example with sane-troubleshoot, you should enable it in /etc/sane.d/dll.conf @@ -153,7 +154,7 @@ If you want to use the test backend, for example with sane-troubleshoot, you sho #define KODAKAIO_VERSION 02 #define KODAKAIO_REVISION 7 -#define KODAKAIO_BUILD 2 +#define KODAKAIO_BUILD 3 /* for usb (but also used for net though it's not required). */ #define MAX_BLOCK_SIZE 32768 @@ -207,6 +208,7 @@ normal levels. This system is a plan rather than a reality #include #include #include +#include #if WITH_AVAHI /* used for auto detecting network printers */ @@ -216,9 +218,6 @@ normal levels. This system is a plan rather than a reality #include #include #include - -static AvahiSimplePoll *simple_poll = NULL; /* global because called by several functions */ - #endif #include "../include/sane/saneopts.h" @@ -639,8 +638,10 @@ static SANE_Status attach_one_usb(SANE_String_Const devname); static SANE_Status attach_one_net(SANE_String_Const devname, unsigned int device); void kodakaio_com_str(unsigned char *buf, char *fmt_buf); int cmparray (unsigned char *array1, unsigned char *array2, size_t len); +#if WITH_AVAHI static struct KodakaioCap *get_device_from_identification (const char *ident, const char *vid, const char *pid); void ProcessAvahiDevice(const char *device_id, const char *vid, const char *pid, const char *ip_addr); +#endif /* Some utility functions */ @@ -731,7 +732,7 @@ That is probably if the scanner disconnected the network connection if (read == 0) *status = SANE_STATUS_IO_ERROR; - DBG(32, "net read %d bytes:%x,%x,%x,%x,%x,%x,%x,%x\n",read,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); + DBG(32, "net read %lu bytes:%x,%x,%x,%x,%x,%x,%x,%x\n",(unsigned long)read,buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); return read; } @@ -881,7 +882,7 @@ In NET mode the timeout is in kodakaio_net_read time(&time_start); DBG(min(16,DBG_READ), "[%ld] %s: net req size = %ld ", (long) time_start, __func__, (long) buf_size); n = kodakaio_net_read(s, buf, buf_size, status); - DBG(min(16,DBG_READ), "returned %d\n", n); + DBG(min(16,DBG_READ), "returned %lu\n", (unsigned long)n); if (*status != SANE_STATUS_GOOD) { DBG(1, "%s: err returned from kodakaio_net_read, %s\n", __func__, sane_strstatus(*status)); } @@ -1109,7 +1110,7 @@ cmd_start_scan (SANE_Handle handle, size_t expect_total) return SANE_STATUS_IO_ERROR; } - DBG(20, "starting the scan, expected total bytes %d\n",expect_total); + DBG(20, "starting the scan, expected total bytes %lu\n",(unsigned long)expect_total); k_send(s, KodakEsp_Go, 8, &status); if (status != SANE_STATUS_GOOD) @@ -1365,25 +1366,25 @@ But it seems that the scanner takes care of that, and gives you the ack as a sep /* only compare 4 bytes because we sometimes get escSS02.. or escSS00.. is 4 the right number ? */ if (cmparray(Last8,KodakEsp_Ack,4) == 0) { - DBG(min(10,DBG_READ), "%s: found KodakEsp_Ack at %d bytes of %d\n", __func__, bytecount, *len); + DBG(min(10,DBG_READ), "%s: found KodakEsp_Ack at %lu bytes of %lu\n", __func__, (unsigned long) bytecount, (unsigned long) *len); s->ack = SANE_TRUE; *len = bytecount - 8; /* discard the Ack response */ s->bytes_unread -= *len; /* return a short block */ } else { /* a not full buffer is returned usb does this */ - DBG(min(10,DBG_READ), "%s: buffer not full, got %d bytes of %d\n", __func__, bytecount, *len); + DBG(min(10,DBG_READ), "%s: buffer not full, got %lu bytes of %lu\n", __func__, (unsigned long) bytecount, (unsigned long) *len); *len = bytecount; s->bytes_unread -= bytecount; } } else { - DBG(min(1,DBG_READ), "%s: tiny read, got %d bytes of %d\n", __func__, (int) bytecount, *len); + DBG(min(1,DBG_READ), "%s: tiny read, got %lu bytes of %lu\n", __func__, (unsigned long) bytecount, (unsigned long) *len); return SANE_STATUS_IO_ERROR; } - if (*len > s->params.bytes_per_line) { + lines = *len / s->params.bytes_per_line; + if (lines > 1) { /* store average colour as background. That's not the ideal method but it's easy to implement. What's it used for? */ - lines = *len / s->params.bytes_per_line; s->background[0] = 0; s->background[1] = 0; s->background[2] = 0; @@ -1934,17 +1935,18 @@ you don't know how many blocks there will be in advance because their size may b * SANE API implementation (high-level functions) */ +#if WITH_AVAHI static struct KodakaioCap * get_device_from_identification (const char *ident, const char *vid, const char *pid) { int n; SANE_Word pidnum, vidnum; - if(sscanf(vid, "%x", &vidnum) == EOF) { + if(sscanf(vid, "%x", (unsigned int *)&vidnum) == EOF) { DBG(5, "could not convert hex vid <%s>\n", vid); return NULL; } - if(sscanf(pid, "%x", &pidnum) == EOF) { + if(sscanf(pid, "%x", (unsigned int *)&pidnum) == EOF) { DBG(5, "could not convert hex pid <%s>\n", pid); return NULL; } @@ -1965,6 +1967,7 @@ get_device_from_identification (const char *ident, const char *vid, const char * } return NULL; } +#endif /* WITH_AVAHI */ /* * close_scanner() @@ -2359,9 +2362,9 @@ static void browse_callback( const char *domain, AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata) { + AvahiSimplePoll *simple_poll = userdata; - AvahiClient *c = userdata; - assert(b); + AvahiClient *c = avahi_service_browser_get_client (b); /* Called whenever a new services becomes available on the LAN or is removed from the LAN */ switch (event) { @@ -2395,7 +2398,8 @@ static void browse_callback( } } -static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) { +static void client_callback(AvahiClient *c, AvahiClientState state, void * userdata) { + AvahiSimplePoll *simple_poll = userdata; assert(c); /* Called whenever the client or server state changes */ @@ -2412,6 +2416,7 @@ kodak_network_discovery(const char*host) /* If host = NULL do autodiscovery. If host != NULL try to verify the model First version only does autodiscovery */ { + AvahiSimplePoll *simple_poll; AvahiClient *client = NULL; AvahiServiceBrowser *sb = NULL; int error; @@ -2427,7 +2432,7 @@ First version only does autodiscovery */ } /* Allocate a new client */ - client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error); + client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, simple_poll, &error); /* Check wether creating the client object succeeded */ if (!client) { @@ -2436,14 +2441,15 @@ First version only does autodiscovery */ } /* Create the service browser */ - if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_scanner._tcp", NULL, 0, browse_callback, client))) { + if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_scanner._tcp", NULL, 0, browse_callback, simple_poll))) { DBG(min(1,DBG_AUTO), "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client))); goto fail; } /* Run the main loop */ for(i=1;iname, devname)) diff --git a/backend/kvs20xx.h b/backend/kvs20xx.h index 9bc833d..442f1c7 100644 --- a/backend/kvs20xx.h +++ b/backend/kvs20xx.h @@ -168,6 +168,12 @@ swap_bytes32 (u32 x) (x & (u32) 0x0000ff00UL) << 8 | (x & (u32) 0x00ff0000UL) >> 8; } +static inline void +copy16 (u8 * p, u16 x) +{ + memcpy (p, (u8 *) &x, sizeof (x)); +} + #if __BYTE_ORDER == __BIG_ENDIAN static inline void set24 (u8 * p, u32 x) diff --git a/backend/kvs20xx_cmd.c b/backend/kvs20xx_cmd.c index 7579701..d0f18ee 100644 --- a/backend/kvs20xx_cmd.c +++ b/backend/kvs20xx_cmd.c @@ -187,7 +187,7 @@ kvs20xx_set_timeout (struct scanner * s, int timeout) }; c.cmd[0] = SET_TIMEOUT; c.cmd[2] = 0x8d; - *((u16 *) (c.cmd + 7)) = cpu2be16 (sizeof (t)); + copy16 (c.cmd + 7, cpu2be16 (sizeof (t))); c.data = &t; c.data_size = sizeof (t); @@ -210,7 +210,7 @@ kvs20xx_set_window (struct scanner * s, int wnd_id) CMD_OUT }; c.cmd[0] = SET_WINDOW; - *((u16 *) (c.cmd + 7)) = cpu2be16 (sizeof (wnd)); + copy16 (c.cmd + 7, cpu2be16 (sizeof (wnd))); c.data = &wnd; c.data_size = sizeof (wnd); @@ -301,29 +301,6 @@ kvs20xx_read_picture_element (struct scanner * s, unsigned side, return SANE_STATUS_GOOD; } -static SANE_Status -get_buffer_status (struct scanner * s, unsigned *data_avalible) -{ - SANE_Status status; - struct cmd c = { - {0}, - 10, - 0, - 12, - CMD_IN - }; - u32 *data; - c.cmd[0] = GET_BUFFER_STATUS; - c.cmd[7] = 12; - - status = send_command (s, &c); - if (status) - return status; - data = (u32 *) c.data; - *data_avalible = be2cpu32 (data[3]); - return SANE_STATUS_GOOD; -} - SANE_Status kvs20xx_read_image_data (struct scanner * s, unsigned page, unsigned side, void *buf, unsigned max_size, unsigned *size) diff --git a/backend/kvs20xx_cmd.h b/backend/kvs20xx_cmd.h index c18b754..4acaf62 100644 --- a/backend/kvs20xx_cmd.h +++ b/backend/kvs20xx_cmd.h @@ -9,6 +9,10 @@ Panasonic KV-S20xx USB-SCSI scanners. */ +#ifdef HAVE_SYS_TYPES_H +#include +#endif + #define COMMAND_BLOCK 1 #define DATA_BLOCK 2 #define RESPONSE_BLOCK 3 diff --git a/backend/kvs20xx_opt.c b/backend/kvs20xx_opt.c index 83d3385..94c4133 100644 --- a/backend/kvs20xx_opt.c +++ b/backend/kvs20xx_opt.c @@ -23,6 +23,7 @@ #include "kvs20xx.h" #include "kvs20xx_cmd.h" +#include static size_t max_string_size (SANE_String_Const strings[]) diff --git a/backend/kvs40xx.h b/backend/kvs40xx.h index fa17163..7fdebe6 100644 --- a/backend/kvs40xx.h +++ b/backend/kvs40xx.h @@ -10,6 +10,9 @@ #include "../include/sane/config.h" #include +#ifdef HAVE_SYS_TYPES_H +#include +#endif #undef BACKEND_NAME #define BACKEND_NAME kvs40xx @@ -225,6 +228,18 @@ swap_bytes32 (u32 x) (x & (u32) 0x0000ff00UL) << 8 | (x & (u32) 0x00ff0000UL) >> 8; } +static inline void +copy16 (u8 * p, u16 x) +{ + memcpy (p, (u8 *) &x, sizeof (x)); +} + +static inline void +copy32 (u8 * p, u32 x) +{ + memcpy (p, (u8 *) &x, sizeof (x)); +} + #if WORDS_BIGENDIAN static inline void set24 (u8 * p, u32 x) diff --git a/backend/kvs40xx_cmd.c b/backend/kvs40xx_cmd.c index ade2014..52ccc38 100644 --- a/backend/kvs40xx_cmd.c +++ b/backend/kvs40xx_cmd.c @@ -360,7 +360,7 @@ kvs40xx_set_timeout (struct scanner * s, int timeout) c.data_size = sizeof (t); c.cmd[0] = SET_TIMEOUT; c.cmd[2] = 0x8d; - *((u16 *) (c.cmd + 7)) = cpu2be16 (sizeof (t)); + copy16 (c.cmd + 7, cpu2be16 (sizeof (t))); if (s->bus == USB) sanei_usb_set_timeout (timeout * 1000); @@ -379,7 +379,7 @@ kvs40xx_set_window (struct scanner * s, int wnd_id) c.data = &wnd; c.data_size = sizeof (wnd); c.cmd[0] = SET_WINDOW; - *((u16 *) (c.cmd + 7)) = cpu2be16 (sizeof (wnd)); + copy16 (c.cmd + 7, cpu2be16 (sizeof (wnd))); kvs40xx_init_window (s, &wnd, wnd_id); return send_command (s, &c); @@ -534,28 +534,6 @@ kvs40xx_read_image_data (struct scanner * s, unsigned page, unsigned side, return status; } -static SANE_Status -get_adjust_data (struct scanner * s, unsigned *dummy_length) -{ - SANE_Status status; - struct cmd c = { - {0}, 10, - NULL, 40, - CMD_IN - }; - u16 *data; - - c.cmd[0] = GET_ADJUST_DATA; - c.cmd[2] = 0x9b; - c.cmd[8] = 40; - status = send_command (s, &c); - if (status) - return status; - data = (u16 *) c.data; - *dummy_length = be2cpu16 (data[0]); - return SANE_STATUS_GOOD; -} - SANE_Status read_support_info (struct scanner * s, struct support_info * inf) { diff --git a/backend/kvs40xx_opt.c b/backend/kvs40xx_opt.c index c4f478b..bd9d85e 100644 --- a/backend/kvs40xx_opt.c +++ b/backend/kvs40xx_opt.c @@ -22,6 +22,7 @@ #include "../include/sane/sanei_debug.h" +#include static inline unsigned mm2scanner_units (unsigned mm) @@ -1271,41 +1272,45 @@ kvs40xx_init_window (struct scanner *s, struct window *wnd, int wnd_id) { int paper = str_index (paper_list, s->val[PAPER_SIZE].s), i; memset (wnd, 0, sizeof (struct window)); - *(u16 *) wnd->window_descriptor_block_length = cpu2be16 (66); + copy16 (wnd->window_descriptor_block_length, cpu2be16 (66)); wnd->window_identifier = wnd_id; - *(u16 *) wnd->x_resolution = cpu2be16 (s->val[RESOLUTION].w); - *(u16 *) wnd->y_resolution = cpu2be16 (s->val[RESOLUTION].w); + copy16 (wnd->x_resolution, cpu2be16 (s->val[RESOLUTION].w)); + copy16 (wnd->y_resolution, cpu2be16 (s->val[RESOLUTION].w)); if (!paper) { - *(u32 *) wnd->upper_left_x = - cpu2be32 (mm2scanner_units (s->val[TL_X].w)); - *(u32 *) wnd->upper_left_y = - cpu2be32 (mm2scanner_units (s->val[TL_Y].w)); - *(u32 *) wnd->document_width = - cpu2be32 (mm2scanner_units (s->val[BR_X].w)); - *(u32 *) wnd->width = - cpu2be32 (mm2scanner_units (s->val[BR_X].w - s->val[TL_X].w)); - *(u32 *) wnd->document_length = cpu2be32 (mm2scanner_units - (s->val[BR_Y].w)); - *(u32 *) wnd->length = - cpu2be32 (mm2scanner_units (s->val[BR_Y].w - s->val[TL_Y].w)); + copy32 (wnd->upper_left_x, + cpu2be32 (mm2scanner_units (s->val[TL_X].w))); + copy32 (wnd->upper_left_y, + cpu2be32 (mm2scanner_units (s->val[TL_Y].w))); + copy32 (wnd->document_width, + cpu2be32 (mm2scanner_units (s->val[BR_X].w))); + copy32 (wnd->width, + cpu2be32 (mm2scanner_units (s->val[BR_X].w - s->val[TL_X].w))); + copy32 (wnd->document_length, cpu2be32 (mm2scanner_units + (s->val[BR_Y].w))); + copy32 (wnd->length, + cpu2be32 (mm2scanner_units (s->val[BR_Y].w - s->val[TL_Y].w))); } else { u32 w = cpu2be32 (mm2scanner_units (paper_sizes[paper].width)); u32 h = cpu2be32 (mm2scanner_units (paper_sizes[paper].height)); - *(u32 *) wnd->upper_left_x = cpu2be32 (mm2scanner_units (0)); - *(u32 *) wnd->upper_left_y = cpu2be32 (mm2scanner_units (0)); + copy32 (wnd->upper_left_x, cpu2be32 (mm2scanner_units (0))); + copy32 (wnd->upper_left_y, cpu2be32 (mm2scanner_units (0))); if (!s->val[LANDSCAPE].b) { - *(u32 *) wnd->document_width = *(u32 *) wnd->width = w; - *(u32 *) wnd->document_length = *(u32 *) wnd->length = h; + copy32 (wnd->width, w); + copy32 (wnd->length, h); + copy32 (wnd->document_width, w); + copy32 (wnd->document_length, h); } else { - *(u32 *) wnd->document_width = *(u32 *) wnd->width = h; - *(u32 *) wnd->document_length = *(u32 *) wnd->length = w; + copy32 (wnd->width, h); + copy32 (wnd->length, w); + copy32 (wnd->document_width, h); + copy32 (wnd->document_length, w); } } wnd->brightness = s->val[BRIGHTNESS].w; @@ -1314,11 +1319,11 @@ kvs40xx_init_window (struct scanner *s, struct window *wnd, int wnd_id) wnd->image_composition = mode_val[str_index (mode_list, s->val[MODE].s)]; wnd->bit_per_pixel = bps_val[str_index (mode_list, s->val[MODE].s)]; - *(u16 *) wnd->halftone_pattern = - cpu2be16 (str_index (halftone_pattern, s->val[HALFTONE_PATTERN].s)); + copy16 (wnd->halftone_pattern, + cpu2be16 (str_index (halftone_pattern, s->val[HALFTONE_PATTERN].s))); wnd->rif_padding = s->val[INVERSE].b << 7; - *(u16 *) wnd->bit_ordering = cpu2be16 (BIT_ORDERING); + copy16 (wnd->bit_ordering, cpu2be16 (BIT_ORDERING)); wnd->compression_type = s->val[COMPRESSION].b ? 0x81 : 0; wnd->compression_argument = s->val[COMPRESSION_PAR].w; diff --git a/backend/lexmark_low.c b/backend/lexmark_low.c index 821b621..fe20e89 100644 --- a/backend/lexmark_low.c +++ b/backend/lexmark_low.c @@ -2369,6 +2369,9 @@ low_get_start_loc (SANE_Int resolution, SANE_Int * vert_start, return SANE_STATUS_INVAL; } break; + default: + /* If we're here we have an unknown dev->model.sensor_type */ + return SANE_STATUS_INVAL; } /* Calculate vertical start distance at 600dpi */ switch (resolution) diff --git a/backend/ma1509.c b/backend/ma1509.c index 5fccd1c..e38ddc5 100644 --- a/backend/ma1509.c +++ b/backend/ma1509.c @@ -1738,7 +1738,6 @@ sane_start (SANE_Handle handle) { Ma1509_Scanner *s = handle; SANE_Status status; - SANE_String_Const mode; struct timeval start; if (!s) @@ -1778,8 +1777,6 @@ sane_start (SANE_Handle handle) /* save start time */ gettimeofday (&start, 0); s->start_time = start.tv_sec; - /* translate options into s->mode for convenient access: */ - mode = s->val[OPT_MODE].s; status = set_window (s); if (status != SANE_STATUS_GOOD) diff --git a/backend/magicolor.c b/backend/magicolor.c index 660f517..d3af142 100644 --- a/backend/magicolor.c +++ b/backend/magicolor.c @@ -1385,7 +1385,6 @@ static SANE_Status mc_init_parameters(Magicolor_Scanner * s) { int dpi, optres; - struct mode_param *mparam; DBG(5, "%s\n", __func__); @@ -1394,8 +1393,6 @@ mc_init_parameters(Magicolor_Scanner * s) dpi = s->val[OPT_RESOLUTION].w; optres = s->hw->cap->optical_res; - mparam = &mode_params[s->val[OPT_MODE].w]; - if (SANE_UNFIX(s->val[OPT_BR_Y].w) == 0 || SANE_UNFIX(s->val[OPT_BR_X].w) == 0) return SANE_STATUS_INVAL; @@ -1521,6 +1518,7 @@ mc_read(struct Magicolor_Scanner *s) ****************************************************************************/ +#if HAVE_LIBSNMP static struct MagicolorCap * mc_get_device_from_identification (const char*ident) { @@ -1531,6 +1529,7 @@ mc_get_device_from_identification (const char*ident) } return NULL; } +#endif /* @@ -1970,10 +1969,10 @@ mc_network_discovery(const char*host) init_snmp("sane-magicolor-backend"); snmp_sess_init (&session); session.version = SNMP_VERSION_2c; - session.community = "public"; - session.community_len = strlen (session.community); + session.community = (u_char *) "public"; + session.community_len = strlen ((char *)session.community); if (host) { - session.peername = host; + session.peername = (char *) host; } else { /* Do a network discovery via a broadcast */ session.peername = "255.255.255.255"; diff --git a/backend/magicolor.h b/backend/magicolor.h index 7ea1e1e..b1195a0 100644 --- a/backend/magicolor.h +++ b/backend/magicolor.h @@ -44,13 +44,6 @@ #include "../include/sane/sanei_debug.h" #include "../include/sane/sanei_backend.h" -#ifdef __GNUC__ -#define __func__ __FUNCTION__ -#else -#define __func__ "(undef)" -/* I cast my vote for C99... :) */ -#endif - /* Silence the compiler for unused arguments */ #define NOT_USED(x) ( (void)(x) ) diff --git a/backend/microtek2.c b/backend/microtek2.c index 8fdf497..dccd707 100644 --- a/backend/microtek2.c +++ b/backend/microtek2.c @@ -443,12 +443,14 @@ sane_get_select_fd (SANE_Handle handle, SANE_Int *fd) /*---------- sane_init() -----------------------------------------------------*/ SANE_Status +#ifdef HAVE_AUTHORIZATION sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize) +#else +sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize) +#endif { Microtek2_Device *md; FILE *fp; - int match; - SANE_Auth_Callback trash; DBG_INIT(); @@ -460,13 +462,10 @@ sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize) #ifdef HAVE_AUTHORIZATION auth_callback = authorize; -#else - trash = authorize; /* prevents compiler warning "unused variable" */ #endif sanei_thread_init(); - match = 0; fp = sanei_config_open(MICROTEK2_CONFIG_FILE); if ( fp == NULL ) DBG(10, "sane_init: file not opened: '%s'\n", MICROTEK2_CONFIG_FILE); @@ -909,7 +908,7 @@ cancel_scan(Microtek2_Scanner *ms) of material on a feeder, then pid may be already -1 and kill(-1, SIGTERM), i.e. killing all our processes, is not likely what we really want - --mj, 2001/Nov/19 */ - if (ms->pid != -1) + if (sanei_thread_is_valid (ms->pid)) { sanei_thread_kill(ms->pid); sanei_thread_waitpid(ms->pid, NULL); @@ -1346,14 +1345,10 @@ check_inquiry(Microtek2_Device *md, SANE_String *model_string) static void cleanup_scanner(Microtek2_Scanner *ms) { - SANE_Status status; - Microtek2_Device *md; - md = ms->dev; - DBG(30, "cleanup_scanner: ms=%p, ms->sfd=%d\n", (void *) ms, ms->sfd); if ( ms->scanning == SANE_TRUE ) - status=cancel_scan(ms); + cancel_scan(ms); if ( ms->sfd != -1 ) sanei_scsi_close(ms->sfd); @@ -1616,10 +1611,9 @@ dump_area2(uint8_t *area, int len, char *info) #define BPL 16 /* bytes per line to print */ - int i, linelength; + int i; char outputline[100]; char *outbuf; - linelength = BPL * 3; if ( ! info[0] ) info = "No additional info available"; @@ -1991,7 +1985,7 @@ parse_config_file(FILE *fp, Config_Temp **ct) /*---------- signal_handler() ------------------------------------------------*/ -static RETSIGTYPE +static void signal_handler (int signal) { if ( signal == SIGTERM ) @@ -4466,15 +4460,12 @@ scsi_read_attributes(Microtek2_Info *pmi, char *device, uint8_t scan_source) static SANE_Status scsi_read_control_bits(Microtek2_Scanner *ms) { - Microtek2_Device *md; SANE_Status status; uint8_t cmd[RCB_CMD_L]; uint32_t byte; int bit; int count_1s; - md = ms->dev; - DBG(30, "scsi_read_control_bits: ms=%p, fd=%d\n", (void *) ms, ms->sfd); DBG(30, "ms->control_bytes = %p\n", ms->control_bytes); @@ -4795,7 +4786,6 @@ scsi_read_image_status(Microtek2_Scanner *ms) static SANE_Status scsi_read_shading(Microtek2_Scanner *ms, uint8_t *buffer, uint32_t length) { - Microtek2_Device *md; uint8_t cmd[RSI_CMD_L]; SANE_Bool endiantype; SANE_Status status = SANE_STATUS_GOOD; @@ -4804,8 +4794,6 @@ scsi_read_shading(Microtek2_Scanner *ms, uint8_t *buffer, uint32_t length) DBG(30, "scsi_read_shading: pos=%p, size=%d, word=%d, color=%d, dark=%d\n", buffer, length, ms->word, ms->current_color, ms->dark); - md = ms->dev; - size = length; RSI_SET_CMD(cmd); @@ -5080,7 +5068,6 @@ scsi_sense_handler (int fd, u_char *sense, void *arg) { int as_info_length; uint8_t sense_key; - uint8_t asl; uint8_t asc; uint8_t ascq; @@ -5090,7 +5077,6 @@ scsi_sense_handler (int fd, u_char *sense, void *arg) dump_area(sense, RQS_LENGTH(sense), "SenseBuffer"); sense_key = RQS_SENSEKEY(sense); - asl = RQS_ASL(sense); asc = RQS_ASC(sense); ascq = RQS_ASCQ(sense); @@ -5152,7 +5138,7 @@ scsi_sense_handler (int fd, u_char *sense, void *arg) else if ( asc == 0x3d && ascq == 0x00) DBG(5, "scsi_sense_handler: Invalid bit in IDENTIFY\n"); else if ( asc == 0x2c && ascq == 0x02 ) -/* Ok */ DBG(5, "scsi_sense_handler: Invalid comb. of windows specfied\n"); +/* Ok */ DBG(5, "scsi_sense_handler: Invalid comb. of windows specified\n"); else if ( asc == 0x20 && ascq == 0x00 ) /* Ok */ DBG(5, "scsi_sense_handler: Invalid command opcode\n"); else if ( asc == 0x24 && ascq == 0x00 ) @@ -5503,7 +5489,7 @@ sane_start(SANE_Handle handle) /* create reader routine as new thread or process */ ms->pid = sanei_thread_begin( reader_process,(void*) ms); - if ( ms->pid == -1 ) + if ( !sanei_thread_is_valid (ms->pid) ) { DBG(1, "sane_start: fork failed\n"); status = SANE_STATUS_IO_ERROR; @@ -7279,7 +7265,6 @@ chunky_proc_data(Microtek2_Scanner *ms) { SANE_Status status; Microtek2_Device *md; - Microtek2_Info *mi; uint32_t line; uint8_t *from; int pad; @@ -7292,7 +7277,6 @@ chunky_proc_data(Microtek2_Scanner *ms) DBG(30, "chunky_proc_data: ms=%p\n", (void *) ms); md = ms->dev; - mi = &md->info[md->scan_source]; bits_pp_in = ms->bits_per_pixel_in; bits_pp_out = ms->bits_per_pixel_out; pad = (int) ceil( (double) (ms->ppl * bits_pp_in) / 8.0 ) % 2; @@ -7410,7 +7394,6 @@ segreg_proc_data(Microtek2_Scanner *ms) int color; int save_current_src; int frame; - int right_to_left; DBG(30, "segreg_proc_data: ms=%p\n", (void *) ms); @@ -7420,7 +7403,6 @@ segreg_proc_data(Microtek2_Scanner *ms) pad = (int) ceil( (double) (ms->ppl * ms->bits_per_pixel_in) / 8.0 ) % 2; bpp = ms->bits_per_pixel_out / 8; /* bits_per_pixel_out is either 8 or 16 */ bpf = ms->bpl / 3; - right_to_left = mi->direction & MI_DATSEQ_RTOL; DBG(30, "segreg_proc_data: lines=%d, bpl=%d, ppl=%d, bpf=%d, bpp=%d,\n" "depth=%d, pad=%d, freelines=%d, calib_backend=%d\n", @@ -7688,7 +7670,6 @@ lplconcat_proc_data(Microtek2_Scanner *ms) uint8_t *save_from[3]; int color; int bpp; - int pad; int gamma_by_backend; int right_to_left; /* 0=left to right, 1=right to left */ @@ -7701,7 +7682,6 @@ lplconcat_proc_data(Microtek2_Scanner *ms) mi = &md->info[md->scan_source]; bpp = ms->bits_per_pixel_out / 8; /* ms->bits_per_pixel_out is 8 or 16 */ - pad = (ms->ppl * bpp) % 2; right_to_left = mi->direction & MI_DATSEQ_RTOL; gamma_by_backend = md->model_flags & MD_NO_GAMMA ? 1 : 0; diff --git a/backend/microtek2.h b/backend/microtek2.h index 4100fad..2a1f697 100644 --- a/backend/microtek2.h +++ b/backend/microtek2.h @@ -1307,7 +1307,7 @@ set_option_dependencies(Microtek2_Scanner *, static SANE_Status shading_function(Microtek2_Scanner *, uint8_t *); -static RETSIGTYPE +static void signal_handler (int); static SANE_Status diff --git a/backend/mustek.c b/backend/mustek.c index 7f0db8c..8426dfe 100644 --- a/backend/mustek.c +++ b/backend/mustek.c @@ -1669,7 +1669,7 @@ attach (SANE_String_Const devname, Mustek_Device ** devp, SANE_Bool may_wait) DBG (0, "WARNING: Your scanner was detected by the SANE Mustek backend, " "but\n it is not fully tested. It may or may not work. Be " - "carefull and read\n the PROBLEMS file in the sane directory. " + "careful and read\n the PROBLEMS file in the sane directory. " "Please set the debug level of this\n backend to maximum " "(export SANE_DEBUG_MUSTEK=255) and send the output of\n " "scanimage -L to the SANE mailing list sane-devel@lists.alioth.debian.org. " @@ -2335,16 +2335,14 @@ send_calibration_lines_se (Mustek_Scanner * s, SANE_Word color) SANE_Byte *cmd; size_t buf_size; SANE_Word column; - SANE_Word lines, bytes_per_color; + SANE_Word bytes_per_color; if (s->mode == MUSTEK_MODE_COLOR) { - lines = s->hw->cal.lines * 3; bytes_per_color = s->hw->cal.bytes / 3; } else { - lines = s->hw->cal.lines; bytes_per_color = s->hw->cal.bytes; } @@ -2952,7 +2950,7 @@ do_stop (Mustek_Scanner * s) s->scanning = SANE_FALSE; s->pass = 0; - if (s->reader_pid != -1) + if (sanei_thread_is_valid (s->reader_pid)) { SANE_Int exit_status; struct timeval now; @@ -2983,7 +2981,7 @@ do_stop (Mustek_Scanner * s) sanei_thread_kill (s->reader_pid); pid = sanei_thread_waitpid (s->reader_pid, &exit_status); - if (pid == -1) + if (!sanei_thread_is_valid (pid)) { DBG (1, "do_stop: sanei_thread_waitpid failed, already terminated? (%s)\n", @@ -4826,7 +4824,7 @@ output_data (Mustek_Scanner * s, FILE * fp, DBG (5, "output_data: end\n"); } -static RETSIGTYPE +static void sigterm_handler (int signal) { DBG (4, @@ -6565,7 +6563,7 @@ sane_start (SANE_Handle handle) /* create reader routine as new process or thread */ s->reader_pid = sanei_thread_begin (reader_process, (void *) s); - if (s->reader_pid == -1) + if (!sanei_thread_is_valid (s->reader_pid)) { DBG (1, "sane_start: sanei_thread_begin failed (%s)\n", strerror (errno)); @@ -6593,7 +6591,6 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, { Mustek_Scanner *s = handle; SANE_Status status; - ssize_t ntotal; ssize_t nread; @@ -6617,7 +6614,6 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, DBG (5, "sane_read\n"); *len = 0; - ntotal = 0; if (s->cancelled) { diff --git a/backend/mustek_pp.c b/backend/mustek_pp.c index cd86bb9..9c9a533 100644 --- a/backend/mustek_pp.c +++ b/backend/mustek_pp.c @@ -237,7 +237,7 @@ do_stop(Mustek_pp_Handle *hndl) */ static int fd_to_release = 0; /*ARGSUSED*/ -static RETSIGTYPE +static void sigterm_handler (int signal __UNUSED__) { sanei_pa4s2_enable(fd_to_release, SANE_FALSE); diff --git a/backend/mustek_pp_cis.c b/backend/mustek_pp_cis.c index d5ef86d..96e89f1 100644 --- a/backend/mustek_pp_cis.c +++ b/backend/mustek_pp_cis.c @@ -1526,7 +1526,7 @@ static void cis_get_next_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) { SANE_Byte *dest, *tmpbuf = dev->tmpbuf; - int ctr, channel, first, last, stride, ignore, step = dev->CIS.line_step; + int ctr, channel, first, last, stride, step = dev->CIS.line_step; SANE_Byte gotline; if (dev->desc->mode == MODE_COLOR) @@ -1534,14 +1534,12 @@ cis_get_next_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) first = MUSTEK_PP_CIS_CHANNEL_RED; last = MUSTEK_PP_CIS_CHANNEL_BLUE; stride = 3; - ignore = 1; /* 1 * 3 channels */ } else { first = MUSTEK_PP_CIS_CHANNEL_GRAY; last = MUSTEK_PP_CIS_CHANNEL_GRAY; stride = 1; - ignore = 3; /* 3 * 1 channel */ } gotline = SANE_FALSE; diff --git a/backend/mustek_usb.c b/backend/mustek_usb.c index 66b1813..58dcc58 100644 --- a/backend/mustek_usb.c +++ b/backend/mustek_usb.c @@ -1572,7 +1572,7 @@ sane_cancel (SANE_Handle handle) else { DBG (4, "sane_cancel: scan has not been initiated yet, " - "or it is allready aborted\n"); + "or it is already aborted\n"); } DBG (5, "sane_cancel: exit\n"); return; diff --git a/backend/mustek_usb2.c b/backend/mustek_usb2.c index 25b8464..58d9e9e 100644 --- a/backend/mustek_usb2.c +++ b/backend/mustek_usb2.c @@ -1270,14 +1270,12 @@ AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines, unsigned short R, G, B, max_R, max_G, max_B, min_R, min_G, min_B; float fmax_R, fmax_G, fmax_B; unsigned int sum_R = 0, sum_G = 0, sum_B = 0; - float mean_R, mean_G, mean_B; unsigned int hisgram_R[256], hisgram_G[256], hisgram_B[256]; unsigned int iWidth = BytesPerLine / 3; unsigned int iHeight = ScanLines; SANE_Byte *pbmpdata = (SANE_Byte *) lpSource; - unsigned int tmp = 0; unsigned short imin_threshold[3]; unsigned short imax_threshold[3]; @@ -1350,10 +1348,6 @@ AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines, DBG (DBG_INFO, "AutoLevel: Find min , max is over!\n"); - mean_R = (float) (sum_R / TotalImgSize); - mean_G = (float) (sum_G / TotalImgSize); - mean_B = (float) (sum_B / TotalImgSize); - imin_threshold[0] = 0; imin_threshold[1] = 0; @@ -1372,7 +1366,6 @@ AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines, } } - tmp = 0; for (ii = 255; ii >= 0; ii--) { if (hisgram_R[ii] > 0) @@ -1383,7 +1376,6 @@ AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines, } } - tmp = 0; for (ii = 0; ii < 256; ii++) { if (hisgram_G[ii] > 0) @@ -1394,7 +1386,6 @@ AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines, } } - tmp = 0; for (ii = 255; ii >= 0; ii--) { if (hisgram_G[ii] > 0) @@ -1405,7 +1396,6 @@ AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines, } } - tmp = 0; for (ii = 0; ii < 256; ii++) { if (hisgram_B[ii] > 0) @@ -1416,7 +1406,6 @@ AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines, } } - tmp = 0; for (ii = 255; ii >= 0; ii--) { if (hisgram_B[ii] > 0) diff --git a/backend/mustek_usb2_asic.c b/backend/mustek_usb2_asic.c index 3019e5e..d9b1a28 100644 --- a/backend/mustek_usb2_asic.c +++ b/backend/mustek_usb2_asic.c @@ -1607,7 +1607,6 @@ LLFMotorMove (PAsic chip, LLF_MOTORMOVE * LLF_MotorMove) STATUS status = STATUS_GOOD; unsigned int motor_steps; SANE_Byte temp_motor_action; - SANE_Byte temp_status; DBG (DBG_ASIC, "LLFMotorMove:Enter\n"); @@ -1727,7 +1726,6 @@ LLFMotorMove (PAsic chip, LLF_MOTORMOVE * LLF_MotorMove) SCAN_BACK_TRACKING_DISABLE | temp_motor_action); Mustek_SendData (chip, ES01_F4_ActiveTriger, ACTION_TRIGER_ENABLE); - temp_status = 0; if (LLF_MotorMove->WaitOrNoWait == 1) { if (LLF_MotorMove->ActionType == ACTION_TYPE_BACKTOHOME) @@ -3020,10 +3018,8 @@ SetPackAddress (PAsic chip, unsigned short wXResolution, unsigned short wWidth, { STATUS status = STATUS_GOOD; - unsigned short LineTotalOverlapPixel; SANE_Byte OverLapPixel; SANE_Byte TotalLineShift; - SANE_Byte InvalidPixelNumberBackup; unsigned short SegmentTotalPixel; unsigned int dwLineTotalPixel; unsigned short ValidPixelNumber = *PValidPixelNumber; @@ -3038,7 +3034,6 @@ SetPackAddress (PAsic chip, unsigned short wXResolution, unsigned short wWidth, DBG (DBG_ASIC, "SetPackAddress:Enter\n"); - LineTotalOverlapPixel = 0; OverLapPixel = 0; TotalLineShift = 1; PackAreaUseLine = TotalLineShift + 1; @@ -3067,7 +3062,6 @@ SetPackAddress (PAsic chip, unsigned short wXResolution, unsigned short wWidth, Mustek_SendData (chip, ES01_2C0_VALID_PIXEL_PARAMETER_OF_SEGMENT1 + i, 0); } - LineTotalOverlapPixel = OverLapPixel * 16; FinalLinePixelPerSegment = ValidPixelNumber + OverLapPixel * 2; @@ -3080,8 +3074,6 @@ SetPackAddress (PAsic chip, unsigned short wXResolution, unsigned short wWidth, InValidPixelNumber = 0; } - InvalidPixelNumberBackup = InValidPixelNumber; - Mustek_SendData (chip, ES01_1B0_SEGMENT_PIXEL_NUMBER_LB, LOBYTE (ValidPixelNumber)); Mustek_SendData (chip, ES01_1B1_SEGMENT_PIXEL_NUMBER_HB, @@ -3823,9 +3815,7 @@ Asic_SetWindow (PAsic chip, SANE_Byte bScanBits, unsigned short ValidPixelNumber; - unsigned short wPerLineNeedBufferSize = 0; unsigned short BytePerPixel = 0; - unsigned int dwTotal_PerLineNeedBufferSize = 0; unsigned int dwTotalLineTheBufferNeed = 0; unsigned short dwTotal_CCDResolution = 1200; unsigned short wThinkCCDResolution = 0; @@ -3890,31 +3880,26 @@ Asic_SetWindow (PAsic chip, SANE_Byte bScanBits, /* calculate byte per line */ if (bScanBits > 24) { - wPerLineNeedBufferSize = wWidth * 6; BytePerPixel = 6; chip->dwBytesCountPerRow = (unsigned int) (wWidth) * 6; } else if (bScanBits == 24) { - wPerLineNeedBufferSize = wWidth * 3; BytePerPixel = 3; chip->dwBytesCountPerRow = (unsigned int) (wWidth) * 3; } else if ((bScanBits > 8) && (bScanBits <= 16)) { - wPerLineNeedBufferSize = wWidth * 2; BytePerPixel = 2; chip->dwBytesCountPerRow = (unsigned int) (wWidth) * 2; } else if ((bScanBits == 8)) { - wPerLineNeedBufferSize = wWidth; BytePerPixel = 1; chip->dwBytesCountPerRow = (unsigned int) (wWidth); } else if ((bScanBits < 8)) { - wPerLineNeedBufferSize = wWidth >> 3; BytePerPixel = 1; chip->dwBytesCountPerRow = (unsigned int) (wWidth); } @@ -3983,7 +3968,6 @@ Asic_SetWindow (PAsic chip, SANE_Byte bScanBits, } } - dwTotal_PerLineNeedBufferSize = wPerLineNeedBufferSize; dwTotalLineTheBufferNeed = wLength; chip->Scan.Dpi = wXResolution; @@ -4318,7 +4302,7 @@ Asic_SetSource (PAsic chip, LIGHTSOURCE lsLightSource) DBG (DBG_ASIC, "Asic_SetSource: Source is Reflect\n"); break; case 2: - DBG (DBG_ASIC, "Asic_SetSource: Source is Postion\n"); + DBG (DBG_ASIC, "Asic_SetSource: Source is Position\n"); break; case 4: DBG (DBG_ASIC, "Asic_SetSource: Source is Negtive\n"); @@ -4848,7 +4832,6 @@ Asic_SetCalibrate (PAsic chip, SANE_Byte bScanBits, unsigned short wXResolution, unsigned short wPerLineNeedBufferSize = 0; unsigned short BytePerPixel = 0; - unsigned int dwTotal_PerLineNeedBufferSize = 0; unsigned int dwTotalLineTheBufferNeed = 0; unsigned short dwTotal_CCDResolution = 0; unsigned short wThinkCCDResolution = 0; @@ -4952,7 +4935,6 @@ Asic_SetCalibrate (PAsic chip, SANE_Byte bScanBits, unsigned short wXResolution, wPerLineNeedBufferSize, BytePerPixel, chip->dwBytesCountPerRow); - dwTotal_PerLineNeedBufferSize = wPerLineNeedBufferSize; dwTotalLineTheBufferNeed = wLength; DBG (DBG_ASIC, "wPerLineNeedBufferSize=%d,wLength=%d\n", wPerLineNeedBufferSize, wLength); diff --git a/backend/mustek_usb2_high.c b/backend/mustek_usb2_high.c index a10dbc7..664528e 100644 --- a/backend/mustek_usb2_high.c +++ b/backend/mustek_usb2_high.c @@ -1696,7 +1696,6 @@ static SANE_Bool MustScanner_GetRgb24BitLine1200DPI (SANE_Byte * lpLine, SANE_Bool isOrderInvert, unsigned short * wLinesCount) { - SANE_Byte *lpTemp; unsigned short wWantedTotalLines; unsigned short TotalXferLines; unsigned short wRLinePosOdd = 0; @@ -1717,7 +1716,6 @@ MustScanner_GetRgb24BitLine1200DPI (SANE_Byte * lpLine, SANE_Bool isOrderInvert, g_isScanning = TRUE; TotalXferLines = 0; wWantedTotalLines = *wLinesCount; - lpTemp = lpLine; if (g_bFirstReadImage) { diff --git a/backend/nec.c b/backend/nec.c index c7af955..d5179d3 100644 --- a/backend/nec.c +++ b/backend/nec.c @@ -2823,7 +2823,7 @@ send_threshold_data(NEC_Scanner *s) SANE_Status sane_start (SANE_Handle handle) { - char *mode, *halftone, *paper, *gamma, *edge, *lightcolor, *adf_fsu; + char *mode, *halftone, *gamma, *edge, *lightcolor, *adf_fsu; NEC_Scanner *s = handle; SANE_Status status; size_t buf_size; @@ -2953,7 +2953,6 @@ sane_start (SANE_Handle handle) mode = s->val[OPT_MODE].s; halftone = s->val[OPT_HALFTONE].s; - paper = s->val[OPT_PAPER].s; gamma = s->val[OPT_GAMMA].s; edge = s->val[OPT_EDGE_EMPHASIS].s; lightcolor = s->val[OPT_LIGHTCOLOR].s; diff --git a/backend/net.c b/backend/net.c index 4beb45d..57889a2 100644 --- a/backend/net.c +++ b/backend/net.c @@ -846,15 +846,15 @@ net_avahi_callback (AvahiClient *c, AvahiClientState state, void * userdata) if (error == AVAHI_ERR_DISCONNECTED) { /* Server disappeared - try to reconnect */ - avahi_client_free (avahi_client); - avahi_client = NULL; - if (avahi_browser) { avahi_service_browser_free (avahi_browser); avahi_browser = NULL; } + avahi_client_free (avahi_client); + avahi_client = NULL; + avahi_client = avahi_client_new (avahi_threaded_poll_get (avahi_thread), AVAHI_CLIENT_NO_FAIL, net_avahi_callback, NULL, &error); if (avahi_client == NULL) { diff --git a/backend/niash.c b/backend/niash.c index 950df21..bbc90d3 100644 --- a/backend/niash.c +++ b/backend/niash.c @@ -1491,7 +1491,7 @@ sane_set_io_mode (SANE_Handle __sane_unused__ h, SANE_Bool m) SANE_Status -sane_get_select_fd (SANE_Handle __sane_unused__ h, SANE_Int * __sane_unused__ fd) +sane_get_select_fd (SANE_Handle __sane_unused__ h, SANE_Int __sane_unused__ * fd) { DBG (DBG_MSG, "sane_select_fd\n"); return SANE_STATUS_UNSUPPORTED; diff --git a/backend/niash_core.c b/backend/niash_core.c index e3ae2b8..b87f4f6 100644 --- a/backend/niash_core.c +++ b/backend/niash_core.c @@ -645,9 +645,6 @@ InitScan (TScanParams * pParams, THWParams * pHWParams) int iHeight; int iExpTime; TScanParams Params; - int iHandle; - - iHandle = pHWParams->iXferHandle; /* check validity of scanparameters */ switch (pParams->iDpi) @@ -1228,7 +1225,7 @@ SimpleCalibExt (THWParams * pHWPar, unsigned char *pabCalibTable, SANE_Bool iReversedHead; int startWhiteY, endWhiteY; int startBlackY, endBlackY; - int startBlackX, endBlackX; + int endBlackX; iHandle = pHWPar->iXferHandle; iReversedHead = pHWPar->iReversedHead; @@ -1265,7 +1262,6 @@ SimpleCalibExt (THWParams * pHWPar, unsigned char *pabCalibTable, endWhiteY = 15; startBlackY = 16; endBlackY = 135; - startBlackX = 0; endBlackX = HW_PIXELS; } else @@ -1274,7 +1270,6 @@ SimpleCalibExt (THWParams * pHWPar, unsigned char *pabCalibTable, endWhiteY = 70; startBlackY = 86; endBlackY = 135; - startBlackX = 1666; endBlackX = 3374; } diff --git a/backend/p5_device.c b/backend/p5_device.c index c065ca2..924144e 100644 --- a/backend/p5_device.c +++ b/backend/p5_device.c @@ -214,19 +214,19 @@ read_data (int fd, uint8_t * data, int length) static void index_write_data (int fd, uint8_t index, uint8_t * data, int length) { - int mode, rc; + int mode; unsigned char bval; bval = index; mode = IEEE1284_MODE_EPP | IEEE1284_ADDR; - rc = ioctl (fd, PPSETMODE, &mode); - rc = write (fd, &bval, 1); + ioctl (fd, PPSETMODE, &mode); + write (fd, &bval, 1); mode = IEEE1284_MODE_EPP | IEEE1284_DATA; - rc = ioctl (fd, PPSETMODE, &mode); + ioctl (fd, PPSETMODE, &mode); mode = 0; /* data forward */ - rc = ioctl (fd, PPDATADIR, &mode); - rc = write (fd, data, length); + ioctl (fd, PPDATADIR, &mode); + write (fd, data, length); return; } @@ -469,7 +469,7 @@ setadresses (int fd, uint16_t start, uint16_t end) static int open_pp (const char *devicename) { - int fd, rc, mode = 0; + int fd, mode = 0; char *name; DBG (DBG_proc, "open_pp: start, devicename=%s\n", devicename); @@ -512,8 +512,8 @@ open_pp (const char *devicename) free(name); /* claim device and set it to EPP */ - rc = ioctl (fd, PPCLAIM); - rc = ioctl (fd, PPGETMODES, &mode); + ioctl (fd, PPCLAIM); + ioctl (fd, PPGETMODES, &mode); if (mode & PARPORT_MODE_PCSPP) DBG (DBG_io, "PARPORT_MODE_PCSPP\n"); if (mode & PARPORT_MODE_TRISTATE) @@ -546,12 +546,12 @@ open_pp (const char *devicename) if (mode == -1) { DBG (DBG_error, "open_pp: no EPP mode, giving up ...\n"); - rc = ioctl (fd, PPRELEASE); + ioctl (fd, PPRELEASE); close (fd); return -1; } - rc = ioctl (fd, PPNEGOT, &mode); - rc = ioctl (fd, PPSETMODE, &mode); + ioctl (fd, PPNEGOT, &mode); + ioctl (fd, PPSETMODE, &mode); DBG (DBG_proc, "open_pp: exit\n"); return fd; } diff --git a/backend/pie.c b/backend/pie.c index 941ed62..76cbb47 100644 --- a/backend/pie.c +++ b/backend/pie.c @@ -2781,7 +2781,7 @@ pie_reader_process (Pie_Scanner * scanner, FILE * fp) /* --------------------------------- READER PROCESS SIGTERM HANDLER ------------ */ -static RETSIGTYPE +static void reader_process_sigterm_handler (int signal) { DBG (DBG_sane_info, "reader_process: terminated by signal %d\n", signal); @@ -2896,7 +2896,7 @@ do_cancel (Pie_Scanner * scanner) scanner->scanning = SANE_FALSE; - if (scanner->reader_pid != -1) + if (sanei_thread_is_valid (scanner->reader_pid)) { DBG (DBG_sane_info, "killing reader_process\n"); sanei_thread_kill (scanner->reader_pid); @@ -3703,7 +3703,7 @@ sane_start (SANE_Handle handle) scanner->reader_fds = fds[1]; scanner->reader_pid = sanei_thread_begin( reader_process, (void*)scanner ); - if (scanner->reader_pid == -1) + if (!sanei_thread_is_valid (scanner->reader_pid)) { DBG (1, "sane_start: sanei_thread_begin failed (%s)\n", strerror (errno)); diff --git a/backend/pieusb.c b/backend/pieusb.c index 4b07304..9730888 100644 --- a/backend/pieusb.c +++ b/backend/pieusb.c @@ -109,6 +109,10 @@ extern void write_tiff_rgbi_header (FILE *fptr, int width, int height, int depth #define DBG_info_scan 11 /* information scanner commands */ #define DBG_info_usb 13 /* information usb level functions */ +/* device flags */ + +#define FLAG_SLIDE_TRANSPORT 0x01 + /* -------------------------------------------------------------------------- * * SUPPORTED DEVICES SPECIFICS @@ -150,7 +154,8 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize char config_line[PATH_MAX]; SANE_Word vendor_id; SANE_Word product_id; - SANE_Word model_number; + SANE_Int model_number; + SANE_Int flags; SANE_Status status; int i; @@ -183,18 +188,22 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize pieusb_supported_usb_device_list[0].vendor = 0x05e3; pieusb_supported_usb_device_list[0].product = 0x0145; pieusb_supported_usb_device_list[0].model = 0x30; + pieusb_supported_usb_device_list[0].flags = 0; /* Reflecta ProScan 7200, model number 0x36 */ pieusb_supported_usb_device_list[1].vendor = 0x05e3; pieusb_supported_usb_device_list[1].product = 0x0145; pieusb_supported_usb_device_list[1].model = 0x36; - /* Reflecta 6000 Multiple Slide Scanner */ + pieusb_supported_usb_device_list[1].flags = 0; + /* Reflecta 6000 Multiple Slide Scanner, model number 0x3a */ pieusb_supported_usb_device_list[2].vendor = 0x05e3; pieusb_supported_usb_device_list[2].product = 0x0142; pieusb_supported_usb_device_list[2].model = 0x3a; + pieusb_supported_usb_device_list[2].flags = FLAG_SLIDE_TRANSPORT; /* end of list */ pieusb_supported_usb_device_list[3].vendor = 0; pieusb_supported_usb_device_list[3].product = 0; pieusb_supported_usb_device_list[3].model = 0; + pieusb_supported_usb_device_list[3].flags = 0; /* Add entries from config file */ fp = sanei_config_open (PIEUSB_CONFIG_FILE); @@ -209,14 +218,14 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize if (strncmp (config_line, "usb ", 4) != 0) continue; /* Parse vendor-id, product-id and model number and add to list */ DBG (DBG_info_sane, "sane_init() config file parsing %s\n", config_line); - status = sanei_pieusb_parse_config_line(config_line, &vendor_id, &product_id, &model_number); + status = sanei_pieusb_parse_config_line(config_line, &vendor_id, &product_id, &model_number, &flags); if (status == SANE_STATUS_GOOD) { - DBG (DBG_info_sane, "sane_init() config file lists device %04x %04x %02x\n",vendor_id, product_id, model_number); - if (!sanei_pieusb_supported_device_list_contains(vendor_id, product_id, model_number)) { - DBG (DBG_info_sane, "sane_init() adding device %04x %04x %02x\n",vendor_id, product_id, model_number); - sanei_pieusb_supported_device_list_add(vendor_id, product_id, model_number); + DBG (DBG_info_sane, "sane_init() config file lists device %04x %04x %02x %02x\n",vendor_id, product_id, model_number, flags); + if (!sanei_pieusb_supported_device_list_contains(vendor_id, product_id, model_number, flags)) { + DBG (DBG_info_sane, "sane_init() adding device %04x %04x %02x %02x\n",vendor_id, product_id, model_number, flags); + sanei_pieusb_supported_device_list_add(vendor_id, product_id, model_number, flags); } else { - DBG (DBG_info_sane, "sane_init() list already contains %04x %04x %02x\n", vendor_id, product_id, model_number); + DBG (DBG_info_sane, "sane_init() list already contains %04x %04x %02x %02x\n", vendor_id, product_id, model_number, flags); } } else { DBG (DBG_info_sane, "sane_init() config file parsing %s: error\n", config_line); @@ -235,8 +244,13 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize pieusb_supported_usb_device.vendor = pieusb_supported_usb_device_list[i].vendor; pieusb_supported_usb_device.product = pieusb_supported_usb_device_list[i].product; pieusb_supported_usb_device.model = pieusb_supported_usb_device_list[i].model; + pieusb_supported_usb_device.flags = pieusb_supported_usb_device_list[i].flags; pieusb_supported_usb_device.device_number = -1; /* No device number (yet) */ - DBG( DBG_info_sane, "sane_init() looking for Reflecta scanner %04x %04x model %02x\n", pieusb_supported_usb_device.vendor, pieusb_supported_usb_device.product, pieusb_supported_usb_device.model); + DBG( DBG_info_sane, "sane_init() looking for scanner %04x %04x model %02x, flags %02x\n", + pieusb_supported_usb_device.vendor, + pieusb_supported_usb_device.product, + pieusb_supported_usb_device.model, + pieusb_supported_usb_device.flags); sanei_usb_find_devices (pieusb_supported_usb_device.vendor, pieusb_supported_usb_device.product, sanei_pieusb_find_device_callback); i++; } @@ -354,6 +368,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) pieusb_supported_usb_device.vendor = vendor; pieusb_supported_usb_device.product = product; pieusb_supported_usb_device.model = pieusb_supported_usb_device_list[i].model; + pieusb_supported_usb_device.flags = pieusb_supported_usb_device_list[i].flags; pieusb_supported_usb_device.device_number = -1; sanei_usb_find_devices (vendor, product, sanei_pieusb_find_device_callback); if (pieusb_supported_usb_device.device_number == -1) { @@ -994,17 +1009,18 @@ sane_start (SANE_Handle handle) * * ---------------------------------------------------------------------- */ - sanei_pieusb_cmd_17 (scanner->device_number, 1, &status); - if (status.pieusb_status != PIEUSB_STATUS_GOOD) { - DBG (DBG_error, "sane_start(): sanei_pieusb_cmd_17 failed: %d\n", status.pieusb_status); - return SANE_STATUS_IO_ERROR; - } - st = sanei_pieusb_wait_ready (scanner, 0); - if (st != SANE_STATUS_GOOD) { - DBG (DBG_error, "sane_start(): scanner not ready after sanei_pieusb_cmd_17: %d\n", st); - return st; + if (scanner->device->flags & FLAG_SLIDE_TRANSPORT) { + sanei_pieusb_cmd_17 (scanner->device_number, 1, &status); + if (status.pieusb_status != PIEUSB_STATUS_GOOD) { + DBG (DBG_error, "sane_start(): sanei_pieusb_cmd_17 failed: %d\n", status.pieusb_status); + return SANE_STATUS_IO_ERROR; + } + st = sanei_pieusb_wait_ready (scanner, 0); + if (st != SANE_STATUS_GOOD) { + DBG (DBG_error, "sane_start(): scanner not ready after sanei_pieusb_cmd_17: %d\n", st); + return st; + } } - /* ---------------------------------------------------------------------- * * Get & set initial gains and offsets @@ -1039,20 +1055,21 @@ sane_start (SANE_Handle handle) /* ---------------------------------------------------------------------- * - * Lamp on + * Init slide transport * * ---------------------------------------------------------------------- */ - sanei_pieusb_cmd_slide (scanner->device_number, SLIDE_LAMP_ON, &status); - if (status.pieusb_status != PIEUSB_STATUS_GOOD) { - DBG (DBG_error, "sane_start(): sanei_pieusb_cmd_slide failed: %d\n", status.pieusb_status); - return SANE_STATUS_IO_ERROR; - } - st = sanei_pieusb_wait_ready (scanner, 0); - if (st != SANE_STATUS_GOOD) { - DBG (DBG_error, "sane_start: scanner not ready %d\n", st); - return st; + if (scanner->device->flags & FLAG_SLIDE_TRANSPORT) { + sanei_pieusb_cmd_slide (scanner->device_number, SLIDE_INIT, &status); + if (status.pieusb_status != PIEUSB_STATUS_GOOD) { + DBG (DBG_error, "sane_start(): sanei_pieusb_cmd_slide failed: %d\n", status.pieusb_status); + return SANE_STATUS_IO_ERROR; + } + st = sanei_pieusb_wait_ready (scanner, 0); + if (st != SANE_STATUS_GOOD) { + DBG (DBG_error, "sane_start: scanner not ready %d\n", st); + return st; + } } - /* Enter SCAN phase 1 */ DBG (DBG_info_sane, "sane_start(): scan phase 1\n"); @@ -1200,12 +1217,14 @@ sane_start (SANE_Handle handle) * Advance to next slide (except for preview) * * ---------------------------------------------------------------------- */ - if (scanner->val[OPT_ADVANCE_SLIDE].b && !scanner->val[OPT_PREVIEW].b) { - sanei_pieusb_cmd_slide (scanner->device_number, SLIDE_NEXT, &status); - if (status.pieusb_status != PIEUSB_STATUS_GOOD) { - DBG (DBG_error, "sane_start(): sanei_pieusb_cmd_slide failed: %d\n", status.pieusb_status); - } + if (scanner->device->flags & FLAG_SLIDE_TRANSPORT) { + if (scanner->val[OPT_ADVANCE_SLIDE].b && !scanner->val[OPT_PREVIEW].b) { + sanei_pieusb_cmd_slide (scanner->device_number, SLIDE_NEXT, &status); + if (status.pieusb_status != PIEUSB_STATUS_GOOD) { + DBG (DBG_error, "sane_start(): sanei_pieusb_cmd_slide failed: %d\n", status.pieusb_status); + } + } } /* ---------------------------------------------------------------------- diff --git a/backend/pieusb.conf.in b/backend/pieusb.conf.in index ec5ba7e..8904d3d 100644 --- a/backend/pieusb.conf.in +++ b/backend/pieusb.conf.in @@ -1,9 +1,20 @@ # pieusb.conf: Configuration file for PIE/Reflecta USB scanner # Read man sane-pieusb for documentation -# Autodetect -# Reflecta 6000 Multiple Slide Scanner -usb 0x05e3 0x0142 +# Format +# usb +# +# Autodetect (built-in) +# Reflecta DigitDia 6000 Multiple Slide Scanner +# usb 0x05e3 0x0142 0x3a 0x01 # Reflecta CrystalScan 7200 +# usb 0x05e3 0x0145 0x30 0x00 # Reflecta ProScan 7200 -usb 0x05e3 0x0145 +# usb 0x05e3 0x0145 0x36 0x00 + +# Reflecta ProScan 10T +usb 0x05e3 0x0145 0x47 0x00 +# Reflecta CrystalScan 3600 +usb 0x05e3 0x0145 0x2e 0x00 +# Reflecta DigitDia 4000 +usb 0x05e3 0x0142 0x2f 0x00 diff --git a/backend/pieusb.h b/backend/pieusb.h index 10ce106..dc4cda7 100644 --- a/backend/pieusb.h +++ b/backend/pieusb.h @@ -80,6 +80,7 @@ struct Pieusb_USB_Device_Entry SANE_Word product; /* USB product identifier */ SANE_Word model; /* USB model number */ SANE_Int device_number; /* USB device number if the device is present */ + SANE_Int flags; /* flags */ }; extern struct Pieusb_USB_Device_Entry* pieusb_supported_usb_device_list; diff --git a/backend/pieusb_buffer.c b/backend/pieusb_buffer.c index 53bd867..8c67a65 100644 --- a/backend/pieusb_buffer.c +++ b/backend/pieusb_buffer.c @@ -100,15 +100,8 @@ #include #include #include -#include -/* When creating the release backend, make complains about unresolved external - * le16toh, although it finds the include */ -#if __BYTE_ORDER == __LITTLE_ENDIAN - #define le16toh(x) (x) -#else - #define le16toh(x) __bswap_16 (x) -#endif +#include "byteorder.h" static void buffer_update_read_index(struct Pieusb_Read_Buffer* buffer, int increment); @@ -163,7 +156,7 @@ sanei_pieusb_buffer_create(struct Pieusb_Read_Buffer* buffer, SANE_Int width, SA snprintf(buffer->buffer_name, L_tmpnam, "/tmp/sane.XXXXXX"); if (buffer->data_file != 0) /* might still be open from previous invocation */ close(buffer->data_file); - buffer->data_file = mkostemp(buffer->buffer_name, O_RDWR | O_CREAT | O_EXCL | O_TRUNC); + buffer->data_file = mkstemp(buffer->buffer_name); if (buffer->data_file == -1) { buffer->data_file = 0; buffer->data = NULL; diff --git a/backend/pieusb_scancmd.c b/backend/pieusb_scancmd.c index a86f8fe..672716f 100644 --- a/backend/pieusb_scancmd.c +++ b/backend/pieusb_scancmd.c @@ -212,7 +212,7 @@ sanei_pieusb_cmd_test_unit_ready(SANE_Int device_number, struct Pieusb_Command_S /** * slide action - * @param action SLIDE_NEXT, SLIDE_PREV, SLIDE_LAMP_ON, SLIDE_RELOAD + * @param action SLIDE_NEXT, SLIDE_PREV, SLIDE_INIT, SLIDE_RELOAD * @return Pieusb_Command_Status */ @@ -294,57 +294,6 @@ sanei_pieusb_cmd_get_sense(SANE_Int device_number, struct Pieusb_Sense* sense, s free(sd); } -/** - * Read the halftone pattern with the specified index. This requires two - * commands, one to ask the device to prepare the pattern, and one to read it. - * - * @param device_number Device number - * @param index index of halftone pattern - * @param pattern Halftone pattern (not implemented) - * @return Pieusb_Command_Status - * @see Pieusb_Halftone_Pattern - */ -void -sanei_pieusb_cmd_get_halftone_pattern(SANE_Int device_number, SANE_Int index, struct Pieusb_Halftone_Pattern* pattern, struct Pieusb_Command_Status *status) -{ - SANE_Byte command[SCSI_COMMAND_LEN]; -#define PATTERN_SIZE 256 /* Assumed maximum pattern size */ - SANE_Int size = PATTERN_SIZE; - SANE_Byte data[PATTERN_SIZE]; - int psize; - SANE_Char* desc; - PIEUSB_Status st; - - DBG (DBG_info_scan, "sanei_pieusb_cmd_get_halftone_pattern()\n"); - - /* Ask scanner to prepare the pattern with the given index. Only SCSI_COMMAND_LEN bytes of data. */ - _prep_scsi_cmd(command, SCSI_WRITE, SCSI_COMMAND_LEN); - memset(data, '\0', SCSI_COMMAND_LEN); - data[0] = SCSI_HALFTONE_PATTERN | 0x80; /* set bit 7 means prepare read */ - data[4] = index; - - st = sanei_pieusb_command(device_number, command, data, SCSI_COMMAND_LEN); - if (st != PIEUSB_STATUS_GOOD) { - status->pieusb_status = st; - /* FIXME */ - return; - } - - /* Read pattern */ - _prep_scsi_cmd(command, SCSI_READ, size); - - memset(data, '\0', size); - status->pieusb_status = sanei_pieusb_command (device_number, command, data, size); - - /*FIXME: analyse */ - fprintf(stderr, "Halftone pattern %d:\n", index); - psize = (data[3]<<8) + data[2]; - desc = (SANE_Char*)(data + 4 + psize); - data[4 + psize + 16] = '\0'; - fprintf(stderr,"Descr. offset from byte 4 = %d, %16s, index = %d, size = %dx%d\n", psize, desc, data[4]&0x7F, data[6], data[7]); -#undef PATTERN_SIZE -} - /** * Read the scan frame with the specified index. This requires two * commands, one to ask the device to prepare the pattern, and one to read it. @@ -425,38 +374,6 @@ sanei_pieusb_cmd_17(SANE_Int device_number, SANE_Int value, struct Pieusb_Comman } } -/** - * Read the relative exposure time for the specified colorbits. This requires two - * commands, one to ask the device to prepare the value, and one to read it. - * - * @param device_number Device number - * @param time Relative exposure time(s) - * @return Pieusb_Command_Status - * @see Pieusb_Exposure_Time - */ -void -sanei_pieusb_cmd_get_exposure_time(SANE_Int device_number, SANE_Int colorbits, struct Pieusb_Exposure_Time* time, struct Pieusb_Command_Status *status) -{ - DBG (DBG_info_scan, "sanei_pieusb_cmd_get_exposure_time(): not implemented\n"); - status->pieusb_status = PIEUSB_STATUS_INVAL; -} - -/** - * Read the highlight and shadow levels with the specified colorbits. This requires two - * commands, one to ask the device to prepare the value, and one to read it. - * - * @param device_number Device number - * @param hgltshdw Highlight and shadow level(s) - * @return Pieusb_Command_Status - * @see Pieusb_Highlight_Shadow - */ -void -sanei_pieusb_cmd_get_highlight_shadow(SANE_Int device_number, SANE_Int colorbits, struct Pieusb_Highlight_Shadow* hgltshdw, struct Pieusb_Command_Status *status) -{ - DBG (DBG_info_scan, "sanei_pieusb_cmd_get_highlight_shadow(): not implemented\n"); - status->pieusb_status = PIEUSB_STATUS_INVAL; -} - /** * Read the shading data parameters. This requires two * commands, one to ask the device to prepare the value, and one to read it. @@ -551,23 +468,6 @@ sanei_pieusb_cmd_get_scanned_lines(SANE_Int device_number, SANE_Byte* data, SANE status->pieusb_status = sanei_pieusb_command (device_number, command, data, size); } -/** - * Set the halftone pattern with the given index to the specified pattern. The - * command is a SCSI WRITE command (code 0x0A, write code 0x11). - * - * @param device_number Device number - * @param index Pattern index (0-7) - * @param pattern Halftone pattern (not implemented) - * @return Pieusb_Command_Status - * @see Pieusb_Halftone_Pattern - */ -void -sanei_pieusb_cmd_set_halftone_pattern(SANE_Int device_number, SANE_Int index, struct Pieusb_Halftone_Pattern* pattern, struct Pieusb_Command_Status *status) -{ - DBG (DBG_info_scan, "sanei_pieusb_cmd_set_halftone_pattern(): not implemented\n"); - status->pieusb_status = PIEUSB_STATUS_INVAL; -} - /** * Set the scan frame with the given index to the frame. The command is a SCSI * WRITE command (code SCSI_WRITE, write code SCSI_SCAN_FRAME). @@ -682,24 +582,6 @@ sanei_pieusb_cmd_set_highlight_shadow(SANE_Int device_number, struct Pieusb_High #undef HIGHLIGHT_SHADOW_SIZE } -/** - * Set the CCD-mask for the colors set in the given color bit mask. The mask - * array must contain mask_size. The command is a SCSI WRITE command - * (code 0x0A, write code 0x16). - * (The command is able to handle more masks at once, but that is not implemented.) - * - * @param device_number Device number - * @param colorbits 0000RGB0 color bit mask; at least one color bit must be set - * @param mask CCD mask to use - * @return Pieusb_Command_Status - */ -void -sanei_pieusb_cmd_set_ccd_mask(SANE_Int device_number, SANE_Byte colorbits, SANE_Byte* mask, SANE_Int mask_size, struct Pieusb_Command_Status *status) -{ - DBG (DBG_info_scan, "sanei_pieusb_cmd_set_ccd_mask(): not implemented\n"); - status->pieusb_status = PIEUSB_STATUS_INVAL; -} - /* SCSI PARAM, code 0x0F */ /** * Get the parameters of an executed scan, such as width, lines and bytes, which diff --git a/backend/pieusb_scancmd.h b/backend/pieusb_scancmd.h index 0dee646..5eefa55 100644 --- a/backend/pieusb_scancmd.h +++ b/backend/pieusb_scancmd.h @@ -318,7 +318,7 @@ struct Pieusb_Command_Status { typedef struct Pieusb_Scanner_Properties Pieusb_Scanner_Properties; typedef enum { - SLIDE_NEXT = 0x04, SLIDE_PREV = 0x05, SLIDE_LAMP_ON = 0x10, SLIDE_RELOAD = 0x40 + SLIDE_NEXT = 0x04, SLIDE_PREV = 0x05, SLIDE_INIT = 0x10, SLIDE_RELOAD = 0x40 } slide_action; void sanei_pieusb_cmd_slide(SANE_Int device_number, slide_action action, struct Pieusb_Command_Status *status); diff --git a/backend/pieusb_specific.c b/backend/pieusb_specific.c index 8231075..ce107cf 100644 --- a/backend/pieusb_specific.c +++ b/backend/pieusb_specific.c @@ -292,6 +292,8 @@ sanei_pieusb_find_device_callback (const char *devicename) return SANE_STATUS_INVAL; } + dev->flags = pieusb_supported_usb_device.flags; + /* Found a supported scanner, put it in the definitions list*/ DBG (DBG_info_proc, "sanei_pieusb_find_device_callback: success\n"); dev->next = pieusb_definition_list_head; @@ -996,18 +998,23 @@ sanei_pieusb_init_options (Pieusb_Scanner* scanner) } /** - * Parse line from config file into a vendor id, product id and a model number + * Parse line from config file into a vendor id, product id, model number, and flags * * @param config_line Text to parse * @param vendor_id * @param product_id * @param model_number + * @param flags * @return SANE_STATUS_GOOD, or SANE_STATUS_INVAL in case of a parse error */ SANE_Status -sanei_pieusb_parse_config_line(const char* config_line, SANE_Word* vendor_id, SANE_Word* product_id, SANE_Word* model_number) +sanei_pieusb_parse_config_line(const char* config_line, + SANE_Word* vendor_id, + SANE_Word* product_id, + SANE_Int* model_number, + SANE_Int* flags) { - char *vendor_id_string, *product_id_string, *model_number_string; + char *vendor_id_string, *product_id_string, *model_number_string, *flags_string; if (strncmp (config_line, "usb ", 4) != 0) { return SANE_STATUS_INVAL; @@ -1041,12 +1048,12 @@ sanei_pieusb_parse_config_line(const char* config_line, SANE_Word* vendor_id, SA } else { return SANE_STATUS_INVAL; } - /* Detect product-id */ + /* Detect model number */ config_line = sanei_config_skip_whitespace (config_line); if (*config_line) { config_line = sanei_config_get_string (config_line, &model_number_string); if (model_number_string) { - *model_number = strtol (model_number_string, 0, 0); + *model_number = (SANE_Int) strtol (model_number_string, 0, 0); free (model_number_string); } else { return SANE_STATUS_INVAL; @@ -1055,6 +1062,16 @@ sanei_pieusb_parse_config_line(const char* config_line, SANE_Word* vendor_id, SA } else { return SANE_STATUS_INVAL; } + /* Detect (optional) flags */ + *flags = 0; + config_line = sanei_config_skip_whitespace (config_line); + if (*config_line) { + config_line = sanei_config_get_string (config_line, &flags_string); + if (flags_string) { + *flags = (SANE_Int) strtol (flags_string, 0, 0); + free (flags_string); + } + } return SANE_STATUS_GOOD; } @@ -1064,16 +1081,18 @@ sanei_pieusb_parse_config_line(const char* config_line, SANE_Word* vendor_id, SA * @param vendor_id * @param product_id * @param model_number + * @param flags * @return */ SANE_Bool -sanei_pieusb_supported_device_list_contains(SANE_Word vendor_id, SANE_Word product_id, SANE_Word model_number) +sanei_pieusb_supported_device_list_contains(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags) { int i = 0; while (pieusb_supported_usb_device_list[i].vendor != 0) { if (pieusb_supported_usb_device_list[i].vendor == vendor_id && pieusb_supported_usb_device_list[i].product == product_id - && pieusb_supported_usb_device_list[i].model == model_number) { + && pieusb_supported_usb_device_list[i].model == model_number + && pieusb_supported_usb_device_list[i].flags == flags) { return SANE_TRUE; } i++; @@ -1086,10 +1105,11 @@ sanei_pieusb_supported_device_list_contains(SANE_Word vendor_id, SANE_Word produ * @param vendor_id * @param product_id * @param model_number + * @param flags * @return */ SANE_Status -sanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id, SANE_Word model_number) +sanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags) { int i = 0, k; struct Pieusb_USB_Device_Entry* dl; @@ -1099,10 +1119,11 @@ sanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id } /* i is index of last entry */ for (k=0; k<=i; k++) { - DBG(DBG_info_proc,"sanei_pieusb_supported_device_list_add(): current %03d: %04x %04x %02x\n", i, + DBG(DBG_info_proc,"sanei_pieusb_supported_device_list_add(): current %03d: %04x %04x %02x %02x\n", i, pieusb_supported_usb_device_list[k].vendor, pieusb_supported_usb_device_list[k].product, - pieusb_supported_usb_device_list[k].model); + pieusb_supported_usb_device_list[k].model, + pieusb_supported_usb_device_list[k].flags); } dl = realloc(pieusb_supported_usb_device_list,(i+2)*sizeof(struct Pieusb_USB_Device_Entry)); /* Add one entry to list */ @@ -1114,14 +1135,17 @@ sanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id pieusb_supported_usb_device_list[i].vendor = vendor_id; pieusb_supported_usb_device_list[i].product = product_id; pieusb_supported_usb_device_list[i].model = model_number; + pieusb_supported_usb_device_list[i].flags = flags; pieusb_supported_usb_device_list[i+1].vendor = 0; pieusb_supported_usb_device_list[i+1].product = 0; pieusb_supported_usb_device_list[i+1].model = 0; + pieusb_supported_usb_device_list[i+1].flags = 0; for (k=0; k<=i+1; k++) { - DBG(DBG_info_proc,"sanei_pieusb_supported_device_list_add() add: %03d: %04x %04x %02x\n", i, + DBG(DBG_info_proc,"sanei_pieusb_supported_device_list_add() add: %03d: %04x %04x %02x %02x\n", i, pieusb_supported_usb_device_list[k].vendor, pieusb_supported_usb_device_list[k].product, - pieusb_supported_usb_device_list[k].model); + pieusb_supported_usb_device_list[k].model, + pieusb_supported_usb_device_list[k].flags); } return SANE_STATUS_GOOD; } diff --git a/backend/pieusb_specific.h b/backend/pieusb_specific.h index 3928adf..f516960 100644 --- a/backend/pieusb_specific.h +++ b/backend/pieusb_specific.h @@ -193,6 +193,7 @@ struct Pieusb_Device_Definition /* USB id's like 0x05e3 0x0145, see pieusb.conf */ SANE_String version; /* INQUIRY productRevision */ SANE_Byte model; /* INQUIRY model */ + SANE_Byte flags; /* pieusb.conf flags */ /* Ranges for various quantities */ SANE_Range dpi_range; @@ -315,7 +316,11 @@ struct Pieusb_Scanner typedef struct Pieusb_Scanner Pieusb_Scanner; -SANE_Status sanei_pieusb_parse_config_line(const char* config_line, SANE_Word* vendor_id, SANE_Word* product_id, SANE_Word* model_number); +SANE_Status sanei_pieusb_parse_config_line(const char* config_line, + SANE_Word* vendor_id, + SANE_Word* product_id, + SANE_Int* model_number, + SANE_Int* flags); /* sub to sane_start() */ SANE_Status sanei_pieusb_post (Pieusb_Scanner *scanner, uint16_t **in_img, int planes); void sanei_pieusb_correct_shading(struct Pieusb_Scanner *scanner, struct Pieusb_Read_Buffer *buffer); @@ -329,8 +334,8 @@ SANE_Status sanei_pieusb_set_frame_from_options(Pieusb_Scanner * scanner); void sanei_pieusb_print_options(struct Pieusb_Scanner *scanner); /* sub to sane_control_option() and sane_start() */ int sanei_pieusb_analyse_options(struct Pieusb_Scanner *scanner); -SANE_Bool sanei_pieusb_supported_device_list_contains(SANE_Word vendor_id, SANE_Word product_id, SANE_Word model_number); -SANE_Status sanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id, SANE_Word model_number); +SANE_Bool sanei_pieusb_supported_device_list_contains(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags); +SANE_Status sanei_pieusb_supported_device_list_add(SANE_Word vendor_id, SANE_Word product_id, SANE_Int model_number, SANE_Int flags); /* sub to sane_init() and sane_open() */ SANE_Status sanei_pieusb_find_device_callback (const char *devicename); /* sub to sane_open() */ diff --git a/backend/pixma.c b/backend/pixma.c index 3396155..d50e4ca 100644 --- a/backend/pixma.c +++ b/backend/pixma.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2007-2008 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -782,6 +782,14 @@ control_option (pixma_sane_t * ss, SANE_Int n, 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; @@ -801,6 +809,7 @@ print_scan_param (int level, const pixma_scan_param_t * sp) 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 @@ -850,6 +859,7 @@ calc_scan_param (pixma_sane_t * ss, pixma_scan_param_t * sp) 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) @@ -928,7 +938,7 @@ init_option_descriptors (pixma_sane_t * ss) /* Writing to reader_ss outside reader_process() is a BUG! */ static pixma_sane_t *reader_ss = NULL; -static RETSIGTYPE +static void reader_signal_handler (int sig) { if (reader_ss) @@ -1083,7 +1093,7 @@ terminate_reader_task (pixma_sane_t * ss, int *exit_code) int status = 0; pid = ss->reader_taskid; - if (pid == -1) + if (!sanei_thread_is_valid (pid)) return -1; if (sanei_thread_is_forked ()) { @@ -1129,7 +1139,7 @@ start_reader_task (pixma_sane_t * ss) ss->rpipe = -1; ss->wpipe = -1; } - if (ss->reader_taskid != -1) + if (sanei_thread_is_valid (ss->reader_taskid)) { PDBG (pixma_dbg (1, "BUG:reader_taskid(%ld) != -1\n", (long) ss->reader_taskid)); @@ -1159,7 +1169,7 @@ start_reader_task (pixma_sane_t * ss) { pid = sanei_thread_begin (reader_thread, ss); } - if (pid == -1) + if (!sanei_thread_is_valid (pid)) { close (ss->wpipe); close (ss->rpipe); @@ -1227,7 +1237,7 @@ read_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen) ss->image_bytes_read, ss->sp.image_size)); close (ss->rpipe); ss->rpipe = -1; - if (terminate_reader_task (ss, &status) != -1 + if (sanei_thread_is_valid (terminate_reader_task (ss, &status)) && status != SANE_STATUS_GOOD) { return status; @@ -1371,6 +1381,7 @@ sane_open (SANE_String_Const name, SANE_Handle * h) 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); @@ -1620,6 +1631,7 @@ sane_cancel (SANE_Handle h) if (!ss) return; ss->cancel = SANE_TRUE; + ss->sp.frontend_cancel = SANE_TRUE; if (ss->idle) return; close (ss->rpipe); @@ -1812,6 +1824,13 @@ type int 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 */ diff --git a/backend/pixma.conf.in b/backend/pixma.conf.in index a275b03..3f5c61a 100644 --- a/backend/pixma.conf.in +++ b/backend/pixma.conf.in @@ -1,5 +1,11 @@ # pixma.conf configuration for the sane pixma backend # +# bjnp-timeout=5000 +# Specify the timeout (in ms) to be used for all the folllowing +# scanners. +# May be specified multiple times. +# The last value (if any) will be used for auto-detection +# # define URI's of scanners (one per line) # This is only used for network scanners. # normally scanners will be detected by sending a broadcast @@ -8,7 +14,12 @@ # # method must be bjnp # port number can normally be left out, port 8612 is used as default +# The timeout parameter sets a timeout value for the scanner on +# the same line # Example: -# bjnp://myscanner.my.domain:8612 -# bjnp://printer-1.pheasant.org +# bjnp://myscanner.my.domain:8612 // uses the default 1000ms timeout +# bjnp-timeout=5000 +# bjnp://printer-1.pheasant.org // will use the 5000 ms timeout +# bjnp://scanner.bad-network.org/timeout=1500 // timeout set to 1500 ms +# bjnp-timeout=3000 // will be used for auto-detected scanners # diff --git a/backend/pixma.h b/backend/pixma.h index 620f038..6d723fb 100644 --- a/backend/pixma.h +++ b/backend/pixma.h @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2007-2008 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -110,11 +110,14 @@ typedef uint32_t uint32_t; /** \addtogroup API * @{ */ +/** Don't forget to update the backend version in the SANE Backend specification + * file: doc/descriptions/pixma.desc !!! + */ /** \name Version of the driver */ /**@{*/ #define PIXMA_VERSION_MAJOR 0 #define PIXMA_VERSION_MINOR 17 -#define PIXMA_VERSION_BUILD 23 +#define PIXMA_VERSION_BUILD 37 /**@}*/ /** \name Error codes */ @@ -150,6 +153,7 @@ typedef uint32_t uint32_t; #define PIXMA_CAP_LINEART (1 << 9) #define PIXMA_CAP_NEGATIVE (1 << 10) #define PIXMA_CAP_TPUIR ((1 << 11) | PIXMA_CAP_TPU) +#define PIXMA_CAP_ADF_WAIT (1 << 12) #define PIXMA_CAP_EXPERIMENT (1 << 31) /**@}*/ @@ -337,6 +341,10 @@ struct pixma_scan_param_t /** The current page # in the same ADF scan session, 0 in non ADF */ unsigned adf_pageid; + + /** adf-wait */ + unsigned adf_wait; + unsigned frontend_cancel; }; /** PIXMA model information */ diff --git a/backend/pixma_bjnp.c b/backend/pixma_bjnp.c index 7d2d541..fc4c501 100644 --- a/backend/pixma_bjnp.c +++ b/backend/pixma_bjnp.c @@ -85,7 +85,7 @@ #ifdef HAVE_IFADDRS_H #include #endif -#ifdef HAVE_SYS_SELSECT_H +#ifdef HAVE_SYS_SELECT_H #include #endif #ifdef HAVE_PWD_H @@ -395,18 +395,19 @@ determine_scanner_serial (const char *hostname, const char * mac_address, char * /* if we only have a literal ipv6 address, we use the mac-address */ strcpy(copy, hostname); - while (strlen (copy) >= SHORT_HOSTNAME_MAX) + if (strlen (copy) >= SERIAL_MAX) { + /* make the string fit into the serial */ /* if this is a FQDN, not an ip-address, remove domain part of the name */ if ((dot = strchr (copy, '.')) != NULL) { *dot = '\0'; } - else - { - strcpy(copy, mac_address); - break; - } + } + /* check if name is still to long. If so use the mac-address */ + if (strlen(copy) >= SERIAL_MAX) + { + strcpy(copy, mac_address); } strcpy( serial, copy ); return serial; @@ -566,6 +567,7 @@ split_uri (const char *devname, char *method, char *host, char *port, return -1; } strcpy(port, start); + start = end_of_port + 1; } /* @@ -613,7 +615,6 @@ set_cmd_for_dev (int devno, struct BJNP_command *cmd, char cmd_code, int payload /* * Set command buffer with command code, session_id and length of payload * Returns: sequence number of command - * If devno < 0, then use devno as negativ index into bjnp_protocol_defs */ strncpy (cmd->BJNP_id, device[devno].protocol_string, sizeof (cmd->BJNP_id)); @@ -706,8 +707,8 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response, FD_ZERO (&fdset); FD_SET (sockfd, &fdset); - timeout.tv_sec = BJNP_TIMEOUT_UDP; - timeout.tv_usec = 0; + timeout.tv_sec = device[dev_no].bjnp_timeout /1000; + timeout.tv_usec = device[dev_no].bjnp_timeout %1000; } while (((result = select (sockfd + 1, &fdset, NULL, NULL, &timeout)) <= 0) @@ -737,7 +738,7 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response, close(sockfd); PDBG (bjnp_dbg - (LOG_CRIT, "udp_command: ERROR - no data received\n" ) ); + (LOG_CRIT, "udp_command: ERROR - no data received (timeout = %d)\n", device[dev_no].bjnp_timeout ) ); return -1; } @@ -807,7 +808,7 @@ get_scanner_name(const bjnp_sockaddr_t *scanner_sa, char *host) { /* * Parse identify command responses to ip-address - * and hostname + * and hostname. Return qulity of the address */ struct addrinfo *results; @@ -1423,8 +1424,8 @@ bjnp_recv_header (int devno, size_t *payload_size ) FD_ZERO (&input); FD_SET (fd, &input); - timeout.tv_sec = BJNP_TIMEOUT_TCP; - timeout.tv_usec = 0; + timeout.tv_sec = device[devno].bjnp_timeout /1000; + timeout.tv_usec = device[devno].bjnp_timeout %1000; } while ( ( (result = select (fd + 1, &input, NULL, NULL, &timeout)) <= 0) && (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS)); @@ -1442,7 +1443,8 @@ bjnp_recv_header (int devno, size_t *payload_size ) { terrno = errno; PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_header: ERROR - could not read response header (select timed out)!\n" ) ); + "bjnp_recv_header: ERROR - could not read response header (select timed out after %d ms)!\n", + device[devno].bjnp_timeout ) ); errno = terrno; return SANE_STATUS_IO_ERROR; } @@ -1502,7 +1504,7 @@ bjnp_recv_header (int devno, size_t *payload_size ) } static int -bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *protocol_defs) +bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *protocol_defs, int min_timeout) { /* initialize device structure */ @@ -1524,7 +1526,8 @@ bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *pr device[dn].address_level = get_scanner_name(sa, name); device[dn].session_id = 0; device[dn].serial = -1; - device[dn].bjnp_timeout = 0; + device[dn].bjnp_timeout = min_timeout; + device[dn].bjnp_min_timeout = min_timeout; device[dn].scanner_data_left = 0; device[dn].last_cmd = 0; device[dn].blocksize = BJNP_BLOCKSIZE_START; @@ -1597,8 +1600,8 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len) /* wait for data to be received, retry on a signal being received */ FD_ZERO (&input); FD_SET (fd, &input); - timeout.tv_sec = BJNP_TIMEOUT_TCP; - timeout.tv_usec = 0; + timeout.tv_sec = device[devno].bjnp_timeout /1000; + timeout.tv_usec = device[devno].bjnp_timeout %1000; } while (((result = select (fd + 1, &input, NULL, NULL, &timeout)) <= 0) && (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS)); @@ -1617,7 +1620,8 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len) { terrno = errno; PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_data: ERROR - could not read response payload (select timed out)!\n") ); + "bjnp_recv_data: ERROR - could not read response payload (select timed out after %d ms)!\n", + device[devno].bjnp_timeout) ); errno = terrno; *len = 0; return SANE_STATUS_IO_ERROR; @@ -1643,7 +1647,7 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len) static BJNP_Status bjnp_allocate_device (SANE_String_Const devname, - SANE_Int * dn, char *res_host) + SANE_Int * dn, char *resulting_host) { char method[BJNP_METHOD_MAX]; char host[BJNP_HOST_MAX]; @@ -1654,6 +1658,7 @@ bjnp_allocate_device (SANE_String_Const devname, struct addrinfo hints; int result; int i; + int min_timeout = BJNP_TIMEOUT_DEFAULT; PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_allocate_device(%s) %d\n", devname, bjnp_no_devices)); @@ -1662,20 +1667,29 @@ bjnp_allocate_device (SANE_String_Const devname, return BJNP_STATUS_INVAL; } - if (strlen (args) != 0) + if (strlen (args) > 0) { - PDBG (bjnp_dbg - (LOG_CRIT, - "bjnp_allocate_device: ERROR - URI may not contain userid, password or aguments: %s\n", - devname)); + /* get device specific timeout if any */ + + if (strncmp(args, "timeout=", strlen("timeout=")) == 0) + { + min_timeout = atoi(args + strlen("timeout=")); + if (min_timeout < BJNP_TIMEOUT_DEFAULT) + min_timeout = BJNP_TIMEOUT_DEFAULT; + } else { + PDBG (bjnp_dbg + (LOG_CRIT, + "bjnp_allocate_device: ERROR - Unrecognized argument: %s\n", + devname)); return BJNP_STATUS_INVAL; + } } if ( (protocol_defs = get_protocol_by_method(method)) == NULL) { PDBG (bjnp_dbg - (LOG_CRIT, "bjnp_allocate_device: ERROR - URI %s contains invalid method: %s\n", devname, - method)); + (LOG_CRIT, "bjnp_allocate_device: ERROR - URI %s contains invalid method: %s\n", + devname, method)); return BJNP_STATUS_INVAL; } @@ -1715,24 +1729,26 @@ bjnp_allocate_device (SANE_String_Const devname, { PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_allocate_device: WARNING - Too many devices, ran out of device structures, can not add %s\n", + "bjnp_allocate_device: WARNING - Too many devices, ran out of device structures, cannot add %s\n", devname)); freeaddrinfo(res); return BJNP_STATUS_INVAL; } if (bjnp_init_device_structure( bjnp_no_devices, (bjnp_sockaddr_t *)cur -> ai_addr, - protocol_defs) != 0) + protocol_defs, min_timeout) != 0) { /* giving up on this address, try next one if any */ break; } for (i = 0; i < bjnp_no_devices; i++) { - /* we check for matching addresses as wel as matching mac_addresses as */ - /* an IPv6 host can have multiple adresses */ - if ( (sa_is_equal( device[i].addr, (bjnp_sockaddr_t *)cur -> ai_addr) ) || - ( strcmp( device[i].mac_address, device[bjnp_no_devices].mac_address ) == 0 ) ) + /* Check if found the scanner before, if so we use the best address + * but still make sure the scanner is listed only once. + * We check for matching addresses as wel as matching mac_addresses as + * an IPv6 host can have multiple adresses */ + + if ( strcmp( device[i].mac_address, device[bjnp_no_devices].mac_address ) == 0 ) { if ( device[i].address_level < device[bjnp_no_devices].address_level ) { @@ -1742,6 +1758,16 @@ bjnp_allocate_device (SANE_String_Const devname, device[bjnp_no_devices].addr = NULL; device[i].address_level = device[bjnp_no_devices].address_level; } + + /* check if new timeout value was defined (e.g. from sanei_bjnp_device_open) + * if so, use new timout value */ + + if (device[i].bjnp_min_timeout < device[bjnp_no_devices].bjnp_min_timeout) + { + /* use the longer timeout as requested */ + device[i].bjnp_timeout = device[bjnp_no_devices].bjnp_min_timeout; + device[i].bjnp_min_timeout = device[bjnp_no_devices].bjnp_min_timeout; + } freeaddrinfo(res); *dn = i; bjnp_free_device_structure( bjnp_no_devices); @@ -1754,17 +1780,17 @@ bjnp_allocate_device (SANE_String_Const devname, PDBG (bjnp_dbg (LOG_INFO, "bjnp_allocate_device: Scanner not yet in our list, added it: %s:%s\n", host, port)); - /* return hostname if required */ + /* Commit new device structure */ - if (res_host != NULL) - { - strcpy (res_host, host); - } *dn = bjnp_no_devices; + bjnp_no_devices++; - /* Commit new device structure */ + /* return hostname if required */ - bjnp_no_devices++; + if (resulting_host != NULL) + { + strcpy (resulting_host, host); + } return BJNP_STATUS_GOOD; } @@ -1800,10 +1826,11 @@ static void add_scanner(SANE_Int *dev_no, */ determine_scanner_serial (scanner_host, device[*dev_no].mac_address, serial); + attach_bjnp (uri, makemodel, serial, pixma_devices); - PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner at %s added!\n", - uri)); + PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner added: %s, serial %s, mac addres: %s.\n", + uri, serial, device[*dev_no].mac_address)); } break; case BJNP_STATUS_ALREADY_ALLOCATED: @@ -1818,6 +1845,34 @@ static void add_scanner(SANE_Int *dev_no, } } +int rewrite_uri(char *uri, int timeout, int max_len) +{ + char method[BJNP_METHOD_MAX]; + char host[BJNP_HOST_MAX]; + char port_str[BJNP_PORT_MAX]; + char args[BJNP_HOST_MAX]; + int port; + + if (split_uri(uri, method, host, port_str, args ) != 0) + { + return -1; + } + + port = atoi(port_str); + if (port == 0) + { + port = 8612; + } + + if (strstr(args, "timeout=") == NULL) + { + sprintf(args, "timeout=%d", timeout); + } + + snprintf(uri, max_len -1, "bjnp://%s:%d/%s", host, port, args); + return 0; +} + /* * Public functions @@ -1870,6 +1925,7 @@ sanei_bjnp_find_devices (const char **conf_devices, char uri[256]; int dev_no; int port; + int timeout_default = BJNP_TIMEOUT_DEFAULT; bjnp_sockaddr_t broadcast_addr[BJNP_SOCK_MAX]; bjnp_sockaddr_t scanner_sa; socklen_t socklen; @@ -1885,16 +1941,30 @@ sanei_bjnp_find_devices (const char **conf_devices, { socket_fd[i] = -1; } - /* First add devices from config file */ + + /* Add devices from config file */ if (conf_devices[0] == NULL) PDBG (bjnp_dbg( LOG_DEBUG, "sanei_bjnp_find_devices: No devices specified in configuration file.\n" ) ); for (i = 0; conf_devices[i] != NULL; i++) { + if (strncmp(conf_devices[i], "bjnp-timeout=", strlen("bjnp-timeout="))== 0) + { + timeout_default = atoi(conf_devices[i] + strlen("bjnp-timeout=") ); + if (timeout_default < BJNP_TIMEOUT_DEFAULT) + { + timeout_default = BJNP_TIMEOUT_DEFAULT; + } + PDBG ( bjnp_dbg + (LOG_DEBUG, "Set new default timeout value: %d ms.", timeout_default)); + continue; + } PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Adding scanner from pixma.conf: %s\n", conf_devices[i])); - add_scanner(&dev_no, conf_devices[i], attach_bjnp, pixma_devices); + strncpy(uri, conf_devices[i], sizeof(uri)); + rewrite_uri(uri, timeout_default, sizeof(uri)); + add_scanner(&dev_no, uri, attach_bjnp, pixma_devices); } PDBG (bjnp_dbg (LOG_DEBUG, @@ -2062,8 +2132,8 @@ sanei_bjnp_find_devices (const char **conf_devices, get_scanner_name( &scanner_sa, scanner_host); /* construct URI */ - sprintf (uri, "%s://%s:%d", protocol_defs->method_string, scanner_host, - port); + sprintf (uri, "%s://%s:%d/timeout=%d", protocol_defs->method_string, scanner_host, + port, timeout_default); add_scanner( &dev_no, uri, attach_bjnp, pixma_devices); @@ -2182,8 +2252,15 @@ sanei_bjnp_deactivate (SANE_Int dn) extern void sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout) { - PDBG (bjnp_dbg (LOG_INFO, "bjnp_set_timeout to %d\n", + if (timeout < device[devno].bjnp_min_timeout) + { + PDBG (bjnp_dbg (LOG_INFO, "bjnp_set_timeout to %d, but using minimum value %d\n", + timeout, device[devno].bjnp_min_timeout)); + timeout = device[devno].bjnp_min_timeout; + } else { + PDBG (bjnp_dbg (LOG_INFO, "bjnp_set_timeout to %d\n", timeout)); + } device[devno].bjnp_timeout = timeout; } @@ -2460,16 +2537,6 @@ sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) if ( resp_len > 0 ) { device[dn].polling_status = BJNP_POLL_STATUS_RECEIVED; - - /* this is a bit of a hack, but the scanner does not like */ - /* us to continue using the existing tcp socket */ - - /* No longer required? Does not work anymore now we moved code from sanei_bjnp_activate/sanei_bjnp_deactivate - to the isanei_bjnp_open and sanei_bjnp_close - sanei_bjnp_deactivate(dn); - sanei_bjnp_activate(dn); - */ - return SANE_STATUS_GOOD; } seconds = timeout > 2 ? 2 : timeout; diff --git a/backend/pixma_bjnp.h b/backend/pixma_bjnp.h index 3770bfd..998c331 100644 --- a/backend/pixma_bjnp.h +++ b/backend/pixma_bjnp.h @@ -65,9 +65,10 @@ extern void sanei_bjnp_init (void); /** Find scanners responding to a BJNP broadcast. * - * The function attach is called for every device which has been found. + * The function sanei_bjnp_attach is called for every device which has + * been found. * Serial is the address of the scanner in human readable form of max - * SHORT_HOSTNAME_MAX characters + * SERIAL_MAX characters * @param conf_devices list of pre-configures device URI's to attach * @param attach attach function * @param pixma_devices device informatio needed by attach function @@ -75,7 +76,7 @@ extern void sanei_bjnp_init (void); * @return SANE_STATUS_GOOD - on success (even if no scanner was found) */ -#define SHORT_HOSTNAME_MAX 16 +#define SERIAL_MAX 16 extern SANE_Status sanei_bjnp_find_devices (const char **conf_devices, diff --git a/backend/pixma_bjnp_private.h b/backend/pixma_bjnp_private.h index 1902c7a..9ecc6ae 100644 --- a/backend/pixma_bjnp_private.h +++ b/backend/pixma_bjnp_private.h @@ -80,8 +80,7 @@ /* timers */ #define BJNP_BROADCAST_INTERVAL 10 /* ms between broadcasts */ #define BJNP_BC_RESPONSE_TIMEOUT 500 /* waiting time for broadc. responses */ -#define BJNP_TIMEOUT_UDP 4 /* standard UDP timeout in seconds */ -#define BJNP_TIMEOUT_TCP 4 /* standard TCP timeout in seconds */ +#define BJNP_TIMEOUT_DEFAULT 1000 /* minimum tiemout value for network operations */ #define BJNP_USLEEP_MS 1000 /* sleep for 1 msec */ /* retries */ @@ -371,6 +370,7 @@ typedef struct device_s bjnp_sockaddr_t * addr; /* ip-address of the scanner */ int address_level; /* link local, public or has a FQDN */ int bjnp_timeout; /* timeout (msec) for next poll command */ + int bjnp_min_timeout; /* device specific min timeout */ #ifdef PIXMA_BJNP_USE_STATUS /* polling state information */ diff --git a/backend/pixma_common.c b/backend/pixma_common.c index 9d41f7a..2882453 100644 --- a/backend/pixma_common.c +++ b/backend/pixma_common.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2007-2008 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -57,6 +57,8 @@ #include "pixma_common.h" #include "pixma_io.h" +#include "../include/sane/sanei_usb.h" + #ifdef __GNUC__ # define UNUSED(v) (void) v @@ -649,15 +651,21 @@ pixma_cmd_transaction (pixma_t * s, const void *cmd, unsigned cmdlen, immediatly answer with PIXMA_STATUS_BUSY. Is 8 seconds timeout enough? This affects ALL commands that use - pixma_cmd_transaction(). */ - tmo = 8; + 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)); - pixma_sleep (1000000); /* 1s timeout */ + +#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); @@ -761,6 +769,7 @@ pixma_open (unsigned devnr, pixma_t ** handle) 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) { @@ -839,6 +848,7 @@ pixma_scan (pixma_t * s, pixma_scan_param_t * sp) 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 diff --git a/backend/pixma_common.h b/backend/pixma_common.h index dbaa23f..6c55c71 100644 --- a/backend/pixma_common.h +++ b/backend/pixma_common.h @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2006-2007 Wittawat Yamwong This file is part of the SANE package. @@ -118,6 +118,7 @@ struct pixma_t int cancel; /* NOTE: It can be set in a signal handler. */ uint32_t events; void *subdriver; /* can be used by model driver. */ + int rec_tmo; /* receive timeout [s] */ /* private */ uint64_t cur_image_size; diff --git a/backend/pixma_imageclass.c b/backend/pixma_imageclass.c index b2d45ee..8ad0083 100644 --- a/backend/pixma_imageclass.c +++ b/backend/pixma_imageclass.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2007-2009 Nicolas Martin, Copyright (C) 2008 Dennis Lou, dlou 99 at yahoo dot com @@ -103,6 +103,8 @@ #define MF820_PID 0x27a6 #define MF220_PID 0x27a8 #define MF210_PID 0x27a9 +#define MF230_PID 0x27d1 +#define MF240_PID 0x27d2 enum iclass_state_t @@ -140,9 +142,22 @@ typedef struct iclass_t unsigned last_block; uint8_t generation; /* New multifunctionals are (generation == 2) */ + + uint8_t adf_state; /* handle adf scanning */ } iclass_t; +static int is_scanning_from_adf (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_ADF + || s->param->source == PIXMA_SOURCE_ADFDUP); +} + +static int is_scanning_from_adfdup (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_ADFDUP); +} + static void iclass_finish_scan (pixma_t * s); /* checksumming is sometimes different than pixmas */ @@ -163,7 +178,8 @@ static int has_paper (pixma_t * s) { iclass_t *mf = (iclass_t *) s->subdriver; - return ((mf->current_status[1] & 0x0f) == 0); /* allow 0x10 as ADF paper OK */ + return ((mf->current_status[1] & 0x0f) == 0 /* allow 0x10 as ADF paper OK */ + || mf->current_status[1] == 81); /* allow 0x51 as ADF paper OK */ } static int @@ -185,9 +201,9 @@ query_status (pixma_t * s) if (error >= 0) { memcpy (mf->current_status, data, 12); - DBG (3, "Current status: paper=%u cal=%u lamp=%u\n", - data[1], data[8], data[7]); - PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u\n", + /*DBG (3, "Current status: paper=0x%02x cal=%u lamp=%u\n", + data[1], data[8], data[7]);*/ + PDBG (pixma_dbg (3, "Current status: paper=0x%02x cal=%u lamp=%u\n", data[1], data[8], data[7])); } return error; @@ -229,9 +245,9 @@ select_source (pixma_t * s) { iclass_t *mf = (iclass_t *) s->subdriver; uint8_t *data = pixma_newcmd (&mf->cb, cmd_select_source, 10, 0); - data[0] = (s->param->source == PIXMA_SOURCE_ADF || - s->param->source == PIXMA_SOURCE_ADFDUP) ? 2 : 1; - data[5] = (s->param->source == PIXMA_SOURCE_ADFDUP) ? 3 : 0; + data[0] = (is_scanning_from_adf(s)) ? 2 : 1; + /* special settings for MF6100 */ + data[5] = is_scanning_from_adfdup(s) ? 3 : ((s->cfg->pid == MF6100_PID && s->param->source == PIXMA_SOURCE_ADF) ? 1 : 0); switch (s->cfg->pid) { case MF4200_PID: @@ -263,7 +279,7 @@ send_scan_param (pixma_t * s) pixma_set_be32 (mf->raw_width, data + 0x10); pixma_set_be32 (s->param->h, data + 0x14); data[0x18] = (s->param->channels == 1) ? 0x04 : 0x08; - data[0x19] = s->param->channels * s->param->depth; /* bits per pixel */ + data[0x19] = s->param->channels * ((s->param->depth == 1) ? 8 : s->param->depth); /* bits per pixel */ data[0x1f] = 0x7f; data[0x20] = 0xff; data[0x23] = 0x81; @@ -294,7 +310,10 @@ request_image_block (pixma_t * s, unsigned flag, uint8_t * info, const int hlen = 2 + 6; memset (mf->cb.buf, 0, 11); - pixma_set_be16 (((mf->generation >= 2) ? cmd_read_image2 : cmd_read_image), mf->cb.buf); + /* generation 2 scanners use cmd_read_image2. + * MF6100, ... are exceptions */ + pixma_set_be16 (((mf->generation >= 2 + && s->cfg->pid != MF6100_PID) ? cmd_read_image2 : cmd_read_image), mf->cb.buf); mf->cb.buf[8] = flag; mf->cb.buf[10] = 0x06; expected_len = (mf->generation >= 2 || @@ -419,13 +438,46 @@ static int step1 (pixma_t * s) { int error; + int rec_tmo; iclass_t *mf = (iclass_t *) s->subdriver; + /* don't wait full timeout for 1st command */ + rec_tmo = s->rec_tmo; /* save globel timeout */ + s->rec_tmo = 2; /* set timeout to 2 seconds */ error = query_status (s); + s->rec_tmo = rec_tmo; /* restore global timeout */ + if (error < 0) + { + PDBG (pixma_dbg (1, "WARNING: Resend first USB command after timeout!\n")); + error = query_status (s); + } if (error < 0) return error; - if (s->param->source == PIXMA_SOURCE_ADF && !has_paper (s)) + + /* wait for inserted paper */ + if (s->param->adf_wait != 0 && is_scanning_from_adf(s)) + { + int tmo = s->param->adf_wait; + + while (!has_paper (s) && --tmo >= 0 && !s->param->frontend_cancel) + { + if ((error = query_status (s)) < 0) + return error; + pixma_sleep (1000000); + PDBG (pixma_dbg(2, "No paper in ADF. Timed out in %d sec.\n", tmo)); + } + /* canceled from frontend */ + if (s->param->frontend_cancel) + { + return PIXMA_ECANCELED; + } + } + /* no paper inserted + * => abort session */ + if (is_scanning_from_adf(s) && !has_paper (s)) + { return PIXMA_ENO_PAPER; + } /* activate only seen for generation 1 scanners */ if (mf->generation == 1) { @@ -484,6 +536,9 @@ iclass_open (pixma_t * s) mf->cb.cmd_header_len = 10; mf->cb.cmd_len_field_ofs = 7; + /* adf scanning */ + mf->adf_state = state_idle; + /* set generation = 2 for new multifunctionals */ mf->generation = (s->cfg->pid >= MF8030_PID) ? 2 : 1; PDBG (pixma_dbg (3, "*iclass_open***** This is a generation %d scanner. *****\n", mf->generation)); @@ -513,8 +568,34 @@ iclass_check_param (pixma_t * s, pixma_scan_param_t * sp) { UNUSED (s); + /* PDBG (pixma_dbg (4, "*iclass_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, line_size=%" PRIu64 " , h=%u*****\n", + sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->line_size, sp->h)); */ + sp->depth = 8; - sp->line_size = ALIGN_SUP (sp->w, 32) * sp->channels; + sp->software_lineart = 0; + if (sp->mode == PIXMA_SCAN_MODE_LINEART) + { + sp->software_lineart = 1; + sp->channels = 1; + sp->depth = 1; + } + + if (sp->software_lineart == 1) + { + unsigned w_max; + + /* for software lineart line_size and w must be a multiple of 8 */ + sp->line_size = ALIGN_SUP (sp->w, 8) * sp->channels; + sp->w = ALIGN_SUP (sp->w, 8); + + /* do not exceed the scanner capability */ + w_max = s->cfg->width * s->cfg->xdpi / 75; + w_max -= w_max % 32; + if (sp->w > w_max) + sp->w = w_max; + } + else + sp->line_size = ALIGN_SUP (sp->w, 32) * sp->channels; /* Some exceptions here for particular devices */ /* Those devices can scan up to Legal 14" with ADF, but A4 11.7" in flatbed */ @@ -522,6 +603,9 @@ iclass_check_param (pixma_t * s, pixma_scan_param_t * sp) if ((s->cfg->cap & PIXMA_CAP_ADF) && sp->source == PIXMA_SOURCE_FLATBED) sp->h = MIN (sp->h, 877 * sp->xdpi / 75); + /* PDBG (pixma_dbg (4, "*iclass_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, line_size=%" PRIu64 " , h=%u*****\n", + sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->line_size, sp->h)); */ + return 0; } @@ -559,7 +643,8 @@ iclass_scan (pixma_t * s) mf->blk_len = 0; error = step1 (s); - if (error >= 0 && (s->param->adf_pageid == 0 || mf->generation == 1)) + if (error >= 0 + && (s->param->adf_pageid == 0 || mf->generation == 1 || mf->adf_state == state_idle)) { /* single sheet or first sheet from ADF */ PDBG (pixma_dbg (3, "*iclass_scan***** start scanning *****\n")); error = start_session (s); @@ -583,6 +668,10 @@ iclass_scan (pixma_t * s) return error; } mf->last_block = 0; + + /* ADF scanning active */ + if (is_scanning_from_adf (s)) + mf->adf_state = state_scanning; return 0; } @@ -592,7 +681,7 @@ iclass_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) { int error, n; iclass_t *mf = (iclass_t *) s->subdriver; - unsigned block_size, lines_size, first_block_size; + unsigned block_size, lines_size, lineart_lines_size, first_block_size; uint8_t info; /* @@ -652,10 +741,33 @@ iclass_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) /* add current block to remainder of previous */ mf->blk_len += block_size; /* n = number of full lines (rows) we have in the buffer. */ - n = mf->blk_len / s->param->line_size; + n = mf->blk_len / ((s->param->mode == PIXMA_SCAN_MODE_LINEART) ? mf->raw_width : s->param->line_size); if (n != 0) { - if (s->param->channels != 1 && + /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** Processing with n=%d, w=%i, line_size=%" PRIu64 ", raw_width=%u ***** \n", + n, s->param->w, s->param->line_size, mf->raw_width)); */ + /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** scan_mode=%d, lineptr=%" PRIu64 ", blkptr=%" PRIu64 " \n", + s->param->mode, (uint64_t)mf->lineptr, (uint64_t)mf->blkptr)); */ + + /* gray to lineart convert + * mf->lineptr : image line + * mf->blkptr : scanned image block as grayscale + * s->param->w : image width + * s->param->line_size : scanned image width */ + if (s->param->mode == PIXMA_SCAN_MODE_LINEART) + { + int i; + uint8_t *sptr, *dptr; + + /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** Processing lineart *****\n")); */ + + /* process ALL lines */ + sptr = mf->blkptr; + dptr = mf->lineptr; + for (i = 0; i < n; i++, sptr += mf->raw_width) + dptr = pixma_binarize_line (s->param, dptr, sptr, s->param->line_size, 1); + } + else if (s->param->channels != 1 && mf->generation == 1 && s->cfg->pid != MF4600_PID && s->cfg->pid != MF6500_PID && @@ -669,17 +781,22 @@ iclass_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) /* grayscale */ memcpy (mf->lineptr, mf->blkptr, n * s->param->line_size); } - lines_size = n * s->param->line_size; /* cull remainder and shift left */ + lineart_lines_size = n * s->param->line_size / 8; + lines_size = n * ((s->param->mode == PIXMA_SCAN_MODE_LINEART) ? mf->raw_width : s->param->line_size); mf->blk_len -= lines_size; memcpy (mf->blkptr, mf->blkptr + lines_size, mf->blk_len); } } while (n == 0); - /* output full lines, keep partial lines for next block */ + /* output full lines, keep partial lines for next block + * ib->rptr : start of image buffer + * ib->rend : end of image buffer */ ib->rptr = mf->lineptr; - ib->rend = mf->lineptr + lines_size; + ib->rend = mf->lineptr + (s->param->mode == PIXMA_SCAN_MODE_LINEART ? lineart_lines_size : lines_size); + /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** rptr=%" PRIu64 ", rend=%" PRIu64 ", diff=%ld \n", + (uint64_t)ib->rptr, (uint64_t)ib->rend, ib->rend - ib->rptr)); */ return ib->rend - ib->rptr; } @@ -718,8 +835,17 @@ iclass_finish_scan (pixma_t * s) || (mf->generation == 1 && mf->last_block == 0x28) /* generation 1 scanner last block */ || (mf->generation >= 2 && !has_paper(s))) /* check status: no paper in ADF */ { + /* ADFDUP scan: wait for 8sec to throw last page out of ADF feeder */ + if (is_scanning_from_adfdup(s)) + { + PDBG (pixma_dbg (4, "*iclass_finish_scan***** sleep for 8s *****\n")); + pixma_sleep(8000000); /* sleep for 8s */ + query_status (s); + } PDBG (pixma_dbg (3, "*iclass_finish_scan***** abort session *****\n")); abort_session (s); + mf->adf_state = state_idle; + mf->last_block = 0; } else PDBG (pixma_dbg (3, "*iclass_finish_scan***** wait for next page from ADF *****\n")); @@ -777,6 +903,8 @@ static const pixma_scan_ops_t pixma_iclass_ops = { adftpu_max_dpi, /* adftpu_max_dpi */ \ 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ w, h, /* width, height */ \ + PIXMA_CAP_LINEART| /* all scanners have software lineart */ \ + PIXMA_CAP_ADF_WAIT| /* adf wait for all ADF and ADFDUP scanners */ \ PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ } const pixma_config_t pixma_iclass_devices[] = { @@ -809,9 +937,11 @@ const pixma_config_t pixma_iclass_devices[] = { DEV ("Canon imageRUNNER 1133", "iR1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), DEV ("Canon i-SENSYS MF5900 Series", "MF5900", MF5900_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), DEV ("Canon i-SENSYS MF8500C Series", "MF8500C", MF8500_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF6100 Series", "MF6100", MF6100_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF6100 Series", "MF6100", MF6100_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), DEV ("Canon imageClass MF810/820", "MF810/820", MF820_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), DEV ("Canon i-SENSYS MF220 Series", "MF220", MF220_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), DEV ("Canon i-SENSYS MF210 Series", "MF210", MF210_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF230 Series", "MF230", MF230_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF240 Series", "MF240", MF240_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), DEV (NULL, NULL, 0, 0, 0, 0, 0, 0) }; diff --git a/backend/pixma_io.h b/backend/pixma_io.h index 004e008..9dc1afb 100644 --- a/backend/pixma_io.h +++ b/backend/pixma_io.h @@ -57,9 +57,9 @@ */ /** Timeout for pixma_read() in milliseconds */ -#define PIXMA_BULKIN_TIMEOUT 20000 +#define PIXMA_BULKIN_TIMEOUT 1000 /** Timeout for pixma_write() in milliseconds */ -#define PIXMA_BULKOUT_TIMEOUT 20000 +#define PIXMA_BULKOUT_TIMEOUT 1000 struct pixma_io_t; diff --git a/backend/pixma_io_sanei.c b/backend/pixma_io_sanei.c index 9e4a2fa..8eec883 100644 --- a/backend/pixma_io_sanei.c +++ b/backend/pixma_io_sanei.c @@ -1,7 +1,7 @@ /* SANE - Scanner Access Now Easy. * For limitations, see function sanei_usb_get_vendor_product(). - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2006-2007 Wittawat Yamwong This file is part of the SANE package. diff --git a/backend/pixma_mp150.c b/backend/pixma_mp150.c index 4f8b232..dca0965 100644 --- a/backend/pixma_mp150.c +++ b/backend/pixma_mp150.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2007-2009 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -228,7 +228,19 @@ #define MX490_PID 0x1787 #define E480_PID 0x1789 #define MG3600_PID 0x178a - +#define MG7700_PID 0x178b +#define MG6900_PID 0x178c +#define MG6800_PID 0x178d +#define MG5700_PID 0x178e + +/* 2016 new devices (untested) */ +#define TS9000_PID 0x179f +#define TS8000_PID 0x1800 +#define TS6000_PID 0x1801 +#define TS5000_PID 0x1802 +#define MG3000_PID 0x180b +#define E470_PID 0x180c +#define G3000_PID 0x181d /* Generation 4 XML messages that encapsulates the Pixma protocol messages */ #define XML_START_1 \ @@ -824,6 +836,7 @@ query_status (pixma_t * s) return error; } +#if 0 static int send_time (pixma_t * s) { @@ -843,6 +856,7 @@ send_time (pixma_t * s) PDBG (pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); return pixma_exec (s, &mp->cb); } +#endif /* TODO: Simplify this function. Read the whole data packet in one shot. */ static int @@ -945,11 +959,13 @@ handle_interrupt (pixma_t * s, int timeout) * tt: target * rr: scan resolution * poll event with 'scanimage -A' */ - if (s->cfg->pid == MG6200_PID + if (s->cfg->pid == MG5400_PID + || s->cfg->pid == MG6200_PID || s->cfg->pid == MG6300_PID || s->cfg->pid == MX520_PID || s->cfg->pid == MX720_PID - || s->cfg->pid == MX920_PID) + || s->cfg->pid == MX920_PID + || s->cfg->pid == MB5000_PID) /* button no. in buf[7] * size in buf[10] 01=A4; 02=Letter; 08=10x15; 09=13x18; 0b=auto * format in buf[11] 01=JPEG; 02=TIFF; 03=PDF; 04=Kompakt-PDF @@ -968,7 +984,10 @@ handle_interrupt (pixma_t * s, int timeout) { /* More than one event can be reported at the same time. */ if (buf[3] & 1) + /* FIXME: This function makes trouble with a lot of scanners send_time (s); + */ + PDBG (pixma_dbg (1, "WARNING:send_time() disabled!\n")); if (buf[9] & 2) query_status (s); if (buf[0] & 2) @@ -1150,13 +1169,17 @@ post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) && s->cfg->pid != MX920_PID && s->cfg->pid != MG3100_PID && s->cfg->pid != MG3500_PID + && s->cfg->pid != MG3600_PID && s->cfg->pid != MG2100_PID && s->cfg->pid != MG5300_PID + && s->cfg->pid != MG5400_PID && s->cfg->pid != MG5500_PID && s->cfg->pid != MG6300_PID && s->cfg->pid != MG6400_PID && s->cfg->pid != MG7100_PID - && s->cfg->pid != MG7500_PID) + && s->cfg->pid != MG7500_PID + && s->cfg->pid != MG7700_PID + && s->cfg->pid != MB5000_PID) reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, line_size); /* Crop line to selected borders */ @@ -1828,6 +1851,19 @@ const pixma_config_t pixma_mp150_devices[] = { DEVICE ("Canon PIXMA MX490 Series", "MX490", MX490_PID, 600, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA E480 Series", "E480", E480_PID, 600, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA MG3600 Series", "MG3600", MG3600_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG7700 Series", "MG7700", MG7700_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6900 Series", "MG6900", MG6900_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6800 Series", "MG6800", MG6800_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG5700 Series", "MG5700", MG5700_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2016) Generation 4 CIS */ + DEVICE ("Canon PIXMA TS9000 Series", "TS9000", TS9000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8000 Series", "TS8000", TS8000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6000 Series", "TS6000", TS6000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS5000 Series", "TS5000", TS5000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG3000 Series", "MG3000", MG3000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E470 Series", "E470", E470_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G4000 Series", "G3000", G3000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), END_OF_DEVICE_LIST }; diff --git a/backend/pixma_mp730.c b/backend/pixma_mp730.c index 2184ff7..6bf3f42 100644 --- a/backend/pixma_mp730.c +++ b/backend/pixma_mp730.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2007-2008 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -63,13 +63,17 @@ #define IMAGE_BLOCK_SIZE (0xc000) #define CMDBUF_SIZE 512 +#define MP10_PID 0x261f + #define MP730_PID 0x262f #define MP700_PID 0x2630 +#define MP5_PID 0x2635 /* untested */ + #define MP360_PID 0x263c #define MP370_PID 0x263d #define MP390_PID 0x263e -#define MP375R_PID 0x263f /* untested */ +#define MP375R_PID 0x263f /* untested */ #define MP740_PID 0x264c /* Untested */ #define MP710_PID 0x264d @@ -341,6 +345,8 @@ handle_interrupt (pixma_t * s, int timeout) s->events = PIXMA_EV_BUTTON1; /* color scan */ break; + case MP5_PID: + case MP10_PID: case MP700_PID: case MP730_PID: case MP710_PID: @@ -453,6 +459,10 @@ step1 (pixma_t * s) default: break; } + + // ignore result from calibrate() + // don't interrupt @ PIXMA_STATUS_BUSY + error = 0; } if (error >= 0) error = activate (s, 0); @@ -537,7 +547,9 @@ calc_raw_width (pixma_t * s, const pixma_scan_param_t * sp) { if (sp->depth == 8) /* grayscale */ { - if (s->cfg->pid == MP700_PID || + if (s->cfg->pid == MP5_PID || + s->cfg->pid == MP10_PID || + s->cfg->pid == MP700_PID || s->cfg->pid == MP730_PID || s->cfg->pid == MP360_PID || s->cfg->pid == MP370_PID || @@ -566,8 +578,10 @@ mp730_check_param (pixma_t * s, pixma_scan_param_t * sp) { sp->depth=8; } - /* for MP360/370, MP700/730 in grayscale & lineart modes, max scan res is 600 dpi */ - if (s->cfg->pid == MP700_PID || + /* for MP5, MP10, MP360/370, MP700/730 in grayscale & lineart modes, max scan res is 600 dpi */ + if (s->cfg->pid == MP5_PID || + s->cfg->pid == MP10_PID || + s->cfg->pid == MP700_PID || s->cfg->pid == MP730_PID || s->cfg->pid == MP360_PID || s->cfg->pid == MP370_PID || @@ -737,19 +751,23 @@ mp730_finish_scan (pixma_t * s) query_status (s); activate (s, 0); - if (! aborted && s->cfg->pid == IR1020_PID) - { - error = abort_session (s); - if (error < 0) - { - PDBG (pixma_dbg - (1, "WARNING:abort_session() failed %s\n", - pixma_strerror (error))); - query_status (s); - query_status (s); - activate (s, 0); - } - } + // MF57x0 devices don't require abort_session() after the last page + if (!aborted && + (s->param->source == PIXMA_SOURCE_ADF || + s->param->source == PIXMA_SOURCE_ADFDUP) && + has_paper (s) && + (s->cfg->pid == MF5730_PID || + s->cfg->pid == MF5750_PID || + s->cfg->pid == MF5770_PID || + s->cfg->pid == IR1020_PID)) + { + error = abort_session (s); + if (error < 0) + PDBG (pixma_dbg + (1, "WARNING:abort_session() failed %s\n", + pixma_strerror (error))); + } + mp->buf = mp->lbuf = mp->imgbuf = NULL; mp->state = state_idle; /* fall through */ @@ -808,6 +826,8 @@ static const pixma_scan_ops_t pixma_mp730_ops = { } const pixma_config_t pixma_mp730_devices[] = { /* TODO: check area limits */ + DEVICE ("PIXUS MP5/SmartBase MPC190/imageCLASS MPC190","MP5", MP5_PID, 600, 636, 868, PIXMA_CAP_LINEART),/* color scan can do 600x1200 */ + DEVICE ("PIXUS MP10/SmartBase MPC200/imageCLASS MPC200","MP10", MP10_PID, 600, 636, 868, PIXMA_CAP_LINEART),/* color scan can do 600x1200 */ DEVICE ("PIXMA MP360", "MP360", MP360_PID, 1200, 636, 868, PIXMA_CAP_LINEART), DEVICE ("PIXMA MP370", "MP370", MP370_PID, 1200, 636, 868, PIXMA_CAP_LINEART), DEVICE ("PIXMA MP375R", "MP375R", MP375R_PID, 1200, 636, 868, PIXMA_CAP_LINEART), diff --git a/backend/pixma_mp750.c b/backend/pixma_mp750.c index 8d2d94c..c5ac335 100644 --- a/backend/pixma_mp750.c +++ b/backend/pixma_mp750.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2006-2007 Wittawat Yamwong This file is part of the SANE package. diff --git a/backend/pixma_mp810.c b/backend/pixma_mp810.c index 5f9043e..b03bebc 100644 --- a/backend/pixma_mp810.c +++ b/backend/pixma_mp810.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2015 Rolf Bensch + Copyright (C) 2011-2016 Rolf Bensch Copyright (C) 2007-2009 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -1009,6 +1009,7 @@ static int query_status (pixma_t * s) return error; } +#if 0 static int send_time (pixma_t * s) { /* Why does a scanner need a time? */ @@ -1025,6 +1026,7 @@ static int send_time (pixma_t * s) PDBG(pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); return pixma_exec (s, &mp->cb); } +#endif /* TODO: Simplify this function. Read the whole data packet in one shot. */ static int read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) @@ -1157,7 +1159,10 @@ static int handle_interrupt (pixma_t * s, int timeout) { /* More than one event can be reported at the same time. */ if (buf[3] & 1) - send_time (s); /* FIXME: some scanners hang here */ + /* FIXME: This function makes trouble with a lot of scanners + send_time (s); + */ + PDBG (pixma_dbg (1, "WARNING:send_time() disabled!\n")); if (buf[9] & 2) query_status (s); diff --git a/backend/pixma_sane_options.c b/backend/pixma_sane_options.c index 890b3ff..2e4a054 100644 --- a/backend/pixma_sane_options.c +++ b/backend/pixma_sane_options.c @@ -7,6 +7,8 @@ static const SANE_Range constraint_threshold = { 0,100,1 }; static const SANE_Range constraint_threshold_curve = { 0,127,1 }; +static const SANE_Range constraint_adf_wait = + { 0,3600,1 }; static @@ -340,6 +342,21 @@ int build_option_descriptors(struct pixma_sane_t *ss) sod->constraint.range = &constraint_threshold_curve; OPT_IN_CTX[opt_threshold_curve].info = 0; + opt = &(OPT_IN_CTX[opt_adf_wait]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_I18N("ADF Waiting Time"); + sod->desc = SANE_I18N("When set, the scanner searches the waiting time in seconds for a new document inserted into the automatic document feeder."); + sod->name = "adf-wait"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &constraint_adf_wait; + OPT_IN_CTX[opt_adf_wait].info = 0; + opt->def.w = 0; + opt->val.w = 0; + return 0; } diff --git a/backend/pixma_sane_options.h b/backend/pixma_sane_options.h index ccc9e34..669a234 100644 --- a/backend/pixma_sane_options.h +++ b/backend/pixma_sane_options.h @@ -35,6 +35,7 @@ typedef enum { opt__group_5, opt_threshold, opt_threshold_curve, + opt_adf_wait, opt_last } option_t; diff --git a/backend/plustek.c b/backend/plustek.c index cd83c26..062df37 100644 --- a/backend/plustek.c +++ b/backend/plustek.c @@ -416,21 +416,21 @@ sig_chldhandler( int signo ) /** signal handler to kill the child process */ -static RETSIGTYPE +static void reader_process_sigterm_handler( int signo ) { DBG( _DBG_PROC, "(SIG) reader_process: terminated by signal %d\n", signo ); _exit( SANE_STATUS_GOOD ); } -static RETSIGTYPE +static void usb_reader_process_sigterm_handler( int signo ) { DBG( _DBG_PROC, "(SIG) reader_process: terminated by signal %d\n", signo ); cancelRead = SANE_TRUE; } -static RETSIGTYPE +static void sigalarm_handler( int signo ) { _VAR_NOT_USED( signo ); @@ -572,7 +572,7 @@ do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe ) DBG( _DBG_PROC,"do_cancel\n" ); scanner->scanning = SANE_FALSE; - if( scanner->reader_pid != -1 ) { + if( sanei_thread_is_valid (scanner->reader_pid) ) { DBG( _DBG_PROC, ">>>>>>>> killing reader_process <<<<<<<<\n" ); @@ -2629,7 +2629,7 @@ sane_start( SANE_Handle handle ) cancelRead = SANE_FALSE; - if( s->reader_pid == -1 ) { + if( !sanei_thread_is_valid (s->reader_pid) ) { DBG( _DBG_ERROR, "ERROR: could not start reader task\n" ); s->scanning = SANE_FALSE; usbDev_close( dev ); diff --git a/backend/plustek_pp.c b/backend/plustek_pp.c index bf4c0d0..f48c3dc 100644 --- a/backend/plustek_pp.c +++ b/backend/plustek_pp.c @@ -348,13 +348,13 @@ static void sig_chldhandler( int signo ) /** signal handler to kill the child process */ -static RETSIGTYPE reader_process_sigterm_handler( int signo ) +static void reader_process_sigterm_handler( int signo ) { DBG( _DBG_PROC, "reader_process: terminated by signal %d\n", signo ); _exit( SANE_STATUS_GOOD ); } -static RETSIGTYPE sigalarm_handler( int signo ) +static void sigalarm_handler( int signo ) { _VAR_NOT_USED( signo ); DBG( _DBG_PROC, "ALARM!!!\n" ); @@ -471,7 +471,7 @@ static SANE_Status do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe ) scanner->scanning = SANE_FALSE; - if( scanner->reader_pid != -1 ) { + if( sanei_thread_is_valid( scanner->reader_pid )) { DBG( _DBG_PROC, ">>>>>>>> killing reader_process <<<<<<<<\n" ); @@ -2014,7 +2014,7 @@ SANE_Status sane_start( SANE_Handle handle ) s->w_pipe = fds[1]; s->reader_pid = sanei_thread_begin( reader_process, s ); - if( s->reader_pid == -1 ) { + if(!sanei_thread_is_valid( s->reader_pid )) { DBG( _DBG_ERROR, "ERROR: could not create child process\n" ); s->scanning = SANE_FALSE; s->hw->close( s->hw ); diff --git a/backend/pnm.c b/backend/pnm.c index b8d3192..ff4e2f2 100644 --- a/backend/pnm.c +++ b/backend/pnm.c @@ -649,7 +649,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, v = 75; DBG (2, "sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n", - handle, option, action, value, info); + handle, option, action, value, (void *) info); if (handle != MAGIC || !is_open) { diff --git a/backend/rts8891.c b/backend/rts8891.c index bdb4011..0eaff7b 100644 --- a/backend/rts8891.c +++ b/backend/rts8891.c @@ -617,7 +617,7 @@ set_automatic_value (Rts8891_Session * s, int option, SANE_Int * myinfo) { SANE_Status status = SANE_STATUS_GOOD; SANE_Int i, min; - SANE_Word *dpi_list; + const SANE_Word *dpi_list; switch (option) { @@ -639,7 +639,7 @@ set_automatic_value (Rts8891_Session * s, int option, SANE_Int * myinfo) break; case OPT_RESOLUTION: /* we set up to the lowest available dpi value */ - dpi_list = (SANE_Word *) s->opt[OPT_RESOLUTION].constraint.word_list; + dpi_list = s->opt[OPT_RESOLUTION].constraint.word_list; min = 65536; for (i = 1; i < dpi_list[0]; i++) { @@ -2233,11 +2233,11 @@ sane_close (SANE_Handle handle) if (session->dev->model->gamma != session->val[OPT_GAMMA_VECTOR_B].wa) free (session->val[OPT_GAMMA_VECTOR_B].wa); free (session->val[OPT_MODE].s); - free (session->opt[OPT_RESOLUTION].constraint.word_list); + free ((void *) session->opt[OPT_RESOLUTION].constraint.word_list); for (i = OPT_BUTTON_1; i <= OPT_BUTTON_11; i++) { - free (session->opt[i].name); - free (session->opt[i].title); + free ((void *) session->opt[i].name); + free ((void *) session->opt[i].title); } free (session); @@ -7702,7 +7702,7 @@ park_head (struct Rts8891_Device *dev, SANE_Bool wait) sanei_rts88xx_read_reg (dev->devnum, CONTROLER_REG, ®); if (reg != 0x20) { - DBG (DBG_warn, "park_head: unexpected controler value 0x%02x\n", reg); + DBG (DBG_warn, "park_head: unexpected controller value 0x%02x\n", reg); } /* head parking */ diff --git a/backend/rts88xx_lib.c b/backend/rts88xx_lib.c index bbbc83a..8e921f2 100644 --- a/backend/rts88xx_lib.c +++ b/backend/rts88xx_lib.c @@ -686,7 +686,7 @@ sanei_rts88xx_setup_nvram (SANE_Int devnum, SANE_Int length, if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "sanei_rts88xx_setup_nvram : controler register write failed\n"); + "sanei_rts88xx_setup_nvram : controller register write failed\n"); return status; } reg = 1; @@ -694,7 +694,7 @@ sanei_rts88xx_setup_nvram (SANE_Int devnum, SANE_Int length, if (status != SANE_STATUS_GOOD) { DBG (DBG_error, - "sanei_rts88xx_setup_nvram : controler register write failed\n"); + "sanei_rts88xx_setup_nvram : controller register write failed\n"); return status; } return status; diff --git a/backend/sharp.c b/backend/sharp.c index 1225a57..69f5000 100644 --- a/backend/sharp.c +++ b/backend/sharp.c @@ -370,7 +370,7 @@ sense_handler(int __sane_unused__ fd, u_char *sense_buffer, void *s) DBG(10, "error: invalid field in parameter list\n"); return SANE_STATUS_IO_ERROR; case 0x29: - DBG(10, "note: reset occured\n"); + DBG(10, "note: reset occurred\n"); return SANE_STATUS_GOOD; case 0x2a: DBG(10, "note: mode parameter change\n"); @@ -495,7 +495,7 @@ sense_handler(int __sane_unused__ fd, u_char *sense_buffer, void *s) switch (add_sense_code) { case 0x29: - DBG(5, "unit attention: reset occured\n"); + DBG(5, "unit attention: reset occurred\n"); return SANE_STATUS_GOOD; case 0x2a: DBG(5, "unit attention: parameter changed by " @@ -3299,7 +3299,7 @@ send_threshold_data(SHARP_Scanner *s) SANE_Status sane_start (SANE_Handle handle) { - char *mode, *halftone, *paper, *gamma, *edge, *lightcolor, *adf_fsu; + char *mode, *halftone, *gamma, *edge, *lightcolor, *adf_fsu; SHARP_Scanner *s = handle; SANE_Status status; size_t buf_size; @@ -3436,7 +3436,6 @@ sane_start (SANE_Handle handle) mode = s->val[OPT_MODE].s; halftone = s->val[OPT_HALFTONE].s; - paper = s->val[OPT_PAPER].s; gamma = s->val[OPT_GAMMA].s; edge = s->val[OPT_EDGE_EMPHASIS].s; lightcolor = s->val[OPT_LIGHTCOLOR].s; diff --git a/backend/sm3600.c b/backend/sm3600.c index dd1f31f..908e8be 100644 --- a/backend/sm3600.c +++ b/backend/sm3600.c @@ -73,7 +73,7 @@ Start: 2.4.2001 #include "../include/sane/saneopts.h" #include "../include/sane/sanei_usb.h" -#undef HAVE_LIBUSB +#undef HAVE_LIBUSB_LEGACY /* prevent inclusion of scantool.h */ #define SCANTOOL_H @@ -431,13 +431,11 @@ sane_exit (void) SANE_Status sane_get_devices (const SANE_Device *** device_list, - SANE_Bool local_only) + SANE_Bool __sane_unused__ local_only) { TDevice *dev; int i; - local_only = TRUE; /* Avoid compile warning */ - if (devlist) free (devlist); devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); @@ -458,7 +456,6 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) { TDevice *pdev; TInstance *this; - SANE_Status rc; DBG(DEBUG_VERBOSE,"opening %s\n",devicename); if (devicename[0]) /* selected */ { @@ -488,8 +485,6 @@ DBG(DEBUG_VERBOSE,"%s<>%s\n",devicename, pdev->sane.name); if (sanei_usb_open (devicename, &this->hScanner) != SANE_STATUS_GOOD) return SetError (this, SANE_STATUS_IO_ERROR, "cannot open scanner device"); - rc = SANE_STATUS_GOOD; - this->quality=fast; return InitOptions(this); } diff --git a/backend/sm3840.c b/backend/sm3840.c old mode 100755 new mode 100644 diff --git a/backend/sm3840.h b/backend/sm3840.h old mode 100755 new mode 100644 diff --git a/backend/sm3840_lib.c b/backend/sm3840_lib.c old mode 100755 new mode 100644 index 485003c..163b356 --- a/backend/sm3840_lib.c +++ b/backend/sm3840_lib.c @@ -191,12 +191,12 @@ find_device (unsigned int idVendor, unsigned int idProduct) static void idle_ab (p_usb_dev_handle udev) { - int len, i; + int i; unsigned char buff[8] = { 0x64, 0x65, 0x16, 0x17, 0x64, 0x65, 0x44, 0x45 }; for (i = 0; i < 8; i++) { - len = usb_control_msg (udev, 0x40, 0x0c, 0x0090, 0x0000, buff + i, - 0x0001, wr_timeout); + usb_control_msg (udev, 0x40, 0x0c, 0x0090, 0x0000, buff + i, + 0x0001, wr_timeout); } } @@ -208,7 +208,7 @@ write_regs (p_usb_dev_handle udev, int regs, unsigned char reg1, { unsigned char buff[512]; va_list marker; - int len, i; + int i; va_start (marker, val1); buff[0] = reg1; @@ -220,8 +220,8 @@ write_regs (p_usb_dev_handle udev, int regs, unsigned char reg1, } va_end (marker); - len = usb_control_msg (udev, 0x40, 0x04, 0x00b0, 0x0000, buff, - regs * 2, wr_timeout); + usb_control_msg (udev, 0x40, 0x04, 0x00b0, 0x0000, buff, + regs * 2, wr_timeout); } static int @@ -297,7 +297,6 @@ record_line (int reset, unsigned char **save_dpi1200_remap, unsigned char **save_color_remap) { - int len; unsigned char *scan_line, *dpi1200_remap; unsigned char *color_remap; int i; @@ -374,7 +373,7 @@ record_line (int reset, while (1) { /* We'll exit inside the loop... */ - len = usb_bulk_read (udev, 1, scan_line, linelen, rd_timeout); + usb_bulk_read (udev, 1, scan_line, linelen, rd_timeout); if (dpi == 1200) { ptrcur = dpi1200_remap + (linelen * (i % DPI1200SHUFFLE)); @@ -886,7 +885,6 @@ download_lut8 (p_usb_dev_handle udev, int dpi, int incolor) 4.40306800664567E-31 }; unsigned char *lut; - int len; DBG (2, "+download_lut8\n"); switch (dpi) @@ -904,7 +902,7 @@ download_lut8 (p_usb_dev_handle udev, int dpi, int incolor) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0x2f, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00); - len = usb_bulk_write (udev, 2, lut, 4096, wr_timeout); + usb_bulk_write (udev, 2, lut, 4096, wr_timeout); } else { @@ -912,15 +910,15 @@ download_lut8 (p_usb_dev_handle udev, int dpi, int incolor) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x10, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0x1f, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00); - len = usb_bulk_write (udev, 2, lut, 4096, wr_timeout); + usb_bulk_write (udev, 2, lut, 4096, wr_timeout); write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0x2f, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00); - len = usb_bulk_write (udev, 2, lut, 4096, wr_timeout); + usb_bulk_write (udev, 2, lut, 4096, wr_timeout); write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x30, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0x3f, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, 0x1000, 0x00); - len = usb_bulk_write (udev, 2, lut, 4096, wr_timeout); + usb_bulk_write (udev, 2, lut, 4096, wr_timeout); } break; @@ -936,7 +934,7 @@ download_lut8 (p_usb_dev_handle udev, int dpi, int incolor) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x06, 0xb3, 0xff, 0xb4, 0x5f, 0xb5, 0x06); write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00); - len = usb_bulk_write (udev, 2, lut, 8192, wr_timeout); + usb_bulk_write (udev, 2, lut, 8192, wr_timeout); } else { @@ -944,15 +942,15 @@ download_lut8 (p_usb_dev_handle udev, int dpi, int incolor) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x20, 0xb2, 0x06, 0xb3, 0xff, 0xb4, 0x3f, 0xb5, 0x06); write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00); - len = usb_bulk_write (udev, 2, lut, 8192, wr_timeout); + usb_bulk_write (udev, 2, lut, 8192, wr_timeout); write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x06, 0xb3, 0xff, 0xb4, 0x5f, 0xb5, 0x06); write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00); - len = usb_bulk_write (udev, 2, lut, 8192, wr_timeout); + usb_bulk_write (udev, 2, lut, 8192, wr_timeout); write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x60, 0xb2, 0x06, 0xb3, 0xff, 0xb4, 0x7f, 0xb5, 0x06); write_vctl (udev, 0x0c, 0x0002, 0x2000, 0x00); - len = usb_bulk_write (udev, 2, lut, 8192, wr_timeout); + usb_bulk_write (udev, 2, lut, 8192, wr_timeout); } break; } diff --git a/backend/sm3840_lib.h b/backend/sm3840_lib.h old mode 100755 new mode 100644 diff --git a/backend/sm3840_scan.c b/backend/sm3840_scan.c old mode 100755 new mode 100644 index e9442a7..148e37b --- a/backend/sm3840_scan.c +++ b/backend/sm3840_scan.c @@ -158,7 +158,6 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) int scanlines = p->scanlines; int leftpix = p->leftpix; int scanpix = p->scanpix; - int len; unsigned char hello[2] = { 0x55, 0xaa }; unsigned char howdy[3]; unsigned short *whitebalance; @@ -182,11 +181,11 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) char fname[64]; char head[128]; - len = usb_set_configuration (udev, 1); - len = usb_claim_interface (udev, 0); - len = usb_clear_halt (udev, 1); - len = usb_clear_halt (udev, 2); - len = usb_clear_halt (udev, 3); + usb_set_configuration (udev, 1); + usb_claim_interface (udev, 0); + usb_clear_halt (udev, 1); + usb_clear_halt (udev, 2); + usb_clear_halt (udev, 3); #endif DBG (2, "params.gray = %d;\n", p->gray); DBG (2, "params.dpi = %d\n", p->dpi); @@ -255,12 +254,12 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) write_regs (udev, 1, 0xb1, 0x00); write_regs (udev, 1, 0xb2, 0x00); write_vctl (udev, 0x0c, 0x0002, 0x0002, 0x00); - len = usb_bulk_write (udev, 2, hello, 2, wr_timeout); + usb_bulk_write (udev, 2, hello, 2, wr_timeout); write_regs (udev, 1, 0xb0, 0x00); write_regs (udev, 1, 0xb1, 0x00); write_regs (udev, 1, 0xb2, 0x00); write_vctl (udev, 0x0c, 0x0003, 0x0003, 0x00); - len = usb_bulk_read (udev, 1, howdy, 3, rd_timeout); + usb_bulk_read (udev, 1, howdy, 3, rd_timeout); write_regs (udev, 4, 0x83, 0x00, 0xa3, 0x00, 0xa4, 0x00, 0x97, 0x0a); write_vctl (udev, 0x0c, 0x0004, 0x008b, 0x00); read_vctl (udev, 0x0c, 0x0007, 0x0000, &rd_byte); @@ -318,9 +317,8 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0x7f, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); - len = - usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, - wr_timeout); + usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, + wr_timeout); set_lightmap_white (whitemap, dpi, 1); if (dpi == 1200) @@ -330,9 +328,8 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x80, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0xbf, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); - len = - usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, - wr_timeout); + usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, + wr_timeout); set_lightmap_white (whitemap, dpi, 2); if (dpi == 1200) @@ -342,9 +339,8 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0xc0, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0xff, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); - len = - usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, - wr_timeout); + usb_bulk_write (udev, 2, (unsigned char *) whitemap, whitemapsize, + wr_timeout); free (whitemap); @@ -391,11 +387,10 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) write_regs (udev, 1, 0xbe, 0x0d); write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); whitebalance = (unsigned short *) malloc (whitebalancesize); - len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); - len = - usb_bulk_read (udev, 1, (unsigned char *) whitebalance, whitebalancesize, - rd_timeout); + usb_bulk_read (udev, 1, (unsigned char *) whitebalance, whitebalancesize, + rd_timeout); write_regs (udev, 2, 0xbe, 0x00, 0x84, 0x00); write_vctl (udev, 0x0c, 0x00c0, 0x8406, 0x00); write_vctl (udev, 0x0c, 0x00c0, 0x0406, 0x00); @@ -419,11 +414,10 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) 0xbf, 0x00, 0x90, 0x40, 0x91, 0x00, 0x83, 0x82); write_regs (udev, 1, 0xbe, 0x0d); write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); - len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); - len = - usb_bulk_read (udev, 1, (unsigned char *) whitebalance, - whitebalancesize, rd_timeout); + usb_bulk_read (udev, 1, (unsigned char *) whitebalance, + whitebalancesize, rd_timeout); fix_endian_short (whitebalance, whitebalancesize/2); if (!donered) { @@ -485,11 +479,10 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) 0xbf, 0x00, 0x90, 0x40, 0x91, 0x00, 0x83, 0x82); write_regs (udev, 1, 0xbe, 0x0d); write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); - len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); - len = - usb_bulk_read (udev, 1, (unsigned char *) whitebalance, - whitebalancesize, rd_timeout); + usb_bulk_read (udev, 1, (unsigned char *) whitebalance, + whitebalancesize, rd_timeout); fix_endian_short (whitebalance, whitebalancesize/2); if (!donered) { @@ -601,7 +594,7 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) 0x00, 0x90, 0x40, 0x91, 0x00, 0x83, 0x82); write_regs (udev, 1, 0xbe, 0x1d); write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); - len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); record_mem (udev, (unsigned char **) (void *)&whitescan, (5632 * 2 * 3 * (dpi == 1200 ? 2 : 1)) * 4); @@ -756,9 +749,8 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0x40, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0x7f, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); - len = - usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, - wr_timeout); + usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, + wr_timeout); calc_lightmap (whitescan, lightmap, 1, dpi, gain, offset); if (dpi == 1200) @@ -772,9 +764,8 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) if (gray) for (i = 0; i < whitemapsize / 2; i++) lightmap[i] |= GRAYMASK; - len = - usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, - wr_timeout); + usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, + wr_timeout); calc_lightmap (whitescan, lightmap, 2, dpi, gain, offset); if (dpi == 1200) @@ -784,9 +775,8 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) write_regs (udev, 6, 0xb0, 0x00, 0xb1, 0xc0, 0xb2, 0x07, 0xb3, 0xff, 0xb4, 0xff, 0xb5, 0x07); write_vctl (udev, 0x0c, 0x0002, whitemapsize, 0x00); - len = - usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, - wr_timeout); + usb_bulk_write (udev, 2, (unsigned char *) lightmap, whitemapsize, + wr_timeout); free (whitescan); free (lightmap); @@ -922,7 +912,7 @@ setup_scan (p_usb_dev_handle udev, SM3840_Params * p) else write_regs (udev, 1, 0xbe, 0x0d); write_vctl (udev, 0x0c, 0x0003, 0x0001, 0x00); - len = usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); + usb_bulk_read (udev, 1, &rd_byte, 1, rd_timeout); write_vctl (udev, 0x0c, 0x0001, 0x0000, 0x00); #ifndef BACKENDNAME diff --git a/backend/snapscan-mutex.c b/backend/snapscan-mutex.c index 0321741..ad0538a 100644 --- a/backend/snapscan-mutex.c +++ b/backend/snapscan-mutex.c @@ -44,7 +44,7 @@ #include #define snapscan_mutex_t sem_id -static int snapscani_mutex_open(snapscan_mutex_t* a_sem, const char* dev UNUSEDARG) +static int snapscani_mutex_open(snapscan_mutex_t* a_sem, const char* dev __sane_unused__) { *a_sem = create_sem(1, "snapscan_mutex"); return 1; @@ -72,7 +72,7 @@ static void snapscani_mutex_unlock(snapscan_mutex_t* a_sem) #include #define snapscan_mutex_t pthread_mutex_t -static int snapscani_mutex_open(snapscan_mutex_t* sem_id, const char* dev UNUSEDARG) +static int snapscani_mutex_open(snapscan_mutex_t* sem_id, const char* dev __sane_unused__) { pthread_mutex_init(sem_id, NULL); return 1; diff --git a/backend/snapscan-sources.c b/backend/snapscan-sources.c index 63eadb2..dc78394 100644 --- a/backend/snapscan-sources.c +++ b/backend/snapscan-sources.c @@ -105,10 +105,6 @@ I hope this makes sense to you (and I got the right idea of the original author' intention). ***********************************************************************************/ -#ifndef __FUNCTION__ -#define __FUNCTION__ "(undef)" -#endif - static SANE_Status Source_init (Source *pself, SnapScan_Scanner *pss, SourceRemaining remaining, @@ -266,13 +262,13 @@ static SANE_Status FDSource_get (Source *pself, SANE_Byte *pbuf, SANE_Int *plen) } /* It's an IO error */ DBG (DL_MAJOR_ERROR, "%s: read failed: %s\n", - __FUNCTION__, strerror(errno)); + __func__, strerror(errno)); status = SANE_STATUS_IO_ERROR; } else if (bytes_read == 0) { /* EOF of current reading */ - DBG(DL_DATA_TRACE, "%s: EOF\n",__FUNCTION__); + DBG(DL_DATA_TRACE, "%s: EOF\n",__func__); break; } ps->bytes_remaining -= bytes_read; @@ -623,7 +619,7 @@ static SANE_Status Expander_init (Expander *pself, { DBG (DL_MAJOR_ERROR, "%s: couldn't allocate channel buffer.\n", - __FUNCTION__); + __func__); status = SANE_STATUS_NO_MEM; } else @@ -654,7 +650,7 @@ static SANE_Status create_Expander (SnapScan_Scanner *pss, { DBG (DL_MAJOR_ERROR, "%s: failed to allocate Expander.\n", - __FUNCTION__); + __func__); status = SANE_STATUS_NO_MEM; } else @@ -871,7 +867,7 @@ static SANE_Status Deinterlacer_init (Deinterlacer *pself, { DBG (DL_MAJOR_ERROR, "%s: couldn't allocate channel buffer.\n", - __FUNCTION__); + __func__); status = SANE_STATUS_NO_MEM; } else @@ -901,7 +897,7 @@ static SANE_Status create_Deinterlacer (SnapScan_Scanner *pss, { DBG (DL_MAJOR_ERROR, "%s: failed to allocate Deinterlacer.\n", - __FUNCTION__); + __func__); status = SANE_STATUS_NO_MEM; } else @@ -1106,7 +1102,7 @@ static SANE_Status RGBRouter_init (RGBRouter *pself, { DBG (DL_MAJOR_ERROR, "%s: failed to allocate circular buffer.\n", - __FUNCTION__); + __func__); status = SANE_STATUS_NO_MEM; } else @@ -1141,7 +1137,7 @@ static SANE_Status create_RGBRouter (SnapScan_Scanner *pss, if (*pps == NULL) { DBG (DL_MAJOR_ERROR, "%s: failed to allocate RGBRouter.\n", - __FUNCTION__); + __func__); status = SANE_STATUS_NO_MEM; } else @@ -1193,7 +1189,7 @@ static SANE_Status create_Inverter (SnapScan_Scanner *pss, if (*pps == NULL) { DBG (DL_MAJOR_ERROR, "%s: failed to allocate Inverter.\n", - __FUNCTION__); + __func__); status = SANE_STATUS_NO_MEM; } else @@ -1256,7 +1252,7 @@ static SANE_Status create_source_chain (SnapScan_Scanner *pss, break; default: DBG (DL_MAJOR_ERROR, "%s: bad mode value %d (internal error)\n", - __FUNCTION__, mode); + __func__, mode); status = SANE_STATUS_INVAL; break; } diff --git a/backend/snapscan.c b/backend/snapscan.c index 3c0fb81..c88537b 100644 --- a/backend/snapscan.c +++ b/backend/snapscan.c @@ -82,12 +82,6 @@ #define BUILD 53 #define BACKEND_NAME snapscan -#ifdef __GNUC__ -#define UNUSEDARG __attribute__ ((unused)) -#else -#define UNUSEDARG -#endif - #include "../include/sane/sanei_backend.h" #include "../include/sane/saneopts.h" @@ -1217,13 +1211,13 @@ static void reader (SnapScan_Scanner *pss) /** signal handler to kill the child process */ -static RETSIGTYPE usb_reader_process_sigterm_handler( int signo ) +static void usb_reader_process_sigterm_handler( int signo ) { DBG( DL_INFO, "(SIG) reader_process: terminated by signal %d\n", signo ); cancelRead = SANE_TRUE; } -static RETSIGTYPE sigalarm_handler( int signo UNUSEDARG) +static void sigalarm_handler( int signo __sane_unused__) { DBG( DL_INFO, "ALARM!!!\n" ); } @@ -1301,7 +1295,7 @@ static SANE_Status start_reader (SnapScan_Scanner *pss) cancelRead = SANE_FALSE; - if (pss->child == -1) + if (!sanei_thread_is_valid (pss->child)) { /* we'll have to read in blocking mode */ DBG (DL_MAJOR_ERROR, @@ -1815,7 +1809,7 @@ SANE_Status sane_read (SANE_Handle h, if (pss->psrc == NULL || pss->psrc->remaining(pss->psrc) == 0) { - if (pss->child != -1) + if (sanei_thread_is_valid (pss->child)) { sanei_thread_waitpid (pss->child, 0); /* ensure no zombies */ pss->child = -1; @@ -1875,7 +1869,7 @@ void sane_cancel (SANE_Handle h) /* signal a cancellation has occurred */ pss->state = ST_CANCEL_INIT; /* signal the reader, if any */ - if (pss->child != -1) + if (sanei_thread_is_valid (pss->child)) { DBG( DL_INFO, ">>>>>>>> killing reader_process <<<<<<<<\n" ); @@ -1941,7 +1935,7 @@ SANE_Status sane_set_io_mode (SANE_Handle h, SANE_Bool m) if (m) { - if (pss->child == -1) + if (!sanei_thread_is_valid (pss->child)) { DBG (DL_MINOR_INFO, "%s: no reader child; must use blocking mode.\n", @@ -1971,7 +1965,7 @@ SANE_Status sane_get_select_fd (SANE_Handle h, SANE_Int * fd) if (pss->state != ST_SCAN_INIT) return SANE_STATUS_INVAL; - if (pss->child == -1) + if (!sanei_thread_is_valid (pss->child)) { DBG (DL_MINOR_INFO, "%s: no reader child; cannot provide select file descriptor.\n", diff --git a/backend/sp15c.c b/backend/sp15c.c index 3937a30..0cabed8 100644 --- a/backend/sp15c.c +++ b/backend/sp15c.c @@ -1762,7 +1762,7 @@ do_cancel (struct sp15c *scanner) do_eof (scanner); /* close pipe and reposition scanner */ - if (scanner->reader_pid != -1) + if (sanei_thread_is_valid (scanner->reader_pid)) { int exit_status; DBG (10, "do_cancel: kill reader_process\n"); diff --git a/backend/stv680.conf.in b/backend/stv680.conf.in old mode 100755 new mode 100644 diff --git a/backend/stv680.h b/backend/stv680.h old mode 100755 new mode 100644 diff --git a/backend/tamarack.c b/backend/tamarack.c index e7073af..6fc259f 100644 --- a/backend/tamarack.c +++ b/backend/tamarack.c @@ -470,7 +470,7 @@ do_cancel (Tamarack_Scanner *s) do_eof (s); - if (s->reader_pid != -1) + if (sanei_thread_is_valid (s->reader_pid)) { int exit_status; @@ -1442,7 +1442,7 @@ sane_cancel (SANE_Handle handle) { Tamarack_Scanner *s = handle; - if (s->reader_pid != -1) + if (sanei_thread_is_valid (s->reader_pid)) sanei_thread_kill (s->reader_pid); s->scanning = SANE_FALSE; } diff --git a/backend/test.c b/backend/test.c index d5b7365..2ca5b3b 100644 --- a/backend/test.c +++ b/backend/test.c @@ -1355,7 +1355,7 @@ finish_pass (Test_Device * test_device) DBG (2, "finish_pass: pipe closed\n"); test_device->pipe = -1; } - if (test_device->reader_pid != -1) + if (sanei_thread_is_valid (test_device->reader_pid)) { int status; SANE_Pid pid; @@ -1364,7 +1364,7 @@ finish_pass (Test_Device * test_device) (long) test_device->reader_pid); sanei_thread_kill (test_device->reader_pid); pid = sanei_thread_waitpid (test_device->reader_pid, &status); - if (pid == -1) + if (!sanei_thread_is_valid (pid)) { DBG (1, "finish_pass: sanei_thread_waitpid failed, already terminated? (%s)\n", @@ -2568,7 +2568,7 @@ sane_start (SANE_Handle handle) test_device->reader_pid = sanei_thread_begin (reader_task, (void *) test_device); - if (test_device->reader_pid == -1) + if (!sanei_thread_is_valid (test_device->reader_pid)) { DBG (1, "sane_start: sanei_thread_begin failed (%s)\n", strerror (errno)); diff --git a/backend/u12-hw.c b/backend/u12-hw.c index 89f37be..e21c78a 100644 --- a/backend/u12-hw.c +++ b/backend/u12-hw.c @@ -338,7 +338,6 @@ static void u12hw_SetGeneralRegister( U12_Device *dev ) static void u12hw_SetupPreviewCondition( U12_Device *dev ) { int i, c; - u_long channel; SANE_Byte rb[100]; DBG( _DBG_INFO, "u12_SetupPreviewCondition()\n" ); @@ -389,7 +388,6 @@ static void u12hw_SetupPreviewCondition( U12_Device *dev ) else dev->scan.bFifoSelect = REG_GFIFOOFFSET; - channel = _BLUE_FULLSIZE << 16; dev->regs.RD_BufFullSize = _SIZE_BLUEFIFO; dev->regs.RD_LineControl = _LOBYTE(dev->shade.wExposure); diff --git a/backend/u12.c b/backend/u12.c index 8401a9f..083d9f3 100644 --- a/backend/u12.c +++ b/backend/u12.c @@ -278,19 +278,19 @@ static void sig_chldhandler( int signo ) /** signal handler to kill the child process */ -static RETSIGTYPE reader_process_sigterm_handler( int signo ) +static void reader_process_sigterm_handler( int signo ) { DBG( _DBG_PROC, "(SIG) reader_process: terminated by signal %d\n", signo ); _exit( SANE_STATUS_GOOD ); } -static RETSIGTYPE usb_reader_process_sigterm_handler( int signo ) +static void usb_reader_process_sigterm_handler( int signo ) { DBG( _DBG_PROC, "(SIG) reader_process: terminated by signal %d\n", signo ); cancelRead = SANE_TRUE; } -static RETSIGTYPE sigalarm_handler( int signo ) +static void sigalarm_handler( int signo ) { _VAR_NOT_USED( signo ); DBG( _DBG_PROC, "ALARM!!!\n" ); @@ -391,7 +391,7 @@ static SANE_Status do_cancel( U12_Scanner *scanner, SANE_Bool closepipe ) scanner->scanning = SANE_FALSE; - if( scanner->reader_pid != -1 ) { + if( sanei_thread_is_valid (scanner->reader_pid) ) { DBG( _DBG_PROC, ">>>>>>>> killing reader_process <<<<<<<<\n" ); @@ -1731,7 +1731,7 @@ SANE_Status sane_start( SANE_Handle handle ) cancelRead = SANE_FALSE; - if( s->reader_pid == -1 ) { + if( !sanei_thread_is_valid (s->reader_pid) ) { DBG( _DBG_ERROR, "ERROR: could not start reader task\n" ); s->scanning = SANE_FALSE; u12if_close( dev ); diff --git a/backend/umax.c b/backend/umax.c index 0d8ddba..22fa2d3 100644 --- a/backend/umax.c +++ b/backend/umax.c @@ -399,7 +399,7 @@ static void umax_print_inquiry(Umax_Device *dev) DBG_inq_nz(" - relative address\n", get_inquiry_scsi_reladr(inquiry_block)); DBG_inq_nz(" - wide bus 32 bit\n", get_inquiry_scsi_wbus32(inquiry_block)); DBG_inq_nz(" - wide bus 16 bit\n", get_inquiry_scsi_wbus16(inquiry_block)); - DBG_inq_nz(" - syncronous neg.\n", get_inquiry_scsi_sync(inquiry_block)); + DBG_inq_nz(" - synchronous neg.\n", get_inquiry_scsi_sync(inquiry_block)); DBG_inq_nz(" - linked commands\n", get_inquiry_scsi_linked(inquiry_block)); DBG_inq_nz(" - (reserved)\n", get_inquiry_scsi_R(inquiry_block)); DBG_inq_nz(" - command queueing\n", get_inquiry_scsi_cmdqueue(inquiry_block)); @@ -526,7 +526,7 @@ static void umax_print_inquiry(Umax_Device *dev) DBG_inq_nz(" + ADF: no paper\n", get_inquiry_ADF_no_paper(inquiry_block)); DBG_inq_nz(" + ADF: cover open\n", get_inquiry_ADF_cover_open(inquiry_block)); DBG_inq_nz(" + ADF: paper jam\n", get_inquiry_ADF_paper_jam(inquiry_block)); - DBG_inq_nz(" - unknwon flag; 0x63 bit 3\n", get_inquiry_0x63_bit3(inquiry_block)); + DBG_inq_nz(" - unknown flag; 0x63 bit 3\n", get_inquiry_0x63_bit3(inquiry_block)); DBG_inq_nz(" - unknown lfag: 0x63 bit 4\n", get_inquiry_0x63_bit4(inquiry_block)); DBG_inq_nz(" - lens calib in doc pos\n", get_inquiry_lens_cal_in_doc_pos(inquiry_block)); DBG_inq_nz(" - manual focus\n", get_inquiry_manual_focus(inquiry_block)); @@ -4670,14 +4670,14 @@ static SANE_Status do_cancel(Umax_Scanner *scanner) scanner->scanning = SANE_FALSE; - if (scanner->reader_pid != -1) + if (sanei_thread_is_valid (scanner->reader_pid)) { DBG(DBG_sane_info,"killing reader_process\n"); sanei_thread_kill(scanner->reader_pid); pid = sanei_thread_waitpid(scanner->reader_pid, &status); - if (pid == -1) + if (!sanei_thread_is_valid (pid)) { DBG(DBG_sane_info, "do_cancel: sanei_thread_waitpid failed, already terminated ? (%s)\n", strerror(errno)); } @@ -4928,7 +4928,7 @@ static SANE_Status attach_scanner(const char *devicename, Umax_Device **devp, in /* ------------------------------------------------------------ READER PROCESS SIGTERM HANDLER ------------ */ -static RETSIGTYPE reader_process_sigterm_handler(int signal) +static void reader_process_sigterm_handler(int signal) { DBG(DBG_sane_info,"reader_process: terminated by signal %d\n", signal); @@ -7624,7 +7624,7 @@ SANE_Status sane_start(SANE_Handle handle) /* of the x-origin defined by the scanner`s inquiry */ if (scanner->device->dor != 0) /* dor mode active */ { - DBG(DBG_info,"substracting DOR x-origin-offset from upper left x\n"); + DBG(DBG_info,"subtracting DOR x-origin-offset from upper left x\n"); scanner->device->upper_left_x -= scanner->device->inquiry_dor_x_off * scanner->device->x_coordinate_base; /* correct DOR x-origin */ if (scanner->device->upper_left_x < 0) /* rounding errors may create a negative value */ @@ -7996,7 +7996,7 @@ SANE_Status sane_start(SANE_Handle handle) /* start reader_process, deponds on OS if fork() or threads are used */ scanner->reader_pid = sanei_thread_begin(reader_process, (void *) scanner); - if (scanner->reader_pid == -1) + if (!sanei_thread_is_valid (scanner->reader_pid)) { DBG(DBG_error, "ERROR: sanei_thread_begin failed (%s)\n", strerror(errno)); scanner->scanning = SANE_FALSE; diff --git a/backend/umax1220u.c b/backend/umax1220u.c index e04d908..79b8c92 100644 --- a/backend/umax1220u.c +++ b/backend/umax1220u.c @@ -742,7 +742,6 @@ void sane_close (SANE_Handle handle) { Umax_Scanner *prev, *scanner; - SANE_Status res; DBG (3, "sane_close\n"); @@ -775,7 +774,7 @@ sane_close (SANE_Handle handle) else first_handle = scanner->next; - res = UMAX_close_device (&scanner->scan); + UMAX_close_device (&scanner->scan); free (scanner); } diff --git a/backend/umax_pp.c b/backend/umax_pp.c index 90cd486..0f7ce4e 100644 --- a/backend/umax_pp.c +++ b/backend/umax_pp.c @@ -388,7 +388,7 @@ umax_pp_try_ports (SANEI_Config * config, char **ports) ports[i]); else DBG (3, - "umax_pp_try_ports: attach to port `%s' successfull\n", + "umax_pp_try_ports: attach to port `%s' successful\n", ports[i]); } free (ports[i]); @@ -1001,9 +1001,9 @@ sane_exit (void) for (i = 0; i < num_devices; i++) { free (devlist[i].port); - free (devlist[i].sane.name); - free (devlist[i].sane.model); - free (devlist[i].sane.vendor); + free ((void *) devlist[i].sane.name); + free ((void *) devlist[i].sane.model); + free ((void *) devlist[i].sane.vendor); } if (devlist != NULL) diff --git a/backend/umax_pp.h b/backend/umax_pp.h index 27ee95e..dbedab8 100644 --- a/backend/umax_pp.h +++ b/backend/umax_pp.h @@ -193,15 +193,8 @@ enum Umax_PP_Configure_Option NUM_CFG_OPTIONS }; -#if (!defined __GNUC__ || __GNUC__ < 2 || \ - __GNUC_MINOR__ < (defined __cplusplus ? 6 : 4)) - -#define __PRETTY_FUNCTION__ "umax_pp" - -#endif - #define DEBUG() DBG(4, "%s(v%d.%d.%d-%s): line %d: debug exception\n", \ - __PRETTY_FUNCTION__, SANE_CURRENT_MAJOR, V_MINOR, \ + __func__, SANE_CURRENT_MAJOR, V_MINOR, \ UMAX_PP_BUILD, UMAX_PP_STATE, __LINE__) #endif /* umax_pp_h */ diff --git a/backend/umax_pp_low.c b/backend/umax_pp_low.c index c5f58a7..1e38aba 100644 --- a/backend/umax_pp_low.c +++ b/backend/umax_pp_low.c @@ -65,6 +65,7 @@ #include #endif #include "../include/sane/sanei_debug.h" +#include "../include/sane/sanei_backend.h" #include #ifdef HAVE_DEV_PPBUS_PPI_H @@ -406,75 +407,51 @@ sanei_outsl (unsigned int port, const void *addr, unsigned long count) #ifndef ENABLE_PARPORT_DIRECTIO #define SANE_INB 0 static int -sanei_ioperm (int start, int length, int enable) +sanei_ioperm (__sane_unused__ int start, __sane_unused__ int length, + __sane_unused__ int enable) { - /* make compilers happy */ - enable = start + length; - /* returns failure */ return -1; } static unsigned char -sanei_inb (unsigned int port) +sanei_inb (__sane_unused__ unsigned int port) { - /* makes compilers happy */ - port = 0; return 255; } static void -sanei_outb (unsigned int port, unsigned char value) +sanei_outb (__sane_unused__ unsigned int port, + __sane_unused__ unsigned char value) { - /* makes compilers happy */ - port = 0; - value = 0; } static void -sanei_insb (unsigned int port, unsigned char *addr, unsigned long count) +sanei_insb (__sane_unused__ unsigned int port, + __sane_unused__ unsigned char *addr, + __sane_unused__ unsigned long count) { - /* makes compilers happy */ - if (addr) - { - port = 0; - count = 0; - } } static void -sanei_insl (unsigned int port, unsigned char *addr, unsigned long count) +sanei_insl (__sane_unused__ unsigned int port, + __sane_unused__ unsigned char *addr, + __sane_unused__ unsigned long count) { - /* makes compilers happy */ - if (addr) - { - port = 0; - count = 0; - } } static void -sanei_outsb (unsigned int port, const unsigned char *addr, - unsigned long count) +sanei_outsb (__sane_unused__ unsigned int port, + __sane_unused__ const unsigned char *addr, + __sane_unused__ unsigned long count) { - /* makes compilers happy */ - if (addr) - { - port = 0; - count = 0; - } } static void -sanei_outsl (unsigned int port, const unsigned char *addr, - unsigned long count) +sanei_outsl (__sane_unused__ unsigned int port, + __sane_unused__ const unsigned char *addr, + __sane_unused__ unsigned long count) { - /* makes compilers happy */ - if (addr) - { - port = 0; - count = 0; - } } #endif /* ENABLE_PARPORT_DIRECTIO is not defined */ @@ -862,7 +839,7 @@ sanei_parport_find_device (void) i = 0; while (devices[i] != NULL) { - DBG (16, "Controling %s: ", devices[i]); + DBG (16, "Controlling %s: ", devices[i]); file = open (devices[i], O_RDWR); if (file < 0) { @@ -950,7 +927,7 @@ int sanei_umax_pp_initPort (int port, char *name) { int fd, ectr; - int found = 0, ecp = 1; + int found = 0; #if ((defined HAVE_IOPERM)||(defined HAVE_MACHINE_CPUFUNC_H)||(defined HAVE_LINUX_PPDEV_H)) int mode, modes, rc; #endif @@ -1095,7 +1072,7 @@ sanei_umax_pp_initPort (int port, char *name) if (rc) { DBG (16, - "umax_pp: ppdev couldn't negociate mode IEEE1284_MODE_EPP for '%s' (ignored)\n", + "umax_pp: ppdev couldn't negotiate mode IEEE1284_MODE_EPP for '%s' (ignored)\n", name); } if (ioctl (fd, PPSETMODE, &mode)) @@ -1121,7 +1098,7 @@ sanei_umax_pp_initPort (int port, char *name) if (rc) { DBG (16, - "umax_pp: ppdev couldn't negociate mode IEEE1284_MODE_ECP for '%s' (ignored)\n", + "umax_pp: ppdev couldn't negotiate mode IEEE1284_MODE_ECP for '%s' (ignored)\n", name); } if (ioctl (fd, PPSETMODE, &mode)) @@ -1234,7 +1211,6 @@ sanei_umax_pp_initPort (int port, char *name) { DBG (1, "iopl could not raise IO permission to level 3\n"); DBG (1, "*NO* ECP support\n"); - ecp = 0; } else @@ -1247,8 +1223,6 @@ sanei_umax_pp_initPort (int port, char *name) } } -#else - ecp = 0; #endif @@ -2126,8 +2100,6 @@ sendCommand (int cmd) int tmp; int val; int i; - int gbufferRead[256]; /* read buffer for command 0x10 */ - if (g674 != 0) { @@ -2216,7 +2188,7 @@ sendCommand (int cmd) tmp = (tmp & 0x1E) | 0x1; Outb (CONTROL, tmp); Outb (CONTROL, tmp); - gbufferRead[i] = Inb (STATUS); + Inb (STATUS); tmp = tmp & 0x1E; Outb (CONTROL, tmp); Outb (CONTROL, tmp); @@ -2721,7 +2693,7 @@ init002 (int arg) static int ECPconnect (void) { - int ret, control, data; + int ret, control; /* these 3 lines set to 'inital mode' */ byteMode (); /*Outb (ECR, 0x20); */ @@ -2735,7 +2707,7 @@ ECPconnect (void) gData = Inb (DATA); gControl = Inb (CONTROL); - data = Inb (DATA); + Inb (DATA); control = Inb (CONTROL); Outb (CONTROL, control & 0x1F); control = Inb (CONTROL); @@ -3224,7 +3196,6 @@ static void ECPSetBuffer (int size) { static int last = 0; - unsigned char breg; /* routine XX */ compatMode (); @@ -3244,7 +3215,7 @@ ECPSetBuffer (int size) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (DATA, 0x0E); if (waitFifoEmpty () == 0) @@ -3253,7 +3224,7 @@ ECPSetBuffer (int size) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (ECPDATA, 0x0B); /* R0E=0x0B */ if (waitFifoEmpty () == 0) @@ -3262,7 +3233,7 @@ ECPSetBuffer (int size) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (DATA, 0x0F); /* R0F=size MSB */ if (waitFifoEmpty () == 0) @@ -3271,7 +3242,7 @@ ECPSetBuffer (int size) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (ECPDATA, size / 256); if (waitFifoEmpty () == 0) @@ -3280,7 +3251,7 @@ ECPSetBuffer (int size) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (DATA, 0x0B); /* R0B=size LSB */ if (waitFifoEmpty () == 0) @@ -3289,7 +3260,7 @@ ECPSetBuffer (int size) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (ECPDATA, size % 256); if (waitFifoEmpty () == 0) @@ -3298,7 +3269,7 @@ ECPSetBuffer (int size) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); DBG (16, "ECPSetBuffer(%d) passed ...\n", size); } @@ -3307,14 +3278,14 @@ ECPSetBuffer (int size) static int ECPbufferRead (int size, unsigned char *dest) { - int breg, n, idx, remain; + int n, idx, remain; idx = 0; n = size / 16; remain = size - 16 * n; /* block transfer */ - breg = Inb (ECR); /* 0x15,0x75 expected: fifo empty */ + Inb (ECR); /* 0x15,0x75 expected: fifo empty */ byteMode (); /*Outb (ECR, 0x20); byte mode */ Outb (CONTROL, 0x04); @@ -3326,7 +3297,7 @@ ECPbufferRead (int size, unsigned char *dest) __FILE__, __LINE__); return idx; } - breg = Inb (ECR); + Inb (ECR); Outb (DATA, 0x80); if (waitFifoEmpty () == 0) @@ -3335,7 +3306,7 @@ ECPbufferRead (int size, unsigned char *dest) __FILE__, __LINE__); return idx; } - breg = Inb (ECR); /* 0x75 expected */ + Inb (ECR); /* 0x75 expected */ byteMode (); /*Outb (ECR, 0x20); byte mode */ Outb (CONTROL, 0x20); /* data reverse */ @@ -4066,13 +4037,12 @@ static int EPPconnect (void) { int control; - int data; /* initial values, don't hardcode */ Outb (DATA, 0x04); Outb (CONTROL, 0x0C); - data = Inb (DATA); + Inb (DATA); control = Inb (CONTROL); Outb (CONTROL, control & 0x1F); control = Inb (CONTROL); @@ -8968,7 +8938,7 @@ cmdGetBuffer610p (int cmd, int len, unsigned char *buffer) static int cmdGetBuffer (int cmd, int len, unsigned char *buffer) { - int reg, tmp, i; + int reg, tmp; int word[5], read; int needed; @@ -8995,7 +8965,6 @@ cmdGetBuffer (int cmd, int len, unsigned char *buffer) REGISTERWRITE (0x0E, 0x0D); REGISTERWRITE (0x0F, 0x00); - i = 0; reg = registerRead (0x19) & 0xF8; /* wait if busy */ @@ -9108,7 +9077,7 @@ cmdGetBuffer (int cmd, int len, unsigned char *buffer) static int cmdGetBuffer32 (int cmd, int len, unsigned char *buffer) { - int reg, tmp, i; + int reg, tmp; int word[5], read; /* compute word */ @@ -9138,7 +9107,6 @@ cmdGetBuffer32 (int cmd, int len, unsigned char *buffer) REGISTERWRITE (0x0E, 0x0D); REGISTERWRITE (0x0F, 0x00); - i = 0; reg = registerRead (0x19) & 0xF8; /* wait if busy */ @@ -9255,7 +9223,7 @@ cmdGetBlockBuffer (int cmd, int len, int window, unsigned char *buffer) struct timeval td, tf; float elapsed; #endif - int reg, i; + int reg; int word[5], read; /* compute word */ @@ -9292,8 +9260,6 @@ cmdGetBlockBuffer (int cmd, int len, int window, unsigned char *buffer) REGISTERWRITE (0x0E, 0x0D); REGISTERWRITE (0x0F, 0x00); - i = 0; - /* init counter */ read = 0; @@ -10975,7 +10941,6 @@ sanei_umax_pp_startScan (int x, int y, int width, int height, int dpi, int *rtw, int *rth) { unsigned char *buffer; - int *dest = NULL; int rc = 0; int calibration[3 * 5100 + 768 + 2 + 1]; int xdpi, ydpi, h; @@ -11107,8 +11072,6 @@ sanei_umax_pp_startScan (int x, int y, int width, int height, int dpi, } DBG (16, "inquire() passed ... (%s:%d)\n", __FILE__, __LINE__); - dest = (int *) malloc (65536 * sizeof (int)); - rc = loadDefaultTables (); if (rc == 0) { @@ -11936,7 +11899,6 @@ offsetCalibration1220p (int color, int *offRed, int *offGreen, int *offBlue) int i, val; int commit[9] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, -1 }; int opsc04[9] = { 0x06, 0xF4, 0xFF, 0x81, 0x1B, 0x00, 0x00, 0x00, -1 }; - int opsc10[9] = { 0x06, 0xF4, 0xFF, 0x81, 0x1B, 0x00, 0x08, 0x00, -1 }; int opsc38[37] = { 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x0C, 0x00, 0x04, 0x40, 0x01, 0x00, 0x00, 0x04, 0x00, 0x6E, 0x18, 0x10, 0x03, 0x06, 0x00, 0x00, 0x00, @@ -11963,11 +11925,6 @@ offsetCalibration1220p (int color, int *offRed, int *offGreen, int *offBlue) opsc04[4] = 0x1B; opsc04[7] = 0x20; - opsc10[0] = 0x19; - opsc10[1] = 0xD5; - opsc10[4] = 0x1B; - opsc10[7] = 0x20; - opsc48[8] = 0x2B; opsc48[11] = 0x20; opsc48[12] = 0x08; diff --git a/backend/v4l.c b/backend/v4l.c index 519bf01..1e032c7 100644 --- a/backend/v4l.c +++ b/backend/v4l.c @@ -495,13 +495,12 @@ sane_exit (void) } SANE_Status -sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) +sane_get_devices (const SANE_Device *** device_list, SANE_Bool __sane_unused__ local_only) { V4L_Device *dev; int i; DBG (5, "sane_get_devices\n"); - local_only = SANE_TRUE; /* Avoid compile warning */ if (devlist) free (devlist); @@ -962,7 +961,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) SANE_Status sane_start (SANE_Handle handle) { - int len, loop; + int len; V4L_Scanner *s; char data; @@ -998,6 +997,7 @@ sane_start (SANE_Handle handle) } else { + int loop; s->is_mmap = SANE_TRUE; DBG (3, "sane_start: mmap frame, buffersize: %d bytes, buffers: %d, offset 0 %d\n", @@ -1046,6 +1046,7 @@ sane_start (SANE_Handle handle) /* v4l1 actually returns BGR when we ask for RGB, so convert it */ if (s->pict.palette == VIDEO_PALETTE_RGB24) { + __u32 loop; DBG (3, "sane_start: converting from BGR to RGB\n"); for (loop = 0; loop < (s->window.width * s->window.height * 3); loop += 3) { @@ -1130,22 +1131,15 @@ sane_cancel (SANE_Handle handle) SANE_Status -sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) +sane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool non_blocking) { - /* Avoid compile warning */ - handle = 0; - if (non_blocking == SANE_FALSE) return SANE_STATUS_GOOD; return SANE_STATUS_UNSUPPORTED; } SANE_Status -sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) +sane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd) { - /* Avoid compile warning */ - handle = 0; - fd = 0; - return SANE_STATUS_UNSUPPORTED; } diff --git a/backend/xerox_mfp-tcp.c b/backend/xerox_mfp-tcp.c index 2addb0d..845ab7e 100644 --- a/backend/xerox_mfp-tcp.c +++ b/backend/xerox_mfp-tcp.c @@ -47,9 +47,9 @@ #define RECV_TIMEOUT 1 /* seconds */ extern int sanei_debug_xerox_mfp; -int tcp_dev_request (struct device *dev, - SANE_Byte *cmd, size_t cmdlen, - SANE_Byte *resp, size_t *resplen) +int tcp_dev_request(struct device *dev, + SANE_Byte *cmd, size_t cmdlen, + SANE_Byte *resp, size_t *resplen) { size_t bytes_recv = 0; ssize_t rc = 1; @@ -58,46 +58,46 @@ int tcp_dev_request (struct device *dev, /* Send request, if any */ if (cmd && cmdlen) { - len = (size_t)sanei_tcp_write(dev->dn, cmd, cmdlen); - if (len != cmdlen) { - DBG (1, "%s: sent only %lu bytes of %lu\n", - __FUNCTION__, (u_long)len, (u_long)cmdlen); - return SANE_STATUS_IO_ERROR; - } + len = (size_t)sanei_tcp_write(dev->dn, cmd, cmdlen); + if (len != cmdlen) { + DBG(1, "%s: sent only %lu bytes of %lu\n", + __func__, (u_long)len, (u_long)cmdlen); + return SANE_STATUS_IO_ERROR; + } } /* Receive response, if expected */ if (resp && resplen) { - DBG (3, "%s: wait for %i bytes\n", __FUNCTION__, (int)*resplen); - - while (bytes_recv < *resplen && rc > 0) { - rc = recv(dev->dn, resp+bytes_recv, *resplen-bytes_recv, 0); - - if (rc > 0) bytes_recv += rc; - else { - DBG(1, "%s: error %s, bytes requested: %i, bytes read: %i\n", - __FUNCTION__, strerror(errno), (int)*resplen, (int)bytes_recv); - *resplen = bytes_recv; -/* - TODO: - do something smarter than that! -*/ - return SANE_STATUS_GOOD; - return SANE_STATUS_IO_ERROR; - } - } + DBG(3, "%s: wait for %i bytes\n", __func__, (int)*resplen); + + while (bytes_recv < *resplen && rc > 0) { + rc = recv(dev->dn, resp+bytes_recv, *resplen-bytes_recv, 0); + + if (rc > 0) bytes_recv += rc; + else { + DBG(1, "%s: error %s, bytes requested: %i, bytes read: %i\n", + __func__, strerror(errno), (int)*resplen, (int)bytes_recv); + *resplen = bytes_recv; + /* + TODO: + do something smarter than that! + */ + return SANE_STATUS_GOOD; + return SANE_STATUS_IO_ERROR; + } + } } *resplen = bytes_recv; - return SANE_STATUS_GOOD; + return SANE_STATUS_GOOD; } -SANE_Status tcp_dev_open (struct device *dev) +SANE_Status tcp_dev_open(struct device *dev) { SANE_Status status; - char* strhost; - char* strport; + char *strhost; + char *strport; int port; struct servent *sp; struct timeval tv; @@ -105,60 +105,60 @@ SANE_Status tcp_dev_open (struct device *dev) devname = dev->sane.name; - DBG (3, "%s: open %s\n", __FUNCTION__, devname); + DBG(3, "%s: open %s\n", __func__, devname); - if (strncmp (devname, "tcp", 3) != 0) return SANE_STATUS_INVAL; + if (strncmp(devname, "tcp", 3) != 0) return SANE_STATUS_INVAL; devname += 3; - devname = sanei_config_skip_whitespace (devname); + devname = sanei_config_skip_whitespace(devname); if (!*devname) return SANE_STATUS_INVAL; - devname = sanei_config_get_string (devname, &strhost); - devname = sanei_config_skip_whitespace (devname); + devname = sanei_config_get_string(devname, &strhost); + devname = sanei_config_skip_whitespace(devname); if (*devname) - devname = sanei_config_get_string (devname, &strport); + devname = sanei_config_get_string(devname, &strport); else - strport = "9400"; + strport = "9400"; if (isdigit(*strport)) { - port = atoi(strport); + port = atoi(strport); } else { - if ((sp = getservbyname(strport, "tcp"))) { - port = ntohs(sp->s_port); - } else { - DBG (1, "%s: unknown TCP service %s\n", __FUNCTION__, strport); - return SANE_STATUS_IO_ERROR; - } + if ((sp = getservbyname(strport, "tcp"))) { + port = ntohs(sp->s_port); + } else { + DBG(1, "%s: unknown TCP service %s\n", __func__, strport); + return SANE_STATUS_IO_ERROR; + } } status = sanei_tcp_open(strhost, port, &dev->dn); if (status == SANE_STATUS_GOOD) { - tv.tv_sec = RECV_TIMEOUT; - tv.tv_usec = 0; - if (setsockopt (dev->dn, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv) < 0) { - DBG(1, "%s: setsockopts %s", __FUNCTION__, strerror(errno)); - } + tv.tv_sec = RECV_TIMEOUT; + tv.tv_usec = 0; + if (setsockopt(dev->dn, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv) < 0) { + DBG(1, "%s: setsockopts %s", __func__, strerror(errno)); + } } return status; } void -tcp_dev_close (struct device *dev) +tcp_dev_close(struct device *dev) { if (!dev) return; - DBG (3, "%s: closing dev %p\n", __FUNCTION__, (void *)dev); + DBG(3, "%s: closing dev %p\n", __func__, (void *)dev); /* finish all operations */ if (dev->scanning) { - dev->cancel = 1; - /* flush READ_IMAGE data */ - if (dev->reading) sane_read(dev, NULL, 1, NULL); - /* send cancel if not sent before */ - if (dev->state != SANE_STATUS_CANCELLED) - ret_cancel(dev, 0); + dev->cancel = 1; + /* flush READ_IMAGE data */ + if (dev->reading) sane_read(dev, NULL, 1, NULL); + /* send cancel if not sent before */ + if (dev->state != SANE_STATUS_CANCELLED) + ret_cancel(dev, 0); } sanei_tcp_close(dev->dn); @@ -167,15 +167,15 @@ tcp_dev_close (struct device *dev) SANE_Status -tcp_configure_device (const char *devname, SANE_Status (*list_one)(SANE_String_Const devname)) +tcp_configure_device(const char *devname, SANE_Status(*list_one)(SANE_String_Const devname)) { -/* - TODO: LAN scanners multicast discovery. - devname would contain "tcp auto" - - We find new devnames and feed them to - `list_one_device' one by one -*/ + /* + TODO: LAN scanners multicast discovery. + devname would contain "tcp auto" + + We find new devnames and feed them to + `list_one_device' one by one + */ return list_one(devname); } diff --git a/backend/xerox_mfp-usb.c b/backend/xerox_mfp-usb.c index b9b56d8..6ef1eea 100644 --- a/backend/xerox_mfp-usb.c +++ b/backend/xerox_mfp-usb.c @@ -22,90 +22,90 @@ extern int sanei_debug_xerox_mfp; int -usb_dev_request (struct device *dev, - SANE_Byte *cmd, size_t cmdlen, - SANE_Byte *resp, size_t *resplen) +usb_dev_request(struct device *dev, + SANE_Byte *cmd, size_t cmdlen, + SANE_Byte *resp, size_t *resplen) { - SANE_Status status; - size_t len = cmdlen; - - if (cmd && cmdlen) { - status = sanei_usb_write_bulk (dev->dn, cmd, &cmdlen); - if (status != SANE_STATUS_GOOD) { - DBG (1, "%s: sanei_usb_write_bulk: %s\n", __FUNCTION__, - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; + SANE_Status status; + size_t len = cmdlen; + + if (cmd && cmdlen) { + status = sanei_usb_write_bulk(dev->dn, cmd, &cmdlen); + if (status != SANE_STATUS_GOOD) { + DBG(1, "%s: sanei_usb_write_bulk: %s\n", __func__, + sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + if (cmdlen != len) { + DBG(1, "%s: sanei_usb_write_bulk: wanted %lu bytes, wrote %lu bytes\n", + __func__, (size_t)len, (size_t)cmdlen); + return SANE_STATUS_IO_ERROR; + } } - if (cmdlen != len) { - DBG (1, "%s: sanei_usb_write_bulk: wanted %lu bytes, wrote %lu bytes\n", - __FUNCTION__, (size_t)len, (size_t)cmdlen); - return SANE_STATUS_IO_ERROR; - } - } - - if (resp && resplen) { - status = sanei_usb_read_bulk (dev->dn, resp, resplen); - if (status != SANE_STATUS_GOOD) { - DBG (1, "%s: sanei_usb_read_bulk: %s\n", __FUNCTION__, - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; + if (resp && resplen) { + status = sanei_usb_read_bulk(dev->dn, resp, resplen); + if (status != SANE_STATUS_GOOD) { + DBG(1, "%s: sanei_usb_read_bulk: %s\n", __func__, + sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } } - } - return SANE_STATUS_GOOD; + return SANE_STATUS_GOOD; } SANE_Status -usb_dev_open (struct device *dev) +usb_dev_open(struct device *dev) { - SANE_Status status; - - DBG (3, "%s: open %p\n", __FUNCTION__, (void *)dev); - status = sanei_usb_open (dev->sane.name, &dev->dn); - if (status != SANE_STATUS_GOOD) { - DBG (1, "%s: sanei_usb_open(%s): %s\n", __FUNCTION__, - dev->sane.name, sane_strstatus (status)); - dev->dn = -1; - return status; + SANE_Status status; + + DBG(3, "%s: open %p\n", __func__, (void *)dev); + status = sanei_usb_open(dev->sane.name, &dev->dn); + if (status != SANE_STATUS_GOOD) { + DBG(1, "%s: sanei_usb_open(%s): %s\n", __func__, + dev->sane.name, sane_strstatus(status)); + dev->dn = -1; + return status; } - sanei_usb_clear_halt (dev->dn); - return SANE_STATUS_GOOD; + sanei_usb_clear_halt(dev->dn); + return SANE_STATUS_GOOD; } void -usb_dev_close (struct device *dev) +usb_dev_close(struct device *dev) { - if (!dev) - return; - DBG (3, "%s: closing dev %p\n", __FUNCTION__, (void *)dev); - - /* finish all operations */ - if (dev->scanning) { - dev->cancel = 1; - /* flush READ_IMAGE data */ - if (dev->reading) - sane_read(dev, NULL, 1, NULL); - /* send cancel if not sent before */ - if (dev->state != SANE_STATUS_CANCELLED) - ret_cancel(dev, 0); - } - - sanei_usb_clear_halt (dev->dn); /* unstall for next users */ - sanei_usb_close (dev->dn); - dev->dn = -1; + if (!dev) + return; + DBG(3, "%s: closing dev %p\n", __func__, (void *)dev); + + /* finish all operations */ + if (dev->scanning) { + dev->cancel = 1; + /* flush READ_IMAGE data */ + if (dev->reading) + sane_read(dev, NULL, 1, NULL); + /* send cancel if not sent before */ + if (dev->state != SANE_STATUS_CANCELLED) + ret_cancel(dev, 0); + } + + sanei_usb_clear_halt(dev->dn); /* unstall for next users */ + sanei_usb_close(dev->dn); + dev->dn = -1; } /* SANE API ignores return code of this callback */ SANE_Status -usb_configure_device (const char *devname, SANE_Status (*attach) (const char *dev)) +usb_configure_device(const char *devname, SANE_Status(*attach)(const char *dev)) { - sanei_usb_set_timeout (1000); - sanei_usb_attach_matching_devices (devname, attach); - sanei_usb_set_timeout (30000); - return SANE_STATUS_GOOD; + sanei_usb_set_timeout(1000); + sanei_usb_attach_matching_devices(devname, attach); + sanei_usb_set_timeout(30000); + return SANE_STATUS_GOOD; } diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index 2ef7078..8b8c895 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -1,9 +1,12 @@ /* - * SANE backend for Xerox Phaser 3200MFP - * Copyright 2008 ABC + * SANE backend for Xerox Phaser 3200MFP et al. + * Copyright 2008-2016 ABC * - * Network Scanners Support - * Copyright 2010 Alexander Kuznetsov + * Network Scanners Support + * Copyright 2010 Alexander Kuznetsov + * + * Color scanning on Samsung M2870 model and Xerox Cognac 3215 & 3225 + * models by Laxmeesh Onkar Markod * * This program is licensed under GPL + SANE exception. * More info at http://www.sane-project.org/license.html @@ -30,6 +33,9 @@ #include "../include/sane/sanei_usb.h" #include "../include/sane/sanei_config.h" #include "../include/sane/sanei_backend.h" +#ifdef HAVE_LIBJPEG +#include +#endif #include "xerox_mfp.h" #define BACKEND_BUILD 13 @@ -46,34 +52,34 @@ transport available_transports[TRANSPORTS_MAX] = { static int resolv_state(int state) { - if (state & STATE_DOCUMENT_JAM) - return SANE_STATUS_JAMMED; - if (state & STATE_NO_DOCUMENT) - return SANE_STATUS_NO_DOCS; - if (state & STATE_COVER_OPEN) - return SANE_STATUS_COVER_OPEN; - if (state & STATE_INVALID_AREA) - return SANE_STATUS_INVAL; /* sane_start: implies SANE_INFO_RELOAD_OPTIONS */ - if (state & STATE_WARMING) + if (state & STATE_DOCUMENT_JAM) + return SANE_STATUS_JAMMED; + if (state & STATE_NO_DOCUMENT) + return SANE_STATUS_NO_DOCS; + if (state & STATE_COVER_OPEN) + return SANE_STATUS_COVER_OPEN; + if (state & STATE_INVALID_AREA) + return SANE_STATUS_INVAL; /* sane_start: implies SANE_INFO_RELOAD_OPTIONS */ + if (state & STATE_WARMING) #ifdef SANE_STATUS_WARMING_UP - return SANE_STATUS_WARMING_UP; + return SANE_STATUS_WARMING_UP; #else - return SANE_STATUS_DEVICE_BUSY; + return SANE_STATUS_DEVICE_BUSY; #endif - if (state & STATE_LOCKING) + if (state & STATE_LOCKING) #ifdef SANE_STATUS_HW_LOCKED - return SANE_STATUS_HW_LOCKED; + return SANE_STATUS_HW_LOCKED; #else - return SANE_STATUS_JAMMED; + return SANE_STATUS_JAMMED; #endif - if (state & ~STATE_NO_ERROR) - return SANE_STATUS_DEVICE_BUSY; - return 0; + if (state & ~STATE_NO_ERROR) + return SANE_STATUS_DEVICE_BUSY; + return 0; } static char *str_cmd(int cmd) { - switch (cmd) { + switch (cmd) { case CMD_ABORT: return "ABORT"; case CMD_INQUIRY: return "INQUIRY"; case CMD_RESERVE_UNIT: return "RESERVE_UNIT"; @@ -82,1262 +88,1442 @@ static char *str_cmd(int cmd) case CMD_READ: return "READ"; case CMD_READ_IMAGE: return "READ_IMAGE"; case CMD_OBJECT_POSITION: return "OBJECT_POSITION"; - } - return "unknown"; + } + return "unknown"; } #define MAX_DUMP 70 +const char *encTmpFileName = "/tmp/stmp_enc.tmp"; + +static int decompress(struct device __sane_unused__ *dev, + const char __sane_unused__ *infilename) +{ +#ifdef HAVE_LIBJPEG + int rc; + int row_stride, width, height, pixel_size; + struct jpeg_decompress_struct cinfo; + struct jpeg_error_mgr jerr; + unsigned long bmp_size = 0; + FILE *pInfile = NULL; + JSAMPARRAY buffer; + + if ((pInfile = fopen(infilename, "rb")) == NULL) { + fprintf(stderr, "can't open %s\n", infilename); + return -1; + } + + cinfo.err = jpeg_std_error(&jerr); + + jpeg_create_decompress(&cinfo); + + jpeg_stdio_src(&cinfo, pInfile); + + rc = jpeg_read_header(&cinfo, TRUE); + if (rc != 1) { + jpeg_destroy_decompress(&cinfo); + fclose(pInfile); + return -1; + } + + jpeg_start_decompress(&cinfo); + + width = cinfo.output_width; + height = cinfo.output_height; + pixel_size = cinfo.output_components; + bmp_size = width * height * pixel_size; + dev->decDataSize = bmp_size; + + row_stride = width * pixel_size; + + buffer = (*cinfo.mem->alloc_sarray) + ((j_common_ptr) &cinfo, JPOOL_IMAGE, row_stride, 1); + + while (cinfo.output_scanline < cinfo.output_height) { + buffer[0] = dev->decData + \ + (cinfo.output_scanline) * row_stride; + jpeg_read_scanlines(&cinfo, buffer, 1); + } + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(pInfile); + return 0; +#else + return -1; +#endif +} + +static int copy_decompress_data(struct device *dev, unsigned char *pDest, int maxlen, int *destLen) +{ + int data_size = 0; + size_t result = 0, retVal = 0; + + + if (0 == dev->decDataSize) { + *destLen = 0; + return retVal; + } + data_size = dev->decDataSize - dev->currentDecDataIndex; + if (data_size > maxlen) { + data_size = maxlen; + } + memcpy(pDest, dev->decData+dev->currentDecDataIndex, data_size); + result = data_size; + *destLen = result; + dev->currentDecDataIndex += result; + retVal = result; + + if (dev->decDataSize == dev->currentDecDataIndex) { + dev->currentDecDataIndex = 0; + dev->decDataSize = 0; + } + + return retVal; +} + +static int decompress_tempfile(struct device *dev) +{ + decompress(dev, encTmpFileName); + remove(encTmpFileName); + return 0; +} + +static int dump_to_tmp_file(struct device *dev) +{ + unsigned char *pSrc = dev->data; + int srcLen = dev->datalen; + FILE *pInfile; + if ((pInfile = fopen(encTmpFileName, "a")) == NULL) { + fprintf(stderr, "can't open %s\n", encTmpFileName); + return 0; + } + + fwrite(pSrc, 1, srcLen, pInfile); + fclose(pInfile); + return srcLen; +} + +static int isSupportedDevice(struct device __sane_unused__ *dev) +{ +#ifdef HAVE_LIBJPEG + /* Checking device which supports JPEG Lossy compression for color scanning*/ + if (dev->compressionTypes & (1 << 6)) + return 1; + else + return 0; +#else + return 0; +#endif +} + static void dbg_dump(struct device *dev) { - int i; - char dbuf[MAX_DUMP * 3 + 1], *dptr = dbuf; - int nzlen = dev->reslen; - int dlen = MIN(dev->reslen, MAX_DUMP); + int i; + char dbuf[MAX_DUMP * 3 + 1], *dptr = dbuf; + int nzlen = dev->reslen; + int dlen = MIN(dev->reslen, MAX_DUMP); - for (i = dev->reslen - 1; i >= 0; i--, nzlen--) - if (dev->res[i] != 0) - break; + for (i = dev->reslen - 1; i >= 0; i--, nzlen--) + if (dev->res[i] != 0) + break; - dlen = MIN(dlen, nzlen + 1); + dlen = MIN(dlen, nzlen + 1); - for (i = 0; i < dlen; i++, dptr += 3) - sprintf(dptr, " %02x", dev->res[i]); + for (i = 0; i < dlen; i++, dptr += 3) + sprintf(dptr, " %02x", dev->res[i]); - DBG (5, "[%lu]%s%s\n", (u_long)dev->reslen, dbuf, - (dlen < (int)dev->reslen)? "..." : ""); + DBG(5, "[%lu]%s%s\n", (u_long)dev->reslen, dbuf, + (dlen < (int)dev->reslen)? "..." : ""); } /* one command to device */ /* return 0: on error, 1: success */ -static int dev_command (struct device *dev, SANE_Byte * cmd, size_t reqlen) +static int dev_command(struct device *dev, SANE_Byte *cmd, size_t reqlen) { - SANE_Status status; - size_t sendlen = cmd[3] + 4; - SANE_Byte *res = dev->res; - - - assert (reqlen <= sizeof (dev->res)); /* requested len */ - dev->reslen = sizeof (dev->res); /* doing full buffer to flush stalled commands */ - - if (cmd[2] == CMD_SET_WINDOW) { - /* Set Window have wrong packet length, huh. */ - sendlen = 25; - } - - if (cmd[2] == CMD_READ_IMAGE) { - /* Read Image is raw data, don't need to read response */ - res = NULL; - } - - dev->state = 0; - DBG (4, ":: dev_command(%s[%#x], %lu)\n", str_cmd(cmd[2]), cmd[2], - (u_long)reqlen); - status = dev->io->dev_request(dev, cmd, sendlen, res, &dev->reslen); - if (status != SANE_STATUS_GOOD) { - DBG (1, "%s: dev_request: %s\n", __FUNCTION__, sane_strstatus (status)); - dev->state = SANE_STATUS_IO_ERROR; - return 0; - } + SANE_Status status; + size_t sendlen = cmd[3] + 4; + SANE_Byte *res = dev->res; - if (!res) { - /* if not need response just return success */ - return 1; - } - /* normal command reply, some sanity checking */ - if (dev->reslen < reqlen) { - DBG (1, "%s: illegal response len %lu, need %lu\n", - __FUNCTION__, (u_long)dev->reslen, (u_long)reqlen); - dev->state = SANE_STATUS_IO_ERROR; - return 0; - } else { - size_t pktlen; /* len specified in packet */ + assert(reqlen <= sizeof(dev->res)); /* requested len */ + dev->reslen = sizeof(dev->res); /* doing full buffer to flush stalled commands */ - if (DBG_LEVEL > 3) - dbg_dump(dev); + if (cmd[2] == CMD_SET_WINDOW) { + /* Set Window have wrong packet length, huh. */ + sendlen = 25; + } - if (dev->res[0] != RES_CODE) { - DBG (2, "%s: illegal data header %02x\n", __FUNCTION__, dev->res[0]); - dev->state = SANE_STATUS_IO_ERROR; - return 0; + if (cmd[2] == CMD_READ_IMAGE) { + /* Read Image is raw data, don't need to read response */ + res = NULL; } - pktlen = dev->res[2] + 3; - if (dev->reslen != pktlen) { - DBG (2, "%s: illegal response len %lu, should be %lu\n", - __FUNCTION__, (u_long)pktlen, (u_long)dev->reslen); - dev->state = SANE_STATUS_IO_ERROR; - return 0; + + dev->state = 0; + DBG(4, ":: dev_command(%s[%#x], %lu)\n", str_cmd(cmd[2]), cmd[2], + (u_long)reqlen); + status = dev->io->dev_request(dev, cmd, sendlen, res, &dev->reslen); + if (status != SANE_STATUS_GOOD) { + DBG(1, "%s: dev_request: %s\n", __func__, sane_strstatus(status)); + dev->state = SANE_STATUS_IO_ERROR; + return 0; } - if (dev->reslen > reqlen) - DBG (2, "%s: too big packet len %lu, need %lu\n", - __FUNCTION__, (u_long)dev->reslen, (u_long)reqlen); - } - - dev->state = 0; - if (cmd[2] == CMD_SET_WINDOW || - cmd[2] == CMD_OBJECT_POSITION || - cmd[2] == CMD_READ || - cmd[2] == CMD_RESERVE_UNIT) { - if (dev->res[1] == STATUS_BUSY) - dev->state = SANE_STATUS_DEVICE_BUSY; - else if (dev->res[1] == STATUS_CANCEL) - dev->state = SANE_STATUS_CANCELLED; - else if (dev->res[1] == STATUS_CHECK) - dev->state = resolv_state((cmd[2] == CMD_READ)? - (dev->res[12] << 8 | dev->res[13]) : - (dev->res[4] << 8 | dev->res[5])); - - if (dev->state) - DBG (3, "%s(%s[%#x]): => %d: %s\n", - __FUNCTION__, str_cmd(cmd[2]), cmd[2], - dev->state, sane_strstatus(dev->state)); - } - - return 1; + + if (!res) { + /* if not need response just return success */ + return 1; + } + + /* normal command reply, some sanity checking */ + if (dev->reslen < reqlen) { + DBG(1, "%s: illegal response len %lu, need %lu\n", + __func__, (u_long)dev->reslen, (u_long)reqlen); + dev->state = SANE_STATUS_IO_ERROR; + return 0; + } else { + size_t pktlen; /* len specified in packet */ + + if (DBG_LEVEL > 3) + dbg_dump(dev); + + if (dev->res[0] != RES_CODE) { + DBG(2, "%s: illegal data header %02x\n", __func__, dev->res[0]); + dev->state = SANE_STATUS_IO_ERROR; + return 0; + } + pktlen = dev->res[2] + 3; + if (dev->reslen != pktlen) { + DBG(2, "%s: illegal response len %lu, should be %lu\n", + __func__, (u_long)pktlen, (u_long)dev->reslen); + dev->state = SANE_STATUS_IO_ERROR; + return 0; + } + if (dev->reslen > reqlen) + DBG(2, "%s: too big packet len %lu, need %lu\n", + __func__, (u_long)dev->reslen, (u_long)reqlen); + } + + dev->state = 0; + if (cmd[2] == CMD_SET_WINDOW || + cmd[2] == CMD_OBJECT_POSITION || + cmd[2] == CMD_READ || + cmd[2] == CMD_RESERVE_UNIT) { + if (dev->res[1] == STATUS_BUSY) + dev->state = SANE_STATUS_DEVICE_BUSY; + else if (dev->res[1] == STATUS_CANCEL) + dev->state = SANE_STATUS_CANCELLED; + else if (dev->res[1] == STATUS_CHECK) + dev->state = resolv_state((cmd[2] == CMD_READ)? + (dev->res[12] << 8 | dev->res[13]) : + (dev->res[4] << 8 | dev->res[5])); + + if (dev->state) + DBG(3, "%s(%s[%#x]): => %d: %s\n", + __func__, str_cmd(cmd[2]), cmd[2], + dev->state, sane_strstatus(dev->state)); + } + + return 1; } /* one short command to device */ -static int dev_cmd (struct device *dev, SANE_Byte command) +static int dev_cmd(struct device *dev, SANE_Byte command) { - SANE_Byte cmd[4] = { REQ_CODE_A, REQ_CODE_B }; - cmd[2] = command; - return dev_command (dev, cmd, (command == CMD_INQUIRY)? 70 : 32); + SANE_Byte cmd[4] = { REQ_CODE_A, REQ_CODE_B }; + cmd[2] = command; + return dev_command(dev, cmd, (command == CMD_INQUIRY)? 70 : 32); } /* stop scanning operation. return previous status */ static SANE_Status dev_stop(struct device *dev) { - int state = dev->state; - - DBG (3, "%s: %p, scanning %d, reserved %d\n", __FUNCTION__, - (void *)dev, dev->scanning, dev->reserved); - dev->scanning = 0; - - /* release */ - if (!dev->reserved) - return state; - dev->reserved = 0; - dev_cmd(dev, CMD_RELEASE_UNIT); - DBG (3, "total image %d*%d size %d (win %d*%d), %d*%d %d data: %d, out %d bytes\n", - dev->para.pixels_per_line, dev->para.lines, - dev->total_img_size, - dev->win_width, dev->win_len, - dev->pixels_per_line, dev->ulines, dev->blocks, - dev->total_data_size, dev->total_out_size); - dev->state = state; - return state; + int state = dev->state; + + DBG(3, "%s: %p, scanning %d, reserved %d\n", __func__, + (void *)dev, dev->scanning, dev->reserved); + dev->scanning = 0; + + /* release */ + if (!dev->reserved) + return state; + dev->reserved = 0; + dev_cmd(dev, CMD_RELEASE_UNIT); + DBG(3, "total image %d*%d size %d (win %d*%d), %d*%d %d data: %d, out %d bytes\n", + dev->para.pixels_per_line, dev->para.lines, + dev->total_img_size, + dev->win_width, dev->win_len, + dev->pixels_per_line, dev->ulines, dev->blocks, + dev->total_data_size, dev->total_out_size); + dev->state = state; + return state; } SANE_Status ret_cancel(struct device *dev, SANE_Status ret) { - dev_cmd(dev, CMD_ABORT); - if (dev->scanning) { - dev_stop(dev); - dev->state = SANE_STATUS_CANCELLED; - } - return ret; + dev_cmd(dev, CMD_ABORT); + if (dev->scanning) { + dev_stop(dev); + dev->state = SANE_STATUS_CANCELLED; + } + return ret; } static int cancelled(struct device *dev) { - if (dev->cancel) - return ret_cancel(dev, 1); - return 0; + if (dev->cancel) + return ret_cancel(dev, 1); + return 0; } /* issue command and wait until scanner is not busy */ /* return 0 on error/blocking, 1 is ok and ready */ static int dev_cmd_wait(struct device *dev, int cmd) { - int sleeptime = 10; - - do { - if (cancelled(dev)) - return 0; - if (!dev_cmd(dev, cmd)) { - dev->state = SANE_STATUS_IO_ERROR; - return 0; - } else if (dev->state) { - if (dev->state != SANE_STATUS_DEVICE_BUSY) - return 0; - else { - if (dev->non_blocking) { - dev->state = SANE_STATUS_GOOD; - return 0; - } else { - if (sleeptime > 1000) - sleeptime = 1000; - DBG (4, "(%s) sleeping(%d ms).. [%x %x]\n", - str_cmd(cmd), sleeptime, dev->res[4], dev->res[5]); - usleep(sleeptime * 1000); - if (sleeptime < 1000) - sleeptime *= (sleeptime < 100)? 10 : 2; - } - } /* BUSY */ - } - } while (dev->state == SANE_STATUS_DEVICE_BUSY); + int sleeptime = 10; + + do { + if (cancelled(dev)) + return 0; + if (!dev_cmd(dev, cmd)) { + dev->state = SANE_STATUS_IO_ERROR; + return 0; + } else if (dev->state) { + if (dev->state != SANE_STATUS_DEVICE_BUSY) + return 0; + else { + if (dev->non_blocking) { + dev->state = SANE_STATUS_GOOD; + return 0; + } else { + if (sleeptime > 1000) + sleeptime = 1000; + DBG(4, "(%s) sleeping(%d ms).. [%x %x]\n", + str_cmd(cmd), sleeptime, dev->res[4], dev->res[5]); + usleep(sleeptime * 1000); + if (sleeptime < 1000) + sleeptime *= (sleeptime < 100)? 10 : 2; + } + } /* BUSY */ + } + } while (dev->state == SANE_STATUS_DEVICE_BUSY); - return 1; + return 1; } static int inq_dpi_bits[] = { - 75, 150, 0, 0, - 200, 300, 0, 0, - 600, 0, 0, 1200, - 100, 0, 0, 2400, - 0, 4800, 0, 9600 + 75, 150, 0, 0, + 200, 300, 0, 0, + 600, 0, 0, 1200, + 100, 0, 0, 2400, + 0, 4800, 0, 9600 }; static int res_dpi_codes[] = { - 75, 0, 150, 0, - 0, 300, 0, 600, - 1200, 200, 100, 2400, - 4800, 9600 + 75, 0, 150, 0, + 0, 300, 0, 600, + 1200, 200, 100, 2400, + 4800, 9600 }; -static int SANE_Word_sort(const void * a, const void * b) +static int SANE_Word_sort(const void *a, const void *b) { - return *(const SANE_Word *)a - *(const SANE_Word *)b; + return *(const SANE_Word *)a - *(const SANE_Word *)b; } /* resolve inquired dpi list to dpi_list array */ static void resolv_inq_dpi(struct device *dev) { - unsigned int i; - int res = dev->resolutions; - - assert(sizeof(inq_dpi_bits) < sizeof(dev->dpi_list)); - for (i = 0; i < sizeof(inq_dpi_bits) / sizeof(int); i++) - if (inq_dpi_bits[i] && (res & (1 << i))) - dev->dpi_list[++dev->dpi_list[0]] = inq_dpi_bits[i]; - qsort(&dev->dpi_list[1], dev->dpi_list[0], sizeof(SANE_Word), SANE_Word_sort); + unsigned int i; + int res = dev->resolutions; + + assert(sizeof(inq_dpi_bits) < sizeof(dev->dpi_list)); + for (i = 0; i < sizeof(inq_dpi_bits) / sizeof(int); i++) + if (inq_dpi_bits[i] && (res & (1 << i))) + dev->dpi_list[++dev->dpi_list[0]] = inq_dpi_bits[i]; + qsort(&dev->dpi_list[1], dev->dpi_list[0], sizeof(SANE_Word), SANE_Word_sort); } static unsigned int dpi_to_code(int dpi) { - unsigned int i; + unsigned int i; - for (i = 0; i < sizeof(res_dpi_codes) / sizeof(int); i++) { - if (dpi == res_dpi_codes[i]) - return i; - } - return 0; + for (i = 0; i < sizeof(res_dpi_codes) / sizeof(int); i++) { + if (dpi == res_dpi_codes[i]) + return i; + } + return 0; } static int string_match_index(const SANE_String_Const s[], SANE_String m) { - int i; - - for (i = 0; *s; i++) { - SANE_String_Const x = *s++; - if (strcasecmp(x, m) == 0) - return i; - } - return 0; + int i; + + for (i = 0; *s; i++) { + SANE_String_Const x = *s++; + if (strcasecmp(x, m) == 0) + return i; + } + return 0; } static SANE_String string_match(const SANE_String_Const s[], SANE_String m) { - return UNCONST(s[string_match_index(s, m)]); + return UNCONST(s[string_match_index(s, m)]); } -static size_t max_string_size (SANE_String_Const s[]) +static size_t max_string_size(SANE_String_Const s[]) { - size_t max = 0; - - while (*s) { - size_t size = strlen(*s++) + 1; - if (size > max) - max = size; - } - return max; + size_t max = 0; + + while (*s) { + size_t size = strlen(*s++) + 1; + if (size > max) + max = size; + } + return max; } static SANE_String_Const doc_sources[] = { - "Flatbed", "ADF", "Auto", NULL + "Flatbed", "ADF", "Auto", NULL }; static int doc_source_to_code[] = { - 0x40, 0x20, 0x80 + 0x40, 0x20, 0x80 }; static SANE_String_Const scan_modes[] = { - SANE_VALUE_SCAN_MODE_LINEART, - SANE_VALUE_SCAN_MODE_HALFTONE, - SANE_VALUE_SCAN_MODE_GRAY, - SANE_VALUE_SCAN_MODE_COLOR, - NULL + SANE_VALUE_SCAN_MODE_LINEART, + SANE_VALUE_SCAN_MODE_HALFTONE, + SANE_VALUE_SCAN_MODE_GRAY, + SANE_VALUE_SCAN_MODE_COLOR, + NULL }; static int scan_mode_to_code[] = { - 0x00, 0x01, 0x03, 0x05 + 0x00, 0x01, 0x03, 0x05 }; static SANE_Range threshold = { - SANE_FIX(30), SANE_FIX(70), SANE_FIX(10) + SANE_FIX(30), SANE_FIX(70), SANE_FIX(10) }; static void reset_options(struct device *dev) { - dev->val[OPT_RESOLUTION].w = 150; - dev->val[OPT_MODE].s = string_match(scan_modes, SANE_VALUE_SCAN_MODE_COLOR); - - /* if docs loaded in adf use it as default source, flatbed oterwise */ - dev->val[OPT_SOURCE].s = UNCONST(doc_sources[(dev->doc_loaded)? 1 : 0]); - - dev->val[OPT_THRESHOLD].w = SANE_FIX(50); - - /* this is reported maximum window size, will be fixed later */ - dev->win_x_range.min = SANE_FIX(0); - dev->win_x_range.max = SANE_FIX((double)dev->max_win_width / PNT_PER_MM); - dev->win_x_range.quant = SANE_FIX(1); - dev->win_y_range.min = SANE_FIX(0); - dev->win_y_range.max = SANE_FIX((double)dev->max_win_len / PNT_PER_MM); - dev->win_y_range.quant = SANE_FIX(1); - dev->val[OPT_SCAN_TL_X].w = dev->win_x_range.min; - dev->val[OPT_SCAN_TL_Y].w = dev->win_y_range.min; - dev->val[OPT_SCAN_BR_X].w = dev->win_x_range.max; - dev->val[OPT_SCAN_BR_Y].w = dev->win_y_range.max; + dev->val[OPT_RESOLUTION].w = 150; + dev->val[OPT_MODE].s = string_match(scan_modes, SANE_VALUE_SCAN_MODE_COLOR); + + /* if docs loaded in adf use it as default source, flatbed oterwise */ + dev->val[OPT_SOURCE].s = UNCONST(doc_sources[(dev->doc_loaded)? 1 : 0]); + + dev->val[OPT_THRESHOLD].w = SANE_FIX(50); + + /* this is reported maximum window size, will be fixed later */ + dev->win_x_range.min = SANE_FIX(0); + dev->win_x_range.max = SANE_FIX((double)dev->max_win_width / PNT_PER_MM); + dev->win_x_range.quant = SANE_FIX(1); + dev->win_y_range.min = SANE_FIX(0); + dev->win_y_range.max = SANE_FIX((double)dev->max_win_len / PNT_PER_MM); + dev->win_y_range.quant = SANE_FIX(1); + dev->val[OPT_SCAN_TL_X].w = dev->win_x_range.min; + dev->val[OPT_SCAN_TL_Y].w = dev->win_y_range.min; + dev->val[OPT_SCAN_BR_X].w = dev->win_x_range.max; + dev->val[OPT_SCAN_BR_Y].w = dev->win_y_range.max; } static void init_options(struct device *dev) { - int i; - - for (i = 0; i < NUM_OPTIONS; i++) { - dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - dev->opt[i].size = sizeof(SANE_Word); - dev->opt[i].type = SANE_TYPE_FIXED; - dev->val[i].s = NULL; - } - - dev->opt[OPT_NUMOPTIONS].name = SANE_NAME_NUM_OPTIONS; - dev->opt[OPT_NUMOPTIONS].title = SANE_TITLE_NUM_OPTIONS; - dev->opt[OPT_NUMOPTIONS].desc = SANE_DESC_NUM_OPTIONS; - dev->opt[OPT_NUMOPTIONS].type = SANE_TYPE_INT; - dev->opt[OPT_NUMOPTIONS].cap = SANE_CAP_SOFT_DETECT; - dev->val[OPT_NUMOPTIONS].w = NUM_OPTIONS; - - dev->opt[OPT_GROUP_STD].name = SANE_NAME_STANDARD; - dev->opt[OPT_GROUP_STD].title = SANE_TITLE_STANDARD; - dev->opt[OPT_GROUP_STD].desc = SANE_DESC_STANDARD; - dev->opt[OPT_GROUP_STD].type = SANE_TYPE_GROUP; - dev->opt[OPT_GROUP_STD].cap = 0; - - dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; - dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; - dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; - dev->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; - dev->opt[OPT_RESOLUTION].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; - dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; - dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; - dev->opt[OPT_RESOLUTION].constraint.word_list = dev->dpi_list; - - dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; - dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; - dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; - dev->opt[OPT_MODE].type = SANE_TYPE_STRING; - dev->opt[OPT_MODE].size = max_string_size(scan_modes); - dev->opt[OPT_MODE].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; - dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; - dev->opt[OPT_MODE].constraint.string_list = scan_modes; - - dev->opt[OPT_THRESHOLD].name = SANE_NAME_HIGHLIGHT; - dev->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; - dev->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; - dev->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; - dev->opt[OPT_THRESHOLD].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; - dev->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; - dev->opt[OPT_THRESHOLD].constraint.range = &threshold; - - dev->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; - dev->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; - dev->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; - dev->opt[OPT_SOURCE].type = SANE_TYPE_STRING; - dev->opt[OPT_SOURCE].size = max_string_size(doc_sources); - dev->opt[OPT_SOURCE].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; - dev->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; - dev->opt[OPT_SOURCE].constraint.string_list = doc_sources; - - dev->opt[OPT_GROUP_GEO].name = SANE_NAME_GEOMETRY; - dev->opt[OPT_GROUP_GEO].title = SANE_TITLE_GEOMETRY; - dev->opt[OPT_GROUP_GEO].desc = SANE_DESC_GEOMETRY; - dev->opt[OPT_GROUP_GEO].type = SANE_TYPE_GROUP; - dev->opt[OPT_GROUP_GEO].cap = 0; - - dev->opt[OPT_SCAN_TL_X].name = SANE_NAME_SCAN_TL_X; - dev->opt[OPT_SCAN_TL_X].title = SANE_TITLE_SCAN_TL_X; - dev->opt[OPT_SCAN_TL_X].desc = SANE_DESC_SCAN_TL_X; - dev->opt[OPT_SCAN_TL_X].unit = SANE_UNIT_MM; - dev->opt[OPT_SCAN_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; - dev->opt[OPT_SCAN_TL_X].constraint.range = &dev->win_x_range; - - dev->opt[OPT_SCAN_TL_Y].name = SANE_NAME_SCAN_TL_Y; - dev->opt[OPT_SCAN_TL_Y].title = SANE_TITLE_SCAN_TL_Y; - dev->opt[OPT_SCAN_TL_Y].desc = SANE_DESC_SCAN_TL_Y; - dev->opt[OPT_SCAN_TL_Y].unit = SANE_UNIT_MM; - dev->opt[OPT_SCAN_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; - dev->opt[OPT_SCAN_TL_Y].constraint.range = &dev->win_y_range; - - dev->opt[OPT_SCAN_BR_X].name = SANE_NAME_SCAN_BR_X; - dev->opt[OPT_SCAN_BR_X].title = SANE_TITLE_SCAN_BR_X; - dev->opt[OPT_SCAN_BR_X].desc = SANE_DESC_SCAN_BR_X; - dev->opt[OPT_SCAN_BR_X].unit = SANE_UNIT_MM; - dev->opt[OPT_SCAN_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; - dev->opt[OPT_SCAN_BR_X].constraint.range = &dev->win_x_range; - - dev->opt[OPT_SCAN_BR_Y].name = SANE_NAME_SCAN_BR_Y; - dev->opt[OPT_SCAN_BR_Y].title = SANE_TITLE_SCAN_BR_Y; - dev->opt[OPT_SCAN_BR_Y].desc = SANE_DESC_SCAN_BR_Y; - dev->opt[OPT_SCAN_BR_Y].unit = SANE_UNIT_MM; - dev->opt[OPT_SCAN_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; - dev->opt[OPT_SCAN_BR_Y].constraint.range = &dev->win_y_range; + int i; + + for (i = 0; i < NUM_OPTIONS; i++) { + dev->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + dev->opt[i].size = sizeof(SANE_Word); + dev->opt[i].type = SANE_TYPE_FIXED; + dev->val[i].s = NULL; + } + + dev->opt[OPT_NUMOPTIONS].name = SANE_NAME_NUM_OPTIONS; + dev->opt[OPT_NUMOPTIONS].title = SANE_TITLE_NUM_OPTIONS; + dev->opt[OPT_NUMOPTIONS].desc = SANE_DESC_NUM_OPTIONS; + dev->opt[OPT_NUMOPTIONS].type = SANE_TYPE_INT; + dev->opt[OPT_NUMOPTIONS].cap = SANE_CAP_SOFT_DETECT; + dev->val[OPT_NUMOPTIONS].w = NUM_OPTIONS; + + dev->opt[OPT_GROUP_STD].name = SANE_NAME_STANDARD; + dev->opt[OPT_GROUP_STD].title = SANE_TITLE_STANDARD; + dev->opt[OPT_GROUP_STD].desc = SANE_DESC_STANDARD; + dev->opt[OPT_GROUP_STD].type = SANE_TYPE_GROUP; + dev->opt[OPT_GROUP_STD].cap = 0; + + dev->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; + dev->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; + dev->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; + dev->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; + dev->opt[OPT_RESOLUTION].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; + dev->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; + dev->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; + dev->opt[OPT_RESOLUTION].constraint.word_list = dev->dpi_list; + + dev->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; + dev->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; + dev->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; + dev->opt[OPT_MODE].type = SANE_TYPE_STRING; + dev->opt[OPT_MODE].size = max_string_size(scan_modes); + dev->opt[OPT_MODE].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; + dev->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + dev->opt[OPT_MODE].constraint.string_list = scan_modes; + + dev->opt[OPT_THRESHOLD].name = SANE_NAME_HIGHLIGHT; + dev->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; + dev->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; + dev->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; + dev->opt[OPT_THRESHOLD].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; + dev->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_THRESHOLD].constraint.range = &threshold; + + dev->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; + dev->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; + dev->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; + dev->opt[OPT_SOURCE].type = SANE_TYPE_STRING; + dev->opt[OPT_SOURCE].size = max_string_size(doc_sources); + dev->opt[OPT_SOURCE].cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; + dev->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + dev->opt[OPT_SOURCE].constraint.string_list = doc_sources; + + dev->opt[OPT_GROUP_GEO].name = SANE_NAME_GEOMETRY; + dev->opt[OPT_GROUP_GEO].title = SANE_TITLE_GEOMETRY; + dev->opt[OPT_GROUP_GEO].desc = SANE_DESC_GEOMETRY; + dev->opt[OPT_GROUP_GEO].type = SANE_TYPE_GROUP; + dev->opt[OPT_GROUP_GEO].cap = 0; + + dev->opt[OPT_SCAN_TL_X].name = SANE_NAME_SCAN_TL_X; + dev->opt[OPT_SCAN_TL_X].title = SANE_TITLE_SCAN_TL_X; + dev->opt[OPT_SCAN_TL_X].desc = SANE_DESC_SCAN_TL_X; + dev->opt[OPT_SCAN_TL_X].unit = SANE_UNIT_MM; + dev->opt[OPT_SCAN_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_SCAN_TL_X].constraint.range = &dev->win_x_range; + + dev->opt[OPT_SCAN_TL_Y].name = SANE_NAME_SCAN_TL_Y; + dev->opt[OPT_SCAN_TL_Y].title = SANE_TITLE_SCAN_TL_Y; + dev->opt[OPT_SCAN_TL_Y].desc = SANE_DESC_SCAN_TL_Y; + dev->opt[OPT_SCAN_TL_Y].unit = SANE_UNIT_MM; + dev->opt[OPT_SCAN_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_SCAN_TL_Y].constraint.range = &dev->win_y_range; + + dev->opt[OPT_SCAN_BR_X].name = SANE_NAME_SCAN_BR_X; + dev->opt[OPT_SCAN_BR_X].title = SANE_TITLE_SCAN_BR_X; + dev->opt[OPT_SCAN_BR_X].desc = SANE_DESC_SCAN_BR_X; + dev->opt[OPT_SCAN_BR_X].unit = SANE_UNIT_MM; + dev->opt[OPT_SCAN_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_SCAN_BR_X].constraint.range = &dev->win_x_range; + + dev->opt[OPT_SCAN_BR_Y].name = SANE_NAME_SCAN_BR_Y; + dev->opt[OPT_SCAN_BR_Y].title = SANE_TITLE_SCAN_BR_Y; + dev->opt[OPT_SCAN_BR_Y].desc = SANE_DESC_SCAN_BR_Y; + dev->opt[OPT_SCAN_BR_Y].unit = SANE_UNIT_MM; + dev->opt[OPT_SCAN_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; + dev->opt[OPT_SCAN_BR_Y].constraint.range = &dev->win_y_range; } /* fill parameters from options */ static void set_parameters(struct device *dev) { - double px_to_len; + double px_to_len; - dev->para.last_frame = SANE_TRUE; - dev->para.lines = -1; - px_to_len = 1200.0 / dev->val[OPT_RESOLUTION].w; + dev->para.last_frame = SANE_TRUE; + dev->para.lines = -1; + px_to_len = 1200.0 / dev->val[OPT_RESOLUTION].w; #define BETTER_BASEDPI 1 - /* tests prove that 1200dpi base is very inexact - * so I calculated better values for each axis */ -#if BETTER_BASEDPI - px_to_len = 1180.0 / dev->val[OPT_RESOLUTION].w; -#endif - dev->para.pixels_per_line = dev->win_width / px_to_len; - dev->para.bytes_per_line = dev->para.pixels_per_line; + /* tests prove that 1200dpi base is very inexact + * so I calculated better values for each axis */ #if BETTER_BASEDPI - px_to_len = 1213.9 / dev->val[OPT_RESOLUTION].w; + px_to_len = 1180.0 / dev->val[OPT_RESOLUTION].w; #endif - dev->para.lines = dev->win_len / px_to_len; - if (dev->composition == MODE_LINEART || - dev->composition == MODE_HALFTONE) { - dev->para.format = SANE_FRAME_GRAY; - dev->para.depth = 1; - dev->para.bytes_per_line = (dev->para.pixels_per_line + 7) / 8; - } else if (dev->composition == MODE_GRAY8) { - dev->para.format = SANE_FRAME_GRAY; - dev->para.depth = 8; + dev->para.pixels_per_line = dev->win_width / px_to_len; dev->para.bytes_per_line = dev->para.pixels_per_line; - } else if (dev->composition == MODE_RGB24) { - dev->para.format = SANE_FRAME_RGB; - dev->para.depth = 8; - dev->para.bytes_per_line *= 3; - } else { - /* this will never happen */ - DBG (1, "%s: impossible image composition %d\n", - __FUNCTION__, dev->composition); - dev->para.format = SANE_FRAME_GRAY; - dev->para.depth = 8; - } + + if (!isSupportedDevice(dev)) { +#if BETTER_BASEDPI + px_to_len = 1213.9 / dev->val[OPT_RESOLUTION].w; +#endif + } + dev->para.lines = dev->win_len / px_to_len; + if (dev->composition == MODE_LINEART || + dev->composition == MODE_HALFTONE) { + dev->para.format = SANE_FRAME_GRAY; + dev->para.depth = 1; + dev->para.bytes_per_line = (dev->para.pixels_per_line + 7) / 8; + } else if (dev->composition == MODE_GRAY8) { + dev->para.format = SANE_FRAME_GRAY; + dev->para.depth = 8; + dev->para.bytes_per_line = dev->para.pixels_per_line; + } else if (dev->composition == MODE_RGB24) { + dev->para.format = SANE_FRAME_RGB; + dev->para.depth = 8; + dev->para.bytes_per_line *= 3; + } else { + /* this will never happen */ + DBG(1, "%s: impossible image composition %d\n", + __func__, dev->composition); + dev->para.format = SANE_FRAME_GRAY; + dev->para.depth = 8; + } } /* resolve all options related to scan window */ /* called after option changed and in set_window */ static int fix_window(struct device *dev) { - double win_width_mm, win_len_mm; - int i; - int threshold = SANE_UNFIX(dev->val[OPT_THRESHOLD].w); - - dev->resolution = dpi_to_code(dev->val[OPT_RESOLUTION].w); - dev->composition = scan_mode_to_code[string_match_index(scan_modes, dev->val[OPT_MODE].s)]; - - if (dev->composition == MODE_LINEART || - dev->composition == MODE_HALFTONE) { - dev->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; - } else { - dev->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; - } - if (threshold < 30) { - dev->val[OPT_THRESHOLD].w = SANE_FIX(30); - } else if (threshold > 70) { - dev->val[OPT_THRESHOLD].w = SANE_FIX(70); - } - threshold = SANE_UNFIX(dev->val[OPT_THRESHOLD].w); - dev->threshold = (threshold - 30) / 10; - dev->val[OPT_THRESHOLD].w = SANE_FIX(dev->threshold * 10 + 30); - - dev->doc_source = doc_source_to_code[string_match_index(doc_sources, dev->val[OPT_SOURCE].s)]; - - /* max window len is dependent of document source */ - if (dev->doc_source == DOC_FLATBED || - (dev->doc_source == DOC_AUTO && !dev->doc_loaded)) - dev->max_len = dev->max_len_fb; - else - dev->max_len = dev->max_len_adf; - - /* parameters */ - dev->win_y_range.max = SANE_FIX((double)dev->max_len / PNT_PER_MM); - - /* window sanity checking */ - for (i = OPT_SCAN_TL_X; i <= OPT_SCAN_BR_Y; i++) { - if (dev->val[i].w < dev->opt[i].constraint.range->min) - dev->val[i].w = dev->opt[i].constraint.range->min; - if (dev->val[i].w > dev->opt[i].constraint.range->max) - dev->val[i].w = dev->opt[i].constraint.range->max; - } - - if (dev->val[OPT_SCAN_TL_X].w > dev->val[OPT_SCAN_BR_X].w) - SWAP_Word(dev->val[OPT_SCAN_TL_X].w, dev->val[OPT_SCAN_BR_X].w); - if (dev->val[OPT_SCAN_TL_Y].w > dev->val[OPT_SCAN_BR_Y].w) - SWAP_Word(dev->val[OPT_SCAN_TL_Y].w, dev->val[OPT_SCAN_BR_Y].w); - - /* recalculate millimeters to inches */ - dev->win_off_x = SANE_UNFIX(dev->val[OPT_SCAN_TL_X].w) / MM_PER_INCH; - dev->win_off_y = SANE_UNFIX(dev->val[OPT_SCAN_TL_Y].w) / MM_PER_INCH; - - /* calc win size in mm */ - win_width_mm = SANE_UNFIX(dev->val[OPT_SCAN_BR_X].w) - - SANE_UNFIX(dev->val[OPT_SCAN_TL_X].w); - win_len_mm = SANE_UNFIX(dev->val[OPT_SCAN_BR_Y].w) - - SANE_UNFIX(dev->val[OPT_SCAN_TL_Y].w); - /* convert mm to 1200 dpi points */ - dev->win_width = (int)(win_width_mm * PNT_PER_MM); - dev->win_len = (int)(win_len_mm * PNT_PER_MM); - - /* don't scan if window is zero size */ - if (!dev->win_width || !dev->win_len) { - /* "The scan cannot be started with the current set of options." */ - dev->state = SANE_STATUS_INVAL; - return 0; - } + double win_width_mm, win_len_mm; + int i; + int threshold = SANE_UNFIX(dev->val[OPT_THRESHOLD].w); - return 1; -} + dev->resolution = dpi_to_code(dev->val[OPT_RESOLUTION].w); + dev->composition = scan_mode_to_code[string_match_index(scan_modes, dev->val[OPT_MODE].s)]; -static int dev_set_window (struct device *dev) -{ - SANE_Byte cmd[0x19] = { - REQ_CODE_A, REQ_CODE_B, CMD_SET_WINDOW, 0x13, MSG_SCANNING_PARAM - }; + if (dev->composition == MODE_LINEART || + dev->composition == MODE_HALFTONE) { + dev->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; + } else { + dev->opt[OPT_THRESHOLD].cap |= SANE_CAP_INACTIVE; + } + if (threshold < 30) { + dev->val[OPT_THRESHOLD].w = SANE_FIX(30); + } else if (threshold > 70) { + dev->val[OPT_THRESHOLD].w = SANE_FIX(70); + } + threshold = SANE_UNFIX(dev->val[OPT_THRESHOLD].w); + dev->threshold = (threshold - 30) / 10; + dev->val[OPT_THRESHOLD].w = SANE_FIX(dev->threshold * 10 + 30); - if (!fix_window(dev)) - return 0; + dev->doc_source = doc_source_to_code[string_match_index(doc_sources, dev->val[OPT_SOURCE].s)]; + + /* max window len is dependent of document source */ + if (dev->doc_source == DOC_FLATBED || + (dev->doc_source == DOC_AUTO && !dev->doc_loaded)) + dev->max_len = dev->max_len_fb; + else + dev->max_len = dev->max_len_adf; + + /* parameters */ + dev->win_y_range.max = SANE_FIX((double)dev->max_len / PNT_PER_MM); + + /* window sanity checking */ + for (i = OPT_SCAN_TL_X; i <= OPT_SCAN_BR_Y; i++) { + if (dev->val[i].w < dev->opt[i].constraint.range->min) + dev->val[i].w = dev->opt[i].constraint.range->min; + if (dev->val[i].w > dev->opt[i].constraint.range->max) + dev->val[i].w = dev->opt[i].constraint.range->max; + } + + if (dev->val[OPT_SCAN_TL_X].w > dev->val[OPT_SCAN_BR_X].w) + SWAP_Word(dev->val[OPT_SCAN_TL_X].w, dev->val[OPT_SCAN_BR_X].w); + if (dev->val[OPT_SCAN_TL_Y].w > dev->val[OPT_SCAN_BR_Y].w) + SWAP_Word(dev->val[OPT_SCAN_TL_Y].w, dev->val[OPT_SCAN_BR_Y].w); + + /* recalculate millimeters to inches */ + dev->win_off_x = SANE_UNFIX(dev->val[OPT_SCAN_TL_X].w) / MM_PER_INCH; + dev->win_off_y = SANE_UNFIX(dev->val[OPT_SCAN_TL_Y].w) / MM_PER_INCH; + + /* calc win size in mm */ + win_width_mm = SANE_UNFIX(dev->val[OPT_SCAN_BR_X].w) - + SANE_UNFIX(dev->val[OPT_SCAN_TL_X].w); + win_len_mm = SANE_UNFIX(dev->val[OPT_SCAN_BR_Y].w) - + SANE_UNFIX(dev->val[OPT_SCAN_TL_Y].w); + /* convert mm to 1200 dpi points */ + dev->win_width = (int)(win_width_mm * PNT_PER_MM); + dev->win_len = (int)(win_len_mm * PNT_PER_MM); + + /* don't scan if window is zero size */ + if (!dev->win_width || !dev->win_len) { + /* "The scan cannot be started with the current set of options." */ + dev->state = SANE_STATUS_INVAL; + return 0; + } - cmd[0x05] = dev->win_width >> 24; - cmd[0x06] = dev->win_width >> 16; - cmd[0x07] = dev->win_width >> 8; - cmd[0x08] = dev->win_width; - cmd[0x09] = dev->win_len >> 24; - cmd[0x0a] = dev->win_len >> 16; - cmd[0x0b] = dev->win_len >> 8; - cmd[0x0c] = dev->win_len; - cmd[0x0d] = dev->resolution; /* x */ - cmd[0x0e] = dev->resolution; /* y */ - cmd[0x0f] = (SANE_Byte)floor(dev->win_off_x); - cmd[0x10] = (SANE_Byte)((dev->win_off_x - floor(dev->win_off_x)) * 100); - cmd[0x11] = (SANE_Byte)floor(dev->win_off_y); - cmd[0x12] = (SANE_Byte)((dev->win_off_y - floor(dev->win_off_y)) * 100); - cmd[0x13] = dev->composition; - cmd[0x16] = dev->threshold; - cmd[0x17] = dev->doc_source; - - DBG (5, "OFF xi: %02x%02x yi: %02x%02x," - " WIN xp: %02x%02x%02x%02x yp %02x%02x%02x%02x," - " MAX %08x %08x\n", - cmd[0x0f], cmd[0x10], cmd[0x11], cmd[0x12], - cmd[0x05], cmd[0x06], cmd[0x07], cmd[0x08], - cmd[0x09], cmd[0x0a], cmd[0x0b], cmd[0x0c], - dev->max_win_width, dev->max_win_len); - - return dev_command (dev, cmd, 32); + return 1; +} + +static int dev_set_window(struct device *dev) +{ + SANE_Byte cmd[0x19] = { + REQ_CODE_A, REQ_CODE_B, CMD_SET_WINDOW, 0x13, MSG_SCANNING_PARAM + }; + + if (!fix_window(dev)) + return 0; + + cmd[0x05] = dev->win_width >> 24; + cmd[0x06] = dev->win_width >> 16; + cmd[0x07] = dev->win_width >> 8; + cmd[0x08] = dev->win_width; + cmd[0x09] = dev->win_len >> 24; + cmd[0x0a] = dev->win_len >> 16; + cmd[0x0b] = dev->win_len >> 8; + cmd[0x0c] = dev->win_len; + cmd[0x0d] = dev->resolution; /* x */ + cmd[0x0e] = dev->resolution; /* y */ + cmd[0x0f] = (SANE_Byte)floor(dev->win_off_x); + cmd[0x10] = (SANE_Byte)((dev->win_off_x - floor(dev->win_off_x)) * 100); + cmd[0x11] = (SANE_Byte)floor(dev->win_off_y); + cmd[0x12] = (SANE_Byte)((dev->win_off_y - floor(dev->win_off_y)) * 100); + cmd[0x13] = dev->composition; + /* Set to JPEG Lossy Compression, if mode is color (only for supported model)... + * else go with Uncompressed (For backard compatibility with old models )*/ + if (dev->composition == MODE_RGB24) { + if (isSupportedDevice(dev)) { + cmd[0x14] = 0x6; + } + } + cmd[0x16] = dev->threshold; + cmd[0x17] = dev->doc_source; + + DBG(5, "OFF xi: %02x%02x yi: %02x%02x," + " WIN xp: %02x%02x%02x%02x yp %02x%02x%02x%02x," + " MAX %08x %08x\n", + cmd[0x0f], cmd[0x10], cmd[0x11], cmd[0x12], + cmd[0x05], cmd[0x06], cmd[0x07], cmd[0x08], + cmd[0x09], cmd[0x0a], cmd[0x0b], cmd[0x0c], + dev->max_win_width, dev->max_win_len); + + return dev_command(dev, cmd, 32); } static SANE_Status -dev_inquiry (struct device *dev) +dev_inquiry(struct device *dev) { - SANE_Byte *ptr; - SANE_Char *optr, *xptr; - - if (!dev_cmd (dev, CMD_INQUIRY)) - return SANE_STATUS_IO_ERROR; - ptr = dev->res; - if (ptr[3] != MSG_PRODUCT_INFO) { - DBG (1, "%s: illegal INQUIRY response %02x\n", __FUNCTION__, ptr[3]); - return SANE_STATUS_IO_ERROR; - } - - /* parse reported manufacturer/product names */ - dev->sane.vendor = optr = (SANE_Char *) malloc (33); - for (ptr += 4; ptr < &dev->res[0x24] && *ptr && *ptr != ' ';) - *optr++ = *ptr++; - *optr++ = 0; - - for (; ptr < &dev->res[0x24] && (!*ptr || *ptr == ' '); ptr++) - /* skip spaces */; - - dev->sane.model = optr = (SANE_Char *) malloc (33); - xptr = optr; /* is last non space character + 1 */ - for (; ptr < &dev->res[0x24] && *ptr;) { - if (*ptr != ' ') - xptr = optr + 1; - *optr++ = *ptr++; - } - *optr++ = 0; - *xptr = 0; - - DBG (1, "%s: found %s/%s\n", __FUNCTION__, dev->sane.vendor, dev->sane.model); - dev->sane.type = strdup ("multi-function peripheral"); - - dev->resolutions = dev->res[0x37] << 16 | - dev->res[0x24] << 8 | - dev->res[0x25]; - dev->compositions = dev->res[0x27]; - dev->max_win_width = dev->res[0x28] << 24 | - dev->res[0x29] << 16 | - dev->res[0x2a] << 8 | - dev->res[0x2b]; - dev->max_win_len = dev->res[0x2c] << 24 | - dev->res[0x2d] << 16 | - dev->res[0x2e] << 8 | - dev->res[0x2f]; - dev->max_len_adf = dev->res[0x38] << 24 | - dev->res[0x39] << 16 | - dev->res[0x3a] << 8 | - dev->res[0x3b]; - dev->max_len_fb = dev->res[0x3c] << 24 | - dev->res[0x3d] << 16 | - dev->res[0x3e] << 8 | - dev->res[0x3f]; - dev->line_order = dev->res[0x31]; - dev->doc_loaded = (dev->res[0x35] == 0x02) && - (dev->res[0x26] & 0x03); - - init_options(dev); - reset_options(dev); - fix_window(dev); - set_parameters(dev); - resolv_inq_dpi(dev); - - return SANE_STATUS_GOOD; + SANE_Byte *ptr; + SANE_Char *optr, *xptr; + + if (!dev_cmd(dev, CMD_INQUIRY)) + return SANE_STATUS_IO_ERROR; + ptr = dev->res; + if (ptr[3] != MSG_PRODUCT_INFO) { + DBG(1, "%s: illegal INQUIRY response %02x\n", __func__, ptr[3]); + return SANE_STATUS_IO_ERROR; + } + + /* parse reported manufacturer/product names */ + dev->sane.vendor = optr = (SANE_Char *) malloc(33); + for (ptr += 4; ptr < &dev->res[0x24] && *ptr && *ptr != ' ';) + *optr++ = *ptr++; + *optr++ = 0; + + for (; ptr < &dev->res[0x24] && (!*ptr || *ptr == ' '); ptr++) + /* skip spaces */; + + dev->sane.model = optr = (SANE_Char *) malloc(33); + xptr = optr; /* is last non space character + 1 */ + for (; ptr < &dev->res[0x24] && *ptr;) { + if (*ptr != ' ') + xptr = optr + 1; + *optr++ = *ptr++; + } + *optr++ = 0; + *xptr = 0; + + DBG(1, "%s: found %s/%s\n", __func__, dev->sane.vendor, dev->sane.model); + dev->sane.type = strdup("multi-function peripheral"); + + dev->resolutions = dev->res[0x37] << 16 | + dev->res[0x24] << 8 | + dev->res[0x25]; + dev->compositions = dev->res[0x27]; + dev->max_win_width = dev->res[0x28] << 24 | + dev->res[0x29] << 16 | + dev->res[0x2a] << 8 | + dev->res[0x2b]; + dev->max_win_len = dev->res[0x2c] << 24 | + dev->res[0x2d] << 16 | + dev->res[0x2e] << 8 | + dev->res[0x2f]; + dev->max_len_adf = dev->res[0x38] << 24 | + dev->res[0x39] << 16 | + dev->res[0x3a] << 8 | + dev->res[0x3b]; + dev->max_len_fb = dev->res[0x3c] << 24 | + dev->res[0x3d] << 16 | + dev->res[0x3e] << 8 | + dev->res[0x3f]; + dev->line_order = dev->res[0x31]; + dev->compressionTypes = dev->res[0x32]; + dev->doc_loaded = (dev->res[0x35] == 0x02) && + (dev->res[0x26] & 0x03); + + init_options(dev); + reset_options(dev); + fix_window(dev); + set_parameters(dev); + resolv_inq_dpi(dev); + + return SANE_STATUS_GOOD; } const SANE_Option_Descriptor * -sane_get_option_descriptor (SANE_Handle h, SANE_Int opt) +sane_get_option_descriptor(SANE_Handle h, SANE_Int opt) { - struct device *dev = h; + struct device *dev = h; - DBG (3, "%s: %p, %d\n", __FUNCTION__, h, opt); - if (opt >= NUM_OPTIONS || opt < 0) - return NULL; - return &dev->opt[opt]; + DBG(3, "%s: %p, %d\n", __func__, h, opt); + if (opt >= NUM_OPTIONS || opt < 0) + return NULL; + return &dev->opt[opt]; } SANE_Status -sane_control_option (SANE_Handle h, SANE_Int opt, SANE_Action act, - void *val, SANE_Word * info) +sane_control_option(SANE_Handle h, SANE_Int opt, SANE_Action act, + void *val, SANE_Word *info) { - struct device *dev = h; - - DBG (3, "%s: %p, %d, <%d>, %p, %p\n", __FUNCTION__, h, opt, act, val, (void *)info); - if (!dev || opt >= NUM_OPTIONS || opt < 0) - return SANE_STATUS_INVAL; - - if (info) - *info = 0; - - if (act == SANE_ACTION_GET_VALUE) { /* GET */ - if (dev->opt[opt].type == SANE_TYPE_STRING) - strcpy(val, dev->val[opt].s); - else - *(SANE_Word *)val = dev->val[opt].w; - } else if (act == SANE_ACTION_SET_VALUE) { /* SET */ - SANE_Parameters xpara = dev->para; - SANE_Option_Descriptor xopt[NUM_OPTIONS]; - Option_Value xval[NUM_OPTIONS]; - int i; - - if (dev->opt[opt].constraint_type == SANE_CONSTRAINT_STRING_LIST) { - dev->val[opt].s = string_match(dev->opt[opt].constraint.string_list, val); - if (info && strcasecmp(dev->val[opt].s, val)) - *info |= SANE_INFO_INEXACT; - } else if (opt == OPT_RESOLUTION) - dev->val[opt].w = res_dpi_codes[dpi_to_code(*(SANE_Word *)val)]; - else - dev->val[opt].w = *(SANE_Word *)val; - - memcpy(&xopt, &dev->opt, sizeof(xopt)); - memcpy(&xval, &dev->val, sizeof(xval)); - fix_window(dev); - set_parameters(dev); - - /* check for side effects */ - if (info) { - if (memcmp(&xpara, &dev->para, sizeof(xpara))) - *info |= SANE_INFO_RELOAD_PARAMS; - if (memcmp(&xopt, &dev->opt, sizeof(xopt))) - *info |= SANE_INFO_RELOAD_OPTIONS; - for (i = 0; i < NUM_OPTIONS; i++) - if (xval[i].w != dev->val[i].w) { - if (i == opt) - *info |= SANE_INFO_INEXACT; - else - *info |= SANE_INFO_RELOAD_OPTIONS; - } + struct device *dev = h; + + DBG(3, "%s: %p, %d, <%d>, %p, %p\n", __func__, h, opt, act, val, (void *)info); + if (!dev || opt >= NUM_OPTIONS || opt < 0) + return SANE_STATUS_INVAL; + + if (info) + *info = 0; + + if (act == SANE_ACTION_GET_VALUE) { /* GET */ + if (dev->opt[opt].type == SANE_TYPE_STRING) + strcpy(val, dev->val[opt].s); + else + *(SANE_Word *)val = dev->val[opt].w; + } else if (act == SANE_ACTION_SET_VALUE) { /* SET */ + SANE_Parameters xpara = dev->para; + SANE_Option_Descriptor xopt[NUM_OPTIONS]; + Option_Value xval[NUM_OPTIONS]; + int i; + + if (dev->opt[opt].constraint_type == SANE_CONSTRAINT_STRING_LIST) { + dev->val[opt].s = string_match(dev->opt[opt].constraint.string_list, val); + if (info && strcasecmp(dev->val[opt].s, val)) + *info |= SANE_INFO_INEXACT; + } else if (opt == OPT_RESOLUTION) + dev->val[opt].w = res_dpi_codes[dpi_to_code(*(SANE_Word *)val)]; + else + dev->val[opt].w = *(SANE_Word *)val; + + memcpy(&xopt, &dev->opt, sizeof(xopt)); + memcpy(&xval, &dev->val, sizeof(xval)); + fix_window(dev); + set_parameters(dev); + + /* check for side effects */ + if (info) { + if (memcmp(&xpara, &dev->para, sizeof(xpara))) + *info |= SANE_INFO_RELOAD_PARAMS; + if (memcmp(&xopt, &dev->opt, sizeof(xopt))) + *info |= SANE_INFO_RELOAD_OPTIONS; + for (i = 0; i < NUM_OPTIONS; i++) + if (xval[i].w != dev->val[i].w) { + if (i == opt) + *info |= SANE_INFO_INEXACT; + else + *info |= SANE_INFO_RELOAD_OPTIONS; + } + } } - } - DBG (4, "%s: %d, <%d> => %08x, %x\n", __FUNCTION__, opt, act, - val? *(SANE_Word *)val : 0, info? *info : 0); - return SANE_STATUS_GOOD; + DBG(4, "%s: %d, <%d> => %08x, %x\n", __func__, opt, act, + val? *(SANE_Word *)val : 0, info? *info : 0); + return SANE_STATUS_GOOD; } static void -dev_free (struct device *dev) +dev_free(struct device *dev) { - if (!dev) - return; - - if (dev->sane.name) - free (UNCONST(dev->sane.name)); - if (dev->sane.vendor) - free (UNCONST(dev->sane.vendor)); - if (dev->sane.model) - free (UNCONST(dev->sane.model)); - if (dev->sane.type) - free (UNCONST(dev->sane.type)); - if (dev->data) - free(dev->data); - memset (dev, 0, sizeof (*dev)); - free (dev); + if (!dev) + return; + + if (dev->sane.name) + free(UNCONST(dev->sane.name)); + if (dev->sane.vendor) + free(UNCONST(dev->sane.vendor)); + if (dev->sane.model) + free(UNCONST(dev->sane.model)); + if (dev->sane.type) + free(UNCONST(dev->sane.type)); + if (dev->data) + free(dev->data); + if (dev->decData) { + free(dev->decData); + dev->decData = NULL; + } + memset(dev, 0, sizeof(*dev)); + free(dev); } static void -free_devices (void) +free_devices(void) { - int i; - struct device *next; - struct device *dev; - - if (devlist) { - free (devlist); - devlist = NULL; - } - for (i = 0, dev = devices_head; dev; dev = next) { - next = dev->next; - dev_free (dev); - } - devices_head = NULL; + struct device *next; + struct device *dev; + + if (devlist) { + free(devlist); + devlist = NULL; + } + for (dev = devices_head; dev; dev = next) { + next = dev->next; + dev_free(dev); + } + devices_head = NULL; } static transport *tr_from_devname(SANE_String_Const devname) { - if (strncmp("tcp", devname, 3) == 0) - return &available_transports[TRANSPORT_TCP]; - return &available_transports[TRANSPORT_USB]; + if (strncmp("tcp", devname, 3) == 0) + return &available_transports[TRANSPORT_TCP]; + return &available_transports[TRANSPORT_USB]; } static SANE_Status -list_one_device (SANE_String_Const devname) +list_one_device(SANE_String_Const devname) { - struct device *dev; - SANE_Status status; - transport *tr; - - DBG (4, "%s: %s\n", __FUNCTION__, devname); - - for (dev = devices_head; dev; dev = dev->next) { - if (strcmp (dev->sane.name, devname) == 0) - return SANE_STATUS_GOOD; - } - - tr = tr_from_devname(devname); - - dev = calloc (1, sizeof (struct device)); - if (dev == NULL) - return SANE_STATUS_NO_MEM; - - dev->sane.name = strdup (devname); - dev->io = tr; - status = tr->dev_open (dev); - if (status != SANE_STATUS_GOOD) { - dev_free (dev); - return status; - } - -/* status = dev_cmd (dev, CMD_ABORT);*/ - status = dev_inquiry (dev); - tr->dev_close (dev); - if (status != SANE_STATUS_GOOD) { - DBG (1, "%s: dev_inquiry(%s): %s\n", __FUNCTION__, - dev->sane.name, sane_strstatus (status)); - dev_free (dev); - return status; - } - - /* good device, add it to list */ - dev->next = devices_head; - devices_head = dev; - return SANE_STATUS_GOOD; + struct device *dev; + SANE_Status status; + transport *tr; + + DBG(4, "%s: %s\n", __func__, devname); + + for (dev = devices_head; dev; dev = dev->next) { + if (strcmp(dev->sane.name, devname) == 0) + return SANE_STATUS_GOOD; + } + + tr = tr_from_devname(devname); + + dev = calloc(1, sizeof(struct device)); + if (dev == NULL) + return SANE_STATUS_NO_MEM; + + dev->sane.name = strdup(devname); + dev->io = tr; + status = tr->dev_open(dev); + if (status != SANE_STATUS_GOOD) { + dev_free(dev); + return status; + } + + /* status = dev_cmd (dev, CMD_ABORT);*/ + status = dev_inquiry(dev); + tr->dev_close(dev); + if (status != SANE_STATUS_GOOD) { + DBG(1, "%s: dev_inquiry(%s): %s\n", __func__, + dev->sane.name, sane_strstatus(status)); + dev_free(dev); + return status; + } + + /* good device, add it to list */ + dev->next = devices_head; + devices_head = dev; + return SANE_STATUS_GOOD; } /* SANE API ignores return code of this callback */ static SANE_Status -list_conf_devices (UNUSED (SANEI_Config * config), const char *devname) +list_conf_devices(UNUSED(SANEI_Config *config), const char *devname) { - return tr_from_devname(devname)->configure_device(devname, list_one_device); + return tr_from_devname(devname)->configure_device(devname, list_one_device); } SANE_Status -sane_init (SANE_Int * version_code, SANE_Auth_Callback cb) +sane_init(SANE_Int *version_code, SANE_Auth_Callback cb) { - DBG_INIT (); - DBG (2, "sane_init: Xerox backend (build %d), version %s null, authorize %s null\n", BACKEND_BUILD, - (version_code) ? "!=" : "==", (cb) ? "!=" : "=="); + DBG_INIT(); + DBG(2, "sane_init: Xerox backend (build %d), version %s null, authorize %s null\n", BACKEND_BUILD, + (version_code) ? "!=" : "==", (cb) ? "!=" : "=="); - if (version_code) - *version_code = SANE_VERSION_CODE (V_MAJOR, V_MINOR, BACKEND_BUILD); + if (version_code) + *version_code = SANE_VERSION_CODE(V_MAJOR, V_MINOR, BACKEND_BUILD); - sanei_usb_init (); - return SANE_STATUS_GOOD; + sanei_usb_init(); + return SANE_STATUS_GOOD; } void -sane_exit (void) +sane_exit(void) { - struct device *dev; + struct device *dev; + + for (dev = devices_head; dev; dev = dev->next) + if (dev->dn != -1) + sane_close(dev); /* implies flush */ - for (dev = devices_head; dev; dev = dev->next) - if (dev->dn != -1) - sane_close(dev); /* implies flush */ - - free_devices (); + free_devices(); } SANE_Status -sane_get_devices (const SANE_Device *** device_list, SANE_Bool local) +sane_get_devices(const SANE_Device *** device_list, SANE_Bool local) { - SANEI_Config config; - struct device *dev; - int dev_count; - int i; + SANEI_Config config; + struct device *dev; + int dev_count; + int i; - DBG (3, "%s: %p, %d\n", __FUNCTION__, (const void *)device_list, local); + DBG(3, "%s: %p, %d\n", __func__, (const void *)device_list, local); - if (devlist) { - if (device_list) - *device_list = devlist; - return SANE_STATUS_GOOD; - } + if (devlist) { + if (device_list) + *device_list = devlist; + return SANE_STATUS_GOOD; + } - free_devices (); + free_devices(); - config.count = 0; - config.descriptors = NULL; - config.values = NULL; - sanei_configure_attach (XEROX_CONFIG_FILE, &config, list_conf_devices); + config.count = 0; + config.descriptors = NULL; + config.values = NULL; + sanei_configure_attach(XEROX_CONFIG_FILE, &config, list_conf_devices); - for (dev_count = 0, dev = devices_head; dev; dev = dev->next) - dev_count++; + for (dev_count = 0, dev = devices_head; dev; dev = dev->next) + dev_count++; - devlist = malloc ((dev_count + 1) * sizeof (*devlist)); - if (!devlist) - { - DBG (1, "%s: malloc: no memory\n", __FUNCTION__); - return SANE_STATUS_NO_MEM; + devlist = malloc((dev_count + 1) * sizeof(*devlist)); + if (!devlist) { + DBG(1, "%s: malloc: no memory\n", __func__); + return SANE_STATUS_NO_MEM; } - for (i = 0, dev = devices_head; dev; dev = dev->next) - devlist[i++] = &dev->sane; - devlist[i++] = NULL; + for (i = 0, dev = devices_head; dev; dev = dev->next) + devlist[i++] = &dev->sane; + devlist[i++] = NULL; - if (device_list) - *device_list = devlist; - return SANE_STATUS_GOOD; + if (device_list) + *device_list = devlist; + return SANE_STATUS_GOOD; } void -sane_close (SANE_Handle h) +sane_close(SANE_Handle h) { - struct device *dev = h; + struct device *dev = h; - if (!dev) - return; + if (!dev) + return; - DBG (3, "%s: %p (%s)\n", __FUNCTION__, (void *)dev, dev->sane.name); - dev->io->dev_close(dev); + DBG(3, "%s: %p (%s)\n", __func__, (void *)dev, dev->sane.name); + dev->io->dev_close(dev); } SANE_Status -sane_open (SANE_String_Const name, SANE_Handle * h) +sane_open(SANE_String_Const name, SANE_Handle *h) { - struct device *dev; - - DBG (3, "%s: '%s'\n", __FUNCTION__, name); - - if (!devlist) - sane_get_devices (NULL, SANE_TRUE); - - if (!name || !*name) { - /* special case of empty name: open first available device */ - for (dev = devices_head; dev; dev = dev->next) { - if (dev->dn != -1) { - if (sane_open (dev->sane.name, h) == SANE_STATUS_GOOD) - return SANE_STATUS_GOOD; - } + struct device *dev; + + DBG(3, "%s: '%s'\n", __func__, name); + + if (!devlist) + sane_get_devices(NULL, SANE_TRUE); + + if (!name || !*name) { + /* special case of empty name: open first available device */ + for (dev = devices_head; dev; dev = dev->next) { + if (dev->dn != -1) { + if (sane_open(dev->sane.name, h) == SANE_STATUS_GOOD) + return SANE_STATUS_GOOD; + } + } + } else { + for (dev = devices_head; dev; dev = dev->next) { + if (strcmp(name, dev->sane.name) == 0) { + *h = dev; + return dev->io->dev_open(dev); + } + } } - } else { - for (dev = devices_head; dev; dev = dev->next) { - if (strcmp(name, dev->sane.name) == 0) { - *h = dev; - return dev->io->dev_open(dev); - } - } - } - return SANE_STATUS_INVAL; + return SANE_STATUS_INVAL; } SANE_Status -sane_get_parameters (SANE_Handle h, SANE_Parameters * para) +sane_get_parameters(SANE_Handle h, SANE_Parameters *para) { - struct device *dev = h; + struct device *dev = h; - DBG (3, "%s: %p, %p\n", __FUNCTION__, h, (void *)para); - if (!para) - return SANE_STATUS_INVAL; + DBG(3, "%s: %p, %p\n", __func__, h, (void *)para); + if (!para) + return SANE_STATUS_INVAL; - *para = dev->para; - return SANE_STATUS_GOOD; + *para = dev->para; + return SANE_STATUS_GOOD; } /* check if image data is ready, and wait if not */ /* 1: image is acquired, 0: error or non_blocking mode */ static int dev_acquire(struct device *dev) { - if (!dev_cmd_wait(dev, CMD_READ)) - return dev->state; - - dev->state = SANE_STATUS_GOOD; - dev->vertical = dev->res[0x08] << 8 | dev->res[0x09]; - dev->horizontal = dev->res[0x0a] << 8 | dev->res[0x0b]; - dev->blocklen = dev->res[4] << 24 | - dev->res[5] << 16 | - dev->res[6] << 8 | - dev->res[7]; - dev->final_block = (dev->res[3] == MSG_END_BLOCK)? 1 : 0; - - dev->pixels_per_line = dev->horizontal; - dev->bytes_per_line = dev->horizontal; - - if (dev->composition == MODE_RGB24) - dev->bytes_per_line *= 3; - else if (dev->composition == MODE_LINEART || - dev->composition == MODE_HALFTONE) - dev->pixels_per_line *= 8; - - DBG (4, "acquiring, size per band v: %d, h: %d, %sblock: %d, slack: %d\n", - dev->vertical, dev->horizontal, dev->final_block? "last " : "", - dev->blocklen, dev->blocklen - (dev->vertical * dev->bytes_per_line)); - - if (dev->bytes_per_line > DATASIZE) { - DBG (1, "%s: unsupported line size: %d bytes > %d\n", - __FUNCTION__, dev->bytes_per_line, DATASIZE); - return ret_cancel(dev, SANE_STATUS_NO_MEM); - } - - dev->reading = 0; /* need to issue READ_IMAGE */ - - dev->dataindex = 0; - dev->datalen = 0; - dev->dataoff = 0; - - return 1; + if (!dev_cmd_wait(dev, CMD_READ)) + return dev->state; + + dev->state = SANE_STATUS_GOOD; + dev->vertical = dev->res[0x08] << 8 | dev->res[0x09]; + dev->horizontal = dev->res[0x0a] << 8 | dev->res[0x0b]; + dev->blocklen = dev->res[4] << 24 | + dev->res[5] << 16 | + dev->res[6] << 8 | + dev->res[7]; + dev->final_block = (dev->res[3] == MSG_END_BLOCK)? 1 : 0; + + dev->pixels_per_line = dev->horizontal; + dev->bytes_per_line = dev->horizontal; + + if (dev->composition == MODE_RGB24) + dev->bytes_per_line *= 3; + else if (dev->composition == MODE_LINEART || + dev->composition == MODE_HALFTONE) + dev->pixels_per_line *= 8; + + DBG(4, "acquiring, size per band v: %d, h: %d, %sblock: %d, slack: %d\n", + dev->vertical, dev->horizontal, dev->final_block? "last " : "", + dev->blocklen, dev->blocklen - (dev->vertical * dev->bytes_per_line)); + + if (dev->bytes_per_line > DATASIZE) { + DBG(1, "%s: unsupported line size: %d bytes > %d\n", + __func__, dev->bytes_per_line, DATASIZE); + return ret_cancel(dev, SANE_STATUS_NO_MEM); + } + + dev->reading = 0; /* need to issue READ_IMAGE */ + + dev->dataindex = 0; + dev->datalen = 0; + dev->dataoff = 0; + + return 1; } static int fill_slack(struct device *dev, SANE_Byte *buf, int maxlen) { - const int slack = dev->total_img_size - dev->total_out_size; - const int havelen = MIN(slack, maxlen); - int j; - - if (havelen <= 0) - return 0; - for (j = 0; j < havelen; j++) - buf[j] = 255; - return havelen; + const int slack = dev->total_img_size - dev->total_out_size; + const int havelen = MIN(slack, maxlen); + int j; + + if (havelen <= 0) + return 0; + for (j = 0; j < havelen; j++) + buf[j] = 255; + return havelen; } static int copy_plain_trim(struct device *dev, SANE_Byte *buf, int maxlen, int *olenp) { - int j; - const int linesize = dev->bytes_per_line; - int k = dev->dataindex; - *olenp = 0; - for (j = 0; j < dev->datalen && *olenp < maxlen; j++, k++) { - const int x = k % linesize; - const int y = k / linesize; - if (y >= dev->vertical) - break; /* slack */ - if (x < dev->para.bytes_per_line && - (y + dev->y_off) < dev->para.lines) { - *buf++ = dev->data[(dev->dataoff + j) & DATAMASK]; - (*olenp)++; + int j; + const int linesize = dev->bytes_per_line; + int k = dev->dataindex; + *olenp = 0; + for (j = 0; j < dev->datalen && *olenp < maxlen; j++, k++) { + const int x = k % linesize; + const int y = k / linesize; + if (y >= dev->vertical) + break; /* slack */ + if (x < dev->para.bytes_per_line && + (y + dev->y_off) < dev->para.lines) { + *buf++ = dev->data[(dev->dataoff + j) & DATAMASK]; + (*olenp)++; + } } - } - dev->dataindex = k; - return j; + dev->dataindex = k; + return j; } /* return: how much data could be freed from cyclic buffer */ /* convert from RRGGBB to RGBRGB */ -static int copy_mix_bands_trim(struct device *dev, SANE_Byte *buf, int maxlen, int *olenp) { - int j; +static int copy_mix_bands_trim(struct device *dev, SANE_Byte *buf, int maxlen, int *olenp) +{ + int j; - const int linesize = dev->bytes_per_line; /* caching real line size */ + const int linesize = dev->bytes_per_line; /* caching real line size */ - /* line number of the head of input buffer, - * input buffer is always aligned to whole line */ - const int y_off = dev->dataindex / linesize; + /* line number of the head of input buffer, + * input buffer is always aligned to whole line */ + const int y_off = dev->dataindex / linesize; - int k = dev->dataindex; /* caching current index of input buffer */ + int k = dev->dataindex; /* caching current index of input buffer */ - /* can only copy as much as full lines we have */ - int havelen = dev->datalen / linesize * linesize - k % linesize; + /* can only copy as much as full lines we have */ + int havelen = dev->datalen / linesize * linesize - k % linesize; - const int bands = 3; - *olenp = 0; + const int bands = 3; + *olenp = 0; - /* while we have data && they can receive */ - for (j = 0; j < havelen && *olenp < maxlen; j++, k++) { - const int band = (k % bands) * dev->horizontal; - const int x = k % linesize / bands; - const int y = k / linesize - y_off; /* y relative to buffer head */ - const int y_rly = y + y_off + dev->y_off; /* global y */ + /* while we have data && they can receive */ + for (j = 0; j < havelen && *olenp < maxlen; j++, k++) { + const int band = (k % bands) * dev->horizontal; + const int x = k % linesize / bands; + const int y = k / linesize - y_off; /* y relative to buffer head */ + const int y_rly = y + y_off + dev->y_off; /* global y */ - if (x < dev->para.pixels_per_line && - y_rly < dev->para.lines) { - *buf++ = dev->data[(dev->dataoff + band + x + y * linesize) & DATAMASK]; - (*olenp)++; + if (x < dev->para.pixels_per_line && + y_rly < dev->para.lines) { + *buf++ = dev->data[(dev->dataoff + band + x + y * linesize) & DATAMASK]; + (*olenp)++; + } } - } - dev->dataindex = k; + dev->dataindex = k; - /* how much full lines are finished */ - return (k / linesize - y_off) * linesize; + /* how much full lines are finished */ + return (k / linesize - y_off) * linesize; } SANE_Status -sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * lenp) +sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) { - SANE_Status status; - struct device *dev = h; + SANE_Status status; + struct device *dev = h; + + DBG(3, "%s: %p, %p, %d, %p\n", __func__, h, buf, maxlen, (void *)lenp); + + if (lenp) + *lenp = 0; + if (!dev) + return SANE_STATUS_INVAL; + + if (!dev->scanning) + return SANE_STATUS_EOF; + + /* if there is no data to read or output from buffer */ + if (!dev->blocklen && dev->datalen <= PADDING_SIZE) { + + /* copying uncompressed data */ + if (dev->composition == MODE_RGB24 && + isSupportedDevice(dev) && + dev->decDataSize > 0) { + int diff = dev->total_img_size - dev->total_out_size; + int bufLen = (diff < maxlen) ? diff : maxlen; + if (0 < diff && + 0 < copy_decompress_data(dev, buf, bufLen, lenp)) { + dev->total_out_size += *lenp; + return SANE_STATUS_GOOD; + } + } + + /* and we don't need to acquire next block */ + if (dev->final_block) { + int slack = dev->total_img_size - dev->total_out_size; + + /* but we may need to fill slack */ + if (buf && lenp && slack > 0) { + *lenp = fill_slack(dev, buf, maxlen); + dev->total_out_size += *lenp; + DBG(9, "<> slack: %d, filled: %d, maxlen %d\n", + slack, *lenp, maxlen); + return SANE_STATUS_GOOD; + } else if (slack < 0) { + /* this will never happen */ + DBG(1, "image overflow %d bytes\n", dev->total_img_size - dev->total_out_size); + } + if (isSupportedDevice(dev) && + dev->composition == MODE_RGB24) { + remove(encTmpFileName); + } + /* that's all */ + dev_stop(dev); + return SANE_STATUS_EOF; + } + + /* queue next image block */ + if (!dev_acquire(dev)) + return dev->state; + } + + if (!dev->reading) { + if (cancelled(dev)) + return dev->state; + DBG(5, "READ_IMAGE\n"); + if (!dev_cmd(dev, CMD_READ_IMAGE)) + return SANE_STATUS_IO_ERROR; + dev->reading++; + dev->ulines += dev->vertical; + dev->y_off = dev->ulines - dev->vertical; + dev->total_data_size += dev->blocklen; + dev->blocks++; + } - DBG (3, "%s: %p, %p, %d, %p\n", __FUNCTION__, h, buf, maxlen, (void *)lenp); + do { + size_t datalen; + int clrlen; /* cleared lines len */ + int olen; /* output len */ + + /* read as much data into the buffer */ + datalen = DATAROOM(dev) & USB_BLOCK_MASK; + while (datalen && dev->blocklen) { + SANE_Byte *rbuf = dev->data + DATATAIL(dev); + + DBG(9, "<> request len: %lu, [%d, %d; %d]\n", + (u_long)datalen, dev->dataoff, DATATAIL(dev), dev->datalen); + if ((status = dev->io->dev_request(dev, NULL, 0, rbuf, &datalen)) != + SANE_STATUS_GOOD) + return status; + dev->datalen += datalen; + dev->blocklen -= datalen; + DBG(9, "<> got %lu, [%d, %d; %d]\n", + (u_long)datalen, dev->dataoff, DATATAIL(dev), dev->datalen); + if (dev->blocklen < 0) + return ret_cancel(dev, SANE_STATUS_IO_ERROR); + + datalen = DATAROOM(dev) & USB_BLOCK_MASK; + } + + if (buf && lenp) { /* read mode */ + /* copy will do minimal of valid data */ + if (dev->para.format == SANE_FRAME_RGB && dev->line_order) { + if (isSupportedDevice(dev)) { + clrlen = dump_to_tmp_file(dev); + /* decompress after reading entire block data*/ + if (0 == dev->blocklen) { + decompress_tempfile(dev); + } + copy_decompress_data(dev, buf, maxlen, &olen); + } else { + clrlen = copy_mix_bands_trim(dev, buf, maxlen, &olen); + } + } else + clrlen = copy_plain_trim(dev, buf, maxlen, &olen); + + dev->datalen -= clrlen; + dev->dataoff = (dev->dataoff + clrlen) & DATAMASK; + buf += olen; + maxlen -= olen; + *lenp += olen; + dev->total_out_size += olen; + + DBG(9, "<> olen: %d, clrlen: %d, blocklen: %d/%d, maxlen %d (%d %d %d)\n", + olen, clrlen, dev->blocklen, dev->datalen, maxlen, + dev->dataindex / dev->bytes_per_line + dev->y_off, + dev->y_off, dev->para.lines); + + /* slack beyond last line */ + if (dev->dataindex / dev->bytes_per_line + dev->y_off >= dev->para.lines) { + dev->datalen = 0; + dev->dataoff = 0; + } + + if (!clrlen || maxlen <= 0) + break; + } else { /* flush mode */ + dev->datalen = 0; + dev->dataoff = 0; + } + + } while (dev->blocklen); + + if (lenp) + DBG(9, " ==> %d\n", *lenp); - if (lenp) - *lenp = 0; - if (!dev) - return SANE_STATUS_INVAL; + return SANE_STATUS_GOOD; +} - if (!dev->scanning) - return SANE_STATUS_EOF; - - /* if there is no data to read or output from buffer */ - if (!dev->blocklen && dev->datalen <= PADDING_SIZE) { - - /* and we don't need to acquire next block */ - if (dev->final_block) { - int slack = dev->total_img_size - dev->total_out_size; - - /* but we may need to fill slack */ - if (buf && lenp && slack > 0) { - *lenp = fill_slack(dev, buf, maxlen); - dev->total_out_size += *lenp; - DBG (9, "<> slack: %d, filled: %d, maxlen %d\n", - slack, *lenp, maxlen); - return SANE_STATUS_GOOD; - } else if (slack < 0) { - /* this will never happen */ - DBG(1, "image overflow %d bytes\n", dev->total_img_size - dev->total_out_size); - } - - /* that's all */ - dev_stop(dev); - return SANE_STATUS_EOF; +SANE_Status +sane_start(SANE_Handle h) +{ + struct device *dev = h; + + DBG(3, "%s: %p\n", __func__, h); + + dev->cancel = 0; + dev->scanning = 0; + dev->total_img_size = 0; + dev->total_out_size = 0; + dev->total_data_size = 0; + dev->blocks = 0; + + if (!dev->reserved) { + if (!dev_cmd_wait(dev, CMD_RESERVE_UNIT)) + return dev->state; + dev->reserved++; } - /* queue next image block */ + if (!dev_set_window(dev) || + (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) + return dev_stop(dev); + + if (!dev_cmd_wait(dev, CMD_OBJECT_POSITION)) + return dev_stop(dev); + + if (!dev_cmd(dev, CMD_READ) || + (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) + return dev_stop(dev); + + dev->scanning = 1; + dev->final_block = 0; + dev->blocklen = 0; + dev->pixels_per_line = 0; + dev->bytes_per_line = 0; + dev->ulines = 0; + + set_parameters(dev); + + if (!dev->data && !(dev->data = malloc(DATASIZE))) + return ret_cancel(dev, SANE_STATUS_NO_MEM); + + if (!dev->decData && !(dev->decData = malloc(POST_DATASIZE))) + return ret_cancel(dev, SANE_STATUS_NO_MEM); + if (!dev_acquire(dev)) - return dev->state; - } - - if (!dev->reading) { - if (cancelled(dev)) - return dev->state; - DBG (5, "READ_IMAGE\n"); - if (!dev_cmd(dev, CMD_READ_IMAGE)) - return SANE_STATUS_IO_ERROR; - dev->reading++; - dev->ulines += dev->vertical; - dev->y_off = dev->ulines - dev->vertical; - dev->total_data_size += dev->blocklen; - dev->blocks++; - } - - do { - size_t datalen; - int clrlen; /* cleared lines len */ - int olen; /* output len */ - - /* read as much data into the buffer */ - datalen = DATAROOM(dev) & USB_BLOCK_MASK; - while (datalen && dev->blocklen) { - SANE_Byte *rbuf = dev->data + DATATAIL(dev); - - DBG (9, "<> request len: %lu, [%d, %d; %d]\n", - (u_long)datalen, dev->dataoff, DATATAIL(dev), dev->datalen); - if ((status = dev->io->dev_request(dev, NULL, 0, rbuf, &datalen)) != - SANE_STATUS_GOOD) - return status; - dev->datalen += datalen; - dev->blocklen -= datalen; - DBG (9, "<> got %lu, [%d, %d; %d]\n", - (u_long)datalen, dev->dataoff, DATATAIL(dev), dev->datalen); - if (dev->blocklen < 0) - return ret_cancel(dev, SANE_STATUS_IO_ERROR); - - datalen = DATAROOM(dev) & USB_BLOCK_MASK; - } + return dev->state; - if (buf && lenp) { /* read mode */ - /* copy will do minimal of valid data */ - if (dev->para.format == SANE_FRAME_RGB && dev->line_order) - clrlen = copy_mix_bands_trim(dev, buf, maxlen, &olen); - else - clrlen = copy_plain_trim(dev, buf, maxlen, &olen); - - dev->datalen -= clrlen; - dev->dataoff = (dev->dataoff + clrlen) & DATAMASK; - buf += olen; - maxlen -= olen; - *lenp += olen; - dev->total_out_size += olen; - - DBG (9, "<> olen: %d, clrlen: %d, blocklen: %d/%d, maxlen %d (%d %d %d)\n", - olen, clrlen, dev->blocklen, dev->datalen, maxlen, - dev->dataindex / dev->bytes_per_line + dev->y_off, - dev->y_off, dev->para.lines); - - /* slack beyond last line */ - if (dev->dataindex / dev->bytes_per_line + dev->y_off >= dev->para.lines) { - dev->datalen = 0; - dev->dataoff = 0; - } - - if (!clrlen || maxlen <= 0) - break; - } else { /* flush mode */ - dev->datalen = 0; - dev->dataoff = 0; + /* make sure to have dev->para <= of real size */ + if (dev->para.pixels_per_line > dev->pixels_per_line) { + dev->para.pixels_per_line = dev->pixels_per_line; + dev->para.bytes_per_line = dev->pixels_per_line; } - } while (dev->blocklen); - - if (lenp) - DBG (9, " ==> %d\n", *lenp); + if (dev->composition == MODE_RGB24) + dev->para.bytes_per_line = dev->para.pixels_per_line * 3; + else if (dev->composition == MODE_LINEART || + dev->composition == MODE_HALFTONE) { + dev->para.bytes_per_line = (dev->para.pixels_per_line + 7) / 8; + dev->para.pixels_per_line = dev->para.bytes_per_line * 8; + } else { + dev->para.bytes_per_line = dev->para.pixels_per_line; + } - return SANE_STATUS_GOOD; -} + dev->total_img_size = dev->para.bytes_per_line * dev->para.lines; -SANE_Status -sane_start (SANE_Handle h) -{ - struct device *dev = h; - - DBG (3, "%s: %p\n", __FUNCTION__, h); - - dev->cancel = 0; - dev->scanning = 0; - dev->total_img_size = 0; - dev->total_out_size = 0; - dev->total_data_size = 0; - dev->blocks = 0; - - if (!dev->reserved) { - if (!dev_cmd_wait(dev, CMD_RESERVE_UNIT)) - return dev->state; - dev->reserved++; - } - - if (!dev_set_window(dev) || - (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) - return dev_stop(dev); - - if (!dev_cmd_wait(dev, CMD_OBJECT_POSITION)) - return dev_stop(dev); - - if (!dev_cmd(dev, CMD_READ) || - (dev->state && dev->state != SANE_STATUS_DEVICE_BUSY)) - return dev_stop(dev); - - dev->scanning = 1; - dev->final_block = 0; - dev->blocklen = 0; - dev->pixels_per_line = 0; - dev->bytes_per_line = 0; - dev->ulines = 0; - - set_parameters(dev); - - if (!dev->data && !(dev->data = malloc(DATASIZE))) - return ret_cancel(dev, SANE_STATUS_NO_MEM); - - if (!dev_acquire(dev)) - return dev->state; - - /* make sure to have dev->para <= of real size */ - if (dev->para.pixels_per_line > dev->pixels_per_line) { - dev->para.pixels_per_line = dev->pixels_per_line; - dev->para.bytes_per_line = dev->pixels_per_line; - } - - if (dev->composition == MODE_RGB24) - dev->para.bytes_per_line = dev->para.pixels_per_line * 3; - else if (dev->composition == MODE_LINEART || - dev->composition == MODE_HALFTONE) { - dev->para.bytes_per_line = (dev->para.pixels_per_line + 7) / 8; - dev->para.pixels_per_line = dev->para.bytes_per_line * 8; - } else { - dev->para.bytes_per_line = dev->para.pixels_per_line; - } + if (isSupportedDevice(dev) && + dev->composition == MODE_RGB24) { + int fd; + remove(encTmpFileName); - dev->total_img_size = dev->para.bytes_per_line * dev->para.lines; + /* Precreate temporary file in exclusive mode. */ + fd = open(encTmpFileName, O_CREAT|O_EXCL, 0600); + if (fd == -1) { + DBG(3, "%s: %p, can't create temporary file %s: %s\n", __func__, + (void *)dev, encTmpFileName, strerror(errno)); + return ret_cancel(dev, SANE_STATUS_ACCESS_DENIED); + } + close(fd); + } + dev->currentDecDataIndex = 0; - return SANE_STATUS_GOOD; + return SANE_STATUS_GOOD; } -SANE_Status sane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking) +SANE_Status sane_set_io_mode(SANE_Handle h, SANE_Bool non_blocking) { - struct device *dev = h; + struct device *dev = h; - DBG (3, "%s: %p, %d\n", __FUNCTION__, h, non_blocking); + DBG(3, "%s: %p, %d\n", __func__, h, non_blocking); - if (non_blocking) - return SANE_STATUS_UNSUPPORTED; + if (non_blocking) + return SANE_STATUS_UNSUPPORTED; - dev->non_blocking = non_blocking; - return SANE_STATUS_GOOD; + dev->non_blocking = non_blocking; + return SANE_STATUS_GOOD; } -SANE_Status sane_get_select_fd (SANE_Handle h, SANE_Int * fdp) +SANE_Status sane_get_select_fd(SANE_Handle h, SANE_Int *fdp) { - DBG (3, "%s: %p, %p\n", __FUNCTION__, h, (void *)fdp); - /* supporting of this will require thread creation */ - return SANE_STATUS_UNSUPPORTED; + DBG(3, "%s: %p, %p\n", __func__, h, (void *)fdp); + /* supporting of this will require thread creation */ + return SANE_STATUS_UNSUPPORTED; } -void sane_cancel (SANE_Handle h) +void sane_cancel(SANE_Handle h) { - struct device *dev = h; + struct device *dev = h; - DBG (3, "%s: %p\n", __FUNCTION__, h); - dev->cancel = 1; + DBG(3, "%s: %p\n", __func__, h); + dev->cancel = 1; } /* xerox_mfp.c */ diff --git a/backend/xerox_mfp.conf.in b/backend/xerox_mfp.conf.in index e0f78ea..b17c7d7 100644 --- a/backend/xerox_mfp.conf.in +++ b/backend/xerox_mfp.conf.in @@ -5,6 +5,24 @@ ### Samsung Models ### ###################### +#Samsung X4300 Series +usb 0x04e8 0x3324 + +#Samsung K4350 Series +usb 0x04e8 0x3325 + +#Samsung X7600 Series +usb 0x04e8 0x3326 + +#Samsung K7600 Series +usb 0x04e8 0x3327 + +#Samsung K703 Series +usb 0x04e8 0x3331 + +#Samsung X703 Series +usb 0x04e8 0x3332 + #Samsung SCX-4x16 Series usb 0x04e8 0x3409 @@ -178,6 +196,24 @@ usb 0x04e8 0x3466 #Samsung C460 Series usb 0x04e8 0x3468 +#Samsung M458x Series +usb 0x04e8 0x346f + +#Samsung M4370 5370 Series +usb 0x04e8 0x3471 + +#Samsung X401 Series +usb 0x04e8 0x3477 + +#Samsung K401 Series +usb 0x04e8 0x3478 + +#Samsung K3250 Series +usb 0x04e8 0x3481 + +#Samsung X3220 Series +usb 0x04e8 0x3482 + #################### ### Xerox Models ### #################### diff --git a/backend/xerox_mfp.h b/backend/xerox_mfp.h index 500dd26..3d93f06 100644 --- a/backend/xerox_mfp.h +++ b/backend/xerox_mfp.h @@ -1,9 +1,12 @@ /* - * SANE backend for Xerox Phaser 3200MFP - * Copyright 2008 ABC + * SANE backend for Xerox Phaser 3200MFP et al. + * Copyright 2008-2016 ABC * - * Network scanners support - * Copyright 2010 Alexander Kuznetsov + * Network Scanners Support + * Copyright 2010 Alexander Kuznetsov + * + * Color scanning on Samsung M2870 model and Xerox Cognac 3215 & 3225 + * models by Laxmeesh Onkar Markod * * This program is licensed under GPL + SANE exception. * More info at http://www.sane-project.org/license.html @@ -29,130 +32,136 @@ #define SWAP_Word(x, y) { SANE_Word z = x; x = y; y = z; } enum options { - OPT_NUMOPTIONS, - OPT_GROUP_STD, - OPT_RESOLUTION, /* dpi*/ - OPT_MODE, /* color */ - OPT_THRESHOLD, /* brightness */ - OPT_SOURCE, /* affects max window size */ - OPT_GROUP_GEO, - OPT_SCAN_TL_X, /* for (OPT_SCAN_TL_X to OPT_SCAN_BR_Y) */ - OPT_SCAN_TL_Y, - OPT_SCAN_BR_X, - OPT_SCAN_BR_Y, - NUM_OPTIONS + OPT_NUMOPTIONS, + OPT_GROUP_STD, + OPT_RESOLUTION, /* dpi*/ + OPT_MODE, /* color */ + OPT_THRESHOLD, /* brightness */ + OPT_SOURCE, /* affects max window size */ + OPT_GROUP_GEO, + OPT_SCAN_TL_X, /* for (OPT_SCAN_TL_X to OPT_SCAN_BR_Y) */ + OPT_SCAN_TL_Y, + OPT_SCAN_BR_X, + OPT_SCAN_BR_Y, + NUM_OPTIONS }; typedef struct transport transport; struct device { - struct device *next; - SANE_Device sane; - int dn; /* usb file descriptor */ - SANE_Byte res[1024]; /* buffer for responses */ - size_t reslen; /* response len */ - SANE_Option_Descriptor opt[NUM_OPTIONS]; - Option_Value val[NUM_OPTIONS]; - SANE_Parameters para; - SANE_Bool non_blocking; - int scanning; /* scanning is started */ - int cancel; /* cancel flag */ - int state; /* current state */ - int reserved; /* CMD_RESERVE_UNIT */ - int reading; /* READ_IMAGE is sent */ - - SANE_Byte *data; /* postprocessing cyclic buffer 64k */ - int datalen; /* how data in buffer */ - int dataoff; /* offset of data */ - int dataindex; /* sequental number */ + struct device *next; + SANE_Device sane; + int dn; /* usb file descriptor */ + SANE_Byte res[1024]; /* buffer for responses */ + size_t reslen; /* response len */ + SANE_Option_Descriptor opt[NUM_OPTIONS]; + Option_Value val[NUM_OPTIONS]; + SANE_Parameters para; + SANE_Bool non_blocking; + int scanning; /* scanning is started */ + int cancel; /* cancel flag */ + int state; /* current state */ + int reserved; /* CMD_RESERVE_UNIT */ + int reading; /* READ_IMAGE is sent */ + + SANE_Byte *data; /* postprocessing cyclic buffer 64k */ + int datalen; /* how data in buffer */ + int dataoff; /* offset of data */ + int dataindex; /* sequental number */ #define DATAMASK 0xffff /* mask of data buffer */ #define DATASIZE (DATAMASK + 1) /* size of data buffer */ - /* 64K will be enough to hold whole line of 2400 dpi of 23cm */ + /* 64K will be enough to hold whole line of 2400 dpi of 23cm */ #define DATATAIL(dev) ((dev->dataoff + dev->datalen) & DATAMASK) #define DATAROOM(dev) dataroom(dev) - /* data from CMD_INQUIRY: */ - int resolutions; /* supported resolution bitmask */ - int compositions; /* supported image compositions bitmask */ - int max_len; /* effective max len for current doc source */ - int max_win_width; - int max_win_len; - int max_len_adf; - int max_len_fb; - int line_order; /* if need post processing */ - SANE_Word dpi_list[30]; /* allowed resolutions */ - int doc_loaded; - - SANE_Range win_x_range; - SANE_Range win_y_range; - - /* CMD_SET_WINDOW parameters we set: */ - int win_width; /* in 1200dpi points */ - int win_len; - double win_off_x; /* in inches (byte.byte) */ - double win_off_y; - int resolution; /* dpi indexed values */ - int composition; /* MODE_ */ - int doc_source; /* document source */ - int threshold; /* brightness */ - - /* CMD_READ data. It is per block only, image could be in many blocks */ - int blocklen; /* image data block len (padding incl.) */ - int vertical; /* lines in block (padded) */ - int horizontal; /* b/w: bytes, gray/color: pixels (padded) */ - int final_block; - int pixels_per_line; - int bytes_per_line; - int ulines; /* up to this block including */ - int y_off; /* up to this block excluding*/ - int blocks; - - /* stat */ - int total_img_size; /* predicted image size */ - int total_out_size; /* total we sent to user */ - int total_data_size; /* total of what scanner sent us */ - - /* transport to use */ - transport *io; +#define POST_DATASIZE 0xFFFFFF + SANE_Byte *decData; + int decDataSize; + int currentDecDataIndex; + /* data from CMD_INQUIRY: */ + int resolutions; /* supported resolution bitmask */ + int compositions; /* supported image compositions bitmask */ + int max_len; /* effective max len for current doc source */ + int max_win_width; + int max_win_len; + int max_len_adf; + int max_len_fb; + int line_order; /* if need post processing */ + SANE_Word dpi_list[30]; /* allowed resolutions */ + int doc_loaded; + + SANE_Range win_x_range; + SANE_Range win_y_range; + + /* CMD_SET_WINDOW parameters we set: */ + int win_width; /* in 1200dpi points */ + int win_len; + double win_off_x; /* in inches (byte.byte) */ + double win_off_y; + int resolution; /* dpi indexed values */ + int composition; /* MODE_ */ + int doc_source; /* document source */ + int threshold; /* brightness */ + int compressionTypes; + + /* CMD_READ data. It is per block only, image could be in many blocks */ + int blocklen; /* image data block len (padding incl.) */ + int vertical; /* lines in block (padded) */ + int horizontal; /* b/w: bytes, gray/color: pixels (padded) */ + int final_block; + int pixels_per_line; + int bytes_per_line; + int ulines; /* up to this block including */ + int y_off; /* up to this block excluding*/ + int blocks; + + /* stat */ + int total_img_size; /* predicted image size */ + int total_out_size; /* total we sent to user */ + int total_data_size; /* total of what scanner sent us */ + + /* transport to use */ + transport *io; }; /* Transport abstract layer */ struct transport { - char* ttype; - - int (*dev_request) (struct device *dev, - SANE_Byte *cmd, size_t cmdlen, - SANE_Byte *resp, size_t *resplen); - SANE_Status (*dev_open) (struct device *dev); - void (*dev_close) (struct device *dev); - SANE_Status (*configure_device) (const char *devname, SANE_Status (*cb)(SANE_String_Const devname)); + char *ttype; + + int (*dev_request)(struct device *dev, + SANE_Byte *cmd, size_t cmdlen, + SANE_Byte *resp, size_t *resplen); + SANE_Status(*dev_open)(struct device *dev); + void (*dev_close)(struct device *dev); + SANE_Status(*configure_device)(const char *devname, SANE_Status(*cb)(SANE_String_Const devname)); }; /* USB transport */ -int usb_dev_request (struct device *dev, SANE_Byte *cmd, size_t cmdlen, SANE_Byte *resp, size_t *resplen); -SANE_Status usb_dev_open (struct device *dev); -void usb_dev_close (struct device *dev); -SANE_Status usb_configure_device (const char *devname, SANE_Status (*cb)(SANE_String_Const devname)); +int usb_dev_request(struct device *dev, SANE_Byte *cmd, size_t cmdlen, SANE_Byte *resp, size_t *resplen); +SANE_Status usb_dev_open(struct device *dev); +void usb_dev_close(struct device *dev); +SANE_Status usb_configure_device(const char *devname, SANE_Status(*cb)(SANE_String_Const devname)); /* TCP unicast */ -int tcp_dev_request (struct device *dev, SANE_Byte *cmd, size_t cmdlen, SANE_Byte *resp, size_t *resplen); -SANE_Status tcp_dev_open (struct device *dev); -void tcp_dev_close (struct device *dev); -SANE_Status tcp_configure_device (const char *devname, SANE_Status (*cb)(SANE_String_Const devname)); +int tcp_dev_request(struct device *dev, SANE_Byte *cmd, size_t cmdlen, SANE_Byte *resp, size_t *resplen); +SANE_Status tcp_dev_open(struct device *dev); +void tcp_dev_close(struct device *dev); +SANE_Status tcp_configure_device(const char *devname, SANE_Status(*cb)(SANE_String_Const devname)); /* device wants transfer buffer to be multiple of 512 */ #define USB_BLOCK_SIZE 512 #define USB_BLOCK_MASK ~(USB_BLOCK_SIZE - 1) -static inline int dataroom(struct device *dev) { - int tail = DATATAIL(dev); - if (tail < dev->dataoff) - return dev->dataoff - tail; - else if (dev->datalen == DATASIZE) { - return 0; - } else - return DATASIZE - tail; +static inline int dataroom(struct device *dev) +{ + int tail = DATATAIL(dev); + if (tail < dev->dataoff) + return dev->dataoff - tail; + else if (dev->datalen == DATASIZE) { + return 0; + } else + return DATASIZE - tail; } /* Functions from original xerox_mfp.c, used in -usb.c and -tcp.c */ -- cgit v1.2.3 From 1687222e1b9e74c89cafbb5910e72d8ec7bfd40f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Wed, 31 Jul 2019 16:59:49 +0200 Subject: New upstream version 1.0.28 --- backend/.gitignore | 5 + backend/Makefile.am | 110 +- backend/Makefile.in | 5644 ------------------------ backend/abaton.c | 42 +- backend/abaton.h | 8 +- backend/agfafocus.c | 128 +- backend/agfafocus.conf.in | 1 - backend/agfafocus.h | 4 +- backend/apple.c | 26 +- backend/apple.h | 8 +- backend/artec.c | 2 +- backend/artec.conf.in | 1 - backend/artec_eplus48u.c | 4 +- backend/artec_eplus48u.conf.in | 1 - backend/as6e.c | 30 +- backend/avision.c | 2110 ++++----- backend/avision.conf.in | 1 - backend/avision.h | 130 +- backend/bh.c | 333 +- backend/bh.h | 50 +- backend/canon-sane.c | 2 +- backend/canon-scsi.c | 2 +- backend/canon.c | 9 +- backend/canon630u-common.c | 42 +- backend/canon630u.c | 4 +- backend/canon_dr-cmd.h | 16 +- backend/canon_dr.c | 743 ++-- backend/canon_dr.conf.in | 2 +- backend/canon_dr.h | 15 +- backend/canon_pp-dev.c | 302 +- backend/canon_pp-dev.h | 12 +- backend/canon_pp-io.c | 90 +- backend/canon_pp-io.h | 8 +- backend/canon_pp.c | 288 +- backend/canon_pp.conf.in | 4 +- backend/canon_pp.h | 5 +- backend/cardscan.c | 334 +- backend/cardscan.h | 12 +- backend/coolscan-scsidef.h | 16 +- backend/coolscan.c | 390 +- backend/coolscan.h | 20 +- backend/coolscan2.c | 4 +- backend/coolscan3.c | 2 +- backend/dc210.c | 20 +- backend/dc210.conf.in | 2 +- backend/dc210.h | 8 +- backend/dc240.c | 38 +- backend/dc240.conf.in | 2 +- backend/dc240.h | 16 +- backend/dc25.c | 62 +- backend/dc25.conf.in | 2 +- backend/dc25.h | 14 +- backend/dell1600n_net.c | 50 +- backend/dell1600n_net.conf.in | 2 - backend/dll.c | 41 +- backend/dll.conf.in | 1 + backend/dmc.c | 22 +- backend/epjitsu-cmd.h | 1 - backend/epjitsu.c | 429 +- backend/epjitsu.conf.in | 3 +- backend/epjitsu.h | 6 +- backend/epson.c | 362 +- backend/epson.conf.in | 2 +- backend/epson2-commands.c | 8 +- backend/epson2-ops.c | 8 +- backend/epson2.c | 35 +- backend/epson2.conf.in | 3 +- backend/epson2_net.c | 4 +- backend/epson2_usb.c | 7 +- backend/epson_usb.c | 2 +- backend/epsonds-cmd.h | 1 - backend/epsonds-io.c | 2 - backend/epsonds-io.h | 1 - backend/epsonds-jpeg.c | 2 - backend/epsonds-ops.c | 2 - backend/epsonds-ops.h | 1 - backend/epsonds.c | 6 + backend/fujitsu-scsi.h | 27 +- backend/fujitsu.c | 1316 +++--- backend/fujitsu.conf.in | 16 - backend/fujitsu.h | 24 +- backend/genesys.c | 8047 ---------------------------------- backend/genesys.cc | 7580 ++++++++++++++++++++++++++++++++ backend/genesys.conf.in | 3 + backend/genesys.h | 125 +- backend/genesys_conv.c | 478 -- backend/genesys_conv.cc | 474 ++ backend/genesys_conv_hlp.c | 345 -- backend/genesys_conv_hlp.cc | 345 ++ backend/genesys_devices.c | 3706 ---------------- backend/genesys_devices.cc | 5165 ++++++++++++++++++++++ backend/genesys_error.cc | 115 + backend/genesys_error.h | 202 + backend/genesys_gl124.c | 3997 ----------------- backend/genesys_gl124.cc | 3592 +++++++++++++++ backend/genesys_gl124.h | 289 +- backend/genesys_gl646.c | 5799 ------------------------ backend/genesys_gl646.cc | 4911 +++++++++++++++++++++ backend/genesys_gl646.h | 428 +- backend/genesys_gl841.c | 6383 --------------------------- backend/genesys_gl841.cc | 5624 ++++++++++++++++++++++++ backend/genesys_gl841.h | 199 +- backend/genesys_gl843.c | 4477 ------------------- backend/genesys_gl843.cc | 4415 +++++++++++++++++++ backend/genesys_gl843.h | 288 +- backend/genesys_gl846.c | 3711 ---------------- backend/genesys_gl846.cc | 3393 ++++++++++++++ backend/genesys_gl846.h | 231 +- backend/genesys_gl847.c | 3824 ---------------- backend/genesys_gl847.cc | 3517 +++++++++++++++ backend/genesys_gl847.h | 201 +- backend/genesys_low.c | 2010 --------- backend/genesys_low.cc | 2059 +++++++++ backend/genesys_low.h | 1901 +++++--- backend/genesys_sanei.cc | 140 + backend/genesys_sanei.h | 97 + backend/genesys_serialize.cc | 0 backend/genesys_serialize.h | 144 + backend/gphoto2.c | 94 +- backend/gphoto2.conf.in | 16 +- backend/gphoto2.h | 4 +- backend/gt68xx.c | 43 +- backend/gt68xx.conf.in | 21 +- backend/gt68xx.h | 20 +- backend/gt68xx_devices.c | 71 +- backend/gt68xx_generic.c | 30 +- backend/gt68xx_generic.h | 20 +- backend/gt68xx_gt6801.c | 22 +- backend/gt68xx_gt6801.h | 20 +- backend/gt68xx_gt6816.c | 20 +- backend/gt68xx_gt6816.h | 20 +- backend/gt68xx_high.c | 43 +- backend/gt68xx_high.h | 24 +- backend/gt68xx_low.c | 22 +- backend/gt68xx_low.h | 39 +- backend/gt68xx_mid.c | 20 +- backend/gt68xx_mid.h | 20 +- backend/gt68xx_shm_channel.c | 20 +- backend/gt68xx_shm_channel.h | 20 +- backend/hp-device.c | 1 - backend/hp-handle.c | 18 +- backend/hp-option.c | 21 +- backend/hp-scl.c | 2 +- backend/hp.README | 2 +- backend/hp.c | 2 +- backend/hp3500.c | 48 +- backend/hp3900.conf.in | 1 - backend/hp3900_config.c | 4 +- backend/hp3900_debug.c | 2 +- backend/hp3900_rts8822.c | 24 +- backend/hp4200.c | 18 +- backend/hp4200.h | 6 +- backend/hp5400.c | 10 +- backend/hp5400_debug.c | 2 - backend/hp5400_internal.c | 10 +- backend/hp5400_sanei.c | 5 +- backend/hp5400_xfer.h | 2 +- backend/hp5590.c | 2150 +++++++-- backend/hp5590_cmds.c | 1286 +++--- backend/hp5590_cmds.h | 132 +- backend/hp5590_low.c | 656 +-- backend/hp5590_low.h | 50 +- backend/hpljm1005.c | 19 +- backend/hpsj5s.c | 18 +- backend/hpsj5s.conf.in | 2 +- backend/hs2p-saneopts.h | 4 +- backend/hs2p-scsi.c | 20 +- backend/hs2p-scsi.h | 106 +- backend/hs2p.c | 50 +- backend/hs2p.h | 8 +- backend/ibm-scsi.c | 12 +- backend/ibm.c | 66 +- backend/ibm.h | 10 +- backend/kodak-cmd.h | 20 +- backend/kodak.c | 210 +- backend/kodak.h | 4 +- backend/kodakaio.c | 150 +- backend/kodakaio.conf.in | 3 +- backend/kvs1025_low.c | 18 +- backend/kvs1025_opt.c | 1 - backend/kvs1025_usb.c | 2 +- backend/kvs20xx_opt.c | 2 +- backend/kvs40xx_opt.c | 2 +- backend/leo.c | 28 +- backend/leo.conf.in | 1 - backend/leo.h | 10 +- backend/lexmark.c | 16 +- backend/lexmark.h | 2 +- backend/lexmark_low.c | 72 +- backend/lexmark_models.c | 2 +- backend/lexmark_sensors.c | 2 +- backend/magicolor.c | 9 +- backend/magicolor.conf.in | 1 - backend/matsushita.c | 40 +- backend/matsushita.conf.in | 2 +- backend/matsushita.h | 8 +- backend/microtek.c | 494 +-- backend/microtek.h | 39 +- backend/microtek2.c | 108 +- backend/microtek2.h | 20 +- backend/mustek.c | 56 +- backend/mustek.conf.in | 6 +- backend/mustek.h | 6 +- backend/mustek_pp.c | 120 +- backend/mustek_pp.conf.in | 12 +- backend/mustek_pp.h | 24 +- backend/mustek_pp_ccd300.c | 6 +- backend/mustek_pp_ccd300.h | 4 +- backend/mustek_pp_cis.c | 742 ++-- backend/mustek_pp_cis.h | 76 +- backend/mustek_pp_decl.h | 32 +- backend/mustek_pp_null.c | 14 +- backend/mustek_scsi_pp.c | 2 +- backend/mustek_scsi_pp.h | 6 +- backend/mustek_usb.c | 8 +- backend/mustek_usb.conf.in | 1 - backend/mustek_usb.h | 2 +- backend/mustek_usb2.c | 64 +- backend/mustek_usb2.h | 2 +- backend/mustek_usb2_asic.c | 24 +- backend/mustek_usb2_asic.h | 6 +- backend/mustek_usb2_high.c | 112 +- backend/mustek_usb2_high.h | 2 +- backend/mustek_usb2_reflective.c | 34 +- backend/mustek_usb2_transparent.c | 32 +- backend/mustek_usb_high.c | 2 +- backend/mustek_usb_high.h | 4 +- backend/mustek_usb_low.c | 4 +- backend/mustek_usb_low.h | 2 +- backend/mustek_usb_mid.c | 2 +- backend/mustek_usb_mid.h | 2 +- backend/nec.c | 282 +- backend/nec.h | 24 +- backend/net.c | 72 +- backend/niash_core.c | 2 +- backend/niash_core.h | 2 +- backend/p5.c | 64 +- backend/p5.h | 18 +- backend/p5_device.c | 14 +- backend/p5_device.h | 18 +- backend/pie-scsidef.h | 6 +- backend/pie.c | 2 +- backend/pieusb_usb.c | 14 +- backend/pixma.c | 356 +- backend/pixma.h | 16 +- backend/pixma_bjnp.c | 244 +- backend/pixma_bjnp.h | 18 +- backend/pixma_bjnp_private.h | 27 +- backend/pixma_common.c | 6 +- backend/pixma_common.h | 2 +- backend/pixma_imageclass.c | 50 +- backend/pixma_io.h | 2 +- backend/pixma_io_sanei.c | 18 +- backend/pixma_mp150.c | 314 +- backend/pixma_mp730.c | 8 +- backend/pixma_mp750.c | 20 +- backend/pixma_mp810.c | 10 +- backend/pixma_sane_options.c | 11 +- backend/pixma_sane_options.h | 1 - backend/plustek-pp.h | 8 +- backend/plustek-pp_dac.c | 26 +- backend/plustek-pp_detect.c | 10 +- backend/plustek-pp_image.c | 30 +- backend/plustek-pp_io.c | 32 +- backend/plustek-pp_map.c | 42 +- backend/plustek-pp_misc.c | 12 +- backend/plustek-pp_models.c | 8 +- backend/plustek-pp_motor.c | 10 +- backend/plustek-pp_p12.c | 10 +- backend/plustek-pp_p12ccd.c | 2 +- backend/plustek-pp_p48xx.c | 2 +- backend/plustek-pp_p9636.c | 4 +- backend/plustek-pp_procfs.c | 10 +- backend/plustek-pp_procs.h | 2 +- backend/plustek-pp_ptdrv.c | 74 +- backend/plustek-pp_scale.c | 4 +- backend/plustek-pp_scan.h | 6 +- backend/plustek-pp_scandata.h | 12 +- backend/plustek-pp_sysdep.h | 2 +- backend/plustek-pp_tpa.c | 6 +- backend/plustek-pp_wrapper.c | 26 +- backend/plustek-usb.c | 76 +- backend/plustek-usb.h | 31 +- backend/plustek-usbcal.c | 38 +- backend/plustek-usbcalfile.c | 30 +- backend/plustek-usbdevs.c | 50 +- backend/plustek-usbhw.c | 100 +- backend/plustek-usbimg.c | 58 +- backend/plustek-usbio.c | 8 +- backend/plustek-usbmap.c | 24 +- backend/plustek-usbscan.c | 52 +- backend/plustek-usbshading.c | 120 +- backend/plustek.c | 76 +- backend/plustek.conf.in | 4 +- backend/plustek.h | 4 +- backend/plustek_pp.c | 198 +- backend/plustek_pp.conf.in | 2 +- backend/pnm.c | 8 +- backend/qcam.c | 36 +- backend/ricoh-scsi.c | 8 +- backend/ricoh.c | 30 +- backend/ricoh.h | 4 +- backend/ricoh2.c | 971 ++++ backend/ricoh2_buffer.c | 229 + backend/rts8891.c | 153 +- backend/rts8891.h | 24 +- backend/rts8891_devices.c | 20 +- backend/rts8891_low.c | 44 +- backend/rts8891_low.h | 24 +- backend/rts88xx_lib.c | 14 +- backend/rts88xx_lib.h | 14 +- backend/s9036.c | 20 +- backend/sceptre.c | 56 +- backend/sceptre.h | 10 +- backend/scripts/pixma_gen_options.py | 389 ++ backend/sharp.c | 382 +- backend/sharp.conf.in | 6 +- backend/sharp.h | 28 +- backend/sm3600-color.c | 7 +- backend/sm3600-gray.c | 7 +- backend/sm3600-homerun.c | 9 +- backend/sm3600-scanusb.c | 9 +- backend/sm3600-scanutil.c | 4 +- backend/sm3600.c | 20 +- backend/snapscan-data.c | 4 +- backend/snapscan-mutex.c | 12 +- backend/snapscan-options.c | 18 +- backend/snapscan-scsi.c | 6 +- backend/snapscan-sources.c | 32 +- backend/snapscan-sources.h | 22 +- backend/snapscan-usb.c | 33 +- backend/snapscan.c | 8 +- backend/sp15c-scsi.h | 1 - backend/sp15c.c | 23 +- backend/sp15c.h | 1 - backend/st400.c | 2 +- backend/stubs.c | 8 + backend/stv680.c | 24 +- backend/stv680.h | 16 +- backend/tamarack.c | 83 +- backend/tamarack.conf.in | 1 - backend/tamarack.h | 10 +- backend/teco1.c | 46 +- backend/teco1.h | 10 +- backend/teco2.c | 104 +- backend/teco2.conf.in | 4 +- backend/teco2.h | 10 +- backend/teco3.c | 46 +- backend/teco3.h | 10 +- backend/test-picture.c | 2 +- backend/test.c | 6 +- backend/u12-ccd.c | 6 +- backend/u12-hw.c | 12 +- backend/u12-hwdef.h | 8 +- backend/u12-if.c | 24 +- backend/u12-image.c | 16 +- backend/u12-io.c | 12 +- backend/u12-motor.c | 10 +- backend/u12-scanner.h | 2 +- backend/u12-shading.c | 4 +- backend/u12.c | 146 +- backend/u12.conf.in | 2 +- backend/u12.h | 8 +- backend/umax-scanner.c | 15 +- backend/umax-scanner.h | 5 +- backend/umax-scsidef.h | 20 +- backend/umax-uc1200s.c | 10 +- backend/umax-uc1200se.c | 10 +- backend/umax-uc1260.c | 12 +- backend/umax-uc630.c | 11 +- backend/umax-uc840.c | 13 +- backend/umax-ug630.c | 9 +- backend/umax-ug80.c | 11 +- backend/umax-usb.c | 38 +- backend/umax.c | 254 +- backend/umax.conf.in | 13 +- backend/umax.h | 8 +- backend/umax1220u-common.c | 4 +- backend/umax1220u.c | 2 +- backend/umax_pp.c | 10 +- backend/umax_pp.conf.in | 6 +- backend/umax_pp.h | 2 +- backend/umax_pp_low.c | 142 +- backend/umax_pp_low.h | 2 +- backend/umax_pp_mid.c | 4 +- backend/umax_pp_mid.h | 12 +- backend/v4l-frequencies.h | 4 +- backend/v4l.c | 2 +- backend/v4l.h | 6 +- backend/xerox_mfp.c | 8 +- backend/xerox_mfp.conf.in | 10 +- 391 files changed, 56680 insertions(+), 59885 deletions(-) create mode 100644 backend/.gitignore delete mode 100644 backend/Makefile.in delete mode 100644 backend/genesys.c create mode 100644 backend/genesys.cc delete mode 100644 backend/genesys_conv.c create mode 100644 backend/genesys_conv.cc delete mode 100644 backend/genesys_conv_hlp.c create mode 100644 backend/genesys_conv_hlp.cc delete mode 100644 backend/genesys_devices.c create mode 100644 backend/genesys_devices.cc create mode 100644 backend/genesys_error.cc create mode 100644 backend/genesys_error.h delete mode 100644 backend/genesys_gl124.c create mode 100644 backend/genesys_gl124.cc delete mode 100644 backend/genesys_gl646.c create mode 100644 backend/genesys_gl646.cc delete mode 100644 backend/genesys_gl841.c create mode 100644 backend/genesys_gl841.cc delete mode 100644 backend/genesys_gl843.c create mode 100644 backend/genesys_gl843.cc delete mode 100644 backend/genesys_gl846.c create mode 100644 backend/genesys_gl846.cc delete mode 100644 backend/genesys_gl847.c create mode 100644 backend/genesys_gl847.cc delete mode 100644 backend/genesys_low.c create mode 100644 backend/genesys_low.cc create mode 100644 backend/genesys_sanei.cc create mode 100644 backend/genesys_sanei.h create mode 100644 backend/genesys_serialize.cc create mode 100644 backend/genesys_serialize.h create mode 100644 backend/ricoh2.c create mode 100644 backend/ricoh2_buffer.c create mode 100755 backend/scripts/pixma_gen_options.py (limited to 'backend') diff --git a/backend/.gitignore b/backend/.gitignore new file mode 100644 index 0000000..6ebfbd5 --- /dev/null +++ b/backend/.gitignore @@ -0,0 +1,5 @@ +*-s.c +*-s.cc +*.conf +dll-preload.c +dll-preload.h diff --git a/backend/Makefile.am b/backend/Makefile.am index f7fb403..44d1e17 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -29,6 +29,10 @@ EXTRA_DIST += stubs.c $(AM_V_at)rm -f $@ $(AM_V_at)$(LN_S) $(srcdir)/stubs.c $@ +%-s.cc: $(srcdir)/stubs.c + $(AM_V_at)rm -f $@ + $(AM_V_at)$(LN_S) $(srcdir)/stubs.c $@ + dll-preload.h: $(AM_V_at)rm -f $@ $(AM_V_at)list="$(PRELOADABLE_BACKENDS)"; for be in $$list; do \ @@ -74,6 +78,10 @@ BACKEND_CONFS= abaton.conf agfafocus.conf apple.conf artec.conf \ teco1.conf teco2.conf teco3.conf test.conf \ u12.conf umax1220u.conf umax.conf umax_pp.conf v4l.conf \ xerox_mfp.conf dll.conf saned.conf +# Although ./configure sets up BACKEND_CONFS_ENABLED it does not take +# into account the fact that some backends don't have a configuration +# file. The becfg should depend on BACKEND_CONFS. The install-becfg +# target uses BACKEND_CONFS_ENABLED and silently skips missing files. becfg: $(BACKEND_CONFS) SUFFIXES = .conf.in .conf @@ -92,9 +100,9 @@ install-data-hook: install-becfg install-firmware-path $(INSTALL_LOCKPATH) # Custom install target to install config files. Do not overwrite # files that have been previously installed so that user modifications # are not lost. -install-becfg: - @# Libtool has a bug where it will sometimes symlink the last - @# installed library in $(sanelibdir) to $(sanelibdir)/libsane.*. +install-becfg: becfg + @# Libtool has a bug where it will sometimes symlink the last + @# installed library in $(sanelibdir) to $(sanelibdir)/libsane.*. @# Having two libsane's can cause issues so get rid of it. -rm -f $(DESTDIR)$(sanelibdir)/libsane.* test -z "$(configdir)" || $(MKDIR_P) "$(DESTDIR)$(configdir)" @@ -161,7 +169,7 @@ be_convenience_libs = libabaton.la libagfafocus.la \ libniash.la libp5.la \ libpie.la libpieusb.la libpint.la libpixma.la \ libplustek.la libplustek_pp.la libpnm.la \ - libqcam.la libricoh.la librts8891.la \ + libqcam.la libricoh.la libricoh2.la librts8891.la \ libs9036.la libsceptre.la libsharp.la \ libsm3600.la libsm3840.la libsnapscan.la \ libsp15c.la libst400.la libstv680.la \ @@ -195,7 +203,7 @@ be_dlopen_libs = libsane-abaton.la libsane-agfafocus.la \ libsane-niash.la libsane-p5.la \ libsane-pie.la libsane-pieusb.la libsane-pint.la libsane-pixma.la \ libsane-plustek.la libsane-plustek_pp.la libsane-pnm.la \ - libsane-qcam.la libsane-ricoh.la libsane-rts8891.la \ + libsane-qcam.la libsane-ricoh.la libsane-ricoh2.la libsane-rts8891.la \ libsane-s9036.la libsane-sceptre.la libsane-sharp.la \ libsane-sm3600.la libsane-sm3840.la libsane-snapscan.la \ libsane-sp15c.la libsane-st400.la libsane-stv680.la \ @@ -217,7 +225,7 @@ COMMON_LIBS = ../lib/liblib.la # all related files within backend directory. General guideline # is to have a ${backend}.c and ${backend}.h. Some backends also # add a few support source files to convience library. -# Note: automake doesn't really use header files listed here. +# Note: automake doesn't really use header files listed here. # They are indications that they need to be distributed only. libabaton_la_SOURCES = abaton.c abaton.h libabaton_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=abaton @@ -228,7 +236,7 @@ libabaton_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=abaton # Also, it will need to link in related convenience library as well as # any external libraries required to resolve symbols. # -# All backends should include $(DIST_SANELIBS_LDFLAGS) so that +# All backends should include $(DIST_SANELIBS_LDFLAGS) so that # library is correctly versioned. # # If a backend has a config file, it must be listed here to get distributed. @@ -239,10 +247,10 @@ libsane_abaton_la_LIBADD = $(COMMON_LIBS) libabaton.la ../sanei/sanei_init_debug EXTRA_DIST += abaton.conf.in libagfafocus_la_SOURCES = agfafocus.c agfafocus.h -libagfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus +libagfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus nodist_libsane_agfafocus_la_SOURCES = agfafocus-s.c -libsane_agfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus +libsane_agfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus libsane_agfafocus_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_agfafocus_la_LIBADD = $(COMMON_LIBS) libagfafocus.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += agfafocus.conf.in @@ -280,12 +288,12 @@ libas6e_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=as6e nodist_libsane_as6e_la_SOURCES = as6e-s.c libsane_as6e_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=as6e libsane_as6e_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_as6e_la_LIBADD = $(COMMON_LIBS) libas6e.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo +libsane_as6e_la_LIBADD = $(COMMON_LIBS) libas6e.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo libavision_la_SOURCES = avision.c avision.h libavision_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=avision -nodist_libsane_avision_la_SOURCES = avision-s.c +nodist_libsane_avision_la_SOURCES = avision-s.c libsane_avision_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=avision libsane_avision_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_avision_la_LIBADD = $(COMMON_LIBS) libavision.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) @@ -303,7 +311,7 @@ EXTRA_DIST += bh.conf.in libcanon_la_SOURCES = canon.c canon.h libcanon_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon -nodist_libsane_canon_la_SOURCES = canon-s.c +nodist_libsane_canon_la_SOURCES = canon-s.c libsane_canon_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon libsane_canon_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_canon_la_LIBADD = $(COMMON_LIBS) libcanon.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(RESMGR_LIBS) @@ -325,7 +333,7 @@ EXTRA_DIST += canon630u-common.c lm9830.h libcanon_dr_la_SOURCES = canon_dr.c canon_dr.h canon_dr-cmd.h libcanon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr -nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c +nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c libsane_canon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) @@ -472,21 +480,27 @@ libsane_fujitsu_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_fujitsu_la_LIBADD = $(COMMON_LIBS) libfujitsu.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) EXTRA_DIST += fujitsu.conf.in -libgenesys_la_SOURCES = genesys.c genesys.h genesys_gl646.c genesys_gl646.h genesys_gl841.c genesys_gl841.h genesys_gl843.c genesys_gl843.h genesys_gl846.c genesys_gl846.h genesys_gl847.c genesys_gl847.h genesys_gl124.c genesys_gl124.h genesys_low.c genesys_low.h +libgenesys_la_SOURCES = genesys.cc genesys.h genesys_sanei.h genesys_sanei.cc genesys_error.h genesys_error.cc \ + genesys_serialize.h \ + genesys_gl646.cc genesys_gl646.h genesys_gl841.cc genesys_gl841.h \ + genesys_gl843.cc genesys_gl843.h genesys_gl846.cc genesys_gl846.h \ + genesys_gl847.cc genesys_gl847.h genesys_gl124.cc genesys_gl124.h \ + genesys_low.cc genesys_low.h + libgenesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys -nodist_libsane_genesys_la_SOURCES = genesys-s.c +nodist_libsane_genesys_la_SOURCES = genesys-s.cc libsane_genesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys libsane_genesys_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) EXTRA_DIST += genesys.conf.in # TODO: Why are this distributed but not compiled? -EXTRA_DIST += genesys_conv.c genesys_conv_hlp.c genesys_devices.c +EXTRA_DIST += genesys_conv.cc genesys_conv_hlp.cc genesys_devices.cc libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2 -nodist_libsane_gphoto2_la_SOURCES = gphoto2-s.c +nodist_libsane_gphoto2_la_SOURCES = gphoto2-s.c libsane_gphoto2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gphoto2 libsane_gphoto2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_gphoto2_la_LIBADD = $(GPHOTO2_LDFLAGS) $(COMMON_LIBS) libgphoto2_i.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(GPHOTO2_LIBS) $(JPEG_LIBS) @@ -495,7 +509,7 @@ EXTRA_DIST += gphoto2.conf.in libgt68xx_la_SOURCES = gt68xx.c gt68xx.h libgt68xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gt68xx -nodist_libsane_gt68xx_la_SOURCES = gt68xx-s.c +nodist_libsane_gt68xx_la_SOURCES = gt68xx-s.c libsane_gt68xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gt68xx libsane_gt68xx_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_gt68xx_la_LIBADD = $(COMMON_LIBS) libgt68xx.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) @@ -536,7 +550,7 @@ EXTRA_DIST += hp3900_config.c hp3900_debug.c hp3900_rts8822.c hp3900_sane.c hp39 libhp4200_la_SOURCES = hp4200.c hp4200.h libhp4200_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp4200 -nodist_libsane_hp4200_la_SOURCES = hp4200-s.c +nodist_libsane_hp4200_la_SOURCES = hp4200-s.c libsane_hp4200_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp4200 libsane_hp4200_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_hp4200_la_LIBADD = $(COMMON_LIBS) libhp4200.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) @@ -576,7 +590,7 @@ libsane_hpljm1005_la_LIBADD = $(COMMON_LIBS) libhpljm1005.la ../sanei/sanei_init libhpsj5s_la_SOURCES = hpsj5s.c hpsj5s.h libhpsj5s_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hpsj5s -nodist_libsane_hpsj5s_la_SOURCES = hpsj5s-s.c +nodist_libsane_hpsj5s_la_SOURCES = hpsj5s-s.c libsane_hpsj5s_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hpsj5s libsane_hpsj5s_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_hpsj5s_la_LIBADD = $(COMMON_LIBS) libhpsj5s.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(IEEE1284_LIBS) @@ -585,7 +599,7 @@ EXTRA_DIST += hpsj5s.conf.in libhs2p_la_SOURCES = hs2p.c hs2p.h hs2p-saneopts.h libhs2p_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hs2p -nodist_libsane_hs2p_la_SOURCES = hs2p-s.c +nodist_libsane_hs2p_la_SOURCES = hs2p-s.c libsane_hs2p_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hs2p libsane_hs2p_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_hs2p_la_LIBADD = $(COMMON_LIBS) libhs2p.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) @@ -633,7 +647,7 @@ libsane_kvs1025_la_LIBADD = $(COMMON_LIBS) libkvs1025.la ../sanei/sanei_init_deb EXTRA_DIST += kvs1025.conf.in libkvs20xx_la_SOURCES = kvs20xx.c kvs20xx_cmd.c kvs20xx_opt.c \ - kvs20xx_cmd.h kvs20xx.h + kvs20xx_cmd.h kvs20xx.h libkvs20xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs20xx nodist_libsane_kvs20xx_la_SOURCES = kvs20xx-s.c @@ -642,7 +656,7 @@ libsane_kvs20xx_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_kvs20xx_la_LIBADD = $(COMMON_LIBS) libkvs20xx.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) libkvs40xx_la_SOURCES = kvs40xx.c kvs40xx_cmd.c kvs40xx_opt.c \ - kvs40xx.h + kvs40xx.h libkvs40xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs40xx nodist_libsane_kvs40xx_la_SOURCES = kvs40xx-s.c @@ -662,7 +676,7 @@ EXTRA_DIST += leo.conf.in liblexmark_la_SOURCES = lexmark.c lexmark.h lexmark_low.c liblexmark_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=lexmark -nodist_libsane_lexmark_la_SOURCES = lexmark-s.c +nodist_libsane_lexmark_la_SOURCES = lexmark-s.c libsane_lexmark_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=lexmark libsane_lexmark_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_lexmark_la_LIBADD = $(COMMON_LIBS) liblexmark.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) @@ -735,12 +749,12 @@ libsane_mustek_pp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_mustek_pp_la_LIBADD = $(COMMON_LIBS) libmustek_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_pa4s2.lo $(MATH_LIB) $(IEEE1284_LIBS) EXTRA_DIST += mustek_pp.conf.in # TODO: Why are these distributed but not compiled? -EXTRA_DIST += mustek_pp_ccd300.c mustek_pp_ccd300.h mustek_pp_cis.c mustek_pp_cis.h mustek_pp_null.c +EXTRA_DIST += mustek_pp_ccd300.c mustek_pp_ccd300.h mustek_pp_cis.c mustek_pp_cis.h mustek_pp_null.c libmustek_usb_la_SOURCES = mustek_usb.c mustek_usb.h libmustek_usb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb -nodist_libsane_mustek_usb_la_SOURCES = mustek_usb-s.c +nodist_libsane_mustek_usb_la_SOURCES = mustek_usb-s.c libsane_mustek_usb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb libsane_mustek_usb_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_mustek_usb_la_LIBADD = $(COMMON_LIBS) libmustek_usb.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) @@ -789,7 +803,7 @@ EXTRA_DIST += niash_core.c niash_core.h niash_xfer.c niash_xfer.h libpie_la_SOURCES = pie.c pie-scsidef.h libpie_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pie -nodist_libsane_pie_la_SOURCES = pie-s.c +nodist_libsane_pie_la_SOURCES = pie-s.c libsane_pie_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pie libsane_pie_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_pie_la_LIBADD = $(COMMON_LIBS) libpie.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) @@ -819,7 +833,7 @@ libpint_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pint nodist_libsane_pint_la_SOURCES = pint-s.c libsane_pint_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pint libsane_pint_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pint_la_LIBADD = $(COMMON_LIBS) libpint.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo +libsane_pint_la_LIBADD = $(COMMON_LIBS) libpint.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo libpixma_la_SOURCES = pixma.c pixma.h pixma_io_sanei.c pixma_io.h pixma_common.c pixma_common.h pixma_mp150.c pixma_mp730.c pixma_mp750.c pixma_mp810.c pixma_imageclass.c pixma_bjnp.c pixma_bjnp.h pixma_bjnp_private.h pixma_rename.h libpixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma @@ -827,7 +841,7 @@ libpixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma nodist_libsane_pixma_la_SOURCES = pixma-s.c libsane_pixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma libsane_pixma_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += pixma.conf.in # TODO: Why are these distributed but not compiled? EXTRA_DIST += pixma_sane_options.c pixma_sane_options.h @@ -856,10 +870,10 @@ EXTRA_DIST += plustek-pp_dac.c plustek-pp_dbg.h plustek-pp_detect.c plustek-pp_g libpnm_la_SOURCES = pnm.c libpnm_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pnm -nodist_libsane_pnm_la_SOURCES = pnm-s.c +nodist_libsane_pnm_la_SOURCES = pnm-s.c libsane_pnm_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pnm libsane_pnm_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pnm_la_LIBADD = $(COMMON_LIBS) libpnm.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo +libsane_pnm_la_LIBADD = $(COMMON_LIBS) libpnm.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo libqcam_la_SOURCES = qcam.c qcam.h libqcam_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=qcam @@ -881,6 +895,15 @@ EXTRA_DIST += ricoh.conf.in # TODO: Why are these distributed but not compiled? EXTRA_DIST += ricoh-scsi.c +libricoh2_la_SOURCES = ricoh2.c +libricoh2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=ricoh2 + +nodist_libsane_ricoh2_la_SOURCES = ricoh2-s.c +libsane_ricoh2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=ricoh2 +libsane_ricoh2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) +libsane_ricoh2_la_LIBADD = $(COMMON_LIBS) libricoh2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_usb.lo ../sanei/sanei_config.lo sane_strstatus.lo $(USB_LIBS) +EXTRA_DIST += ricoh2_buffer.c + librts8891_la_SOURCES = rts8891.c rts8891.h rts88xx_lib.c rts88xx_lib.h librts8891_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=rts8891 @@ -963,7 +986,7 @@ EXTRA_DIST += sp15c.conf.in libst400_la_SOURCES = st400.c st400.h libst400_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=st400 -nodist_libsane_st400_la_SOURCES = st400-s.c ../sanei/sanei_scsi.lo +nodist_libsane_st400_la_SOURCES = st400-s.c ../sanei/sanei_scsi.lo libsane_st400_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=st400 libsane_st400_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_st400_la_LIBADD = $(COMMON_LIBS) libst400.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) @@ -1050,7 +1073,7 @@ EXTRA_DIST += umax-scanner.c umax-scanner.h umax-scsidef.h umax-uc1200s.c umax-u libumax1220u_la_SOURCES = umax1220u.c libumax1220u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax1220u -nodist_libsane_umax1220u_la_SOURCES = umax1220u-s.c +nodist_libsane_umax1220u_la_SOURCES = umax1220u-s.c libsane_umax1220u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax1220u libsane_umax1220u_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_umax1220u_la_LIBADD = $(COMMON_LIBS) libumax1220u.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) @@ -1101,28 +1124,31 @@ EXTRA_DIST += dll.conf.in EXTRA_DIST += dll.aliases # libsane.la and libsane-dll.la are the same thing except for -# the addition of backends listed by PRELOADABLE_BACKENDS that are +# the addition of backends listed by PRELOADABLE_BACKENDS that are # statically linked in. # Also, libsane.la goes into $(libdir) where as all libsane-* # (including libsane-dll.la) go into $(libdir)/sane # FIXME: Since we are throwing in the kitchen sink, might as # well link in ../sanei/libsanei.la instead. But currently, -# libsanei.la is linking in sanei_auth which requires md5. +# libsanei.la is linking in sanei_auth which requires md5. # Shipping md5 could cause symbol conflicts with commonly used # md5 external libraries. Either need to prefix md5 with sanei_ # (see liblib.la and snprintf), or move sanei_auth outside # of libsanei. # -# FIXME: This is linking in every possible external library because there -# is the off chance user is using PRELOADABLE_BACKENDS that may need -# them. Since standard mode is to only have the dll backend, its a waste. -# Need to update configure to build a list of only what needs to go into -# LIBADD based on whats being preloaded. +# FIXME: This is using every possibly needed library and dependency +# when the user is using any PRELOADABLE_BACKENDS, irrespective of +# what backends are preloaded. It should include what is needed by +# those backends that are actually preloaded. +if preloadable_backends_enabled +PRELOADABLE_BACKENDS_LIBS = ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +PRELOADABLE_BACKENDS_DEPS = ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(SANEI_SANEI_JPEG_LO) +endif nodist_libsane_la_SOURCES = dll-s.c libsane_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll libsane_la_LDFLAGS = $(DIST_LIBS_LDFLAGS) -libsane_la_LIBADD = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(DL_LIBS) $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_la_LIBADD = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo $(PRELOADABLE_BACKENDS_LIBS) $(DL_LIBS) # WARNING: Automake is getting this wrong so have to do it ourselves. -libsane_la_DEPENDENCIES = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(SANEI_SANEI_JPEG_LO) +libsane_la_DEPENDENCIES = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo $(PRELOADABLE_BACKENDS_DEPS) diff --git a/backend/Makefile.in b/backend/Makefile.in deleted file mode 100644 index 4e070f0..0000000 --- a/backend/Makefile.in +++ /dev/null @@ -1,5644 +0,0 @@ -# Makefile.in generated by automake 1.14.1 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2013 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = backend -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/mkinstalldirs $(top_srcdir)/depcomp -ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 -am__aclocal_m4_deps = $(top_srcdir)/m4/gettext.m4 \ - $(top_srcdir)/m4/iconv.m4 $(top_srcdir)/m4/intlmacosx.m4 \ - $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \ - $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/ltoptions.m4 \ - $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ - $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ - $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ - $(top_srcdir)/acinclude.m4 $(top_srcdir)/m4/libtool.m4 \ - $(top_srcdir)/m4/byteorder.m4 $(top_srcdir)/m4/stdint.m4 \ - $(top_srcdir)/configure.ac -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs -CONFIG_HEADER = $(top_builddir)/include/sane/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sanelibdir)" -LTLIBRARIES = $(lib_LTLIBRARIES) $(sanelib_LTLIBRARIES) -libabaton_la_LIBADD = -am_libabaton_la_OBJECTS = libabaton_la-abaton.lo -libabaton_la_OBJECTS = $(am_libabaton_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -libagfafocus_la_LIBADD = -am_libagfafocus_la_OBJECTS = libagfafocus_la-agfafocus.lo -libagfafocus_la_OBJECTS = $(am_libagfafocus_la_OBJECTS) -libapple_la_LIBADD = -am_libapple_la_OBJECTS = libapple_la-apple.lo -libapple_la_OBJECTS = $(am_libapple_la_OBJECTS) -libartec_la_LIBADD = -am_libartec_la_OBJECTS = libartec_la-artec.lo -libartec_la_OBJECTS = $(am_libartec_la_OBJECTS) -libartec_eplus48u_la_LIBADD = -am_libartec_eplus48u_la_OBJECTS = \ - libartec_eplus48u_la-artec_eplus48u.lo -libartec_eplus48u_la_OBJECTS = $(am_libartec_eplus48u_la_OBJECTS) -libas6e_la_LIBADD = -am_libas6e_la_OBJECTS = libas6e_la-as6e.lo -libas6e_la_OBJECTS = $(am_libas6e_la_OBJECTS) -libavision_la_LIBADD = -am_libavision_la_OBJECTS = libavision_la-avision.lo -libavision_la_OBJECTS = $(am_libavision_la_OBJECTS) -libbh_la_LIBADD = -am_libbh_la_OBJECTS = libbh_la-bh.lo -libbh_la_OBJECTS = $(am_libbh_la_OBJECTS) -libcanon_la_LIBADD = -am_libcanon_la_OBJECTS = libcanon_la-canon.lo -libcanon_la_OBJECTS = $(am_libcanon_la_OBJECTS) -libcanon630u_la_LIBADD = -am_libcanon630u_la_OBJECTS = libcanon630u_la-canon630u.lo -libcanon630u_la_OBJECTS = $(am_libcanon630u_la_OBJECTS) -libcanon_dr_la_LIBADD = -am_libcanon_dr_la_OBJECTS = libcanon_dr_la-canon_dr.lo -libcanon_dr_la_OBJECTS = $(am_libcanon_dr_la_OBJECTS) -libcanon_pp_la_LIBADD = -am_libcanon_pp_la_OBJECTS = libcanon_pp_la-canon_pp.lo \ - libcanon_pp_la-canon_pp-io.lo libcanon_pp_la-canon_pp-dev.lo -libcanon_pp_la_OBJECTS = $(am_libcanon_pp_la_OBJECTS) -libcardscan_la_LIBADD = -am_libcardscan_la_OBJECTS = libcardscan_la-cardscan.lo -libcardscan_la_OBJECTS = $(am_libcardscan_la_OBJECTS) -libcoolscan_la_LIBADD = -am_libcoolscan_la_OBJECTS = libcoolscan_la-coolscan.lo -libcoolscan_la_OBJECTS = $(am_libcoolscan_la_OBJECTS) -libcoolscan2_la_LIBADD = -am_libcoolscan2_la_OBJECTS = libcoolscan2_la-coolscan2.lo -libcoolscan2_la_OBJECTS = $(am_libcoolscan2_la_OBJECTS) -libcoolscan3_la_LIBADD = -am_libcoolscan3_la_OBJECTS = libcoolscan3_la-coolscan3.lo -libcoolscan3_la_OBJECTS = $(am_libcoolscan3_la_OBJECTS) -libdc210_la_LIBADD = -am_libdc210_la_OBJECTS = libdc210_la-dc210.lo -libdc210_la_OBJECTS = $(am_libdc210_la_OBJECTS) -libdc240_la_LIBADD = -am_libdc240_la_OBJECTS = libdc240_la-dc240.lo -libdc240_la_OBJECTS = $(am_libdc240_la_OBJECTS) -libdc25_la_LIBADD = -am_libdc25_la_OBJECTS = libdc25_la-dc25.lo -libdc25_la_OBJECTS = $(am_libdc25_la_OBJECTS) -libdell1600n_net_la_LIBADD = -am_libdell1600n_net_la_OBJECTS = libdell1600n_net_la-dell1600n_net.lo -libdell1600n_net_la_OBJECTS = $(am_libdell1600n_net_la_OBJECTS) -libdll_la_LIBADD = -am_libdll_la_OBJECTS = libdll_la-dll.lo -libdll_la_OBJECTS = $(am_libdll_la_OBJECTS) -libdll_preload_la_LIBADD = -am_libdll_preload_la_OBJECTS = libdll_preload_la-dll.lo -libdll_preload_la_OBJECTS = $(am_libdll_preload_la_OBJECTS) -libdmc_la_LIBADD = -am_libdmc_la_OBJECTS = libdmc_la-dmc.lo -libdmc_la_OBJECTS = $(am_libdmc_la_OBJECTS) -libepjitsu_la_LIBADD = -am_libepjitsu_la_OBJECTS = libepjitsu_la-epjitsu.lo -libepjitsu_la_OBJECTS = $(am_libepjitsu_la_OBJECTS) -libepson_la_LIBADD = -am_libepson_la_OBJECTS = libepson_la-epson.lo \ - libepson_la-epson_scsi.lo libepson_la-epson_usb.lo -libepson_la_OBJECTS = $(am_libepson_la_OBJECTS) -libepson2_la_LIBADD = -am_libepson2_la_OBJECTS = libepson2_la-epson2.lo \ - libepson2_la-epson2_scsi.lo libepson2_la-epson2_usb.lo \ - libepson2_la-epson2_net.lo libepson2_la-epson2-io.lo \ - libepson2_la-epson2-commands.lo libepson2_la-epson2-ops.lo \ - libepson2_la-epson2-cct.lo -libepson2_la_OBJECTS = $(am_libepson2_la_OBJECTS) -libepsonds_la_LIBADD = -am_libepsonds_la_OBJECTS = libepsonds_la-epsonds.lo \ - libepsonds_la-epsonds-usb.lo libepsonds_la-epsonds-io.lo \ - libepsonds_la-epsonds-cmd.lo libepsonds_la-epsonds-ops.lo \ - libepsonds_la-epsonds-jpeg.lo libepsonds_la-epsonds-net.lo -libepsonds_la_OBJECTS = $(am_libepsonds_la_OBJECTS) -libfujitsu_la_LIBADD = -am_libfujitsu_la_OBJECTS = libfujitsu_la-fujitsu.lo -libfujitsu_la_OBJECTS = $(am_libfujitsu_la_OBJECTS) -libgenesys_la_LIBADD = -am_libgenesys_la_OBJECTS = libgenesys_la-genesys.lo \ - libgenesys_la-genesys_gl646.lo libgenesys_la-genesys_gl841.lo \ - libgenesys_la-genesys_gl843.lo libgenesys_la-genesys_gl846.lo \ - libgenesys_la-genesys_gl847.lo libgenesys_la-genesys_gl124.lo \ - libgenesys_la-genesys_low.lo -libgenesys_la_OBJECTS = $(am_libgenesys_la_OBJECTS) -libgphoto2_i_la_LIBADD = -am_libgphoto2_i_la_OBJECTS = libgphoto2_i_la-gphoto2.lo -libgphoto2_i_la_OBJECTS = $(am_libgphoto2_i_la_OBJECTS) -libgt68xx_la_LIBADD = -am_libgt68xx_la_OBJECTS = libgt68xx_la-gt68xx.lo -libgt68xx_la_OBJECTS = $(am_libgt68xx_la_OBJECTS) -libhp_la_LIBADD = -am_libhp_la_OBJECTS = libhp_la-hp.lo libhp_la-hp-accessor.lo \ - libhp_la-hp-device.lo libhp_la-hp-handle.lo \ - libhp_la-hp-hpmem.lo libhp_la-hp-option.lo libhp_la-hp-scl.lo -libhp_la_OBJECTS = $(am_libhp_la_OBJECTS) -libhp3500_la_LIBADD = -am_libhp3500_la_OBJECTS = libhp3500_la-hp3500.lo -libhp3500_la_OBJECTS = $(am_libhp3500_la_OBJECTS) -libhp3900_la_LIBADD = -am_libhp3900_la_OBJECTS = libhp3900_la-hp3900.lo -libhp3900_la_OBJECTS = $(am_libhp3900_la_OBJECTS) -libhp4200_la_LIBADD = -am_libhp4200_la_OBJECTS = libhp4200_la-hp4200.lo -libhp4200_la_OBJECTS = $(am_libhp4200_la_OBJECTS) -libhp5400_la_LIBADD = -am_libhp5400_la_OBJECTS = libhp5400_la-hp5400.lo -libhp5400_la_OBJECTS = $(am_libhp5400_la_OBJECTS) -libhp5590_la_LIBADD = -am_libhp5590_la_OBJECTS = libhp5590_la-hp5590.lo -libhp5590_la_OBJECTS = $(am_libhp5590_la_OBJECTS) -libhpljm1005_la_LIBADD = -am_libhpljm1005_la_OBJECTS = libhpljm1005_la-hpljm1005.lo -libhpljm1005_la_OBJECTS = $(am_libhpljm1005_la_OBJECTS) -libhpsj5s_la_LIBADD = -am_libhpsj5s_la_OBJECTS = libhpsj5s_la-hpsj5s.lo -libhpsj5s_la_OBJECTS = $(am_libhpsj5s_la_OBJECTS) -libhs2p_la_LIBADD = -am_libhs2p_la_OBJECTS = libhs2p_la-hs2p.lo -libhs2p_la_OBJECTS = $(am_libhs2p_la_OBJECTS) -libibm_la_LIBADD = -am_libibm_la_OBJECTS = libibm_la-ibm.lo -libibm_la_OBJECTS = $(am_libibm_la_OBJECTS) -libkodak_la_LIBADD = -am_libkodak_la_OBJECTS = libkodak_la-kodak.lo -libkodak_la_OBJECTS = $(am_libkodak_la_OBJECTS) -libkodakaio_la_LIBADD = -am_libkodakaio_la_OBJECTS = libkodakaio_la-kodakaio.lo -libkodakaio_la_OBJECTS = $(am_libkodakaio_la_OBJECTS) -libkvs1025_la_LIBADD = -am_libkvs1025_la_OBJECTS = libkvs1025_la-kvs1025.lo \ - libkvs1025_la-kvs1025_low.lo libkvs1025_la-kvs1025_opt.lo \ - libkvs1025_la-kvs1025_usb.lo -libkvs1025_la_OBJECTS = $(am_libkvs1025_la_OBJECTS) -libkvs20xx_la_LIBADD = -am_libkvs20xx_la_OBJECTS = libkvs20xx_la-kvs20xx.lo \ - libkvs20xx_la-kvs20xx_cmd.lo libkvs20xx_la-kvs20xx_opt.lo -libkvs20xx_la_OBJECTS = $(am_libkvs20xx_la_OBJECTS) -libkvs40xx_la_LIBADD = -am_libkvs40xx_la_OBJECTS = libkvs40xx_la-kvs40xx.lo \ - libkvs40xx_la-kvs40xx_cmd.lo libkvs40xx_la-kvs40xx_opt.lo -libkvs40xx_la_OBJECTS = $(am_libkvs40xx_la_OBJECTS) -libleo_la_LIBADD = -am_libleo_la_OBJECTS = libleo_la-leo.lo -libleo_la_OBJECTS = $(am_libleo_la_OBJECTS) -liblexmark_la_LIBADD = -am_liblexmark_la_OBJECTS = liblexmark_la-lexmark.lo \ - liblexmark_la-lexmark_low.lo -liblexmark_la_OBJECTS = $(am_liblexmark_la_OBJECTS) -libma1509_la_LIBADD = -am_libma1509_la_OBJECTS = libma1509_la-ma1509.lo -libma1509_la_OBJECTS = $(am_libma1509_la_OBJECTS) -libmagicolor_la_LIBADD = -am_libmagicolor_la_OBJECTS = libmagicolor_la-magicolor.lo -libmagicolor_la_OBJECTS = $(am_libmagicolor_la_OBJECTS) -libmatsushita_la_LIBADD = -am_libmatsushita_la_OBJECTS = libmatsushita_la-matsushita.lo -libmatsushita_la_OBJECTS = $(am_libmatsushita_la_OBJECTS) -libmicrotek_la_LIBADD = -am_libmicrotek_la_OBJECTS = libmicrotek_la-microtek.lo -libmicrotek_la_OBJECTS = $(am_libmicrotek_la_OBJECTS) -libmicrotek2_la_LIBADD = -am_libmicrotek2_la_OBJECTS = libmicrotek2_la-microtek2.lo -libmicrotek2_la_OBJECTS = $(am_libmicrotek2_la_OBJECTS) -libmustek_la_LIBADD = -am_libmustek_la_OBJECTS = libmustek_la-mustek.lo -libmustek_la_OBJECTS = $(am_libmustek_la_OBJECTS) -libmustek_pp_la_LIBADD = -am_libmustek_pp_la_OBJECTS = libmustek_pp_la-mustek_pp.lo -libmustek_pp_la_OBJECTS = $(am_libmustek_pp_la_OBJECTS) -libmustek_usb_la_LIBADD = -am_libmustek_usb_la_OBJECTS = libmustek_usb_la-mustek_usb.lo -libmustek_usb_la_OBJECTS = $(am_libmustek_usb_la_OBJECTS) -libmustek_usb2_la_LIBADD = -am_libmustek_usb2_la_OBJECTS = libmustek_usb2_la-mustek_usb2.lo -libmustek_usb2_la_OBJECTS = $(am_libmustek_usb2_la_OBJECTS) -libnec_la_LIBADD = -am_libnec_la_OBJECTS = libnec_la-nec.lo -libnec_la_OBJECTS = $(am_libnec_la_OBJECTS) -libnet_la_LIBADD = -am_libnet_la_OBJECTS = libnet_la-net.lo -libnet_la_OBJECTS = $(am_libnet_la_OBJECTS) -libniash_la_LIBADD = -am_libniash_la_OBJECTS = libniash_la-niash.lo -libniash_la_OBJECTS = $(am_libniash_la_OBJECTS) -libp5_la_LIBADD = -am_libp5_la_OBJECTS = libp5_la-p5.lo -libp5_la_OBJECTS = $(am_libp5_la_OBJECTS) -libpie_la_LIBADD = -am_libpie_la_OBJECTS = libpie_la-pie.lo -libpie_la_OBJECTS = $(am_libpie_la_OBJECTS) -libpieusb_la_LIBADD = -am_libpieusb_la_OBJECTS = libpieusb_la-pieusb_buffer.lo \ - libpieusb_la-pieusb_scancmd.lo libpieusb_la-pieusb_specific.lo \ - libpieusb_la-pieusb_usb.lo libpieusb_la-pieusb.lo -libpieusb_la_OBJECTS = $(am_libpieusb_la_OBJECTS) -libpint_la_LIBADD = -am_libpint_la_OBJECTS = libpint_la-pint.lo -libpint_la_OBJECTS = $(am_libpint_la_OBJECTS) -libpixma_la_LIBADD = -am_libpixma_la_OBJECTS = libpixma_la-pixma.lo \ - libpixma_la-pixma_io_sanei.lo libpixma_la-pixma_common.lo \ - libpixma_la-pixma_mp150.lo libpixma_la-pixma_mp730.lo \ - libpixma_la-pixma_mp750.lo libpixma_la-pixma_mp810.lo \ - libpixma_la-pixma_imageclass.lo libpixma_la-pixma_bjnp.lo -libpixma_la_OBJECTS = $(am_libpixma_la_OBJECTS) -libplustek_la_LIBADD = -am_libplustek_la_OBJECTS = libplustek_la-plustek.lo -libplustek_la_OBJECTS = $(am_libplustek_la_OBJECTS) -libplustek_pp_la_LIBADD = -am_libplustek_pp_la_OBJECTS = libplustek_pp_la-plustek_pp.lo -libplustek_pp_la_OBJECTS = $(am_libplustek_pp_la_OBJECTS) -libpnm_la_LIBADD = -am_libpnm_la_OBJECTS = libpnm_la-pnm.lo -libpnm_la_OBJECTS = $(am_libpnm_la_OBJECTS) -libqcam_la_LIBADD = -am_libqcam_la_OBJECTS = libqcam_la-qcam.lo -libqcam_la_OBJECTS = $(am_libqcam_la_OBJECTS) -libricoh_la_LIBADD = -am_libricoh_la_OBJECTS = libricoh_la-ricoh.lo -libricoh_la_OBJECTS = $(am_libricoh_la_OBJECTS) -librts8891_la_LIBADD = -am_librts8891_la_OBJECTS = librts8891_la-rts8891.lo \ - librts8891_la-rts88xx_lib.lo -librts8891_la_OBJECTS = $(am_librts8891_la_OBJECTS) -libs9036_la_LIBADD = -am_libs9036_la_OBJECTS = libs9036_la-s9036.lo -libs9036_la_OBJECTS = $(am_libs9036_la_OBJECTS) -am__DEPENDENCIES_1 = -libsane_abaton_la_DEPENDENCIES = $(COMMON_LIBS) libabaton.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_abaton_la_OBJECTS = libsane_abaton_la-abaton-s.lo -libsane_abaton_la_OBJECTS = $(nodist_libsane_abaton_la_OBJECTS) -libsane_abaton_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_abaton_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_agfafocus_la_DEPENDENCIES = $(COMMON_LIBS) libagfafocus.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_thread.lo \ - ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_agfafocus_la_OBJECTS = \ - libsane_agfafocus_la-agfafocus-s.lo -libsane_agfafocus_la_OBJECTS = $(nodist_libsane_agfafocus_la_OBJECTS) -libsane_agfafocus_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_agfafocus_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_apple_la_DEPENDENCIES = $(COMMON_LIBS) libapple.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_apple_la_OBJECTS = libsane_apple_la-apple-s.lo -libsane_apple_la_OBJECTS = $(nodist_libsane_apple_la_OBJECTS) -libsane_apple_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_apple_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_artec_la_DEPENDENCIES = $(COMMON_LIBS) libartec.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_artec_la_OBJECTS = libsane_artec_la-artec-s.lo -libsane_artec_la_OBJECTS = $(nodist_libsane_artec_la_OBJECTS) -libsane_artec_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_artec_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_artec_eplus48u_la_DEPENDENCIES = $(COMMON_LIBS) \ - libartec_eplus48u.la ../sanei/sanei_init_debug.lo \ - ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo \ - ../sanei/sanei_thread.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_artec_eplus48u_la_OBJECTS = \ - libsane_artec_eplus48u_la-artec_eplus48u-s.lo -libsane_artec_eplus48u_la_OBJECTS = \ - $(nodist_libsane_artec_eplus48u_la_OBJECTS) -libsane_artec_eplus48u_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_artec_eplus48u_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_as6e_la_DEPENDENCIES = $(COMMON_LIBS) libas6e.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo -nodist_libsane_as6e_la_OBJECTS = libsane_as6e_la-as6e-s.lo -libsane_as6e_la_OBJECTS = $(nodist_libsane_as6e_la_OBJECTS) -libsane_as6e_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_as6e_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_avision_la_DEPENDENCIES = $(COMMON_LIBS) libavision.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo \ - ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_avision_la_OBJECTS = libsane_avision_la-avision-s.lo -libsane_avision_la_OBJECTS = $(nodist_libsane_avision_la_OBJECTS) -libsane_avision_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_avision_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_bh_la_DEPENDENCIES = $(COMMON_LIBS) libbh.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_bh_la_OBJECTS = libsane_bh_la-bh-s.lo -libsane_bh_la_OBJECTS = $(nodist_libsane_bh_la_OBJECTS) -libsane_bh_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libsane_bh_la_LDFLAGS) $(LDFLAGS) -o $@ -libsane_canon_la_DEPENDENCIES = $(COMMON_LIBS) libcanon.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_canon_la_OBJECTS = libsane_canon_la-canon-s.lo -libsane_canon_la_OBJECTS = $(nodist_libsane_canon_la_OBJECTS) -libsane_canon_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_canon_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_canon630u_la_DEPENDENCIES = $(COMMON_LIBS) libcanon630u.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_canon630u_la_OBJECTS = \ - libsane_canon630u_la-canon630u-s.lo -libsane_canon630u_la_OBJECTS = $(nodist_libsane_canon630u_la_OBJECTS) -libsane_canon630u_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_canon630u_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_canon_dr_la_DEPENDENCIES = $(COMMON_LIBS) libcanon_dr.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_magic.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_canon_dr_la_OBJECTS = \ - libsane_canon_dr_la-canon_dr-s.lo -libsane_canon_dr_la_OBJECTS = $(nodist_libsane_canon_dr_la_OBJECTS) -libsane_canon_dr_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_canon_dr_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_canon_pp_la_DEPENDENCIES = $(COMMON_LIBS) libcanon_pp.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) -nodist_libsane_canon_pp_la_OBJECTS = \ - libsane_canon_pp_la-canon_pp-s.lo -libsane_canon_pp_la_OBJECTS = $(nodist_libsane_canon_pp_la_OBJECTS) -libsane_canon_pp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_canon_pp_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_cardscan_la_DEPENDENCIES = $(COMMON_LIBS) libcardscan.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_cardscan_la_OBJECTS = \ - libsane_cardscan_la-cardscan-s.lo -libsane_cardscan_la_OBJECTS = $(nodist_libsane_cardscan_la_OBJECTS) -libsane_cardscan_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_cardscan_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_coolscan_la_DEPENDENCIES = $(COMMON_LIBS) libcoolscan.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_thread.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_coolscan_la_OBJECTS = \ - libsane_coolscan_la-coolscan-s.lo -libsane_coolscan_la_OBJECTS = $(nodist_libsane_coolscan_la_OBJECTS) -libsane_coolscan_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_coolscan_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_coolscan2_la_DEPENDENCIES = $(COMMON_LIBS) libcoolscan2.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_coolscan2_la_OBJECTS = \ - libsane_coolscan2_la-coolscan2-s.lo -libsane_coolscan2_la_OBJECTS = $(nodist_libsane_coolscan2_la_OBJECTS) -libsane_coolscan2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_coolscan2_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_coolscan3_la_DEPENDENCIES = $(COMMON_LIBS) libcoolscan3.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_coolscan3_la_OBJECTS = \ - libsane_coolscan3_la-coolscan3-s.lo -libsane_coolscan3_la_OBJECTS = $(nodist_libsane_coolscan3_la_OBJECTS) -libsane_coolscan3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_coolscan3_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_dc210_la_DEPENDENCIES = $(COMMON_LIBS) libdc210.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_dc210_la_OBJECTS = libsane_dc210_la-dc210-s.lo -libsane_dc210_la_OBJECTS = $(nodist_libsane_dc210_la_OBJECTS) -libsane_dc210_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_dc210_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_dc240_la_DEPENDENCIES = $(COMMON_LIBS) libdc240.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_dc240_la_OBJECTS = libsane_dc240_la-dc240-s.lo -libsane_dc240_la_OBJECTS = $(nodist_libsane_dc240_la_OBJECTS) -libsane_dc240_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_dc240_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_dc25_la_DEPENDENCIES = $(COMMON_LIBS) libdc25.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) -nodist_libsane_dc25_la_OBJECTS = libsane_dc25_la-dc25-s.lo -libsane_dc25_la_OBJECTS = $(nodist_libsane_dc25_la_OBJECTS) -libsane_dc25_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_dc25_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_dell1600n_net_la_DEPENDENCIES = $(COMMON_LIBS) \ - libdell1600n_net.la ../sanei/sanei_init_debug.lo \ - ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo \ - sane_strstatus.lo $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_dell1600n_net_la_OBJECTS = \ - libsane_dell1600n_net_la-dell1600n_net-s.lo -libsane_dell1600n_net_la_OBJECTS = \ - $(nodist_libsane_dell1600n_net_la_OBJECTS) -libsane_dell1600n_net_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_dell1600n_net_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_dll_la_DEPENDENCIES = $(COMMON_LIBS) libdll.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) -nodist_libsane_dll_la_OBJECTS = libsane_dll_la-dll-s.lo -libsane_dll_la_OBJECTS = $(nodist_libsane_dll_la_OBJECTS) -libsane_dll_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_dll_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_dmc_la_DEPENDENCIES = $(COMMON_LIBS) libdmc.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_dmc_la_OBJECTS = libsane_dmc_la-dmc-s.lo -libsane_dmc_la_OBJECTS = $(nodist_libsane_dmc_la_OBJECTS) -libsane_dmc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_dmc_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_epjitsu_la_DEPENDENCIES = $(COMMON_LIBS) libepjitsu.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_epjitsu_la_OBJECTS = libsane_epjitsu_la-epjitsu-s.lo -libsane_epjitsu_la_OBJECTS = $(nodist_libsane_epjitsu_la_OBJECTS) -libsane_epjitsu_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_epjitsu_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_epson_la_DEPENDENCIES = $(COMMON_LIBS) libepson.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_pio.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_epson_la_OBJECTS = libsane_epson_la-epson-s.lo -libsane_epson_la_OBJECTS = $(nodist_libsane_epson_la_OBJECTS) -libsane_epson_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_epson_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_epson2_la_DEPENDENCIES = $(COMMON_LIBS) libepson2.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo \ - ../sanei/sanei_udp.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_epson2_la_OBJECTS = libsane_epson2_la-epson2-s.lo -libsane_epson2_la_OBJECTS = $(nodist_libsane_epson2_la_OBJECTS) -libsane_epson2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_epson2_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_epsonds_la_DEPENDENCIES = $(COMMON_LIBS) libepsonds.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_epsonds_la_OBJECTS = libsane_epsonds_la-epsonds-s.lo -libsane_epsonds_la_OBJECTS = $(nodist_libsane_epsonds_la_OBJECTS) -libsane_epsonds_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_epsonds_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_fujitsu_la_DEPENDENCIES = $(COMMON_LIBS) libfujitsu.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_magic.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_fujitsu_la_OBJECTS = libsane_fujitsu_la-fujitsu-s.lo -libsane_fujitsu_la_OBJECTS = $(nodist_libsane_fujitsu_la_OBJECTS) -libsane_fujitsu_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_fujitsu_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_genesys_la_DEPENDENCIES = $(COMMON_LIBS) libgenesys.la \ - ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo \ - ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_genesys_la_OBJECTS = libsane_genesys_la-genesys-s.lo -libsane_genesys_la_OBJECTS = $(nodist_libsane_genesys_la_OBJECTS) -libsane_genesys_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_genesys_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_gphoto2_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(COMMON_LIBS) \ - libgphoto2_i.la ../sanei/sanei_init_debug.lo \ - ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo \ - sane_strstatus.lo $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_gphoto2_la_OBJECTS = libsane_gphoto2_la-gphoto2-s.lo -libsane_gphoto2_la_OBJECTS = $(nodist_libsane_gphoto2_la_OBJECTS) -libsane_gphoto2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_gphoto2_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_gt68xx_la_DEPENDENCIES = $(COMMON_LIBS) libgt68xx.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_gt68xx_la_OBJECTS = libsane_gt68xx_la-gt68xx-s.lo -libsane_gt68xx_la_OBJECTS = $(nodist_libsane_gt68xx_la_OBJECTS) -libsane_gt68xx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_gt68xx_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_hp_la_DEPENDENCIES = $(COMMON_LIBS) libhp.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_pio.lo ../sanei/sanei_thread.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_hp_la_OBJECTS = libsane_hp_la-hp-s.lo -libsane_hp_la_OBJECTS = $(nodist_libsane_hp_la_OBJECTS) -libsane_hp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libsane_hp_la_LDFLAGS) $(LDFLAGS) -o $@ -libsane_hp3500_la_DEPENDENCIES = $(COMMON_LIBS) libhp3500.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_hp3500_la_OBJECTS = libsane_hp3500_la-hp3500-s.lo -libsane_hp3500_la_OBJECTS = $(nodist_libsane_hp3500_la_OBJECTS) -libsane_hp3500_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_hp3500_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_hp3900_la_DEPENDENCIES = $(COMMON_LIBS) libhp3900.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_hp3900_la_OBJECTS = libsane_hp3900_la-hp3900-s.lo -libsane_hp3900_la_OBJECTS = $(nodist_libsane_hp3900_la_OBJECTS) -libsane_hp3900_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_hp3900_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_hp4200_la_DEPENDENCIES = $(COMMON_LIBS) libhp4200.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_pv8630.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_hp4200_la_OBJECTS = libsane_hp4200_la-hp4200-s.lo -libsane_hp4200_la_OBJECTS = $(nodist_libsane_hp4200_la_OBJECTS) -libsane_hp4200_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_hp4200_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_hp5400_la_DEPENDENCIES = $(COMMON_LIBS) libhp5400.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_hp5400_la_OBJECTS = libsane_hp5400_la-hp5400-s.lo -libsane_hp5400_la_OBJECTS = $(nodist_libsane_hp5400_la_OBJECTS) -libsane_hp5400_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_hp5400_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_hp5590_la_DEPENDENCIES = $(COMMON_LIBS) libhp5590.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_hp5590_la_OBJECTS = libsane_hp5590_la-hp5590-s.lo -libsane_hp5590_la_OBJECTS = $(nodist_libsane_hp5590_la_OBJECTS) -libsane_hp5590_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_hp5590_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_hpljm1005_la_DEPENDENCIES = $(COMMON_LIBS) libhpljm1005.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_hpljm1005_la_OBJECTS = \ - libsane_hpljm1005_la-hpljm1005-s.lo -libsane_hpljm1005_la_OBJECTS = $(nodist_libsane_hpljm1005_la_OBJECTS) -libsane_hpljm1005_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_hpljm1005_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_hpsj5s_la_DEPENDENCIES = $(COMMON_LIBS) libhpsj5s.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) -nodist_libsane_hpsj5s_la_OBJECTS = libsane_hpsj5s_la-hpsj5s-s.lo -libsane_hpsj5s_la_OBJECTS = $(nodist_libsane_hpsj5s_la_OBJECTS) -libsane_hpsj5s_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_hpsj5s_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_hs2p_la_DEPENDENCIES = $(COMMON_LIBS) libhs2p.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_hs2p_la_OBJECTS = libsane_hs2p_la-hs2p-s.lo -libsane_hs2p_la_OBJECTS = $(nodist_libsane_hs2p_la_OBJECTS) -libsane_hs2p_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_hs2p_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_ibm_la_DEPENDENCIES = $(COMMON_LIBS) libibm.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_ibm_la_OBJECTS = libsane_ibm_la-ibm-s.lo -libsane_ibm_la_OBJECTS = $(nodist_libsane_ibm_la_OBJECTS) -libsane_ibm_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_ibm_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_kodak_la_DEPENDENCIES = $(COMMON_LIBS) libkodak.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_kodak_la_OBJECTS = libsane_kodak_la-kodak-s.lo -libsane_kodak_la_OBJECTS = $(nodist_libsane_kodak_la_OBJECTS) -libsane_kodak_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_kodak_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_kodakaio_la_DEPENDENCIES = $(COMMON_LIBS) libkodakaio.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_kodakaio_la_OBJECTS = \ - libsane_kodakaio_la-kodakaio-s.lo -libsane_kodakaio_la_OBJECTS = $(nodist_libsane_kodakaio_la_OBJECTS) -libsane_kodakaio_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_kodakaio_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_kvs1025_la_DEPENDENCIES = $(COMMON_LIBS) libkvs1025.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_magic.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_kvs1025_la_OBJECTS = libsane_kvs1025_la-kvs1025-s.lo -libsane_kvs1025_la_OBJECTS = $(nodist_libsane_kvs1025_la_OBJECTS) -libsane_kvs1025_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_kvs1025_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_kvs20xx_la_DEPENDENCIES = $(COMMON_LIBS) libkvs20xx.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_kvs20xx_la_OBJECTS = libsane_kvs20xx_la-kvs20xx-s.lo -libsane_kvs20xx_la_OBJECTS = $(nodist_libsane_kvs20xx_la_OBJECTS) -libsane_kvs20xx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_kvs20xx_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_kvs40xx_la_DEPENDENCIES = $(COMMON_LIBS) libkvs40xx.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_kvs40xx_la_OBJECTS = libsane_kvs40xx_la-kvs40xx-s.lo -libsane_kvs40xx_la_OBJECTS = $(nodist_libsane_kvs40xx_la_OBJECTS) -libsane_kvs40xx_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_kvs40xx_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_leo_la_DEPENDENCIES = $(COMMON_LIBS) libleo.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_leo_la_OBJECTS = libsane_leo_la-leo-s.lo -libsane_leo_la_OBJECTS = $(nodist_libsane_leo_la_OBJECTS) -libsane_leo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_leo_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_lexmark_la_DEPENDENCIES = $(COMMON_LIBS) liblexmark.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_lexmark_la_OBJECTS = libsane_lexmark_la-lexmark-s.lo -libsane_lexmark_la_OBJECTS = $(nodist_libsane_lexmark_la_OBJECTS) -libsane_lexmark_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_lexmark_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_ma1509_la_DEPENDENCIES = $(COMMON_LIBS) libma1509.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_ma1509_la_OBJECTS = libsane_ma1509_la-ma1509-s.lo -libsane_ma1509_la_OBJECTS = $(nodist_libsane_ma1509_la_OBJECTS) -libsane_ma1509_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_ma1509_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_magicolor_la_DEPENDENCIES = $(COMMON_LIBS) libmagicolor.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_magicolor_la_OBJECTS = \ - libsane_magicolor_la-magicolor-s.lo -libsane_magicolor_la_OBJECTS = $(nodist_libsane_magicolor_la_OBJECTS) -libsane_magicolor_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_magicolor_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_matsushita_la_DEPENDENCIES = $(COMMON_LIBS) libmatsushita.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_matsushita_la_OBJECTS = \ - libsane_matsushita_la-matsushita-s.lo -libsane_matsushita_la_OBJECTS = \ - $(nodist_libsane_matsushita_la_OBJECTS) -libsane_matsushita_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_matsushita_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_microtek_la_DEPENDENCIES = $(COMMON_LIBS) libmicrotek.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_microtek_la_OBJECTS = \ - libsane_microtek_la-microtek-s.lo -libsane_microtek_la_OBJECTS = $(nodist_libsane_microtek_la_OBJECTS) -libsane_microtek_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_microtek_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_microtek2_la_DEPENDENCIES = $(COMMON_LIBS) libmicrotek2.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_thread.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_microtek2_la_OBJECTS = \ - libsane_microtek2_la-microtek2-s.lo -libsane_microtek2_la_OBJECTS = $(nodist_libsane_microtek2_la_OBJECTS) -libsane_microtek2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_microtek2_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_mustek_la_DEPENDENCIES = $(COMMON_LIBS) libmustek.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_thread.lo ../sanei/sanei_ab306.lo \ - ../sanei/sanei_pa4s2.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_mustek_la_OBJECTS = libsane_mustek_la-mustek-s.lo -libsane_mustek_la_OBJECTS = $(nodist_libsane_mustek_la_OBJECTS) -libsane_mustek_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_mustek_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_mustek_pp_la_DEPENDENCIES = $(COMMON_LIBS) libmustek_pp.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_pa4s2.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_mustek_pp_la_OBJECTS = \ - libsane_mustek_pp_la-mustek_pp-s.lo -libsane_mustek_pp_la_OBJECTS = $(nodist_libsane_mustek_pp_la_OBJECTS) -libsane_mustek_pp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_mustek_pp_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_mustek_usb_la_DEPENDENCIES = $(COMMON_LIBS) libmustek_usb.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_mustek_usb_la_OBJECTS = \ - libsane_mustek_usb_la-mustek_usb-s.lo -libsane_mustek_usb_la_OBJECTS = \ - $(nodist_libsane_mustek_usb_la_OBJECTS) -libsane_mustek_usb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_mustek_usb_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_mustek_usb2_la_DEPENDENCIES = $(COMMON_LIBS) libmustek_usb2.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_mustek_usb2_la_OBJECTS = \ - libsane_mustek_usb2_la-mustek_usb2-s.lo -libsane_mustek_usb2_la_OBJECTS = \ - $(nodist_libsane_mustek_usb2_la_OBJECTS) -libsane_mustek_usb2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_mustek_usb2_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_nec_la_DEPENDENCIES = $(COMMON_LIBS) libnec.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_nec_la_OBJECTS = libsane_nec_la-nec-s.lo -libsane_nec_la_OBJECTS = $(nodist_libsane_nec_la_OBJECTS) -libsane_nec_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_nec_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_net_la_DEPENDENCIES = $(COMMON_LIBS) libnet.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_net.lo ../sanei/sanei_wire.lo \ - ../sanei/sanei_codec_bin.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_net_la_OBJECTS = libsane_net_la-net-s.lo -libsane_net_la_OBJECTS = $(nodist_libsane_net_la_OBJECTS) -libsane_net_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_net_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_niash_la_DEPENDENCIES = $(COMMON_LIBS) libniash.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_niash_la_OBJECTS = libsane_niash_la-niash-s.lo -libsane_niash_la_OBJECTS = $(nodist_libsane_niash_la_OBJECTS) -libsane_niash_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_niash_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_p5_la_DEPENDENCIES = $(COMMON_LIBS) libp5.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo -nodist_libsane_p5_la_OBJECTS = libsane_p5_la-p5-s.lo -libsane_p5_la_OBJECTS = $(nodist_libsane_p5_la_OBJECTS) -libsane_p5_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libsane_p5_la_LDFLAGS) $(LDFLAGS) -o $@ -libsane_pie_la_DEPENDENCIES = $(COMMON_LIBS) libpie.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_thread.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_pie_la_OBJECTS = libsane_pie_la-pie-s.lo -libsane_pie_la_OBJECTS = $(nodist_libsane_pie_la_OBJECTS) -libsane_pie_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_pie_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_pieusb_la_DEPENDENCIES = $(COMMON_LIBS) libpieusb.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo \ - ../sanei/sanei_ir.lo ../sanei/sanei_magic.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_pieusb_la_OBJECTS = libsane_pieusb_la-pieusb-s.lo -libsane_pieusb_la_OBJECTS = $(nodist_libsane_pieusb_la_OBJECTS) -libsane_pieusb_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_pieusb_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_pint_la_DEPENDENCIES = $(COMMON_LIBS) libpint.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo -nodist_libsane_pint_la_OBJECTS = libsane_pint_la-pint-s.lo -libsane_pint_la_OBJECTS = $(nodist_libsane_pint_la_OBJECTS) -libsane_pint_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_pint_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_pixma_la_DEPENDENCIES = $(COMMON_LIBS) libpixma.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_pixma_la_OBJECTS = libsane_pixma_la-pixma-s.lo -libsane_pixma_la_OBJECTS = $(nodist_libsane_pixma_la_OBJECTS) -libsane_pixma_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_pixma_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_plustek_la_DEPENDENCIES = $(COMMON_LIBS) libplustek.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo \ - ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_plustek_la_OBJECTS = libsane_plustek_la-plustek-s.lo -libsane_plustek_la_OBJECTS = $(nodist_libsane_plustek_la_OBJECTS) -libsane_plustek_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_plustek_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_plustek_pp_la_DEPENDENCIES = $(COMMON_LIBS) libplustek_pp.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_plustek_pp_la_OBJECTS = \ - libsane_plustek_pp_la-plustek_pp-s.lo -libsane_plustek_pp_la_OBJECTS = \ - $(nodist_libsane_plustek_pp_la_OBJECTS) -libsane_plustek_pp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_plustek_pp_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_pnm_la_DEPENDENCIES = $(COMMON_LIBS) libpnm.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo -nodist_libsane_pnm_la_OBJECTS = libsane_pnm_la-pnm-s.lo -libsane_pnm_la_OBJECTS = $(nodist_libsane_pnm_la_OBJECTS) -libsane_pnm_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_pnm_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_qcam_la_DEPENDENCIES = $(COMMON_LIBS) libqcam.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_pio.lo -nodist_libsane_qcam_la_OBJECTS = libsane_qcam_la-qcam-s.lo -libsane_qcam_la_OBJECTS = $(nodist_libsane_qcam_la_OBJECTS) -libsane_qcam_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_qcam_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_ricoh_la_DEPENDENCIES = $(COMMON_LIBS) libricoh.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_ricoh_la_OBJECTS = libsane_ricoh_la-ricoh-s.lo -libsane_ricoh_la_OBJECTS = $(nodist_libsane_ricoh_la_OBJECTS) -libsane_ricoh_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_ricoh_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_rts8891_la_DEPENDENCIES = $(COMMON_LIBS) librts8891.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_scsi.lo ../sanei/sanei_usb.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_rts8891_la_OBJECTS = libsane_rts8891_la-rts8891-s.lo -libsane_rts8891_la_OBJECTS = $(nodist_libsane_rts8891_la_OBJECTS) -libsane_rts8891_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_rts8891_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_s9036_la_DEPENDENCIES = $(COMMON_LIBS) libs9036.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_s9036_la_OBJECTS = libsane_s9036_la-s9036-s.lo -libsane_s9036_la_OBJECTS = $(nodist_libsane_s9036_la_OBJECTS) -libsane_s9036_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_s9036_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_sceptre_la_DEPENDENCIES = $(COMMON_LIBS) libsceptre.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_sceptre_la_OBJECTS = libsane_sceptre_la-sceptre-s.lo -libsane_sceptre_la_OBJECTS = $(nodist_libsane_sceptre_la_OBJECTS) -libsane_sceptre_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_sceptre_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_sharp_la_DEPENDENCIES = $(COMMON_LIBS) libsharp.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_sharp_la_OBJECTS = libsane_sharp_la-sharp-s.lo -libsane_sharp_la_OBJECTS = $(nodist_libsane_sharp_la_OBJECTS) -libsane_sharp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_sharp_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_sm3600_la_DEPENDENCIES = $(COMMON_LIBS) libsm3600.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_sm3600_la_OBJECTS = libsane_sm3600_la-sm3600-s.lo -libsane_sm3600_la_OBJECTS = $(nodist_libsane_sm3600_la_OBJECTS) -libsane_sm3600_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_sm3600_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_sm3840_la_DEPENDENCIES = $(COMMON_LIBS) libsm3840.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_sm3840_la_OBJECTS = libsane_sm3840_la-sm3840-s.lo -libsane_sm3840_la_OBJECTS = $(nodist_libsane_sm3840_la_OBJECTS) -libsane_sm3840_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_sm3840_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_snapscan_la_DEPENDENCIES = $(COMMON_LIBS) libsnapscan.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo \ - ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_snapscan_la_OBJECTS = \ - libsane_snapscan_la-snapscan-s.lo -libsane_snapscan_la_OBJECTS = $(nodist_libsane_snapscan_la_OBJECTS) -libsane_snapscan_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_snapscan_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_sp15c_la_DEPENDENCIES = $(COMMON_LIBS) libsp15c.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_thread.lo \ - ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_sp15c_la_OBJECTS = libsane_sp15c_la-sp15c-s.lo -libsane_sp15c_la_OBJECTS = $(nodist_libsane_sp15c_la_OBJECTS) -libsane_sp15c_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_sp15c_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_st400_la_DEPENDENCIES = $(COMMON_LIBS) libst400.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_st400_la_OBJECTS = libsane_st400_la-st400-s.lo -libsane_st400_la_OBJECTS = $(nodist_libsane_st400_la_OBJECTS) -libsane_st400_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_st400_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_stv680_la_DEPENDENCIES = $(COMMON_LIBS) libstv680.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_stv680_la_OBJECTS = libsane_stv680_la-stv680-s.lo -libsane_stv680_la_OBJECTS = $(nodist_libsane_stv680_la_OBJECTS) -libsane_stv680_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_stv680_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_tamarack_la_DEPENDENCIES = $(COMMON_LIBS) libtamarack.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_thread.lo \ - ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_tamarack_la_OBJECTS = \ - libsane_tamarack_la-tamarack-s.lo -libsane_tamarack_la_OBJECTS = $(nodist_libsane_tamarack_la_OBJECTS) -libsane_tamarack_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_tamarack_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_teco1_la_DEPENDENCIES = $(COMMON_LIBS) libteco1.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_teco1_la_OBJECTS = libsane_teco1_la-teco1-s.lo -libsane_teco1_la_OBJECTS = $(nodist_libsane_teco1_la_OBJECTS) -libsane_teco1_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_teco1_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_teco2_la_DEPENDENCIES = $(COMMON_LIBS) libteco2.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_teco2_la_OBJECTS = libsane_teco2_la-teco2-s.lo -libsane_teco2_la_OBJECTS = $(nodist_libsane_teco2_la_OBJECTS) -libsane_teco2_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_teco2_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_teco3_la_DEPENDENCIES = $(COMMON_LIBS) libteco3.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_scsi.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_teco3_la_OBJECTS = libsane_teco3_la-teco3-s.lo -libsane_teco3_la_OBJECTS = $(nodist_libsane_teco3_la_OBJECTS) -libsane_teco3_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_teco3_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_test_la_DEPENDENCIES = $(COMMON_LIBS) libtest.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_thread.lo $(am__DEPENDENCIES_1) -nodist_libsane_test_la_OBJECTS = libsane_test_la-test-s.lo -libsane_test_la_OBJECTS = $(nodist_libsane_test_la_OBJECTS) -libsane_test_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_test_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_u12_la_DEPENDENCIES = $(COMMON_LIBS) libu12.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_u12_la_OBJECTS = libsane_u12_la-u12-s.lo -libsane_u12_la_OBJECTS = $(nodist_libsane_u12_la_OBJECTS) -libsane_u12_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_u12_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_umax_la_DEPENDENCIES = $(COMMON_LIBS) libumax.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo \ - sane_strstatus.lo ../sanei/sanei_usb.lo \ - ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_pv8630.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -nodist_libsane_umax_la_OBJECTS = libsane_umax_la-umax-s.lo -libsane_umax_la_OBJECTS = $(nodist_libsane_umax_la_OBJECTS) -libsane_umax_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_umax_la_LDFLAGS) $(LDFLAGS) \ - -o $@ -libsane_umax1220u_la_DEPENDENCIES = $(COMMON_LIBS) libumax1220u.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_pv8630.lo \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_umax1220u_la_OBJECTS = \ - libsane_umax1220u_la-umax1220u-s.lo -libsane_umax1220u_la_OBJECTS = $(nodist_libsane_umax1220u_la_OBJECTS) -libsane_umax1220u_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_umax1220u_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_umax_pp_la_DEPENDENCIES = $(COMMON_LIBS) libumax_pp.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) -nodist_libsane_umax_pp_la_OBJECTS = libsane_umax_pp_la-umax_pp-s.lo -libsane_umax_pp_la_OBJECTS = $(nodist_libsane_umax_pp_la_OBJECTS) -libsane_umax_pp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_umax_pp_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -libsane_v4l_la_DEPENDENCIES = $(COMMON_LIBS) libv4l.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) -nodist_libsane_v4l_la_OBJECTS = libsane_v4l_la-v4l-s.lo -libsane_v4l_la_OBJECTS = $(nodist_libsane_v4l_la_OBJECTS) -libsane_v4l_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_v4l_la_LDFLAGS) $(LDFLAGS) -o \ - $@ -libsane_xerox_mfp_la_DEPENDENCIES = $(COMMON_LIBS) libxerox_mfp.la \ - ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo sane_strstatus.lo \ - $(am__DEPENDENCIES_1) ../sanei/sanei_usb.lo \ - ../sanei/sanei_tcp.lo $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -nodist_libsane_xerox_mfp_la_OBJECTS = \ - libsane_xerox_mfp_la-xerox_mfp-s.lo -libsane_xerox_mfp_la_OBJECTS = $(nodist_libsane_xerox_mfp_la_OBJECTS) -libsane_xerox_mfp_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ - $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ - $(AM_CFLAGS) $(CFLAGS) $(libsane_xerox_mfp_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -nodist_libsane_la_OBJECTS = libsane_la-dll-s.lo -libsane_la_OBJECTS = $(nodist_libsane_la_OBJECTS) -libsane_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(libsane_la_LDFLAGS) $(LDFLAGS) -o $@ -libsceptre_la_LIBADD = -am_libsceptre_la_OBJECTS = libsceptre_la-sceptre.lo -libsceptre_la_OBJECTS = $(am_libsceptre_la_OBJECTS) -libsharp_la_LIBADD = -am_libsharp_la_OBJECTS = libsharp_la-sharp.lo -libsharp_la_OBJECTS = $(am_libsharp_la_OBJECTS) -libsm3600_la_LIBADD = -am_libsm3600_la_OBJECTS = libsm3600_la-sm3600.lo -libsm3600_la_OBJECTS = $(am_libsm3600_la_OBJECTS) -libsm3840_la_LIBADD = -am_libsm3840_la_OBJECTS = libsm3840_la-sm3840.lo -libsm3840_la_OBJECTS = $(am_libsm3840_la_OBJECTS) -libsnapscan_la_LIBADD = -am_libsnapscan_la_OBJECTS = libsnapscan_la-snapscan.lo -libsnapscan_la_OBJECTS = $(am_libsnapscan_la_OBJECTS) -libsp15c_la_LIBADD = -am_libsp15c_la_OBJECTS = libsp15c_la-sp15c.lo -libsp15c_la_OBJECTS = $(am_libsp15c_la_OBJECTS) -libst400_la_LIBADD = -am_libst400_la_OBJECTS = libst400_la-st400.lo -libst400_la_OBJECTS = $(am_libst400_la_OBJECTS) -libstv680_la_LIBADD = -am_libstv680_la_OBJECTS = libstv680_la-stv680.lo -libstv680_la_OBJECTS = $(am_libstv680_la_OBJECTS) -libtamarack_la_LIBADD = -am_libtamarack_la_OBJECTS = libtamarack_la-tamarack.lo -libtamarack_la_OBJECTS = $(am_libtamarack_la_OBJECTS) -libteco1_la_LIBADD = -am_libteco1_la_OBJECTS = libteco1_la-teco1.lo -libteco1_la_OBJECTS = $(am_libteco1_la_OBJECTS) -libteco2_la_LIBADD = -am_libteco2_la_OBJECTS = libteco2_la-teco2.lo -libteco2_la_OBJECTS = $(am_libteco2_la_OBJECTS) -libteco3_la_LIBADD = -am_libteco3_la_OBJECTS = libteco3_la-teco3.lo -libteco3_la_OBJECTS = $(am_libteco3_la_OBJECTS) -libtest_la_LIBADD = -am_libtest_la_OBJECTS = libtest_la-test.lo -libtest_la_OBJECTS = $(am_libtest_la_OBJECTS) -libu12_la_LIBADD = -am_libu12_la_OBJECTS = libu12_la-u12.lo -libu12_la_OBJECTS = $(am_libu12_la_OBJECTS) -libumax_la_LIBADD = -am_libumax_la_OBJECTS = libumax_la-umax.lo -libumax_la_OBJECTS = $(am_libumax_la_OBJECTS) -libumax1220u_la_LIBADD = -am_libumax1220u_la_OBJECTS = libumax1220u_la-umax1220u.lo -libumax1220u_la_OBJECTS = $(am_libumax1220u_la_OBJECTS) -libumax_pp_la_LIBADD = -am_libumax_pp_la_OBJECTS = libumax_pp_la-umax_pp.lo \ - libumax_pp_la-umax_pp_low.lo libumax_pp_la-umax_pp_mid.lo -libumax_pp_la_OBJECTS = $(am_libumax_pp_la_OBJECTS) -libv4l_la_LIBADD = -am_libv4l_la_OBJECTS = libv4l_la-v4l.lo -libv4l_la_OBJECTS = $(am_libv4l_la_OBJECTS) -libxerox_mfp_la_LIBADD = -am_libxerox_mfp_la_OBJECTS = libxerox_mfp_la-xerox_mfp.lo \ - libxerox_mfp_la-xerox_mfp-usb.lo \ - libxerox_mfp_la-xerox_mfp-tcp.lo -libxerox_mfp_la_OBJECTS = $(am_libxerox_mfp_la_OBJECTS) -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/include/sane -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(libabaton_la_SOURCES) $(libagfafocus_la_SOURCES) \ - $(libapple_la_SOURCES) $(libartec_la_SOURCES) \ - $(libartec_eplus48u_la_SOURCES) $(libas6e_la_SOURCES) \ - $(libavision_la_SOURCES) $(libbh_la_SOURCES) \ - $(libcanon_la_SOURCES) $(libcanon630u_la_SOURCES) \ - $(libcanon_dr_la_SOURCES) $(libcanon_pp_la_SOURCES) \ - $(libcardscan_la_SOURCES) $(libcoolscan_la_SOURCES) \ - $(libcoolscan2_la_SOURCES) $(libcoolscan3_la_SOURCES) \ - $(libdc210_la_SOURCES) $(libdc240_la_SOURCES) \ - $(libdc25_la_SOURCES) $(libdell1600n_net_la_SOURCES) \ - $(libdll_la_SOURCES) $(libdll_preload_la_SOURCES) \ - $(libdmc_la_SOURCES) $(libepjitsu_la_SOURCES) \ - $(libepson_la_SOURCES) $(libepson2_la_SOURCES) \ - $(libepsonds_la_SOURCES) $(libfujitsu_la_SOURCES) \ - $(libgenesys_la_SOURCES) $(libgphoto2_i_la_SOURCES) \ - $(libgt68xx_la_SOURCES) $(libhp_la_SOURCES) \ - $(libhp3500_la_SOURCES) $(libhp3900_la_SOURCES) \ - $(libhp4200_la_SOURCES) $(libhp5400_la_SOURCES) \ - $(libhp5590_la_SOURCES) $(libhpljm1005_la_SOURCES) \ - $(libhpsj5s_la_SOURCES) $(libhs2p_la_SOURCES) \ - $(libibm_la_SOURCES) $(libkodak_la_SOURCES) \ - $(libkodakaio_la_SOURCES) $(libkvs1025_la_SOURCES) \ - $(libkvs20xx_la_SOURCES) $(libkvs40xx_la_SOURCES) \ - $(libleo_la_SOURCES) $(liblexmark_la_SOURCES) \ - $(libma1509_la_SOURCES) $(libmagicolor_la_SOURCES) \ - $(libmatsushita_la_SOURCES) $(libmicrotek_la_SOURCES) \ - $(libmicrotek2_la_SOURCES) $(libmustek_la_SOURCES) \ - $(libmustek_pp_la_SOURCES) $(libmustek_usb_la_SOURCES) \ - $(libmustek_usb2_la_SOURCES) $(libnec_la_SOURCES) \ - $(libnet_la_SOURCES) $(libniash_la_SOURCES) \ - $(libp5_la_SOURCES) $(libpie_la_SOURCES) \ - $(libpieusb_la_SOURCES) $(libpint_la_SOURCES) \ - $(libpixma_la_SOURCES) $(libplustek_la_SOURCES) \ - $(libplustek_pp_la_SOURCES) $(libpnm_la_SOURCES) \ - $(libqcam_la_SOURCES) $(libricoh_la_SOURCES) \ - $(librts8891_la_SOURCES) $(libs9036_la_SOURCES) \ - $(nodist_libsane_abaton_la_SOURCES) \ - $(nodist_libsane_agfafocus_la_SOURCES) \ - $(nodist_libsane_apple_la_SOURCES) \ - $(nodist_libsane_artec_la_SOURCES) \ - $(nodist_libsane_artec_eplus48u_la_SOURCES) \ - $(nodist_libsane_as6e_la_SOURCES) \ - $(nodist_libsane_avision_la_SOURCES) \ - $(nodist_libsane_bh_la_SOURCES) \ - $(nodist_libsane_canon_la_SOURCES) \ - $(nodist_libsane_canon630u_la_SOURCES) \ - $(nodist_libsane_canon_dr_la_SOURCES) \ - $(nodist_libsane_canon_pp_la_SOURCES) \ - $(nodist_libsane_cardscan_la_SOURCES) \ - $(nodist_libsane_coolscan_la_SOURCES) \ - $(nodist_libsane_coolscan2_la_SOURCES) \ - $(nodist_libsane_coolscan3_la_SOURCES) \ - $(nodist_libsane_dc210_la_SOURCES) \ - $(nodist_libsane_dc240_la_SOURCES) \ - $(nodist_libsane_dc25_la_SOURCES) \ - $(nodist_libsane_dell1600n_net_la_SOURCES) \ - $(nodist_libsane_dll_la_SOURCES) \ - $(nodist_libsane_dmc_la_SOURCES) \ - $(nodist_libsane_epjitsu_la_SOURCES) \ - $(nodist_libsane_epson_la_SOURCES) \ - $(nodist_libsane_epson2_la_SOURCES) \ - $(nodist_libsane_epsonds_la_SOURCES) \ - $(nodist_libsane_fujitsu_la_SOURCES) \ - $(nodist_libsane_genesys_la_SOURCES) \ - $(nodist_libsane_gphoto2_la_SOURCES) \ - $(nodist_libsane_gt68xx_la_SOURCES) \ - $(nodist_libsane_hp_la_SOURCES) \ - $(nodist_libsane_hp3500_la_SOURCES) \ - $(nodist_libsane_hp3900_la_SOURCES) \ - $(nodist_libsane_hp4200_la_SOURCES) \ - $(nodist_libsane_hp5400_la_SOURCES) \ - $(nodist_libsane_hp5590_la_SOURCES) \ - $(nodist_libsane_hpljm1005_la_SOURCES) \ - $(nodist_libsane_hpsj5s_la_SOURCES) \ - $(nodist_libsane_hs2p_la_SOURCES) \ - $(nodist_libsane_ibm_la_SOURCES) \ - $(nodist_libsane_kodak_la_SOURCES) \ - $(nodist_libsane_kodakaio_la_SOURCES) \ - $(nodist_libsane_kvs1025_la_SOURCES) \ - $(nodist_libsane_kvs20xx_la_SOURCES) \ - $(nodist_libsane_kvs40xx_la_SOURCES) \ - $(nodist_libsane_leo_la_SOURCES) \ - $(nodist_libsane_lexmark_la_SOURCES) \ - $(nodist_libsane_ma1509_la_SOURCES) \ - $(nodist_libsane_magicolor_la_SOURCES) \ - $(nodist_libsane_matsushita_la_SOURCES) \ - $(nodist_libsane_microtek_la_SOURCES) \ - $(nodist_libsane_microtek2_la_SOURCES) \ - $(nodist_libsane_mustek_la_SOURCES) \ - $(nodist_libsane_mustek_pp_la_SOURCES) \ - $(nodist_libsane_mustek_usb_la_SOURCES) \ - $(nodist_libsane_mustek_usb2_la_SOURCES) \ - $(nodist_libsane_nec_la_SOURCES) \ - $(nodist_libsane_net_la_SOURCES) \ - $(nodist_libsane_niash_la_SOURCES) \ - $(nodist_libsane_p5_la_SOURCES) \ - $(nodist_libsane_pie_la_SOURCES) \ - $(nodist_libsane_pieusb_la_SOURCES) \ - $(nodist_libsane_pint_la_SOURCES) \ - $(nodist_libsane_pixma_la_SOURCES) \ - $(nodist_libsane_plustek_la_SOURCES) \ - $(nodist_libsane_plustek_pp_la_SOURCES) \ - $(nodist_libsane_pnm_la_SOURCES) \ - $(nodist_libsane_qcam_la_SOURCES) \ - $(nodist_libsane_ricoh_la_SOURCES) \ - $(nodist_libsane_rts8891_la_SOURCES) \ - $(nodist_libsane_s9036_la_SOURCES) \ - $(nodist_libsane_sceptre_la_SOURCES) \ - $(nodist_libsane_sharp_la_SOURCES) \ - $(nodist_libsane_sm3600_la_SOURCES) \ - $(nodist_libsane_sm3840_la_SOURCES) \ - $(nodist_libsane_snapscan_la_SOURCES) \ - $(nodist_libsane_sp15c_la_SOURCES) \ - $(nodist_libsane_st400_la_SOURCES) \ - $(nodist_libsane_stv680_la_SOURCES) \ - $(nodist_libsane_tamarack_la_SOURCES) \ - $(nodist_libsane_teco1_la_SOURCES) \ - $(nodist_libsane_teco2_la_SOURCES) \ - $(nodist_libsane_teco3_la_SOURCES) \ - $(nodist_libsane_test_la_SOURCES) \ - $(nodist_libsane_u12_la_SOURCES) \ - $(nodist_libsane_umax_la_SOURCES) \ - $(nodist_libsane_umax1220u_la_SOURCES) \ - $(nodist_libsane_umax_pp_la_SOURCES) \ - $(nodist_libsane_v4l_la_SOURCES) \ - $(nodist_libsane_xerox_mfp_la_SOURCES) \ - $(nodist_libsane_la_SOURCES) $(libsceptre_la_SOURCES) \ - $(libsharp_la_SOURCES) $(libsm3600_la_SOURCES) \ - $(libsm3840_la_SOURCES) $(libsnapscan_la_SOURCES) \ - $(libsp15c_la_SOURCES) $(libst400_la_SOURCES) \ - $(libstv680_la_SOURCES) $(libtamarack_la_SOURCES) \ - $(libteco1_la_SOURCES) $(libteco2_la_SOURCES) \ - $(libteco3_la_SOURCES) $(libtest_la_SOURCES) \ - $(libu12_la_SOURCES) $(libumax_la_SOURCES) \ - $(libumax1220u_la_SOURCES) $(libumax_pp_la_SOURCES) \ - $(libv4l_la_SOURCES) $(libxerox_mfp_la_SOURCES) -DIST_SOURCES = $(libabaton_la_SOURCES) $(libagfafocus_la_SOURCES) \ - $(libapple_la_SOURCES) $(libartec_la_SOURCES) \ - $(libartec_eplus48u_la_SOURCES) $(libas6e_la_SOURCES) \ - $(libavision_la_SOURCES) $(libbh_la_SOURCES) \ - $(libcanon_la_SOURCES) $(libcanon630u_la_SOURCES) \ - $(libcanon_dr_la_SOURCES) $(libcanon_pp_la_SOURCES) \ - $(libcardscan_la_SOURCES) $(libcoolscan_la_SOURCES) \ - $(libcoolscan2_la_SOURCES) $(libcoolscan3_la_SOURCES) \ - $(libdc210_la_SOURCES) $(libdc240_la_SOURCES) \ - $(libdc25_la_SOURCES) $(libdell1600n_net_la_SOURCES) \ - $(libdll_la_SOURCES) $(libdll_preload_la_SOURCES) \ - $(libdmc_la_SOURCES) $(libepjitsu_la_SOURCES) \ - $(libepson_la_SOURCES) $(libepson2_la_SOURCES) \ - $(libepsonds_la_SOURCES) $(libfujitsu_la_SOURCES) \ - $(libgenesys_la_SOURCES) $(libgphoto2_i_la_SOURCES) \ - $(libgt68xx_la_SOURCES) $(libhp_la_SOURCES) \ - $(libhp3500_la_SOURCES) $(libhp3900_la_SOURCES) \ - $(libhp4200_la_SOURCES) $(libhp5400_la_SOURCES) \ - $(libhp5590_la_SOURCES) $(libhpljm1005_la_SOURCES) \ - $(libhpsj5s_la_SOURCES) $(libhs2p_la_SOURCES) \ - $(libibm_la_SOURCES) $(libkodak_la_SOURCES) \ - $(libkodakaio_la_SOURCES) $(libkvs1025_la_SOURCES) \ - $(libkvs20xx_la_SOURCES) $(libkvs40xx_la_SOURCES) \ - $(libleo_la_SOURCES) $(liblexmark_la_SOURCES) \ - $(libma1509_la_SOURCES) $(libmagicolor_la_SOURCES) \ - $(libmatsushita_la_SOURCES) $(libmicrotek_la_SOURCES) \ - $(libmicrotek2_la_SOURCES) $(libmustek_la_SOURCES) \ - $(libmustek_pp_la_SOURCES) $(libmustek_usb_la_SOURCES) \ - $(libmustek_usb2_la_SOURCES) $(libnec_la_SOURCES) \ - $(libnet_la_SOURCES) $(libniash_la_SOURCES) \ - $(libp5_la_SOURCES) $(libpie_la_SOURCES) \ - $(libpieusb_la_SOURCES) $(libpint_la_SOURCES) \ - $(libpixma_la_SOURCES) $(libplustek_la_SOURCES) \ - $(libplustek_pp_la_SOURCES) $(libpnm_la_SOURCES) \ - $(libqcam_la_SOURCES) $(libricoh_la_SOURCES) \ - $(librts8891_la_SOURCES) $(libs9036_la_SOURCES) \ - $(libsceptre_la_SOURCES) $(libsharp_la_SOURCES) \ - $(libsm3600_la_SOURCES) $(libsm3840_la_SOURCES) \ - $(libsnapscan_la_SOURCES) $(libsp15c_la_SOURCES) \ - $(libst400_la_SOURCES) $(libstv680_la_SOURCES) \ - $(libtamarack_la_SOURCES) $(libteco1_la_SOURCES) \ - $(libteco2_la_SOURCES) $(libteco3_la_SOURCES) \ - $(libtest_la_SOURCES) $(libu12_la_SOURCES) \ - $(libumax_la_SOURCES) $(libumax1220u_la_SOURCES) \ - $(libumax_pp_la_SOURCES) $(libv4l_la_SOURCES) \ - $(libxerox_mfp_la_SOURCES) -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ALLOCA = @ALLOCA@ -AMTAR = @AMTAR@ -AM_CFLAGS = @AM_CFLAGS@ -AM_CPPFLAGS = @AM_CPPFLAGS@ -I. -I$(srcdir) -I$(top_builddir)/include \ - -I$(top_srcdir)/include $(USB_CFLAGS) \ - -DLIBDIR="\"$(libdir)/sane\"" -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AM_LDFLAGS = @AM_LDFLAGS@ $(STRICT_LDFLAGS) -AR = @AR@ -AS = @AS@ -AUTOCONF = @AUTOCONF@ -AUTOHEADER = @AUTOHEADER@ -AUTOMAKE = @AUTOMAKE@ -AVAHI_CFLAGS = @AVAHI_CFLAGS@ -AVAHI_LIBS = @AVAHI_LIBS@ -AWK = @AWK@ -BACKENDS = @BACKENDS@ -BACKEND_CONFS_ENABLED = @BACKEND_CONFS_ENABLED@ -BACKEND_LIBS_ENABLED = @BACKEND_LIBS_ENABLED@ -BACKEND_MANS_ENABLED = @BACKEND_MANS_ENABLED@ -CC = @CC@ -CCDEPMODE = @CCDEPMODE@ -CFLAGS = @CFLAGS@ -CPP = @CPP@ -CPPFLAGS = @CPPFLAGS@ -CYGPATH_W = @CYGPATH_W@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLH = @DLH@ -DLLTOOL = @DLLTOOL@ -DL_LIBS = @DL_LIBS@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -DVIPS = @DVIPS@ -DYNAMIC_FLAG = @DYNAMIC_FLAG@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -EXEEXT = @EXEEXT@ -FGREP = @FGREP@ -FIG2DEV = @FIG2DEV@ -GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ -GMSGFMT = @GMSGFMT@ -GMSGFMT_015 = @GMSGFMT_015@ -GPHOTO2_CPPFLAGS = @GPHOTO2_CPPFLAGS@ -GPHOTO2_LDFLAGS = @GPHOTO2_LDFLAGS@ -GPHOTO2_LIBS = @GPHOTO2_LIBS@ -GREP = @GREP@ -GS = @GS@ -HAVE_GPHOTO2 = @HAVE_GPHOTO2@ -IEEE1284_LIBS = @IEEE1284_LIBS@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_LOCKPATH = @INSTALL_LOCKPATH@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ -INTLLIBS = @INTLLIBS@ -INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ -JPEG_LIBS = @JPEG_LIBS@ -LATEX = @LATEX@ -LD = @LD@ -LDFLAGS = @LDFLAGS@ -LIBICONV = @LIBICONV@ -LIBINTL = @LIBINTL@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ - -# LIBTOOL install is a little to noisy for my liking. -LIBTOOL = @LIBTOOL@ --silent -LIBV4L_CFLAGS = @LIBV4L_CFLAGS@ -LIBV4L_LIBS = @LIBV4L_LIBS@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LOCKPATH_GROUP = @LOCKPATH_GROUP@ -LTALLOCA = @LTALLOCA@ -LTLIBICONV = @LTLIBICONV@ -LTLIBINTL = @LTLIBINTL@ -LTLIBOBJS = @LTLIBOBJS@ -MAINT = @MAINT@ -MAKEINDEX = @MAKEINDEX@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MATH_LIB = @MATH_LIB@ -MKDIR_P = @MKDIR_P@ -MSGFMT = @MSGFMT@ -MSGFMT_015 = @MSGFMT_015@ -MSGMERGE = @MSGMERGE@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PDFLATEX = @PDFLATEX@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PNG_LIBS = @PNG_LIBS@ -POSUB = @POSUB@ -PPMTOGIF = @PPMTOGIF@ -PRELOADABLE_BACKENDS = @PRELOADABLE_BACKENDS@ -PRELOADABLE_BACKENDS_ENABLED = @PRELOADABLE_BACKENDS_ENABLED@ -PTHREAD_LIBS = @PTHREAD_LIBS@ -RANLIB = @RANLIB@ -RESMGR_LIBS = @RESMGR_LIBS@ -SANEI_SANEI_JPEG_LO = @SANEI_SANEI_JPEG_LO@ -SANE_CONFIG_PATH = @SANE_CONFIG_PATH@ -SCSI_LIBS = @SCSI_LIBS@ -SED = @SED@ -SET_MAKE = @SET_MAKE@ -SHELL = @SHELL@ -SNMP_CFLAGS = @SNMP_CFLAGS@ -SNMP_CONFIG_PATH = @SNMP_CONFIG_PATH@ -SNMP_LIBS = @SNMP_LIBS@ -SOCKET_LIBS = @SOCKET_LIBS@ -STRICT_LDFLAGS = @STRICT_LDFLAGS@ -STRIP = @STRIP@ -SYSLOG_LIBS = @SYSLOG_LIBS@ -SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@ -SYSTEMD_LIBS = @SYSTEMD_LIBS@ -TIFF_LIBS = @TIFF_LIBS@ -USB_CFLAGS = @USB_CFLAGS@ -USB_LIBS = @USB_LIBS@ -USE_NLS = @USE_NLS@ -VERSION = @VERSION@ -V_MAJOR = @V_MAJOR@ -V_MINOR = @V_MINOR@ -V_REV = @V_REV@ -XGETTEXT = @XGETTEXT@ -XGETTEXT_015 = @XGETTEXT_015@ -XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ -abs_builddir = @abs_builddir@ -abs_srcdir = @abs_srcdir@ -abs_top_builddir = @abs_top_builddir@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -configdir = @configdir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -effective_target = @effective_target@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -locksanedir = @locksanedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -# The -rpath option is added because we are creating _LTLIBRARIES based -# on configure substitution. This causes automake to not know the -# correct $libdir and must be added here. -DIST_SANELIBS_LDFLAGS = $(AM_LDFLAGS) -rpath '$(libdir)/sane' -version-number $(V_MAJOR):$(V_MINOR):$(V_REV) $(DYNAMIC_FLAG) -DIST_LIBS_LDFLAGS = $(AM_LDFLAGS) -rpath '$(libdir)' -version-number $(V_MAJOR):$(V_MINOR):$(V_REV) -FIRMWARE_DIRS = artec_eplus48u gt68xx snapscan epjitsu - -# TODO: This really belongs together with the saned sources and -# should be installed there as well. -# TODO: Why are these distributed but not compiled? -# TODO: Why are this distributed but not compiled? -# TODO: Why are this distributed but not compiled? -# TODO: Why are this distributed but not compiled? -# TODO: These should be moved to ../docs/hp; don't belong here. -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why are these distributed but not compiled? -# TODO: Why is this distributed but not installed? -EXTRA_DIST = sane_strstatus.c stubs.c saned.conf.in abaton.conf.in \ - agfafocus.conf.in apple.conf.in artec.conf.in \ - artec_eplus48u.conf.in avision.conf.in bh.conf.in \ - canon.conf.in canon-sane.c canon-scsi.c canon630u.conf.in \ - canon630u-common.c lm9830.h canon_dr.conf.in canon_pp.conf.in \ - cardscan.conf.in coolscan.conf.in coolscan2.conf.in \ - coolscan3.conf.in dc25.conf.in dc210.conf.in dc240.conf.in \ - dell1600n_net.conf.in dmc.conf.in epjitsu.conf.in \ - epson.conf.in epson2.conf.in epsonds.conf.in fujitsu.conf.in \ - genesys.conf.in genesys_conv.c genesys_conv_hlp.c \ - genesys_devices.c gphoto2.conf.in gt68xx.conf.in \ - gt68xx_devices.c gt68xx_generic.c gt68xx_generic.h \ - gt68xx_gt6801.c gt68xx_gt6801.h gt68xx_gt6816.c \ - gt68xx_gt6816.h gt68xx_high.c gt68xx_high.h gt68xx_low.c \ - gt68xx_low.h gt68xx_mid.c gt68xx_mid.h gt68xx_shm_channel.c \ - gt68xx_shm_channel.h hp.conf.in hp.README hp.TODO \ - hp3900.conf.in hp3900_config.c hp3900_debug.c hp3900_rts8822.c \ - hp3900_sane.c hp3900_types.c hp3900_usb.c hp4200.conf.in \ - hp4200_lm9830.c hp4200_lm9830.h hp5400.conf.in hp5400_debug.c \ - hp5400_debug.h hp5400_internal.c hp5400_internal.h \ - hp5400_sane.c hp5400_sanei.c hp5400_sanei.h hp5400_xfer.h \ - hp5590_cmds.c hp5590_cmds.h hp5590_low.c hp5590_low.h \ - hpsj5s.conf.in hs2p.conf.in hs2p-scsi.c hs2p-scsi.h \ - ibm.conf.in ibm-scsi.c kodak.conf.in kodakaio.conf.in \ - kvs1025.conf.in leo.conf.in lexmark.conf.in lexmark_models.c \ - lexmark_sensors.c ma1509.conf.in magicolor.conf.in \ - matsushita.conf.in microtek.conf.in microtek2.conf.in \ - mustek.conf.in mustek_scsi_pp.c mustek_scsi_pp.h \ - mustek_pp.conf.in mustek_pp_ccd300.c mustek_pp_ccd300.h \ - mustek_pp_cis.c mustek_pp_cis.h mustek_pp_null.c \ - mustek_usb.conf.in mustek_usb_high.c mustek_usb_high.h \ - mustek_usb_low.c mustek_usb_low.h mustek_usb_mid.c \ - mustek_usb_mid.h mustek_usb2_asic.c mustek_usb2_asic.h \ - mustek_usb2_high.c mustek_usb2_high.h mustek_usb2_reflective.c \ - mustek_usb2_transparent.c nec.conf.in net.conf.in niash_core.c \ - niash_core.h niash_xfer.c niash_xfer.h pie.conf.in \ - pieusb.conf.in p5.conf.in p5_device.c pixma.conf.in \ - pixma_sane_options.c pixma_sane_options.h plustek.conf.in \ - plustek-usb.c plustek-usb.h plustek-usbcal.c \ - plustek-usbcalfile.c plustek-usbdevs.c plustek-usbhw.c \ - plustek-usbimg.c plustek-usbio.c plustek-usbmap.c \ - plustek-usbscan.c plustek-usbshading.c plustek_pp.conf.in \ - plustek-pp_dac.c plustek-pp_dbg.h plustek-pp_detect.c \ - plustek-pp_genericio.c plustek-pp_hwdefs.h plustek-pp_image.c \ - plustek-pp_io.c plustek-pp_map.c plustek-pp_misc.c \ - plustek-pp_models.c plustek-pp_motor.c plustek-pp_p12.c \ - plustek-pp_p12ccd.c plustek-pp_p48xx.c plustek-pp_p9636.c \ - plustek-pp_procfs.c plustek-pp_procs.h plustek-pp_ptdrv.c \ - plustek-pp_scale.c plustek-pp_scan.h plustek-pp_scandata.h \ - plustek-pp_sysdep.h plustek-pp_tpa.c plustek-pp_types.h \ - plustek-pp_wrapper.c qcam.conf.in ricoh.conf.in ricoh-scsi.c \ - rts8891.conf.in rts8891_devices.c rts8891_low.c rts8891_low.h \ - s9036.conf.in sceptre.conf.in sharp.conf.in sm3600-color.c \ - sm3600-gray.c sm3600-homerun.c sm3600-scanmtek.c \ - sm3600-scantool.h sm3600-scanusb.c sm3600-scanutil.c \ - sm3840.conf.in sm3840_lib.c sm3840_lib.h sm3840_scan.c \ - snapscan.conf.in snapscan-data.c snapscan-mutex.c \ - snapscan-options.c snapscan-scsi.c snapscan-sources.c \ - snapscan-sources.h snapscan-usb.c snapscan-usb.h sp15c.conf.in \ - st400.conf.in stv680.conf.in tamarack.conf.in test.conf.in \ - test-picture.c teco1.conf.in teco2.conf.in teco3.conf.in \ - u12.conf.in u12-ccd.c u12-hw.c u12-hwdef.h u12-if.c \ - u12-image.c u12-io.c u12-map.c u12-motor.c u12-scanner.h \ - u12-shading.c u12-tpa.c umax.conf.in umax-scanner.c \ - umax-scanner.h umax-scsidef.h umax-uc1200s.c umax-uc1200se.c \ - umax-uc1260.c umax-uc630.c umax-uc840.c umax-ug630.c \ - umax-ug80.c umax-usb.c umax1220u.conf.in umax1220u-common.c \ - umax_pp.conf.in v4l.conf.in xerox_mfp.conf.in dll.conf.in \ - dll.aliases - -# Backends are not required to have a config file. Any backend -# that wants to install a config file should list it here. -BACKEND_CONFS = abaton.conf agfafocus.conf apple.conf artec.conf \ - artec_eplus48u.conf avision.conf bh.conf \ - canon630u.conf canon.conf canon_dr.conf \ - canon_pp.conf cardscan.conf coolscan2.conf coolscan3.conf \ - coolscan.conf dc210.conf dc240.conf dc25.conf \ - dell1600n_net.conf dmc.conf epjitsu.conf epson2.conf \ - epson.conf epsonds.conf fujitsu.conf genesys.conf gphoto2.conf \ - gt68xx.conf hp3900.conf hp4200.conf hp5400.conf \ - hp.conf hpsj5s.conf hs2p.conf ibm.conf kodak.conf kodakaio.conf\ - kvs1025.conf \ - leo.conf lexmark.conf ma1509.conf magicolor.conf \ - matsushita.conf microtek2.conf microtek.conf mustek.conf \ - mustek_pp.conf mustek_usb.conf nec.conf net.conf \ - p5.conf \ - pie.conf pieusb.conf pixma.conf plustek.conf plustek_pp.conf \ - qcam.conf ricoh.conf rts8891.conf s9036.conf sceptre.conf \ - sharp.conf sm3840.conf snapscan.conf sp15c.conf \ - st400.conf stv680.conf tamarack.conf \ - teco1.conf teco2.conf teco3.conf test.conf \ - u12.conf umax1220u.conf umax.conf umax_pp.conf v4l.conf \ - xerox_mfp.conf dll.conf saned.conf - -SUFFIXES = .conf.in .conf -CLEANFILES = $(BACKEND_CONFS) $(be_convenience_libs) dll-preload.h - -# Backends -# -# All possible backends should be listed here. As a first step, we create -# a convenience library containing all files needed to link a backend -# directly into libsane.la. Convenience library should have the -# form of lib${backend}.la to match what configure will list to -# build. -# Occasionally, this approach will have name conflicts with external -# libraries that need to be linked in. See libgphoto2_i.la for -# example of working around that issue. -be_convenience_libs = libabaton.la libagfafocus.la \ - libapple.la libartec.la libartec_eplus48u.la \ - libas6e.la libavision.la libbh.la \ - libcanon.la libcanon630u.la libcanon_dr.la \ - libcanon_pp.la libcardscan.la libcoolscan.la \ - libcoolscan2.la libcoolscan3.la libdc25.la \ - libdc210.la libdc240.la libdell1600n_net.la \ - libdmc.la libdll.la libdll_preload.la libepjitsu.la libepson.la \ - libepson2.la libepsonds.la libfujitsu.la libgenesys.la \ - libgphoto2_i.la libgt68xx.la libhp.la \ - libhp3500.la libhp3900.la libhp4200.la \ - libhp5400.la libhp5590.la libhpljm1005.la \ - libhpsj5s.la libhs2p.la libibm.la libkodak.la libkodakaio.la\ - libkvs1025.la libkvs20xx.la libkvs40xx.la \ - libleo.la liblexmark.la libma1509.la libmagicolor.la \ - libmatsushita.la libmicrotek.la libmicrotek2.la \ - libmustek.la libmustek_pp.la libmustek_usb.la \ - libmustek_usb2.la libnec.la libnet.la \ - libniash.la libp5.la \ - libpie.la libpieusb.la libpint.la libpixma.la \ - libplustek.la libplustek_pp.la libpnm.la \ - libqcam.la libricoh.la librts8891.la \ - libs9036.la libsceptre.la libsharp.la \ - libsm3600.la libsm3840.la libsnapscan.la \ - libsp15c.la libst400.la libstv680.la \ - libtamarack.la libtest.la libteco1.la \ - libteco2.la libteco3.la libu12.la libumax.la \ - libumax1220u.la libumax_pp.la libv4l.la \ - libxerox_mfp.la - - -# Each stand alone backend thats possible to be built should be listed -# here. There are the libraries that are installed under $(libdir)/sane. -# Format is libsane-${backend}.la. -be_dlopen_libs = libsane-abaton.la libsane-agfafocus.la \ - libsane-apple.la libsane-artec.la libsane-artec_eplus48u.la \ - libsane-as6e.la libsane-avision.la libsane-bh.la \ - libsane-canon.la libsane-canon630u.la libsane-canon_dr.la \ - libsane-canon_pp.la libsane-cardscan.la libsane-coolscan.la \ - libsane-coolscan2.la libsane-coolscan3.la libsane-dc25.la \ - libsane-dc210.la libsane-dc240.la libsane-dell1600n_net.la \ - libsane-dmc.la libsane-epjitsu.la libsane-epson.la \ - libsane-epson2.la libsane-epsonds.la libsane-fujitsu.la libsane-genesys.la \ - libsane-gphoto2.la libsane-gt68xx.la libsane-hp.la \ - libsane-hp3500.la libsane-hp3900.la libsane-hp4200.la \ - libsane-hp5400.la libsane-hp5590.la libsane-hpljm1005.la \ - libsane-hpsj5s.la libsane-hs2p.la libsane-ibm.la libsane-kodak.la libsane-kodakaio.la\ - libsane-kvs1025.la libsane-kvs20xx.la libsane-kvs40xx.la \ - libsane-leo.la \ - libsane-lexmark.la libsane-ma1509.la libsane-magicolor.la \ - libsane-matsushita.la libsane-microtek.la libsane-microtek2.la \ - libsane-mustek.la libsane-mustek_pp.la libsane-mustek_usb.la \ - libsane-mustek_usb2.la libsane-nec.la libsane-net.la \ - libsane-niash.la libsane-p5.la \ - libsane-pie.la libsane-pieusb.la libsane-pint.la libsane-pixma.la \ - libsane-plustek.la libsane-plustek_pp.la libsane-pnm.la \ - libsane-qcam.la libsane-ricoh.la libsane-rts8891.la \ - libsane-s9036.la libsane-sceptre.la libsane-sharp.la \ - libsane-sm3600.la libsane-sm3840.la libsane-snapscan.la \ - libsane-sp15c.la libsane-st400.la libsane-stv680.la \ - libsane-tamarack.la libsane-test.la libsane-teco1.la \ - libsane-teco2.la libsane-teco3.la libsane-u12.la libsane-umax.la \ - libsane-umax1220u.la libsane-umax_pp.la libsane-v4l.la \ - libsane-xerox_mfp.la - -EXTRA_LTLIBRARIES = $(be_convenience_libs) $(be_dlopen_libs) -lib_LTLIBRARIES = libsane.la -sanelibdir = $(libdir)/sane -sanelib_LTLIBRARIES = $(BACKEND_LIBS_ENABLED) libsane-dll.la -COMMON_LIBS = ../lib/liblib.la - -# Each backend should define a convenience library that compiles -# all related files within backend directory. General guideline -# is to have a ${backend}.c and ${backend}.h. Some backends also -# add a few support source files to convience library. -# Note: automake doesn't really use header files listed here. -# They are indications that they need to be distributed only. -libabaton_la_SOURCES = abaton.c abaton.h -libabaton_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=abaton - -# Each backend should define a stand alone library that gets installed. -# This will need to link in a special file ${backend}-s.c that allows -# the backend to be stand alone and contain all SANE API functions. -# Also, it will need to link in related convenience library as well as -# any external libraries required to resolve symbols. -# -# All backends should include $(DIST_SANELIBS_LDFLAGS) so that -# library is correctly versioned. -# -# If a backend has a config file, it must be listed here to get distributed. -nodist_libsane_abaton_la_SOURCES = abaton-s.c -libsane_abaton_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=abaton -libsane_abaton_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_abaton_la_LIBADD = $(COMMON_LIBS) libabaton.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libagfafocus_la_SOURCES = agfafocus.c agfafocus.h -libagfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus -nodist_libsane_agfafocus_la_SOURCES = agfafocus-s.c -libsane_agfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus -libsane_agfafocus_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_agfafocus_la_LIBADD = $(COMMON_LIBS) libagfafocus.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libapple_la_SOURCES = apple.c apple.h -libapple_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=apple -nodist_libsane_apple_la_SOURCES = apple-s.c -libsane_apple_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=apple -libsane_apple_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_apple_la_LIBADD = $(COMMON_LIBS) libapple.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libartec_la_SOURCES = artec.c artec.h -libartec_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=artec -nodist_libsane_artec_la_SOURCES = artec-s.c -libsane_artec_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_artec_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=artec -libsane_artec_la_LIBADD = $(COMMON_LIBS) libartec.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libartec_eplus48u_la_SOURCES = artec_eplus48u.c artec_eplus48u.h -libartec_eplus48u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=artec_eplus48u -nodist_libsane_artec_eplus48u_la_SOURCES = artec_eplus48u-s.c -libsane_artec_eplus48u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=artec_eplus48u -libsane_artec_eplus48u_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_artec_eplus48u_la_LIBADD = $(COMMON_LIBS) libartec_eplus48u.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMEG_LIBS) -libas6e_la_SOURCES = as6e.c as6e.h -libas6e_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=as6e -nodist_libsane_as6e_la_SOURCES = as6e-s.c -libsane_as6e_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=as6e -libsane_as6e_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_as6e_la_LIBADD = $(COMMON_LIBS) libas6e.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo -libavision_la_SOURCES = avision.c avision.h -libavision_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=avision -nodist_libsane_avision_la_SOURCES = avision-s.c -libsane_avision_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=avision -libsane_avision_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_avision_la_LIBADD = $(COMMON_LIBS) libavision.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libbh_la_SOURCES = bh.c bh.h -libbh_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=bh -nodist_libsane_bh_la_SOURCES = bh-s.c -libsane_bh_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=bh -libsane_bh_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_bh_la_LIBADD = $(COMMON_LIBS) libbh.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libcanon_la_SOURCES = canon.c canon.h -libcanon_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon -nodist_libsane_canon_la_SOURCES = canon-s.c -libsane_canon_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon -libsane_canon_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_canon_la_LIBADD = $(COMMON_LIBS) libcanon.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(RESMGR_LIBS) -libcanon630u_la_SOURCES = canon630u.c -libcanon630u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon630u -nodist_libsane_canon630u_la_SOURCES = canon630u-s.c -libsane_canon630u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon630u -libsane_canon630u_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_canon630u_la_LIBADD = $(COMMON_LIBS) libcanon630u.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libcanon_dr_la_SOURCES = canon_dr.c canon_dr.h canon_dr-cmd.h -libcanon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr -nodist_libsane_canon_dr_la_SOURCES = canon_dr-s.c -libsane_canon_dr_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_dr -libsane_canon_dr_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_canon_dr_la_LIBADD = $(COMMON_LIBS) libcanon_dr.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) -libcanon_pp_la_SOURCES = canon_pp.c canon_pp.h canon_pp-io.c canon_pp-io.h canon_pp-dev.c canon_pp-dev.h -libcanon_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_pp -nodist_libsane_canon_pp_la_SOURCES = canon_pp-s.c -libsane_canon_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=canon_pp -libsane_canon_pp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_canon_pp_la_LIBADD = $(COMMON_LIBS) libcanon_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(IEEE1284_LIBS) -libcardscan_la_SOURCES = cardscan.c cardscan.h -libcardscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=cardscan -nodist_libsane_cardscan_la_SOURCES = cardscan-s.c -libsane_cardscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=cardscan -libsane_cardscan_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_cardscan_la_LIBADD = $(COMMON_LIBS) libcardscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) -libcoolscan_la_SOURCES = coolscan.c coolscan.h coolscan-scsidef.h -libcoolscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan -nodist_libsane_coolscan_la_SOURCES = coolscan-s.c -libsane_coolscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan -libsane_coolscan_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_coolscan_la_LIBADD = $(COMMON_LIBS) libcoolscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libcoolscan2_la_SOURCES = coolscan2.c -libcoolscan2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan2 -nodist_libsane_coolscan2_la_SOURCES = coolscan2-s.c -libsane_coolscan2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan2 -libsane_coolscan2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_coolscan2_la_LIBADD = $(COMMON_LIBS) libcoolscan2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libcoolscan3_la_SOURCES = coolscan3.c -libcoolscan3_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan3 -nodist_libsane_coolscan3_la_SOURCES = coolscan3-s.c -libsane_coolscan3_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan3 -libsane_coolscan3_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_coolscan3_la_LIBADD = $(COMMON_LIBS) libcoolscan3.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libdc25_la_SOURCES = dc25.c dc25.h -libdc25_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc25 -nodist_libsane_dc25_la_SOURCES = dc25-s.c -libsane_dc25_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc25 -libsane_dc25_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dc25_la_LIBADD = $(COMMON_LIBS) libdc25.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(MATH_LIB) -libdc210_la_SOURCES = dc210.c dc210.h -libdc210_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc210 -nodist_libsane_dc210_la_SOURCES = dc210-s.c -libsane_dc210_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc210 -libsane_dc210_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dc210_la_LIBADD = $(COMMON_LIBS) libdc210.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) -libdc240_la_SOURCES = dc240.c dc240.h -libdc240_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc240 -nodist_libsane_dc240_la_SOURCES = dc240-s.c -libsane_dc240_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dc240 -libsane_dc240_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dc240_la_LIBADD = $(COMMON_LIBS) libdc240.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) -libdell1600n_net_la_SOURCES = dell1600n_net.c -libdell1600n_net_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dell1600n_net -nodist_libsane_dell1600n_net_la_SOURCES = dell1600n_net-s.c -libsane_dell1600n_net_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dell1600n_net -libsane_dell1600n_net_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dell1600n_net_la_LIBADD = $(COMMON_LIBS) libdell1600n_net.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(TIFF_LIBS) $(JPEG_LIBS) $(SOCKET_LIBS) -libdmc_la_SOURCES = dmc.c dmc.h -libdmc_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dmc -nodist_libsane_dmc_la_SOURCES = dmc-s.c -libsane_dmc_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dmc -libsane_dmc_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dmc_la_LIBADD = $(COMMON_LIBS) libdmc.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libepjitsu_la_SOURCES = epjitsu.c epjitsu.h epjitsu-cmd.h -libepjitsu_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epjitsu -nodist_libsane_epjitsu_la_SOURCES = epjitsu-s.c -libsane_epjitsu_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epjitsu -libsane_epjitsu_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_epjitsu_la_LIBADD = $(COMMON_LIBS) libepjitsu.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libepson_la_SOURCES = epson.c epson.h epson_scsi.c epson_scsi.h epson_usb.c epson_usb.h -libepson_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epson -nodist_libsane_epson_la_SOURCES = epson-s.c -libsane_epson_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epson -libsane_epson_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_epson_la_LIBADD = $(COMMON_LIBS) libepson.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pio.lo $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) -libepson2_la_SOURCES = epson2.c epson2.h epson2_scsi.c epson2_scsi.h epson2_usb.c epson2_net.c epson2_net.h epson2-io.c epson2-io.h epson2-commands.c epson2-commands.h epson2-ops.c epson2-ops.h epson2-cct.c -libepson2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epson2 -nodist_libsane_epson2_la_SOURCES = epson2-s.c -libsane_epson2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epson2 -libsane_epson2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_epson2_la_LIBADD = $(COMMON_LIBS) libepson2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo $(SCSI_LIBS) $(USB_LIBS) $(SOCKET_LIBS) $(MATH_LIB) $(RESMGR_LIBS) -libepsonds_la_SOURCES = epsonds.c epsonds.h epsonds-usb.c epsonds-usb.h epsonds-io.c epsonds-io.h \ - epsonds-cmd.c epsonds-cmd.h epsonds-ops.c epsonds-ops.h epsonds-jpeg.c epsonds-jpeg.h \ - epsonds-net.c epsonds-net.h - -libepsonds_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epsonds -nodist_libsane_epsonds_la_SOURCES = epsonds-s.c -libsane_epsonds_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epsonds -libsane_epsonds_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_epsonds_la_LIBADD = $(COMMON_LIBS) libepsonds.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo \ - ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo \ - ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo \ - ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo \ - $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(USB_LIBS) $(MATH_LIB) $(RESMGR_LIBS) $(SOCKET_LIBS) - -libfujitsu_la_SOURCES = fujitsu.c fujitsu.h fujitsu-scsi.h -libfujitsu_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=fujitsu -nodist_libsane_fujitsu_la_SOURCES = fujitsu-s.c -libsane_fujitsu_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=fujitsu -libsane_fujitsu_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_fujitsu_la_LIBADD = $(COMMON_LIBS) libfujitsu.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) -libgenesys_la_SOURCES = genesys.c genesys.h genesys_gl646.c genesys_gl646.h genesys_gl841.c genesys_gl841.h genesys_gl843.c genesys_gl843.h genesys_gl846.c genesys_gl846.h genesys_gl847.c genesys_gl847.h genesys_gl124.c genesys_gl124.h genesys_low.c genesys_low.h -libgenesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys -nodist_libsane_genesys_la_SOURCES = genesys-s.c -libsane_genesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys -libsane_genesys_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h -libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2 -nodist_libsane_gphoto2_la_SOURCES = gphoto2-s.c -libsane_gphoto2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gphoto2 -libsane_gphoto2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_gphoto2_la_LIBADD = $(GPHOTO2_LDFLAGS) $(COMMON_LIBS) libgphoto2_i.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(SANEI_SANEI_JPEG_LO) $(GPHOTO2_LIBS) $(JPEG_LIBS) -libgt68xx_la_SOURCES = gt68xx.c gt68xx.h -libgt68xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gt68xx -nodist_libsane_gt68xx_la_SOURCES = gt68xx-s.c -libsane_gt68xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=gt68xx -libsane_gt68xx_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_gt68xx_la_LIBADD = $(COMMON_LIBS) libgt68xx.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libhp_la_SOURCES = hp.c hp.h hp-accessor.c hp-accessor.h hp-device.c hp-device.h hp-handle.c hp-handle.h hp-hpmem.c hp-option.c hp-option.h hp-scl.c hp-scl.h hp-scsi.h -libhp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp -nodist_libsane_hp_la_SOURCES = hp-s.c -libsane_hp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp -libsane_hp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp_la_LIBADD = $(COMMON_LIBS) libhp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pio.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libhp3500_la_SOURCES = hp3500.c -libhp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500 -nodist_libsane_hp3500_la_SOURCES = hp3500-s.c -libsane_hp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500 -libsane_hp3500_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libhp3900_la_SOURCES = hp3900.c -libhp3900_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3900 -nodist_libsane_hp3900_la_SOURCES = hp3900-s.c -libsane_hp3900_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3900 -libsane_hp3900_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp3900_la_LIBADD = $(COMMON_LIBS) libhp3900.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(TIFF_LIBS) $(USB_LIBS) $(RESMGR_LIBS) -libhp4200_la_SOURCES = hp4200.c hp4200.h -libhp4200_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp4200 -nodist_libsane_hp4200_la_SOURCES = hp4200-s.c -libsane_hp4200_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp4200 -libsane_hp4200_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp4200_la_LIBADD = $(COMMON_LIBS) libhp4200.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libhp5400_la_SOURCES = hp5400.c hp5400.h -libhp5400_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp5400 -nodist_libsane_hp5400_la_SOURCES = hp5400-s.c -libsane_hp5400_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp5400 -libsane_hp5400_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp5400_la_LIBADD = $(COMMON_LIBS) libhp5400.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) -libhp5590_la_SOURCES = hp5590.c -libhp5590_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp5590 -nodist_libsane_hp5590_la_SOURCES = hp5590-s.c -libsane_hp5590_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp5590 -libsane_hp5590_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp5590_la_LIBADD = $(COMMON_LIBS) libhp5590.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) -libhpljm1005_la_SOURCES = hpljm1005.c -libhpljm1005_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hpljm1005 -nodist_libsane_hpljm1005_la_SOURCES = hpljm1005-s.c -libsane_hpljm1005_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hpljm1005 -libsane_hpljm1005_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hpljm1005_la_LIBADD = $(COMMON_LIBS) libhpljm1005.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libhpsj5s_la_SOURCES = hpsj5s.c hpsj5s.h -libhpsj5s_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hpsj5s -nodist_libsane_hpsj5s_la_SOURCES = hpsj5s-s.c -libsane_hpsj5s_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hpsj5s -libsane_hpsj5s_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hpsj5s_la_LIBADD = $(COMMON_LIBS) libhpsj5s.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(IEEE1284_LIBS) -libhs2p_la_SOURCES = hs2p.c hs2p.h hs2p-saneopts.h -libhs2p_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hs2p -nodist_libsane_hs2p_la_SOURCES = hs2p-s.c -libsane_hs2p_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hs2p -libsane_hs2p_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hs2p_la_LIBADD = $(COMMON_LIBS) libhs2p.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libibm_la_SOURCES = ibm.c ibm.h -libibm_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=ibm -nodist_libsane_ibm_la_SOURCES = ibm-s.c -libsane_ibm_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=ibm -libsane_ibm_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_ibm_la_LIBADD = $(COMMON_LIBS) libibm.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libkodak_la_SOURCES = kodak.c kodak.h kodak-cmd.h -libkodak_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kodak -nodist_libsane_kodak_la_SOURCES = kodak-s.c -libsane_kodak_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kodak -libsane_kodak_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_kodak_la_LIBADD = $(COMMON_LIBS) libkodak.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) -libkodakaio_la_SOURCES = kodakaio.c kodakaio.h -libkodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kodakaio -nodist_libsane_kodakaio_la_SOURCES = kodakaio-s.c -libsane_kodakaio_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kodakaio -libsane_kodakaio_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_kodakaio_la_LIBADD = $(COMMON_LIBS) libkodakaio.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo $(USB_LIBS) $(SOCKET_LIBS) $(AVAHI_LIBS) $(MATH_LIB) $(RESMGR_LIBS) -libkvs1025_la_SOURCES = kvs1025.c kvs1025_low.c kvs1025_opt.c kvs1025_usb.c \ - kvs1025.h kvs1025_low.h kvs1025_usb.h kvs1025_cmds.h - -libkvs1025_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs1025 -nodist_libsane_kvs1025_la_SOURCES = kvs1025-s.c -libsane_kvs1025_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs1025 -libsane_kvs1025_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_kvs1025_la_LIBADD = $(COMMON_LIBS) libkvs1025.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libkvs20xx_la_SOURCES = kvs20xx.c kvs20xx_cmd.c kvs20xx_opt.c \ - kvs20xx_cmd.h kvs20xx.h - -libkvs20xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs20xx -nodist_libsane_kvs20xx_la_SOURCES = kvs20xx-s.c -libsane_kvs20xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs20xx -libsane_kvs20xx_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_kvs20xx_la_LIBADD = $(COMMON_LIBS) libkvs20xx.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) -libkvs40xx_la_SOURCES = kvs40xx.c kvs40xx_cmd.c kvs40xx_opt.c \ - kvs40xx.h - -libkvs40xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs40xx -nodist_libsane_kvs40xx_la_SOURCES = kvs40xx-s.c -libsane_kvs40xx_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=kvs40xx -libsane_kvs40xx_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_kvs40xx_la_LIBADD = $(COMMON_LIBS) libkvs40xx.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libleo_la_SOURCES = leo.c leo.h -libleo_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=leo -nodist_libsane_leo_la_SOURCES = leo-s.c -libsane_leo_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=leo -libsane_leo_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_leo_la_LIBADD = $(COMMON_LIBS) libleo.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -liblexmark_la_SOURCES = lexmark.c lexmark.h lexmark_low.c -liblexmark_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=lexmark -nodist_libsane_lexmark_la_SOURCES = lexmark-s.c -libsane_lexmark_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=lexmark -libsane_lexmark_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_lexmark_la_LIBADD = $(COMMON_LIBS) liblexmark.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) -libma1509_la_SOURCES = ma1509.c ma1509.h -libma1509_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=ma1509 -nodist_libsane_ma1509_la_SOURCES = ma1509-s.c -libsane_ma1509_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=ma1509 -libsane_ma1509_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_ma1509_la_LIBADD = $(COMMON_LIBS) libma1509.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) -libmagicolor_la_SOURCES = magicolor.c magicolor.h -libmagicolor_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=magicolor $(SNMP_CFLAGS) -nodist_libsane_magicolor_la_SOURCES = magicolor-s.c -libsane_magicolor_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=magicolor -libsane_magicolor_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_magicolor_la_LIBADD = $(COMMON_LIBS) libmagicolor.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo $(USB_LIBS) $(SOCKET_LIBS) $(MATH_LIB) $(RESMGR_LIBS) $(SNMP_LIBS) -libmatsushita_la_SOURCES = matsushita.c matsushita.h -libmatsushita_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=matsushita -nodist_libsane_matsushita_la_SOURCES = matsushita-s.c -libsane_matsushita_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=matsushita -libsane_matsushita_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_matsushita_la_LIBADD = $(COMMON_LIBS) libmatsushita.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libmicrotek_la_SOURCES = microtek.c microtek.h -libmicrotek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=microtek -nodist_libsane_microtek_la_SOURCES = microtek-s.c -libsane_microtek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=microtek -libsane_microtek_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_microtek_la_LIBADD = $(COMMON_LIBS) libmicrotek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(RESMGR_LIBS) -libmicrotek2_la_SOURCES = microtek2.c microtek2.h -libmicrotek2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=microtek2 -nodist_libsane_microtek2_la_SOURCES = microtek2-s.c -libsane_microtek2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=microtek2 -libsane_microtek2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_microtek2_la_LIBADD = $(COMMON_LIBS) libmicrotek2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libmustek_la_SOURCES = mustek.c mustek.h -libmustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek -nodist_libsane_mustek_la_SOURCES = mustek-s.c -libsane_mustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek -libsane_mustek_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_mustek_la_LIBADD = $(COMMON_LIBS) libmustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pa4s2.lo $(IEEE1284_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libmustek_pp_la_SOURCES = mustek_pp.c mustek_pp.h mustek_pp_decl.h mustek_pp_drivers.h -libmustek_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_pp -nodist_libsane_mustek_pp_la_SOURCES = mustek_pp-s.c -libsane_mustek_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_pp -libsane_mustek_pp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_mustek_pp_la_LIBADD = $(COMMON_LIBS) libmustek_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_pa4s2.lo $(MATH_LIB) $(IEEE1284_LIBS) -libmustek_usb_la_SOURCES = mustek_usb.c mustek_usb.h -libmustek_usb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb -nodist_libsane_mustek_usb_la_SOURCES = mustek_usb-s.c -libsane_mustek_usb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb -libsane_mustek_usb_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_mustek_usb_la_LIBADD = $(COMMON_LIBS) libmustek_usb.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) -libmustek_usb2_la_SOURCES = mustek_usb2.c mustek_usb2.h -libmustek_usb2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb2 -nodist_libsane_mustek_usb2_la_SOURCES = mustek_usb2-s.c -libsane_mustek_usb2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb2 -libsane_mustek_usb2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_mustek_usb2_la_LIBADD = $(COMMON_LIBS) libmustek_usb2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(PTHREAD_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libnec_la_SOURCES = nec.c nec.h -libnec_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=nec -nodist_libsane_nec_la_SOURCES = nec-s.c -libsane_nec_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=nec -libsane_nec_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_nec_la_LIBADD = $(COMMON_LIBS) libnec.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(RESMGR_LIBS) -libnet_la_SOURCES = net.c net.h -libnet_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=net -nodist_libsane_net_la_SOURCES = net-s.c -libsane_net_la_CPPFLAGS = $(AM_CPPFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=net -libsane_net_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_net_la_LIBADD = $(COMMON_LIBS) libnet.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo $(AVAHI_LIBS) $(SOCKET_LIBS) -libniash_la_SOURCES = niash.c -libniash_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=niash -nodist_libsane_niash_la_SOURCES = niash-s.c -libsane_niash_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=niash -libsane_niash_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_niash_la_LIBADD = $(COMMON_LIBS) libniash.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libpie_la_SOURCES = pie.c pie-scsidef.h -libpie_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pie -nodist_libsane_pie_la_SOURCES = pie-s.c -libsane_pie_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pie -libsane_pie_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pie_la_LIBADD = $(COMMON_LIBS) libpie.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libpieusb_la_SOURCES = pieusb.h pieusb_buffer.c pieusb_buffer.h pieusb_scancmd.c pieusb_scancmd.h pieusb_specific.c pieusb_specific.h pieusb_usb.c pieusb_usb.h pieusb.c -libpieusb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pieusb -nodist_libsane_pieusb_la_SOURCES = pieusb-s.c -libsane_pieusb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pieusb -libsane_pieusb_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pieusb_la_LIBADD = $(COMMON_LIBS) libpieusb.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_ir.lo ../sanei/sanei_magic.lo $(PTHREAD_LIBS) $(RESMGR_LIBS) $(USB_LIBS) $(MATH_LIB) -libp5_la_SOURCES = p5.c p5.h p5_device.h -libp5_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=p5 -nodist_libsane_p5_la_SOURCES = p5-s.c -libsane_p5_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=p5 -libsane_p5_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_p5_la_LIBADD = $(COMMON_LIBS) libp5.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo -libpint_la_SOURCES = pint.c pint.h -libpint_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pint -nodist_libsane_pint_la_SOURCES = pint-s.c -libsane_pint_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pint -libsane_pint_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pint_la_LIBADD = $(COMMON_LIBS) libpint.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo -libpixma_la_SOURCES = pixma.c pixma.h pixma_io_sanei.c pixma_io.h pixma_common.c pixma_common.h pixma_mp150.c pixma_mp730.c pixma_mp750.c pixma_mp810.c pixma_imageclass.c pixma_bjnp.c pixma_bjnp.h pixma_bjnp_private.h pixma_rename.h -libpixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma -nodist_libsane_pixma_la_SOURCES = pixma-s.c -libsane_pixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma -libsane_pixma_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libplustek_la_SOURCES = plustek.c plustek.h -libplustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek -nodist_libsane_plustek_la_SOURCES = plustek-s.c -libsane_plustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek -libsane_plustek_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_plustek_la_LIBADD = $(COMMON_LIBS) libplustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libplustek_pp_la_SOURCES = plustek_pp.c plustek-pp.h -libplustek_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek_pp -nodist_libsane_plustek_pp_la_SOURCES = plustek_pp-s.c -libsane_plustek_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek_pp -libsane_plustek_pp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_plustek_pp_la_LIBADD = $(COMMON_LIBS) libplustek_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(IEEE1284_LIBS) $(PTHREAD_LIBS) -libpnm_la_SOURCES = pnm.c -libpnm_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pnm -nodist_libsane_pnm_la_SOURCES = pnm-s.c -libsane_pnm_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pnm -libsane_pnm_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pnm_la_LIBADD = $(COMMON_LIBS) libpnm.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo -libqcam_la_SOURCES = qcam.c qcam.h -libqcam_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=qcam -nodist_libsane_qcam_la_SOURCES = qcam-s.c -libsane_qcam_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=qcam -libsane_qcam_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_qcam_la_LIBADD = $(COMMON_LIBS) libqcam.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_pio.lo -libricoh_la_SOURCES = ricoh.c ricoh.h -libricoh_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=ricoh -nodist_libsane_ricoh_la_SOURCES = ricoh-s.c -libsane_ricoh_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=ricoh -libsane_ricoh_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_ricoh_la_LIBADD = $(COMMON_LIBS) libricoh.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -librts8891_la_SOURCES = rts8891.c rts8891.h rts88xx_lib.c rts88xx_lib.h -librts8891_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=rts8891 -nodist_libsane_rts8891_la_SOURCES = rts8891-s.c -libsane_rts8891_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=rts8891 -libsane_rts8891_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_rts8891_la_LIBADD = $(COMMON_LIBS) librts8891.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_usb.lo $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) $(RESMGR_LIBS) -libs9036_la_SOURCES = s9036.c s9036.h -libs9036_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=s9036 -nodist_libsane_s9036_la_SOURCES = s9036-s.c -libsane_s9036_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=s9036 -libsane_s9036_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_s9036_la_LIBADD = $(COMMON_LIBS) libs9036.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libsceptre_la_SOURCES = sceptre.c sceptre.h -libsceptre_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sceptre -nodist_libsane_sceptre_la_SOURCES = sceptre-s.c -libsane_sceptre_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sceptre -libsane_sceptre_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_sceptre_la_LIBADD = $(COMMON_LIBS) libsceptre.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libsharp_la_SOURCES = sharp.c sharp.h -libsharp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sharp -nodist_libsane_sharp_la_SOURCES = sharp-s.c -libsane_sharp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sharp -libsane_sharp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_sharp_la_LIBADD = $(COMMON_LIBS) libsharp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(RESMGR_LIBS) -libsm3600_la_SOURCES = sm3600.c sm3600.h -libsm3600_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sm3600 -nodist_libsane_sm3600_la_SOURCES = sm3600-s.c -libsane_sm3600_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sm3600 -libsane_sm3600_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_sm3600_la_LIBADD = $(COMMON_LIBS) libsm3600.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) -libsm3840_la_SOURCES = sm3840.c sm3840.h sm3840_params.h -libsm3840_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sm3840 -nodist_libsane_sm3840_la_SOURCES = sm3840-s.c -libsane_sm3840_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sm3840 -libsane_sm3840_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_sm3840_la_LIBADD = $(COMMON_LIBS) libsm3840.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libsnapscan_la_SOURCES = snapscan.c snapscan.h -libsnapscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=snapscan -nodist_libsane_snapscan_la_SOURCES = snapscan-s.c -libsane_snapscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=snapscan -libsane_snapscan_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_snapscan_la_LIBADD = $(COMMON_LIBS) libsnapscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libsp15c_la_SOURCES = sp15c.c sp15c.h sp15c-scsi.h -libsp15c_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sp15c -nodist_libsane_sp15c_la_SOURCES = sp15c-s.c -libsane_sp15c_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sp15c -libsane_sp15c_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_sp15c_la_LIBADD = $(COMMON_LIBS) libsp15c.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libst400_la_SOURCES = st400.c st400.h -libst400_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=st400 -nodist_libsane_st400_la_SOURCES = st400-s.c ../sanei/sanei_scsi.lo -libsane_st400_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=st400 -libsane_st400_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_st400_la_LIBADD = $(COMMON_LIBS) libst400.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libstv680_la_SOURCES = stv680.c stv680.h -libstv680_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=stv680 -nodist_libsane_stv680_la_SOURCES = stv680-s.c -libsane_stv680_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=stv680 -libsane_stv680_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_stv680_la_LIBADD = $(COMMON_LIBS) libstv680.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(USB_LIBS) $(RESMGR_LIBS) -libtamarack_la_SOURCES = tamarack.c tamarack.h -libtamarack_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=tamarack -nodist_libsane_tamarack_la_SOURCES = tamarack-s.c -libsane_tamarack_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=tamarack -libsane_tamarack_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_tamarack_la_LIBADD = $(COMMON_LIBS) libtamarack.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libtest_la_SOURCES = test.c test.h -libtest_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=test -nodist_libsane_test_la_SOURCES = test-s.c -libsane_test_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=test -libsane_test_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_test_la_LIBADD = $(COMMON_LIBS) libtest.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_thread.lo $(PTHREAD_LIBS) -libteco1_la_SOURCES = teco1.c teco1.h -libteco1_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=teco1 -nodist_libsane_teco1_la_SOURCES = teco1-s.c -libsane_teco1_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=teco1 -libsane_teco1_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_teco1_la_LIBADD = $(COMMON_LIBS) libteco1.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libteco2_la_SOURCES = teco2.c teco2.h -libteco2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=teco2 -nodist_libsane_teco2_la_SOURCES = teco2-s.c -libsane_teco2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=teco2 -libsane_teco2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_teco2_la_LIBADD = $(COMMON_LIBS) libteco2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libteco3_la_SOURCES = teco3.c teco3.h -libteco3_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=teco3 -nodist_libsane_teco3_la_SOURCES = teco3-s.c -libsane_teco3_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=teco3 -libsane_teco3_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_teco3_la_LIBADD = $(COMMON_LIBS) libteco3.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) -libu12_la_SOURCES = u12.c u12.h -libu12_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=u12 -nodist_libsane_u12_la_SOURCES = u12-s.c -libsane_u12_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=u12 -libsane_u12_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_u12_la_LIBADD = $(COMMON_LIBS) libu12.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libumax_la_SOURCES = umax.c umax.h -libumax_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax -nodist_libsane_umax_la_SOURCES = umax-s.c -libsane_umax_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax -libsane_umax_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_umax_la_LIBADD = $(COMMON_LIBS) libumax.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) -libumax1220u_la_SOURCES = umax1220u.c -libumax1220u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax1220u -nodist_libsane_umax1220u_la_SOURCES = umax1220u-s.c -libsane_umax1220u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax1220u -libsane_umax1220u_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_umax1220u_la_LIBADD = $(COMMON_LIBS) libumax1220u.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) -libumax_pp_la_SOURCES = umax_pp.c umax_pp.h umax_pp_low.c umax_pp_low.h umax_pp_mid.c umax_pp_mid.h -libumax_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax_pp -nodist_libsane_umax_pp_la_SOURCES = umax_pp-s.c -libsane_umax_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax_pp -libsane_umax_pp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_umax_pp_la_LIBADD = $(COMMON_LIBS) libumax_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(MATH_LIB) -libv4l_la_SOURCES = v4l.c v4l.h v4l-frequencies.h -libv4l_la_CPPFLAGS = $(AM_CPPFLAGS) $(LIBV4L_CFLAGS) -DBACKEND_NAME=v4l -nodist_libsane_v4l_la_SOURCES = v4l-s.c -libsane_v4l_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=v4l -libsane_v4l_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_v4l_la_LIBADD = $(COMMON_LIBS) libv4l.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(LIBV4L_LIBS) -libxerox_mfp_la_SOURCES = xerox_mfp.c xerox_mfp-usb.c xerox_mfp-tcp.c xerox_mfp.h -libxerox_mfp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=xerox_mfp -nodist_libsane_xerox_mfp_la_SOURCES = xerox_mfp-s.c -libsane_xerox_mfp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=xerox_mfp -libsane_xerox_mfp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_xerox_mfp_la_LIBADD = $(COMMON_LIBS) libxerox_mfp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo @SANEI_SANEI_JPEG_LO@ $(JPEG_LIBS) ../sanei/sanei_usb.lo ../sanei/sanei_tcp.lo $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(RESMGR_LIBS) -libdll_preload_la_SOURCES = dll.c -libdll_preload_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll -DENABLE_PRELOAD -libdll_la_SOURCES = dll.c -libdll_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll -BUILT_SOURCES = dll-preload.h -nodist_libsane_dll_la_SOURCES = dll-s.c -libsane_dll_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll -libsane_dll_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_dll_la_LIBADD = $(COMMON_LIBS) libdll.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(DL_LIBS) - -# libsane.la and libsane-dll.la are the same thing except for -# the addition of backends listed by PRELOADABLE_BACKENDS that are -# statically linked in. -# Also, libsane.la goes into $(libdir) where as all libsane-* -# (including libsane-dll.la) go into $(libdir)/sane - -# FIXME: Since we are throwing in the kitchen sink, might as -# well link in ../sanei/libsanei.la instead. But currently, -# libsanei.la is linking in sanei_auth which requires md5. -# Shipping md5 could cause symbol conflicts with commonly used -# md5 external libraries. Either need to prefix md5 with sanei_ -# (see liblib.la and snprintf), or move sanei_auth outside -# of libsanei. -# -# FIXME: This is linking in every possible external library because there -# is the off chance user is using PRELOADABLE_BACKENDS that may need -# them. Since standard mode is to only have the dll backend, its a waste. -# Need to update configure to build a list of only what needs to go into -# LIBADD based on whats being preloaded. -nodist_libsane_la_SOURCES = dll-s.c -libsane_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll -libsane_la_LDFLAGS = $(DIST_LIBS_LDFLAGS) -libsane_la_LIBADD = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(DL_LIBS) $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) - -# WARNING: Automake is getting this wrong so have to do it ourselves. -libsane_la_DEPENDENCIES = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(SANEI_SANEI_JPEG_LO) -all: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) all-am - -.SUFFIXES: -.SUFFIXES: .conf.in .conf .c .lo .o .obj -$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu backend/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --gnu backend/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ - } - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -install-sanelibLTLIBRARIES: $(sanelib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(sanelib_LTLIBRARIES)'; test -n "$(sanelibdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(sanelibdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(sanelibdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(sanelibdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(sanelibdir)"; \ - } - -uninstall-sanelibLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(sanelib_LTLIBRARIES)'; test -n "$(sanelibdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(sanelibdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(sanelibdir)/$$f"; \ - done - -clean-sanelibLTLIBRARIES: - -test -z "$(sanelib_LTLIBRARIES)" || rm -f $(sanelib_LTLIBRARIES) - @list='$(sanelib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -libabaton.la: $(libabaton_la_OBJECTS) $(libabaton_la_DEPENDENCIES) $(EXTRA_libabaton_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libabaton_la_OBJECTS) $(libabaton_la_LIBADD) $(LIBS) - -libagfafocus.la: $(libagfafocus_la_OBJECTS) $(libagfafocus_la_DEPENDENCIES) $(EXTRA_libagfafocus_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libagfafocus_la_OBJECTS) $(libagfafocus_la_LIBADD) $(LIBS) - -libapple.la: $(libapple_la_OBJECTS) $(libapple_la_DEPENDENCIES) $(EXTRA_libapple_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libapple_la_OBJECTS) $(libapple_la_LIBADD) $(LIBS) - -libartec.la: $(libartec_la_OBJECTS) $(libartec_la_DEPENDENCIES) $(EXTRA_libartec_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libartec_la_OBJECTS) $(libartec_la_LIBADD) $(LIBS) - -libartec_eplus48u.la: $(libartec_eplus48u_la_OBJECTS) $(libartec_eplus48u_la_DEPENDENCIES) $(EXTRA_libartec_eplus48u_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libartec_eplus48u_la_OBJECTS) $(libartec_eplus48u_la_LIBADD) $(LIBS) - -libas6e.la: $(libas6e_la_OBJECTS) $(libas6e_la_DEPENDENCIES) $(EXTRA_libas6e_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libas6e_la_OBJECTS) $(libas6e_la_LIBADD) $(LIBS) - -libavision.la: $(libavision_la_OBJECTS) $(libavision_la_DEPENDENCIES) $(EXTRA_libavision_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libavision_la_OBJECTS) $(libavision_la_LIBADD) $(LIBS) - -libbh.la: $(libbh_la_OBJECTS) $(libbh_la_DEPENDENCIES) $(EXTRA_libbh_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libbh_la_OBJECTS) $(libbh_la_LIBADD) $(LIBS) - -libcanon.la: $(libcanon_la_OBJECTS) $(libcanon_la_DEPENDENCIES) $(EXTRA_libcanon_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libcanon_la_OBJECTS) $(libcanon_la_LIBADD) $(LIBS) - -libcanon630u.la: $(libcanon630u_la_OBJECTS) $(libcanon630u_la_DEPENDENCIES) $(EXTRA_libcanon630u_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libcanon630u_la_OBJECTS) $(libcanon630u_la_LIBADD) $(LIBS) - -libcanon_dr.la: $(libcanon_dr_la_OBJECTS) $(libcanon_dr_la_DEPENDENCIES) $(EXTRA_libcanon_dr_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libcanon_dr_la_OBJECTS) $(libcanon_dr_la_LIBADD) $(LIBS) - -libcanon_pp.la: $(libcanon_pp_la_OBJECTS) $(libcanon_pp_la_DEPENDENCIES) $(EXTRA_libcanon_pp_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libcanon_pp_la_OBJECTS) $(libcanon_pp_la_LIBADD) $(LIBS) - -libcardscan.la: $(libcardscan_la_OBJECTS) $(libcardscan_la_DEPENDENCIES) $(EXTRA_libcardscan_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libcardscan_la_OBJECTS) $(libcardscan_la_LIBADD) $(LIBS) - -libcoolscan.la: $(libcoolscan_la_OBJECTS) $(libcoolscan_la_DEPENDENCIES) $(EXTRA_libcoolscan_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libcoolscan_la_OBJECTS) $(libcoolscan_la_LIBADD) $(LIBS) - -libcoolscan2.la: $(libcoolscan2_la_OBJECTS) $(libcoolscan2_la_DEPENDENCIES) $(EXTRA_libcoolscan2_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libcoolscan2_la_OBJECTS) $(libcoolscan2_la_LIBADD) $(LIBS) - -libcoolscan3.la: $(libcoolscan3_la_OBJECTS) $(libcoolscan3_la_DEPENDENCIES) $(EXTRA_libcoolscan3_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libcoolscan3_la_OBJECTS) $(libcoolscan3_la_LIBADD) $(LIBS) - -libdc210.la: $(libdc210_la_OBJECTS) $(libdc210_la_DEPENDENCIES) $(EXTRA_libdc210_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libdc210_la_OBJECTS) $(libdc210_la_LIBADD) $(LIBS) - -libdc240.la: $(libdc240_la_OBJECTS) $(libdc240_la_DEPENDENCIES) $(EXTRA_libdc240_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libdc240_la_OBJECTS) $(libdc240_la_LIBADD) $(LIBS) - -libdc25.la: $(libdc25_la_OBJECTS) $(libdc25_la_DEPENDENCIES) $(EXTRA_libdc25_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libdc25_la_OBJECTS) $(libdc25_la_LIBADD) $(LIBS) - -libdell1600n_net.la: $(libdell1600n_net_la_OBJECTS) $(libdell1600n_net_la_DEPENDENCIES) $(EXTRA_libdell1600n_net_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libdell1600n_net_la_OBJECTS) $(libdell1600n_net_la_LIBADD) $(LIBS) - -libdll.la: $(libdll_la_OBJECTS) $(libdll_la_DEPENDENCIES) $(EXTRA_libdll_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libdll_la_OBJECTS) $(libdll_la_LIBADD) $(LIBS) - -libdll_preload.la: $(libdll_preload_la_OBJECTS) $(libdll_preload_la_DEPENDENCIES) $(EXTRA_libdll_preload_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libdll_preload_la_OBJECTS) $(libdll_preload_la_LIBADD) $(LIBS) - -libdmc.la: $(libdmc_la_OBJECTS) $(libdmc_la_DEPENDENCIES) $(EXTRA_libdmc_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libdmc_la_OBJECTS) $(libdmc_la_LIBADD) $(LIBS) - -libepjitsu.la: $(libepjitsu_la_OBJECTS) $(libepjitsu_la_DEPENDENCIES) $(EXTRA_libepjitsu_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libepjitsu_la_OBJECTS) $(libepjitsu_la_LIBADD) $(LIBS) - -libepson.la: $(libepson_la_OBJECTS) $(libepson_la_DEPENDENCIES) $(EXTRA_libepson_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libepson_la_OBJECTS) $(libepson_la_LIBADD) $(LIBS) - -libepson2.la: $(libepson2_la_OBJECTS) $(libepson2_la_DEPENDENCIES) $(EXTRA_libepson2_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libepson2_la_OBJECTS) $(libepson2_la_LIBADD) $(LIBS) - -libepsonds.la: $(libepsonds_la_OBJECTS) $(libepsonds_la_DEPENDENCIES) $(EXTRA_libepsonds_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libepsonds_la_OBJECTS) $(libepsonds_la_LIBADD) $(LIBS) - -libfujitsu.la: $(libfujitsu_la_OBJECTS) $(libfujitsu_la_DEPENDENCIES) $(EXTRA_libfujitsu_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libfujitsu_la_OBJECTS) $(libfujitsu_la_LIBADD) $(LIBS) - -libgenesys.la: $(libgenesys_la_OBJECTS) $(libgenesys_la_DEPENDENCIES) $(EXTRA_libgenesys_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libgenesys_la_OBJECTS) $(libgenesys_la_LIBADD) $(LIBS) - -libgphoto2_i.la: $(libgphoto2_i_la_OBJECTS) $(libgphoto2_i_la_DEPENDENCIES) $(EXTRA_libgphoto2_i_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libgphoto2_i_la_OBJECTS) $(libgphoto2_i_la_LIBADD) $(LIBS) - -libgt68xx.la: $(libgt68xx_la_OBJECTS) $(libgt68xx_la_DEPENDENCIES) $(EXTRA_libgt68xx_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libgt68xx_la_OBJECTS) $(libgt68xx_la_LIBADD) $(LIBS) - -libhp.la: $(libhp_la_OBJECTS) $(libhp_la_DEPENDENCIES) $(EXTRA_libhp_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhp_la_OBJECTS) $(libhp_la_LIBADD) $(LIBS) - -libhp3500.la: $(libhp3500_la_OBJECTS) $(libhp3500_la_DEPENDENCIES) $(EXTRA_libhp3500_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhp3500_la_OBJECTS) $(libhp3500_la_LIBADD) $(LIBS) - -libhp3900.la: $(libhp3900_la_OBJECTS) $(libhp3900_la_DEPENDENCIES) $(EXTRA_libhp3900_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhp3900_la_OBJECTS) $(libhp3900_la_LIBADD) $(LIBS) - -libhp4200.la: $(libhp4200_la_OBJECTS) $(libhp4200_la_DEPENDENCIES) $(EXTRA_libhp4200_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhp4200_la_OBJECTS) $(libhp4200_la_LIBADD) $(LIBS) - -libhp5400.la: $(libhp5400_la_OBJECTS) $(libhp5400_la_DEPENDENCIES) $(EXTRA_libhp5400_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhp5400_la_OBJECTS) $(libhp5400_la_LIBADD) $(LIBS) - -libhp5590.la: $(libhp5590_la_OBJECTS) $(libhp5590_la_DEPENDENCIES) $(EXTRA_libhp5590_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhp5590_la_OBJECTS) $(libhp5590_la_LIBADD) $(LIBS) - -libhpljm1005.la: $(libhpljm1005_la_OBJECTS) $(libhpljm1005_la_DEPENDENCIES) $(EXTRA_libhpljm1005_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhpljm1005_la_OBJECTS) $(libhpljm1005_la_LIBADD) $(LIBS) - -libhpsj5s.la: $(libhpsj5s_la_OBJECTS) $(libhpsj5s_la_DEPENDENCIES) $(EXTRA_libhpsj5s_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhpsj5s_la_OBJECTS) $(libhpsj5s_la_LIBADD) $(LIBS) - -libhs2p.la: $(libhs2p_la_OBJECTS) $(libhs2p_la_DEPENDENCIES) $(EXTRA_libhs2p_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libhs2p_la_OBJECTS) $(libhs2p_la_LIBADD) $(LIBS) - -libibm.la: $(libibm_la_OBJECTS) $(libibm_la_DEPENDENCIES) $(EXTRA_libibm_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libibm_la_OBJECTS) $(libibm_la_LIBADD) $(LIBS) - -libkodak.la: $(libkodak_la_OBJECTS) $(libkodak_la_DEPENDENCIES) $(EXTRA_libkodak_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libkodak_la_OBJECTS) $(libkodak_la_LIBADD) $(LIBS) - -libkodakaio.la: $(libkodakaio_la_OBJECTS) $(libkodakaio_la_DEPENDENCIES) $(EXTRA_libkodakaio_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libkodakaio_la_OBJECTS) $(libkodakaio_la_LIBADD) $(LIBS) - -libkvs1025.la: $(libkvs1025_la_OBJECTS) $(libkvs1025_la_DEPENDENCIES) $(EXTRA_libkvs1025_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libkvs1025_la_OBJECTS) $(libkvs1025_la_LIBADD) $(LIBS) - -libkvs20xx.la: $(libkvs20xx_la_OBJECTS) $(libkvs20xx_la_DEPENDENCIES) $(EXTRA_libkvs20xx_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libkvs20xx_la_OBJECTS) $(libkvs20xx_la_LIBADD) $(LIBS) - -libkvs40xx.la: $(libkvs40xx_la_OBJECTS) $(libkvs40xx_la_DEPENDENCIES) $(EXTRA_libkvs40xx_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libkvs40xx_la_OBJECTS) $(libkvs40xx_la_LIBADD) $(LIBS) - -libleo.la: $(libleo_la_OBJECTS) $(libleo_la_DEPENDENCIES) $(EXTRA_libleo_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libleo_la_OBJECTS) $(libleo_la_LIBADD) $(LIBS) - -liblexmark.la: $(liblexmark_la_OBJECTS) $(liblexmark_la_DEPENDENCIES) $(EXTRA_liblexmark_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(liblexmark_la_OBJECTS) $(liblexmark_la_LIBADD) $(LIBS) - -libma1509.la: $(libma1509_la_OBJECTS) $(libma1509_la_DEPENDENCIES) $(EXTRA_libma1509_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libma1509_la_OBJECTS) $(libma1509_la_LIBADD) $(LIBS) - -libmagicolor.la: $(libmagicolor_la_OBJECTS) $(libmagicolor_la_DEPENDENCIES) $(EXTRA_libmagicolor_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libmagicolor_la_OBJECTS) $(libmagicolor_la_LIBADD) $(LIBS) - -libmatsushita.la: $(libmatsushita_la_OBJECTS) $(libmatsushita_la_DEPENDENCIES) $(EXTRA_libmatsushita_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libmatsushita_la_OBJECTS) $(libmatsushita_la_LIBADD) $(LIBS) - -libmicrotek.la: $(libmicrotek_la_OBJECTS) $(libmicrotek_la_DEPENDENCIES) $(EXTRA_libmicrotek_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libmicrotek_la_OBJECTS) $(libmicrotek_la_LIBADD) $(LIBS) - -libmicrotek2.la: $(libmicrotek2_la_OBJECTS) $(libmicrotek2_la_DEPENDENCIES) $(EXTRA_libmicrotek2_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libmicrotek2_la_OBJECTS) $(libmicrotek2_la_LIBADD) $(LIBS) - -libmustek.la: $(libmustek_la_OBJECTS) $(libmustek_la_DEPENDENCIES) $(EXTRA_libmustek_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libmustek_la_OBJECTS) $(libmustek_la_LIBADD) $(LIBS) - -libmustek_pp.la: $(libmustek_pp_la_OBJECTS) $(libmustek_pp_la_DEPENDENCIES) $(EXTRA_libmustek_pp_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libmustek_pp_la_OBJECTS) $(libmustek_pp_la_LIBADD) $(LIBS) - -libmustek_usb.la: $(libmustek_usb_la_OBJECTS) $(libmustek_usb_la_DEPENDENCIES) $(EXTRA_libmustek_usb_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libmustek_usb_la_OBJECTS) $(libmustek_usb_la_LIBADD) $(LIBS) - -libmustek_usb2.la: $(libmustek_usb2_la_OBJECTS) $(libmustek_usb2_la_DEPENDENCIES) $(EXTRA_libmustek_usb2_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libmustek_usb2_la_OBJECTS) $(libmustek_usb2_la_LIBADD) $(LIBS) - -libnec.la: $(libnec_la_OBJECTS) $(libnec_la_DEPENDENCIES) $(EXTRA_libnec_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libnec_la_OBJECTS) $(libnec_la_LIBADD) $(LIBS) - -libnet.la: $(libnet_la_OBJECTS) $(libnet_la_DEPENDENCIES) $(EXTRA_libnet_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libnet_la_OBJECTS) $(libnet_la_LIBADD) $(LIBS) - -libniash.la: $(libniash_la_OBJECTS) $(libniash_la_DEPENDENCIES) $(EXTRA_libniash_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libniash_la_OBJECTS) $(libniash_la_LIBADD) $(LIBS) - -libp5.la: $(libp5_la_OBJECTS) $(libp5_la_DEPENDENCIES) $(EXTRA_libp5_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libp5_la_OBJECTS) $(libp5_la_LIBADD) $(LIBS) - -libpie.la: $(libpie_la_OBJECTS) $(libpie_la_DEPENDENCIES) $(EXTRA_libpie_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libpie_la_OBJECTS) $(libpie_la_LIBADD) $(LIBS) - -libpieusb.la: $(libpieusb_la_OBJECTS) $(libpieusb_la_DEPENDENCIES) $(EXTRA_libpieusb_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libpieusb_la_OBJECTS) $(libpieusb_la_LIBADD) $(LIBS) - -libpint.la: $(libpint_la_OBJECTS) $(libpint_la_DEPENDENCIES) $(EXTRA_libpint_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libpint_la_OBJECTS) $(libpint_la_LIBADD) $(LIBS) - -libpixma.la: $(libpixma_la_OBJECTS) $(libpixma_la_DEPENDENCIES) $(EXTRA_libpixma_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libpixma_la_OBJECTS) $(libpixma_la_LIBADD) $(LIBS) - -libplustek.la: $(libplustek_la_OBJECTS) $(libplustek_la_DEPENDENCIES) $(EXTRA_libplustek_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libplustek_la_OBJECTS) $(libplustek_la_LIBADD) $(LIBS) - -libplustek_pp.la: $(libplustek_pp_la_OBJECTS) $(libplustek_pp_la_DEPENDENCIES) $(EXTRA_libplustek_pp_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libplustek_pp_la_OBJECTS) $(libplustek_pp_la_LIBADD) $(LIBS) - -libpnm.la: $(libpnm_la_OBJECTS) $(libpnm_la_DEPENDENCIES) $(EXTRA_libpnm_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libpnm_la_OBJECTS) $(libpnm_la_LIBADD) $(LIBS) - -libqcam.la: $(libqcam_la_OBJECTS) $(libqcam_la_DEPENDENCIES) $(EXTRA_libqcam_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libqcam_la_OBJECTS) $(libqcam_la_LIBADD) $(LIBS) - -libricoh.la: $(libricoh_la_OBJECTS) $(libricoh_la_DEPENDENCIES) $(EXTRA_libricoh_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libricoh_la_OBJECTS) $(libricoh_la_LIBADD) $(LIBS) - -librts8891.la: $(librts8891_la_OBJECTS) $(librts8891_la_DEPENDENCIES) $(EXTRA_librts8891_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(librts8891_la_OBJECTS) $(librts8891_la_LIBADD) $(LIBS) - -libs9036.la: $(libs9036_la_OBJECTS) $(libs9036_la_DEPENDENCIES) $(EXTRA_libs9036_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libs9036_la_OBJECTS) $(libs9036_la_LIBADD) $(LIBS) - -libsane-abaton.la: $(libsane_abaton_la_OBJECTS) $(libsane_abaton_la_DEPENDENCIES) $(EXTRA_libsane_abaton_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_abaton_la_LINK) $(libsane_abaton_la_OBJECTS) $(libsane_abaton_la_LIBADD) $(LIBS) - -libsane-agfafocus.la: $(libsane_agfafocus_la_OBJECTS) $(libsane_agfafocus_la_DEPENDENCIES) $(EXTRA_libsane_agfafocus_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_agfafocus_la_LINK) $(libsane_agfafocus_la_OBJECTS) $(libsane_agfafocus_la_LIBADD) $(LIBS) - -libsane-apple.la: $(libsane_apple_la_OBJECTS) $(libsane_apple_la_DEPENDENCIES) $(EXTRA_libsane_apple_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_apple_la_LINK) $(libsane_apple_la_OBJECTS) $(libsane_apple_la_LIBADD) $(LIBS) - -libsane-artec.la: $(libsane_artec_la_OBJECTS) $(libsane_artec_la_DEPENDENCIES) $(EXTRA_libsane_artec_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_artec_la_LINK) $(libsane_artec_la_OBJECTS) $(libsane_artec_la_LIBADD) $(LIBS) - -libsane-artec_eplus48u.la: $(libsane_artec_eplus48u_la_OBJECTS) $(libsane_artec_eplus48u_la_DEPENDENCIES) $(EXTRA_libsane_artec_eplus48u_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_artec_eplus48u_la_LINK) $(libsane_artec_eplus48u_la_OBJECTS) $(libsane_artec_eplus48u_la_LIBADD) $(LIBS) - -libsane-as6e.la: $(libsane_as6e_la_OBJECTS) $(libsane_as6e_la_DEPENDENCIES) $(EXTRA_libsane_as6e_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_as6e_la_LINK) $(libsane_as6e_la_OBJECTS) $(libsane_as6e_la_LIBADD) $(LIBS) - -libsane-avision.la: $(libsane_avision_la_OBJECTS) $(libsane_avision_la_DEPENDENCIES) $(EXTRA_libsane_avision_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_avision_la_LINK) $(libsane_avision_la_OBJECTS) $(libsane_avision_la_LIBADD) $(LIBS) - -libsane-bh.la: $(libsane_bh_la_OBJECTS) $(libsane_bh_la_DEPENDENCIES) $(EXTRA_libsane_bh_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_bh_la_LINK) $(libsane_bh_la_OBJECTS) $(libsane_bh_la_LIBADD) $(LIBS) - -libsane-canon.la: $(libsane_canon_la_OBJECTS) $(libsane_canon_la_DEPENDENCIES) $(EXTRA_libsane_canon_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_canon_la_LINK) $(libsane_canon_la_OBJECTS) $(libsane_canon_la_LIBADD) $(LIBS) - -libsane-canon630u.la: $(libsane_canon630u_la_OBJECTS) $(libsane_canon630u_la_DEPENDENCIES) $(EXTRA_libsane_canon630u_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_canon630u_la_LINK) $(libsane_canon630u_la_OBJECTS) $(libsane_canon630u_la_LIBADD) $(LIBS) - -libsane-canon_dr.la: $(libsane_canon_dr_la_OBJECTS) $(libsane_canon_dr_la_DEPENDENCIES) $(EXTRA_libsane_canon_dr_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_canon_dr_la_LINK) $(libsane_canon_dr_la_OBJECTS) $(libsane_canon_dr_la_LIBADD) $(LIBS) - -libsane-canon_pp.la: $(libsane_canon_pp_la_OBJECTS) $(libsane_canon_pp_la_DEPENDENCIES) $(EXTRA_libsane_canon_pp_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_canon_pp_la_LINK) $(libsane_canon_pp_la_OBJECTS) $(libsane_canon_pp_la_LIBADD) $(LIBS) - -libsane-cardscan.la: $(libsane_cardscan_la_OBJECTS) $(libsane_cardscan_la_DEPENDENCIES) $(EXTRA_libsane_cardscan_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_cardscan_la_LINK) $(libsane_cardscan_la_OBJECTS) $(libsane_cardscan_la_LIBADD) $(LIBS) - -libsane-coolscan.la: $(libsane_coolscan_la_OBJECTS) $(libsane_coolscan_la_DEPENDENCIES) $(EXTRA_libsane_coolscan_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_coolscan_la_LINK) $(libsane_coolscan_la_OBJECTS) $(libsane_coolscan_la_LIBADD) $(LIBS) - -libsane-coolscan2.la: $(libsane_coolscan2_la_OBJECTS) $(libsane_coolscan2_la_DEPENDENCIES) $(EXTRA_libsane_coolscan2_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_coolscan2_la_LINK) $(libsane_coolscan2_la_OBJECTS) $(libsane_coolscan2_la_LIBADD) $(LIBS) - -libsane-coolscan3.la: $(libsane_coolscan3_la_OBJECTS) $(libsane_coolscan3_la_DEPENDENCIES) $(EXTRA_libsane_coolscan3_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_coolscan3_la_LINK) $(libsane_coolscan3_la_OBJECTS) $(libsane_coolscan3_la_LIBADD) $(LIBS) - -libsane-dc210.la: $(libsane_dc210_la_OBJECTS) $(libsane_dc210_la_DEPENDENCIES) $(EXTRA_libsane_dc210_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_dc210_la_LINK) $(libsane_dc210_la_OBJECTS) $(libsane_dc210_la_LIBADD) $(LIBS) - -libsane-dc240.la: $(libsane_dc240_la_OBJECTS) $(libsane_dc240_la_DEPENDENCIES) $(EXTRA_libsane_dc240_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_dc240_la_LINK) $(libsane_dc240_la_OBJECTS) $(libsane_dc240_la_LIBADD) $(LIBS) - -libsane-dc25.la: $(libsane_dc25_la_OBJECTS) $(libsane_dc25_la_DEPENDENCIES) $(EXTRA_libsane_dc25_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_dc25_la_LINK) $(libsane_dc25_la_OBJECTS) $(libsane_dc25_la_LIBADD) $(LIBS) - -libsane-dell1600n_net.la: $(libsane_dell1600n_net_la_OBJECTS) $(libsane_dell1600n_net_la_DEPENDENCIES) $(EXTRA_libsane_dell1600n_net_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_dell1600n_net_la_LINK) $(libsane_dell1600n_net_la_OBJECTS) $(libsane_dell1600n_net_la_LIBADD) $(LIBS) - -libsane-dll.la: $(libsane_dll_la_OBJECTS) $(libsane_dll_la_DEPENDENCIES) $(EXTRA_libsane_dll_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_dll_la_LINK) -rpath $(sanelibdir) $(libsane_dll_la_OBJECTS) $(libsane_dll_la_LIBADD) $(LIBS) - -libsane-dmc.la: $(libsane_dmc_la_OBJECTS) $(libsane_dmc_la_DEPENDENCIES) $(EXTRA_libsane_dmc_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_dmc_la_LINK) $(libsane_dmc_la_OBJECTS) $(libsane_dmc_la_LIBADD) $(LIBS) - -libsane-epjitsu.la: $(libsane_epjitsu_la_OBJECTS) $(libsane_epjitsu_la_DEPENDENCIES) $(EXTRA_libsane_epjitsu_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_epjitsu_la_LINK) $(libsane_epjitsu_la_OBJECTS) $(libsane_epjitsu_la_LIBADD) $(LIBS) - -libsane-epson.la: $(libsane_epson_la_OBJECTS) $(libsane_epson_la_DEPENDENCIES) $(EXTRA_libsane_epson_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_epson_la_LINK) $(libsane_epson_la_OBJECTS) $(libsane_epson_la_LIBADD) $(LIBS) - -libsane-epson2.la: $(libsane_epson2_la_OBJECTS) $(libsane_epson2_la_DEPENDENCIES) $(EXTRA_libsane_epson2_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_epson2_la_LINK) $(libsane_epson2_la_OBJECTS) $(libsane_epson2_la_LIBADD) $(LIBS) - -libsane-epsonds.la: $(libsane_epsonds_la_OBJECTS) $(libsane_epsonds_la_DEPENDENCIES) $(EXTRA_libsane_epsonds_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_epsonds_la_LINK) $(libsane_epsonds_la_OBJECTS) $(libsane_epsonds_la_LIBADD) $(LIBS) - -libsane-fujitsu.la: $(libsane_fujitsu_la_OBJECTS) $(libsane_fujitsu_la_DEPENDENCIES) $(EXTRA_libsane_fujitsu_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_fujitsu_la_LINK) $(libsane_fujitsu_la_OBJECTS) $(libsane_fujitsu_la_LIBADD) $(LIBS) - -libsane-genesys.la: $(libsane_genesys_la_OBJECTS) $(libsane_genesys_la_DEPENDENCIES) $(EXTRA_libsane_genesys_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_genesys_la_LINK) $(libsane_genesys_la_OBJECTS) $(libsane_genesys_la_LIBADD) $(LIBS) - -libsane-gphoto2.la: $(libsane_gphoto2_la_OBJECTS) $(libsane_gphoto2_la_DEPENDENCIES) $(EXTRA_libsane_gphoto2_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_gphoto2_la_LINK) $(libsane_gphoto2_la_OBJECTS) $(libsane_gphoto2_la_LIBADD) $(LIBS) - -libsane-gt68xx.la: $(libsane_gt68xx_la_OBJECTS) $(libsane_gt68xx_la_DEPENDENCIES) $(EXTRA_libsane_gt68xx_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_gt68xx_la_LINK) $(libsane_gt68xx_la_OBJECTS) $(libsane_gt68xx_la_LIBADD) $(LIBS) - -libsane-hp.la: $(libsane_hp_la_OBJECTS) $(libsane_hp_la_DEPENDENCIES) $(EXTRA_libsane_hp_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hp_la_LINK) $(libsane_hp_la_OBJECTS) $(libsane_hp_la_LIBADD) $(LIBS) - -libsane-hp3500.la: $(libsane_hp3500_la_OBJECTS) $(libsane_hp3500_la_DEPENDENCIES) $(EXTRA_libsane_hp3500_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hp3500_la_LINK) $(libsane_hp3500_la_OBJECTS) $(libsane_hp3500_la_LIBADD) $(LIBS) - -libsane-hp3900.la: $(libsane_hp3900_la_OBJECTS) $(libsane_hp3900_la_DEPENDENCIES) $(EXTRA_libsane_hp3900_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hp3900_la_LINK) $(libsane_hp3900_la_OBJECTS) $(libsane_hp3900_la_LIBADD) $(LIBS) - -libsane-hp4200.la: $(libsane_hp4200_la_OBJECTS) $(libsane_hp4200_la_DEPENDENCIES) $(EXTRA_libsane_hp4200_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hp4200_la_LINK) $(libsane_hp4200_la_OBJECTS) $(libsane_hp4200_la_LIBADD) $(LIBS) - -libsane-hp5400.la: $(libsane_hp5400_la_OBJECTS) $(libsane_hp5400_la_DEPENDENCIES) $(EXTRA_libsane_hp5400_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hp5400_la_LINK) $(libsane_hp5400_la_OBJECTS) $(libsane_hp5400_la_LIBADD) $(LIBS) - -libsane-hp5590.la: $(libsane_hp5590_la_OBJECTS) $(libsane_hp5590_la_DEPENDENCIES) $(EXTRA_libsane_hp5590_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hp5590_la_LINK) $(libsane_hp5590_la_OBJECTS) $(libsane_hp5590_la_LIBADD) $(LIBS) - -libsane-hpljm1005.la: $(libsane_hpljm1005_la_OBJECTS) $(libsane_hpljm1005_la_DEPENDENCIES) $(EXTRA_libsane_hpljm1005_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hpljm1005_la_LINK) $(libsane_hpljm1005_la_OBJECTS) $(libsane_hpljm1005_la_LIBADD) $(LIBS) - -libsane-hpsj5s.la: $(libsane_hpsj5s_la_OBJECTS) $(libsane_hpsj5s_la_DEPENDENCIES) $(EXTRA_libsane_hpsj5s_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hpsj5s_la_LINK) $(libsane_hpsj5s_la_OBJECTS) $(libsane_hpsj5s_la_LIBADD) $(LIBS) - -libsane-hs2p.la: $(libsane_hs2p_la_OBJECTS) $(libsane_hs2p_la_DEPENDENCIES) $(EXTRA_libsane_hs2p_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_hs2p_la_LINK) $(libsane_hs2p_la_OBJECTS) $(libsane_hs2p_la_LIBADD) $(LIBS) - -libsane-ibm.la: $(libsane_ibm_la_OBJECTS) $(libsane_ibm_la_DEPENDENCIES) $(EXTRA_libsane_ibm_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_ibm_la_LINK) $(libsane_ibm_la_OBJECTS) $(libsane_ibm_la_LIBADD) $(LIBS) - -libsane-kodak.la: $(libsane_kodak_la_OBJECTS) $(libsane_kodak_la_DEPENDENCIES) $(EXTRA_libsane_kodak_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_kodak_la_LINK) $(libsane_kodak_la_OBJECTS) $(libsane_kodak_la_LIBADD) $(LIBS) - -libsane-kodakaio.la: $(libsane_kodakaio_la_OBJECTS) $(libsane_kodakaio_la_DEPENDENCIES) $(EXTRA_libsane_kodakaio_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_kodakaio_la_LINK) $(libsane_kodakaio_la_OBJECTS) $(libsane_kodakaio_la_LIBADD) $(LIBS) - -libsane-kvs1025.la: $(libsane_kvs1025_la_OBJECTS) $(libsane_kvs1025_la_DEPENDENCIES) $(EXTRA_libsane_kvs1025_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_kvs1025_la_LINK) $(libsane_kvs1025_la_OBJECTS) $(libsane_kvs1025_la_LIBADD) $(LIBS) - -libsane-kvs20xx.la: $(libsane_kvs20xx_la_OBJECTS) $(libsane_kvs20xx_la_DEPENDENCIES) $(EXTRA_libsane_kvs20xx_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_kvs20xx_la_LINK) $(libsane_kvs20xx_la_OBJECTS) $(libsane_kvs20xx_la_LIBADD) $(LIBS) - -libsane-kvs40xx.la: $(libsane_kvs40xx_la_OBJECTS) $(libsane_kvs40xx_la_DEPENDENCIES) $(EXTRA_libsane_kvs40xx_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_kvs40xx_la_LINK) $(libsane_kvs40xx_la_OBJECTS) $(libsane_kvs40xx_la_LIBADD) $(LIBS) - -libsane-leo.la: $(libsane_leo_la_OBJECTS) $(libsane_leo_la_DEPENDENCIES) $(EXTRA_libsane_leo_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_leo_la_LINK) $(libsane_leo_la_OBJECTS) $(libsane_leo_la_LIBADD) $(LIBS) - -libsane-lexmark.la: $(libsane_lexmark_la_OBJECTS) $(libsane_lexmark_la_DEPENDENCIES) $(EXTRA_libsane_lexmark_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_lexmark_la_LINK) $(libsane_lexmark_la_OBJECTS) $(libsane_lexmark_la_LIBADD) $(LIBS) - -libsane-ma1509.la: $(libsane_ma1509_la_OBJECTS) $(libsane_ma1509_la_DEPENDENCIES) $(EXTRA_libsane_ma1509_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_ma1509_la_LINK) $(libsane_ma1509_la_OBJECTS) $(libsane_ma1509_la_LIBADD) $(LIBS) - -libsane-magicolor.la: $(libsane_magicolor_la_OBJECTS) $(libsane_magicolor_la_DEPENDENCIES) $(EXTRA_libsane_magicolor_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_magicolor_la_LINK) $(libsane_magicolor_la_OBJECTS) $(libsane_magicolor_la_LIBADD) $(LIBS) - -libsane-matsushita.la: $(libsane_matsushita_la_OBJECTS) $(libsane_matsushita_la_DEPENDENCIES) $(EXTRA_libsane_matsushita_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_matsushita_la_LINK) $(libsane_matsushita_la_OBJECTS) $(libsane_matsushita_la_LIBADD) $(LIBS) - -libsane-microtek.la: $(libsane_microtek_la_OBJECTS) $(libsane_microtek_la_DEPENDENCIES) $(EXTRA_libsane_microtek_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_microtek_la_LINK) $(libsane_microtek_la_OBJECTS) $(libsane_microtek_la_LIBADD) $(LIBS) - -libsane-microtek2.la: $(libsane_microtek2_la_OBJECTS) $(libsane_microtek2_la_DEPENDENCIES) $(EXTRA_libsane_microtek2_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_microtek2_la_LINK) $(libsane_microtek2_la_OBJECTS) $(libsane_microtek2_la_LIBADD) $(LIBS) - -libsane-mustek.la: $(libsane_mustek_la_OBJECTS) $(libsane_mustek_la_DEPENDENCIES) $(EXTRA_libsane_mustek_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_mustek_la_LINK) $(libsane_mustek_la_OBJECTS) $(libsane_mustek_la_LIBADD) $(LIBS) - -libsane-mustek_pp.la: $(libsane_mustek_pp_la_OBJECTS) $(libsane_mustek_pp_la_DEPENDENCIES) $(EXTRA_libsane_mustek_pp_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_mustek_pp_la_LINK) $(libsane_mustek_pp_la_OBJECTS) $(libsane_mustek_pp_la_LIBADD) $(LIBS) - -libsane-mustek_usb.la: $(libsane_mustek_usb_la_OBJECTS) $(libsane_mustek_usb_la_DEPENDENCIES) $(EXTRA_libsane_mustek_usb_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_mustek_usb_la_LINK) $(libsane_mustek_usb_la_OBJECTS) $(libsane_mustek_usb_la_LIBADD) $(LIBS) - -libsane-mustek_usb2.la: $(libsane_mustek_usb2_la_OBJECTS) $(libsane_mustek_usb2_la_DEPENDENCIES) $(EXTRA_libsane_mustek_usb2_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_mustek_usb2_la_LINK) $(libsane_mustek_usb2_la_OBJECTS) $(libsane_mustek_usb2_la_LIBADD) $(LIBS) - -libsane-nec.la: $(libsane_nec_la_OBJECTS) $(libsane_nec_la_DEPENDENCIES) $(EXTRA_libsane_nec_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_nec_la_LINK) $(libsane_nec_la_OBJECTS) $(libsane_nec_la_LIBADD) $(LIBS) - -libsane-net.la: $(libsane_net_la_OBJECTS) $(libsane_net_la_DEPENDENCIES) $(EXTRA_libsane_net_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_net_la_LINK) $(libsane_net_la_OBJECTS) $(libsane_net_la_LIBADD) $(LIBS) - -libsane-niash.la: $(libsane_niash_la_OBJECTS) $(libsane_niash_la_DEPENDENCIES) $(EXTRA_libsane_niash_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_niash_la_LINK) $(libsane_niash_la_OBJECTS) $(libsane_niash_la_LIBADD) $(LIBS) - -libsane-p5.la: $(libsane_p5_la_OBJECTS) $(libsane_p5_la_DEPENDENCIES) $(EXTRA_libsane_p5_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_p5_la_LINK) $(libsane_p5_la_OBJECTS) $(libsane_p5_la_LIBADD) $(LIBS) - -libsane-pie.la: $(libsane_pie_la_OBJECTS) $(libsane_pie_la_DEPENDENCIES) $(EXTRA_libsane_pie_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_pie_la_LINK) $(libsane_pie_la_OBJECTS) $(libsane_pie_la_LIBADD) $(LIBS) - -libsane-pieusb.la: $(libsane_pieusb_la_OBJECTS) $(libsane_pieusb_la_DEPENDENCIES) $(EXTRA_libsane_pieusb_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_pieusb_la_LINK) $(libsane_pieusb_la_OBJECTS) $(libsane_pieusb_la_LIBADD) $(LIBS) - -libsane-pint.la: $(libsane_pint_la_OBJECTS) $(libsane_pint_la_DEPENDENCIES) $(EXTRA_libsane_pint_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_pint_la_LINK) $(libsane_pint_la_OBJECTS) $(libsane_pint_la_LIBADD) $(LIBS) - -libsane-pixma.la: $(libsane_pixma_la_OBJECTS) $(libsane_pixma_la_DEPENDENCIES) $(EXTRA_libsane_pixma_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_pixma_la_LINK) $(libsane_pixma_la_OBJECTS) $(libsane_pixma_la_LIBADD) $(LIBS) - -libsane-plustek.la: $(libsane_plustek_la_OBJECTS) $(libsane_plustek_la_DEPENDENCIES) $(EXTRA_libsane_plustek_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_plustek_la_LINK) $(libsane_plustek_la_OBJECTS) $(libsane_plustek_la_LIBADD) $(LIBS) - -libsane-plustek_pp.la: $(libsane_plustek_pp_la_OBJECTS) $(libsane_plustek_pp_la_DEPENDENCIES) $(EXTRA_libsane_plustek_pp_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_plustek_pp_la_LINK) $(libsane_plustek_pp_la_OBJECTS) $(libsane_plustek_pp_la_LIBADD) $(LIBS) - -libsane-pnm.la: $(libsane_pnm_la_OBJECTS) $(libsane_pnm_la_DEPENDENCIES) $(EXTRA_libsane_pnm_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_pnm_la_LINK) $(libsane_pnm_la_OBJECTS) $(libsane_pnm_la_LIBADD) $(LIBS) - -libsane-qcam.la: $(libsane_qcam_la_OBJECTS) $(libsane_qcam_la_DEPENDENCIES) $(EXTRA_libsane_qcam_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_qcam_la_LINK) $(libsane_qcam_la_OBJECTS) $(libsane_qcam_la_LIBADD) $(LIBS) - -libsane-ricoh.la: $(libsane_ricoh_la_OBJECTS) $(libsane_ricoh_la_DEPENDENCIES) $(EXTRA_libsane_ricoh_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_ricoh_la_LINK) $(libsane_ricoh_la_OBJECTS) $(libsane_ricoh_la_LIBADD) $(LIBS) - -libsane-rts8891.la: $(libsane_rts8891_la_OBJECTS) $(libsane_rts8891_la_DEPENDENCIES) $(EXTRA_libsane_rts8891_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_rts8891_la_LINK) $(libsane_rts8891_la_OBJECTS) $(libsane_rts8891_la_LIBADD) $(LIBS) - -libsane-s9036.la: $(libsane_s9036_la_OBJECTS) $(libsane_s9036_la_DEPENDENCIES) $(EXTRA_libsane_s9036_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_s9036_la_LINK) $(libsane_s9036_la_OBJECTS) $(libsane_s9036_la_LIBADD) $(LIBS) - -libsane-sceptre.la: $(libsane_sceptre_la_OBJECTS) $(libsane_sceptre_la_DEPENDENCIES) $(EXTRA_libsane_sceptre_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_sceptre_la_LINK) $(libsane_sceptre_la_OBJECTS) $(libsane_sceptre_la_LIBADD) $(LIBS) - -libsane-sharp.la: $(libsane_sharp_la_OBJECTS) $(libsane_sharp_la_DEPENDENCIES) $(EXTRA_libsane_sharp_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_sharp_la_LINK) $(libsane_sharp_la_OBJECTS) $(libsane_sharp_la_LIBADD) $(LIBS) - -libsane-sm3600.la: $(libsane_sm3600_la_OBJECTS) $(libsane_sm3600_la_DEPENDENCIES) $(EXTRA_libsane_sm3600_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_sm3600_la_LINK) $(libsane_sm3600_la_OBJECTS) $(libsane_sm3600_la_LIBADD) $(LIBS) - -libsane-sm3840.la: $(libsane_sm3840_la_OBJECTS) $(libsane_sm3840_la_DEPENDENCIES) $(EXTRA_libsane_sm3840_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_sm3840_la_LINK) $(libsane_sm3840_la_OBJECTS) $(libsane_sm3840_la_LIBADD) $(LIBS) - -libsane-snapscan.la: $(libsane_snapscan_la_OBJECTS) $(libsane_snapscan_la_DEPENDENCIES) $(EXTRA_libsane_snapscan_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_snapscan_la_LINK) $(libsane_snapscan_la_OBJECTS) $(libsane_snapscan_la_LIBADD) $(LIBS) - -libsane-sp15c.la: $(libsane_sp15c_la_OBJECTS) $(libsane_sp15c_la_DEPENDENCIES) $(EXTRA_libsane_sp15c_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_sp15c_la_LINK) $(libsane_sp15c_la_OBJECTS) $(libsane_sp15c_la_LIBADD) $(LIBS) - -libsane-st400.la: $(libsane_st400_la_OBJECTS) $(libsane_st400_la_DEPENDENCIES) $(EXTRA_libsane_st400_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_st400_la_LINK) $(libsane_st400_la_OBJECTS) $(libsane_st400_la_LIBADD) $(LIBS) - -libsane-stv680.la: $(libsane_stv680_la_OBJECTS) $(libsane_stv680_la_DEPENDENCIES) $(EXTRA_libsane_stv680_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_stv680_la_LINK) $(libsane_stv680_la_OBJECTS) $(libsane_stv680_la_LIBADD) $(LIBS) - -libsane-tamarack.la: $(libsane_tamarack_la_OBJECTS) $(libsane_tamarack_la_DEPENDENCIES) $(EXTRA_libsane_tamarack_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_tamarack_la_LINK) $(libsane_tamarack_la_OBJECTS) $(libsane_tamarack_la_LIBADD) $(LIBS) - -libsane-teco1.la: $(libsane_teco1_la_OBJECTS) $(libsane_teco1_la_DEPENDENCIES) $(EXTRA_libsane_teco1_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_teco1_la_LINK) $(libsane_teco1_la_OBJECTS) $(libsane_teco1_la_LIBADD) $(LIBS) - -libsane-teco2.la: $(libsane_teco2_la_OBJECTS) $(libsane_teco2_la_DEPENDENCIES) $(EXTRA_libsane_teco2_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_teco2_la_LINK) $(libsane_teco2_la_OBJECTS) $(libsane_teco2_la_LIBADD) $(LIBS) - -libsane-teco3.la: $(libsane_teco3_la_OBJECTS) $(libsane_teco3_la_DEPENDENCIES) $(EXTRA_libsane_teco3_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_teco3_la_LINK) $(libsane_teco3_la_OBJECTS) $(libsane_teco3_la_LIBADD) $(LIBS) - -libsane-test.la: $(libsane_test_la_OBJECTS) $(libsane_test_la_DEPENDENCIES) $(EXTRA_libsane_test_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_test_la_LINK) $(libsane_test_la_OBJECTS) $(libsane_test_la_LIBADD) $(LIBS) - -libsane-u12.la: $(libsane_u12_la_OBJECTS) $(libsane_u12_la_DEPENDENCIES) $(EXTRA_libsane_u12_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_u12_la_LINK) $(libsane_u12_la_OBJECTS) $(libsane_u12_la_LIBADD) $(LIBS) - -libsane-umax.la: $(libsane_umax_la_OBJECTS) $(libsane_umax_la_DEPENDENCIES) $(EXTRA_libsane_umax_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_umax_la_LINK) $(libsane_umax_la_OBJECTS) $(libsane_umax_la_LIBADD) $(LIBS) - -libsane-umax1220u.la: $(libsane_umax1220u_la_OBJECTS) $(libsane_umax1220u_la_DEPENDENCIES) $(EXTRA_libsane_umax1220u_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_umax1220u_la_LINK) $(libsane_umax1220u_la_OBJECTS) $(libsane_umax1220u_la_LIBADD) $(LIBS) - -libsane-umax_pp.la: $(libsane_umax_pp_la_OBJECTS) $(libsane_umax_pp_la_DEPENDENCIES) $(EXTRA_libsane_umax_pp_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_umax_pp_la_LINK) $(libsane_umax_pp_la_OBJECTS) $(libsane_umax_pp_la_LIBADD) $(LIBS) - -libsane-v4l.la: $(libsane_v4l_la_OBJECTS) $(libsane_v4l_la_DEPENDENCIES) $(EXTRA_libsane_v4l_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_v4l_la_LINK) $(libsane_v4l_la_OBJECTS) $(libsane_v4l_la_LIBADD) $(LIBS) - -libsane-xerox_mfp.la: $(libsane_xerox_mfp_la_OBJECTS) $(libsane_xerox_mfp_la_DEPENDENCIES) $(EXTRA_libsane_xerox_mfp_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_xerox_mfp_la_LINK) $(libsane_xerox_mfp_la_OBJECTS) $(libsane_xerox_mfp_la_LIBADD) $(LIBS) - -libsane.la: $(libsane_la_OBJECTS) $(libsane_la_DEPENDENCIES) $(EXTRA_libsane_la_DEPENDENCIES) - $(AM_V_CCLD)$(libsane_la_LINK) -rpath $(libdir) $(libsane_la_OBJECTS) $(libsane_la_LIBADD) $(LIBS) - -libsceptre.la: $(libsceptre_la_OBJECTS) $(libsceptre_la_DEPENDENCIES) $(EXTRA_libsceptre_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libsceptre_la_OBJECTS) $(libsceptre_la_LIBADD) $(LIBS) - -libsharp.la: $(libsharp_la_OBJECTS) $(libsharp_la_DEPENDENCIES) $(EXTRA_libsharp_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libsharp_la_OBJECTS) $(libsharp_la_LIBADD) $(LIBS) - -libsm3600.la: $(libsm3600_la_OBJECTS) $(libsm3600_la_DEPENDENCIES) $(EXTRA_libsm3600_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libsm3600_la_OBJECTS) $(libsm3600_la_LIBADD) $(LIBS) - -libsm3840.la: $(libsm3840_la_OBJECTS) $(libsm3840_la_DEPENDENCIES) $(EXTRA_libsm3840_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libsm3840_la_OBJECTS) $(libsm3840_la_LIBADD) $(LIBS) - -libsnapscan.la: $(libsnapscan_la_OBJECTS) $(libsnapscan_la_DEPENDENCIES) $(EXTRA_libsnapscan_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libsnapscan_la_OBJECTS) $(libsnapscan_la_LIBADD) $(LIBS) - -libsp15c.la: $(libsp15c_la_OBJECTS) $(libsp15c_la_DEPENDENCIES) $(EXTRA_libsp15c_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libsp15c_la_OBJECTS) $(libsp15c_la_LIBADD) $(LIBS) - -libst400.la: $(libst400_la_OBJECTS) $(libst400_la_DEPENDENCIES) $(EXTRA_libst400_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libst400_la_OBJECTS) $(libst400_la_LIBADD) $(LIBS) - -libstv680.la: $(libstv680_la_OBJECTS) $(libstv680_la_DEPENDENCIES) $(EXTRA_libstv680_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libstv680_la_OBJECTS) $(libstv680_la_LIBADD) $(LIBS) - -libtamarack.la: $(libtamarack_la_OBJECTS) $(libtamarack_la_DEPENDENCIES) $(EXTRA_libtamarack_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libtamarack_la_OBJECTS) $(libtamarack_la_LIBADD) $(LIBS) - -libteco1.la: $(libteco1_la_OBJECTS) $(libteco1_la_DEPENDENCIES) $(EXTRA_libteco1_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libteco1_la_OBJECTS) $(libteco1_la_LIBADD) $(LIBS) - -libteco2.la: $(libteco2_la_OBJECTS) $(libteco2_la_DEPENDENCIES) $(EXTRA_libteco2_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libteco2_la_OBJECTS) $(libteco2_la_LIBADD) $(LIBS) - -libteco3.la: $(libteco3_la_OBJECTS) $(libteco3_la_DEPENDENCIES) $(EXTRA_libteco3_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libteco3_la_OBJECTS) $(libteco3_la_LIBADD) $(LIBS) - -libtest.la: $(libtest_la_OBJECTS) $(libtest_la_DEPENDENCIES) $(EXTRA_libtest_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libtest_la_OBJECTS) $(libtest_la_LIBADD) $(LIBS) - -libu12.la: $(libu12_la_OBJECTS) $(libu12_la_DEPENDENCIES) $(EXTRA_libu12_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libu12_la_OBJECTS) $(libu12_la_LIBADD) $(LIBS) - -libumax.la: $(libumax_la_OBJECTS) $(libumax_la_DEPENDENCIES) $(EXTRA_libumax_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libumax_la_OBJECTS) $(libumax_la_LIBADD) $(LIBS) - -libumax1220u.la: $(libumax1220u_la_OBJECTS) $(libumax1220u_la_DEPENDENCIES) $(EXTRA_libumax1220u_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libumax1220u_la_OBJECTS) $(libumax1220u_la_LIBADD) $(LIBS) - -libumax_pp.la: $(libumax_pp_la_OBJECTS) $(libumax_pp_la_DEPENDENCIES) $(EXTRA_libumax_pp_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libumax_pp_la_OBJECTS) $(libumax_pp_la_LIBADD) $(LIBS) - -libv4l.la: $(libv4l_la_OBJECTS) $(libv4l_la_DEPENDENCIES) $(EXTRA_libv4l_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libv4l_la_OBJECTS) $(libv4l_la_LIBADD) $(LIBS) - -libxerox_mfp.la: $(libxerox_mfp_la_OBJECTS) $(libxerox_mfp_la_DEPENDENCIES) $(EXTRA_libxerox_mfp_la_DEPENDENCIES) - $(AM_V_CCLD)$(LINK) $(libxerox_mfp_la_OBJECTS) $(libxerox_mfp_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libabaton_la-abaton.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libagfafocus_la-agfafocus.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libapple_la-apple.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libartec_eplus48u_la-artec_eplus48u.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libartec_la-artec.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libas6e_la-as6e.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libavision_la-avision.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libbh_la-bh.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcanon630u_la-canon630u.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcanon_dr_la-canon_dr.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcanon_la-canon.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcanon_pp_la-canon_pp-dev.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcanon_pp_la-canon_pp-io.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcanon_pp_la-canon_pp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcardscan_la-cardscan.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcoolscan2_la-coolscan2.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcoolscan3_la-coolscan3.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libcoolscan_la-coolscan.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdc210_la-dc210.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdc240_la-dc240.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdc25_la-dc25.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdell1600n_net_la-dell1600n_net.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdll_la-dll.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdll_preload_la-dll.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libdmc_la-dmc.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepjitsu_la-epjitsu.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson2_la-epson2-cct.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson2_la-epson2-commands.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson2_la-epson2-io.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson2_la-epson2-ops.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson2_la-epson2.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson2_la-epson2_net.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson2_la-epson2_scsi.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson2_la-epson2_usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson_la-epson.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson_la-epson_scsi.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepson_la-epson_usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-cmd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-io.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-jpeg.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-net.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-ops.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds-usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libepsonds_la-epsonds.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libfujitsu_la-fujitsu.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgenesys_la-genesys.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgenesys_la-genesys_gl124.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgenesys_la-genesys_gl646.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgenesys_la-genesys_gl841.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgenesys_la-genesys_gl843.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgenesys_la-genesys_gl846.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgenesys_la-genesys_gl847.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgenesys_la-genesys_low.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgphoto2_i_la-gphoto2.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgt68xx_la-gt68xx.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp3500_la-hp3500.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp3900_la-hp3900.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp4200_la-hp4200.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp5400_la-hp5400.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp5590_la-hp5590.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp_la-hp-accessor.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp_la-hp-device.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp_la-hp-handle.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp_la-hp-hpmem.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp_la-hp-option.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp_la-hp-scl.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhp_la-hp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhpljm1005_la-hpljm1005.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhpsj5s_la-hpsj5s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libhs2p_la-hs2p.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libibm_la-ibm.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkodak_la-kodak.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkodakaio_la-kodakaio.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs1025_la-kvs1025.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs1025_la-kvs1025_low.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs1025_la-kvs1025_opt.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs1025_la-kvs1025_usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs20xx_la-kvs20xx.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs20xx_la-kvs20xx_cmd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs20xx_la-kvs20xx_opt.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs40xx_la-kvs40xx.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs40xx_la-kvs40xx_cmd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libkvs40xx_la-kvs40xx_opt.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libleo_la-leo.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblexmark_la-lexmark.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/liblexmark_la-lexmark_low.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libma1509_la-ma1509.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmagicolor_la-magicolor.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmatsushita_la-matsushita.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmicrotek2_la-microtek2.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmicrotek_la-microtek.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmustek_la-mustek.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmustek_pp_la-mustek_pp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmustek_usb2_la-mustek_usb2.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libmustek_usb_la-mustek_usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnec_la-nec.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnet_la-net.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libniash_la-niash.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libp5_la-p5.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpie_la-pie.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpieusb_la-pieusb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpieusb_la-pieusb_buffer.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpieusb_la-pieusb_scancmd.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpieusb_la-pieusb_specific.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpieusb_la-pieusb_usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpint_la-pint.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma_bjnp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma_common.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma_imageclass.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma_io_sanei.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma_mp150.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma_mp730.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma_mp750.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpixma_la-pixma_mp810.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libplustek_la-plustek.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libplustek_pp_la-plustek_pp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpnm_la-pnm.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libqcam_la-qcam.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libricoh_la-ricoh.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librts8891_la-rts8891.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/librts8891_la-rts88xx_lib.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libs9036_la-s9036.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_abaton_la-abaton-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_agfafocus_la-agfafocus-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_apple_la-apple-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_artec_eplus48u_la-artec_eplus48u-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_artec_la-artec-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_as6e_la-as6e-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_avision_la-avision-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_bh_la-bh-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_canon630u_la-canon630u-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_canon_dr_la-canon_dr-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_canon_la-canon-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_canon_pp_la-canon_pp-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_cardscan_la-cardscan-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_coolscan2_la-coolscan2-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_coolscan3_la-coolscan3-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_coolscan_la-coolscan-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_dc210_la-dc210-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_dc240_la-dc240-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_dc25_la-dc25-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_dell1600n_net_la-dell1600n_net-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_dll_la-dll-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_dmc_la-dmc-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_epjitsu_la-epjitsu-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_epson2_la-epson2-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_epson_la-epson-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_epsonds_la-epsonds-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_fujitsu_la-fujitsu-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_genesys_la-genesys-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_gphoto2_la-gphoto2-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_gt68xx_la-gt68xx-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hp3500_la-hp3500-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hp3900_la-hp3900-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hp4200_la-hp4200-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hp5400_la-hp5400-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hp5590_la-hp5590-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hp_la-hp-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hpljm1005_la-hpljm1005-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hpsj5s_la-hpsj5s-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_hs2p_la-hs2p-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_ibm_la-ibm-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_kodak_la-kodak-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_kodakaio_la-kodakaio-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_kvs1025_la-kvs1025-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_kvs20xx_la-kvs20xx-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_kvs40xx_la-kvs40xx-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_la-dll-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_leo_la-leo-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_lexmark_la-lexmark-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_ma1509_la-ma1509-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_magicolor_la-magicolor-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_matsushita_la-matsushita-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_microtek2_la-microtek2-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_microtek_la-microtek-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_mustek_la-mustek-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_mustek_pp_la-mustek_pp-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_mustek_usb2_la-mustek_usb2-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_mustek_usb_la-mustek_usb-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_nec_la-nec-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_net_la-net-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_niash_la-niash-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_p5_la-p5-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_pie_la-pie-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_pieusb_la-pieusb-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_pint_la-pint-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_pixma_la-pixma-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_plustek_la-plustek-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_plustek_pp_la-plustek_pp-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_pnm_la-pnm-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_qcam_la-qcam-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_ricoh_la-ricoh-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_rts8891_la-rts8891-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_s9036_la-s9036-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_sceptre_la-sceptre-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_sharp_la-sharp-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_sm3600_la-sm3600-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_sm3840_la-sm3840-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_snapscan_la-snapscan-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_sp15c_la-sp15c-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_st400_la-st400-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_stv680_la-stv680-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_tamarack_la-tamarack-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_teco1_la-teco1-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_teco2_la-teco2-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_teco3_la-teco3-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_test_la-test-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_u12_la-u12-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_umax1220u_la-umax1220u-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_umax_la-umax-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_umax_pp_la-umax_pp-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_v4l_la-v4l-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsane_xerox_mfp_la-xerox_mfp-s.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsceptre_la-sceptre.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsharp_la-sharp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsm3600_la-sm3600.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsm3840_la-sm3840.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsnapscan_la-snapscan.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libsp15c_la-sp15c.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libst400_la-st400.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libstv680_la-stv680.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtamarack_la-tamarack.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libteco1_la-teco1.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libteco2_la-teco2.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libteco3_la-teco3.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtest_la-test.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libu12_la-u12.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libumax1220u_la-umax1220u.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libumax_la-umax.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libumax_pp_la-umax_pp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libumax_pp_la-umax_pp_low.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libumax_pp_la-umax_pp_mid.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libv4l_la-v4l.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxerox_mfp_la-xerox_mfp-tcp.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxerox_mfp_la-xerox_mfp-usb.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libxerox_mfp_la-xerox_mfp.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\ -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\ -@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\ -@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\ -@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -libabaton_la-abaton.lo: abaton.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libabaton_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libabaton_la-abaton.lo -MD -MP -MF $(DEPDIR)/libabaton_la-abaton.Tpo -c -o libabaton_la-abaton.lo `test -f 'abaton.c' || echo '$(srcdir)/'`abaton.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libabaton_la-abaton.Tpo $(DEPDIR)/libabaton_la-abaton.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='abaton.c' object='libabaton_la-abaton.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libabaton_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libabaton_la-abaton.lo `test -f 'abaton.c' || echo '$(srcdir)/'`abaton.c - -libagfafocus_la-agfafocus.lo: agfafocus.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libagfafocus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libagfafocus_la-agfafocus.lo -MD -MP -MF $(DEPDIR)/libagfafocus_la-agfafocus.Tpo -c -o libagfafocus_la-agfafocus.lo `test -f 'agfafocus.c' || echo '$(srcdir)/'`agfafocus.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libagfafocus_la-agfafocus.Tpo $(DEPDIR)/libagfafocus_la-agfafocus.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='agfafocus.c' object='libagfafocus_la-agfafocus.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libagfafocus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libagfafocus_la-agfafocus.lo `test -f 'agfafocus.c' || echo '$(srcdir)/'`agfafocus.c - -libapple_la-apple.lo: apple.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libapple_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libapple_la-apple.lo -MD -MP -MF $(DEPDIR)/libapple_la-apple.Tpo -c -o libapple_la-apple.lo `test -f 'apple.c' || echo '$(srcdir)/'`apple.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapple_la-apple.Tpo $(DEPDIR)/libapple_la-apple.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apple.c' object='libapple_la-apple.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libapple_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libapple_la-apple.lo `test -f 'apple.c' || echo '$(srcdir)/'`apple.c - -libartec_la-artec.lo: artec.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libartec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libartec_la-artec.lo -MD -MP -MF $(DEPDIR)/libartec_la-artec.Tpo -c -o libartec_la-artec.lo `test -f 'artec.c' || echo '$(srcdir)/'`artec.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libartec_la-artec.Tpo $(DEPDIR)/libartec_la-artec.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='artec.c' object='libartec_la-artec.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libartec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libartec_la-artec.lo `test -f 'artec.c' || echo '$(srcdir)/'`artec.c - -libartec_eplus48u_la-artec_eplus48u.lo: artec_eplus48u.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libartec_eplus48u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libartec_eplus48u_la-artec_eplus48u.lo -MD -MP -MF $(DEPDIR)/libartec_eplus48u_la-artec_eplus48u.Tpo -c -o libartec_eplus48u_la-artec_eplus48u.lo `test -f 'artec_eplus48u.c' || echo '$(srcdir)/'`artec_eplus48u.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libartec_eplus48u_la-artec_eplus48u.Tpo $(DEPDIR)/libartec_eplus48u_la-artec_eplus48u.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='artec_eplus48u.c' object='libartec_eplus48u_la-artec_eplus48u.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libartec_eplus48u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libartec_eplus48u_la-artec_eplus48u.lo `test -f 'artec_eplus48u.c' || echo '$(srcdir)/'`artec_eplus48u.c - -libas6e_la-as6e.lo: as6e.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libas6e_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libas6e_la-as6e.lo -MD -MP -MF $(DEPDIR)/libas6e_la-as6e.Tpo -c -o libas6e_la-as6e.lo `test -f 'as6e.c' || echo '$(srcdir)/'`as6e.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libas6e_la-as6e.Tpo $(DEPDIR)/libas6e_la-as6e.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='as6e.c' object='libas6e_la-as6e.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libas6e_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libas6e_la-as6e.lo `test -f 'as6e.c' || echo '$(srcdir)/'`as6e.c - -libavision_la-avision.lo: avision.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libavision_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libavision_la-avision.lo -MD -MP -MF $(DEPDIR)/libavision_la-avision.Tpo -c -o libavision_la-avision.lo `test -f 'avision.c' || echo '$(srcdir)/'`avision.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libavision_la-avision.Tpo $(DEPDIR)/libavision_la-avision.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='avision.c' object='libavision_la-avision.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libavision_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libavision_la-avision.lo `test -f 'avision.c' || echo '$(srcdir)/'`avision.c - -libbh_la-bh.lo: bh.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libbh_la-bh.lo -MD -MP -MF $(DEPDIR)/libbh_la-bh.Tpo -c -o libbh_la-bh.lo `test -f 'bh.c' || echo '$(srcdir)/'`bh.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libbh_la-bh.Tpo $(DEPDIR)/libbh_la-bh.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bh.c' object='libbh_la-bh.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libbh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libbh_la-bh.lo `test -f 'bh.c' || echo '$(srcdir)/'`bh.c - -libcanon_la-canon.lo: canon.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcanon_la-canon.lo -MD -MP -MF $(DEPDIR)/libcanon_la-canon.Tpo -c -o libcanon_la-canon.lo `test -f 'canon.c' || echo '$(srcdir)/'`canon.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcanon_la-canon.Tpo $(DEPDIR)/libcanon_la-canon.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon.c' object='libcanon_la-canon.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcanon_la-canon.lo `test -f 'canon.c' || echo '$(srcdir)/'`canon.c - -libcanon630u_la-canon630u.lo: canon630u.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon630u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcanon630u_la-canon630u.lo -MD -MP -MF $(DEPDIR)/libcanon630u_la-canon630u.Tpo -c -o libcanon630u_la-canon630u.lo `test -f 'canon630u.c' || echo '$(srcdir)/'`canon630u.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcanon630u_la-canon630u.Tpo $(DEPDIR)/libcanon630u_la-canon630u.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon630u.c' object='libcanon630u_la-canon630u.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon630u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcanon630u_la-canon630u.lo `test -f 'canon630u.c' || echo '$(srcdir)/'`canon630u.c - -libcanon_dr_la-canon_dr.lo: canon_dr.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_dr_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcanon_dr_la-canon_dr.lo -MD -MP -MF $(DEPDIR)/libcanon_dr_la-canon_dr.Tpo -c -o libcanon_dr_la-canon_dr.lo `test -f 'canon_dr.c' || echo '$(srcdir)/'`canon_dr.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcanon_dr_la-canon_dr.Tpo $(DEPDIR)/libcanon_dr_la-canon_dr.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon_dr.c' object='libcanon_dr_la-canon_dr.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_dr_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcanon_dr_la-canon_dr.lo `test -f 'canon_dr.c' || echo '$(srcdir)/'`canon_dr.c - -libcanon_pp_la-canon_pp.lo: canon_pp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcanon_pp_la-canon_pp.lo -MD -MP -MF $(DEPDIR)/libcanon_pp_la-canon_pp.Tpo -c -o libcanon_pp_la-canon_pp.lo `test -f 'canon_pp.c' || echo '$(srcdir)/'`canon_pp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcanon_pp_la-canon_pp.Tpo $(DEPDIR)/libcanon_pp_la-canon_pp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon_pp.c' object='libcanon_pp_la-canon_pp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcanon_pp_la-canon_pp.lo `test -f 'canon_pp.c' || echo '$(srcdir)/'`canon_pp.c - -libcanon_pp_la-canon_pp-io.lo: canon_pp-io.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcanon_pp_la-canon_pp-io.lo -MD -MP -MF $(DEPDIR)/libcanon_pp_la-canon_pp-io.Tpo -c -o libcanon_pp_la-canon_pp-io.lo `test -f 'canon_pp-io.c' || echo '$(srcdir)/'`canon_pp-io.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcanon_pp_la-canon_pp-io.Tpo $(DEPDIR)/libcanon_pp_la-canon_pp-io.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon_pp-io.c' object='libcanon_pp_la-canon_pp-io.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcanon_pp_la-canon_pp-io.lo `test -f 'canon_pp-io.c' || echo '$(srcdir)/'`canon_pp-io.c - -libcanon_pp_la-canon_pp-dev.lo: canon_pp-dev.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcanon_pp_la-canon_pp-dev.lo -MD -MP -MF $(DEPDIR)/libcanon_pp_la-canon_pp-dev.Tpo -c -o libcanon_pp_la-canon_pp-dev.lo `test -f 'canon_pp-dev.c' || echo '$(srcdir)/'`canon_pp-dev.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcanon_pp_la-canon_pp-dev.Tpo $(DEPDIR)/libcanon_pp_la-canon_pp-dev.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon_pp-dev.c' object='libcanon_pp_la-canon_pp-dev.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcanon_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcanon_pp_la-canon_pp-dev.lo `test -f 'canon_pp-dev.c' || echo '$(srcdir)/'`canon_pp-dev.c - -libcardscan_la-cardscan.lo: cardscan.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcardscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcardscan_la-cardscan.lo -MD -MP -MF $(DEPDIR)/libcardscan_la-cardscan.Tpo -c -o libcardscan_la-cardscan.lo `test -f 'cardscan.c' || echo '$(srcdir)/'`cardscan.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcardscan_la-cardscan.Tpo $(DEPDIR)/libcardscan_la-cardscan.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cardscan.c' object='libcardscan_la-cardscan.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcardscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcardscan_la-cardscan.lo `test -f 'cardscan.c' || echo '$(srcdir)/'`cardscan.c - -libcoolscan_la-coolscan.lo: coolscan.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcoolscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcoolscan_la-coolscan.lo -MD -MP -MF $(DEPDIR)/libcoolscan_la-coolscan.Tpo -c -o libcoolscan_la-coolscan.lo `test -f 'coolscan.c' || echo '$(srcdir)/'`coolscan.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcoolscan_la-coolscan.Tpo $(DEPDIR)/libcoolscan_la-coolscan.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='coolscan.c' object='libcoolscan_la-coolscan.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcoolscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcoolscan_la-coolscan.lo `test -f 'coolscan.c' || echo '$(srcdir)/'`coolscan.c - -libcoolscan2_la-coolscan2.lo: coolscan2.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcoolscan2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcoolscan2_la-coolscan2.lo -MD -MP -MF $(DEPDIR)/libcoolscan2_la-coolscan2.Tpo -c -o libcoolscan2_la-coolscan2.lo `test -f 'coolscan2.c' || echo '$(srcdir)/'`coolscan2.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcoolscan2_la-coolscan2.Tpo $(DEPDIR)/libcoolscan2_la-coolscan2.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='coolscan2.c' object='libcoolscan2_la-coolscan2.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcoolscan2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcoolscan2_la-coolscan2.lo `test -f 'coolscan2.c' || echo '$(srcdir)/'`coolscan2.c - -libcoolscan3_la-coolscan3.lo: coolscan3.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcoolscan3_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libcoolscan3_la-coolscan3.lo -MD -MP -MF $(DEPDIR)/libcoolscan3_la-coolscan3.Tpo -c -o libcoolscan3_la-coolscan3.lo `test -f 'coolscan3.c' || echo '$(srcdir)/'`coolscan3.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libcoolscan3_la-coolscan3.Tpo $(DEPDIR)/libcoolscan3_la-coolscan3.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='coolscan3.c' object='libcoolscan3_la-coolscan3.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libcoolscan3_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libcoolscan3_la-coolscan3.lo `test -f 'coolscan3.c' || echo '$(srcdir)/'`coolscan3.c - -libdc210_la-dc210.lo: dc210.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdc210_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdc210_la-dc210.lo -MD -MP -MF $(DEPDIR)/libdc210_la-dc210.Tpo -c -o libdc210_la-dc210.lo `test -f 'dc210.c' || echo '$(srcdir)/'`dc210.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdc210_la-dc210.Tpo $(DEPDIR)/libdc210_la-dc210.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dc210.c' object='libdc210_la-dc210.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdc210_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdc210_la-dc210.lo `test -f 'dc210.c' || echo '$(srcdir)/'`dc210.c - -libdc240_la-dc240.lo: dc240.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdc240_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdc240_la-dc240.lo -MD -MP -MF $(DEPDIR)/libdc240_la-dc240.Tpo -c -o libdc240_la-dc240.lo `test -f 'dc240.c' || echo '$(srcdir)/'`dc240.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdc240_la-dc240.Tpo $(DEPDIR)/libdc240_la-dc240.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dc240.c' object='libdc240_la-dc240.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdc240_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdc240_la-dc240.lo `test -f 'dc240.c' || echo '$(srcdir)/'`dc240.c - -libdc25_la-dc25.lo: dc25.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdc25_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdc25_la-dc25.lo -MD -MP -MF $(DEPDIR)/libdc25_la-dc25.Tpo -c -o libdc25_la-dc25.lo `test -f 'dc25.c' || echo '$(srcdir)/'`dc25.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdc25_la-dc25.Tpo $(DEPDIR)/libdc25_la-dc25.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dc25.c' object='libdc25_la-dc25.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdc25_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdc25_la-dc25.lo `test -f 'dc25.c' || echo '$(srcdir)/'`dc25.c - -libdell1600n_net_la-dell1600n_net.lo: dell1600n_net.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdell1600n_net_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdell1600n_net_la-dell1600n_net.lo -MD -MP -MF $(DEPDIR)/libdell1600n_net_la-dell1600n_net.Tpo -c -o libdell1600n_net_la-dell1600n_net.lo `test -f 'dell1600n_net.c' || echo '$(srcdir)/'`dell1600n_net.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdell1600n_net_la-dell1600n_net.Tpo $(DEPDIR)/libdell1600n_net_la-dell1600n_net.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dell1600n_net.c' object='libdell1600n_net_la-dell1600n_net.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdell1600n_net_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdell1600n_net_la-dell1600n_net.lo `test -f 'dell1600n_net.c' || echo '$(srcdir)/'`dell1600n_net.c - -libdll_la-dll.lo: dll.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdll_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdll_la-dll.lo -MD -MP -MF $(DEPDIR)/libdll_la-dll.Tpo -c -o libdll_la-dll.lo `test -f 'dll.c' || echo '$(srcdir)/'`dll.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdll_la-dll.Tpo $(DEPDIR)/libdll_la-dll.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dll.c' object='libdll_la-dll.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdll_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdll_la-dll.lo `test -f 'dll.c' || echo '$(srcdir)/'`dll.c - -libdll_preload_la-dll.lo: dll.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdll_preload_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdll_preload_la-dll.lo -MD -MP -MF $(DEPDIR)/libdll_preload_la-dll.Tpo -c -o libdll_preload_la-dll.lo `test -f 'dll.c' || echo '$(srcdir)/'`dll.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdll_preload_la-dll.Tpo $(DEPDIR)/libdll_preload_la-dll.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dll.c' object='libdll_preload_la-dll.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdll_preload_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdll_preload_la-dll.lo `test -f 'dll.c' || echo '$(srcdir)/'`dll.c - -libdmc_la-dmc.lo: dmc.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdmc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libdmc_la-dmc.lo -MD -MP -MF $(DEPDIR)/libdmc_la-dmc.Tpo -c -o libdmc_la-dmc.lo `test -f 'dmc.c' || echo '$(srcdir)/'`dmc.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libdmc_la-dmc.Tpo $(DEPDIR)/libdmc_la-dmc.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dmc.c' object='libdmc_la-dmc.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libdmc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libdmc_la-dmc.lo `test -f 'dmc.c' || echo '$(srcdir)/'`dmc.c - -libepjitsu_la-epjitsu.lo: epjitsu.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepjitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepjitsu_la-epjitsu.lo -MD -MP -MF $(DEPDIR)/libepjitsu_la-epjitsu.Tpo -c -o libepjitsu_la-epjitsu.lo `test -f 'epjitsu.c' || echo '$(srcdir)/'`epjitsu.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepjitsu_la-epjitsu.Tpo $(DEPDIR)/libepjitsu_la-epjitsu.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epjitsu.c' object='libepjitsu_la-epjitsu.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepjitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepjitsu_la-epjitsu.lo `test -f 'epjitsu.c' || echo '$(srcdir)/'`epjitsu.c - -libepson_la-epson.lo: epson.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson_la-epson.lo -MD -MP -MF $(DEPDIR)/libepson_la-epson.Tpo -c -o libepson_la-epson.lo `test -f 'epson.c' || echo '$(srcdir)/'`epson.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson_la-epson.Tpo $(DEPDIR)/libepson_la-epson.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson.c' object='libepson_la-epson.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson_la-epson.lo `test -f 'epson.c' || echo '$(srcdir)/'`epson.c - -libepson_la-epson_scsi.lo: epson_scsi.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson_la-epson_scsi.lo -MD -MP -MF $(DEPDIR)/libepson_la-epson_scsi.Tpo -c -o libepson_la-epson_scsi.lo `test -f 'epson_scsi.c' || echo '$(srcdir)/'`epson_scsi.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson_la-epson_scsi.Tpo $(DEPDIR)/libepson_la-epson_scsi.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson_scsi.c' object='libepson_la-epson_scsi.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson_la-epson_scsi.lo `test -f 'epson_scsi.c' || echo '$(srcdir)/'`epson_scsi.c - -libepson_la-epson_usb.lo: epson_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson_la-epson_usb.lo -MD -MP -MF $(DEPDIR)/libepson_la-epson_usb.Tpo -c -o libepson_la-epson_usb.lo `test -f 'epson_usb.c' || echo '$(srcdir)/'`epson_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson_la-epson_usb.Tpo $(DEPDIR)/libepson_la-epson_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson_usb.c' object='libepson_la-epson_usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson_la-epson_usb.lo `test -f 'epson_usb.c' || echo '$(srcdir)/'`epson_usb.c - -libepson2_la-epson2.lo: epson2.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson2_la-epson2.lo -MD -MP -MF $(DEPDIR)/libepson2_la-epson2.Tpo -c -o libepson2_la-epson2.lo `test -f 'epson2.c' || echo '$(srcdir)/'`epson2.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson2_la-epson2.Tpo $(DEPDIR)/libepson2_la-epson2.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2.c' object='libepson2_la-epson2.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson2_la-epson2.lo `test -f 'epson2.c' || echo '$(srcdir)/'`epson2.c - -libepson2_la-epson2_scsi.lo: epson2_scsi.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson2_la-epson2_scsi.lo -MD -MP -MF $(DEPDIR)/libepson2_la-epson2_scsi.Tpo -c -o libepson2_la-epson2_scsi.lo `test -f 'epson2_scsi.c' || echo '$(srcdir)/'`epson2_scsi.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson2_la-epson2_scsi.Tpo $(DEPDIR)/libepson2_la-epson2_scsi.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2_scsi.c' object='libepson2_la-epson2_scsi.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson2_la-epson2_scsi.lo `test -f 'epson2_scsi.c' || echo '$(srcdir)/'`epson2_scsi.c - -libepson2_la-epson2_usb.lo: epson2_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson2_la-epson2_usb.lo -MD -MP -MF $(DEPDIR)/libepson2_la-epson2_usb.Tpo -c -o libepson2_la-epson2_usb.lo `test -f 'epson2_usb.c' || echo '$(srcdir)/'`epson2_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson2_la-epson2_usb.Tpo $(DEPDIR)/libepson2_la-epson2_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2_usb.c' object='libepson2_la-epson2_usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson2_la-epson2_usb.lo `test -f 'epson2_usb.c' || echo '$(srcdir)/'`epson2_usb.c - -libepson2_la-epson2_net.lo: epson2_net.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson2_la-epson2_net.lo -MD -MP -MF $(DEPDIR)/libepson2_la-epson2_net.Tpo -c -o libepson2_la-epson2_net.lo `test -f 'epson2_net.c' || echo '$(srcdir)/'`epson2_net.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson2_la-epson2_net.Tpo $(DEPDIR)/libepson2_la-epson2_net.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2_net.c' object='libepson2_la-epson2_net.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson2_la-epson2_net.lo `test -f 'epson2_net.c' || echo '$(srcdir)/'`epson2_net.c - -libepson2_la-epson2-io.lo: epson2-io.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson2_la-epson2-io.lo -MD -MP -MF $(DEPDIR)/libepson2_la-epson2-io.Tpo -c -o libepson2_la-epson2-io.lo `test -f 'epson2-io.c' || echo '$(srcdir)/'`epson2-io.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson2_la-epson2-io.Tpo $(DEPDIR)/libepson2_la-epson2-io.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2-io.c' object='libepson2_la-epson2-io.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson2_la-epson2-io.lo `test -f 'epson2-io.c' || echo '$(srcdir)/'`epson2-io.c - -libepson2_la-epson2-commands.lo: epson2-commands.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson2_la-epson2-commands.lo -MD -MP -MF $(DEPDIR)/libepson2_la-epson2-commands.Tpo -c -o libepson2_la-epson2-commands.lo `test -f 'epson2-commands.c' || echo '$(srcdir)/'`epson2-commands.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson2_la-epson2-commands.Tpo $(DEPDIR)/libepson2_la-epson2-commands.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2-commands.c' object='libepson2_la-epson2-commands.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson2_la-epson2-commands.lo `test -f 'epson2-commands.c' || echo '$(srcdir)/'`epson2-commands.c - -libepson2_la-epson2-ops.lo: epson2-ops.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson2_la-epson2-ops.lo -MD -MP -MF $(DEPDIR)/libepson2_la-epson2-ops.Tpo -c -o libepson2_la-epson2-ops.lo `test -f 'epson2-ops.c' || echo '$(srcdir)/'`epson2-ops.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson2_la-epson2-ops.Tpo $(DEPDIR)/libepson2_la-epson2-ops.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2-ops.c' object='libepson2_la-epson2-ops.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson2_la-epson2-ops.lo `test -f 'epson2-ops.c' || echo '$(srcdir)/'`epson2-ops.c - -libepson2_la-epson2-cct.lo: epson2-cct.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepson2_la-epson2-cct.lo -MD -MP -MF $(DEPDIR)/libepson2_la-epson2-cct.Tpo -c -o libepson2_la-epson2-cct.lo `test -f 'epson2-cct.c' || echo '$(srcdir)/'`epson2-cct.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepson2_la-epson2-cct.Tpo $(DEPDIR)/libepson2_la-epson2-cct.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2-cct.c' object='libepson2_la-epson2-cct.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepson2_la-epson2-cct.lo `test -f 'epson2-cct.c' || echo '$(srcdir)/'`epson2-cct.c - -libepsonds_la-epsonds.lo: epsonds.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepsonds_la-epsonds.lo -MD -MP -MF $(DEPDIR)/libepsonds_la-epsonds.Tpo -c -o libepsonds_la-epsonds.lo `test -f 'epsonds.c' || echo '$(srcdir)/'`epsonds.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepsonds_la-epsonds.Tpo $(DEPDIR)/libepsonds_la-epsonds.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds.c' object='libepsonds_la-epsonds.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds.lo `test -f 'epsonds.c' || echo '$(srcdir)/'`epsonds.c - -libepsonds_la-epsonds-usb.lo: epsonds-usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepsonds_la-epsonds-usb.lo -MD -MP -MF $(DEPDIR)/libepsonds_la-epsonds-usb.Tpo -c -o libepsonds_la-epsonds-usb.lo `test -f 'epsonds-usb.c' || echo '$(srcdir)/'`epsonds-usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepsonds_la-epsonds-usb.Tpo $(DEPDIR)/libepsonds_la-epsonds-usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds-usb.c' object='libepsonds_la-epsonds-usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds-usb.lo `test -f 'epsonds-usb.c' || echo '$(srcdir)/'`epsonds-usb.c - -libepsonds_la-epsonds-io.lo: epsonds-io.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepsonds_la-epsonds-io.lo -MD -MP -MF $(DEPDIR)/libepsonds_la-epsonds-io.Tpo -c -o libepsonds_la-epsonds-io.lo `test -f 'epsonds-io.c' || echo '$(srcdir)/'`epsonds-io.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepsonds_la-epsonds-io.Tpo $(DEPDIR)/libepsonds_la-epsonds-io.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds-io.c' object='libepsonds_la-epsonds-io.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds-io.lo `test -f 'epsonds-io.c' || echo '$(srcdir)/'`epsonds-io.c - -libepsonds_la-epsonds-cmd.lo: epsonds-cmd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepsonds_la-epsonds-cmd.lo -MD -MP -MF $(DEPDIR)/libepsonds_la-epsonds-cmd.Tpo -c -o libepsonds_la-epsonds-cmd.lo `test -f 'epsonds-cmd.c' || echo '$(srcdir)/'`epsonds-cmd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepsonds_la-epsonds-cmd.Tpo $(DEPDIR)/libepsonds_la-epsonds-cmd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds-cmd.c' object='libepsonds_la-epsonds-cmd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds-cmd.lo `test -f 'epsonds-cmd.c' || echo '$(srcdir)/'`epsonds-cmd.c - -libepsonds_la-epsonds-ops.lo: epsonds-ops.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepsonds_la-epsonds-ops.lo -MD -MP -MF $(DEPDIR)/libepsonds_la-epsonds-ops.Tpo -c -o libepsonds_la-epsonds-ops.lo `test -f 'epsonds-ops.c' || echo '$(srcdir)/'`epsonds-ops.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepsonds_la-epsonds-ops.Tpo $(DEPDIR)/libepsonds_la-epsonds-ops.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds-ops.c' object='libepsonds_la-epsonds-ops.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds-ops.lo `test -f 'epsonds-ops.c' || echo '$(srcdir)/'`epsonds-ops.c - -libepsonds_la-epsonds-jpeg.lo: epsonds-jpeg.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepsonds_la-epsonds-jpeg.lo -MD -MP -MF $(DEPDIR)/libepsonds_la-epsonds-jpeg.Tpo -c -o libepsonds_la-epsonds-jpeg.lo `test -f 'epsonds-jpeg.c' || echo '$(srcdir)/'`epsonds-jpeg.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepsonds_la-epsonds-jpeg.Tpo $(DEPDIR)/libepsonds_la-epsonds-jpeg.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds-jpeg.c' object='libepsonds_la-epsonds-jpeg.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds-jpeg.lo `test -f 'epsonds-jpeg.c' || echo '$(srcdir)/'`epsonds-jpeg.c - -libepsonds_la-epsonds-net.lo: epsonds-net.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libepsonds_la-epsonds-net.lo -MD -MP -MF $(DEPDIR)/libepsonds_la-epsonds-net.Tpo -c -o libepsonds_la-epsonds-net.lo `test -f 'epsonds-net.c' || echo '$(srcdir)/'`epsonds-net.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libepsonds_la-epsonds-net.Tpo $(DEPDIR)/libepsonds_la-epsonds-net.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds-net.c' object='libepsonds_la-epsonds-net.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libepsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libepsonds_la-epsonds-net.lo `test -f 'epsonds-net.c' || echo '$(srcdir)/'`epsonds-net.c - -libfujitsu_la-fujitsu.lo: fujitsu.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfujitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libfujitsu_la-fujitsu.lo -MD -MP -MF $(DEPDIR)/libfujitsu_la-fujitsu.Tpo -c -o libfujitsu_la-fujitsu.lo `test -f 'fujitsu.c' || echo '$(srcdir)/'`fujitsu.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libfujitsu_la-fujitsu.Tpo $(DEPDIR)/libfujitsu_la-fujitsu.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fujitsu.c' object='libfujitsu_la-fujitsu.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libfujitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libfujitsu_la-fujitsu.lo `test -f 'fujitsu.c' || echo '$(srcdir)/'`fujitsu.c - -libgenesys_la-genesys.lo: genesys.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgenesys_la-genesys.lo -MD -MP -MF $(DEPDIR)/libgenesys_la-genesys.Tpo -c -o libgenesys_la-genesys.lo `test -f 'genesys.c' || echo '$(srcdir)/'`genesys.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgenesys_la-genesys.Tpo $(DEPDIR)/libgenesys_la-genesys.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys.c' object='libgenesys_la-genesys.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgenesys_la-genesys.lo `test -f 'genesys.c' || echo '$(srcdir)/'`genesys.c - -libgenesys_la-genesys_gl646.lo: genesys_gl646.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgenesys_la-genesys_gl646.lo -MD -MP -MF $(DEPDIR)/libgenesys_la-genesys_gl646.Tpo -c -o libgenesys_la-genesys_gl646.lo `test -f 'genesys_gl646.c' || echo '$(srcdir)/'`genesys_gl646.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgenesys_la-genesys_gl646.Tpo $(DEPDIR)/libgenesys_la-genesys_gl646.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys_gl646.c' object='libgenesys_la-genesys_gl646.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgenesys_la-genesys_gl646.lo `test -f 'genesys_gl646.c' || echo '$(srcdir)/'`genesys_gl646.c - -libgenesys_la-genesys_gl841.lo: genesys_gl841.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgenesys_la-genesys_gl841.lo -MD -MP -MF $(DEPDIR)/libgenesys_la-genesys_gl841.Tpo -c -o libgenesys_la-genesys_gl841.lo `test -f 'genesys_gl841.c' || echo '$(srcdir)/'`genesys_gl841.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgenesys_la-genesys_gl841.Tpo $(DEPDIR)/libgenesys_la-genesys_gl841.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys_gl841.c' object='libgenesys_la-genesys_gl841.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgenesys_la-genesys_gl841.lo `test -f 'genesys_gl841.c' || echo '$(srcdir)/'`genesys_gl841.c - -libgenesys_la-genesys_gl843.lo: genesys_gl843.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgenesys_la-genesys_gl843.lo -MD -MP -MF $(DEPDIR)/libgenesys_la-genesys_gl843.Tpo -c -o libgenesys_la-genesys_gl843.lo `test -f 'genesys_gl843.c' || echo '$(srcdir)/'`genesys_gl843.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgenesys_la-genesys_gl843.Tpo $(DEPDIR)/libgenesys_la-genesys_gl843.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys_gl843.c' object='libgenesys_la-genesys_gl843.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgenesys_la-genesys_gl843.lo `test -f 'genesys_gl843.c' || echo '$(srcdir)/'`genesys_gl843.c - -libgenesys_la-genesys_gl846.lo: genesys_gl846.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgenesys_la-genesys_gl846.lo -MD -MP -MF $(DEPDIR)/libgenesys_la-genesys_gl846.Tpo -c -o libgenesys_la-genesys_gl846.lo `test -f 'genesys_gl846.c' || echo '$(srcdir)/'`genesys_gl846.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgenesys_la-genesys_gl846.Tpo $(DEPDIR)/libgenesys_la-genesys_gl846.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys_gl846.c' object='libgenesys_la-genesys_gl846.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgenesys_la-genesys_gl846.lo `test -f 'genesys_gl846.c' || echo '$(srcdir)/'`genesys_gl846.c - -libgenesys_la-genesys_gl847.lo: genesys_gl847.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgenesys_la-genesys_gl847.lo -MD -MP -MF $(DEPDIR)/libgenesys_la-genesys_gl847.Tpo -c -o libgenesys_la-genesys_gl847.lo `test -f 'genesys_gl847.c' || echo '$(srcdir)/'`genesys_gl847.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgenesys_la-genesys_gl847.Tpo $(DEPDIR)/libgenesys_la-genesys_gl847.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys_gl847.c' object='libgenesys_la-genesys_gl847.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgenesys_la-genesys_gl847.lo `test -f 'genesys_gl847.c' || echo '$(srcdir)/'`genesys_gl847.c - -libgenesys_la-genesys_gl124.lo: genesys_gl124.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgenesys_la-genesys_gl124.lo -MD -MP -MF $(DEPDIR)/libgenesys_la-genesys_gl124.Tpo -c -o libgenesys_la-genesys_gl124.lo `test -f 'genesys_gl124.c' || echo '$(srcdir)/'`genesys_gl124.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgenesys_la-genesys_gl124.Tpo $(DEPDIR)/libgenesys_la-genesys_gl124.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys_gl124.c' object='libgenesys_la-genesys_gl124.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgenesys_la-genesys_gl124.lo `test -f 'genesys_gl124.c' || echo '$(srcdir)/'`genesys_gl124.c - -libgenesys_la-genesys_low.lo: genesys_low.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgenesys_la-genesys_low.lo -MD -MP -MF $(DEPDIR)/libgenesys_la-genesys_low.Tpo -c -o libgenesys_la-genesys_low.lo `test -f 'genesys_low.c' || echo '$(srcdir)/'`genesys_low.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgenesys_la-genesys_low.Tpo $(DEPDIR)/libgenesys_la-genesys_low.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys_low.c' object='libgenesys_la-genesys_low.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgenesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgenesys_la-genesys_low.lo `test -f 'genesys_low.c' || echo '$(srcdir)/'`genesys_low.c - -libgphoto2_i_la-gphoto2.lo: gphoto2.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgphoto2_i_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgphoto2_i_la-gphoto2.lo -MD -MP -MF $(DEPDIR)/libgphoto2_i_la-gphoto2.Tpo -c -o libgphoto2_i_la-gphoto2.lo `test -f 'gphoto2.c' || echo '$(srcdir)/'`gphoto2.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgphoto2_i_la-gphoto2.Tpo $(DEPDIR)/libgphoto2_i_la-gphoto2.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gphoto2.c' object='libgphoto2_i_la-gphoto2.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgphoto2_i_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgphoto2_i_la-gphoto2.lo `test -f 'gphoto2.c' || echo '$(srcdir)/'`gphoto2.c - -libgt68xx_la-gt68xx.lo: gt68xx.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgt68xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libgt68xx_la-gt68xx.lo -MD -MP -MF $(DEPDIR)/libgt68xx_la-gt68xx.Tpo -c -o libgt68xx_la-gt68xx.lo `test -f 'gt68xx.c' || echo '$(srcdir)/'`gt68xx.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgt68xx_la-gt68xx.Tpo $(DEPDIR)/libgt68xx_la-gt68xx.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gt68xx.c' object='libgt68xx_la-gt68xx.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgt68xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libgt68xx_la-gt68xx.lo `test -f 'gt68xx.c' || echo '$(srcdir)/'`gt68xx.c - -libhp_la-hp.lo: hp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp_la-hp.lo -MD -MP -MF $(DEPDIR)/libhp_la-hp.Tpo -c -o libhp_la-hp.lo `test -f 'hp.c' || echo '$(srcdir)/'`hp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp_la-hp.Tpo $(DEPDIR)/libhp_la-hp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp.c' object='libhp_la-hp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp_la-hp.lo `test -f 'hp.c' || echo '$(srcdir)/'`hp.c - -libhp_la-hp-accessor.lo: hp-accessor.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp_la-hp-accessor.lo -MD -MP -MF $(DEPDIR)/libhp_la-hp-accessor.Tpo -c -o libhp_la-hp-accessor.lo `test -f 'hp-accessor.c' || echo '$(srcdir)/'`hp-accessor.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp_la-hp-accessor.Tpo $(DEPDIR)/libhp_la-hp-accessor.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp-accessor.c' object='libhp_la-hp-accessor.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp_la-hp-accessor.lo `test -f 'hp-accessor.c' || echo '$(srcdir)/'`hp-accessor.c - -libhp_la-hp-device.lo: hp-device.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp_la-hp-device.lo -MD -MP -MF $(DEPDIR)/libhp_la-hp-device.Tpo -c -o libhp_la-hp-device.lo `test -f 'hp-device.c' || echo '$(srcdir)/'`hp-device.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp_la-hp-device.Tpo $(DEPDIR)/libhp_la-hp-device.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp-device.c' object='libhp_la-hp-device.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp_la-hp-device.lo `test -f 'hp-device.c' || echo '$(srcdir)/'`hp-device.c - -libhp_la-hp-handle.lo: hp-handle.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp_la-hp-handle.lo -MD -MP -MF $(DEPDIR)/libhp_la-hp-handle.Tpo -c -o libhp_la-hp-handle.lo `test -f 'hp-handle.c' || echo '$(srcdir)/'`hp-handle.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp_la-hp-handle.Tpo $(DEPDIR)/libhp_la-hp-handle.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp-handle.c' object='libhp_la-hp-handle.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp_la-hp-handle.lo `test -f 'hp-handle.c' || echo '$(srcdir)/'`hp-handle.c - -libhp_la-hp-hpmem.lo: hp-hpmem.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp_la-hp-hpmem.lo -MD -MP -MF $(DEPDIR)/libhp_la-hp-hpmem.Tpo -c -o libhp_la-hp-hpmem.lo `test -f 'hp-hpmem.c' || echo '$(srcdir)/'`hp-hpmem.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp_la-hp-hpmem.Tpo $(DEPDIR)/libhp_la-hp-hpmem.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp-hpmem.c' object='libhp_la-hp-hpmem.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp_la-hp-hpmem.lo `test -f 'hp-hpmem.c' || echo '$(srcdir)/'`hp-hpmem.c - -libhp_la-hp-option.lo: hp-option.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp_la-hp-option.lo -MD -MP -MF $(DEPDIR)/libhp_la-hp-option.Tpo -c -o libhp_la-hp-option.lo `test -f 'hp-option.c' || echo '$(srcdir)/'`hp-option.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp_la-hp-option.Tpo $(DEPDIR)/libhp_la-hp-option.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp-option.c' object='libhp_la-hp-option.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp_la-hp-option.lo `test -f 'hp-option.c' || echo '$(srcdir)/'`hp-option.c - -libhp_la-hp-scl.lo: hp-scl.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp_la-hp-scl.lo -MD -MP -MF $(DEPDIR)/libhp_la-hp-scl.Tpo -c -o libhp_la-hp-scl.lo `test -f 'hp-scl.c' || echo '$(srcdir)/'`hp-scl.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp_la-hp-scl.Tpo $(DEPDIR)/libhp_la-hp-scl.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp-scl.c' object='libhp_la-hp-scl.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp_la-hp-scl.lo `test -f 'hp-scl.c' || echo '$(srcdir)/'`hp-scl.c - -libhp3500_la-hp3500.lo: hp3500.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp3500_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp3500_la-hp3500.lo -MD -MP -MF $(DEPDIR)/libhp3500_la-hp3500.Tpo -c -o libhp3500_la-hp3500.lo `test -f 'hp3500.c' || echo '$(srcdir)/'`hp3500.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp3500_la-hp3500.Tpo $(DEPDIR)/libhp3500_la-hp3500.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp3500.c' object='libhp3500_la-hp3500.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp3500_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp3500_la-hp3500.lo `test -f 'hp3500.c' || echo '$(srcdir)/'`hp3500.c - -libhp3900_la-hp3900.lo: hp3900.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp3900_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp3900_la-hp3900.lo -MD -MP -MF $(DEPDIR)/libhp3900_la-hp3900.Tpo -c -o libhp3900_la-hp3900.lo `test -f 'hp3900.c' || echo '$(srcdir)/'`hp3900.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp3900_la-hp3900.Tpo $(DEPDIR)/libhp3900_la-hp3900.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp3900.c' object='libhp3900_la-hp3900.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp3900_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp3900_la-hp3900.lo `test -f 'hp3900.c' || echo '$(srcdir)/'`hp3900.c - -libhp4200_la-hp4200.lo: hp4200.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp4200_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp4200_la-hp4200.lo -MD -MP -MF $(DEPDIR)/libhp4200_la-hp4200.Tpo -c -o libhp4200_la-hp4200.lo `test -f 'hp4200.c' || echo '$(srcdir)/'`hp4200.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp4200_la-hp4200.Tpo $(DEPDIR)/libhp4200_la-hp4200.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp4200.c' object='libhp4200_la-hp4200.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp4200_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp4200_la-hp4200.lo `test -f 'hp4200.c' || echo '$(srcdir)/'`hp4200.c - -libhp5400_la-hp5400.lo: hp5400.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp5400_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp5400_la-hp5400.lo -MD -MP -MF $(DEPDIR)/libhp5400_la-hp5400.Tpo -c -o libhp5400_la-hp5400.lo `test -f 'hp5400.c' || echo '$(srcdir)/'`hp5400.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp5400_la-hp5400.Tpo $(DEPDIR)/libhp5400_la-hp5400.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp5400.c' object='libhp5400_la-hp5400.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp5400_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp5400_la-hp5400.lo `test -f 'hp5400.c' || echo '$(srcdir)/'`hp5400.c - -libhp5590_la-hp5590.lo: hp5590.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp5590_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhp5590_la-hp5590.lo -MD -MP -MF $(DEPDIR)/libhp5590_la-hp5590.Tpo -c -o libhp5590_la-hp5590.lo `test -f 'hp5590.c' || echo '$(srcdir)/'`hp5590.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhp5590_la-hp5590.Tpo $(DEPDIR)/libhp5590_la-hp5590.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp5590.c' object='libhp5590_la-hp5590.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhp5590_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhp5590_la-hp5590.lo `test -f 'hp5590.c' || echo '$(srcdir)/'`hp5590.c - -libhpljm1005_la-hpljm1005.lo: hpljm1005.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhpljm1005_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhpljm1005_la-hpljm1005.lo -MD -MP -MF $(DEPDIR)/libhpljm1005_la-hpljm1005.Tpo -c -o libhpljm1005_la-hpljm1005.lo `test -f 'hpljm1005.c' || echo '$(srcdir)/'`hpljm1005.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhpljm1005_la-hpljm1005.Tpo $(DEPDIR)/libhpljm1005_la-hpljm1005.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hpljm1005.c' object='libhpljm1005_la-hpljm1005.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhpljm1005_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhpljm1005_la-hpljm1005.lo `test -f 'hpljm1005.c' || echo '$(srcdir)/'`hpljm1005.c - -libhpsj5s_la-hpsj5s.lo: hpsj5s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhpsj5s_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhpsj5s_la-hpsj5s.lo -MD -MP -MF $(DEPDIR)/libhpsj5s_la-hpsj5s.Tpo -c -o libhpsj5s_la-hpsj5s.lo `test -f 'hpsj5s.c' || echo '$(srcdir)/'`hpsj5s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhpsj5s_la-hpsj5s.Tpo $(DEPDIR)/libhpsj5s_la-hpsj5s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hpsj5s.c' object='libhpsj5s_la-hpsj5s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhpsj5s_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhpsj5s_la-hpsj5s.lo `test -f 'hpsj5s.c' || echo '$(srcdir)/'`hpsj5s.c - -libhs2p_la-hs2p.lo: hs2p.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhs2p_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libhs2p_la-hs2p.lo -MD -MP -MF $(DEPDIR)/libhs2p_la-hs2p.Tpo -c -o libhs2p_la-hs2p.lo `test -f 'hs2p.c' || echo '$(srcdir)/'`hs2p.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libhs2p_la-hs2p.Tpo $(DEPDIR)/libhs2p_la-hs2p.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hs2p.c' object='libhs2p_la-hs2p.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libhs2p_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libhs2p_la-hs2p.lo `test -f 'hs2p.c' || echo '$(srcdir)/'`hs2p.c - -libibm_la-ibm.lo: ibm.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libibm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libibm_la-ibm.lo -MD -MP -MF $(DEPDIR)/libibm_la-ibm.Tpo -c -o libibm_la-ibm.lo `test -f 'ibm.c' || echo '$(srcdir)/'`ibm.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libibm_la-ibm.Tpo $(DEPDIR)/libibm_la-ibm.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ibm.c' object='libibm_la-ibm.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libibm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libibm_la-ibm.lo `test -f 'ibm.c' || echo '$(srcdir)/'`ibm.c - -libkodak_la-kodak.lo: kodak.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkodak_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkodak_la-kodak.lo -MD -MP -MF $(DEPDIR)/libkodak_la-kodak.Tpo -c -o libkodak_la-kodak.lo `test -f 'kodak.c' || echo '$(srcdir)/'`kodak.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkodak_la-kodak.Tpo $(DEPDIR)/libkodak_la-kodak.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kodak.c' object='libkodak_la-kodak.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkodak_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkodak_la-kodak.lo `test -f 'kodak.c' || echo '$(srcdir)/'`kodak.c - -libkodakaio_la-kodakaio.lo: kodakaio.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkodakaio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkodakaio_la-kodakaio.lo -MD -MP -MF $(DEPDIR)/libkodakaio_la-kodakaio.Tpo -c -o libkodakaio_la-kodakaio.lo `test -f 'kodakaio.c' || echo '$(srcdir)/'`kodakaio.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkodakaio_la-kodakaio.Tpo $(DEPDIR)/libkodakaio_la-kodakaio.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kodakaio.c' object='libkodakaio_la-kodakaio.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkodakaio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkodakaio_la-kodakaio.lo `test -f 'kodakaio.c' || echo '$(srcdir)/'`kodakaio.c - -libkvs1025_la-kvs1025.lo: kvs1025.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs1025_la-kvs1025.lo -MD -MP -MF $(DEPDIR)/libkvs1025_la-kvs1025.Tpo -c -o libkvs1025_la-kvs1025.lo `test -f 'kvs1025.c' || echo '$(srcdir)/'`kvs1025.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs1025_la-kvs1025.Tpo $(DEPDIR)/libkvs1025_la-kvs1025.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs1025.c' object='libkvs1025_la-kvs1025.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs1025_la-kvs1025.lo `test -f 'kvs1025.c' || echo '$(srcdir)/'`kvs1025.c - -libkvs1025_la-kvs1025_low.lo: kvs1025_low.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs1025_la-kvs1025_low.lo -MD -MP -MF $(DEPDIR)/libkvs1025_la-kvs1025_low.Tpo -c -o libkvs1025_la-kvs1025_low.lo `test -f 'kvs1025_low.c' || echo '$(srcdir)/'`kvs1025_low.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs1025_la-kvs1025_low.Tpo $(DEPDIR)/libkvs1025_la-kvs1025_low.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs1025_low.c' object='libkvs1025_la-kvs1025_low.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs1025_la-kvs1025_low.lo `test -f 'kvs1025_low.c' || echo '$(srcdir)/'`kvs1025_low.c - -libkvs1025_la-kvs1025_opt.lo: kvs1025_opt.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs1025_la-kvs1025_opt.lo -MD -MP -MF $(DEPDIR)/libkvs1025_la-kvs1025_opt.Tpo -c -o libkvs1025_la-kvs1025_opt.lo `test -f 'kvs1025_opt.c' || echo '$(srcdir)/'`kvs1025_opt.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs1025_la-kvs1025_opt.Tpo $(DEPDIR)/libkvs1025_la-kvs1025_opt.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs1025_opt.c' object='libkvs1025_la-kvs1025_opt.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs1025_la-kvs1025_opt.lo `test -f 'kvs1025_opt.c' || echo '$(srcdir)/'`kvs1025_opt.c - -libkvs1025_la-kvs1025_usb.lo: kvs1025_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs1025_la-kvs1025_usb.lo -MD -MP -MF $(DEPDIR)/libkvs1025_la-kvs1025_usb.Tpo -c -o libkvs1025_la-kvs1025_usb.lo `test -f 'kvs1025_usb.c' || echo '$(srcdir)/'`kvs1025_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs1025_la-kvs1025_usb.Tpo $(DEPDIR)/libkvs1025_la-kvs1025_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs1025_usb.c' object='libkvs1025_la-kvs1025_usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs1025_la-kvs1025_usb.lo `test -f 'kvs1025_usb.c' || echo '$(srcdir)/'`kvs1025_usb.c - -libkvs20xx_la-kvs20xx.lo: kvs20xx.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs20xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs20xx_la-kvs20xx.lo -MD -MP -MF $(DEPDIR)/libkvs20xx_la-kvs20xx.Tpo -c -o libkvs20xx_la-kvs20xx.lo `test -f 'kvs20xx.c' || echo '$(srcdir)/'`kvs20xx.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs20xx_la-kvs20xx.Tpo $(DEPDIR)/libkvs20xx_la-kvs20xx.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs20xx.c' object='libkvs20xx_la-kvs20xx.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs20xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs20xx_la-kvs20xx.lo `test -f 'kvs20xx.c' || echo '$(srcdir)/'`kvs20xx.c - -libkvs20xx_la-kvs20xx_cmd.lo: kvs20xx_cmd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs20xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs20xx_la-kvs20xx_cmd.lo -MD -MP -MF $(DEPDIR)/libkvs20xx_la-kvs20xx_cmd.Tpo -c -o libkvs20xx_la-kvs20xx_cmd.lo `test -f 'kvs20xx_cmd.c' || echo '$(srcdir)/'`kvs20xx_cmd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs20xx_la-kvs20xx_cmd.Tpo $(DEPDIR)/libkvs20xx_la-kvs20xx_cmd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs20xx_cmd.c' object='libkvs20xx_la-kvs20xx_cmd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs20xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs20xx_la-kvs20xx_cmd.lo `test -f 'kvs20xx_cmd.c' || echo '$(srcdir)/'`kvs20xx_cmd.c - -libkvs20xx_la-kvs20xx_opt.lo: kvs20xx_opt.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs20xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs20xx_la-kvs20xx_opt.lo -MD -MP -MF $(DEPDIR)/libkvs20xx_la-kvs20xx_opt.Tpo -c -o libkvs20xx_la-kvs20xx_opt.lo `test -f 'kvs20xx_opt.c' || echo '$(srcdir)/'`kvs20xx_opt.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs20xx_la-kvs20xx_opt.Tpo $(DEPDIR)/libkvs20xx_la-kvs20xx_opt.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs20xx_opt.c' object='libkvs20xx_la-kvs20xx_opt.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs20xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs20xx_la-kvs20xx_opt.lo `test -f 'kvs20xx_opt.c' || echo '$(srcdir)/'`kvs20xx_opt.c - -libkvs40xx_la-kvs40xx.lo: kvs40xx.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs40xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs40xx_la-kvs40xx.lo -MD -MP -MF $(DEPDIR)/libkvs40xx_la-kvs40xx.Tpo -c -o libkvs40xx_la-kvs40xx.lo `test -f 'kvs40xx.c' || echo '$(srcdir)/'`kvs40xx.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs40xx_la-kvs40xx.Tpo $(DEPDIR)/libkvs40xx_la-kvs40xx.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs40xx.c' object='libkvs40xx_la-kvs40xx.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs40xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs40xx_la-kvs40xx.lo `test -f 'kvs40xx.c' || echo '$(srcdir)/'`kvs40xx.c - -libkvs40xx_la-kvs40xx_cmd.lo: kvs40xx_cmd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs40xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs40xx_la-kvs40xx_cmd.lo -MD -MP -MF $(DEPDIR)/libkvs40xx_la-kvs40xx_cmd.Tpo -c -o libkvs40xx_la-kvs40xx_cmd.lo `test -f 'kvs40xx_cmd.c' || echo '$(srcdir)/'`kvs40xx_cmd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs40xx_la-kvs40xx_cmd.Tpo $(DEPDIR)/libkvs40xx_la-kvs40xx_cmd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs40xx_cmd.c' object='libkvs40xx_la-kvs40xx_cmd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs40xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs40xx_la-kvs40xx_cmd.lo `test -f 'kvs40xx_cmd.c' || echo '$(srcdir)/'`kvs40xx_cmd.c - -libkvs40xx_la-kvs40xx_opt.lo: kvs40xx_opt.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs40xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libkvs40xx_la-kvs40xx_opt.lo -MD -MP -MF $(DEPDIR)/libkvs40xx_la-kvs40xx_opt.Tpo -c -o libkvs40xx_la-kvs40xx_opt.lo `test -f 'kvs40xx_opt.c' || echo '$(srcdir)/'`kvs40xx_opt.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libkvs40xx_la-kvs40xx_opt.Tpo $(DEPDIR)/libkvs40xx_la-kvs40xx_opt.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs40xx_opt.c' object='libkvs40xx_la-kvs40xx_opt.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libkvs40xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libkvs40xx_la-kvs40xx_opt.lo `test -f 'kvs40xx_opt.c' || echo '$(srcdir)/'`kvs40xx_opt.c - -libleo_la-leo.lo: leo.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libleo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libleo_la-leo.lo -MD -MP -MF $(DEPDIR)/libleo_la-leo.Tpo -c -o libleo_la-leo.lo `test -f 'leo.c' || echo '$(srcdir)/'`leo.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libleo_la-leo.Tpo $(DEPDIR)/libleo_la-leo.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='leo.c' object='libleo_la-leo.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libleo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libleo_la-leo.lo `test -f 'leo.c' || echo '$(srcdir)/'`leo.c - -liblexmark_la-lexmark.lo: lexmark.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblexmark_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblexmark_la-lexmark.lo -MD -MP -MF $(DEPDIR)/liblexmark_la-lexmark.Tpo -c -o liblexmark_la-lexmark.lo `test -f 'lexmark.c' || echo '$(srcdir)/'`lexmark.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblexmark_la-lexmark.Tpo $(DEPDIR)/liblexmark_la-lexmark.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lexmark.c' object='liblexmark_la-lexmark.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblexmark_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblexmark_la-lexmark.lo `test -f 'lexmark.c' || echo '$(srcdir)/'`lexmark.c - -liblexmark_la-lexmark_low.lo: lexmark_low.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblexmark_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT liblexmark_la-lexmark_low.lo -MD -MP -MF $(DEPDIR)/liblexmark_la-lexmark_low.Tpo -c -o liblexmark_la-lexmark_low.lo `test -f 'lexmark_low.c' || echo '$(srcdir)/'`lexmark_low.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/liblexmark_la-lexmark_low.Tpo $(DEPDIR)/liblexmark_la-lexmark_low.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lexmark_low.c' object='liblexmark_la-lexmark_low.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(liblexmark_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o liblexmark_la-lexmark_low.lo `test -f 'lexmark_low.c' || echo '$(srcdir)/'`lexmark_low.c - -libma1509_la-ma1509.lo: ma1509.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libma1509_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libma1509_la-ma1509.lo -MD -MP -MF $(DEPDIR)/libma1509_la-ma1509.Tpo -c -o libma1509_la-ma1509.lo `test -f 'ma1509.c' || echo '$(srcdir)/'`ma1509.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libma1509_la-ma1509.Tpo $(DEPDIR)/libma1509_la-ma1509.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ma1509.c' object='libma1509_la-ma1509.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libma1509_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libma1509_la-ma1509.lo `test -f 'ma1509.c' || echo '$(srcdir)/'`ma1509.c - -libmagicolor_la-magicolor.lo: magicolor.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmagicolor_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmagicolor_la-magicolor.lo -MD -MP -MF $(DEPDIR)/libmagicolor_la-magicolor.Tpo -c -o libmagicolor_la-magicolor.lo `test -f 'magicolor.c' || echo '$(srcdir)/'`magicolor.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmagicolor_la-magicolor.Tpo $(DEPDIR)/libmagicolor_la-magicolor.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='magicolor.c' object='libmagicolor_la-magicolor.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmagicolor_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmagicolor_la-magicolor.lo `test -f 'magicolor.c' || echo '$(srcdir)/'`magicolor.c - -libmatsushita_la-matsushita.lo: matsushita.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmatsushita_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmatsushita_la-matsushita.lo -MD -MP -MF $(DEPDIR)/libmatsushita_la-matsushita.Tpo -c -o libmatsushita_la-matsushita.lo `test -f 'matsushita.c' || echo '$(srcdir)/'`matsushita.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmatsushita_la-matsushita.Tpo $(DEPDIR)/libmatsushita_la-matsushita.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='matsushita.c' object='libmatsushita_la-matsushita.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmatsushita_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmatsushita_la-matsushita.lo `test -f 'matsushita.c' || echo '$(srcdir)/'`matsushita.c - -libmicrotek_la-microtek.lo: microtek.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmicrotek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmicrotek_la-microtek.lo -MD -MP -MF $(DEPDIR)/libmicrotek_la-microtek.Tpo -c -o libmicrotek_la-microtek.lo `test -f 'microtek.c' || echo '$(srcdir)/'`microtek.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmicrotek_la-microtek.Tpo $(DEPDIR)/libmicrotek_la-microtek.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='microtek.c' object='libmicrotek_la-microtek.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmicrotek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmicrotek_la-microtek.lo `test -f 'microtek.c' || echo '$(srcdir)/'`microtek.c - -libmicrotek2_la-microtek2.lo: microtek2.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmicrotek2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmicrotek2_la-microtek2.lo -MD -MP -MF $(DEPDIR)/libmicrotek2_la-microtek2.Tpo -c -o libmicrotek2_la-microtek2.lo `test -f 'microtek2.c' || echo '$(srcdir)/'`microtek2.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmicrotek2_la-microtek2.Tpo $(DEPDIR)/libmicrotek2_la-microtek2.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='microtek2.c' object='libmicrotek2_la-microtek2.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmicrotek2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmicrotek2_la-microtek2.lo `test -f 'microtek2.c' || echo '$(srcdir)/'`microtek2.c - -libmustek_la-mustek.lo: mustek.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmustek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmustek_la-mustek.lo -MD -MP -MF $(DEPDIR)/libmustek_la-mustek.Tpo -c -o libmustek_la-mustek.lo `test -f 'mustek.c' || echo '$(srcdir)/'`mustek.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmustek_la-mustek.Tpo $(DEPDIR)/libmustek_la-mustek.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mustek.c' object='libmustek_la-mustek.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmustek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmustek_la-mustek.lo `test -f 'mustek.c' || echo '$(srcdir)/'`mustek.c - -libmustek_pp_la-mustek_pp.lo: mustek_pp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmustek_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmustek_pp_la-mustek_pp.lo -MD -MP -MF $(DEPDIR)/libmustek_pp_la-mustek_pp.Tpo -c -o libmustek_pp_la-mustek_pp.lo `test -f 'mustek_pp.c' || echo '$(srcdir)/'`mustek_pp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmustek_pp_la-mustek_pp.Tpo $(DEPDIR)/libmustek_pp_la-mustek_pp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mustek_pp.c' object='libmustek_pp_la-mustek_pp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmustek_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmustek_pp_la-mustek_pp.lo `test -f 'mustek_pp.c' || echo '$(srcdir)/'`mustek_pp.c - -libmustek_usb_la-mustek_usb.lo: mustek_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmustek_usb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmustek_usb_la-mustek_usb.lo -MD -MP -MF $(DEPDIR)/libmustek_usb_la-mustek_usb.Tpo -c -o libmustek_usb_la-mustek_usb.lo `test -f 'mustek_usb.c' || echo '$(srcdir)/'`mustek_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmustek_usb_la-mustek_usb.Tpo $(DEPDIR)/libmustek_usb_la-mustek_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mustek_usb.c' object='libmustek_usb_la-mustek_usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmustek_usb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmustek_usb_la-mustek_usb.lo `test -f 'mustek_usb.c' || echo '$(srcdir)/'`mustek_usb.c - -libmustek_usb2_la-mustek_usb2.lo: mustek_usb2.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmustek_usb2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libmustek_usb2_la-mustek_usb2.lo -MD -MP -MF $(DEPDIR)/libmustek_usb2_la-mustek_usb2.Tpo -c -o libmustek_usb2_la-mustek_usb2.lo `test -f 'mustek_usb2.c' || echo '$(srcdir)/'`mustek_usb2.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libmustek_usb2_la-mustek_usb2.Tpo $(DEPDIR)/libmustek_usb2_la-mustek_usb2.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mustek_usb2.c' object='libmustek_usb2_la-mustek_usb2.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libmustek_usb2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libmustek_usb2_la-mustek_usb2.lo `test -f 'mustek_usb2.c' || echo '$(srcdir)/'`mustek_usb2.c - -libnec_la-nec.lo: nec.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnec_la-nec.lo -MD -MP -MF $(DEPDIR)/libnec_la-nec.Tpo -c -o libnec_la-nec.lo `test -f 'nec.c' || echo '$(srcdir)/'`nec.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnec_la-nec.Tpo $(DEPDIR)/libnec_la-nec.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nec.c' object='libnec_la-nec.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnec_la-nec.lo `test -f 'nec.c' || echo '$(srcdir)/'`nec.c - -libnet_la-net.lo: net.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnet_la-net.lo -MD -MP -MF $(DEPDIR)/libnet_la-net.Tpo -c -o libnet_la-net.lo `test -f 'net.c' || echo '$(srcdir)/'`net.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnet_la-net.Tpo $(DEPDIR)/libnet_la-net.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='net.c' object='libnet_la-net.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnet_la-net.lo `test -f 'net.c' || echo '$(srcdir)/'`net.c - -libniash_la-niash.lo: niash.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libniash_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libniash_la-niash.lo -MD -MP -MF $(DEPDIR)/libniash_la-niash.Tpo -c -o libniash_la-niash.lo `test -f 'niash.c' || echo '$(srcdir)/'`niash.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libniash_la-niash.Tpo $(DEPDIR)/libniash_la-niash.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='niash.c' object='libniash_la-niash.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libniash_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libniash_la-niash.lo `test -f 'niash.c' || echo '$(srcdir)/'`niash.c - -libp5_la-p5.lo: p5.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libp5_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libp5_la-p5.lo -MD -MP -MF $(DEPDIR)/libp5_la-p5.Tpo -c -o libp5_la-p5.lo `test -f 'p5.c' || echo '$(srcdir)/'`p5.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libp5_la-p5.Tpo $(DEPDIR)/libp5_la-p5.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='p5.c' object='libp5_la-p5.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libp5_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libp5_la-p5.lo `test -f 'p5.c' || echo '$(srcdir)/'`p5.c - -libpie_la-pie.lo: pie.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpie_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpie_la-pie.lo -MD -MP -MF $(DEPDIR)/libpie_la-pie.Tpo -c -o libpie_la-pie.lo `test -f 'pie.c' || echo '$(srcdir)/'`pie.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpie_la-pie.Tpo $(DEPDIR)/libpie_la-pie.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pie.c' object='libpie_la-pie.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpie_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpie_la-pie.lo `test -f 'pie.c' || echo '$(srcdir)/'`pie.c - -libpieusb_la-pieusb_buffer.lo: pieusb_buffer.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpieusb_la-pieusb_buffer.lo -MD -MP -MF $(DEPDIR)/libpieusb_la-pieusb_buffer.Tpo -c -o libpieusb_la-pieusb_buffer.lo `test -f 'pieusb_buffer.c' || echo '$(srcdir)/'`pieusb_buffer.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpieusb_la-pieusb_buffer.Tpo $(DEPDIR)/libpieusb_la-pieusb_buffer.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pieusb_buffer.c' object='libpieusb_la-pieusb_buffer.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpieusb_la-pieusb_buffer.lo `test -f 'pieusb_buffer.c' || echo '$(srcdir)/'`pieusb_buffer.c - -libpieusb_la-pieusb_scancmd.lo: pieusb_scancmd.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpieusb_la-pieusb_scancmd.lo -MD -MP -MF $(DEPDIR)/libpieusb_la-pieusb_scancmd.Tpo -c -o libpieusb_la-pieusb_scancmd.lo `test -f 'pieusb_scancmd.c' || echo '$(srcdir)/'`pieusb_scancmd.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpieusb_la-pieusb_scancmd.Tpo $(DEPDIR)/libpieusb_la-pieusb_scancmd.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pieusb_scancmd.c' object='libpieusb_la-pieusb_scancmd.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpieusb_la-pieusb_scancmd.lo `test -f 'pieusb_scancmd.c' || echo '$(srcdir)/'`pieusb_scancmd.c - -libpieusb_la-pieusb_specific.lo: pieusb_specific.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpieusb_la-pieusb_specific.lo -MD -MP -MF $(DEPDIR)/libpieusb_la-pieusb_specific.Tpo -c -o libpieusb_la-pieusb_specific.lo `test -f 'pieusb_specific.c' || echo '$(srcdir)/'`pieusb_specific.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpieusb_la-pieusb_specific.Tpo $(DEPDIR)/libpieusb_la-pieusb_specific.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pieusb_specific.c' object='libpieusb_la-pieusb_specific.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpieusb_la-pieusb_specific.lo `test -f 'pieusb_specific.c' || echo '$(srcdir)/'`pieusb_specific.c - -libpieusb_la-pieusb_usb.lo: pieusb_usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpieusb_la-pieusb_usb.lo -MD -MP -MF $(DEPDIR)/libpieusb_la-pieusb_usb.Tpo -c -o libpieusb_la-pieusb_usb.lo `test -f 'pieusb_usb.c' || echo '$(srcdir)/'`pieusb_usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpieusb_la-pieusb_usb.Tpo $(DEPDIR)/libpieusb_la-pieusb_usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pieusb_usb.c' object='libpieusb_la-pieusb_usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpieusb_la-pieusb_usb.lo `test -f 'pieusb_usb.c' || echo '$(srcdir)/'`pieusb_usb.c - -libpieusb_la-pieusb.lo: pieusb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpieusb_la-pieusb.lo -MD -MP -MF $(DEPDIR)/libpieusb_la-pieusb.Tpo -c -o libpieusb_la-pieusb.lo `test -f 'pieusb.c' || echo '$(srcdir)/'`pieusb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpieusb_la-pieusb.Tpo $(DEPDIR)/libpieusb_la-pieusb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pieusb.c' object='libpieusb_la-pieusb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpieusb_la-pieusb.lo `test -f 'pieusb.c' || echo '$(srcdir)/'`pieusb.c - -libpint_la-pint.lo: pint.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpint_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpint_la-pint.lo -MD -MP -MF $(DEPDIR)/libpint_la-pint.Tpo -c -o libpint_la-pint.lo `test -f 'pint.c' || echo '$(srcdir)/'`pint.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpint_la-pint.Tpo $(DEPDIR)/libpint_la-pint.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pint.c' object='libpint_la-pint.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpint_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpint_la-pint.lo `test -f 'pint.c' || echo '$(srcdir)/'`pint.c - -libpixma_la-pixma.lo: pixma.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma.Tpo -c -o libpixma_la-pixma.lo `test -f 'pixma.c' || echo '$(srcdir)/'`pixma.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma.Tpo $(DEPDIR)/libpixma_la-pixma.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma.c' object='libpixma_la-pixma.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma.lo `test -f 'pixma.c' || echo '$(srcdir)/'`pixma.c - -libpixma_la-pixma_io_sanei.lo: pixma_io_sanei.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma_io_sanei.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma_io_sanei.Tpo -c -o libpixma_la-pixma_io_sanei.lo `test -f 'pixma_io_sanei.c' || echo '$(srcdir)/'`pixma_io_sanei.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma_io_sanei.Tpo $(DEPDIR)/libpixma_la-pixma_io_sanei.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma_io_sanei.c' object='libpixma_la-pixma_io_sanei.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma_io_sanei.lo `test -f 'pixma_io_sanei.c' || echo '$(srcdir)/'`pixma_io_sanei.c - -libpixma_la-pixma_common.lo: pixma_common.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma_common.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma_common.Tpo -c -o libpixma_la-pixma_common.lo `test -f 'pixma_common.c' || echo '$(srcdir)/'`pixma_common.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma_common.Tpo $(DEPDIR)/libpixma_la-pixma_common.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma_common.c' object='libpixma_la-pixma_common.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma_common.lo `test -f 'pixma_common.c' || echo '$(srcdir)/'`pixma_common.c - -libpixma_la-pixma_mp150.lo: pixma_mp150.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma_mp150.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma_mp150.Tpo -c -o libpixma_la-pixma_mp150.lo `test -f 'pixma_mp150.c' || echo '$(srcdir)/'`pixma_mp150.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma_mp150.Tpo $(DEPDIR)/libpixma_la-pixma_mp150.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma_mp150.c' object='libpixma_la-pixma_mp150.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma_mp150.lo `test -f 'pixma_mp150.c' || echo '$(srcdir)/'`pixma_mp150.c - -libpixma_la-pixma_mp730.lo: pixma_mp730.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma_mp730.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma_mp730.Tpo -c -o libpixma_la-pixma_mp730.lo `test -f 'pixma_mp730.c' || echo '$(srcdir)/'`pixma_mp730.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma_mp730.Tpo $(DEPDIR)/libpixma_la-pixma_mp730.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma_mp730.c' object='libpixma_la-pixma_mp730.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma_mp730.lo `test -f 'pixma_mp730.c' || echo '$(srcdir)/'`pixma_mp730.c - -libpixma_la-pixma_mp750.lo: pixma_mp750.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma_mp750.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma_mp750.Tpo -c -o libpixma_la-pixma_mp750.lo `test -f 'pixma_mp750.c' || echo '$(srcdir)/'`pixma_mp750.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma_mp750.Tpo $(DEPDIR)/libpixma_la-pixma_mp750.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma_mp750.c' object='libpixma_la-pixma_mp750.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma_mp750.lo `test -f 'pixma_mp750.c' || echo '$(srcdir)/'`pixma_mp750.c - -libpixma_la-pixma_mp810.lo: pixma_mp810.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma_mp810.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma_mp810.Tpo -c -o libpixma_la-pixma_mp810.lo `test -f 'pixma_mp810.c' || echo '$(srcdir)/'`pixma_mp810.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma_mp810.Tpo $(DEPDIR)/libpixma_la-pixma_mp810.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma_mp810.c' object='libpixma_la-pixma_mp810.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma_mp810.lo `test -f 'pixma_mp810.c' || echo '$(srcdir)/'`pixma_mp810.c - -libpixma_la-pixma_imageclass.lo: pixma_imageclass.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma_imageclass.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma_imageclass.Tpo -c -o libpixma_la-pixma_imageclass.lo `test -f 'pixma_imageclass.c' || echo '$(srcdir)/'`pixma_imageclass.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma_imageclass.Tpo $(DEPDIR)/libpixma_la-pixma_imageclass.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma_imageclass.c' object='libpixma_la-pixma_imageclass.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma_imageclass.lo `test -f 'pixma_imageclass.c' || echo '$(srcdir)/'`pixma_imageclass.c - -libpixma_la-pixma_bjnp.lo: pixma_bjnp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpixma_la-pixma_bjnp.lo -MD -MP -MF $(DEPDIR)/libpixma_la-pixma_bjnp.Tpo -c -o libpixma_la-pixma_bjnp.lo `test -f 'pixma_bjnp.c' || echo '$(srcdir)/'`pixma_bjnp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpixma_la-pixma_bjnp.Tpo $(DEPDIR)/libpixma_la-pixma_bjnp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma_bjnp.c' object='libpixma_la-pixma_bjnp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpixma_la-pixma_bjnp.lo `test -f 'pixma_bjnp.c' || echo '$(srcdir)/'`pixma_bjnp.c - -libplustek_la-plustek.lo: plustek.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libplustek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libplustek_la-plustek.lo -MD -MP -MF $(DEPDIR)/libplustek_la-plustek.Tpo -c -o libplustek_la-plustek.lo `test -f 'plustek.c' || echo '$(srcdir)/'`plustek.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libplustek_la-plustek.Tpo $(DEPDIR)/libplustek_la-plustek.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plustek.c' object='libplustek_la-plustek.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libplustek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libplustek_la-plustek.lo `test -f 'plustek.c' || echo '$(srcdir)/'`plustek.c - -libplustek_pp_la-plustek_pp.lo: plustek_pp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libplustek_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libplustek_pp_la-plustek_pp.lo -MD -MP -MF $(DEPDIR)/libplustek_pp_la-plustek_pp.Tpo -c -o libplustek_pp_la-plustek_pp.lo `test -f 'plustek_pp.c' || echo '$(srcdir)/'`plustek_pp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libplustek_pp_la-plustek_pp.Tpo $(DEPDIR)/libplustek_pp_la-plustek_pp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plustek_pp.c' object='libplustek_pp_la-plustek_pp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libplustek_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libplustek_pp_la-plustek_pp.lo `test -f 'plustek_pp.c' || echo '$(srcdir)/'`plustek_pp.c - -libpnm_la-pnm.lo: pnm.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpnm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libpnm_la-pnm.lo -MD -MP -MF $(DEPDIR)/libpnm_la-pnm.Tpo -c -o libpnm_la-pnm.lo `test -f 'pnm.c' || echo '$(srcdir)/'`pnm.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpnm_la-pnm.Tpo $(DEPDIR)/libpnm_la-pnm.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pnm.c' object='libpnm_la-pnm.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpnm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libpnm_la-pnm.lo `test -f 'pnm.c' || echo '$(srcdir)/'`pnm.c - -libqcam_la-qcam.lo: qcam.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqcam_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libqcam_la-qcam.lo -MD -MP -MF $(DEPDIR)/libqcam_la-qcam.Tpo -c -o libqcam_la-qcam.lo `test -f 'qcam.c' || echo '$(srcdir)/'`qcam.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libqcam_la-qcam.Tpo $(DEPDIR)/libqcam_la-qcam.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='qcam.c' object='libqcam_la-qcam.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libqcam_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libqcam_la-qcam.lo `test -f 'qcam.c' || echo '$(srcdir)/'`qcam.c - -libricoh_la-ricoh.lo: ricoh.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libricoh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libricoh_la-ricoh.lo -MD -MP -MF $(DEPDIR)/libricoh_la-ricoh.Tpo -c -o libricoh_la-ricoh.lo `test -f 'ricoh.c' || echo '$(srcdir)/'`ricoh.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libricoh_la-ricoh.Tpo $(DEPDIR)/libricoh_la-ricoh.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ricoh.c' object='libricoh_la-ricoh.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libricoh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libricoh_la-ricoh.lo `test -f 'ricoh.c' || echo '$(srcdir)/'`ricoh.c - -librts8891_la-rts8891.lo: rts8891.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(librts8891_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT librts8891_la-rts8891.lo -MD -MP -MF $(DEPDIR)/librts8891_la-rts8891.Tpo -c -o librts8891_la-rts8891.lo `test -f 'rts8891.c' || echo '$(srcdir)/'`rts8891.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librts8891_la-rts8891.Tpo $(DEPDIR)/librts8891_la-rts8891.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rts8891.c' object='librts8891_la-rts8891.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(librts8891_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o librts8891_la-rts8891.lo `test -f 'rts8891.c' || echo '$(srcdir)/'`rts8891.c - -librts8891_la-rts88xx_lib.lo: rts88xx_lib.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(librts8891_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT librts8891_la-rts88xx_lib.lo -MD -MP -MF $(DEPDIR)/librts8891_la-rts88xx_lib.Tpo -c -o librts8891_la-rts88xx_lib.lo `test -f 'rts88xx_lib.c' || echo '$(srcdir)/'`rts88xx_lib.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/librts8891_la-rts88xx_lib.Tpo $(DEPDIR)/librts8891_la-rts88xx_lib.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rts88xx_lib.c' object='librts8891_la-rts88xx_lib.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(librts8891_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o librts8891_la-rts88xx_lib.lo `test -f 'rts88xx_lib.c' || echo '$(srcdir)/'`rts88xx_lib.c - -libs9036_la-s9036.lo: s9036.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libs9036_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libs9036_la-s9036.lo -MD -MP -MF $(DEPDIR)/libs9036_la-s9036.Tpo -c -o libs9036_la-s9036.lo `test -f 's9036.c' || echo '$(srcdir)/'`s9036.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libs9036_la-s9036.Tpo $(DEPDIR)/libs9036_la-s9036.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='s9036.c' object='libs9036_la-s9036.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libs9036_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libs9036_la-s9036.lo `test -f 's9036.c' || echo '$(srcdir)/'`s9036.c - -libsane_abaton_la-abaton-s.lo: abaton-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_abaton_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_abaton_la-abaton-s.lo -MD -MP -MF $(DEPDIR)/libsane_abaton_la-abaton-s.Tpo -c -o libsane_abaton_la-abaton-s.lo `test -f 'abaton-s.c' || echo '$(srcdir)/'`abaton-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_abaton_la-abaton-s.Tpo $(DEPDIR)/libsane_abaton_la-abaton-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='abaton-s.c' object='libsane_abaton_la-abaton-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_abaton_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_abaton_la-abaton-s.lo `test -f 'abaton-s.c' || echo '$(srcdir)/'`abaton-s.c - -libsane_agfafocus_la-agfafocus-s.lo: agfafocus-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_agfafocus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_agfafocus_la-agfafocus-s.lo -MD -MP -MF $(DEPDIR)/libsane_agfafocus_la-agfafocus-s.Tpo -c -o libsane_agfafocus_la-agfafocus-s.lo `test -f 'agfafocus-s.c' || echo '$(srcdir)/'`agfafocus-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_agfafocus_la-agfafocus-s.Tpo $(DEPDIR)/libsane_agfafocus_la-agfafocus-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='agfafocus-s.c' object='libsane_agfafocus_la-agfafocus-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_agfafocus_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_agfafocus_la-agfafocus-s.lo `test -f 'agfafocus-s.c' || echo '$(srcdir)/'`agfafocus-s.c - -libsane_apple_la-apple-s.lo: apple-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_apple_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_apple_la-apple-s.lo -MD -MP -MF $(DEPDIR)/libsane_apple_la-apple-s.Tpo -c -o libsane_apple_la-apple-s.lo `test -f 'apple-s.c' || echo '$(srcdir)/'`apple-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_apple_la-apple-s.Tpo $(DEPDIR)/libsane_apple_la-apple-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='apple-s.c' object='libsane_apple_la-apple-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_apple_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_apple_la-apple-s.lo `test -f 'apple-s.c' || echo '$(srcdir)/'`apple-s.c - -libsane_artec_la-artec-s.lo: artec-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_artec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_artec_la-artec-s.lo -MD -MP -MF $(DEPDIR)/libsane_artec_la-artec-s.Tpo -c -o libsane_artec_la-artec-s.lo `test -f 'artec-s.c' || echo '$(srcdir)/'`artec-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_artec_la-artec-s.Tpo $(DEPDIR)/libsane_artec_la-artec-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='artec-s.c' object='libsane_artec_la-artec-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_artec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_artec_la-artec-s.lo `test -f 'artec-s.c' || echo '$(srcdir)/'`artec-s.c - -libsane_artec_eplus48u_la-artec_eplus48u-s.lo: artec_eplus48u-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_artec_eplus48u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_artec_eplus48u_la-artec_eplus48u-s.lo -MD -MP -MF $(DEPDIR)/libsane_artec_eplus48u_la-artec_eplus48u-s.Tpo -c -o libsane_artec_eplus48u_la-artec_eplus48u-s.lo `test -f 'artec_eplus48u-s.c' || echo '$(srcdir)/'`artec_eplus48u-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_artec_eplus48u_la-artec_eplus48u-s.Tpo $(DEPDIR)/libsane_artec_eplus48u_la-artec_eplus48u-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='artec_eplus48u-s.c' object='libsane_artec_eplus48u_la-artec_eplus48u-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_artec_eplus48u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_artec_eplus48u_la-artec_eplus48u-s.lo `test -f 'artec_eplus48u-s.c' || echo '$(srcdir)/'`artec_eplus48u-s.c - -libsane_as6e_la-as6e-s.lo: as6e-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_as6e_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_as6e_la-as6e-s.lo -MD -MP -MF $(DEPDIR)/libsane_as6e_la-as6e-s.Tpo -c -o libsane_as6e_la-as6e-s.lo `test -f 'as6e-s.c' || echo '$(srcdir)/'`as6e-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_as6e_la-as6e-s.Tpo $(DEPDIR)/libsane_as6e_la-as6e-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='as6e-s.c' object='libsane_as6e_la-as6e-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_as6e_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_as6e_la-as6e-s.lo `test -f 'as6e-s.c' || echo '$(srcdir)/'`as6e-s.c - -libsane_avision_la-avision-s.lo: avision-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_avision_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_avision_la-avision-s.lo -MD -MP -MF $(DEPDIR)/libsane_avision_la-avision-s.Tpo -c -o libsane_avision_la-avision-s.lo `test -f 'avision-s.c' || echo '$(srcdir)/'`avision-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_avision_la-avision-s.Tpo $(DEPDIR)/libsane_avision_la-avision-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='avision-s.c' object='libsane_avision_la-avision-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_avision_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_avision_la-avision-s.lo `test -f 'avision-s.c' || echo '$(srcdir)/'`avision-s.c - -libsane_bh_la-bh-s.lo: bh-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_bh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_bh_la-bh-s.lo -MD -MP -MF $(DEPDIR)/libsane_bh_la-bh-s.Tpo -c -o libsane_bh_la-bh-s.lo `test -f 'bh-s.c' || echo '$(srcdir)/'`bh-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_bh_la-bh-s.Tpo $(DEPDIR)/libsane_bh_la-bh-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='bh-s.c' object='libsane_bh_la-bh-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_bh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_bh_la-bh-s.lo `test -f 'bh-s.c' || echo '$(srcdir)/'`bh-s.c - -libsane_canon_la-canon-s.lo: canon-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_canon_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_canon_la-canon-s.lo -MD -MP -MF $(DEPDIR)/libsane_canon_la-canon-s.Tpo -c -o libsane_canon_la-canon-s.lo `test -f 'canon-s.c' || echo '$(srcdir)/'`canon-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_canon_la-canon-s.Tpo $(DEPDIR)/libsane_canon_la-canon-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon-s.c' object='libsane_canon_la-canon-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_canon_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_canon_la-canon-s.lo `test -f 'canon-s.c' || echo '$(srcdir)/'`canon-s.c - -libsane_canon630u_la-canon630u-s.lo: canon630u-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_canon630u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_canon630u_la-canon630u-s.lo -MD -MP -MF $(DEPDIR)/libsane_canon630u_la-canon630u-s.Tpo -c -o libsane_canon630u_la-canon630u-s.lo `test -f 'canon630u-s.c' || echo '$(srcdir)/'`canon630u-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_canon630u_la-canon630u-s.Tpo $(DEPDIR)/libsane_canon630u_la-canon630u-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon630u-s.c' object='libsane_canon630u_la-canon630u-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_canon630u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_canon630u_la-canon630u-s.lo `test -f 'canon630u-s.c' || echo '$(srcdir)/'`canon630u-s.c - -libsane_canon_dr_la-canon_dr-s.lo: canon_dr-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_canon_dr_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_canon_dr_la-canon_dr-s.lo -MD -MP -MF $(DEPDIR)/libsane_canon_dr_la-canon_dr-s.Tpo -c -o libsane_canon_dr_la-canon_dr-s.lo `test -f 'canon_dr-s.c' || echo '$(srcdir)/'`canon_dr-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_canon_dr_la-canon_dr-s.Tpo $(DEPDIR)/libsane_canon_dr_la-canon_dr-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon_dr-s.c' object='libsane_canon_dr_la-canon_dr-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_canon_dr_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_canon_dr_la-canon_dr-s.lo `test -f 'canon_dr-s.c' || echo '$(srcdir)/'`canon_dr-s.c - -libsane_canon_pp_la-canon_pp-s.lo: canon_pp-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_canon_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_canon_pp_la-canon_pp-s.lo -MD -MP -MF $(DEPDIR)/libsane_canon_pp_la-canon_pp-s.Tpo -c -o libsane_canon_pp_la-canon_pp-s.lo `test -f 'canon_pp-s.c' || echo '$(srcdir)/'`canon_pp-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_canon_pp_la-canon_pp-s.Tpo $(DEPDIR)/libsane_canon_pp_la-canon_pp-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='canon_pp-s.c' object='libsane_canon_pp_la-canon_pp-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_canon_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_canon_pp_la-canon_pp-s.lo `test -f 'canon_pp-s.c' || echo '$(srcdir)/'`canon_pp-s.c - -libsane_cardscan_la-cardscan-s.lo: cardscan-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_cardscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_cardscan_la-cardscan-s.lo -MD -MP -MF $(DEPDIR)/libsane_cardscan_la-cardscan-s.Tpo -c -o libsane_cardscan_la-cardscan-s.lo `test -f 'cardscan-s.c' || echo '$(srcdir)/'`cardscan-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_cardscan_la-cardscan-s.Tpo $(DEPDIR)/libsane_cardscan_la-cardscan-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cardscan-s.c' object='libsane_cardscan_la-cardscan-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_cardscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_cardscan_la-cardscan-s.lo `test -f 'cardscan-s.c' || echo '$(srcdir)/'`cardscan-s.c - -libsane_coolscan_la-coolscan-s.lo: coolscan-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_coolscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_coolscan_la-coolscan-s.lo -MD -MP -MF $(DEPDIR)/libsane_coolscan_la-coolscan-s.Tpo -c -o libsane_coolscan_la-coolscan-s.lo `test -f 'coolscan-s.c' || echo '$(srcdir)/'`coolscan-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_coolscan_la-coolscan-s.Tpo $(DEPDIR)/libsane_coolscan_la-coolscan-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='coolscan-s.c' object='libsane_coolscan_la-coolscan-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_coolscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_coolscan_la-coolscan-s.lo `test -f 'coolscan-s.c' || echo '$(srcdir)/'`coolscan-s.c - -libsane_coolscan2_la-coolscan2-s.lo: coolscan2-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_coolscan2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_coolscan2_la-coolscan2-s.lo -MD -MP -MF $(DEPDIR)/libsane_coolscan2_la-coolscan2-s.Tpo -c -o libsane_coolscan2_la-coolscan2-s.lo `test -f 'coolscan2-s.c' || echo '$(srcdir)/'`coolscan2-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_coolscan2_la-coolscan2-s.Tpo $(DEPDIR)/libsane_coolscan2_la-coolscan2-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='coolscan2-s.c' object='libsane_coolscan2_la-coolscan2-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_coolscan2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_coolscan2_la-coolscan2-s.lo `test -f 'coolscan2-s.c' || echo '$(srcdir)/'`coolscan2-s.c - -libsane_coolscan3_la-coolscan3-s.lo: coolscan3-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_coolscan3_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_coolscan3_la-coolscan3-s.lo -MD -MP -MF $(DEPDIR)/libsane_coolscan3_la-coolscan3-s.Tpo -c -o libsane_coolscan3_la-coolscan3-s.lo `test -f 'coolscan3-s.c' || echo '$(srcdir)/'`coolscan3-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_coolscan3_la-coolscan3-s.Tpo $(DEPDIR)/libsane_coolscan3_la-coolscan3-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='coolscan3-s.c' object='libsane_coolscan3_la-coolscan3-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_coolscan3_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_coolscan3_la-coolscan3-s.lo `test -f 'coolscan3-s.c' || echo '$(srcdir)/'`coolscan3-s.c - -libsane_dc210_la-dc210-s.lo: dc210-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dc210_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_dc210_la-dc210-s.lo -MD -MP -MF $(DEPDIR)/libsane_dc210_la-dc210-s.Tpo -c -o libsane_dc210_la-dc210-s.lo `test -f 'dc210-s.c' || echo '$(srcdir)/'`dc210-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_dc210_la-dc210-s.Tpo $(DEPDIR)/libsane_dc210_la-dc210-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dc210-s.c' object='libsane_dc210_la-dc210-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dc210_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_dc210_la-dc210-s.lo `test -f 'dc210-s.c' || echo '$(srcdir)/'`dc210-s.c - -libsane_dc240_la-dc240-s.lo: dc240-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dc240_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_dc240_la-dc240-s.lo -MD -MP -MF $(DEPDIR)/libsane_dc240_la-dc240-s.Tpo -c -o libsane_dc240_la-dc240-s.lo `test -f 'dc240-s.c' || echo '$(srcdir)/'`dc240-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_dc240_la-dc240-s.Tpo $(DEPDIR)/libsane_dc240_la-dc240-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dc240-s.c' object='libsane_dc240_la-dc240-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dc240_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_dc240_la-dc240-s.lo `test -f 'dc240-s.c' || echo '$(srcdir)/'`dc240-s.c - -libsane_dc25_la-dc25-s.lo: dc25-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dc25_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_dc25_la-dc25-s.lo -MD -MP -MF $(DEPDIR)/libsane_dc25_la-dc25-s.Tpo -c -o libsane_dc25_la-dc25-s.lo `test -f 'dc25-s.c' || echo '$(srcdir)/'`dc25-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_dc25_la-dc25-s.Tpo $(DEPDIR)/libsane_dc25_la-dc25-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dc25-s.c' object='libsane_dc25_la-dc25-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dc25_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_dc25_la-dc25-s.lo `test -f 'dc25-s.c' || echo '$(srcdir)/'`dc25-s.c - -libsane_dell1600n_net_la-dell1600n_net-s.lo: dell1600n_net-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dell1600n_net_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_dell1600n_net_la-dell1600n_net-s.lo -MD -MP -MF $(DEPDIR)/libsane_dell1600n_net_la-dell1600n_net-s.Tpo -c -o libsane_dell1600n_net_la-dell1600n_net-s.lo `test -f 'dell1600n_net-s.c' || echo '$(srcdir)/'`dell1600n_net-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_dell1600n_net_la-dell1600n_net-s.Tpo $(DEPDIR)/libsane_dell1600n_net_la-dell1600n_net-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dell1600n_net-s.c' object='libsane_dell1600n_net_la-dell1600n_net-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dell1600n_net_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_dell1600n_net_la-dell1600n_net-s.lo `test -f 'dell1600n_net-s.c' || echo '$(srcdir)/'`dell1600n_net-s.c - -libsane_dll_la-dll-s.lo: dll-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dll_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_dll_la-dll-s.lo -MD -MP -MF $(DEPDIR)/libsane_dll_la-dll-s.Tpo -c -o libsane_dll_la-dll-s.lo `test -f 'dll-s.c' || echo '$(srcdir)/'`dll-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_dll_la-dll-s.Tpo $(DEPDIR)/libsane_dll_la-dll-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dll-s.c' object='libsane_dll_la-dll-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dll_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_dll_la-dll-s.lo `test -f 'dll-s.c' || echo '$(srcdir)/'`dll-s.c - -libsane_dmc_la-dmc-s.lo: dmc-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dmc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_dmc_la-dmc-s.lo -MD -MP -MF $(DEPDIR)/libsane_dmc_la-dmc-s.Tpo -c -o libsane_dmc_la-dmc-s.lo `test -f 'dmc-s.c' || echo '$(srcdir)/'`dmc-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_dmc_la-dmc-s.Tpo $(DEPDIR)/libsane_dmc_la-dmc-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dmc-s.c' object='libsane_dmc_la-dmc-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_dmc_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_dmc_la-dmc-s.lo `test -f 'dmc-s.c' || echo '$(srcdir)/'`dmc-s.c - -libsane_epjitsu_la-epjitsu-s.lo: epjitsu-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_epjitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_epjitsu_la-epjitsu-s.lo -MD -MP -MF $(DEPDIR)/libsane_epjitsu_la-epjitsu-s.Tpo -c -o libsane_epjitsu_la-epjitsu-s.lo `test -f 'epjitsu-s.c' || echo '$(srcdir)/'`epjitsu-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_epjitsu_la-epjitsu-s.Tpo $(DEPDIR)/libsane_epjitsu_la-epjitsu-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epjitsu-s.c' object='libsane_epjitsu_la-epjitsu-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_epjitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_epjitsu_la-epjitsu-s.lo `test -f 'epjitsu-s.c' || echo '$(srcdir)/'`epjitsu-s.c - -libsane_epson_la-epson-s.lo: epson-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_epson_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_epson_la-epson-s.lo -MD -MP -MF $(DEPDIR)/libsane_epson_la-epson-s.Tpo -c -o libsane_epson_la-epson-s.lo `test -f 'epson-s.c' || echo '$(srcdir)/'`epson-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_epson_la-epson-s.Tpo $(DEPDIR)/libsane_epson_la-epson-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson-s.c' object='libsane_epson_la-epson-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_epson_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_epson_la-epson-s.lo `test -f 'epson-s.c' || echo '$(srcdir)/'`epson-s.c - -libsane_epson2_la-epson2-s.lo: epson2-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_epson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_epson2_la-epson2-s.lo -MD -MP -MF $(DEPDIR)/libsane_epson2_la-epson2-s.Tpo -c -o libsane_epson2_la-epson2-s.lo `test -f 'epson2-s.c' || echo '$(srcdir)/'`epson2-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_epson2_la-epson2-s.Tpo $(DEPDIR)/libsane_epson2_la-epson2-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epson2-s.c' object='libsane_epson2_la-epson2-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_epson2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_epson2_la-epson2-s.lo `test -f 'epson2-s.c' || echo '$(srcdir)/'`epson2-s.c - -libsane_epsonds_la-epsonds-s.lo: epsonds-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_epsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_epsonds_la-epsonds-s.lo -MD -MP -MF $(DEPDIR)/libsane_epsonds_la-epsonds-s.Tpo -c -o libsane_epsonds_la-epsonds-s.lo `test -f 'epsonds-s.c' || echo '$(srcdir)/'`epsonds-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_epsonds_la-epsonds-s.Tpo $(DEPDIR)/libsane_epsonds_la-epsonds-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='epsonds-s.c' object='libsane_epsonds_la-epsonds-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_epsonds_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_epsonds_la-epsonds-s.lo `test -f 'epsonds-s.c' || echo '$(srcdir)/'`epsonds-s.c - -libsane_fujitsu_la-fujitsu-s.lo: fujitsu-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_fujitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_fujitsu_la-fujitsu-s.lo -MD -MP -MF $(DEPDIR)/libsane_fujitsu_la-fujitsu-s.Tpo -c -o libsane_fujitsu_la-fujitsu-s.lo `test -f 'fujitsu-s.c' || echo '$(srcdir)/'`fujitsu-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_fujitsu_la-fujitsu-s.Tpo $(DEPDIR)/libsane_fujitsu_la-fujitsu-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fujitsu-s.c' object='libsane_fujitsu_la-fujitsu-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_fujitsu_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_fujitsu_la-fujitsu-s.lo `test -f 'fujitsu-s.c' || echo '$(srcdir)/'`fujitsu-s.c - -libsane_genesys_la-genesys-s.lo: genesys-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_genesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_genesys_la-genesys-s.lo -MD -MP -MF $(DEPDIR)/libsane_genesys_la-genesys-s.Tpo -c -o libsane_genesys_la-genesys-s.lo `test -f 'genesys-s.c' || echo '$(srcdir)/'`genesys-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_genesys_la-genesys-s.Tpo $(DEPDIR)/libsane_genesys_la-genesys-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='genesys-s.c' object='libsane_genesys_la-genesys-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_genesys_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_genesys_la-genesys-s.lo `test -f 'genesys-s.c' || echo '$(srcdir)/'`genesys-s.c - -libsane_gphoto2_la-gphoto2-s.lo: gphoto2-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_gphoto2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_gphoto2_la-gphoto2-s.lo -MD -MP -MF $(DEPDIR)/libsane_gphoto2_la-gphoto2-s.Tpo -c -o libsane_gphoto2_la-gphoto2-s.lo `test -f 'gphoto2-s.c' || echo '$(srcdir)/'`gphoto2-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_gphoto2_la-gphoto2-s.Tpo $(DEPDIR)/libsane_gphoto2_la-gphoto2-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gphoto2-s.c' object='libsane_gphoto2_la-gphoto2-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_gphoto2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_gphoto2_la-gphoto2-s.lo `test -f 'gphoto2-s.c' || echo '$(srcdir)/'`gphoto2-s.c - -libsane_gt68xx_la-gt68xx-s.lo: gt68xx-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_gt68xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_gt68xx_la-gt68xx-s.lo -MD -MP -MF $(DEPDIR)/libsane_gt68xx_la-gt68xx-s.Tpo -c -o libsane_gt68xx_la-gt68xx-s.lo `test -f 'gt68xx-s.c' || echo '$(srcdir)/'`gt68xx-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_gt68xx_la-gt68xx-s.Tpo $(DEPDIR)/libsane_gt68xx_la-gt68xx-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gt68xx-s.c' object='libsane_gt68xx_la-gt68xx-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_gt68xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_gt68xx_la-gt68xx-s.lo `test -f 'gt68xx-s.c' || echo '$(srcdir)/'`gt68xx-s.c - -libsane_hp_la-hp-s.lo: hp-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hp_la-hp-s.lo -MD -MP -MF $(DEPDIR)/libsane_hp_la-hp-s.Tpo -c -o libsane_hp_la-hp-s.lo `test -f 'hp-s.c' || echo '$(srcdir)/'`hp-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hp_la-hp-s.Tpo $(DEPDIR)/libsane_hp_la-hp-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp-s.c' object='libsane_hp_la-hp-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hp_la-hp-s.lo `test -f 'hp-s.c' || echo '$(srcdir)/'`hp-s.c - -libsane_hp3500_la-hp3500-s.lo: hp3500-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp3500_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hp3500_la-hp3500-s.lo -MD -MP -MF $(DEPDIR)/libsane_hp3500_la-hp3500-s.Tpo -c -o libsane_hp3500_la-hp3500-s.lo `test -f 'hp3500-s.c' || echo '$(srcdir)/'`hp3500-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hp3500_la-hp3500-s.Tpo $(DEPDIR)/libsane_hp3500_la-hp3500-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp3500-s.c' object='libsane_hp3500_la-hp3500-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp3500_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hp3500_la-hp3500-s.lo `test -f 'hp3500-s.c' || echo '$(srcdir)/'`hp3500-s.c - -libsane_hp3900_la-hp3900-s.lo: hp3900-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp3900_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hp3900_la-hp3900-s.lo -MD -MP -MF $(DEPDIR)/libsane_hp3900_la-hp3900-s.Tpo -c -o libsane_hp3900_la-hp3900-s.lo `test -f 'hp3900-s.c' || echo '$(srcdir)/'`hp3900-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hp3900_la-hp3900-s.Tpo $(DEPDIR)/libsane_hp3900_la-hp3900-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp3900-s.c' object='libsane_hp3900_la-hp3900-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp3900_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hp3900_la-hp3900-s.lo `test -f 'hp3900-s.c' || echo '$(srcdir)/'`hp3900-s.c - -libsane_hp4200_la-hp4200-s.lo: hp4200-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp4200_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hp4200_la-hp4200-s.lo -MD -MP -MF $(DEPDIR)/libsane_hp4200_la-hp4200-s.Tpo -c -o libsane_hp4200_la-hp4200-s.lo `test -f 'hp4200-s.c' || echo '$(srcdir)/'`hp4200-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hp4200_la-hp4200-s.Tpo $(DEPDIR)/libsane_hp4200_la-hp4200-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp4200-s.c' object='libsane_hp4200_la-hp4200-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp4200_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hp4200_la-hp4200-s.lo `test -f 'hp4200-s.c' || echo '$(srcdir)/'`hp4200-s.c - -libsane_hp5400_la-hp5400-s.lo: hp5400-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp5400_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hp5400_la-hp5400-s.lo -MD -MP -MF $(DEPDIR)/libsane_hp5400_la-hp5400-s.Tpo -c -o libsane_hp5400_la-hp5400-s.lo `test -f 'hp5400-s.c' || echo '$(srcdir)/'`hp5400-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hp5400_la-hp5400-s.Tpo $(DEPDIR)/libsane_hp5400_la-hp5400-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp5400-s.c' object='libsane_hp5400_la-hp5400-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp5400_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hp5400_la-hp5400-s.lo `test -f 'hp5400-s.c' || echo '$(srcdir)/'`hp5400-s.c - -libsane_hp5590_la-hp5590-s.lo: hp5590-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp5590_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hp5590_la-hp5590-s.lo -MD -MP -MF $(DEPDIR)/libsane_hp5590_la-hp5590-s.Tpo -c -o libsane_hp5590_la-hp5590-s.lo `test -f 'hp5590-s.c' || echo '$(srcdir)/'`hp5590-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hp5590_la-hp5590-s.Tpo $(DEPDIR)/libsane_hp5590_la-hp5590-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hp5590-s.c' object='libsane_hp5590_la-hp5590-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hp5590_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hp5590_la-hp5590-s.lo `test -f 'hp5590-s.c' || echo '$(srcdir)/'`hp5590-s.c - -libsane_hpljm1005_la-hpljm1005-s.lo: hpljm1005-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hpljm1005_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hpljm1005_la-hpljm1005-s.lo -MD -MP -MF $(DEPDIR)/libsane_hpljm1005_la-hpljm1005-s.Tpo -c -o libsane_hpljm1005_la-hpljm1005-s.lo `test -f 'hpljm1005-s.c' || echo '$(srcdir)/'`hpljm1005-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hpljm1005_la-hpljm1005-s.Tpo $(DEPDIR)/libsane_hpljm1005_la-hpljm1005-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hpljm1005-s.c' object='libsane_hpljm1005_la-hpljm1005-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hpljm1005_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hpljm1005_la-hpljm1005-s.lo `test -f 'hpljm1005-s.c' || echo '$(srcdir)/'`hpljm1005-s.c - -libsane_hpsj5s_la-hpsj5s-s.lo: hpsj5s-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hpsj5s_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hpsj5s_la-hpsj5s-s.lo -MD -MP -MF $(DEPDIR)/libsane_hpsj5s_la-hpsj5s-s.Tpo -c -o libsane_hpsj5s_la-hpsj5s-s.lo `test -f 'hpsj5s-s.c' || echo '$(srcdir)/'`hpsj5s-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hpsj5s_la-hpsj5s-s.Tpo $(DEPDIR)/libsane_hpsj5s_la-hpsj5s-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hpsj5s-s.c' object='libsane_hpsj5s_la-hpsj5s-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hpsj5s_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hpsj5s_la-hpsj5s-s.lo `test -f 'hpsj5s-s.c' || echo '$(srcdir)/'`hpsj5s-s.c - -libsane_hs2p_la-hs2p-s.lo: hs2p-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hs2p_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_hs2p_la-hs2p-s.lo -MD -MP -MF $(DEPDIR)/libsane_hs2p_la-hs2p-s.Tpo -c -o libsane_hs2p_la-hs2p-s.lo `test -f 'hs2p-s.c' || echo '$(srcdir)/'`hs2p-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_hs2p_la-hs2p-s.Tpo $(DEPDIR)/libsane_hs2p_la-hs2p-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hs2p-s.c' object='libsane_hs2p_la-hs2p-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_hs2p_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_hs2p_la-hs2p-s.lo `test -f 'hs2p-s.c' || echo '$(srcdir)/'`hs2p-s.c - -libsane_ibm_la-ibm-s.lo: ibm-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_ibm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_ibm_la-ibm-s.lo -MD -MP -MF $(DEPDIR)/libsane_ibm_la-ibm-s.Tpo -c -o libsane_ibm_la-ibm-s.lo `test -f 'ibm-s.c' || echo '$(srcdir)/'`ibm-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_ibm_la-ibm-s.Tpo $(DEPDIR)/libsane_ibm_la-ibm-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ibm-s.c' object='libsane_ibm_la-ibm-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_ibm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_ibm_la-ibm-s.lo `test -f 'ibm-s.c' || echo '$(srcdir)/'`ibm-s.c - -libsane_kodak_la-kodak-s.lo: kodak-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kodak_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_kodak_la-kodak-s.lo -MD -MP -MF $(DEPDIR)/libsane_kodak_la-kodak-s.Tpo -c -o libsane_kodak_la-kodak-s.lo `test -f 'kodak-s.c' || echo '$(srcdir)/'`kodak-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_kodak_la-kodak-s.Tpo $(DEPDIR)/libsane_kodak_la-kodak-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kodak-s.c' object='libsane_kodak_la-kodak-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kodak_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_kodak_la-kodak-s.lo `test -f 'kodak-s.c' || echo '$(srcdir)/'`kodak-s.c - -libsane_kodakaio_la-kodakaio-s.lo: kodakaio-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kodakaio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_kodakaio_la-kodakaio-s.lo -MD -MP -MF $(DEPDIR)/libsane_kodakaio_la-kodakaio-s.Tpo -c -o libsane_kodakaio_la-kodakaio-s.lo `test -f 'kodakaio-s.c' || echo '$(srcdir)/'`kodakaio-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_kodakaio_la-kodakaio-s.Tpo $(DEPDIR)/libsane_kodakaio_la-kodakaio-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kodakaio-s.c' object='libsane_kodakaio_la-kodakaio-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kodakaio_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_kodakaio_la-kodakaio-s.lo `test -f 'kodakaio-s.c' || echo '$(srcdir)/'`kodakaio-s.c - -libsane_kvs1025_la-kvs1025-s.lo: kvs1025-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_kvs1025_la-kvs1025-s.lo -MD -MP -MF $(DEPDIR)/libsane_kvs1025_la-kvs1025-s.Tpo -c -o libsane_kvs1025_la-kvs1025-s.lo `test -f 'kvs1025-s.c' || echo '$(srcdir)/'`kvs1025-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_kvs1025_la-kvs1025-s.Tpo $(DEPDIR)/libsane_kvs1025_la-kvs1025-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs1025-s.c' object='libsane_kvs1025_la-kvs1025-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kvs1025_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_kvs1025_la-kvs1025-s.lo `test -f 'kvs1025-s.c' || echo '$(srcdir)/'`kvs1025-s.c - -libsane_kvs20xx_la-kvs20xx-s.lo: kvs20xx-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kvs20xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_kvs20xx_la-kvs20xx-s.lo -MD -MP -MF $(DEPDIR)/libsane_kvs20xx_la-kvs20xx-s.Tpo -c -o libsane_kvs20xx_la-kvs20xx-s.lo `test -f 'kvs20xx-s.c' || echo '$(srcdir)/'`kvs20xx-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_kvs20xx_la-kvs20xx-s.Tpo $(DEPDIR)/libsane_kvs20xx_la-kvs20xx-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs20xx-s.c' object='libsane_kvs20xx_la-kvs20xx-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kvs20xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_kvs20xx_la-kvs20xx-s.lo `test -f 'kvs20xx-s.c' || echo '$(srcdir)/'`kvs20xx-s.c - -libsane_kvs40xx_la-kvs40xx-s.lo: kvs40xx-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kvs40xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_kvs40xx_la-kvs40xx-s.lo -MD -MP -MF $(DEPDIR)/libsane_kvs40xx_la-kvs40xx-s.Tpo -c -o libsane_kvs40xx_la-kvs40xx-s.lo `test -f 'kvs40xx-s.c' || echo '$(srcdir)/'`kvs40xx-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_kvs40xx_la-kvs40xx-s.Tpo $(DEPDIR)/libsane_kvs40xx_la-kvs40xx-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='kvs40xx-s.c' object='libsane_kvs40xx_la-kvs40xx-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_kvs40xx_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_kvs40xx_la-kvs40xx-s.lo `test -f 'kvs40xx-s.c' || echo '$(srcdir)/'`kvs40xx-s.c - -libsane_leo_la-leo-s.lo: leo-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_leo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_leo_la-leo-s.lo -MD -MP -MF $(DEPDIR)/libsane_leo_la-leo-s.Tpo -c -o libsane_leo_la-leo-s.lo `test -f 'leo-s.c' || echo '$(srcdir)/'`leo-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_leo_la-leo-s.Tpo $(DEPDIR)/libsane_leo_la-leo-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='leo-s.c' object='libsane_leo_la-leo-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_leo_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_leo_la-leo-s.lo `test -f 'leo-s.c' || echo '$(srcdir)/'`leo-s.c - -libsane_lexmark_la-lexmark-s.lo: lexmark-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_lexmark_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_lexmark_la-lexmark-s.lo -MD -MP -MF $(DEPDIR)/libsane_lexmark_la-lexmark-s.Tpo -c -o libsane_lexmark_la-lexmark-s.lo `test -f 'lexmark-s.c' || echo '$(srcdir)/'`lexmark-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_lexmark_la-lexmark-s.Tpo $(DEPDIR)/libsane_lexmark_la-lexmark-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='lexmark-s.c' object='libsane_lexmark_la-lexmark-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_lexmark_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_lexmark_la-lexmark-s.lo `test -f 'lexmark-s.c' || echo '$(srcdir)/'`lexmark-s.c - -libsane_ma1509_la-ma1509-s.lo: ma1509-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_ma1509_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_ma1509_la-ma1509-s.lo -MD -MP -MF $(DEPDIR)/libsane_ma1509_la-ma1509-s.Tpo -c -o libsane_ma1509_la-ma1509-s.lo `test -f 'ma1509-s.c' || echo '$(srcdir)/'`ma1509-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_ma1509_la-ma1509-s.Tpo $(DEPDIR)/libsane_ma1509_la-ma1509-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ma1509-s.c' object='libsane_ma1509_la-ma1509-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_ma1509_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_ma1509_la-ma1509-s.lo `test -f 'ma1509-s.c' || echo '$(srcdir)/'`ma1509-s.c - -libsane_magicolor_la-magicolor-s.lo: magicolor-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_magicolor_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_magicolor_la-magicolor-s.lo -MD -MP -MF $(DEPDIR)/libsane_magicolor_la-magicolor-s.Tpo -c -o libsane_magicolor_la-magicolor-s.lo `test -f 'magicolor-s.c' || echo '$(srcdir)/'`magicolor-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_magicolor_la-magicolor-s.Tpo $(DEPDIR)/libsane_magicolor_la-magicolor-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='magicolor-s.c' object='libsane_magicolor_la-magicolor-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_magicolor_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_magicolor_la-magicolor-s.lo `test -f 'magicolor-s.c' || echo '$(srcdir)/'`magicolor-s.c - -libsane_matsushita_la-matsushita-s.lo: matsushita-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_matsushita_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_matsushita_la-matsushita-s.lo -MD -MP -MF $(DEPDIR)/libsane_matsushita_la-matsushita-s.Tpo -c -o libsane_matsushita_la-matsushita-s.lo `test -f 'matsushita-s.c' || echo '$(srcdir)/'`matsushita-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_matsushita_la-matsushita-s.Tpo $(DEPDIR)/libsane_matsushita_la-matsushita-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='matsushita-s.c' object='libsane_matsushita_la-matsushita-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_matsushita_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_matsushita_la-matsushita-s.lo `test -f 'matsushita-s.c' || echo '$(srcdir)/'`matsushita-s.c - -libsane_microtek_la-microtek-s.lo: microtek-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_microtek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_microtek_la-microtek-s.lo -MD -MP -MF $(DEPDIR)/libsane_microtek_la-microtek-s.Tpo -c -o libsane_microtek_la-microtek-s.lo `test -f 'microtek-s.c' || echo '$(srcdir)/'`microtek-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_microtek_la-microtek-s.Tpo $(DEPDIR)/libsane_microtek_la-microtek-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='microtek-s.c' object='libsane_microtek_la-microtek-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_microtek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_microtek_la-microtek-s.lo `test -f 'microtek-s.c' || echo '$(srcdir)/'`microtek-s.c - -libsane_microtek2_la-microtek2-s.lo: microtek2-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_microtek2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_microtek2_la-microtek2-s.lo -MD -MP -MF $(DEPDIR)/libsane_microtek2_la-microtek2-s.Tpo -c -o libsane_microtek2_la-microtek2-s.lo `test -f 'microtek2-s.c' || echo '$(srcdir)/'`microtek2-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_microtek2_la-microtek2-s.Tpo $(DEPDIR)/libsane_microtek2_la-microtek2-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='microtek2-s.c' object='libsane_microtek2_la-microtek2-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_microtek2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_microtek2_la-microtek2-s.lo `test -f 'microtek2-s.c' || echo '$(srcdir)/'`microtek2-s.c - -libsane_mustek_la-mustek-s.lo: mustek-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_mustek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_mustek_la-mustek-s.lo -MD -MP -MF $(DEPDIR)/libsane_mustek_la-mustek-s.Tpo -c -o libsane_mustek_la-mustek-s.lo `test -f 'mustek-s.c' || echo '$(srcdir)/'`mustek-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_mustek_la-mustek-s.Tpo $(DEPDIR)/libsane_mustek_la-mustek-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mustek-s.c' object='libsane_mustek_la-mustek-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_mustek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_mustek_la-mustek-s.lo `test -f 'mustek-s.c' || echo '$(srcdir)/'`mustek-s.c - -libsane_mustek_pp_la-mustek_pp-s.lo: mustek_pp-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_mustek_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_mustek_pp_la-mustek_pp-s.lo -MD -MP -MF $(DEPDIR)/libsane_mustek_pp_la-mustek_pp-s.Tpo -c -o libsane_mustek_pp_la-mustek_pp-s.lo `test -f 'mustek_pp-s.c' || echo '$(srcdir)/'`mustek_pp-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_mustek_pp_la-mustek_pp-s.Tpo $(DEPDIR)/libsane_mustek_pp_la-mustek_pp-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mustek_pp-s.c' object='libsane_mustek_pp_la-mustek_pp-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_mustek_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_mustek_pp_la-mustek_pp-s.lo `test -f 'mustek_pp-s.c' || echo '$(srcdir)/'`mustek_pp-s.c - -libsane_mustek_usb_la-mustek_usb-s.lo: mustek_usb-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_mustek_usb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_mustek_usb_la-mustek_usb-s.lo -MD -MP -MF $(DEPDIR)/libsane_mustek_usb_la-mustek_usb-s.Tpo -c -o libsane_mustek_usb_la-mustek_usb-s.lo `test -f 'mustek_usb-s.c' || echo '$(srcdir)/'`mustek_usb-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_mustek_usb_la-mustek_usb-s.Tpo $(DEPDIR)/libsane_mustek_usb_la-mustek_usb-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mustek_usb-s.c' object='libsane_mustek_usb_la-mustek_usb-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_mustek_usb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_mustek_usb_la-mustek_usb-s.lo `test -f 'mustek_usb-s.c' || echo '$(srcdir)/'`mustek_usb-s.c - -libsane_mustek_usb2_la-mustek_usb2-s.lo: mustek_usb2-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_mustek_usb2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_mustek_usb2_la-mustek_usb2-s.lo -MD -MP -MF $(DEPDIR)/libsane_mustek_usb2_la-mustek_usb2-s.Tpo -c -o libsane_mustek_usb2_la-mustek_usb2-s.lo `test -f 'mustek_usb2-s.c' || echo '$(srcdir)/'`mustek_usb2-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_mustek_usb2_la-mustek_usb2-s.Tpo $(DEPDIR)/libsane_mustek_usb2_la-mustek_usb2-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mustek_usb2-s.c' object='libsane_mustek_usb2_la-mustek_usb2-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_mustek_usb2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_mustek_usb2_la-mustek_usb2-s.lo `test -f 'mustek_usb2-s.c' || echo '$(srcdir)/'`mustek_usb2-s.c - -libsane_nec_la-nec-s.lo: nec-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_nec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_nec_la-nec-s.lo -MD -MP -MF $(DEPDIR)/libsane_nec_la-nec-s.Tpo -c -o libsane_nec_la-nec-s.lo `test -f 'nec-s.c' || echo '$(srcdir)/'`nec-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_nec_la-nec-s.Tpo $(DEPDIR)/libsane_nec_la-nec-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nec-s.c' object='libsane_nec_la-nec-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_nec_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_nec_la-nec-s.lo `test -f 'nec-s.c' || echo '$(srcdir)/'`nec-s.c - -libsane_net_la-net-s.lo: net-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_net_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_net_la-net-s.lo -MD -MP -MF $(DEPDIR)/libsane_net_la-net-s.Tpo -c -o libsane_net_la-net-s.lo `test -f 'net-s.c' || echo '$(srcdir)/'`net-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_net_la-net-s.Tpo $(DEPDIR)/libsane_net_la-net-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='net-s.c' object='libsane_net_la-net-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_net_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_net_la-net-s.lo `test -f 'net-s.c' || echo '$(srcdir)/'`net-s.c - -libsane_niash_la-niash-s.lo: niash-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_niash_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_niash_la-niash-s.lo -MD -MP -MF $(DEPDIR)/libsane_niash_la-niash-s.Tpo -c -o libsane_niash_la-niash-s.lo `test -f 'niash-s.c' || echo '$(srcdir)/'`niash-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_niash_la-niash-s.Tpo $(DEPDIR)/libsane_niash_la-niash-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='niash-s.c' object='libsane_niash_la-niash-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_niash_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_niash_la-niash-s.lo `test -f 'niash-s.c' || echo '$(srcdir)/'`niash-s.c - -libsane_p5_la-p5-s.lo: p5-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_p5_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_p5_la-p5-s.lo -MD -MP -MF $(DEPDIR)/libsane_p5_la-p5-s.Tpo -c -o libsane_p5_la-p5-s.lo `test -f 'p5-s.c' || echo '$(srcdir)/'`p5-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_p5_la-p5-s.Tpo $(DEPDIR)/libsane_p5_la-p5-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='p5-s.c' object='libsane_p5_la-p5-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_p5_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_p5_la-p5-s.lo `test -f 'p5-s.c' || echo '$(srcdir)/'`p5-s.c - -libsane_pie_la-pie-s.lo: pie-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pie_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_pie_la-pie-s.lo -MD -MP -MF $(DEPDIR)/libsane_pie_la-pie-s.Tpo -c -o libsane_pie_la-pie-s.lo `test -f 'pie-s.c' || echo '$(srcdir)/'`pie-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_pie_la-pie-s.Tpo $(DEPDIR)/libsane_pie_la-pie-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pie-s.c' object='libsane_pie_la-pie-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pie_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_pie_la-pie-s.lo `test -f 'pie-s.c' || echo '$(srcdir)/'`pie-s.c - -libsane_pieusb_la-pieusb-s.lo: pieusb-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_pieusb_la-pieusb-s.lo -MD -MP -MF $(DEPDIR)/libsane_pieusb_la-pieusb-s.Tpo -c -o libsane_pieusb_la-pieusb-s.lo `test -f 'pieusb-s.c' || echo '$(srcdir)/'`pieusb-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_pieusb_la-pieusb-s.Tpo $(DEPDIR)/libsane_pieusb_la-pieusb-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pieusb-s.c' object='libsane_pieusb_la-pieusb-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pieusb_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_pieusb_la-pieusb-s.lo `test -f 'pieusb-s.c' || echo '$(srcdir)/'`pieusb-s.c - -libsane_pint_la-pint-s.lo: pint-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pint_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_pint_la-pint-s.lo -MD -MP -MF $(DEPDIR)/libsane_pint_la-pint-s.Tpo -c -o libsane_pint_la-pint-s.lo `test -f 'pint-s.c' || echo '$(srcdir)/'`pint-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_pint_la-pint-s.Tpo $(DEPDIR)/libsane_pint_la-pint-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pint-s.c' object='libsane_pint_la-pint-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pint_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_pint_la-pint-s.lo `test -f 'pint-s.c' || echo '$(srcdir)/'`pint-s.c - -libsane_pixma_la-pixma-s.lo: pixma-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_pixma_la-pixma-s.lo -MD -MP -MF $(DEPDIR)/libsane_pixma_la-pixma-s.Tpo -c -o libsane_pixma_la-pixma-s.lo `test -f 'pixma-s.c' || echo '$(srcdir)/'`pixma-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_pixma_la-pixma-s.Tpo $(DEPDIR)/libsane_pixma_la-pixma-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pixma-s.c' object='libsane_pixma_la-pixma-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pixma_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_pixma_la-pixma-s.lo `test -f 'pixma-s.c' || echo '$(srcdir)/'`pixma-s.c - -libsane_plustek_la-plustek-s.lo: plustek-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_plustek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_plustek_la-plustek-s.lo -MD -MP -MF $(DEPDIR)/libsane_plustek_la-plustek-s.Tpo -c -o libsane_plustek_la-plustek-s.lo `test -f 'plustek-s.c' || echo '$(srcdir)/'`plustek-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_plustek_la-plustek-s.Tpo $(DEPDIR)/libsane_plustek_la-plustek-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plustek-s.c' object='libsane_plustek_la-plustek-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_plustek_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_plustek_la-plustek-s.lo `test -f 'plustek-s.c' || echo '$(srcdir)/'`plustek-s.c - -libsane_plustek_pp_la-plustek_pp-s.lo: plustek_pp-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_plustek_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_plustek_pp_la-plustek_pp-s.lo -MD -MP -MF $(DEPDIR)/libsane_plustek_pp_la-plustek_pp-s.Tpo -c -o libsane_plustek_pp_la-plustek_pp-s.lo `test -f 'plustek_pp-s.c' || echo '$(srcdir)/'`plustek_pp-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_plustek_pp_la-plustek_pp-s.Tpo $(DEPDIR)/libsane_plustek_pp_la-plustek_pp-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='plustek_pp-s.c' object='libsane_plustek_pp_la-plustek_pp-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_plustek_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_plustek_pp_la-plustek_pp-s.lo `test -f 'plustek_pp-s.c' || echo '$(srcdir)/'`plustek_pp-s.c - -libsane_pnm_la-pnm-s.lo: pnm-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pnm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_pnm_la-pnm-s.lo -MD -MP -MF $(DEPDIR)/libsane_pnm_la-pnm-s.Tpo -c -o libsane_pnm_la-pnm-s.lo `test -f 'pnm-s.c' || echo '$(srcdir)/'`pnm-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_pnm_la-pnm-s.Tpo $(DEPDIR)/libsane_pnm_la-pnm-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pnm-s.c' object='libsane_pnm_la-pnm-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_pnm_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_pnm_la-pnm-s.lo `test -f 'pnm-s.c' || echo '$(srcdir)/'`pnm-s.c - -libsane_qcam_la-qcam-s.lo: qcam-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_qcam_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_qcam_la-qcam-s.lo -MD -MP -MF $(DEPDIR)/libsane_qcam_la-qcam-s.Tpo -c -o libsane_qcam_la-qcam-s.lo `test -f 'qcam-s.c' || echo '$(srcdir)/'`qcam-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_qcam_la-qcam-s.Tpo $(DEPDIR)/libsane_qcam_la-qcam-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='qcam-s.c' object='libsane_qcam_la-qcam-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_qcam_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_qcam_la-qcam-s.lo `test -f 'qcam-s.c' || echo '$(srcdir)/'`qcam-s.c - -libsane_ricoh_la-ricoh-s.lo: ricoh-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_ricoh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_ricoh_la-ricoh-s.lo -MD -MP -MF $(DEPDIR)/libsane_ricoh_la-ricoh-s.Tpo -c -o libsane_ricoh_la-ricoh-s.lo `test -f 'ricoh-s.c' || echo '$(srcdir)/'`ricoh-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_ricoh_la-ricoh-s.Tpo $(DEPDIR)/libsane_ricoh_la-ricoh-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='ricoh-s.c' object='libsane_ricoh_la-ricoh-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_ricoh_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_ricoh_la-ricoh-s.lo `test -f 'ricoh-s.c' || echo '$(srcdir)/'`ricoh-s.c - -libsane_rts8891_la-rts8891-s.lo: rts8891-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_rts8891_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_rts8891_la-rts8891-s.lo -MD -MP -MF $(DEPDIR)/libsane_rts8891_la-rts8891-s.Tpo -c -o libsane_rts8891_la-rts8891-s.lo `test -f 'rts8891-s.c' || echo '$(srcdir)/'`rts8891-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_rts8891_la-rts8891-s.Tpo $(DEPDIR)/libsane_rts8891_la-rts8891-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rts8891-s.c' object='libsane_rts8891_la-rts8891-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_rts8891_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_rts8891_la-rts8891-s.lo `test -f 'rts8891-s.c' || echo '$(srcdir)/'`rts8891-s.c - -libsane_s9036_la-s9036-s.lo: s9036-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_s9036_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_s9036_la-s9036-s.lo -MD -MP -MF $(DEPDIR)/libsane_s9036_la-s9036-s.Tpo -c -o libsane_s9036_la-s9036-s.lo `test -f 's9036-s.c' || echo '$(srcdir)/'`s9036-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_s9036_la-s9036-s.Tpo $(DEPDIR)/libsane_s9036_la-s9036-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='s9036-s.c' object='libsane_s9036_la-s9036-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_s9036_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_s9036_la-s9036-s.lo `test -f 's9036-s.c' || echo '$(srcdir)/'`s9036-s.c - -libsane_sceptre_la-sceptre-s.lo: sceptre-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sceptre_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_sceptre_la-sceptre-s.lo -MD -MP -MF $(DEPDIR)/libsane_sceptre_la-sceptre-s.Tpo -c -o libsane_sceptre_la-sceptre-s.lo `test -f 'sceptre-s.c' || echo '$(srcdir)/'`sceptre-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_sceptre_la-sceptre-s.Tpo $(DEPDIR)/libsane_sceptre_la-sceptre-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sceptre-s.c' object='libsane_sceptre_la-sceptre-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sceptre_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_sceptre_la-sceptre-s.lo `test -f 'sceptre-s.c' || echo '$(srcdir)/'`sceptre-s.c - -libsane_sharp_la-sharp-s.lo: sharp-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sharp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_sharp_la-sharp-s.lo -MD -MP -MF $(DEPDIR)/libsane_sharp_la-sharp-s.Tpo -c -o libsane_sharp_la-sharp-s.lo `test -f 'sharp-s.c' || echo '$(srcdir)/'`sharp-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_sharp_la-sharp-s.Tpo $(DEPDIR)/libsane_sharp_la-sharp-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sharp-s.c' object='libsane_sharp_la-sharp-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sharp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_sharp_la-sharp-s.lo `test -f 'sharp-s.c' || echo '$(srcdir)/'`sharp-s.c - -libsane_sm3600_la-sm3600-s.lo: sm3600-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sm3600_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_sm3600_la-sm3600-s.lo -MD -MP -MF $(DEPDIR)/libsane_sm3600_la-sm3600-s.Tpo -c -o libsane_sm3600_la-sm3600-s.lo `test -f 'sm3600-s.c' || echo '$(srcdir)/'`sm3600-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_sm3600_la-sm3600-s.Tpo $(DEPDIR)/libsane_sm3600_la-sm3600-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sm3600-s.c' object='libsane_sm3600_la-sm3600-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sm3600_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_sm3600_la-sm3600-s.lo `test -f 'sm3600-s.c' || echo '$(srcdir)/'`sm3600-s.c - -libsane_sm3840_la-sm3840-s.lo: sm3840-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sm3840_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_sm3840_la-sm3840-s.lo -MD -MP -MF $(DEPDIR)/libsane_sm3840_la-sm3840-s.Tpo -c -o libsane_sm3840_la-sm3840-s.lo `test -f 'sm3840-s.c' || echo '$(srcdir)/'`sm3840-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_sm3840_la-sm3840-s.Tpo $(DEPDIR)/libsane_sm3840_la-sm3840-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sm3840-s.c' object='libsane_sm3840_la-sm3840-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sm3840_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_sm3840_la-sm3840-s.lo `test -f 'sm3840-s.c' || echo '$(srcdir)/'`sm3840-s.c - -libsane_snapscan_la-snapscan-s.lo: snapscan-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_snapscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_snapscan_la-snapscan-s.lo -MD -MP -MF $(DEPDIR)/libsane_snapscan_la-snapscan-s.Tpo -c -o libsane_snapscan_la-snapscan-s.lo `test -f 'snapscan-s.c' || echo '$(srcdir)/'`snapscan-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_snapscan_la-snapscan-s.Tpo $(DEPDIR)/libsane_snapscan_la-snapscan-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='snapscan-s.c' object='libsane_snapscan_la-snapscan-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_snapscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_snapscan_la-snapscan-s.lo `test -f 'snapscan-s.c' || echo '$(srcdir)/'`snapscan-s.c - -libsane_sp15c_la-sp15c-s.lo: sp15c-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sp15c_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_sp15c_la-sp15c-s.lo -MD -MP -MF $(DEPDIR)/libsane_sp15c_la-sp15c-s.Tpo -c -o libsane_sp15c_la-sp15c-s.lo `test -f 'sp15c-s.c' || echo '$(srcdir)/'`sp15c-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_sp15c_la-sp15c-s.Tpo $(DEPDIR)/libsane_sp15c_la-sp15c-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sp15c-s.c' object='libsane_sp15c_la-sp15c-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_sp15c_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_sp15c_la-sp15c-s.lo `test -f 'sp15c-s.c' || echo '$(srcdir)/'`sp15c-s.c - -libsane_st400_la-st400-s.lo: st400-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_st400_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_st400_la-st400-s.lo -MD -MP -MF $(DEPDIR)/libsane_st400_la-st400-s.Tpo -c -o libsane_st400_la-st400-s.lo `test -f 'st400-s.c' || echo '$(srcdir)/'`st400-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_st400_la-st400-s.Tpo $(DEPDIR)/libsane_st400_la-st400-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='st400-s.c' object='libsane_st400_la-st400-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_st400_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_st400_la-st400-s.lo `test -f 'st400-s.c' || echo '$(srcdir)/'`st400-s.c - -libsane_stv680_la-stv680-s.lo: stv680-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_stv680_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_stv680_la-stv680-s.lo -MD -MP -MF $(DEPDIR)/libsane_stv680_la-stv680-s.Tpo -c -o libsane_stv680_la-stv680-s.lo `test -f 'stv680-s.c' || echo '$(srcdir)/'`stv680-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_stv680_la-stv680-s.Tpo $(DEPDIR)/libsane_stv680_la-stv680-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stv680-s.c' object='libsane_stv680_la-stv680-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_stv680_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_stv680_la-stv680-s.lo `test -f 'stv680-s.c' || echo '$(srcdir)/'`stv680-s.c - -libsane_tamarack_la-tamarack-s.lo: tamarack-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_tamarack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_tamarack_la-tamarack-s.lo -MD -MP -MF $(DEPDIR)/libsane_tamarack_la-tamarack-s.Tpo -c -o libsane_tamarack_la-tamarack-s.lo `test -f 'tamarack-s.c' || echo '$(srcdir)/'`tamarack-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_tamarack_la-tamarack-s.Tpo $(DEPDIR)/libsane_tamarack_la-tamarack-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tamarack-s.c' object='libsane_tamarack_la-tamarack-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_tamarack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_tamarack_la-tamarack-s.lo `test -f 'tamarack-s.c' || echo '$(srcdir)/'`tamarack-s.c - -libsane_teco1_la-teco1-s.lo: teco1-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_teco1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_teco1_la-teco1-s.lo -MD -MP -MF $(DEPDIR)/libsane_teco1_la-teco1-s.Tpo -c -o libsane_teco1_la-teco1-s.lo `test -f 'teco1-s.c' || echo '$(srcdir)/'`teco1-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_teco1_la-teco1-s.Tpo $(DEPDIR)/libsane_teco1_la-teco1-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='teco1-s.c' object='libsane_teco1_la-teco1-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_teco1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_teco1_la-teco1-s.lo `test -f 'teco1-s.c' || echo '$(srcdir)/'`teco1-s.c - -libsane_teco2_la-teco2-s.lo: teco2-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_teco2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_teco2_la-teco2-s.lo -MD -MP -MF $(DEPDIR)/libsane_teco2_la-teco2-s.Tpo -c -o libsane_teco2_la-teco2-s.lo `test -f 'teco2-s.c' || echo '$(srcdir)/'`teco2-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_teco2_la-teco2-s.Tpo $(DEPDIR)/libsane_teco2_la-teco2-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='teco2-s.c' object='libsane_teco2_la-teco2-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_teco2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_teco2_la-teco2-s.lo `test -f 'teco2-s.c' || echo '$(srcdir)/'`teco2-s.c - -libsane_teco3_la-teco3-s.lo: teco3-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_teco3_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_teco3_la-teco3-s.lo -MD -MP -MF $(DEPDIR)/libsane_teco3_la-teco3-s.Tpo -c -o libsane_teco3_la-teco3-s.lo `test -f 'teco3-s.c' || echo '$(srcdir)/'`teco3-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_teco3_la-teco3-s.Tpo $(DEPDIR)/libsane_teco3_la-teco3-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='teco3-s.c' object='libsane_teco3_la-teco3-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_teco3_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_teco3_la-teco3-s.lo `test -f 'teco3-s.c' || echo '$(srcdir)/'`teco3-s.c - -libsane_test_la-test-s.lo: test-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_test_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_test_la-test-s.lo -MD -MP -MF $(DEPDIR)/libsane_test_la-test-s.Tpo -c -o libsane_test_la-test-s.lo `test -f 'test-s.c' || echo '$(srcdir)/'`test-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_test_la-test-s.Tpo $(DEPDIR)/libsane_test_la-test-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test-s.c' object='libsane_test_la-test-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_test_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_test_la-test-s.lo `test -f 'test-s.c' || echo '$(srcdir)/'`test-s.c - -libsane_u12_la-u12-s.lo: u12-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_u12_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_u12_la-u12-s.lo -MD -MP -MF $(DEPDIR)/libsane_u12_la-u12-s.Tpo -c -o libsane_u12_la-u12-s.lo `test -f 'u12-s.c' || echo '$(srcdir)/'`u12-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_u12_la-u12-s.Tpo $(DEPDIR)/libsane_u12_la-u12-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='u12-s.c' object='libsane_u12_la-u12-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_u12_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_u12_la-u12-s.lo `test -f 'u12-s.c' || echo '$(srcdir)/'`u12-s.c - -libsane_umax_la-umax-s.lo: umax-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_umax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_umax_la-umax-s.lo -MD -MP -MF $(DEPDIR)/libsane_umax_la-umax-s.Tpo -c -o libsane_umax_la-umax-s.lo `test -f 'umax-s.c' || echo '$(srcdir)/'`umax-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_umax_la-umax-s.Tpo $(DEPDIR)/libsane_umax_la-umax-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax-s.c' object='libsane_umax_la-umax-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_umax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_umax_la-umax-s.lo `test -f 'umax-s.c' || echo '$(srcdir)/'`umax-s.c - -libsane_umax1220u_la-umax1220u-s.lo: umax1220u-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_umax1220u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_umax1220u_la-umax1220u-s.lo -MD -MP -MF $(DEPDIR)/libsane_umax1220u_la-umax1220u-s.Tpo -c -o libsane_umax1220u_la-umax1220u-s.lo `test -f 'umax1220u-s.c' || echo '$(srcdir)/'`umax1220u-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_umax1220u_la-umax1220u-s.Tpo $(DEPDIR)/libsane_umax1220u_la-umax1220u-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax1220u-s.c' object='libsane_umax1220u_la-umax1220u-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_umax1220u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_umax1220u_la-umax1220u-s.lo `test -f 'umax1220u-s.c' || echo '$(srcdir)/'`umax1220u-s.c - -libsane_umax_pp_la-umax_pp-s.lo: umax_pp-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_umax_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_umax_pp_la-umax_pp-s.lo -MD -MP -MF $(DEPDIR)/libsane_umax_pp_la-umax_pp-s.Tpo -c -o libsane_umax_pp_la-umax_pp-s.lo `test -f 'umax_pp-s.c' || echo '$(srcdir)/'`umax_pp-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_umax_pp_la-umax_pp-s.Tpo $(DEPDIR)/libsane_umax_pp_la-umax_pp-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax_pp-s.c' object='libsane_umax_pp_la-umax_pp-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_umax_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_umax_pp_la-umax_pp-s.lo `test -f 'umax_pp-s.c' || echo '$(srcdir)/'`umax_pp-s.c - -libsane_v4l_la-v4l-s.lo: v4l-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_v4l_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_v4l_la-v4l-s.lo -MD -MP -MF $(DEPDIR)/libsane_v4l_la-v4l-s.Tpo -c -o libsane_v4l_la-v4l-s.lo `test -f 'v4l-s.c' || echo '$(srcdir)/'`v4l-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_v4l_la-v4l-s.Tpo $(DEPDIR)/libsane_v4l_la-v4l-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='v4l-s.c' object='libsane_v4l_la-v4l-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_v4l_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_v4l_la-v4l-s.lo `test -f 'v4l-s.c' || echo '$(srcdir)/'`v4l-s.c - -libsane_xerox_mfp_la-xerox_mfp-s.lo: xerox_mfp-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_xerox_mfp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_xerox_mfp_la-xerox_mfp-s.lo -MD -MP -MF $(DEPDIR)/libsane_xerox_mfp_la-xerox_mfp-s.Tpo -c -o libsane_xerox_mfp_la-xerox_mfp-s.lo `test -f 'xerox_mfp-s.c' || echo '$(srcdir)/'`xerox_mfp-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_xerox_mfp_la-xerox_mfp-s.Tpo $(DEPDIR)/libsane_xerox_mfp_la-xerox_mfp-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xerox_mfp-s.c' object='libsane_xerox_mfp_la-xerox_mfp-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_xerox_mfp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_xerox_mfp_la-xerox_mfp-s.lo `test -f 'xerox_mfp-s.c' || echo '$(srcdir)/'`xerox_mfp-s.c - -libsane_la-dll-s.lo: dll-s.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsane_la-dll-s.lo -MD -MP -MF $(DEPDIR)/libsane_la-dll-s.Tpo -c -o libsane_la-dll-s.lo `test -f 'dll-s.c' || echo '$(srcdir)/'`dll-s.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsane_la-dll-s.Tpo $(DEPDIR)/libsane_la-dll-s.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='dll-s.c' object='libsane_la-dll-s.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsane_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsane_la-dll-s.lo `test -f 'dll-s.c' || echo '$(srcdir)/'`dll-s.c - -libsceptre_la-sceptre.lo: sceptre.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsceptre_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsceptre_la-sceptre.lo -MD -MP -MF $(DEPDIR)/libsceptre_la-sceptre.Tpo -c -o libsceptre_la-sceptre.lo `test -f 'sceptre.c' || echo '$(srcdir)/'`sceptre.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsceptre_la-sceptre.Tpo $(DEPDIR)/libsceptre_la-sceptre.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sceptre.c' object='libsceptre_la-sceptre.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsceptre_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsceptre_la-sceptre.lo `test -f 'sceptre.c' || echo '$(srcdir)/'`sceptre.c - -libsharp_la-sharp.lo: sharp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsharp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsharp_la-sharp.lo -MD -MP -MF $(DEPDIR)/libsharp_la-sharp.Tpo -c -o libsharp_la-sharp.lo `test -f 'sharp.c' || echo '$(srcdir)/'`sharp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsharp_la-sharp.Tpo $(DEPDIR)/libsharp_la-sharp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sharp.c' object='libsharp_la-sharp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsharp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsharp_la-sharp.lo `test -f 'sharp.c' || echo '$(srcdir)/'`sharp.c - -libsm3600_la-sm3600.lo: sm3600.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsm3600_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsm3600_la-sm3600.lo -MD -MP -MF $(DEPDIR)/libsm3600_la-sm3600.Tpo -c -o libsm3600_la-sm3600.lo `test -f 'sm3600.c' || echo '$(srcdir)/'`sm3600.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsm3600_la-sm3600.Tpo $(DEPDIR)/libsm3600_la-sm3600.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sm3600.c' object='libsm3600_la-sm3600.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsm3600_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsm3600_la-sm3600.lo `test -f 'sm3600.c' || echo '$(srcdir)/'`sm3600.c - -libsm3840_la-sm3840.lo: sm3840.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsm3840_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsm3840_la-sm3840.lo -MD -MP -MF $(DEPDIR)/libsm3840_la-sm3840.Tpo -c -o libsm3840_la-sm3840.lo `test -f 'sm3840.c' || echo '$(srcdir)/'`sm3840.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsm3840_la-sm3840.Tpo $(DEPDIR)/libsm3840_la-sm3840.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sm3840.c' object='libsm3840_la-sm3840.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsm3840_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsm3840_la-sm3840.lo `test -f 'sm3840.c' || echo '$(srcdir)/'`sm3840.c - -libsnapscan_la-snapscan.lo: snapscan.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsnapscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsnapscan_la-snapscan.lo -MD -MP -MF $(DEPDIR)/libsnapscan_la-snapscan.Tpo -c -o libsnapscan_la-snapscan.lo `test -f 'snapscan.c' || echo '$(srcdir)/'`snapscan.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsnapscan_la-snapscan.Tpo $(DEPDIR)/libsnapscan_la-snapscan.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='snapscan.c' object='libsnapscan_la-snapscan.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsnapscan_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsnapscan_la-snapscan.lo `test -f 'snapscan.c' || echo '$(srcdir)/'`snapscan.c - -libsp15c_la-sp15c.lo: sp15c.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsp15c_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libsp15c_la-sp15c.lo -MD -MP -MF $(DEPDIR)/libsp15c_la-sp15c.Tpo -c -o libsp15c_la-sp15c.lo `test -f 'sp15c.c' || echo '$(srcdir)/'`sp15c.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libsp15c_la-sp15c.Tpo $(DEPDIR)/libsp15c_la-sp15c.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='sp15c.c' object='libsp15c_la-sp15c.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libsp15c_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libsp15c_la-sp15c.lo `test -f 'sp15c.c' || echo '$(srcdir)/'`sp15c.c - -libst400_la-st400.lo: st400.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libst400_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libst400_la-st400.lo -MD -MP -MF $(DEPDIR)/libst400_la-st400.Tpo -c -o libst400_la-st400.lo `test -f 'st400.c' || echo '$(srcdir)/'`st400.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libst400_la-st400.Tpo $(DEPDIR)/libst400_la-st400.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='st400.c' object='libst400_la-st400.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libst400_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libst400_la-st400.lo `test -f 'st400.c' || echo '$(srcdir)/'`st400.c - -libstv680_la-stv680.lo: stv680.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstv680_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libstv680_la-stv680.lo -MD -MP -MF $(DEPDIR)/libstv680_la-stv680.Tpo -c -o libstv680_la-stv680.lo `test -f 'stv680.c' || echo '$(srcdir)/'`stv680.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libstv680_la-stv680.Tpo $(DEPDIR)/libstv680_la-stv680.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='stv680.c' object='libstv680_la-stv680.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libstv680_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libstv680_la-stv680.lo `test -f 'stv680.c' || echo '$(srcdir)/'`stv680.c - -libtamarack_la-tamarack.lo: tamarack.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtamarack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libtamarack_la-tamarack.lo -MD -MP -MF $(DEPDIR)/libtamarack_la-tamarack.Tpo -c -o libtamarack_la-tamarack.lo `test -f 'tamarack.c' || echo '$(srcdir)/'`tamarack.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtamarack_la-tamarack.Tpo $(DEPDIR)/libtamarack_la-tamarack.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='tamarack.c' object='libtamarack_la-tamarack.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtamarack_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libtamarack_la-tamarack.lo `test -f 'tamarack.c' || echo '$(srcdir)/'`tamarack.c - -libteco1_la-teco1.lo: teco1.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libteco1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libteco1_la-teco1.lo -MD -MP -MF $(DEPDIR)/libteco1_la-teco1.Tpo -c -o libteco1_la-teco1.lo `test -f 'teco1.c' || echo '$(srcdir)/'`teco1.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libteco1_la-teco1.Tpo $(DEPDIR)/libteco1_la-teco1.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='teco1.c' object='libteco1_la-teco1.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libteco1_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libteco1_la-teco1.lo `test -f 'teco1.c' || echo '$(srcdir)/'`teco1.c - -libteco2_la-teco2.lo: teco2.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libteco2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libteco2_la-teco2.lo -MD -MP -MF $(DEPDIR)/libteco2_la-teco2.Tpo -c -o libteco2_la-teco2.lo `test -f 'teco2.c' || echo '$(srcdir)/'`teco2.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libteco2_la-teco2.Tpo $(DEPDIR)/libteco2_la-teco2.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='teco2.c' object='libteco2_la-teco2.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libteco2_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libteco2_la-teco2.lo `test -f 'teco2.c' || echo '$(srcdir)/'`teco2.c - -libteco3_la-teco3.lo: teco3.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libteco3_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libteco3_la-teco3.lo -MD -MP -MF $(DEPDIR)/libteco3_la-teco3.Tpo -c -o libteco3_la-teco3.lo `test -f 'teco3.c' || echo '$(srcdir)/'`teco3.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libteco3_la-teco3.Tpo $(DEPDIR)/libteco3_la-teco3.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='teco3.c' object='libteco3_la-teco3.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libteco3_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libteco3_la-teco3.lo `test -f 'teco3.c' || echo '$(srcdir)/'`teco3.c - -libtest_la-test.lo: test.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtest_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libtest_la-test.lo -MD -MP -MF $(DEPDIR)/libtest_la-test.Tpo -c -o libtest_la-test.lo `test -f 'test.c' || echo '$(srcdir)/'`test.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtest_la-test.Tpo $(DEPDIR)/libtest_la-test.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='test.c' object='libtest_la-test.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtest_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libtest_la-test.lo `test -f 'test.c' || echo '$(srcdir)/'`test.c - -libu12_la-u12.lo: u12.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libu12_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libu12_la-u12.lo -MD -MP -MF $(DEPDIR)/libu12_la-u12.Tpo -c -o libu12_la-u12.lo `test -f 'u12.c' || echo '$(srcdir)/'`u12.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libu12_la-u12.Tpo $(DEPDIR)/libu12_la-u12.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='u12.c' object='libu12_la-u12.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libu12_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libu12_la-u12.lo `test -f 'u12.c' || echo '$(srcdir)/'`u12.c - -libumax_la-umax.lo: umax.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libumax_la-umax.lo -MD -MP -MF $(DEPDIR)/libumax_la-umax.Tpo -c -o libumax_la-umax.lo `test -f 'umax.c' || echo '$(srcdir)/'`umax.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libumax_la-umax.Tpo $(DEPDIR)/libumax_la-umax.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax.c' object='libumax_la-umax.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libumax_la-umax.lo `test -f 'umax.c' || echo '$(srcdir)/'`umax.c - -libumax1220u_la-umax1220u.lo: umax1220u.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax1220u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libumax1220u_la-umax1220u.lo -MD -MP -MF $(DEPDIR)/libumax1220u_la-umax1220u.Tpo -c -o libumax1220u_la-umax1220u.lo `test -f 'umax1220u.c' || echo '$(srcdir)/'`umax1220u.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libumax1220u_la-umax1220u.Tpo $(DEPDIR)/libumax1220u_la-umax1220u.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax1220u.c' object='libumax1220u_la-umax1220u.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax1220u_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libumax1220u_la-umax1220u.lo `test -f 'umax1220u.c' || echo '$(srcdir)/'`umax1220u.c - -libumax_pp_la-umax_pp.lo: umax_pp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libumax_pp_la-umax_pp.lo -MD -MP -MF $(DEPDIR)/libumax_pp_la-umax_pp.Tpo -c -o libumax_pp_la-umax_pp.lo `test -f 'umax_pp.c' || echo '$(srcdir)/'`umax_pp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libumax_pp_la-umax_pp.Tpo $(DEPDIR)/libumax_pp_la-umax_pp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax_pp.c' object='libumax_pp_la-umax_pp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libumax_pp_la-umax_pp.lo `test -f 'umax_pp.c' || echo '$(srcdir)/'`umax_pp.c - -libumax_pp_la-umax_pp_low.lo: umax_pp_low.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libumax_pp_la-umax_pp_low.lo -MD -MP -MF $(DEPDIR)/libumax_pp_la-umax_pp_low.Tpo -c -o libumax_pp_la-umax_pp_low.lo `test -f 'umax_pp_low.c' || echo '$(srcdir)/'`umax_pp_low.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libumax_pp_la-umax_pp_low.Tpo $(DEPDIR)/libumax_pp_la-umax_pp_low.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax_pp_low.c' object='libumax_pp_la-umax_pp_low.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libumax_pp_la-umax_pp_low.lo `test -f 'umax_pp_low.c' || echo '$(srcdir)/'`umax_pp_low.c - -libumax_pp_la-umax_pp_mid.lo: umax_pp_mid.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libumax_pp_la-umax_pp_mid.lo -MD -MP -MF $(DEPDIR)/libumax_pp_la-umax_pp_mid.Tpo -c -o libumax_pp_la-umax_pp_mid.lo `test -f 'umax_pp_mid.c' || echo '$(srcdir)/'`umax_pp_mid.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libumax_pp_la-umax_pp_mid.Tpo $(DEPDIR)/libumax_pp_la-umax_pp_mid.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='umax_pp_mid.c' object='libumax_pp_la-umax_pp_mid.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libumax_pp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libumax_pp_la-umax_pp_mid.lo `test -f 'umax_pp_mid.c' || echo '$(srcdir)/'`umax_pp_mid.c - -libv4l_la-v4l.lo: v4l.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libv4l_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libv4l_la-v4l.lo -MD -MP -MF $(DEPDIR)/libv4l_la-v4l.Tpo -c -o libv4l_la-v4l.lo `test -f 'v4l.c' || echo '$(srcdir)/'`v4l.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libv4l_la-v4l.Tpo $(DEPDIR)/libv4l_la-v4l.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='v4l.c' object='libv4l_la-v4l.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libv4l_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libv4l_la-v4l.lo `test -f 'v4l.c' || echo '$(srcdir)/'`v4l.c - -libxerox_mfp_la-xerox_mfp.lo: xerox_mfp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxerox_mfp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxerox_mfp_la-xerox_mfp.lo -MD -MP -MF $(DEPDIR)/libxerox_mfp_la-xerox_mfp.Tpo -c -o libxerox_mfp_la-xerox_mfp.lo `test -f 'xerox_mfp.c' || echo '$(srcdir)/'`xerox_mfp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libxerox_mfp_la-xerox_mfp.Tpo $(DEPDIR)/libxerox_mfp_la-xerox_mfp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xerox_mfp.c' object='libxerox_mfp_la-xerox_mfp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxerox_mfp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxerox_mfp_la-xerox_mfp.lo `test -f 'xerox_mfp.c' || echo '$(srcdir)/'`xerox_mfp.c - -libxerox_mfp_la-xerox_mfp-usb.lo: xerox_mfp-usb.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxerox_mfp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxerox_mfp_la-xerox_mfp-usb.lo -MD -MP -MF $(DEPDIR)/libxerox_mfp_la-xerox_mfp-usb.Tpo -c -o libxerox_mfp_la-xerox_mfp-usb.lo `test -f 'xerox_mfp-usb.c' || echo '$(srcdir)/'`xerox_mfp-usb.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libxerox_mfp_la-xerox_mfp-usb.Tpo $(DEPDIR)/libxerox_mfp_la-xerox_mfp-usb.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xerox_mfp-usb.c' object='libxerox_mfp_la-xerox_mfp-usb.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxerox_mfp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxerox_mfp_la-xerox_mfp-usb.lo `test -f 'xerox_mfp-usb.c' || echo '$(srcdir)/'`xerox_mfp-usb.c - -libxerox_mfp_la-xerox_mfp-tcp.lo: xerox_mfp-tcp.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxerox_mfp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libxerox_mfp_la-xerox_mfp-tcp.lo -MD -MP -MF $(DEPDIR)/libxerox_mfp_la-xerox_mfp-tcp.Tpo -c -o libxerox_mfp_la-xerox_mfp-tcp.lo `test -f 'xerox_mfp-tcp.c' || echo '$(srcdir)/'`xerox_mfp-tcp.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libxerox_mfp_la-xerox_mfp-tcp.Tpo $(DEPDIR)/libxerox_mfp_la-xerox_mfp-tcp.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xerox_mfp-tcp.c' object='libxerox_mfp_la-xerox_mfp-tcp.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libxerox_mfp_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libxerox_mfp_la-xerox_mfp-tcp.lo `test -f 'xerox_mfp-tcp.c' || echo '$(srcdir)/'`xerox_mfp-tcp.c - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am -check: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) check-am -all-am: Makefile $(LTLIBRARIES) -installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(sanelibdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: $(BUILT_SOURCES) - $(MAKE) $(AM_MAKEFLAGS) install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." - -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) -clean: clean-am - -clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ - clean-sanelibLTLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-sanelibLTLIBRARIES - @$(NORMAL_INSTALL) - $(MAKE) $(AM_MAKEFLAGS) install-data-hook -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-libLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-libLTLIBRARIES uninstall-sanelibLTLIBRARIES - @$(NORMAL_INSTALL) - $(MAKE) $(AM_MAKEFLAGS) uninstall-hook -.MAKE: all check install install-am install-data-am install-strip \ - uninstall-am - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ - clean-libLTLIBRARIES clean-libtool clean-local \ - clean-sanelibLTLIBRARIES cscopelist-am ctags ctags-am \ - distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-data-hook install-dvi install-dvi-am \ - install-exec install-exec-am install-html install-html-am \ - install-info install-info-am install-libLTLIBRARIES \ - install-man install-pdf install-pdf-am install-ps \ - install-ps-am install-sanelibLTLIBRARIES install-strip \ - installcheck installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags tags-am uninstall uninstall-am uninstall-hook \ - uninstall-libLTLIBRARIES uninstall-sanelibLTLIBRARIES - - -all: becfg - -# FIXME: % is a GNU extension... This is only thing left requiring -# use to use GNU make. -%-s.c: $(srcdir)/stubs.c - $(AM_V_at)rm -f $@ - $(AM_V_at)$(LN_S) $(srcdir)/stubs.c $@ - -dll-preload.h: - $(AM_V_at)rm -f $@ - $(AM_V_at)list="$(PRELOADABLE_BACKENDS)"; for be in $$list; do \ - echo "PRELOAD_DECL($$be)" >> $@; \ - done; \ - echo "static struct backend preloaded_backends[] = {" >> $@; \ - sep=""; \ - list="$(PRELOADABLE_BACKENDS)"; \ - if test -z "$${list}"; then \ - echo { 0, 0, 0, 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }} >> $@; \ - else \ - for be in $$list; do \ - echo "$${sep}PRELOAD_DEFN($$be)" >> $@; \ - sep=","; \ - done; \ - fi; \ - echo "};" >> $@ -becfg: $(BACKEND_CONFS) -.conf.in.conf: - @echo Generating $@ from $^ - @sed -e 's|@DATADIR@|$(datadir)|g' \ - -e 's|@CONFIGDIR@|$(configdir)|g' \ - -e 's|@DOCDIR@|$(docdir)|g' \ - -e 's|@LIBDIR@|$(libdir)/sane|g' \ - -e 's|@BINDIR@|$(bindir)|g' \ - -e 's|@SBINDIR@|$(sbindir)|g' \ - -e 's|@PACKAGEVERSION@|$(PACKAGE_VERSION)|g' $? > $@ - -install-data-hook: install-becfg install-firmware-path $(INSTALL_LOCKPATH) - -# Custom install target to install config files. Do not overwrite -# files that have been previously installed so that user modifications -# are not lost. -install-becfg: - @# Libtool has a bug where it will sometimes symlink the last - @# installed library in $(sanelibdir) to $(sanelibdir)/libsane.*. - @# Having two libsane's can cause issues so get rid of it. - -rm -f $(DESTDIR)$(sanelibdir)/libsane.* - test -z "$(configdir)" || $(MKDIR_P) "$(DESTDIR)$(configdir)" - test -z "$(configdir)/dll.d" || $(MKDIR_P) "$(DESTDIR)$(configdir)/dll.d" - @list="$(BACKEND_CONFS_ENABLED) saned.conf dll.conf"; for cfg in $$list; do \ - if test ! -r $${cfg}; then continue; fi; \ - if test -f $(DESTDIR)$(configdir)/$${cfg}; then \ - echo NOT overwriting $${cfg} in $(configdir)...; \ - else \ - echo installing $${cfg} in $(configdir)/$${cfg}...; \ - $(INSTALL_DATA) $${cfg} $(DESTDIR)$(configdir)/$${cfg} \ - || exit 1; \ - fi; \ - done - -install-firmware-path: - for dir in $(FIRMWARE_DIRS) ; do \ - $(mkinstalldirs) $(DESTDIR)$(datadir)/sane/$${dir} ; \ - done - -install-lockpath: - $(mkinstalldirs) -m 775 $(DESTDIR)$(locksanedir) - -uninstall-hook: - rm -rf $(DESTDIR)$(libdir)/sane $(DESTDIR)$(configdir) $(DESTDIR)$(locksanedir) - rm -f $(DESTDIR)$(libdir)/libsane.* - -for dir in $(FIRMWARE_DIRS) ; do \ - rmdir $(DESTDIR)$(datadir)/sane/$${dir} ; \ - done -clean-local: - find . -type l -name \*-s.c | xargs rm -f - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/backend/abaton.c b/backend/abaton.c index 4008c62..3e487aa 100644 --- a/backend/abaton.c +++ b/backend/abaton.c @@ -322,7 +322,7 @@ set_window (Abaton_Scanner * s) uint8_t cmd[10 + 40]; uint8_t *window = cmd + 10 + 8; int invert; - + memset (cmd, 0, sizeof (cmd)); cmd[0] = SET_WINDOW; cmd[8] = 40; @@ -379,11 +379,11 @@ set_window (Abaton_Scanner * s) s->val[OPT_HALFTONE_PATTERN].s); return SANE_STATUS_INVAL; } - + /* We have to invert these ones for some reason, so why not let the scanner do it for us... */ STORE8 (window + 21, invert ? 0x80 : 0); - + STORE16 (window + 22, (s->val[OPT_MIRROR].w != 0)); return sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), 0, 0); @@ -511,7 +511,7 @@ calc_parameters (Abaton_Scanner * s) SANE_Int dpix = s->val[OPT_X_RESOLUTION].w; SANE_Int dpiy = s->val[OPT_Y_RESOLUTION].w; double ulx, uly, width, height; - + DBG (FLOW_CONTROL, "Entering calc_parameters\n"); if (!strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) || !strcmp (val, SANE_VALUE_SCAN_MODE_HALFTONE)) @@ -549,7 +549,7 @@ calc_parameters (Abaton_Scanner * s) s->ULy = uly * dpiy; s->Width = width * dpix; s->Height = height * dpiy; - + DBG (VARIABLE_CONTROL, "(pixels) ulx: %d, uly: %d, width: %d, height: %d\n", s->ULx, s->ULy, s->Width, s->Height); @@ -653,7 +653,7 @@ init_options (Abaton_Scanner * s) s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; - + /* "Mode" group: */ s->opt[OPT_MODE_GROUP].title = "Scan Mode"; s->opt[OPT_MODE_GROUP].desc = ""; @@ -662,7 +662,7 @@ init_options (Abaton_Scanner * s) s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; mode_list[0]=SANE_VALUE_SCAN_MODE_LINEART; - + switch (s->hw->ScannerModel) { case ABATON_300GS: @@ -676,7 +676,7 @@ init_options (Abaton_Scanner * s) mode_list[1]=NULL; break; } - + /* scan mode */ s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; @@ -724,7 +724,7 @@ init_options (Abaton_Scanner * s) s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; s->val[OPT_PREVIEW].w = SANE_FALSE; - + /* halftone pattern */ s->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN; s->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN; @@ -832,7 +832,7 @@ init_options (Abaton_Scanner * s) s->opt[OPT_NEGATIVE].unit = SANE_UNIT_NONE; s->opt[OPT_NEGATIVE].constraint_type = SANE_CONSTRAINT_NONE; s->val[OPT_NEGATIVE].w = SANE_FALSE; - + /* mirror-image */ s->opt[OPT_MIRROR].name = "mirror"; s->opt[OPT_MIRROR].title = "Mirror Image"; @@ -974,7 +974,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) /* set up some universal parameters */ s->params.last_frame = SANE_TRUE; s->params.format = SANE_FRAME_GRAY; - + /* insert newly opened handle into list of open handles: */ s->next = first_handle; first_handle = s; @@ -1017,7 +1017,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if ((unsigned) option >= NUM_OPTIONS) return NULL; - + return s->opt + option; } @@ -1072,7 +1072,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_HALFTONE_PATTERN: status = sanei_constrain_value (s->opt + option, s->val[option].s, info); - strcpy (val, s->val[option].s); + strcpy (val, s->val[option].s); return SANE_STATUS_GOOD; } } @@ -1103,7 +1103,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (info) *info |= SANE_INFO_RELOAD_PARAMS; return SANE_STATUS_GOOD; - + case OPT_RESOLUTION_BIND: s->val[option].w = *(SANE_Word *) val; if (*(SANE_Word *) val) { @@ -1114,7 +1114,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_INFO_RELOAD_OPTIONS; } return SANE_STATUS_GOOD; - + case OPT_X_RESOLUTION: if (s->val[OPT_PREVIEW].w || s->val[OPT_RESOLUTION_BIND].w) { s->val[OPT_Y_RESOLUTION].w = *(SANE_Word *)val; @@ -1155,7 +1155,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, calc_parameters (s); if (info) *info |= SANE_INFO_RELOAD_PARAMS - | SANE_INFO_INEXACT; + | SANE_INFO_INEXACT; return SANE_STATUS_GOOD; /* no side-effects whatsoever */ @@ -1176,7 +1176,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, free (s->val[option].s); s->val[option].s = strdup (val); return SANE_STATUS_GOOD; - + case OPT_MODE: status = mode_update (s, val); if (status != SANE_STATUS_GOOD) @@ -1295,7 +1295,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, /* this is a sub-optimal way of doing this, I'm sure */ if (!s->scanning) return SANE_STATUS_EOF; - + if (!strcmp (s->val[OPT_MODE].s, "Gray16")) Pseudo8bit = SANE_TRUE; @@ -1352,13 +1352,13 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, { rread = data_av; } - + DBG (IO_MESSAGE, "sane_read: (action) Actual read request for %u bytes.\n", rread); size = rread; - + STORE24 (read + 6, rread); status = sanei_scsi_cmd (s->fd, read, sizeof (read), @@ -1487,7 +1487,7 @@ sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) { handle = handle; /* silence gcc */ fd = fd; /* silence gcc */ - + DBG (FLOW_CONTROL, "sane_get_select_fd: Don't call me please. " "Unimplemented function\n"); return SANE_STATUS_UNSUPPORTED; diff --git a/backend/abaton.h b/backend/abaton.h index 1f46ded..1ecd867 100644 --- a/backend/abaton.h +++ b/backend/abaton.h @@ -54,7 +54,7 @@ enum Abaton_Modes ABATON_MODE_HALFTONE, ABATON_MODE_GRAY }; - + enum Abaton_Option { OPT_NUM_OPTS = 0, @@ -66,7 +66,7 @@ enum Abaton_Option OPT_RESOLUTION_BIND, OPT_PREVIEW, OPT_HALFTONE_PATTERN, - + OPT_GEOMETRY_GROUP, OPT_TL_X, /* top-left x */ OPT_TL_Y, /* top-left y */ @@ -79,7 +79,7 @@ enum Abaton_Option OPT_THRESHOLD, OPT_NEGATIVE, OPT_MIRROR, - + /* must come last: */ NUM_OPTIONS }; @@ -110,7 +110,7 @@ typedef struct Abaton_Scanner SANE_Bool scanning; SANE_Bool AbortedByUser; - + SANE_Parameters params; /* The actual bpp, before "Pseudo-8-bit" fiddling */ diff --git a/backend/agfafocus.c b/backend/agfafocus.c index c2c5664..0b59d2d 100644 --- a/backend/agfafocus.c +++ b/backend/agfafocus.c @@ -1,7 +1,7 @@ /* sane - Scanner Access Now Easy. This file (C) 1997 Ingo Schneider - (C) 1998 Karl Anders Øygard + (C) 1998 Karl Anders Øygard This file is part of the SANE package. @@ -116,11 +116,11 @@ max_string_size (const SANE_String_Const strings[]) } /* sets loc_s bytes long value at offset loc in scsi command to value size */ -static void +static void set_size (Byte * loc, int loc_s, size_t size) { int i; - + for (i = 0; i < loc_s; i++) { loc[loc_s - i - 1] = (size >> (i * 8)) & 0xff; @@ -142,10 +142,10 @@ get_size (Byte * loc, int loc_s) return j; } -static long +static long reserve_unit (int fd) { - struct + struct { /* Command */ Byte cmd; @@ -164,10 +164,10 @@ reserve_unit (int fd) return sanei_scsi_cmd (fd, &scsi_reserve, sizeof (scsi_reserve), 0, 0); } -static long +static long release_unit (int fd) { - struct + struct { /* Command */ Byte cmd; @@ -192,7 +192,7 @@ test_ready (int fd) SANE_Status status; int try; - struct + struct { /* Command */ Byte cmd; @@ -317,7 +317,7 @@ wait_ready (int fd) Byte tr_len[3]; Byte ctrl; } cmd; - + memset (&cmd, 0, sizeof (cmd)); cmd.cmd = 0x28; /* READ */ @@ -468,7 +468,7 @@ set_window (AgfaFocus_Scanner * s) Byte tonecurve; /* Tone curve (0 - 8) */ Byte ht_pattern; /* Halftone pattern */ Byte paddingtype; /* Padding type */ - + Byte bitordering[2]; /* Bit ordering (0 = left to right) */ Byte comprtype; /* Compression type */ Byte comprarg; /* Compression argument */ @@ -522,7 +522,7 @@ set_window (AgfaFocus_Scanner * s) set_size (cmd.tr_len, 3, 36 + 8); set_size (cmd.wd_len, 2, 36); break; - + case AGFACOLOR: set_size (cmd.tr_len, 3, 65 + 8); set_size (cmd.wd_len, 2, 65); @@ -582,7 +582,7 @@ set_window (AgfaFocus_Scanner * s) cmd.wd.ht_pattern = s->halftone; else cmd.wd.ht_pattern = 3; - + cmd.wd.intensity = brightness; cmd.wd.contrast = contrast; @@ -645,20 +645,20 @@ upload_dither_matrix (AgfaFocus_Scanner * s, int rows, int cols, int *dither_mat Byte re1[3]; Byte tr_len[3]; Byte ctrl; - + struct { Byte nrrows[2]; Byte nrcols[2]; - + struct { Byte data[2]; } element[256]; } wd; } cmd; - + SANE_Status status; int i; - + memset (&cmd, 0, sizeof (cmd)); cmd.cmd = 0x2a; /* WRITE */ @@ -670,9 +670,9 @@ upload_dither_matrix (AgfaFocus_Scanner * s, int rows, int cols, int *dither_mat for (i = 0; i < cols * rows; ++i) set_size (cmd.wd.element[i].data, 2, dither_matrix[i]); - + status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0); - + if (status != SANE_STATUS_GOOD) /* Command failed */ return SANE_STATUS_IO_ERROR; @@ -692,7 +692,7 @@ upload_tonecurve (AgfaFocus_Scanner * s, int color_type, int input, int output, Byte re1[4]; Byte tr_len[3]; Byte ctrl; - + Byte re2[6]; Byte wd_len[2]; @@ -700,7 +700,7 @@ upload_tonecurve (AgfaFocus_Scanner * s, int color_type, int input, int output, Byte color_type[2]; Byte nrinput[2]; Byte nroutput[2]; - + struct { Byte data[2]; } outputval[256]; @@ -721,9 +721,9 @@ upload_tonecurve (AgfaFocus_Scanner * s, int color_type, int input, int output, for (i = 0; i < cols; ++i) for (j = 0; j < rows; ++j) set_size (cmd.wd.element[j + i * rows].data, 2, dither_matrix[j + i * rows]); - + status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), 0, 0); - + if (status != SANE_STATUS_GOOD) /* * Command failed * */ return SANE_STATUS_IO_ERROR; @@ -760,22 +760,22 @@ read_data (AgfaFocus_Scanner * s, SANE_Byte *buf, int lines, int bpl) set_size (cmd.tr_len, 3, lines); size = lines * bpl; - + status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), buf, &size); - + if (status != SANE_STATUS_GOOD) { DBG (1, "sanei_scsi_cmd() = %d\n", status); return SANE_STATUS_IO_ERROR; } - + if (size != ((unsigned int) lines * bpl)) { DBG (1, "sanei_scsi_cmd(): got %lu bytes, expected %d\n", (u_long) size, lines * bpl); return SANE_STATUS_INVAL; } - + DBG (1, "Got %lu bytes\n", (u_long) size); /* Reverse: */ @@ -788,7 +788,7 @@ read_data (AgfaFocus_Scanner * s, SANE_Byte *buf, int lines, int bpl) for (i = 0; i < size; i++) buf[i] = 255 - ((buf[i] * 256.0f) / 64.0f); } - + s->lines_available -= lines; return SANE_STATUS_GOOD; @@ -954,7 +954,7 @@ do_cancel (AgfaFocus_Scanner * s) /* ensure child knows it's time to stop: */ sanei_thread_kill (s->reader_pid); sanei_thread_waitpid (s->reader_pid, &exit_status); - s->reader_pid = -1; + sanei_thread_invalidate(s->reader_pid); } if (s->fd >= 0) @@ -980,9 +980,9 @@ init_options (AgfaFocus_Scanner * s) static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 1 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(-100), /* minimum */ + SANE_FIX(100), /* maximum */ + SANE_FIX(1) /* quantization */ }; static const SANE_Range sharpen_range = @@ -991,9 +991,9 @@ init_options (AgfaFocus_Scanner * s) {0, 100, 0}; static const SANE_Range attenuation_range = { - 0 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 1 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(0), /* minimum */ + SANE_FIX(100), /* maximum */ + SANE_FIX(1) /* quantization */ }; @@ -1182,7 +1182,7 @@ init_options (AgfaFocus_Scanner * s) s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; s->opt[OPT_CONTRAST].constraint.range = &percentage_range; s->val[OPT_CONTRAST].w = 0; - + /* halftone patterns */ s->opt[OPT_HALFTONE_PATTERN].name = SANE_NAME_HALFTONE_PATTERN; s->opt[OPT_HALFTONE_PATTERN].title = SANE_TITLE_HALFTONE_PATTERN; @@ -1324,7 +1324,7 @@ sane_exit (void) sane_close (dev->handle); free (dev); } - + if (devlist) free (devlist); } @@ -1510,16 +1510,16 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->val[option].s = strdup (val); if (strcmp (s->val[option].s, "Gray (6 bit)") == 0) - s->mode = GRAY6BIT; + s->mode = GRAY6BIT; else if (strcmp (s->val[option].s, "Gray (8 bit)") == 0) - s->mode = GRAY8BIT; + s->mode = GRAY8BIT; else if (strcmp (s->val[option].s, "Color (18 bit)") == 0) - s->mode = COLOR18BIT; + s->mode = COLOR18BIT; else if (strcmp (s->val[option].s, "Color (24 bit)") == 0) - s->mode = COLOR24BIT; + s->mode = COLOR24BIT; else s->mode = LINEART; - + switch (s->mode) { case LINEART: @@ -1679,18 +1679,18 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) case LINEART: { const char *halftone; - + s->image_composition = 0; - + /* in 1 bpp mode, lines need to be 8 pixel length */ - + if (s->params.pixels_per_line % 8) s->params.pixels_per_line += 8 - (s->params.pixels_per_line % 8); - + s->params.format = SANE_FRAME_GRAY; s->params.bytes_per_line = s->params.pixels_per_line / 8; s->bpp = s->params.depth = 1; - + halftone = s->val[OPT_HALFTONE_PATTERN].s; if (strcmp (halftone, "1") == 0 ) s->halftone = 1; @@ -1704,14 +1704,14 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) s->halftone = 5; else s->halftone = 0; - + s->edge = s->val[OPT_SHARPEN].w; } break; case GRAY6BIT: s->image_composition = 2; - + s->params.format = SANE_FRAME_GRAY; s->params.bytes_per_line = s->params.pixels_per_line; s->bpp = 6; @@ -1722,7 +1722,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) case GRAY8BIT: s->image_composition = 2; - + s->params.format = SANE_FRAME_GRAY; s->params.bytes_per_line = s->params.pixels_per_line; s->bpp = s->params.depth = 8; @@ -1760,9 +1760,9 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) if (s->mode == COLOR18BIT || s->mode == COLOR24BIT) s->params.format = SANE_FRAME_RED + s->pass; - + s->params.last_frame = (s->params.format != SANE_FRAME_RED && s->params.format != SANE_FRAME_GREEN); - + if (params) *params = s->params; return SANE_STATUS_GOOD; @@ -1856,23 +1856,23 @@ reader_process (void *scanner) { /* No lines in scanner? Scan some more */ status = request_more_data (s); - + if (status != SANE_STATUS_GOOD) { close (fd); return 1; } } - + /* We only request as many lines as there are already scanned */ if (lines > s->lines_available) lines = s->lines_available; DBG (1, "Requesting %d lines, in scanner: %d, total: %d\n", lines, s->lines_available, s->params.lines); - + status = read_data (s, data, lines, bytes_per_line); - + if (status != SANE_STATUS_GOOD) { DBG (1, "sane_read: read_data() failed (%s)\n", @@ -1881,10 +1881,10 @@ reader_process (void *scanner) close (fd); return 1; } - + /* Sometimes the scanner will return more bytes per line than requested, so we copy only what we wanted. */ - + for (i = 0; i < lines; i++) if (write (fd, data + i * bytes_per_line, s->params.bytes_per_line) != s->params.bytes_per_line) { @@ -1895,7 +1895,7 @@ reader_process (void *scanner) lines_read += lines; } - + close (fd); return 0; } @@ -1906,14 +1906,14 @@ sane_start (SANE_Handle handle) AgfaFocus_Scanner *s = handle; SANE_Status status; int fds[2]; - + /* First make sure we have a current parameter set. Some of the parameters will be overwritten below, but that's OK. */ - + status = sane_get_parameters (s, 0); if (status != SANE_STATUS_GOOD) return status; - + /* don't initialise scanner if we're doing a three-pass scan */ if (s->pass == 0) @@ -1966,10 +1966,10 @@ sane_start (SANE_Handle handle) 42, 26, 38, 22, 43, 27, 39, 23, 4, 58, 14, 54, 1, 59, 15, 55, 36, 20, 46, 30, 33, 17, 47, 31, - 12, 52, 8, 62, 9, 49, 5, 63, + 12, 52, 8, 62, 9, 49, 5, 63, 44, 28, 40, 24, 41, 25, 37, 21 }; - + status = upload_dither_matrix (s, 8, 8, matrix); if (status != SANE_STATUS_GOOD) { @@ -2030,7 +2030,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, if (!s->scanning) return do_cancel (s); - + if (nread < 0) { if (errno == EAGAIN) { return SANE_STATUS_GOOD; diff --git a/backend/agfafocus.conf.in b/backend/agfafocus.conf.in index 2648863..caa0783 100644 --- a/backend/agfafocus.conf.in +++ b/backend/agfafocus.conf.in @@ -1,2 +1 @@ /dev/scanner - diff --git a/backend/agfafocus.h b/backend/agfafocus.h index 078b68e..036a656 100644 --- a/backend/agfafocus.h +++ b/backend/agfafocus.h @@ -1,7 +1,7 @@ /* sane - Scanner Access Now Easy. This file (C) 1997 Ingo Schneider - (C) 1998 Karl Anders Øygard + (C) 1998 Karl Anders Øygard This file is part of the SANE package. @@ -27,7 +27,7 @@ enum AgfaFocus_Scanner_Type AGFAGRAY64, AGFALINEART, AGFAGRAY256, - AGFACOLOR + AGFACOLOR }; typedef enum diff --git a/backend/apple.c b/backend/apple.c index 487d743..167f6ea 100644 --- a/backend/apple.c +++ b/backend/apple.c @@ -227,14 +227,14 @@ static const uint8_t test_unit_ready[] = #if 0 -SANE_Int +SANE_Int xqstep (unsigned int Xres, unsigned int bpp) { return (SANE_Int) ((double) (8 * 1200)) / ((double) (Xres * bpp)); } -SANE_Int +SANE_Int yqstep (unsigned int Yres, unsigned int bpp) { return (SANE_Int) ((double) (1200)) / ((double) (Yres)); @@ -246,7 +246,7 @@ yqstep (unsigned int Yres, unsigned int bpp) /* The functions below return the quantized value of x,y in scanners dots aka 1/1200 of an inch */ -static SANE_Int +static SANE_Int xquant (double x, unsigned int Xres, unsigned int bpp, int dir) { double tmp; @@ -264,7 +264,7 @@ xquant (double x, unsigned int Xres, unsigned int bpp, int dir) -static SANE_Int +static SANE_Int yquant (double y, unsigned int Yres, int dir) { double tmp; @@ -986,7 +986,7 @@ calc_parameters (Apple_Scanner * s) s->ulx, s->uly, s->wx, s->wy); -/* +/* TODO: Remove this ugly hack (Protect). Read to learn why! @@ -1168,7 +1168,7 @@ mode_update (SANE_Handle handle, char *val) DISABLE (OPT_HALFTONE_PATTERN); if (s->hw->ScannerModel == COLORONESCANNER) ENABLE(OPT_COLOR_SENSOR); - + } /* End of Gray */ else if (!strcmp (val, "BiColor")) { @@ -1215,7 +1215,7 @@ mode_update (SANE_Handle handle, char *val) { DISABLE (OPT_THRESHOLD); DISABLE (OPT_AUTOBACKGROUND_THRESHOLD); - + if (s->hw->ScannerModel == COLORONESCANNER) { ENABLE (OPT_VOLT_REF); @@ -1302,7 +1302,7 @@ init_options (Apple_Scanner * s) s->opt[OPT_HWDETECT_GROUP].type = SANE_TYPE_GROUP; s->opt[OPT_HWDETECT_GROUP].cap = 0; s->opt[OPT_HWDETECT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - + s->opt[OPT_MODEL].name = "model"; s->opt[OPT_MODEL].title = "Model"; s->opt[OPT_MODEL].desc = "Model and capabilities"; @@ -1325,7 +1325,7 @@ init_options (Apple_Scanner * s) halftone_pattern_list[1]="bayer4x4"; halftone_pattern_list[2]="download"; halftone_pattern_list[3]=NULL; - + switch (s->hw->ScannerModel) { @@ -1515,7 +1515,7 @@ init_options (Apple_Scanner * s) s->opt[OPT_AUTOBACKGROUND_THRESHOLD].constraint.range = &byte_range; s->val[OPT_AUTOBACKGROUND_THRESHOLD].w = 64; - + /* AppleScanner & OneScanner options */ /* Select HalfTone Pattern */ @@ -2440,7 +2440,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, #ifdef RESERVE_RELEASE_HACK uint8_t reserve[6]; uint8_t release[6]; -#endif +#endif uint8_t result[12]; size_t size; @@ -2457,7 +2457,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, #else *len = 0; if (!s->scanning) return SANE_STATUS_EOF; - + if (!strcmp (s->val[OPT_MODE].s, "Gray16")) Pseudo8bit = SANE_TRUE; @@ -2493,7 +2493,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, release[1]|=SETTHIRDPARTY; #endif - + do { size = sizeof (result); diff --git a/backend/apple.h b/backend/apple.h index 9e14434..b4a0c03 100644 --- a/backend/apple.h +++ b/backend/apple.h @@ -91,7 +91,7 @@ enum Apple_Modes EMPTY_DONT_USE_IT, APPLE_MODE_COLOR }; - + enum Apple_Option { OPT_NUM_OPTS = 0, @@ -116,7 +116,7 @@ enum Apple_Option OPT_BRIGHTNESS, OPT_CONTRAST, OPT_THRESHOLD, - + /* AppleScanner only */ OPT_GRAYMAP, OPT_AUTOBACKGROUND, @@ -147,7 +147,7 @@ enum Apple_Option /* OneScanner && ColorOneScanner */ OPT_LED, OPT_CCD, - + /* ColorOneScanner only */ OPT_MTF_CIRCUIT, @@ -255,7 +255,7 @@ TODO: Initialize this beasts with malloc instead of statically allocation. SANE_Bool scanning; SANE_Bool AbortedByUser; - + int pass; /* pass number */ SANE_Parameters params; diff --git a/backend/artec.c b/backend/artec.c index 2d564a5..2ba8d6d 100644 --- a/backend/artec.c +++ b/backend/artec.c @@ -1715,7 +1715,7 @@ artec_get_cap_data (ARTEC_Device * dev, int fd) DBG (7, "artec_get_cap_data()\n"); - /* DB always use the hard-coded capability info first + /* DB always use the hard-coded capability info first * if we get cap data from the scanner, we override */ cap_model = -1; for (loop = 0; loop < NELEMS (cap_data); loop++) diff --git a/backend/artec.conf.in b/backend/artec.conf.in index 371a174..8b13880 100644 --- a/backend/artec.conf.in +++ b/backend/artec.conf.in @@ -1,3 +1,2 @@ scsi ULTIMA /dev/scanner - diff --git a/backend/artec_eplus48u.c b/backend/artec_eplus48u.c index f31bf5c..0e81b06 100644 --- a/backend/artec_eplus48u.c +++ b/backend/artec_eplus48u.c @@ -3505,7 +3505,7 @@ do_cancel (Artec48U_Scanner * s, SANE_Bool closepipe) { XDBG ((1, "sanei_thread_waitpid() failed !\n")); } - s->reader_pid = -1; + sanei_thread_invalidate (s->reader_pid); XDBG ((1, "reader_process killed\n")); } if (SANE_TRUE == closepipe) @@ -4337,7 +4337,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, if (s->eof == SANE_TRUE) { sanei_thread_waitpid (s->reader_pid, 0); - s->reader_pid = -1; + sanei_thread_invalidate (s->reader_pid); artec48u_scanner_stop_scan (s); artec48u_carriage_home (s->dev); return close_pipe (s); diff --git a/backend/artec_eplus48u.conf.in b/backend/artec_eplus48u.conf.in index 0b20c6e..03c9b57 100644 --- a/backend/artec_eplus48u.conf.in +++ b/backend/artec_eplus48u.conf.in @@ -116,4 +116,3 @@ usb 0x05d8 0x4011 option artecFirmwareFile @DATADIR@/sane/artec_eplus48u/Artec48.usb option vendorString "Yakumo" option modelString "Scan50" - diff --git a/backend/as6e.c b/backend/as6e.c index 76241fb..37a6d3b 100644 --- a/backend/as6e.c +++ b/backend/as6e.c @@ -799,7 +799,7 @@ check_for_driver (const char *devname) char *path; char fullname[NAMESIZE]; char dir[NAMESIZE]; - int count = 0, offset = 0; + int count = 0, offset = 0, valid; path = getenv ("PATH"); if (!path) @@ -808,21 +808,29 @@ check_for_driver (const char *devname) { memset (fullname, '\0', sizeof (fullname)); memset (dir, '\0', sizeof (dir)); + valid = 1; while ((path[count] != ':') && (path[count] != '\0')) { - dir[count - offset] = path[count]; + /* prevent writing data, which are out of bounds */ + if ((unsigned int)(count - offset) < sizeof (dir)) + dir[count - offset] = path[count]; + else + valid = 0; count++; } - /* use sizeof(fullname)-1 to make sure there is at least one padded null byte */ - strncpy (fullname, dir, sizeof(fullname)-1); - /* take into account that fullname already contains non-null bytes */ - strncat (fullname, "/", sizeof(fullname)-strlen(fullname)-1); - strncat (fullname, devname, sizeof(fullname)-strlen(fullname)-1); - if (!stat (fullname, &statbuf)) + if (valid == 1) { - modes = statbuf.st_mode; - if (S_ISREG (modes)) - return (1); /* found as6edriver */ + /* use sizeof(fullname)-1 to make sure there is at least one padded null byte */ + strncpy (fullname, dir, sizeof(fullname)-1); + /* take into account that fullname already contains non-null bytes */ + strncat (fullname, "/", sizeof(fullname)-strlen(fullname)-1); + strncat (fullname, devname, sizeof(fullname)-strlen(fullname)-1); + if (!stat (fullname, &statbuf)) + { + modes = statbuf.st_mode; + if (S_ISREG (modes)) + return (1); /* found as6edriver */ + } } if (path[count] == '\0') return (0); /* end of path --no driver found */ diff --git a/backend/avision.c b/backend/avision.c index 61491a2..e9f0145 100644 --- a/backend/avision.c +++ b/backend/avision.c @@ -44,7 +44,7 @@ 74xx, Minolta FS-V1 ...) or Fujitsu ScanPartner with the AVISION SCSI-2/3 or USB command set and written by René Rebe and Meino Cramer. - + Copyright 2002 - 2015 by "Ren Rebe" @@ -54,7 +54,7 @@ Copyright 2002 by "Jose Paulo Moitinho de Almeida" - + Copyright 2010, 2011 by "Mike Kelly" @@ -73,7 +73,7 @@ OS/2 threading support "Falk Rohsiepe" Spelling and whitespace as well as HP5370 quirks - + Many additional special thanks to: Avision INC for providing protocol documentation. Avision INC for sponsoring an AV 8000S with ADF. @@ -90,7 +90,7 @@ Thanks to all the people and companies above. Without you the Avision backend would not be in the shape it is today! ;-) - + ********************************************************************************/ /* SANE-FLOW-DIAGRAMM (from umax.c) @@ -166,13 +166,13 @@ static Avision_HWEntry Avision_Device_List [] = "Avision", "AV100CS", 0}, /* status="untested" */ - + { "AVISION", "AV100IIICS", 0, 0, "Avision", "AV100IIICS", 0}, /* status="untested" */ - + { "AVISION", "AV100S", 0, 0, "Avision", "AV100S", @@ -199,7 +199,7 @@ static Avision_HWEntry Avision_Device_List [] = AV_INT_BUTTON | AV_2ND_LINE_INTERLACED | AV_NO_REAR | AV_SOFT_SCALE | AV_DOES_KEEP_WINDOW | AV_DOES_KEEP_GAMMA | AV_REAR_OFFSET}, /* comment="sheetfed duplex scanner" */ /* status="good" */ - + { NULL, NULL, 0x0638, 0x0A93, "Avision", "AV122 C2", @@ -213,7 +213,7 @@ static Avision_HWEntry Avision_Device_List [] = AV_INT_BUTTON | AV_ACCEL_TABLE}, /* comment="sheetfed scanner" */ /* status="complete" */ - + { NULL, NULL, 0x0638, 0x0A25, "Avision", "AV210", @@ -303,37 +303,37 @@ static Avision_HWEntry Avision_Device_List [] = "Avision", "AV240SC", 0}, /* status="untested" */ - + { "AVISION", "AV260CS", 0, 0, "Avision", "AV260CS", 0}, /* status="untested" */ - + { "AVISION", "AV360CS", 0, 0, "Avision", "AV360CS", 0}, /* status="untested" */ - + { "AVISION", "AV363CS", 0, 0, "Avision", "AV363CS", 0}, /* status="untested" */ - + { "AVISION", "AV420CS", 0, 0, "Avision", "AV420CS", 0}, /* status="untested" */ - + { "AVISION", "AV6120", 0, 0, "Avision", "AV6120", 0}, /* status="untested" */ - + { NULL, "AV610", 0x0638, 0x0a18, "Avision", "AV610", @@ -353,7 +353,7 @@ static Avision_HWEntry Avision_Device_List [] = AV_NO_BACKGROUND | AV_INT_BUTTON}, /* cancel button -> sense abort! */ /* status="good" */ - { NULL, NULL, + { NULL, NULL, 0x0638, 0x0a41, "Avision", "AM3000 Series", 0}, @@ -373,35 +373,35 @@ static Avision_HWEntry Avision_Device_List [] = 0}, /* comment="1 pass, 600 dpi" */ /* status="complete" */ - + { "AVISION", "AV620CS Plus", 0, 0, "Avision", "AV620CS Plus", 0}, /* comment="1 pass, 1200 dpi" */ /* status="complete" */ - + { "AVISION", "AV630CS", 0, 0, "Avision", "AV630CS", 0}, /* comment="1 pass, 1200 dpi" */ /* status="complete" */ - + { "AVISION", "AV630CSL", 0, 0, "Avision", "AV630CSL", 0}, /* comment="1 pass, 1200 dpi" */ /* status="untested" */ - + { "AVISION", "AV6240", 0, 0, "Avision", "AV6240", 0}, /* comment="1 pass, ??? dpi" */ /* status="complete" */ - + { NULL, NULL, 0x0638, 0x0A13, "Avision", "AV600U", @@ -422,70 +422,70 @@ static Avision_HWEntry Avision_Device_List [] = 0}, /* comment="1 pass, ??? dpi" */ /* status="untested" */ - + { "AVISION", "AV690U", 0, 0, "Avision", "AV690U", 0}, /* comment="1 pass, 2400 dpi" */ /* status="untested" */ - + { "AVISION", "AV800S", 0, 0, "Avision", "AV800S", 0}, /* comment="1 pass, ??? dpi" */ /* status="untested" */ - + { "AVISION", "AV810C", 0, 0, "Avision", "AV810C", 0}, /* comment="1 pass, ??? dpi" */ /* status="untested" */ - + { "AVISION", "AV820", 0, 0, "Avision", "AV820", 0}, /* comment="1 pass, ??? dpi" */ /* status="untested" */ - + { "AVISION", "AV820C", 0, 0, "Avision", "AV820C", 0}, /* comment="1 pass, ??? dpi" */ /* status="complete" */ - + { "AVISION", "AV820C Plus", 0, 0, "Avision", "AV820C Plus", 0}, /* comment="1 pass, ??? dpi" */ /* status="complete" */ - + { "AVISION", "AV830C", 0, 0, "Avision", "AV830C", 0}, /* comment="1 pass, ??? dpi" */ /* status="complete" */ - + { "AVISION", "AV830C Plus", 0, 0, "Avision", "AV830C Plus", 0}, /* comment="1 pass, ??? dpi" */ /* status="untested" */ - + { "AVISION", "AV880", 0, 0, "Avision", "AV880", 0}, /* comment="1 pass, ??? dpi" */ /* status="untested" */ - + { "AVISION", "AV880C", 0, 0, "Avision", "AV880C", @@ -613,7 +613,7 @@ static Avision_HWEntry Avision_Device_List [] = /* status="basic" */ /* and possibly more avisions ;-) */ - + { "HP", "ScanJet 5300C", 0x03f0, 0x0701, "Hewlett-Packard", "ScanJet 5300C", @@ -627,14 +627,14 @@ static Avision_HWEntry Avision_Device_List [] = AV_MULTI_CALIB_CMD | AV_INT_STATUS}, /* comment="1 pass, 2400 dpi - some FW revisions have x-axis image scaling problems over 1200 dpi" */ /* status="good" */ - + { "hp", "scanjet 7400c", 0x03f0, 0x0801, "Hewlett-Packard", "ScanJet 7400c", AV_LIGHT_CHECK_BOGUS | AV_NO_64BYTE_ALIGN | AV_INT_STATUS}, /* comment="1 pass, 2400 dpi - dual USB/SCSI interface" */ /* status="good" */ - + #ifdef FAKE_ENTRIES_FOR_DESC_GENERATION { "hp", "scanjet 7450c", 0x03f0, 0x0801, @@ -642,7 +642,7 @@ static Avision_HWEntry Avision_Device_List [] = AV_NO_64BYTE_ALIGN | AV_INT_STATUS}, /* comment="1 pass, 2400 dpi - dual USB/SCSI interface" */ /* status="good" */ - + { "hp", "scanjet 7490c", 0x03f0, 0x0801, "Hewlett-Packard", "ScanJet 7490c", @@ -681,8 +681,8 @@ static Avision_HWEntry Avision_Device_List [] = AV_ADF_FLIPPING_DUPLEX | AV_FIRMWARE}, /* comment="1 pass, 4800 (?) dpi - USB 2.0 and SCSI - only SCSI tested so far" */ /* status="good" */ - -#endif + +#endif { "HP", "C9930A", 0x03f0, 0x3805, "Hewlett-Packard", "ScanJet 8300", @@ -705,7 +705,7 @@ static Avision_HWEntry Avision_Device_List [] = /* comment="1 pass, 4800 (?) dpi - USB 2.0" */ /* status="good" */ -#endif +#endif { "Minolta", "#2882", 0, 0, "Minolta", "Dimage Scan Dual I", @@ -717,21 +717,21 @@ static Avision_HWEntry Avision_Device_List [] = "Minolta", "Scan Multi Pro", AV_FORCE_FILM | AV_NO_START_SCAN}, /* AV_FILMSCANNER (frame control)? */ /* status="untested" */ - + { "MINOLTA", "FS-V1", 0x0638, 0x026a, "Minolta", "Dimage Scan Dual II", AV_FILMSCANNER | AV_ONE_CALIB_CMD | AV_12_BIT_MODE}, /* comment="1 pass, film-scanner" */ /* status="good" */ - + { "MINOLTA", "Elite II", 0x0686, 0x4004, "Minolta", "Elite II", AV_FILMSCANNER | AV_ONE_CALIB_CMD}, /* comment="1 pass, film-scanner" */ /* status="untested" */ - + { "MINOLTA", "FS-V3", 0x0686, 0x400d, "Minolta", "Dimage Scan Dual III", @@ -759,33 +759,33 @@ static Avision_HWEntry Avision_Device_List [] = 0}, /* comment="" */ /* status="good" */ - + { "MITSBISH", "MCA-ADFC", 0, 0, "Mitsubishi", "MCA-ADFC", 0}, /* status="untested" */ - + { "MITSBISH", "MCA-S1200C", 0, 0, "Mitsubishi", "S1200C", 0}, /* status="untested" */ - + { "MITSBISH", "MCA-S600C", 0, 0, "Mitsubishi", "S600C", 0}, /* status="untested" */ - + { "MITSBISH", "SS600", 0, 0, "Mitsubishi", "SS600", 0}, /* status="good" */ - + /* The next are all untested ... */ - + { "FCPA", "ScanPartner", 0, 0, "Fujitsu", "ScanPartner", @@ -797,25 +797,25 @@ static Avision_HWEntry Avision_Device_List [] = "Fujitsu", "ScanPartner 10", AV_FUJITSU}, /* status="untested" */ - + { "FCPA", "ScanPartner 10C", 0, 0, "Fujitsu", "ScanPartner 10C", AV_FUJITSU}, /* status="untested" */ - + { "FCPA", "ScanPartner 15C", 0, 0, "Fujitsu", "ScanPartner 15C", AV_FUJITSU}, /* status="untested" */ - + { "FCPA", "ScanPartner 300C", 0, 0, "Fujitsu", "ScanPartner 300C", 0}, /* status="untested" */ - + { "FCPA", "ScanPartner 600C", 0, 0, "Fujitsu", "ScanPartner 600C", @@ -827,13 +827,13 @@ static Avision_HWEntry Avision_Device_List [] = "Fujitsu", "ScanPartner 620C", AV_LIGHT_CHECK_BOGUS}, /* status="good" */ - + { "FCPA", "ScanPartner Jr", 0, 0, "Fujitsu", "ScanPartner Jr", 0}, /* status="untested" */ - + { "FCPA", "ScanStation", 0, 0, "Fujitsu", "ScanStation", @@ -863,13 +863,13 @@ static Avision_HWEntry Avision_Device_List [] = "Kodak", "i40", AV_INT_BUTTON | AV_GRAY_MODES}, /* status="basic" */ - + { NULL, NULL, 0x040a, 0x6003, "Kodak", "i50", AV_INT_BUTTON}, /* status="untested" */ - + #ifdef FAKE_ENTRIES_FOR_DESC_GENERATION { NULL, NULL, 0x040a, 0x6003, @@ -877,13 +877,13 @@ static Avision_HWEntry Avision_Device_List [] = AV_INT_BUTTON}, /* status="untested" */ #endif - + { NULL, NULL, 0x040a, 0x6004, "Kodak", "i60", AV_INT_BUTTON}, /* status="untested" */ - + #ifdef FAKE_ENTRIES_FOR_DESC_GENERATION { NULL, NULL, 0x040a, 0x6004, @@ -891,19 +891,19 @@ static Avision_HWEntry Avision_Device_List [] = AV_INT_BUTTON}, /* status="untested" */ #endif - + { NULL, NULL, 0x040a, 0x6005, "Kodak", "i80", AV_INT_BUTTON}, - /* status="good" */ - + /* status="good" */ + { "iVina", "1200U", 0x0638, 0x0268, "iVina", "1200U", 0}, /* status="untested" */ - + { NULL, NULL, 0x04a7, 0x0424, "Visioneer", "Strobe XP 450", @@ -917,7 +917,7 @@ static Avision_HWEntry Avision_Device_List [] = AV_INT_BUTTON | AV_ACCEL_TABLE}, /* comment="sheetfed scanner" */ /* status="complete" */ - + { NULL, NULL, 0x04a7, 0x0479, "Visioneer", "Strobe XP 470", @@ -931,7 +931,7 @@ static Avision_HWEntry Avision_Device_List [] = AV_INT_BUTTON | AV_ACCEL_TABLE}, /* comment="sheetfed scanner" */ /* status="complete" */ - + { NULL, NULL, 0x04a7, 0x0420, "Visioneer", "9320", @@ -973,7 +973,7 @@ static Avision_HWEntry Avision_Device_List [] = 0}, /* comment="sheetfed scanner" */ /* status="complete" */ - + { NULL, NULL, 0x04a7, 0x0423, "Visioneer", "9750", @@ -1017,7 +1017,7 @@ static Avision_HWEntry Avision_Device_List [] = AV_INT_BUTTON}, /* comment="sheetfed scanner" */ /* status="complete" */ - + { NULL, NULL, 0x04a7, 0x049C, "Xerox", "DocuMate150", @@ -1047,7 +1047,7 @@ static Avision_HWEntry Avision_Device_List [] = "Xerox", "DocuMate250-G", AV_INT_BUTTON}, /* status="good" */ - + { NULL, NULL, 0x04a7, 0x0449, "Xerox", "DocuMate252", @@ -1059,7 +1059,7 @@ static Avision_HWEntry Avision_Device_List [] = "Xerox", "DocuMate252-G", AV_INT_BUTTON}, /* status="good" */ - + { NULL, NULL, 0x04a7, 0x0476, "Xerox", "DocuMate232", @@ -1077,7 +1077,7 @@ static Avision_HWEntry Avision_Device_List [] = "Xerox", "DocuMate262-G", AV_INT_BUTTON}, /* status="good" */ - + { NULL, NULL, 0x04a7, 0x04a7, "Xerox", "DocuMate262i", @@ -1095,7 +1095,7 @@ static Avision_HWEntry Avision_Device_List [] = "Xerox", "DocuMate272-G", AV_INT_BUTTON}, /* status="untested" */ - + { NULL, NULL, 0x04a7, 0x0446, "Xerox", "DocuMate510", @@ -1179,35 +1179,35 @@ static Avision_HWEntry Avision_Device_List [] = V6240 */ /* Possibly: -Lexmark 4600 MFP Option MFP Options -Lexmark 4600 MFP Option (C772n) MFP Options +Lexmark 4600 MFP Option MFP Options +Lexmark 4600 MFP Option (C772n) MFP Options Lexmark X215 -Lexmark Optra Image X242 +Lexmark Optra Image X242 Lexmark X443 Lexmark 3100 -Lexmark 3200 -Lexmark X340 MFP Multifunction -Lexmark X342n MFP Multifunction +Lexmark 3200 +Lexmark X340 MFP Multifunction +Lexmark X342n MFP Multifunction Lexmark X522 Lexmark X630 Lexmark X632E -Lexmark X642e MFP Multifunction -Lexmark X644e MFP Multifunction -Lexmark X646dte MFP Multifunction -Lexmark X646e MFP Multifunction -Lexmark X646ef MFP Multifunction -Lexmark X772e Multifunction -Lexmark X850e MFP Multifunction -Lexmark X852e MFP Multifunction -Lexmark X854e MFP Multifunction +Lexmark X642e MFP Multifunction +Lexmark X644e MFP Multifunction +Lexmark X646dte MFP Multifunction +Lexmark X646e MFP Multifunction +Lexmark X646ef MFP Multifunction +Lexmark X772e Multifunction +Lexmark X850e MFP Multifunction +Lexmark X852e MFP Multifunction +Lexmark X854e MFP Multifunction Lexmark X4500 MFP */ - + /* last entry detection */ { NULL, NULL, 0, 0, NULL, NULL, - 0} + 0} }; #if 0 @@ -1316,13 +1316,6 @@ static const SANE_Range percentage_range = SANE_FIX (1) /* quantization */ }; -static const SANE_Range abs_percentage_range = - { - SANE_FIX (0), /* minimum */ - SANE_FIX (100), /* maximum */ - SANE_FIX (1) /* quantization */ - }; - static const SANE_Range exposure_range = { 0, /* minimum */ @@ -1352,20 +1345,26 @@ static const uint8_t test_unit_ready[] = AVISION_SCSI_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/* Remove #ifdef and this comment when this SCSI command is used for + something. Keeping this definition around so we don't loose info + about the protocol. + */ +#ifdef ENABLE_AVISION_SCSI_GET_DATA_STATUS static const uint8_t get_status[] = { - AVISION_SCSI_GET_DATA_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, + AVISION_SCSI_GET_DATA_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00 }; +#endif static size_t max_string_size (const SANE_String_Const strings[]) { size_t size, max_size = 0; int i; - + DBG (3, "max_string_size:\n"); - + for (i = 0; strings[i]; ++ i) { size = strlen (strings[i]) + 1; if (size > max_size) @@ -1386,7 +1385,7 @@ static void debug_print_raw (int dbg_level, char* info, const uint8_t* data, size_t count) { size_t i; - + DBG (dbg_level, "%s", info); for (i = 0; i < count; ++ i) { DBG (dbg_level, " [%lu] %1d%1d%1d%1d%1d%1d%1d%1db %3oo %3dd %2xx\n", @@ -1412,7 +1411,7 @@ static void debug_print_hex_raw (int dbg_level, char* info, const uint8_t* data, count--; i++; } *--t = 0; - + DBG (dbg_level, " [%08x] %s\n", address, text); address += 16; } @@ -1429,7 +1428,7 @@ static void debug_print_nvram_data (int dbg_level, char* func, func, get_quad(nvram->adf_duplex_scans)); DBG (dbg_level, "%s: flatbed scans: %d\n", func, get_quad(nvram->flatbed_scans)); - + DBG (dbg_level, "%s: flatbed leading edge: %d\n", func, (int16_t)get_double(nvram->flatbed_leading_edge)); DBG (dbg_level, "%s: flatbed side edge: %d\n", @@ -1442,7 +1441,7 @@ static void debug_print_nvram_data (int dbg_level, char* func, func, (int16_t)get_double(nvram->adf_rear_leading_edge)); DBG (dbg_level, "%s: ADF rear side edge: %d\n", func, (int16_t)get_double(nvram->adf_rear_side_edge)); - + DBG (dbg_level, "%s: born month: %d\n", func, get_double(nvram->born_month)); DBG (dbg_level, "%s: born day: %d\n", @@ -1456,7 +1455,7 @@ static void debug_print_nvram_data (int dbg_level, char* func, func, get_double(nvram->first_scan_day)); DBG (dbg_level, "%s: first scan year: %d\n", func, get_double(nvram->first_scan_year)); - + DBG (dbg_level, "%s: vert. magnification: %d\n", func, get_double(nvram->vertical_magnification)); @@ -1467,10 +1466,10 @@ static void debug_print_nvram_data (int dbg_level, char* func, func, nvram->ccd_type); DBG (dbg_level, "%s: scan speed: %d\n", func, nvram->scan_speed); - + DBG (dbg_level, "%s: serial: '%.24s'\n", /* 24 chars max */ func, nvram->serial); - + DBG (dbg_level, "%s: power saving time: %d\n", func, get_double(nvram->power_saving_time)); @@ -1495,11 +1494,11 @@ static void debug_print_avdimen (int dbg_level, char* func, { DBG (dbg_level, "%s: hw_xres: %d, hw_yres: %d, line_difference: %d\n", func, avdimen->hw_xres, avdimen->hw_yres, avdimen->line_difference); - + DBG (dbg_level, "%s: tlx: %ld, tly: %ld, brx: %ld, bry: %ld\n", func, avdimen->tlx, avdimen->tly, avdimen->brx, avdimen->bry); - + DBG (dbg_level, "%s: hw_pixel_per_line: %d, hw_lines: %d, hw_bytes_per_line: %d\n", func, avdimen->hw_pixels_per_line, avdimen->hw_lines, avdimen->hw_bytes_per_line); @@ -1520,18 +1519,18 @@ static void debug_print_calib_format (int dbg_level, char* func, uint8_t* result) { debug_print_raw (dbg_level + 2, "debug_print_calib_format:\n", result, 32); - + DBG (dbg_level, "%s: [0-1] pixels per line: %d\n", func, get_double ( &(result[0]) )); DBG (dbg_level, "%s: [2] bytes per channel: %d\n", func, result[2]); DBG (dbg_level, "%s: [3] line count: %d\n", func, result[3]); - + DBG (dbg_level, "%s: [4] FLAG:%s%s%s\n", func, result[4] == 1?" MUST_DO_CALIBRATION":"", result[4] == 2?" SCAN_IMAGE_DOES_CALIBRATION":"", result[4] == 3?" NEEDS_NO_CALIBRATION":""); - + DBG (dbg_level, "%s: [5] Ability1:%s%s%s%s%s%s%s%s\n", func, BIT(result[5],7)?" NONE_PACKED":" PACKED", @@ -1542,18 +1541,18 @@ static void debug_print_calib_format (int dbg_level, char* func, BIT(result[5],2)?" DARK_CALIB":"", BIT(result[5],1)?" NEEDS_WHITE_BLACK_SHADING_DATA":"", BIT(result[5],0)?" NEEDS_CALIB_TABLE_CHANNEL_BY_CHANNEL":""); - + DBG (dbg_level, "%s: [6] R gain: %d\n", func, result[6]); DBG (dbg_level, "%s: [7] G gain: %d\n", func, result[7]); DBG (dbg_level, "%s: [8] B gain: %d\n", func, result[8]); - + DBG (dbg_level, "%s: [9-10] R shading target: %x\n", func, get_double ( &(result[9]) ) ); DBG (dbg_level, "%s: [11-12] G shading target: %x\n", func, get_double ( &(result[11]) ) ); DBG (dbg_level, "%s: [13-14] B shading target: %x\n", func, get_double ( &(result[13]) ) ); - + DBG (dbg_level, "%s: [15-16] R dark shading target: %x\n", func, get_double ( &(result[15]) ) ); DBG (dbg_level, "%s: [17-18] G dark shading target: %x\n", @@ -1564,7 +1563,7 @@ static void debug_print_calib_format (int dbg_level, char* func, DBG (dbg_level, "%s: [21] true-gray gain: %d\n", func, result[21]); DBG (dbg_level, "%s: [22-23] true-gray shading target: %x\n", func, get_double ( &(result[22]) ) ); - + DBG (dbg_level, "%s: [24-25] true-gray dark shading target: %x\n", func, get_double ( &(result[24]) ) ); } @@ -1573,7 +1572,7 @@ static void debug_print_accel_info (int dbg_level, char* func, uint8_t* result) { debug_print_raw (dbg_level + 2, "debug_print_accel_info:\n", result, 24); - + DBG (dbg_level, "%s: [0-1] acceleration step count: %d\n", func, get_double ( &(result[0]) )); DBG (dbg_level, "%s: [2-3] stable step count: %d\n", @@ -1591,7 +1590,7 @@ static void debug_print_accel_info (int dbg_level, char* func, BIT(result[16],0)?" TWO_BYTES_PER_ELEM":" SINGLE_BYTE_PER_ELEM", BIT(result[16],1)?" LOW_HIGH_ORDER":" HIGH_LOW_ORDER"); DBG (dbg_level, "%s: [17] table count: %d\n", func, result[17]); - + } static void debug_print_window_descriptor (int dbg_level, char* func, @@ -1605,7 +1604,7 @@ static void debug_print_window_descriptor (int dbg_level, char* func, (uint8_t*)(&window->descriptor), sizeof(*window) - sizeof(window->header)); - + DBG (dbg_level, "%s: [0] window_id: %d\n", func, window->descriptor.winid); DBG (dbg_level, "%s: [2-3] x-axis res: %d\n", func, @@ -1618,7 +1617,7 @@ static void debug_print_window_descriptor (int dbg_level, char* func, func, get_quad (window->descriptor.uly)); DBG (dbg_level, "%s: [14-17] window width: %d\n", func, get_quad (window->descriptor.width)); - DBG (dbg_level, "%s: [18-21] window length: %d\n", func, + DBG (dbg_level, "%s: [18-21] window length: %d\n", func, get_quad (window->descriptor.length)); DBG (dbg_level, "%s: [22] brightness: %d\n", func, window->descriptor.brightness); @@ -1660,14 +1659,14 @@ static void debug_print_window_descriptor (int dbg_level, char* func, window->avision.type.normal.bitset2); DBG (dbg_level, "%s: [50] ir exposure time: %x\n", func, window->avision.type.normal.ir_exposure_time); - + DBG (dbg_level, "%s: [51-52] r exposure: %x\n", func, get_double (window->avision.type.normal.r_exposure_time)); DBG (dbg_level, "%s: [53-54] g exposure: %x\n", func, get_double (window->avision.type.normal.g_exposure_time)); DBG (dbg_level, "%s: [55-56] b exposure: %x\n", func, get_double (window->avision.type.normal.b_exposure_time)); - + DBG (dbg_level, "%s: [57] bitset3: %x\n", func, window->avision.type.normal.bitset3); DBG (dbg_level, "%s: [58] auto focus: %d\n", func, @@ -1685,7 +1684,7 @@ static int write_pnm_header (FILE* f, color_mode m, int depth, int width, int he int maxval = (1 << depth) - 1; const char* hdr_str = NULL; /* construct PNM header */ - + switch (m) { case AV_THRESHOLDED: case AV_DITHERED: @@ -1704,7 +1703,7 @@ static int write_pnm_header (FILE* f, color_mode m, int depth, int width, int he case AV_COLOR_MODE_LAST: ; /* silence compiler warning */ } - + return fprintf (f, hdr_str, width, height, maxval); } @@ -1712,19 +1711,19 @@ static SANE_Status sense_handler (int fd, u_char* sense, void* arg) { SANE_Status status = SANE_STATUS_IO_ERROR; /* default case */ - + char* text; char textbuf[64]; - + uint8_t error_code = sense[0] & 0x7f; uint8_t sense_key = sense[2] & 0xf; uint8_t additional_sense = sense[7]; - + fd = fd; /* silence gcc */ arg = arg; /* silence gcc */ - + DBG (3, "sense_handler:\n"); - + switch (error_code) { case 0x70: @@ -1736,15 +1735,15 @@ sense_handler (int fd, u_char* sense, void* arg) default: text = "unknown sense"; } - + debug_print_raw (1, "sense_handler: data:\n", sense, 8 + additional_sense); - + /* request valid? */ if (! (sense[0] & (1<<7))) { DBG (1, "sense_handler: sense not valid ...\n"); return status; } - + switch (sense_key) { case 0x00: @@ -1778,26 +1777,26 @@ sense_handler (int fd, u_char* sense, void* arg) sprintf (textbuf, "got unknown sense code 0x%02x", (int)sense_key); text = textbuf; } - + DBG (1, "sense_handler: sense code: %s\n", text); - + if (sense[2] & (1<<6)) - DBG (1, "sense_handler: end of scan\n"); - else + DBG (1, "sense_handler: end of scan\n"); + else DBG (1, "sense_handler: scan has not yet been completed\n"); - + if (sense[2] & (1<<5)) DBG (1, "sense_handler: incorrect logical length\n"); - else + else DBG (1, "sense_handler: correct logical length\n"); - { + { uint8_t asc = sense[12]; uint8_t ascq = sense[13]; - + #define ADDITIONAL_SENSE(asc,ascq,txt) \ case ( (asc << 8) + ascq): text = txt; break - + switch ( (asc << 8) + ascq ) { /* normal */ @@ -1808,9 +1807,9 @@ sense_handler (int fd, u_char* sense, void* arg) ADDITIONAL_SENSE (0x15,0x02, "Flatbed Home Sensor Error (OKI only"); ADDITIONAL_SENSE (0x15,0x03, "ADF Home Sensor Error (OKI only)"); ADDITIONAL_SENSE (0x15,0x04, "Lock Error (OKI only)"); - + ADDITIONAL_SENSE (0x1a,0x00, "parameter list length error"); - + ADDITIONAL_SENSE (0x20,0x00, "Invalid command"); ADDITIONAL_SENSE (0x24,0x00, "Invalid field in CDB"); ADDITIONAL_SENSE (0x25,0x00, "Logical unit not supported"); @@ -1822,7 +1821,7 @@ sense_handler (int fd, u_char* sense, void* arg) ADDITIONAL_SENSE (0x2f,0x00, "Command cleared by another initiator"); ADDITIONAL_SENSE (0x3D,0x00, "Invalid Bit in Identify Message"); - + ADDITIONAL_SENSE (0x43,0x00, "Message error"); ADDITIONAL_SENSE (0x44,0x00, "Internal target failure"); ADDITIONAL_SENSE (0x44,0x01, "Flatbed DRAM Error(OKI only)"); @@ -1830,12 +1829,12 @@ sense_handler (int fd, u_char* sense, void* arg) ADDITIONAL_SENSE (0x44,0x03, "Write NVRAM Error"); ADDITIONAL_SENSE (0x47,0x00, "SCSI parity error"); ADDITIONAL_SENSE (0x49,0x00, "Invalid message error"); - + ADDITIONAL_SENSE (0x60,0x00, "Lamp failure"); ADDITIONAL_SENSE (0x60,0x01, "Flatbed Lamp error (Oki only)"); ADDITIONAL_SENSE (0x60,0x02, "ADF lamp error (Oki only)"); ADDITIONAL_SENSE (0x62,0x00, "Scan head positioning error"); - + ADDITIONAL_SENSE (0x80,0x01, "ADF paper jam"; status = SANE_STATUS_JAMMED); ADDITIONAL_SENSE (0x80,0x02, "ADF cover open"; status = SANE_STATUS_COVER_OPEN); ADDITIONAL_SENSE (0x80,0x03, "ADF chute empty"; status = SANE_STATUS_NO_DOCS); @@ -1848,7 +1847,7 @@ sense_handler (int fd, u_char* sense, void* arg) ADDITIONAL_SENSE (0x80,0x0A, "ADF Paper Start"); ADDITIONAL_SENSE (0x80,0x0B, "Multiple ADF paper End and Start"); ADDITIONAL_SENSE (0x80,0x0C, "Multiple ADF paper End"); - + /* film scanner */ ADDITIONAL_SENSE (0x81,0x00, "ADF/MFP front door open"; status = SANE_STATUS_COVER_OPEN); ADDITIONAL_SENSE (0x81,0x01, "ADF holder cartridge open"; status = SANE_STATUS_COVER_OPEN); @@ -1861,19 +1860,19 @@ sense_handler (int fd, u_char* sense, void* arg) ADDITIONAL_SENSE (0x81,0x08, "ADF adapter error"); ADDITIONAL_SENSE (0xA0,0x01, "Filter Positioning Error"); - + ADDITIONAL_SENSE (0x90,0x00, "Scanner busy (FW busy)"); - + default: sprintf (textbuf, "Unknown sense code asc: 0x%02x, ascq: 0x%02x", (int)asc, (int)ascq); text = textbuf; } - + #undef ADDITIONAL_SENSE - + DBG (1, "sense_handler: sense code: %s\n", text); - + /* sense code specific for invalid request * it is possible to get a detailed error location here ;-)*/ if (sense_key == 0x05) { @@ -1883,10 +1882,10 @@ sense_handler (int fd, u_char* sense, void* arg) DBG (1, "sense_handler: error in command parameter\n"); else DBG (1, "sense_handler: error in data parameter\n"); - + DBG (1, "sense_handler: error in parameter byte: %d, %x\n", get_double(&(sense[16])), get_double(&(sense[16]))); - + /* bit pointer valid ?*/ if (sense[15] & (1<<3) ) DBG (1, "sense_handler: error in command parameter\n"); @@ -1895,7 +1894,7 @@ sense_handler (int fd, u_char* sense, void* arg) } } } - + return status; } @@ -1912,7 +1911,7 @@ avision_usb_status (Avision_Connection* av_con, int retry, int timeout) int t_retry = retry; #define valid_status(status,a) (status == SANE_STATUS_GOOD ? a : 0) - + DBG (4, "avision_usb_status: timeout %d, %d retries\n", timeout, retry); #ifndef HAVE_SANEI_USB_SET_TIMEOUT #error "You must update include/sane/sanei_usb.h and sanei/sanei_usb.c accordingly!" @@ -1928,7 +1927,7 @@ avision_usb_status (Avision_Connection* av_con, int retry, int timeout) --retry) { count = sizeof (usb_status); - + DBG (5, "==> (bulk read) going down ...\n"); status = sanei_usb_read_bulk (av_con->usb_dn, usb_status, &count); @@ -1939,10 +1938,10 @@ avision_usb_status (Avision_Connection* av_con, int retry, int timeout) av_con->usb_status = AVISION_USB_BULK_STATUS; } } - + /* reset retry count ... */ retry = t_retry; - + /* 2nd try interrupt status read - if not yet disabled */ for (; count == 0 && @@ -1952,23 +1951,23 @@ avision_usb_status (Avision_Connection* av_con, int retry, int timeout) --retry) { count = sizeof (usb_status); - + DBG (5, "==> (interrupt read) going down ...\n"); status = sanei_usb_read_int (av_con->usb_dn, usb_status, &count); DBG (5, "<== (interrupt read) got: %ld, status: %d\n", (u_long)count, valid_status(status, usb_status[0])); - + if (count > 0) av_con->usb_status = AVISION_USB_INT_STATUS; - } - + } + if (status != SANE_STATUS_GOOD) return status; - + if (count == 0) return SANE_STATUS_IO_ERROR; - + /* 0 = ok, 2 => request sense, 8 ==> busy, else error */ switch (usb_status[0]) { @@ -2051,7 +2050,7 @@ static SANE_Status avision_cmd (Avision_Connection* av_con, } else { SANE_Status status = SANE_STATUS_GOOD; - + size_t i, count, out_count; /* some commands on some devices need a rather long time to respond */ #define STD_TIMEOUT 30000 @@ -2065,11 +2064,11 @@ static SANE_Status avision_cmd (Avision_Connection* av_con, const uint8_t* m_cmd = (const uint8_t*)cmd; const uint8_t* m_src = (const uint8_t*)src; uint8_t* m_dst = (uint8_t*)dst; - + /* may I vote for the possibility to use C99 ... */ #define min_usb_size 10 #define max_usb_size 256 * 1024 /* or 0x10000, used by AV Windows driver during background raster read, ... ? */ - + /* 1st send command data - at least 10 Bytes for USB scanners */ uint8_t enlarged_cmd [min_usb_size]; if (cmd_size < min_usb_size) { @@ -2106,12 +2105,12 @@ write_usb_cmd: sanei_usb_set_timeout (write_timeout); DBG (8, "try to write cmd, count: %lu.\n", (u_long) count); status = sanei_usb_write_bulk (av_con->usb_dn, m_cmd, &count); - + DBG (8, "wrote %lu bytes\n", (u_long) count); if (status != SANE_STATUS_GOOD || count != cmd_size) { DBG (3, "=== Got error %d trying to write, wrote: %ld. ===\n", status, (long)count); - + if (status != SANE_STATUS_GOOD) /* == SANE_STATUS_EOF) */ { DBG (3, "try to read status to clear the FIFO\n"); status = avision_usb_status (av_con, 1, 500); @@ -2125,21 +2124,21 @@ write_usb_cmd: DBG (3, "Retrying to send command\n"); goto write_usb_cmd; } - + return SANE_STATUS_IO_ERROR; } - + /* 2nd send command data (if any) */ for (i = 0; i < src_size; ) { - + count = src_size - i; /* if (count > max_usb_size) count = max_usb_size; */ - + DBG (8, "try to write src, count: %lu.\n", (u_long) count); sanei_usb_set_timeout (write_timeout); status = sanei_usb_write_bulk (av_con->usb_dn, &(m_src[i]), &count); - + DBG (8, "wrote %lu bytes\n", (u_long) count); if (status == SANE_STATUS_GOOD) { i += count; @@ -2155,7 +2154,7 @@ write_usb_cmd: sanei_usb_set_timeout (read_timeout); while (out_count < *dst_size) { count = (*dst_size - out_count); - + DBG (8, "try to read %lu bytes\n", (u_long) count); status = sanei_usb_read_bulk(av_con->usb_dn, &(m_dst[out_count]), &count); @@ -2174,7 +2173,7 @@ write_usb_cmd: } } } - + /* last: read the device status via a pseudo interrupt transfer * this is needed - otherwise the scanner will hang ... */ sanei_usb_set_timeout (status_timeout); @@ -2182,49 +2181,49 @@ write_usb_cmd: /* next i/o hardening attempt - and yes this gets ugly ... */ if (status != SANE_STATUS_GOOD && status != SANE_STATUS_INVAL) goto write_usb_cmd; - + if (status == SANE_STATUS_INVAL) { struct { command_header header; uint8_t pad[4]; } sense_cmd; - + uint8_t sense_buffer[22]; - + DBG (3, "Error during status read!\n"); DBG (3, "=== Try to request sense ===\n"); - + /* we can not call avision_cmd recursively - we might ending in an endless recursion requesting sense for failing request sense transfers ...*/ - + memset (&sense_cmd, 0, sizeof (sense_cmd) ); memset (&sense_buffer, 0, sizeof (sense_buffer) ); sense_cmd.header.opc = AVISION_SCSI_REQUEST_SENSE; sense_cmd.header.len = sizeof (sense_buffer); - + count = sizeof(sense_cmd); - + DBG (8, "try to write %lu bytes\n", (u_long) count); sanei_usb_set_timeout (write_timeout); status = sanei_usb_write_bulk (av_con->usb_dn, (uint8_t*) &sense_cmd, &count); DBG (8, "wrote %lu bytes\n", (u_long) count); - + if (status != SANE_STATUS_GOOD) { DBG (3, "=== Got error %d trying to request sense! ===\n", status); } else { count = sizeof (sense_buffer); - + DBG (8, "try to read %lu bytes sense data\n", (u_long) count); sanei_usb_set_timeout (read_timeout); status = sanei_usb_read_bulk(av_con->usb_dn, sense_buffer, &count); DBG (8, "read %lu bytes sense data\n", (u_long) count); - + /* we need to read out the status from the scanner i/o buffer */ status = avision_usb_status (av_con, 1, status_timeout); - + /* some scanner return NEED_SENSE even after reading it */ if (status != SANE_STATUS_GOOD && status != SANE_STATUS_INVAL) DBG (3, "=== Got error %d trying to read sense! ===\n", status); @@ -2248,33 +2247,33 @@ bubble_sort (uint8_t* sort_data, size_t count) { size_t i, j, limit, k; double sum = 0.0; - + limit = count / 3; - + for (i = 0; i < limit; ++i) { uint16_t ti = 0; uint16_t tj = 0; - + for (j = (i + 1); j < count; ++j) { ti = get_double ((sort_data + i*2)); tj = get_double ((sort_data + j*2)); - + if (ti > tj) { set_double ((sort_data + i*2), tj); set_double ((sort_data + j*2), ti); } } } - + for (k = 0, i = limit; i < count; ++i) { sum += get_double ((sort_data + i*2)); ++ k; } - + /* DBG (7, "bubble_sort: %d values for average\n", k); */ - + if (k > 0) /* if avg to compute */ return (uint16_t) (sum / k); else @@ -2286,7 +2285,7 @@ add_color_mode (Avision_Device* dev, color_mode mode, SANE_String name) { int i; DBG (3, "add_color_mode: %d %s\n", mode, name); - + for (i = 0; i < AV_COLOR_MODE_LAST; ++i) { if (dev->color_list [i] == 0) { @@ -2298,7 +2297,7 @@ add_color_mode (Avision_Device* dev, color_mode mode, SANE_String name) return SANE_STATUS_GOOD; } } - + DBG (3, "add_color_mode: failed\n"); return SANE_STATUS_NO_MEM; } @@ -2307,13 +2306,13 @@ static int last_color_mode (Avision_Device* dev) { int i = 1; - + while (dev->color_list [i] != 0 && i < AV_COLOR_MODE_LAST) ++i; - + /* we are off by one */ --i; - + return i; } @@ -2331,7 +2330,7 @@ match_color_mode (Avision_Device* dev, SANE_String name) return dev->color_list_num [i]; } } - + DBG (3, "match_color_mode: source mode invalid\n"); return AV_GRAYSCALE; } @@ -2352,14 +2351,14 @@ static SANE_Bool is_adf_scan (Avision_Scanner* s) { return s->hw->scanner_type == AV_SHEETFEED || (s->hw->scanner_type == AV_FLATBED && s->source_mode_dim == AV_ADF_DIM); - + } static SANE_Status add_source_mode (Avision_Device* dev, source_mode mode, SANE_String name) { int i; - + for (i = 0; i < AV_SOURCE_MODE_LAST; ++i) { if (dev->source_list [i] == 0) { @@ -2371,7 +2370,7 @@ add_source_mode (Avision_Device* dev, source_mode mode, SANE_String name) return SANE_STATUS_GOOD; } } - + return SANE_STATUS_NO_MEM; } @@ -2379,7 +2378,7 @@ static source_mode match_source_mode (Avision_Device* dev, SANE_String name) { int i; - + DBG (3, "match_source_mode: \"%s\"\n", name); for (i = 0; i < AV_SOURCE_MODE_LAST; ++i) @@ -2390,7 +2389,7 @@ match_source_mode (Avision_Device* dev, SANE_String name) return dev->source_list_num [i]; } } - + DBG (3, "match_source_mode: source mode invalid\n"); return AV_NORMAL; } @@ -2399,7 +2398,7 @@ static source_mode_dim match_source_mode_dim (source_mode sm) { DBG (3, "match_source_mode_dim: %d\n", sm); - + switch (sm) { case AV_NORMAL: return AV_NORMAL_DIM; @@ -2420,7 +2419,7 @@ get_pixel_boundary (Avision_Scanner* s) { Avision_Device* dev = s->hw; int boundary; - + switch (s->c_mode) { case AV_TRUECOLOR: case AV_TRUECOLOR12: @@ -2447,7 +2446,7 @@ get_pixel_boundary (Avision_Scanner* s) default: boundary = 8; } - + return boundary; } @@ -2458,11 +2457,11 @@ compute_parameters (Avision_Scanner* s) int boundary = get_pixel_boundary (s); SANE_Bool gray_mode = color_mode_is_shaded (s->c_mode); - + /* interlaced duplex (higher end) or flipping paper (HP8xxx)? */ s->avdimen.interlaced_duplex = s->source_mode == AV_ADF_DUPLEX && dev->inquiry_duplex_interlaced; - + /* for infra-red we use the same code path es for interlaced duplex */ if (s->val[OPT_IR].w) @@ -2491,23 +2490,23 @@ compute_parameters (Avision_Scanner* s) break; } #endif - + DBG (3, "sane_compute_parameters:\n"); - + DBG (3, "sane_compute_parameters: boundary %d, gray_mode: %d, \n", boundary, gray_mode); - + /* TODO: Implement different x/y resolutions support */ s->avdimen.xres = s->val[OPT_RESOLUTION].w; s->avdimen.yres = s->val[OPT_RESOLUTION].w; - + /* soft scale ? */ if (dev->hw->feature_type & AV_SOFT_SCALE) { /* find supported hardware resolution */ const int* hw_res; const int* hw_res_list = dev->inquiry_asic_type == AV_ASIC_C5 ? hw_res_list_c5 : hw_res_list_generic; - + for (hw_res = hw_res_list; *hw_res && *hw_res < s->avdimen.xres; ++hw_res) /* just iterate */; s->avdimen.hw_xres = *hw_res; @@ -2515,11 +2514,11 @@ compute_parameters (Avision_Scanner* s) for (hw_res = hw_res_list; *hw_res && *hw_res < s->avdimen.yres; ++hw_res) /* just iterate */; s->avdimen.hw_yres = *hw_res; - + DBG (3, "sane_compute_parameters: soft scale, hw res: %dx%d\n", s->avdimen.hw_xres, s->avdimen.hw_yres); - + if (!s->avdimen.hw_xres || ! s->avdimen.hw_yres) { DBG (1, "sane_compute_parameters: no matching HW res for: %dx%d\n", s->avdimen.xres, @@ -2531,11 +2530,11 @@ compute_parameters (Avision_Scanner* s) s->avdimen.hw_xres = s->val[OPT_RESOLUTION].w; s->avdimen.hw_yres = s->val[OPT_RESOLUTION].w; } - + DBG (3, "sane_compute_parameters: tlx: %f, tly: %f, brx: %f, bry: %f\n", SANE_UNFIX (s->val[OPT_TL_X].w), SANE_UNFIX (s->val[OPT_TL_Y].w), SANE_UNFIX (s->val[OPT_BR_X].w), SANE_UNFIX (s->val[OPT_BR_Y].w)); - + /* window parameter in pixel */ s->avdimen.tlx = s->avdimen.hw_xres * SANE_UNFIX (s->val[OPT_TL_X].w) / MM_PER_INCH; @@ -2545,7 +2544,7 @@ compute_parameters (Avision_Scanner* s) / MM_PER_INCH; s->avdimen.bry = s->avdimen.hw_yres * SANE_UNFIX (s->val[OPT_BR_Y].w) / MM_PER_INCH; - + /* line difference */ if (color_mode_is_color (s->c_mode) && dev->inquiry_needs_software_colorpack && @@ -2553,27 +2552,27 @@ compute_parameters (Avision_Scanner* s) { s->avdimen.line_difference = (dev->inquiry_line_difference * s->avdimen.hw_yres) / dev->inquiry_optical_res; - + s->avdimen.bry += 2 * s->avdimen.line_difference; - + /* limit bry + line_difference to real scan boundary */ { long y_max = dev->inquiry_y_ranges[s->source_mode_dim] * s->avdimen.hw_yres / MM_PER_INCH; DBG (3, "sane_compute_parameters: y_max: %ld, bry: %ld, line_difference: %d\n", y_max, s->avdimen.bry, s->avdimen.line_difference); - + if (s->avdimen.bry + 2 * s->avdimen.line_difference > y_max) { DBG (1, "sane_compute_parameters: bry limited!\n"); s->avdimen.bry = y_max - 2 * s->avdimen.line_difference; } } - + } /* end if needs software colorpack */ else { s->avdimen.line_difference = 0; } - + /* add overscan */ if (dev->inquiry_tune_scan_length && is_adf_scan (s)) { /* some extra effort for precise rounding ... */ @@ -2584,7 +2583,7 @@ compute_parameters (Avision_Scanner* s) DBG (3, "sane_compute_parameters: overscan lines: %d\n", overscan); s->avdimen.bry += overscan; } - + /* rear offset compensation */ if (s->avdimen.interlaced_duplex && dev->hw->feature_type & AV_REAR_OFFSET) { const double offset = 0.5; /* in current affected models 1/2 inch */ @@ -2598,16 +2597,16 @@ compute_parameters (Avision_Scanner* s) } memset (&s->params, 0, sizeof (s->params)); - + s->avdimen.hw_pixels_per_line = (s->avdimen.brx - s->avdimen.tlx); s->avdimen.hw_pixels_per_line -= s->avdimen.hw_pixels_per_line % boundary; - + s->avdimen.hw_lines = (s->avdimen.bry - s->avdimen.tly - 2 * s->avdimen.line_difference); - + if (s->avdimen.interlaced_duplex && dev->scanner_type != AV_FILM) s->avdimen.hw_lines -= s->avdimen.hw_lines % dev->read_stripe_size; - + s->params.pixels_per_line = s->avdimen.hw_pixels_per_line * s->avdimen.xres / s->avdimen.hw_xres; s->params.lines = s->avdimen.hw_lines * s->avdimen.xres / s->avdimen.hw_xres; if (is_adf_scan (s)) @@ -2615,9 +2614,9 @@ compute_parameters (Avision_Scanner* s) s->params.lines = -1; if (s->c_mode == AV_THRESHOLDED || s->c_mode == AV_DITHERED) s->params.pixels_per_line -= s->params.pixels_per_line % 8; - + debug_print_avdimen (1, "sane_compute_parameters", &s->avdimen); - + switch (s->c_mode) { case AV_THRESHOLDED: @@ -2662,9 +2661,9 @@ compute_parameters (Avision_Scanner* s) DBG (1, "Invalid mode. %d\n", s->c_mode); return SANE_STATUS_INVAL; } /* end switch */ - + s->params.last_frame = SANE_TRUE; - + debug_print_params (1, "sane_compute_parameters", &s->params); return SANE_STATUS_GOOD; } @@ -2675,26 +2674,26 @@ inquiry (Avision_Connection av_con, uint8_t* data, size_t len) SANE_Status status; command_header inquiry; int try = 2; - + DBG (3, "inquiry: length: %ld\n", (long)len); - + memset (&inquiry, 0, sizeof(inquiry)); inquiry.opc = AVISION_SCSI_INQUIRY; inquiry.len = len; - + do { size_t size = inquiry.len; - + DBG (3, "inquiry: inquiring ...\n"); status = avision_cmd (&av_con, &inquiry, sizeof (inquiry), 0, 0, data, &size); if (status == SANE_STATUS_GOOD && size == inquiry.len) break; - + DBG (1, "inquiry: inquiry failed (%s)\n", sane_strstatus (status)); --try; } while (try > 0); - + return status; } @@ -2703,14 +2702,14 @@ wait_ready (Avision_Connection* av_con, int delay) { SANE_Status status; int try; - + for (try = 0; try < 10; ++ try) { DBG (3, "wait_ready: sending TEST_UNIT_READY\n"); status = avision_cmd (av_con, test_unit_ready, sizeof (test_unit_ready), 0, 0, 0, 0); sleep (delay); - + switch (status) { default: @@ -2734,45 +2733,45 @@ static SANE_Status wait_4_light (Avision_Scanner* s) { Avision_Device* dev = s->hw; - + /* read stuff */ struct command_read rcmd; char* light_status[] = - { "off", "on", "warming up", "needs warm up test", + { "off", "on", "warming up", "needs warm up test", "light check error", "backlight on", "RESERVED" }; - + SANE_Status status; uint8_t result; int try; size_t size = 1; - + DBG (3, "wait_4_light: getting light status.\n"); - + memset (&rcmd, 0, sizeof (rcmd)); - + rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0xa0; /* get light status */ set_double (rcmd.datatypequal, dev->data_dq); set_triple (rcmd.transferlen, size); - + for (try = 0; try < 90; ++ try) { if (s->cancelled) { DBG (3, "wait_4_light: cancelled\n"); return SANE_STATUS_CANCELLED; } - + DBG (5, "wait_4_light: read bytes %lu\n", (u_long) size); status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, &result, &size); - + if (status != SANE_STATUS_GOOD || size != sizeof (result)) { DBG (1, "wait_4_light: read failed (%s)\n", sane_strstatus (status)); return status; } - + DBG (3, "wait_4_light: command is %d. Result is %d (%s)\n", status, result, light_status[(result>5)?6:result]); - + if (result == 1 || result == 5) { return SANE_STATUS_GOOD; } @@ -2783,20 +2782,20 @@ wait_4_light (Avision_Scanner* s) else { struct command_send scmd; uint8_t light_on = 1; - + /* turn on the light */ DBG (3, "wait_4_light: setting light status.\n"); - + memset (&scmd, 0, sizeof (scmd)); - + scmd.opc = AVISION_SCSI_SEND; scmd.datatypecode = 0xa0; /* send light status */ set_double (scmd.datatypequal, dev->data_dq); set_triple (scmd.transferlen, size); - + status = avision_cmd (&s->av_con, &scmd, sizeof (scmd), &light_on, sizeof (light_on), 0, 0); - + if (status != SANE_STATUS_GOOD) { DBG (1, "wait_4_light: send failed (%s)\n", sane_strstatus (status)); return status; @@ -2804,7 +2803,7 @@ wait_4_light (Avision_Scanner* s) } sleep (1); } - + DBG (1, "wait_4_light: timed out after %d attempts\n", try); return SANE_STATUS_DEVICE_BUSY; } @@ -2846,27 +2845,27 @@ get_firmware_status (Avision_Connection* av_con) SANE_Status status; firmware_status result; - + DBG (3, "get_firmware_status\n"); - + size = sizeof (result); - + memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; - + rcmd.datatypecode = 0x90; /* firmware status */ set_double (rcmd.datatypequal, 0); /* dev->data_dq not available */ set_triple (rcmd.transferlen, size); - + status = avision_cmd (av_con, &rcmd, sizeof (rcmd), 0, 0, &result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result)) { DBG (1, "get_firmware_status: read failed (%s)\n", sane_strstatus (status)); return (status); } - + debug_print_raw (6, "get_firmware_status: raw data:\n", (uint8_t*)&result, size); - + DBG (3, "get_firmware_status: [0] needs firmware %x\n", result.download_firmware); DBG (3, "get_firmware_status: [1] side edge: %d\n", get_double ( result.first_effective_pixel_flatbed )); DBG (3, "get_firmware_status: [3] side edge: %d\n", get_double ( result.first_effective_pixel_adf_front )); @@ -2883,28 +2882,28 @@ get_flash_ram_info (Avision_Connection* av_con) size_t size; SANE_Status status; uint8_t result[40]; - + DBG (3, "get_flash_ram_info\n"); - + size = sizeof (result); - + memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; - + rcmd.datatypecode = 0x6a; /* flash ram information */ set_double (rcmd.datatypequal, 0); /* dev->data_dq not available */ set_triple (rcmd.transferlen, size); - + status = avision_cmd (av_con, &rcmd, sizeof (rcmd), 0, 0, result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result)) { DBG (1, "get_flash_ram_info: read failed (%s)\n", sane_strstatus (status)); return (status); } - + debug_print_raw (6, "get_flash_ram_info: raw data:\n", result, size); - - DBG (3, "get_flash_ram_info: [0] data type %x\n", result [0]); + + DBG (3, "get_flash_ram_info: [0] data type %x\n", result [0]); DBG (3, "get_flash_ram_info: [1] Ability1:%s%s%s%s%s%s%s%s\n", BIT(result[1],7)?" RESERVED_BIT7":"", BIT(result[1],6)?" RESERVED_BIT6":"", @@ -2914,7 +2913,7 @@ get_flash_ram_info (Avision_Connection* av_con) BIT(result[1],2)?" RAWLINE(r)":"", BIT(result[1],1)?" FIRMWARE(r/w)":"", BIT(result[1],0)?" CTAB(r/w)":""); - + DBG (3, "get_flash_ram_info: [2-5] size CTAB: %d\n", get_quad ( &(result[2]) ) ); @@ -2938,7 +2937,7 @@ get_flash_ram_info (Avision_Connection* av_con) DBG (3, "get_flash_ram_info: [30-33] size RESERVED: %d\n", get_quad ( &(result[30]) ) ); - + return SANE_STATUS_GOOD; } @@ -2947,23 +2946,23 @@ get_nvram_data (Avision_Scanner* s, nvram_data* nvram) { /* read stuff */ struct command_send rcmd; - + size_t size; SANE_Status status; - + DBG (3, "get_nvram_data\n"); - + size = sizeof (*nvram); - + memset (&rcmd, 0, sizeof (rcmd)); memset (nvram, 0, size); - + rcmd.opc = AVISION_SCSI_READ; - + rcmd.datatypecode = 0x69; /* Read NVM RAM data */ set_double (rcmd.datatypequal, 0); /* dev->data_dq not available */ set_triple (rcmd.transferlen, size); - + status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, nvram, &size); if (status != SANE_STATUS_GOOD) { @@ -2971,9 +2970,9 @@ get_nvram_data (Avision_Scanner* s, nvram_data* nvram) sane_strstatus (status)); return (status); } - + debug_print_nvram_data (5, "get_nvram_data", nvram); - + return SANE_STATUS_GOOD; } @@ -2985,7 +2984,7 @@ get_and_parse_nvram (Avision_Scanner* s, char* str, int n) int x; nvram_data nvram; uint8_t inquiry_result [AVISION_INQUIRY_SIZE_V1]; - + status = inquiry (s->av_con, inquiry_result, sizeof(inquiry_result)); if (status == SANE_STATUS_GOOD) { i += snprintf (str+i, n-i, "Vendor: %.8s", @@ -2995,17 +2994,17 @@ get_and_parse_nvram (Avision_Scanner* s, char* str, int n) i += snprintf (str+i, n-i, "\nFirmware: %.4s", inquiry_result+32); } - + if (!s->hw->inquiry_nvram_read) return SANE_STATUS_GOOD; - + status = get_nvram_data (s, &nvram); if (status == SANE_STATUS_GOOD) { if (nvram.serial[0]) i += snprintf (str+i, n-i, "\nSerial: %.24s", nvram.serial); - + if (nvram.born_year) i += snprintf (str+i, n-i, "\nManufacturing date: %d-%d-%d", get_double(nvram.born_year), @@ -3016,7 +3015,7 @@ get_and_parse_nvram (Avision_Scanner* s, char* str, int n) get_double(nvram.first_scan_year), get_double(nvram.first_scan_month), get_double(nvram.first_scan_day)); - + x = get_quad (nvram.flatbed_scans); if (x) i += snprintf (str+i, n-i, "\nFlatbed scans: %d", x); @@ -3030,7 +3029,7 @@ get_and_parse_nvram (Avision_Scanner* s, char* str, int n) if (x) i += snprintf (str+i, n-i, "\nADF duplex scans: %d", x); } - + return status; } @@ -3039,21 +3038,21 @@ get_power_save_time (Avision_Scanner* s, SANE_Word* time) { SANE_Status status; nvram_data nvram; - + DBG (3, "get_power_save_time\n"); - + if (!s->hw->inquiry_nvram_read) return SANE_STATUS_INVAL; - + status = get_nvram_data (s, &nvram); - + if (status != SANE_STATUS_GOOD) { DBG (1, "get_power_save_time: read nvram failed (%s)\n", sane_strstatus (status)); return status; } - + *time = get_double (nvram.power_saving_time); - + return SANE_STATUS_GOOD; } @@ -3066,18 +3065,18 @@ send_nvram_data (Avision_Connection* av_con) struct command_send scmd; size_t size; SANE_Status status; - + DBG (3, "send_nvram_data\n"); - + size = sizeof (c7_nvram); - + memset (&scmd, 0, sizeof (scmd)); scmd.opc = AVISION_SCSI_SEND; - + scmd.datatypecode = 0x85; /* nvram data */ set_double (scmd.datatypequal, 0); /* dev->data_dq not available */ set_triple (scmd.transferlen, size); - + status = avision_cmd (av_con, &scmd, sizeof (scmd), &c7_nvram, size, 0, 0); if (status != SANE_STATUS_GOOD) { @@ -3085,7 +3084,7 @@ send_nvram_data (Avision_Connection* av_con) sane_strstatus (status)); return (status); } - + return SANE_STATUS_GOOD; } @@ -3096,18 +3095,18 @@ send_flash_ram_data (Avision_Connection* av_con) struct command_send scmd; size_t size; SANE_Status status; - + DBG (3, "send_flash_ram_data\n"); - + size = sizeof (c7_flash_ram); - + memset (&scmd, 0, sizeof (scmd)); scmd.opc = AVISION_SCSI_SEND; - + scmd.datatypecode = 0x86; /* flash data */ set_double (scmd.datatypequal, 0); set_triple (scmd.transferlen, size); - + status = avision_cmd (av_con, &scmd, sizeof (scmd), &c7_flash_ram, size, 0, 0); if (status != SANE_STATUS_GOOD) { @@ -3115,7 +3114,7 @@ send_flash_ram_data (Avision_Connection* av_con) sane_strstatus (status)); return (status); } - + return SANE_STATUS_GOOD; } #endif @@ -3177,28 +3176,28 @@ get_accessories_info (Avision_Scanner* s) { Avision_Device* dev = s->hw; int try = 3; - + /* read stuff */ struct command_read rcmd; size_t size; SANE_Status status; uint8_t result[8]; - + char* adf_model[] = { "Origami", "Oodles", "HP9930", "unknown" }; const int adf_models = sizeof (adf_model) / sizeof(char*) - 1; - + DBG (3, "get_accessories_info\n"); - + size = sizeof (result); - + memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; - + rcmd.datatypecode = 0x64; /* detect accessories */ set_double (rcmd.datatypequal, dev->data_dq); set_triple (rcmd.transferlen, size); - + /* after resetting the ADF unit, try reprobing it again */ RETRY: @@ -3291,7 +3290,7 @@ string_for_button (Avision_Scanner* s, int button) case 2: return "duplex"; } } - + if (strcmp (dev->sane.model, "AV210C2") == 0 || strcmp (dev->sane.model, "AV210D2+") == 0 || strcmp (dev->sane.model, "AV220C2") == 0 || @@ -3303,7 +3302,7 @@ string_for_button (Avision_Scanner* s, int button) else goto return_scan; } - + /* those are unique, right now */ if (strcmp (dev->sane.model, "AV610") == 0) { @@ -3314,11 +3313,11 @@ string_for_button (Avision_Scanner* s, int button) case 2: return "scan"; } } - + /* last resort */ snprintf (buffer, sizeof (buffer), "button%d", button); return buffer; - + return_scan: return "scan"; } @@ -3327,7 +3326,7 @@ static SANE_Status get_button_status (Avision_Scanner* s) { Avision_Device* dev = s->hw; - + /* read stuff */ struct command_read rcmd; size_t size; @@ -3341,21 +3340,21 @@ get_button_status (Avision_Scanner* s) } result; unsigned int i; - + DBG (3, "get_button_status:\n"); - + size = sizeof (result); - + /* AV220 et.al. */ if (! (dev->hw->feature_type & AV_INT_BUTTON)) { memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; - + rcmd.datatypecode = 0xA1; /* button status */ set_double (rcmd.datatypequal, dev->data_dq); set_triple (rcmd.transferlen, size); - + status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, (uint8_t*)&result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result)) { @@ -3367,7 +3366,7 @@ get_button_status (Avision_Scanner* s) { /* only try to read the first 8 bytes ...*/ size = 8; - + /* no SCSI equivalent */ /* either there was a button press and this completes quickly or there is no point waiting for a future press */ @@ -3376,21 +3375,21 @@ get_button_status (Avision_Scanner* s) status = sanei_usb_read_int (s->av_con.usb_dn, (uint8_t*)&result, &size); DBG (5, "==> (interrupt read) got: %ld\n", (long)size); - + if (status != SANE_STATUS_GOOD) { DBG (1, "get_button_status: interrupt read failed (%s)\n", sane_strstatus (status)); return SANE_STATUS_GOOD; } - + if (size < sizeof (result)) memset ((char*)result.buttons + size, 0, sizeof (result) - size); - + /* hack to fill in meaningful values for the AV 210 / 610 and under some conditions the AV 220 */ if (size == 1) { /* AV 210, AV 610 */ DBG (1, "get_button_status: just one byte, filling the rest\n"); - + if (result.press_state > 0) { debug_print_raw (6, "get_button_status: raw data\n", (uint8_t*)&result, size); @@ -3402,72 +3401,72 @@ get_button_status (Avision_Scanner* s) return SANE_STATUS_GOOD; } else if (size >= 8 && result.press_state == 0) { /* AV 220 */ - + debug_print_raw (6, "get_button_status: raw data\n", (uint8_t*)&result, size); - + DBG (1, "get_button_status: zero buttons - filling values ...\n"); - + /* simulate button press of the last button ... */ result.press_state = 0x80 | 1; result.buttons[0] = dev->inquiry_buttons; /* 1 based */ } } - + debug_print_raw (6, "get_button_status: raw data\n", (uint8_t*)&result, size); - + DBG (3, "get_button_status: [0] Button status: %x\n", result.press_state); for (i = 0; i < 5; ++i) DBG (3, "get_button_status: [%d] Button number %d: %x\n", i+1, i, result.buttons[i]); DBG (3, "get_button_status: [7] Display: %d\n", result.display); - + { char* message_begin = s->val[OPT_MESSAGE].s; char* message_end = s->val[OPT_MESSAGE].s + s->opt[OPT_MESSAGE].size; char* message = message_begin; - + #define add_token(format,value) do { \ int n = snprintf (message, message_end - message, "%s" format, \ message == message_begin ? "" : ":", value); \ message += n > 0 ? n : 0; \ } while (0) - + if (result.display > 0) add_token ("%d", result.display); - + if (result.press_state >> 7) /* AV220 et.al. bit 6 is long/short press? */ { - + const unsigned int buttons_pressed = result.press_state & 0x7F; DBG (3, "get_button_status: %d button(s) pressed\n", buttons_pressed); - + /* reset the hardware button status */ if (! (dev->hw->feature_type & AV_INT_BUTTON)) { struct command_send scmd; uint8_t button_reset = 1; - + DBG (3, "get_button_status: resetting status\n"); - + memset (&scmd, 0, sizeof (scmd)); - + scmd.opc = AVISION_SCSI_SEND; scmd.datatypecode = 0xA1; /* button control */ set_double (scmd.datatypequal, dev->data_dq); set_triple (scmd.transferlen, size); - + status = avision_cmd (&s->av_con, &scmd, sizeof (scmd), &button_reset, sizeof (button_reset), 0, 0); - + if (status != SANE_STATUS_GOOD) { DBG (1, "get_button_status: send failed (%s)\n", sane_strstatus (status)); return status; } } - + for (i = 0; i < buttons_pressed; ++i) { const unsigned int button = result.buttons[i] - 1; /* 1 based ... */ DBG (3, "get_button_status: button %d pressed\n", button); @@ -3487,7 +3486,7 @@ get_button_status (Avision_Scanner* s) else DBG (3, "get_button_status: no button pressed\n"); } - + return SANE_STATUS_GOOD; #undef add_token } @@ -3496,33 +3495,33 @@ static SANE_Status get_frame_info (Avision_Scanner* s) { Avision_Device* dev = s->hw; - + /* read stuff */ struct command_read rcmd; size_t size; SANE_Status status; uint8_t result[8]; size_t i; - + DBG (3, "get_frame_info:\n"); - + size = sizeof (result); - + memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; - + rcmd.datatypecode = 0x87; /* film holder sense */ set_double (rcmd.datatypequal, dev->data_dq); set_triple (rcmd.transferlen, size); - + status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result)) { DBG (1, "get_frame_info: read failed (%s)\n", sane_strstatus (status)); return (status); } - + debug_print_raw (6, "get_frame_info: raw data\n", result, size); - + DBG (3, "get_frame_info: [0] Holder type: %s\n", (result[0]==1)?"APS": (result[0]==2)?"Film holder (35mm)": @@ -3531,24 +3530,24 @@ get_frame_info (Avision_Scanner* s) DBG (3, "get_frame_info: [1] Current frame number: %d\n", result[1]); DBG (3, "get_frame_info: [2] Frame amount: %d\n", result[2]); DBG (3, "get_frame_info: [3] Mode: %s\n", BIT(result[3],4)?"APS":"Not APS"); - DBG (3, "get_frame_info: [3] Exposures (if APS): %s\n", + DBG (3, "get_frame_info: [3] Exposures (if APS): %s\n", ((i=(BIT(result[3],3)<<1)+BIT(result[2],2))==0)?"Unknown": (i==1)?"15":(i==2)?"25":"40"); - DBG (3, "get_frame_info: [3] Film Type (if APS): %s\n", + DBG (3, "get_frame_info: [3] Film Type (if APS): %s\n", ((i=(BIT(result[1],3)<<1)+BIT(result[0],2))==0)?"Unknown": (i==1)?"B&W Negative":(i==2)?"Color slide":"Color Negative"); dev->holder_type = result[0]; dev->current_frame = result[1]; - + dev->frame_range.min = 1; dev->frame_range.quant = 1; - + if (result[0] != 0xff) dev->frame_range.max = result[2]; else dev->frame_range.max = 1; - + return SANE_STATUS_GOOD; } @@ -3556,7 +3555,7 @@ static SANE_Status get_duplex_info (Avision_Scanner* s) { Avision_Device* dev = s->hw; - + /* read stuff */ struct command_read rcmd; @@ -3567,30 +3566,30 @@ get_duplex_info (Avision_Scanner* s) uint8_t lineart_line_difference[2]; uint8_t image_info; } result; - + size_t size; SANE_Status status; - + DBG (3, "get_duplex_info:\n"); - + size = sizeof (result); - + memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; - + rcmd.datatypecode = 0xB1; /* read duplex info */ set_double (rcmd.datatypequal, dev->data_dq); set_triple (rcmd.transferlen, size); - + status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, &result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result)) { DBG (1, "get_duplex_info: read failed (%s)\n", sane_strstatus (status)); return (status); } - + debug_print_raw (6, "get_duplex_info: raw data\n", (uint8_t*)&result, size); - + DBG (3, "get_duplex_info: [0] Mode: %s%s\n", BIT(result.mode,0)?"MERGED_PAGES":"", BIT(result.mode,1)?"2ND_PAGE_FOLLOWS":""); @@ -3606,7 +3605,7 @@ get_duplex_info (Avision_Scanner* s) BIT(result.image_info,1)?" ADF_BGR":" ADF_RGB", BIT(result.image_info,2)?" FLATBED_NEEDS_MIRROR_IMAGE":"", BIT(result.image_info,3)?" ADF_NEEDS_MIRROR_IMAGE":""); - + return SANE_STATUS_GOOD; } @@ -3617,45 +3616,45 @@ set_frame (Avision_Scanner* s, SANE_Word frame) struct command_send cmd; uint8_t data[8]; } scmd; - + Avision_Device* dev = s->hw; SANE_Status status; - + DBG (3, "set_frame: request frame %d\n", frame); - + /* Better check the current status of the film holder, because it can be changed between scans. */ status = get_frame_info (s); if (status != SANE_STATUS_GOOD) return status; - + /* No film holder? */ if (dev->holder_type == 0xff) { DBG (1, "set_frame: No film holder!!\n"); return SANE_STATUS_INVAL; } - + /* Requesting frame 0xff indicates eject/rewind */ if (frame != 0xff && (frame < 1 || frame > dev->frame_range.max) ) { DBG (1, "set_frame: Illegal frame (%d) requested (min=1, max=%d)\n", - frame, dev->frame_range.max); + frame, dev->frame_range.max); return SANE_STATUS_INVAL; } - + memset (&scmd, 0, sizeof (scmd)); scmd.cmd.opc = AVISION_SCSI_SEND; scmd.cmd.datatypecode = 0x87; /* send film holder "sense" */ set_double (scmd.cmd.datatypequal, dev->data_dq); set_triple (scmd.cmd.transferlen, sizeof (scmd.data) ); - + scmd.data[0] = dev->holder_type; - scmd.data[1] = frame; - + scmd.data[1] = frame; + status = avision_cmd (&s->av_con, &scmd.cmd, sizeof (scmd.cmd), &scmd.data, sizeof (scmd.data), 0, 0); if (status != SANE_STATUS_GOOD) { DBG (1, "set_frame: send_data (%s)\n", sane_strstatus (status)); - } + } return status; } @@ -3669,20 +3668,20 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, Avision_Device* dev; SANE_Status status; - + Avision_Connection av_con; char mfg [9]; char model [17]; char rev [5]; - + unsigned int i; char* s; SANE_Bool found; - + DBG (3, "attach:\n"); memset (result, 0, sizeof(result)); - + for (dev = first_dev; dev; dev = dev->next) if (strcmp (dev->sane.name, devname) == 0) { if (devp) @@ -3693,25 +3692,25 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, av_con.connection_type = con_type; if (av_con.connection_type == AV_USB) av_con.usb_status = AVISION_USB_UNTESTED_STATUS; - + /* set known USB status type */ if (attaching_hw && attaching_hw->feature_type & AV_INT_STATUS) av_con.usb_status = AVISION_USB_INT_STATUS; - + DBG (3, "attach: opening %s\n", devname); status = avision_open (devname, &av_con, sense_handler, 0); if (status != SANE_STATUS_GOOD) { DBG (1, "attach: open failed (%s)\n", sane_strstatus (status)); return SANE_STATUS_INVAL; } - + /* first: get the standard inquiry? */ status = inquiry (av_con, result, AVISION_INQUIRY_SIZE_V1); if (status != SANE_STATUS_GOOD) { DBG (1, "attach: 1st inquiry failed (%s)\n", sane_strstatus (status)); return status; } - + /* copy string information - and zero terminate them c-style */ memcpy (&mfg, result + 8, 8); mfg [8] = 0; @@ -3719,7 +3718,7 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, model [16] = 0; memcpy (&rev, result + 32, 4); rev [4] = 0; - + /* shorten strings (-1 for last index -1 for last 0; >0 because one char at least) */ for (i = sizeof (mfg) - 2; i > 0; i--) { @@ -3734,10 +3733,10 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, else break; } - + DBG (1, "attach: Inquiry gives mfg=%s, model=%s, product revision=%s.\n", mfg, model, rev); - + model_num = 0; found = 0; /* while not at at end of list NULL terminator */ @@ -3746,7 +3745,7 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, { int matches = 0, match_count = 0; /* count number of matches */ DBG (1, "attach: Checking model: %d\n", model_num); - + if (Avision_Device_List[model_num].scsi_mfg) { ++match_count; if (strcmp(mfg, Avision_Device_List[model_num].scsi_mfg) == 0) @@ -3757,7 +3756,7 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, if (strcmp(model, Avision_Device_List[model_num].scsi_model) == 0) ++matches; } - + /* we need 2 matches (mfg, model) for SCSI entries, or the ones available for "we know what we are looking for" USB entries */ if ((attaching_hw == &(Avision_Device_List [model_num]) && @@ -3775,16 +3774,16 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, } ++model_num; } - + if (!found) { DBG (0, "attach: \"%s\" - \"%s\" not yet in whitelist!\n", mfg, model); DBG (0, "attach: You might want to report this output.\n"); DBG (0, "attach: To: rene@exactcode.de (the Avision backend author)\n"); - + status = SANE_STATUS_INVAL; goto close_scanner_and_return; } - + /* second: maybe ask for the firmware status and flash ram info */ if (Avision_Device_List [model_num].feature_type & AV_FIRMWARE) { @@ -3795,7 +3794,7 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, sane_strstatus (status)); goto close_scanner_and_return; } - + DBG (3, "attach: reading flash ram info\n"); status = get_flash_ram_info (&av_con); if (status != SANE_STATUS_GOOD) { @@ -3803,7 +3802,7 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, sane_strstatus (status)); goto close_scanner_and_return; } - + #ifdef FIRMWARE_DATABASE_INCLUDED /* Send new NV-RAM (firmware) data */ status = send_nvram_data (&av_con); @@ -3811,7 +3810,7 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, goto close_scanner_and_return; #endif } - + /* third: get the extended Avision inquiry */ status = inquiry (av_con, result, AVISION_INQUIRY_SIZE_V1); if (status != SANE_STATUS_GOOD) { @@ -3824,17 +3823,17 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, status = SANE_STATUS_NO_MEM; goto close_scanner_and_return; } - + memset (dev, 0, sizeof (*dev)); dev->hw = &Avision_Device_List[model_num]; - + dev->sane.name = strdup (devname); dev->sane.vendor = dev->hw->real_mfg ? dev->hw->real_mfg : strdup (mfg); dev->sane.model = dev->hw->real_model ? dev->hw->real_model : strdup (model); dev->connection.connection_type = av_con.connection_type; dev->connection.usb_status = av_con.usb_status; - + /* and finally Avision even extended this one later on the AV220C2 does not grok this */ dev->inquiry_asic_type = (int) result[91]; @@ -3846,13 +3845,13 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, goto close_scanner_and_return; } } - + debug_print_raw (6, "attach: raw data:\n", result, sizeof (result) ); - + DBG (3, "attach: [8-15] Vendor id.: '%8.8s'\n", result+8); DBG (3, "attach: [16-31] Product id.: '%16.16s'\n", result+16); DBG (3, "attach: [32-35] Product rev.: '%4.4s'\n", result+32); - + i = (result[36] >> 4) & 0x7; switch (result[36] & 0x07) { case 0: @@ -3873,7 +3872,7 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, DBG (3, "attach: [37] Optical res.: %d00 dpi\n", result[37]); DBG (3, "attach: [38] Maximum res.: %d00 dpi\n", result[38]); - + DBG (3, "attach: [39] Bitfield1:%s%s%s%s%s%s\n", BIT(result[39],7)?" TRANS":"", BIT(result[39],6)?" Q_SCAN":"", @@ -3881,7 +3880,7 @@ attach (SANE_String_Const devname, Avision_ConnectionType con_type, BIT(result[39],4)?" SUPPORTS_CALIB":"", BIT(result[39],2)?" NEW_PROTOCOL":"", (result[39] & 0x03) == 0x03 ? " AVISION":" OEM"); - + DBG (3, "attach: [40-41] X res. in gray: %d dpi\n", get_double ( &(result[40]) )); DBG (3, "attach: [42-43] Y res. in gray: %d dpi\n", @@ -3920,7 +3919,7 @@ get_double ( &(result[48] ) )); BIT(result[52],2)?" INDEX_COLOR":"", BIT(result[52],1)?" POWER_SAVING_TIMER":"", BIT(result[52],0)?" NVM_DATA_REC":""); - + /* print some more scanner features/params */ DBG (3, "attach: [53] line difference (software color pack): %d\n", result[53]); DBG (3, "attach: [54] color mode pixel boundary: %d\n", result[54]); @@ -3929,13 +3928,13 @@ get_double ( &(result[48] ) )); DBG (3, "attach: [57] lineart mode pixel boundary: %d\n", result[57]); DBG (3, "attach: [58] halftone mode pixel boundary: %d\n", result[58]); DBG (3, "attach: [59] error-diffusion mode pixel boundary: %d\n", result[59]); - + DBG (3, "attach: [60] channels per pixel:%s%s%s\n", BIT(result[60],7)?" 1":"", BIT(result[60],6)?" 3":"", (result[60] & 0x3F) != 0 ? " RESERVED":""); - - DBG (3, "attach: [61] bits per channel:%s%s%s%s%s%s%s\n", + + DBG (3, "attach: [61] bits per channel:%s%s%s%s%s%s%s\n", BIT(result[61],7)?" 1":"", BIT(result[61],6)?" 4":"", BIT(result[61],5)?" 6":"", @@ -3943,40 +3942,40 @@ get_double ( &(result[48] ) )); BIT(result[61],3)?" 10":"", BIT(result[61],2)?" 12":"", BIT(result[61],1)?" 16":""); - - DBG (3, "attach: [62] scanner type:%s%s%s%s%s%s\n", + + DBG (3, "attach: [62] scanner type:%s%s%s%s%s%s\n", BIT(result[62],7)?" Flatbed":"", BIT(result[62],6)?" Roller (ADF)":"", BIT(result[62],5)?" Flatbed (ADF)":"", BIT(result[62],4)?" Roller":"", /* does not feed multiple pages, AV25 */ BIT(result[62],3)?" Film scanner":"", BIT(result[62],2)?" Duplex":""); - + DBG (3, "attach: [75-76] Max shading target : %x\n", get_double ( &(result[75]) )); - + DBG (3, "attach: [77-78] Max X of transparency: %d dots * base_dpi\n", get_double ( &(result[77]) )); DBG (3, "attach: [79-80] Max Y of transparency: %d dots * base_dpi\n", get_double ( &(result[79]) )); - + DBG (3, "attach: [81-82] Max X of flatbed: %d dots * base_dpi\n", get_double ( &(result[81]) )); DBG (3, "attach: [83-84] Max Y of flatbed: %d dots * base_dpi\n", get_double ( &(result[83]) )); - + DBG (3, "attach: [85-86] Max X of ADF: %d dots * base_dpi\n", get_double ( &(result[85]) )); DBG (3, "attach: [87-88] Max Y of ADF: %d dots * base_dpi\n", get_double ( &(result[87]) )); /* 0xFFFF means unlimited length */ - + DBG (3, "attach: [89-90] Res. in Ex. mode: %d dpi\n", get_double ( &(result[89]) )); - + DBG (3, "attach: [91] ASIC: %d\n", result[91]); - + DBG (3, "attach: [92] Buttons: %d\n", result[92]); - + DBG (3, "attach: [93] ESA4:%s%s%s%s%s%s%s%s\n", BIT(result[93],7)?" SUPPORTS_ACCESSORIES_DETECT":"", BIT(result[93],6)?" ADF_IS_BGR_ORDERED":"", @@ -3986,7 +3985,7 @@ get_double ( &(result[48] ) )); BIT(result[93],2)?" SUPPORTS_LIGHT_DETECT":"", BIT(result[93],1)?" SUPPORTS_READ_PRNU_DATA":"", BIT(result[93],0)?" FLATBED_MIRRORS_IMAGE":""); - + DBG (3, "attach: [94] ESA5:%s%s%s%s%s%s%s%s\n", BIT(result[94],7)?" IGNORE_LINE_DIFFERENCE_FOR_ADF":"", BIT(result[94],6)?" NEEDS_SW_LINE_COLOR_PACK":"", @@ -3996,7 +3995,7 @@ get_double ( &(result[48] ) )); BIT(result[94],2)?" SUPPORTS_TUNE_SCAN_LENGTH":"", BIT(result[94],1)?" SUPPORTS_SWITCH_STRIP_FOR_DESKEW":"", /* Kodak i80 only */ BIT(result[94],0)?" SEARCHES_LEADING_SIDE_EDGE_BY_FIRMWARE":""); - + DBG (3, "attach: [95] ESA6:%s%s%s%s%s%s%s%s\n", BIT(result[95],7)?" SUPPORTS_PAPER_SIZE_AUTO_DETECTION":"", BIT(result[95],6)?" SUPPORTS_DO_HOUSEKEEPING":"", /* Kodak i80 only */ @@ -4006,7 +4005,7 @@ get_double ( &(result[48] ) )); BIT(result[95],2)?" SUPPORTS_GET_BACKGROUND_RASTER":"", /* AV220 et.al. */ BIT(result[95],1)?" SUPPORTS_NVRAM_RESET":"", BIT(result[95],0)?" SUPPORTS_BATCH_SCAN":""); - + DBG (3, "attach: [128] ESA7:%s%s%s%s%s%s%s%s\n", BIT(result[128],7)?" SUPPORTS_ADF_CONTINUOUS":"", BIT(result[128],6)?" SUPPORTS_YCbCr_COLOR":"", @@ -4016,7 +4015,7 @@ get_double ( &(result[48] ) )); BIT(result[128],2)?" SUPPORTS_JOB_CONTROL":"", BIT(result[128],1)?" SUPPORTS_INF_LENGTH":"", BIT(result[128],0)?" ULTRA_SONIC_DOUBLE_FEED_DETECTION":""); - + DBG (3, "attach: [129] YCbCr:%s%s%s%s%s%s%s%s\n", BIT(result[129],7)?" YCC4:2:0":"", BIT(result[129],6)?" YCC(profile2)":"", @@ -4026,7 +4025,7 @@ get_double ( &(result[48] ) )); BIT(result[129],2)?" JPEG(profile2)":"", BIT(result[129],1)?" JPEG(profile3)":"", BIT(result[129],0)?" JPEG(profile4)":""); - + /* I have no idea how film scanner could reliably be detected -ReneR */ if (dev->hw->feature_type & AV_FILMSCANNER) { dev->scanner_type = AV_FILM; @@ -4046,19 +4045,19 @@ get_double ( &(result[48] ) )); dev->inquiry_nvram_read = BIT(result[52],0); dev->inquiry_power_save_time = BIT(result[52],1); - + dev->inquiry_adf = BIT (result[62], 5); dev->inquiry_duplex = BIT (result[62], 2) || BIT (result[94], 5); - dev->inquiry_duplex_interlaced = BIT(result[62],2) || BIT (result[94], 4); + dev->inquiry_duplex_interlaced = BIT(result[62],2) || BIT (result[94], 4); /* the first avision scanners (AV3200) do not set the interlaced bit */ if (dev->inquiry_duplex && dev->inquiry_asic_type < AV_ASIC_C6) dev->inquiry_duplex_interlaced = 1; dev->inquiry_paper_length = BIT (result[95], 5); dev->inquiry_batch_scan = BIT (result[95], 0); /* AV122, DM152 */ - + dev->inquiry_detect_accessories = BIT (result[93], 7); - + dev->inquiry_needs_calibration = BIT (result[50], 4); dev->inquiry_keeps_window = BIT (result[50], 1); @@ -4066,7 +4065,7 @@ get_double ( &(result[48] ) )); dev->inquiry_keeps_window = 0; if (Avision_Device_List [model_num].feature_type & AV_DOES_KEEP_WINDOW) dev->inquiry_keeps_window = 1; - + dev->inquiry_needs_gamma = BIT (result[50], 3); dev->inquiry_keeps_gamma = BIT (result[50], 2); if (Avision_Device_List [model_num].feature_type & AV_DOES_NOT_KEEP_GAMMA) @@ -4076,33 +4075,33 @@ get_double ( &(result[48] ) )); dev->inquiry_3x3_matrix = BIT (result[51], 1); dev->inquiry_needs_software_colorpack = BIT (result[50],5); - + dev->inquiry_needs_line_pack = BIT (result[94], 6); - + dev->inquiry_adf_need_mirror = BIT (result[51], 0); dev->inquiry_adf_bgr_order = BIT (result[93], 6); if (Avision_Device_List [model_num].feature_type & AV_ADF_BGR_ORDER_INVERT) dev->inquiry_adf_bgr_order = ! dev->inquiry_adf_bgr_order; - + dev->inquiry_light_detect = BIT (result[93], 2); dev->inquiry_light_control = BIT (result[50], 7); dev->inquiry_button_control = BIT (result[50], 6) | BIT (result[51],2); - + dev->inquiry_exposure_control = BIT(result[51],7); dev->inquiry_max_shading_target = get_double ( &(result[75]) ); - + dev->inquiry_color_boundary = result[54]; if (dev->inquiry_color_boundary == 0) dev->inquiry_color_boundary = 8; - + dev->inquiry_gray_boundary = result[55]; if (dev->inquiry_gray_boundary == 0) dev->inquiry_gray_boundary = 8; - + dev->inquiry_dithered_boundary = result[59]; if (dev->inquiry_dithered_boundary == 0) dev->inquiry_dithered_boundary = 8; - + dev->inquiry_thresholded_boundary = result[57]; if (dev->inquiry_thresholded_boundary == 0) dev->inquiry_thresholded_boundary = 8; @@ -4121,7 +4120,7 @@ get_double ( &(result[48] ) )); default: ; } - + if (dev->inquiry_new_protocol) { dev->inquiry_optical_res = get_double ( &(result[89]) ); dev->inquiry_max_res = get_double ( &(result[44]) ); @@ -4136,7 +4135,7 @@ get_double ( &(result[48] ) )); DBG (1, "Inquiry optical resolution > max_resolution, adjusting!\n"); dev->inquiry_max_res = dev->inquiry_optical_res; } - + if (dev->inquiry_optical_res == 0) { DBG (1, "Inquiry optical resolution is invalid!\n"); @@ -4151,7 +4150,7 @@ get_double ( &(result[48] ) )); DBG (1, "Inquiry max resolution is invalid, using 1200 dpi!\n"); dev->inquiry_max_res = 1200; } - + DBG (1, "attach: optical resolution set to: %d dpi\n", dev->inquiry_optical_res); DBG (1, "attach: max resolution set to: %d dpi\n", dev->inquiry_max_res); @@ -4163,7 +4162,7 @@ get_double ( &(result[48] ) )); dev->inquiry_channels_per_pixel = 3; else dev->inquiry_channels_per_pixel = 1; - + if (BIT(result[61],1)) dev->inquiry_bits_per_channel = 16; else if (BIT(result[61],2)) @@ -4192,7 +4191,7 @@ get_double ( &(result[48] ) )); if (! (dev->hw->feature_type & AV_NO_BUTTON)) dev->inquiry_buttons = result[92]; - + /* get max x/y ranges for the different modes */ { double base_dpi; /* TODO: make int */ @@ -4205,39 +4204,39 @@ get_double ( &(result[48] ) )); */ base_dpi = dev->inquiry_optical_res; } - + /* .1 to slightly increase the size to match the one of American standard paper formats that would otherwise be .1 mm too large to scan ... */ dev->inquiry_x_ranges [AV_NORMAL_DIM] = (double)get_double (&(result[81])) * MM_PER_INCH / base_dpi + .1; dev->inquiry_y_ranges [AV_NORMAL_DIM] = (double)get_double (&(result[83])) * MM_PER_INCH / base_dpi; - + dev->inquiry_x_ranges [AV_TRANSPARENT_DIM] = (double)get_double (&(result[77])) * MM_PER_INCH / base_dpi + .1; dev->inquiry_y_ranges [AV_TRANSPARENT_DIM] = (double)get_double (&(result[79])) * MM_PER_INCH / base_dpi; - + dev->inquiry_x_ranges [AV_ADF_DIM] = (double)get_double (&(result[85])) * MM_PER_INCH / base_dpi + .1; dev->inquiry_y_ranges [AV_ADF_DIM] = (double)get_double (&(result[87])) * MM_PER_INCH / base_dpi; } - + dev->inquiry_tune_scan_length = BIT(result[94],2); if (Avision_Device_List [model_num].feature_type & AV_NO_TUNE_SCAN_LENGTH) dev->inquiry_tune_scan_length = 0; dev->inquiry_background_raster = BIT(result[95],2); - + if (dev->hw->feature_type & AV_NO_BACKGROUND) dev->inquiry_background_raster = 0; - + if (dev->inquiry_background_raster) { dev->inquiry_background_raster_pixel = get_double(&(result[85])) * dev->inquiry_optical_res / AVISION_BASE_RES; } - + /* check if x/y ranges are valid :-((( */ { source_mode_dim mode; @@ -4271,7 +4270,7 @@ get_double ( &(result[48] ) )); } else { dev->inquiry_x_ranges [mode] = A4_X_RANGE * MM_PER_INCH; - + if (dev->scanner_type == AV_SHEETFEED) dev->inquiry_y_ranges [mode] = SHEETFEED_Y_RANGE * MM_PER_INCH; else @@ -4283,7 +4282,7 @@ get_double ( &(result[48] ) )); dev->inquiry_x_ranges [mode], dev->inquiry_y_ranges [mode]); } /* end for all modes */ } - + /* We need a bigger buffer for USB devices, since they seem to have a firmware bug and do not support reading the calibration data in tiny chunks */ @@ -4298,26 +4297,26 @@ get_double ( &(result[48] ) )); dev->read_stripe_size = 32; else /* tested on AV3200 with it's max of 300dpi @color */ dev->read_stripe_size = 8; /* maybe made dynamic on scan res ... */ - + /* normally the data_dq is 0x0a0d - but some newer scanner hang with it ... */ if (dev->inquiry_new_protocol) /* TODO: match on ASIC? which model hung? */ dev->data_dq = 0x0a0d; else dev->data_dq = 0; - + avision_close (&av_con); - + ++ num_devices; dev->next = first_dev; first_dev = dev; if (devp) *devp = dev; - + return SANE_STATUS_GOOD; - + close_scanner_and_return: avision_close (&av_con); - + return status; } @@ -4327,39 +4326,39 @@ get_tune_scan_length (Avision_Scanner* s) { SANE_Status status; int i; - + struct command_read rcmd; size_t size; - + struct max_value { uint8_t max [2]; } payload; - + /* turn on the light */ DBG (3, "get_tune_scan_length:\n"); memset (&rcmd, 0, sizeof (rcmd)); size = sizeof (payload); - + rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0xD2; /* Read General Ability/Parameter */ - + for (i = 1; i <= 8; ++i) { memset (&payload, 0, sizeof (payload)); - + set_double (rcmd.datatypequal, i); /* type */ set_triple (rcmd.transferlen, size); - + status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, &payload, &size); - + if (status != SANE_STATUS_GOOD) { DBG (1, "get_tune_scan_length: read %d failed (%s)\n", i, sane_strstatus (status)); return status; } DBG (1, "get_tune_scan_length: %d: %d\n", i, get_double (payload.max)); } - + return SANE_STATUS_GOOD; } @@ -4367,7 +4366,7 @@ static SANE_Status send_tune_scan_length (Avision_Scanner* s) { int top, bottom; - + SANE_Status status; size_t size; struct command_send scmd; @@ -4375,31 +4374,31 @@ send_tune_scan_length (Avision_Scanner* s) uint8_t vertical [2]; /* uint8_t horizontal [2]; not send by the Windows driver, yet */ } payload; - + DBG (3, "send_tune_scan_length:\n"); - + memset (&scmd, 0, sizeof (scmd)); - + size = sizeof (payload); scmd.opc = AVISION_SCSI_SEND; scmd.datatypecode = 0x96; /* Attach/Truncate head(left) of scan length */ set_triple (scmd.transferlen, size); - + /* the SPEC says optical DPI, but real world measuring suggests it is 1200 as in the window descriptor */ top = 1200 * SANE_UNFIX (s->val[OPT_OVERSCAN_TOP].w) / MM_PER_INCH; DBG (3, "send_tune_scan_length: top: %d\n", top); - + set_double (scmd.datatypequal, 0x0001); /* attach, 0x000 is shorten */ set_double (payload.vertical, top); /* set_double (payload.horizontal, 0); */ - + /* we alway send it, even for 0 as the scanner keeps it in RAM and previous runs could already have set something */ - + status = avision_cmd (&s->av_con, &scmd, sizeof (scmd), &payload, sizeof (payload), 0, 0); - + if (status != SANE_STATUS_GOOD) { DBG (1, "send_tune_scan_length: send top/left failed (%s)\n", sane_strstatus (status)); return status; @@ -4411,16 +4410,16 @@ send_tune_scan_length (Avision_Scanner* s) set_double (payload.vertical, bottom); /*set_double (payload.horizontal, 0); */ - + size = sizeof (payload); status = avision_cmd (&s->av_con, &scmd, sizeof (scmd), &payload, sizeof (payload), 0, 0); - + if (status != SANE_STATUS_GOOD) { DBG (1, "send_tune_scan_length: send bottom/right failed (%s)\n", sane_strstatus (status)); return status; } - + return SANE_STATUS_GOOD; } @@ -4428,10 +4427,10 @@ static SANE_Status additional_probe (Avision_Scanner* s) { Avision_Device* dev = s->hw; - + /* we should wait until the scanner is ready before we perform further actions */ - + SANE_Status status; /* try to retrieve additional accessory information */ if (dev->inquiry_detect_accessories) { @@ -4439,28 +4438,28 @@ additional_probe (Avision_Scanner* s) if (status != SANE_STATUS_GOOD) return status; } - + /* for a film scanner try to retrieve additional frame information */ if (dev->scanner_type == AV_FILM) { status = get_frame_info (s); if (status != SANE_STATUS_GOOD) return status; } - + /* no scanner did support this so far: tried on AV220, DM152 */ if (0 && dev->inquiry_duplex) { status = get_duplex_info (s); if (status != SANE_STATUS_GOOD) return status; } - + /* get overscan ("head/tail tune") information: hangs AV220, zeros on AV122 */ if (0 && dev->inquiry_tune_scan_length) { status = get_tune_scan_length (s); if (status != SANE_STATUS_GOOD) return status; } - + /* create dynamic *-mode entries */ if (!dev->inquiry_no_gray_modes) { @@ -4474,7 +4473,7 @@ additional_probe (Avision_Scanner* s) if (dev->inquiry_bits_per_channel == 12) add_color_mode (dev, AV_GRAYSCALE12, "12bit Gray"); - + if (dev->inquiry_bits_per_channel >= 16) add_color_mode (dev, AV_GRAYSCALE16, "16bit Gray"); } @@ -4484,17 +4483,17 @@ additional_probe (Avision_Scanner* s) if (dev->inquiry_bits_per_channel == 12) add_color_mode (dev, AV_TRUECOLOR12, "12bit Color"); - + if (dev->inquiry_bits_per_channel >= 16) add_color_mode (dev, AV_TRUECOLOR16, "16bit Color"); } - + /* now choose the default mode - avoiding the 12/16 bit modes */ dev->color_list_default = last_color_mode (dev); if (dev->inquiry_bits_per_channel > 8 && dev->color_list_default > 0) { dev->color_list_default--; } - + if (dev->scanner_type == AV_SHEETFEED) { add_source_mode (dev, AV_ADF, "ADF Front"); @@ -4502,20 +4501,20 @@ additional_probe (Avision_Scanner* s) else { add_source_mode (dev, AV_NORMAL, "Normal"); - + if (dev->inquiry_light_box) add_source_mode (dev, AV_TRANSPARENT, "Transparency"); - + if (dev->inquiry_adf) add_source_mode (dev, AV_ADF, "ADF Front"); } - + if (dev->inquiry_duplex) { if (dev->inquiry_duplex_interlaced && !(dev->hw->feature_type & AV_NO_REAR)) add_source_mode (dev, AV_ADF_REAR, "ADF Back"); add_source_mode (dev, AV_ADF_DUPLEX, "ADF Duplex"); } - + return SANE_STATUS_GOOD; } @@ -4523,21 +4522,21 @@ static SANE_Status get_calib_format (Avision_Scanner* s, struct calibration_format* format) { SANE_Status status; - + struct command_read rcmd; uint8_t result [32]; size_t size; - + DBG (3, "get_calib_format:\n"); size = sizeof (result); - + memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0x60; /* get calibration format */ set_double (rcmd.datatypequal, s->hw->data_dq); set_triple (rcmd.transferlen, size); - + DBG (3, "get_calib_format: read_data: %lu bytes\n", (u_long) size); status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result) ) { @@ -4545,9 +4544,9 @@ get_calib_format (Avision_Scanner* s, struct calibration_format* format) sane_strstatus (status) ); return status; } - + debug_print_calib_format (3, "get_calib_format", result); - + format->pixel_per_line = get_double (&(result[0])); format->bytes_per_channel = result[2]; format->lines = result[3]; @@ -4562,21 +4561,21 @@ get_calib_format (Avision_Scanner* s, struct calibration_format* format) format->r_dark_shading_target = get_double (&(result[15])); format->g_dark_shading_target = get_double (&(result[17])); format->b_dark_shading_target = get_double (&(result[19])); - + /* now translate to normal! */ /* firmware return R--RG--GB--B with 3 line count */ /* software format it as 1 line if true color scan */ /* only line interleave format to be supported */ - + if (color_mode_is_color (s->c_mode) || BIT(format->ability1, 3)) { format->channels = 3; format->lines /= 3; /* line interleave */ } else format->channels = 1; - + DBG (3, "get_calib_format: channels: %d\n", format->channels); - + return SANE_STATUS_GOOD; } @@ -4587,26 +4586,26 @@ get_calib_data (Avision_Scanner* s, uint8_t data_type, { SANE_Status status; uint8_t *calib_ptr; - + size_t get_size, data_size, chunk_size; - + struct command_read rcmd; - + chunk_size = calib_size; - + DBG (3, "get_calib_data: type %x, size %lu, chunk_size: %lu\n", data_type, (u_long) calib_size, (u_long) chunk_size); - + memset (&rcmd, 0, sizeof (rcmd)); - + rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = data_type; set_double (rcmd.datatypequal, s->hw->data_dq); - + calib_ptr = calib_data; get_size = chunk_size; data_size = calib_size; - + while (data_size) { if (get_size > data_size) get_size = data_size; @@ -4617,7 +4616,7 @@ get_calib_data (Avision_Scanner* s, uint8_t data_type, DBG (3, "get_calib_data: Reading %ld bytes calibration data\n", (long)get_size); - + status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, calib_ptr, &get_size); if (status != SANE_STATUS_GOOD) { @@ -4631,7 +4630,7 @@ get_calib_data (Avision_Scanner* s, uint8_t data_type, data_size -= get_size; calib_ptr += get_size; } - + return SANE_STATUS_GOOD; } @@ -4640,22 +4639,22 @@ set_calib_data (Avision_Scanner* s, struct calibration_format* format, uint8_t* dark_data, uint8_t* white_data) { Avision_Device* dev = s->hw; - + const int elements_per_line = format->pixel_per_line * format->channels; - + SANE_Status status; - + uint8_t send_type; uint16_t send_type_q; - + struct command_send scmd; - + int i; - + DBG (3, "set_calib_data:\n"); - + send_type = 0x82; /* download calibration data */ - + /* do we use a color mode? */ if (format->channels > 1) { send_type_q = 0x12; /* color calib data */ @@ -4666,40 +4665,40 @@ set_calib_data (Avision_Scanner* s, struct calibration_format* format, else send_type_q = 0x11; /* gray/bw calib data */ } - + memset (&scmd, 0x00, sizeof (scmd)); scmd.opc = AVISION_SCSI_SEND; scmd.datatypecode = send_type; - + /* data corrections due to dark calibration data merge */ if (BIT (format->ability1, 2) ) { DBG (3, "set_calib_data: merging dark calibration data\n"); for (i = 0; i < elements_per_line; ++i) { uint16_t value_orig = get_double_le (white_data + i*2); uint16_t value_new = value_orig; - + value_new &= 0xffc0; value_new |= (get_double_le (dark_data + i*2) >> 10) & 0x3f; - + DBG (9, "set_calib_data: element %d, dark difference %d\n", i, value_orig - value_new); - + set_double_le ((white_data + i*2), value_new); } } - + /* send data in one command? */ /* FR: HP5370 reports one-pass, but needs multi (or other format in single) */ if (format->channels == 1 || ( ( (dev->hw->feature_type & AV_ONE_CALIB_CMD) || - ! BIT(format->ability1, 0) ) && + ! BIT(format->ability1, 0) ) && ! (dev->hw->feature_type & AV_MULTI_CALIB_CMD) ) ) /* one command (most scanners) */ { size_t send_size = elements_per_line * 2; DBG (3, "set_calib_data: all channels in one command\n"); DBG (3, "set_calib_data: send_size: %lu\n", (u_long) send_size); - + memset (&scmd, 0, sizeof (scmd) ); scmd.opc = AVISION_SCSI_SEND; scmd.datatypecode = send_type; @@ -4715,9 +4714,9 @@ set_calib_data (Avision_Scanner* s, struct calibration_format* format, int conv_out_size = format->pixel_per_line * 2; uint16_t* conv_out_data; /* here it is save to use 16bit data since we only move whole words around */ - + DBG (3, "set_calib_data: channels in single commands\n"); - + conv_out_data = (uint16_t*) malloc (conv_out_size); if (!conv_out_data) { status = SANE_STATUS_NO_MEM; @@ -4727,24 +4726,24 @@ set_calib_data (Avision_Scanner* s, struct calibration_format* format, for (channel = 0; channel < 3; ++ channel) { int i; - + /* no need for endianness handling since whole word copy */ uint16_t* casted_avg_data = (uint16_t*) white_data; - + DBG (3, "set_calib_data_calibration: channel: %i\n", channel); - + for (i = 0; i < format->pixel_per_line; ++ i) conv_out_data [i] = casted_avg_data [i * 3 + channel]; - + DBG (3, "set_calib_data: sending %i bytes now\n", conv_out_size); - + memset (&scmd, 0, sizeof (scmd)); scmd.opc = AVISION_SCSI_SEND; scmd.datatypecode = send_type; /* send calibration data */ set_double (scmd.datatypequal, channel); set_triple (scmd.transferlen, conv_out_size); - + status = avision_cmd (&s->av_con, &scmd, sizeof (scmd), conv_out_data, conv_out_size, 0, 0); if (status != SANE_STATUS_GOOD) { @@ -4756,14 +4755,14 @@ set_calib_data (Avision_Scanner* s, struct calibration_format* format, free (conv_out_data); } /* end else send calib data*/ } - + return SANE_STATUS_GOOD; } /* Sort data pixel by pixel and average first 2/3 of the data. The caller has to free return pointer. R,G,B pixels interleave to R,G,B line interleave. - + The input data data is in 16 bits little endian, always. That is a = b[1] << 8 + b[0] in all system. @@ -4776,34 +4775,34 @@ sort_and_average (struct calibration_format* format, uint8_t* data) const int elements_per_line = format->pixel_per_line * format->channels; const int stride = format->bytes_per_channel * elements_per_line; int i, line; - + uint8_t *sort_data, *avg_data; - + DBG (1, "sort_and_average:\n"); - + if (!format || !data) return NULL; - + sort_data = malloc (format->lines * 2); if (!sort_data) return NULL; - + avg_data = malloc (elements_per_line * 2); if (!avg_data) { free (sort_data); return NULL; } - + /* for each pixel */ for (i = 0; i < elements_per_line; ++ i) { uint8_t* ptr1 = data + i * format->bytes_per_channel; uint16_t temp; - + /* copy all lines for pixel i into the linear array sort_data */ for (line = 0; line < format->lines; ++ line) { uint8_t* ptr2 = ptr1 + line * stride; /* pixel */ - + if (format->bytes_per_channel == 1) temp = 0xffff * *ptr2 / 255; else @@ -4811,12 +4810,12 @@ sort_and_average (struct calibration_format* format, uint8_t* data) set_double ((sort_data + line*2), temp); /* store big-endian */ /* DBG (7, "ReneR to sort: %x\n", temp); */ } - + temp = bubble_sort (sort_data, format->lines); /* DBG (7, "ReneR averaged: %x\n", temp); */ set_double ((avg_data + i*2), temp); /* store big-endian */ } - + free ((void *) sort_data); return avg_data; } @@ -4828,28 +4827,28 @@ compute_dark_shading_data (Avision_Scanner* s, { uint16_t map_value = DEFAULT_DARK_SHADING; uint16_t rgb_map_value[3]; - + int elements_per_line, i; - + DBG (3, "compute_dark_shading_data:\n"); - + if (s->hw->inquiry_max_shading_target != INVALID_DARK_SHADING) map_value = s->hw->inquiry_max_shading_target << 8; - + rgb_map_value[0] = format->r_dark_shading_target; rgb_map_value[1] = format->g_dark_shading_target; rgb_map_value[2] = format->b_dark_shading_target; - + for (i = 0; i < format->channels; ++i) { if (rgb_map_value[i] == INVALID_DARK_SHADING) rgb_map_value[i] = map_value; } - + if (format->channels == 1) { /* set to green, TODO: should depend on color drop-out and true-gray -ReneR */ rgb_map_value[0] = rgb_map_value[1] = rgb_map_value[2] = rgb_map_value[1]; } - + elements_per_line = format->pixel_per_line * format->channels; /* Check line interleave or pixel interleave. */ @@ -4874,22 +4873,22 @@ compute_white_shading_data (Avision_Scanner* s, int i; uint16_t inquiry_mst = DEFAULT_WHITE_SHADING; uint16_t mst[3]; - + int elements_per_line = format->pixel_per_line * format->channels; - + /* debug counter */ int values_invalid = 0; int values_limitted = 0; - + DBG (3, "compute_white_shading_data:\n"); - + if (s->hw->inquiry_max_shading_target != INVALID_WHITE_SHADING) inquiry_mst = s->hw->inquiry_max_shading_target << 4; - + mst[0] = format->r_shading_target; mst[1] = format->g_shading_target; mst[2] = format->b_shading_target; - + for (i = 0; i < 3; ++i) { if (mst[i] == INVALID_WHITE_SHADING) /* mst[i] > MAX_WHITE_SHADING) */ { DBG (3, "compute_white_shading_data: target %d invalid (%x) using inquiry (%x)\n", @@ -4913,7 +4912,7 @@ compute_white_shading_data (Avision_Scanner* s, else DBG (3, "compute_white_shading_data: target %d: %x\n", i, mst[0]); } - + /* some Avision example code was present here until SANE/Avision * BUILD 57. */ @@ -4921,31 +4920,31 @@ compute_white_shading_data (Avision_Scanner* s, /* set to green, TODO: should depend on color drop-out and true-gray -ReneR */ mst[0] = mst[1] = mst[2] = mst[1]; } - + /* calculate calibration data */ for (i = 0; i < elements_per_line; ++ i) { int result; /* calculate calibration value for pixel i */ uint16_t tmp_data = get_double((data + i*2)); - + if (tmp_data == INVALID_WHITE_SHADING) { tmp_data = DEFAULT_WHITE_SHADING; ++ values_invalid; } - + result = ( (int)mst[i % 3] * WHITE_MAP_RANGE / (tmp_data + 0.5)); - + /* sanity check for over-amplification, clipping */ if (result > MAX_WHITE_SHADING) { result = WHITE_MAP_RANGE; ++ values_limitted; } - + /* for visual debugging ... */ if (static_calib_list [i % 3] == SANE_TRUE) result = 0xA000; - + /* the output to the scanner will be 16 bit little endian again */ set_double_le ((data + i*2), result); } @@ -4959,20 +4958,20 @@ static SANE_Status normal_calibration (Avision_Scanner* s) { SANE_Status status; - + struct calibration_format calib_format; - + int calib_data_size, calib_bytes_per_line; uint8_t read_type; uint8_t *calib_tmp_data; - + DBG (1, "normal_calibration:\n"); - + /* get calibration format and data */ status = get_calib_format (s, &calib_format); if (status != SANE_STATUS_GOOD) return status; - + /* check if need do calibration */ if (calib_format.flags != 1) { DBG (1, "normal_calibration: Scanner claims no calibration needed -> skipped!\n"); @@ -4983,27 +4982,27 @@ normal_calibration (Avision_Scanner* s) /* size = lines * bytes_per_channel * pixels_per_line * channel */ calib_bytes_per_line = calib_format.bytes_per_channel * calib_format.pixel_per_line * calib_format.channels; - + calib_data_size = calib_format.lines * calib_bytes_per_line; - + calib_tmp_data = malloc (calib_data_size); if (!calib_tmp_data) return SANE_STATUS_NO_MEM; - + /* check if we need to do dark calibration (shading) */ if (BIT(calib_format.ability1, 3)) { DBG (1, "normal_calibration: reading dark data\n"); /* read dark calib data */ status = get_calib_data (s, 0x66, calib_tmp_data, calib_data_size); - + if (status != SANE_STATUS_GOOD) { free (calib_tmp_data); return status; } - + /* process dark data: sort and average. */ - + if (s->dark_avg_data) { free (s->dark_avg_data); s->dark_avg_data = 0; @@ -5015,7 +5014,7 @@ normal_calibration (Avision_Scanner* s) } compute_dark_shading_data (s, &calib_format, s->dark_avg_data); } - + /* do we use a color mode? */ if (calib_format.channels > 1) { DBG (3, "normal_calibration: using color calibration\n"); @@ -5025,15 +5024,15 @@ normal_calibration (Avision_Scanner* s) DBG (3, "normal_calibration: using gray calibration\n"); read_type = 0x61; /* gray calib data */ } - + /* do white calibration: read gray or color data */ status = get_calib_data (s, read_type, calib_tmp_data, calib_data_size); - + if (status != SANE_STATUS_GOOD) { free (calib_tmp_data); return status; } - + if (0) /* debug */ { FILE* f = NULL; @@ -5041,11 +5040,11 @@ normal_calibration (Avision_Scanner* s) write_pnm_header (f, AV_GRAYSCALE, calib_format.bytes_per_channel * 8, calib_format.pixel_per_line, calib_format.lines * calib_format.channels); - + fwrite (calib_tmp_data, 1, calib_data_size, f); fclose (f); } - + if (s->white_avg_data) { free (s->white_avg_data); s->white_avg_data = 0; @@ -5055,24 +5054,24 @@ normal_calibration (Avision_Scanner* s) free (calib_tmp_data); return SANE_STATUS_NO_MEM; } - + /* decrease white average data (if dark average data is present) */ if (s->dark_avg_data) { int elements_per_line = calib_format.pixel_per_line * calib_format.channels; int i; DBG (1, "normal_calibration: dark data present - decreasing white average data\n"); - + for (i = 0; i < elements_per_line; ++ i) { s->white_avg_data[i] -= s->dark_avg_data[i]; } } - + compute_white_shading_data (s, &calib_format, s->white_avg_data); - + status = set_calib_data (s, &calib_format, s->dark_avg_data, s->white_avg_data); - + free (calib_tmp_data); return status; } @@ -5080,12 +5079,12 @@ normal_calibration (Avision_Scanner* s) /* next was taken from the GIMP and is a bit modified ... ;-) * original Copyright (C) 1995 Spencer Kimball and Peter Mattis */ -static double +static double brightness_contrast_func (double brightness, double contrast, double value) { double nvalue; double power; - + /* apply brightness */ if (brightness < 0.0) value = value * (1.0 + brightness); @@ -5130,28 +5129,28 @@ send_gamma (Avision_Scanner* s) { Avision_Device* dev = s->hw; SANE_Status status = SANE_STATUS_GOOD; - + int invert_table = 0; - + size_t gamma_table_raw_size; size_t gamma_table_size; size_t gamma_values; - + struct command_send scmd; uint8_t *gamma_data; - + int color; /* current color */ size_t i; /* big table index */ size_t j; /* little table index */ size_t k; /* big table sub index */ double v1, v2; - + double brightness; double contrast; - + if (dev->inquiry_asic_type != AV_ASIC_OA980) invert_table = (s->c_mode == AV_THRESHOLDED) || (s->c_mode == AV_DITHERED); - + switch (dev->inquiry_asic_type) { case AV_ASIC_Cx: @@ -5176,37 +5175,37 @@ send_gamma (Avision_Scanner* s) gamma_table_raw_size = 512; /* SPEC claims: 256 ... ? */ gamma_table_size = 512; } - + gamma_values = gamma_table_size / 256; - + DBG (3, "send_gamma: table_raw_size: %lu, table_size: %lu\n", (u_long) gamma_table_raw_size, (u_long) gamma_table_size); DBG (3, "send_gamma: values: %lu, invert_table: %d\n", (u_long) gamma_values, invert_table); - + /* prepare for emulating contrast, brightness ... via the gamma-table */ brightness = SANE_UNFIX (s->val[OPT_BRIGHTNESS].w); brightness /= 100; contrast = SANE_UNFIX (s->val[OPT_CONTRAST].w); contrast /= 100; - + DBG (3, "send_gamma: brightness: %f, contrast: %f\n", brightness, contrast); - + gamma_data = malloc (gamma_table_raw_size); if (!gamma_data) return SANE_STATUS_NO_MEM; - + memset (&scmd, 0, sizeof (scmd) ); - + scmd.opc = AVISION_SCSI_SEND; scmd.datatypecode = 0x81; /* 0x81 for download gamma table */ set_triple (scmd.transferlen, gamma_table_raw_size); - + for (color = 0; color < 3 && status == SANE_STATUS_GOOD; ++ color) { /* color: 0=red; 1=green; 2=blue */ set_double (scmd.datatypequal, color); - + i = 0; /* big table index */ for (j = 0; j < 256; ++ j) /* little table index */ { @@ -5237,21 +5236,21 @@ send_gamma (Avision_Scanner* s) v2 = (double) s->gamma_table [0][j + 1]; } } /*end switch */ - + /* Emulate brightness and contrast (at least the Avision AV6[2,3]0 * as well as many others do not have a hardware implementation, * --$. The function was taken from the GIMP source - maybe I'll * optimize it in the future (when I have spare time). */ - + v1 /= 255; v2 /= 255; - + v1 = (brightness_contrast_func (brightness, contrast, v1) ); v2 = (brightness_contrast_func (brightness, contrast, v2) ); - + v1 *= 255; v2 *= 255; - + if (invert_table) { v1 = 255 - v1; v2 = 255 - v2; @@ -5260,7 +5259,7 @@ send_gamma (Avision_Scanner* s) if (v2 <= 0) v2 = 0; } - + for (k = 0; k < gamma_values; ++ k, ++ i) { gamma_data [i] = (uint8_t) (((v1 * (gamma_values - k)) + (v2 * k) ) / (double) gamma_values); @@ -5275,12 +5274,12 @@ send_gamma (Avision_Scanner* s) gamma_data [i] = gamma_data [t_i]; } } - + DBG (4, "send_gamma: sending %lu bytes gamma table.\n", (u_long) gamma_table_raw_size); status = avision_cmd (&s->av_con, &scmd, sizeof (scmd), gamma_data, gamma_table_raw_size, 0, 0); - + if (status != SANE_STATUS_GOOD) { DBG (1, "send_gamma: gamma table upload failed: %s\n", sane_strstatus (status)); @@ -5294,33 +5293,33 @@ static SANE_Status send_3x3_matrix (Avision_Scanner* s) { SANE_Status status; - + #define SIGN_BIT 0x1000 #define INT_PART 10 - + struct matrix_cmd { struct command_send scmd; struct matrix_3x3 matrix; } cmd; - - /* 04 00 00 00 00 00 + + /* 04 00 00 00 00 00 00 00 04 00 00 00 00 00 00 00 04 00 */ - + int i, a_i; static const double c5_matrix[] = { 1.000, 0.000, 0.000, 0.000, 1.000, 0.000, 0.000, 0.000, 1.000 }; - + double a_f, b_f; uint16_t m; - + DBG (3, "send_3x3_matrix:\n"); - + memset (&cmd, 0, sizeof (cmd)); - + for (i = 0; i < 9; i++) { m = 0; @@ -5329,18 +5328,18 @@ send_3x3_matrix (Avision_Scanner* s) m |= SIGN_BIT; a_f = -a_f; } - + a_i = (int) a_f; /* integer */ b_f = a_f - (double) a_i; /* float */ m |= ((a_i & 0x3) << INT_PART); m |= (uint16_t) (b_f * 1024); set_double (((uint8_t*)(&cmd.matrix.v[i])), m); } - + cmd.scmd.opc = AVISION_SCSI_SEND; cmd.scmd.datatypecode = 0x83; /* 0x83 for 3x3 color matrix */ set_triple (cmd.scmd.transferlen, sizeof (struct matrix_3x3)); - + if (1) { DBG (3, "send_3x3_matrix: sending matrix split into two commands\n"); status = avision_cmd (&s->av_con, &cmd.scmd, sizeof (cmd.scmd), @@ -5350,7 +5349,7 @@ send_3x3_matrix (Avision_Scanner* s) DBG (3, "send_3x3_matrix: sending matrix in one command\n"); status = avision_cmd (&s->av_con, &cmd, sizeof (cmd), 0, 0, 0, 0); } - + return status; } @@ -5358,21 +5357,21 @@ static SANE_Status get_acceleration_info (Avision_Scanner* s, struct acceleration_info* info) { SANE_Status status; - + struct command_read rcmd; uint8_t result [24]; size_t size; - + DBG (3, "get_acceleration_info:\n"); size = sizeof (result); - + memset (&rcmd, 0, sizeof (rcmd)); rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0x6c; /* get acceleration information */ set_double (rcmd.datatypequal, s->hw->data_dq); set_triple (rcmd.transferlen, size); - + DBG (3, "get_acceleration_info: read_data: %lu bytes\n", (u_long) size); status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, result, &size); if (status != SANE_STATUS_GOOD || size != sizeof (result) ) { @@ -5380,9 +5379,9 @@ get_acceleration_info (Avision_Scanner* s, struct acceleration_info* info) sane_strstatus (status) ); return status; } - + debug_print_accel_info (3, "get_acceleration_info", result); - + info->total_steps = get_double (&(result[0])); info->stable_steps = get_double (&(result[2])); info->table_units = get_quad (&(result[4])); @@ -5391,7 +5390,7 @@ get_acceleration_info (Avision_Scanner* s, struct acceleration_info* info) info->target_speed = get_double (&(result[14])); info->ability = result[16]; info->table_count = result[17]; - + return SANE_STATUS_GOOD; } @@ -5399,45 +5398,45 @@ static SANE_Status send_acceleration_table (Avision_Scanner* s) { SANE_Status status; - + struct command_send scmd; int table = 0; int i; struct acceleration_info accel_info = accel_info; uint8_t* table_data; - + DBG (3, "send_acceleration_table:\n"); do { status = get_acceleration_info (s, &accel_info); - + if (accel_info.table_count == 0) { DBG (3, "send_acceleration_table: device does not need tables\n"); return SANE_STATUS_GOOD; } - + if (accel_info.target_speed > accel_info.start_speed || accel_info.target_speed == 0 || accel_info.total_steps <= accel_info.stable_steps) { DBG (1, "send_acceleration_table: table does not look right.\n"); return SANE_STATUS_INVAL; } - + if (accel_info.ability != 0) { DBG (1, "send_acceleration_table: ability non-zero - insert code\n"); return SANE_STATUS_INVAL; } - + /* so far I assume we have one byte tables as used in the C6 ASIC ... */ table_data = malloc (accel_info.total_steps + 1000); - + memset (&scmd, 0x00, sizeof (scmd)); scmd.opc = AVISION_SCSI_SEND; scmd.datatypecode = 0x6c; /* send acceleration table */ - + set_double (scmd.datatypequal, table); set_triple (scmd.transferlen, accel_info.total_steps); - + /* construct the table - Warning: This code is derived from Avision sample code and is a bit scary! I have no idea why the scanner needs such a dumb table and also do not know /why/ it has to be @@ -5447,16 +5446,16 @@ send_acceleration_table (Avision_Scanner* s) float up_lim = 1.0; uint16_t accel_steps = accel_info.total_steps - accel_info.stable_steps + 1; - + /* acceleration ramp */ while ((up_lim - low_lim) > 0.0001) { float mid = (up_lim + low_lim) / 2; /* accel rate */ - + uint16_t now_count = accel_info.start_speed; - + uint16_t i = 0; - + float now_count_f = now_count; table_data [i++] = (uint8_t) accel_info.start_speed; @@ -5467,8 +5466,8 @@ send_acceleration_table (Avision_Scanner* s) now_count = (uint16_t)(now_count_f + 0.5); table_data[i++] = (uint8_t) now_count; } - - + + if (i == accel_steps) break; if (i > accel_steps) @@ -5476,23 +5475,23 @@ send_acceleration_table (Avision_Scanner* s) else up_lim = mid; } - + /* fill stable steps */ for (i = accel_steps; i < accel_info.total_steps; i++) table_data [i] = table_data [i-1]; - + debug_print_hex_raw (5, "send_acceleration_table: first pass:\n", table_data, accel_info.total_steps); - + /* maybe post fix-up */ { int add_count; - + /* count total steps in table */ int table_total = 0; for (i = 0; i < accel_info.total_steps; i++) table_total += table_data [i]; - + i = 0; if (((table_total * accel_info.table_units) % accel_info.base_units) == 0) add_count = 0; @@ -5500,7 +5499,7 @@ send_acceleration_table (Avision_Scanner* s) add_count = (accel_info.base_units - ((table_total*accel_info.table_units) % accel_info.base_units)) / accel_info.table_units; - + /* add_count should not be bigger than 255 */ if (add_count > 255) { DBG (1, "send_acceleration_table: add_count limited, was: %d\n", add_count); @@ -5510,26 +5509,26 @@ send_acceleration_table (Avision_Scanner* s) { uint16_t temp_count = 255 - table_data [i]; temp_count = temp_count > add_count ? add_count : temp_count; - + table_data [i] += (uint8_t) temp_count; add_count -= temp_count; } } } - + debug_print_hex_raw (5, "send_acceleration_table: fixed up:\n", table_data, accel_info.total_steps); - + /* decrease all by one ... */ for (i = 0; i < accel_info.total_steps; i++) { table_data[i]--; } - + DBG (1, "send_acceleration_table: sending table %d\n", table); - + debug_print_hex_raw (5, "send_acceleration_table: final:\n", table_data, accel_info.total_steps); - + status = avision_cmd (&s->av_con, &scmd, sizeof (scmd), (char*) table_data, accel_info.total_steps, 0, 0); @@ -5537,13 +5536,13 @@ send_acceleration_table (Avision_Scanner* s) DBG (3, "send_acceleration_table: send_data failed (%s)\n", sane_strstatus (status)); } - + free (table_data); table_data = 0; - + table++; } while (table < accel_info.table_count); - - + + return status; } @@ -5555,17 +5554,17 @@ set_window (Avision_Scanner* s) int base_dpi_abs, base_dpi_rel; int transferlen; int paralen; - + int bytes_per_line; int line_count; - + struct { struct command_set_window cmd; struct command_set_window_window window; } cmd; - + DBG (1, "set_window:\n"); - + /* plain old scanners, the C3 ASIC HP 53xx and the C6 ASIC HP 74xx and up do use 1200 as base - only the C5 differs */ switch (dev->inquiry_asic_type) { @@ -5582,64 +5581,64 @@ set_window (Avision_Scanner* s) base_dpi_abs = 1200; base_dpi_rel = 1200; } - + DBG (2, "set_window: base_dpi_abs: %d, base_dpi_rel: %d\n", base_dpi_abs, base_dpi_rel); - + /* wipe out anything */ memset (&cmd, 0, sizeof (cmd) ); cmd.window.descriptor.winid = AV_WINID; /* normally defined to be zero */ - + /* optional parameter length to use */ paralen = sizeof (cmd.window.avision) - sizeof (cmd.window.avision.type); - + DBG (2, "set_window: base paralen: %d\n", paralen); - + if (dev->hw->feature_type & AV_FUJITSU) paralen += sizeof (cmd.window.avision.type.fujitsu); else if (!dev->inquiry_new_protocol) paralen += sizeof (cmd.window.avision.type.old); else paralen += sizeof (cmd.window.avision.type.normal); - + DBG (2, "set_window: final paralen: %d\n", paralen); - + transferlen = sizeof (cmd.window) - sizeof (cmd.window.avision) + paralen; - + DBG (2, "set_window: transferlen: %d\n", transferlen); - + /* command setup */ cmd.cmd.opc = AVISION_SCSI_SET_WINDOW; set_triple (cmd.cmd.transferlen, transferlen); set_double (cmd.window.header.desclen, sizeof (cmd.window.descriptor) + paralen); - + /* resolution parameters */ set_double (cmd.window.descriptor.xres, s->avdimen.hw_xres); set_double (cmd.window.descriptor.yres, s->avdimen.hw_yres); - + /* upper left corner x/y as well as width/length in inch * base_dpi - avdimen are world pixels */ set_quad (cmd.window.descriptor.ulx, s->avdimen.tlx * base_dpi_abs / s->avdimen.hw_xres); set_quad (cmd.window.descriptor.uly, s->avdimen.tly * base_dpi_abs / s->avdimen.hw_yres); - + set_quad (cmd.window.descriptor.width, s->avdimen.hw_pixels_per_line * base_dpi_rel / s->avdimen.hw_xres + 1); line_count = s->avdimen.hw_lines + 2 * s->avdimen.line_difference + s->avdimen.rear_offset; set_quad (cmd.window.descriptor.length, line_count * base_dpi_rel / s->avdimen.hw_yres + 1); - + /* interlaced duplex scans are twice as long */ if (s->avdimen.interlaced_duplex && dev->scanner_type != AV_FILM) { DBG (2, "set_window: interlaced duplex scan, doubled line count\n"); line_count *= 2; } - + bytes_per_line = s->avdimen.hw_bytes_per_line; - + set_double (cmd.window.avision.line_width, bytes_per_line); set_double (cmd.window.avision.line_count, line_count); - + /* here go the most significant bits if bigger than 16 bit */ if (dev->inquiry_new_protocol && !(dev->hw->feature_type & AV_FUJITSU) ) { DBG (2, "set_window: large data-transfer support (>16bit)!\n"); @@ -5648,16 +5647,16 @@ set_window (Avision_Scanner* s) cmd.window.avision.type.normal.line_count_msb = line_count >> 16; } - + if (dev->inquiry_background_raster) cmd.window.avision.type.normal.background_lines = s->val[OPT_BACKGROUND].w; - + /* scanner should use our line-width and count */ - SET_BIT (cmd.window.avision.bitset1, 6); - + SET_BIT (cmd.window.avision.bitset1, 6); + /* set speed */ cmd.window.avision.bitset1 |= s->val[OPT_SPEED].w & 0x07; /* only 3 bit */ - + /* ADF scan? */ DBG (3, "set_window: source mode %d source mode dim %d\n", s->source_mode, s->source_mode_dim); @@ -5687,43 +5686,43 @@ set_window (Avision_Scanner* s) SET_BIT(cmd.window.avision.type.normal.bitset3, 2); /* MIRR 0x04 */ } } - + if (s->val[OPT_PAPERLEN].w != SANE_FALSE) { set_double (cmd.window.descriptor.paper_length, (int)((double)30.0*1200)); } if ( !(dev->hw->feature_type & AV_FUJITSU) ) - { + { /* quality scan option switch */ if (s->val[OPT_QSCAN].w == SANE_TRUE) { SET_BIT (cmd.window.avision.type.normal.bitset2, 4); } - + /* quality calibration option switch (inverted! if set == speed) */ if (s->val[OPT_QCALIB].w == SANE_FALSE) { SET_BIT (cmd.window.avision.type.normal.bitset2, 3); } - + /* transparency option switch */ if (s->source_mode_dim == AV_TRANSPARENT_DIM) { SET_BIT (cmd.window.avision.type.normal.bitset2, 7); } - + if (dev->scanner_type == AV_FILM) { /* TODO: wire to IR exposure option? */ cmd.window.avision.type.normal.ir_exposure_time = 100; set_double (cmd.window.avision.type.normal.r_exposure_time, s->val[OPT_EXPOSURE].w); set_double (cmd.window.avision.type.normal.g_exposure_time, s->val[OPT_EXPOSURE].w); set_double (cmd.window.avision.type.normal.b_exposure_time, s->val[OPT_EXPOSURE].w); - + if (s->val[OPT_IR].w) cmd.window.avision.type.normal.bitset3 |= (1 << 0); - + if (s->val[OPT_MULTISAMPLE].w) cmd.window.avision.type.normal.bitset3 |= (1 << 1); } } - + /* fixed values */ cmd.window.descriptor.padding_and_bitset = 3; cmd.window.descriptor.vendor_specific = 0xFF; @@ -5732,7 +5731,7 @@ set_window (Avision_Scanner* s) /* This is normally unsupported by Avision scanners, and we do this via the gamma table - which works for all devices ... */ cmd.window.descriptor.threshold = 128; - cmd.window.descriptor.brightness = 128; + cmd.window.descriptor.brightness = 128; cmd.window.descriptor.contrast = 128; cmd.window.avision.highlight = 0xFF; cmd.window.avision.shadow = 0x00; @@ -5744,17 +5743,17 @@ set_window (Avision_Scanner* s) cmd.window.descriptor.bpc = 1; cmd.window.descriptor.image_comp = 0; break; - + case AV_DITHERED: cmd.window.descriptor.bpc = 1; cmd.window.descriptor.image_comp = 1; break; - + case AV_GRAYSCALE: cmd.window.descriptor.bpc = 8; cmd.window.descriptor.image_comp = 2; break; - + case AV_GRAYSCALE12: cmd.window.descriptor.bpc = 12; cmd.window.descriptor.image_comp = 2; @@ -5764,7 +5763,7 @@ set_window (Avision_Scanner* s) cmd.window.descriptor.bpc = 16; cmd.window.descriptor.image_comp = 2; break; - + case AV_TRUECOLOR: cmd.window.descriptor.bpc = 8; cmd.window.descriptor.image_comp = 5; @@ -5779,7 +5778,7 @@ set_window (Avision_Scanner* s) cmd.window.descriptor.bpc = 16; cmd.window.descriptor.image_comp = 5; break; - + default: DBG (1, "Invalid mode. %d\n", s->c_mode); return SANE_STATUS_INVAL; @@ -5796,13 +5795,13 @@ set_window (Avision_Scanner* s) else cmd.window.avision.bitset1 |= AVISION_FILTER_NONE; } - + debug_print_window_descriptor (5, "set_window", &(cmd.window)); - + DBG (3, "set_window: sending command. Bytes: %d\n", transferlen); status = avision_cmd (&s->av_con, &cmd, sizeof (cmd.cmd), &(cmd.window), transferlen, 0, 0); - + return status; } @@ -5813,13 +5812,13 @@ get_background_raster (Avision_Scanner* s) Avision_Device* dev = s->hw; SANE_Status status; - + struct command_read rcmd; size_t size; int bytes_per_line, i; const int bpp = color_mode_is_color (s->c_mode) ? 3 : 1; const int lines = s->val[OPT_BACKGROUND].w * (s->avdimen.interlaced_duplex ? 2 : 1); - + uint8_t* background = NULL; DBG (1, "get_background_raster:\n"); @@ -5828,20 +5827,20 @@ get_background_raster (Avision_Scanner* s) DBG (1, "get_background_raster: no background requested\n"); return SANE_STATUS_GOOD; } - + /* full width, always :-(, duplex *2 for front and rear */ bytes_per_line = dev->inquiry_background_raster_pixel * s->avdimen.hw_xres / dev->inquiry_optical_res; bytes_per_line *= bpp; - + DBG (3, "get_background_raster: native raster pixels: %d, raster bytes_per_line: %d\n", dev->inquiry_background_raster_pixel, bytes_per_line); - + /* according to spec only 8-bit gray or color, TODO: test for bi-level scans */ size = bytes_per_line * lines; DBG (3, "get_background_raster: buffer size: %ld\n", (long)size); - + background = s->background_raster = realloc (s->background_raster, size); if (!background) return SANE_STATUS_NO_MEM; @@ -5850,13 +5849,13 @@ get_background_raster (Avision_Scanner* s) rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0x9b; /* get background raster */ set_double (rcmd.datatypequal, s->hw->data_dq); - + /* Ok, well - this part is very messy. The AV122 and DM152 appear to contain differently buggy ASICs. The only combination I found to at least get a correct front raster out of them is to read it line by line and then every second line appears to be valid front data, ... */ - + /* read the raster data */ for (i = 0; i < lines;) { @@ -5864,7 +5863,7 @@ get_background_raster (Avision_Scanner* s) /* read stripe by stripe, or all in one chunk */ size_t this_read, read_size; int this_lines; - + if (dev->hw->feature_type & AV_2ND_LINE_INTERLACED) { if (dev->hw->feature_type & AV_BACKGROUND_QUIRK) this_lines = 1; @@ -5875,12 +5874,12 @@ get_background_raster (Avision_Scanner* s) this_lines = s->val[OPT_BACKGROUND].w; } this_read = bytes_per_line * this_lines; - + DBG (3, "get_background_raster: line: %d, lines: %d, %lu bytes\n", i, this_lines, (u_long) this_read); set_triple (rcmd.transferlen, this_read); - + read_size = this_read; status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, dst_raster, &read_size); if (status != SANE_STATUS_GOOD || read_size != this_read) { @@ -5888,29 +5887,29 @@ get_background_raster (Avision_Scanner* s) sane_strstatus (status) ); return status; } - + i += this_lines; } - + /* dump raw result while debugging */ if (debug) { FILE* f = NULL; f = fopen ("background-raw.pnm", "w"); - + write_pnm_header (f, (color_mode_is_color (s->c_mode) ? AV_TRUECOLOR : AV_GRAYSCALE), 8, bytes_per_line / bpp, lines); - + fwrite (background, 1, bytes_per_line * lines, f); fclose (f); } /* line-pack - move to unified processing flow, later */ if (dev->inquiry_needs_line_pack) - { + { /* TODO: add 16bit per sample code? */ int l, p; - + uint8_t* tmp_data = malloc (bytes_per_line); for (l = 0; l < lines; ++l) { @@ -5918,47 +5917,47 @@ get_background_raster (Avision_Scanner* s) uint8_t* r_ptr = background + (bytes_per_line * l); uint8_t* g_ptr = r_ptr + bytes_per_line / bpp; uint8_t* b_ptr = g_ptr + bytes_per_line / bpp; - + for (p = 0; p < bytes_per_line;) { out_data [p++] = *(r_ptr++); out_data [p++] = *(g_ptr++); out_data [p++] = *(b_ptr++); } - + memcpy (background + (bytes_per_line * l), tmp_data, bytes_per_line); } - + free (tmp_data); } /* end line pack */ - + /* deinterlace? */ if (s->avdimen.interlaced_duplex && dev->hw->feature_type & AV_2ND_LINE_INTERLACED) { uint8_t* deinterlaced = malloc (size * 2); if (!deinterlaced) return SANE_STATUS_NO_MEM; - + for (i = 0; i < lines; ++i) { int dst_i = i / 2 + (i % 2) * (lines / 2); uint8_t* dst_raster; /* just no C99 in SANE :-( */ uint8_t* src_raster; - + /* for the quirky devices and some resolutions the interlacing differs */ if (dev->hw->feature_type & AV_BACKGROUND_QUIRK && s->avdimen.hw_xres >= 150) dst_i = i / 2 + ((i+1) % 2) * (lines / 2); - + dst_raster = deinterlaced + bytes_per_line * dst_i; src_raster = background + bytes_per_line * i; - + DBG(3, "get_background_raster: deinterlaced %d -> %d\n", i, dst_i); memcpy(dst_raster, src_raster, bytes_per_line); } - + free (background); background = s->background_raster = deinterlaced; } - + /* dump raw result while debugging */ for (i = 0; debug && i < (s->avdimen.interlaced_duplex ? 2 : 1); ++i) { @@ -5971,14 +5970,14 @@ get_background_raster (Avision_Scanner* s) f = fopen ("background-rear.pnm", "w"); raster += bytes_per_line * s->val[OPT_BACKGROUND].w; } - + write_pnm_header (f, (color_mode_is_color (s->c_mode) ? AV_TRUECOLOR : AV_GRAYSCALE), 8, bytes_per_line / bpp, s->val[OPT_BACKGROUND].w); - + fwrite (raster, 1, bytes_per_line * s->val[OPT_BACKGROUND].w, f); fclose (f); } - + /* crop from full-width scanlines to scan window */ { uint8_t *dst_ptr, *src_ptr; @@ -5991,19 +5990,19 @@ get_background_raster (Avision_Scanner* s) src_ptr += bytes_per_line; } } - + /* soft-scale - move to unified processing flow, later */ if (s->avdimen.hw_xres != s->avdimen.xres) { const uint8_t* out_data = background; uint8_t* dst = background; - + int l; for (l = 0; l < lines; ++l) { const int hwbpl = s->avdimen.hw_bytes_per_line; const int sy = l; - + int x; for (x = 0; x < s->params.pixels_per_line; ++x) { @@ -6011,24 +6010,24 @@ get_background_raster (Avision_Scanner* s) const int sx = (int)floor(bx); const int xdist = (int) ((bx - sx) * 256); const int sxx = sx + 1; - + switch (bpp) { case 1: { - uint8_t v = + uint8_t v = ( out_data [sy*hwbpl + sx ] * (256-xdist) + out_data [sy*hwbpl + sxx] * xdist ) / (256); *dst++ = v; } break; - + case 3: { int c; for (c = 0; c < 3; ++c) { - uint8_t v = + uint8_t v = ( out_data [sy*hwbpl + sx*3 + c] * (256-xdist) + out_data [sy*hwbpl + sxx*3 + c] * xdist ) / (256); @@ -6040,7 +6039,7 @@ get_background_raster (Avision_Scanner* s) } } } - + /* dump final result while debugging */ if (debug) { for (i = 0; i < (s->avdimen.interlaced_duplex ? 2 : 1); ++i) @@ -6054,15 +6053,15 @@ get_background_raster (Avision_Scanner* s) f = fopen ("background-final-rear.pnm", "w"); raster += s->params.bytes_per_line * s->val[OPT_BACKGROUND].w; } - + write_pnm_header (f, (color_mode_is_color (s->c_mode) ? AV_TRUECOLOR : AV_GRAYSCALE), 8, s->params.bytes_per_line / bpp, s->val[OPT_BACKGROUND].w); - + fwrite (raster, 1, s->params.bytes_per_line * s->val[OPT_BACKGROUND].w, f); fclose (f); } } - + return SANE_STATUS_GOOD; } @@ -6072,9 +6071,9 @@ reserve_unit (Avision_Scanner* s) char cmd[] = {AVISION_SCSI_RESERVE_UNIT, 0, 0, 0, 0, 0}; SANE_Status status; - + DBG (1, "reserve_unit:\n"); - + status = avision_cmd (&s->av_con, cmd, sizeof (cmd), 0, 0, 0, 0); return status; } @@ -6085,7 +6084,7 @@ release_unit (Avision_Scanner* s, int type) char cmd[] = {AVISION_SCSI_RELEASE_UNIT, 0, 0, 0, 0, 0}; SANE_Status status; - + DBG (1, "release unit: type: %d\n", type); cmd[5] = type; /* latest scanners also allow 1: release paper and 2: end job */ status = avision_cmd (&s->av_con, cmd, sizeof (cmd), 0, 0, 0, 0); @@ -6100,17 +6099,17 @@ media_check (Avision_Scanner* s) SANE_Status status; uint8_t result[1]; /* 4 */ size_t size = sizeof(result); - + status = avision_cmd (&s->av_con, cmd, sizeof (cmd), 0, 0, result, &size); - + debug_print_raw (5, "media_check: result\n", result, size); - + if (status == SANE_STATUS_GOOD) { if (!(result[0] & 0x1)) status = SANE_STATUS_NO_DOCS; } - + return status; } @@ -6120,7 +6119,7 @@ flush_media (Avision_Scanner* s) { Avision_Device* dev = s->hw; SANE_Status status; - + if (s->source_mode_dim == AV_ADF_DIM && dev->inquiry_batch_scan) { DBG (1, "flush_media: flushing pages out of batch scanner\n"); @@ -6133,7 +6132,7 @@ flush_media (Avision_Scanner* s) DBG (1, "flush_media: release status: %d\n", status2); } } while (status == SANE_STATUS_GOOD); - } + } return SANE_STATUS_GOOD; } #endif /* 0 - unused */ @@ -6142,15 +6141,15 @@ static SANE_Status object_position (Avision_Scanner* s, uint8_t position) { SANE_Status status; - + uint8_t cmd [10]; - + memset (cmd, 0, sizeof (cmd)); cmd[0] = AVISION_SCSI_OBJECT_POSITION; cmd[1] = position; - + DBG (1, "object_position: %d\n", position); - + status = avision_cmd (&s->av_con, cmd, sizeof(cmd), 0, 0, 0, 0); return status; } @@ -6159,11 +6158,11 @@ static SANE_Status start_scan (Avision_Scanner* s) { struct command_scan cmd; - + size_t size = sizeof (cmd); - + DBG (3, "start_scan:\n"); - + memset (&cmd, 0, sizeof (cmd)); cmd.opc = AVISION_SCSI_SCAN; cmd.transferlen = 1; @@ -6176,7 +6175,7 @@ start_scan (Avision_Scanner* s) if (s->val[OPT_QSCAN].w == SANE_TRUE) { SET_BIT(cmd.bitset1,7); } - + DBG (3, "start_scan: sending command. Bytes: %lu\n", (u_long) size); return avision_cmd (&s->av_con, &cmd, size, 0, 0, 0, 0); } @@ -6185,12 +6184,12 @@ static SANE_Status do_eof (Avision_Scanner *s) { int exit_status; - + DBG (3, "do_eof:\n"); /* we do not scan anymore */ s->prepared = s->scanning = SANE_FALSE; - + /* we can now mark the rear data as valid */ if (s->avdimen.interlaced_duplex || (s->hw->hw->feature_type & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX)) { @@ -6199,16 +6198,16 @@ do_eof (Avision_Scanner *s) DBG (3, "do_eof: duplex rear data valid: %x\n", s->duplex_rear_valid); } - + if (s->read_fds >= 0) { close (s->read_fds); s->read_fds = -1; } - + /* join our processes - without a wait() you will produce zombies (defunct children) */ sanei_thread_waitpid (s->reader_pid, &exit_status); - s->reader_pid = -1; + sanei_thread_invalidate (s->reader_pid); DBG (3, "do_eof: returning %d\n", exit_status); return (SANE_Status)exit_status; @@ -6218,19 +6217,19 @@ static SANE_Status do_cancel (Avision_Scanner* s) { DBG (3, "do_cancel:\n"); - + s->prepared = s->scanning = SANE_FALSE; s->duplex_rear_valid = SANE_FALSE; s->page = 0; s->cancelled = 1; - + if (sanei_thread_is_valid (s->reader_pid)) { int exit_status; - + /* ensure child knows it's time to stop: */ sanei_thread_kill (s->reader_pid); sanei_thread_waitpid (s->reader_pid, &exit_status); - s->reader_pid = -1; + sanei_thread_invalidate (s->reader_pid); } return SANE_STATUS_CANCELLED; @@ -6243,16 +6242,16 @@ read_data (Avision_Scanner* s, SANE_Byte* buf, size_t* count) SANE_Status status; DBG (9, "read_data: %lu\n", (u_long) *count); - + memset (&rcmd, 0, sizeof (rcmd)); - + rcmd.opc = AVISION_SCSI_READ; rcmd.datatypecode = 0x00; /* read image data */ set_double (rcmd.datatypequal, s->hw->data_dq); set_triple (rcmd.transferlen, *count); - + status = avision_cmd (&s->av_con, &rcmd, sizeof (rcmd), 0, 0, buf, count); - + return status; } @@ -6261,9 +6260,9 @@ init_options (Avision_Scanner* s) { Avision_Device* dev = s->hw; int i; - + DBG (3, "init_options:\n"); - + memset (s->opt, 0, sizeof (s->opt)); memset (s->val, 0, sizeof (s->val)); @@ -6271,9 +6270,9 @@ init_options (Avision_Scanner* s) s->opt[i].size = sizeof (SANE_Word); s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; } - + /* Init the SANE option from the scanner inquiry data */ - + switch (dev->inquiry_asic_type) { case AV_ASIC_C2: dev->dpi_range.min = 100; @@ -6294,11 +6293,11 @@ init_options (Avision_Scanner* s) dev->dpi_range.quant = 1; /* any, including 72, 144, etc. */ dev->dpi_range.max = dev->inquiry_max_res; - + dev->speed_range.min = (SANE_Int)0; dev->speed_range.max = (SANE_Int)4; dev->speed_range.quant = (SANE_Int)1; - + s->opt[OPT_NUM_OPTS].name = ""; s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].desc = ""; @@ -6306,7 +6305,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; s->opt[OPT_NUM_OPTS].size = sizeof(SANE_TYPE_INT); s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; - + /* "Mode" group: */ s->opt[OPT_MODE_GROUP].title = SANE_TITLE_SCAN_MODE; s->opt[OPT_MODE_GROUP].desc = ""; /* for groups only title and type are valid */ @@ -6314,7 +6313,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_MODE_GROUP].cap = 0; s->opt[OPT_MODE_GROUP].size = 0; s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - + /* color mode */ s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; @@ -6325,7 +6324,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_MODE].constraint.string_list = dev->color_list; s->val[OPT_MODE].s = strdup (dev->color_list[dev->color_list_default]); s->c_mode = match_color_mode (dev, s->val[OPT_MODE].s); - + /* source mode */ s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; @@ -6366,7 +6365,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_SPEED].desc = SANE_DESC_SCAN_SPEED; s->opt[OPT_SPEED].type = SANE_TYPE_INT; s->opt[OPT_SPEED].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_SPEED].constraint.range = &dev->speed_range; + s->opt[OPT_SPEED].constraint.range = &dev->speed_range; s->val[OPT_SPEED].w = 0; if (dev->scanner_type == AV_SHEETFEED) s->opt[OPT_SPEED].cap |= SANE_CAP_INACTIVE; @@ -6418,7 +6417,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; s->opt[OPT_BR_Y].constraint.range = &dev->y_range; s->val[OPT_BR_Y].w = dev->y_range.max; - + /* overscan top */ s->opt[OPT_OVERSCAN_TOP].name = "overscan-top"; s->opt[OPT_OVERSCAN_TOP].title = "Overscan top"; @@ -6428,7 +6427,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_OVERSCAN_TOP].constraint_type = SANE_CONSTRAINT_RANGE; s->opt[OPT_OVERSCAN_TOP].constraint.range = &overscan_range; s->val[OPT_OVERSCAN_TOP].w = SANE_FIX(0); - + /* overscan bottom */ s->opt[OPT_OVERSCAN_BOTTOM].name = "overscan-bottom"; s->opt[OPT_OVERSCAN_BOTTOM].title = "Overscan bottom"; @@ -6438,12 +6437,12 @@ init_options (Avision_Scanner* s) s->opt[OPT_OVERSCAN_BOTTOM].constraint_type = SANE_CONSTRAINT_RANGE; s->opt[OPT_OVERSCAN_BOTTOM].constraint.range = &overscan_range; s->val[OPT_OVERSCAN_BOTTOM].w = SANE_FIX(0); - + if (!dev->inquiry_tune_scan_length) s->opt[OPT_OVERSCAN_TOP].cap |= SANE_CAP_INACTIVE; if (!dev->inquiry_tune_scan_length) s->opt[OPT_OVERSCAN_BOTTOM].cap |= SANE_CAP_INACTIVE; - + /* background raster */ s->opt[OPT_BACKGROUND].name = "background-lines"; s->opt[OPT_BACKGROUND].title = "Background raster lines"; @@ -6453,11 +6452,11 @@ init_options (Avision_Scanner* s) s->opt[OPT_BACKGROUND].constraint_type = SANE_CONSTRAINT_RANGE; s->opt[OPT_BACKGROUND].constraint.range = &background_range; s->val[OPT_BACKGROUND].w = 0; - + if (!dev->inquiry_background_raster) { s->opt[OPT_BACKGROUND].cap |= SANE_CAP_INACTIVE; } - + /* "Enhancement" group: */ s->opt[OPT_ENHANCEMENT_GROUP].title = "Enhancement"; s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; /* for groups only title and type are valid */ @@ -6553,7 +6552,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_GAMMA_VECTOR_B].constraint_type = SANE_CONSTRAINT_RANGE; s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &u8_range; s->val[OPT_GAMMA_VECTOR_B].wa = &s->gamma_table[3][0]; - + if (!disable_gamma_table) { if (color_mode_is_color (s->c_mode)) { @@ -6565,7 +6564,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; } } - + /* exposure */ s->opt[OPT_EXPOSURE].name = "exposure"; s->opt[OPT_EXPOSURE].title = "Exposure"; @@ -6575,7 +6574,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_EXPOSURE].constraint_type = SANE_CONSTRAINT_RANGE; s->opt[OPT_EXPOSURE].constraint.range = &exposure_range; s->val[OPT_EXPOSURE].w = 100; - + if (!dev->inquiry_exposure_control) { s->opt[OPT_EXPOSURE].cap |= SANE_CAP_INACTIVE; } @@ -6587,7 +6586,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_MULTISAMPLE].type = SANE_TYPE_BOOL; s->opt[OPT_MULTISAMPLE].unit = SANE_UNIT_NONE; s->val[OPT_MULTISAMPLE].w = SANE_FALSE; - + /* TODO: No idea how to detect, assume exposure control devices are new enough to support this, for now. -ReneR */ if (!dev->inquiry_exposure_control) { @@ -6601,13 +6600,13 @@ init_options (Avision_Scanner* s) s->opt[OPT_IR].type = SANE_TYPE_BOOL; s->opt[OPT_IR].unit = SANE_UNIT_NONE; s->val[OPT_IR].w = SANE_FALSE; - + /* TODO: No idea how to detect, assume exposure control devices are new enough to support this, for now. -ReneR */ if (!dev->inquiry_exposure_control) { s->opt[OPT_IR].cap |= SANE_CAP_INACTIVE; } - + /* "MISC" group: */ s->opt[OPT_MISC_GROUP].title = SANE_TITLE_SCAN_MODE; s->opt[OPT_MISC_GROUP].desc = ""; /* for groups only title and type are valid */ @@ -6615,7 +6614,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_MISC_GROUP].cap = 0; s->opt[OPT_MISC_GROUP].size = 0; s->opt[OPT_MISC_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - + /* film holder control */ if (dev->scanner_type != AV_FILM) s->opt[OPT_FRAME].cap |= SANE_CAP_INACTIVE; @@ -6649,7 +6648,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_MESSAGE].constraint_type = SANE_CONSTRAINT_NONE; s->val[OPT_MESSAGE].s = malloc(s->opt[OPT_MESSAGE].size); s->val[OPT_MESSAGE].s[0] = 0; - + /* NVRAM */ s->opt[OPT_NVRAM].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; if (!dev->inquiry_nvram_read) @@ -6663,7 +6662,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_NVRAM].constraint_type = SANE_CONSTRAINT_NONE; s->val[OPT_NVRAM].s = malloc(s->opt[OPT_NVRAM].size); s->val[OPT_NVRAM].s[0] = 0; - + /* paper_length */ s->opt[OPT_PAPERLEN].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; if (!dev->inquiry_paper_length) @@ -6676,7 +6675,7 @@ init_options (Avision_Scanner* s) s->opt[OPT_PAPERLEN].size = sizeof(SANE_Word); s->opt[OPT_PAPERLEN].constraint_type = SANE_CONSTRAINT_NONE; s->val[OPT_PAPERLEN].w = SANE_FALSE; - + /* ADF page flipping */ s->opt[OPT_ADF_FLIP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_AUTOMATIC | SANE_CAP_ADVANCED; if (!(s->hw->hw->feature_type & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX)) @@ -6711,24 +6710,24 @@ reader_process (void *data) int fd = s->write_fds; Avision_Device* dev = s->hw; - + SANE_Status status; SANE_Status exit_status = SANE_STATUS_GOOD; sigset_t sigterm_set; sigset_t ignore_set; struct SIGACTION act; - + FILE* fp; FILE* rear_fp = 0; /* used to store the deinterlaced rear data */ FILE* raw_fp = 0; /* used to write the RAW image data for debugging */ - + /* the complex params */ unsigned int lines_per_stripe; unsigned int lines_per_output; unsigned int max_bytes_per_read; - + SANE_Bool gray_mode; - + /* the simple params for the data reader */ int hw_line = 0; int line = 0; @@ -6736,17 +6735,17 @@ reader_process (void *data) unsigned int stripe_size; unsigned int stripe_fill; unsigned int out_size; - + size_t total_size; size_t processed_bytes; - + enum { NONE, /* do not de-interlace at all */ STRIPE, /* every 2nd stripe */ HALF, /* the 2nd half */ LINE /* every 2nd line */ } deinterlace = NONE; - + /* the fat strip we currently puzzle together to perform software-colorpack and more */ uint8_t* stripe_data; @@ -6755,44 +6754,44 @@ reader_process (void *data) /* interpolation output data, one line */ uint8_t* ip_history = 0; uint8_t* ip_data = 0; - + DBG (3, "reader_process:\n"); - + if (sanei_thread_is_forked()) close (s->read_fds); - + sigfillset (&ignore_set); sigdelset (&ignore_set, SIGTERM); #if defined (__APPLE__) && defined (__MACH__) sigdelset (&ignore_set, SIGUSR2); #endif sigprocmask (SIG_SETMASK, &ignore_set, 0); - + memset (&act, 0, sizeof (act)); sigaction (SIGTERM, &act, 0); - + sigemptyset (&sigterm_set); sigaddset (&sigterm_set, SIGTERM); - + gray_mode = color_mode_is_shaded (s->c_mode); if (s->avdimen.interlaced_duplex) { deinterlace = STRIPE; - + if ( (dev->hw->feature_type & AV_NON_INTERLACED_DUPLEX_300) && (s->avdimen.hw_xres <= 300 && s->avdimen.hw_yres <= 300) ) deinterlace = HALF; if (dev->hw->feature_type & AV_2ND_LINE_INTERLACED) deinterlace = LINE; - + if (dev->scanner_type == AV_FILM) deinterlace = LINE; } - + fp = fdopen (fd, "w"); if (!fp) return SANE_STATUS_NO_MEM; - + /* start scan ? */ if ((deinterlace == NONE && !((dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && s->duplex_rear_valid)) || (deinterlace != NONE && !s->duplex_rear_valid)) @@ -6806,7 +6805,7 @@ reader_process (void *data) sane_strstatus (status)); return status; } - + if (dev->hw->feature_type & AV_NO_START_SCAN) { DBG (1, "reader_process: start_scan skipped due to device-list!\n"); } @@ -6818,7 +6817,7 @@ reader_process (void *data) return status; } } - + if (dev->hw->feature_type & AV_ACCEL_TABLE) /* (s->hw->inquiry_asic_type == AV_ASIC_C6) */ { status = send_acceleration_table (s); @@ -6829,7 +6828,7 @@ reader_process (void *data) } } } - + /* setup file i/o for deinterlacing scans or if we are the back page with a flipping duplexer */ if (deinterlace != NONE || (dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX && s->source_mode == AV_ADF_DUPLEX && !(s->page % 2))) @@ -6851,38 +6850,38 @@ reader_process (void *data) } } } - + /* it takes quite a few lines to saturate the (USB) bus */ lines_per_stripe = dev->read_stripe_size; if (s->avdimen.line_difference) lines_per_stripe += 2 * s->avdimen.line_difference; - + stripe_size = s->avdimen.hw_bytes_per_line * lines_per_stripe; lines_per_output = lines_per_stripe - 2 * s->avdimen.line_difference; - + if (s->av_con.connection_type == AV_SCSI) /* maybe better not /2 ... */ max_bytes_per_read = dev->scsi_buffer_size / 2; - else + else /* vast buffer size to saturate the bus */ max_bytes_per_read = 0x100000; - + out_size = s->avdimen.hw_bytes_per_line * lines_per_output; - + DBG (3, "dev->scsi_buffer_size / 2: %d\n", dev->scsi_buffer_size / 2); - + DBG (3, "bytes_per_line: %d, pixels_per_line: %d\n", s->avdimen.hw_bytes_per_line, s->avdimen.hw_pixels_per_line); - + DBG (3, "lines_per_stripe: %d, lines_per_output: %d\n", lines_per_stripe, lines_per_output); - + DBG (3, "max_bytes_per_read: %d, stripe_size: %d, out_size: %d\n", max_bytes_per_read, stripe_size, out_size); - + stripe_data = malloc (stripe_size); - + /* for software scaling we need an additional interpolation line buffer */ if (s->avdimen.hw_xres != s->avdimen.xres || s->avdimen.hw_yres != s->avdimen.yres) @@ -6890,13 +6889,13 @@ reader_process (void *data) /* layout out_data so that the interpolation history is exactly in front */ ip_history = malloc (s->avdimen.hw_bytes_per_line + out_size); out_data = ip_history + s->avdimen.hw_bytes_per_line; - + ip_data = malloc (s->params.bytes_per_line); } else { out_data = malloc (out_size); } - + /* calculate params for the reading loop */ total_size = s->avdimen.hw_bytes_per_line * (s->avdimen.hw_lines + 2 * s->avdimen.line_difference + @@ -6904,7 +6903,7 @@ reader_process (void *data) if (deinterlace != NONE && !s->duplex_rear_valid) total_size *= 2; DBG (3, "reader_process: total_size: %lu\n", (u_long) total_size); - + /* write a RAW PNM file for debugging -ReneR */ if (0 /* DEBUG */ && (deinterlace == NONE || (deinterlace != NONE && !s->duplex_rear_valid)) ) @@ -6913,36 +6912,36 @@ reader_process (void *data) write_pnm_header (fp, s->c_mode, s->params.depth, s->avdimen.hw_pixels_per_line, total_size / s->avdimen.hw_bytes_per_line); } - + processed_bytes = 0; stripe_fill = 0; - + /* First, dump background raster, bypassing all the other processing. */ if (dev->inquiry_background_raster && s->val[OPT_BACKGROUND].w) { uint8_t* background = s->background_raster; if (s->duplex_rear_valid) background += s->params.bytes_per_line * s->val[OPT_BACKGROUND].w; - + DBG (5, "reader_process: dumping background raster\n"); fwrite (background, s->params.bytes_per_line, s->val[OPT_BACKGROUND].w, fp); } - + /* Data read; loop until all data has been processed. Might exit before all lines are transferred for ADF paper end. */ while (exit_status == SANE_STATUS_GOOD && processed_bytes < total_size) { unsigned int useful_bytes; - + DBG (5, "reader_process: stripe filled: %d\n", stripe_fill); - + /* fill the stripe buffer with real data */ while (!s->duplex_rear_valid && processed_bytes < total_size && stripe_fill < stripe_size && exit_status == SANE_STATUS_GOOD) { size_t this_read = stripe_size - stripe_fill; - + /* Limit reads to max_bytes_per_read and global data boundaries. Rounded to the next lower multiple of byte_per_lines, otherwise some scanners freeze. */ @@ -6962,7 +6961,7 @@ reader_process (void *data) sigprocmask (SIG_BLOCK, &sigterm_set, 0); status = read_data (s, stripe_data + stripe_fill, &this_read); sigprocmask (SIG_UNBLOCK, &sigterm_set, 0); - + /* only EOF on the second stripe, as otherwise the rear page is shorter */ if (status == SANE_STATUS_EOF && deinterlace == STRIPE) { @@ -6977,59 +6976,59 @@ reader_process (void *data) } } } - + /* write RAW data to file for debugging */ if (raw_fp && this_read > 0) fwrite (stripe_data + stripe_fill, this_read, 1, raw_fp); - + if (status == SANE_STATUS_EOF || this_read == 0) { DBG (1, "reader_process: read_data failed due to EOF\n"); exit_status = SANE_STATUS_EOF; } - + if (status != SANE_STATUS_GOOD) { DBG (1, "reader_process: read_data failed with status: %d\n", status); exit_status = status; } - + stripe_fill += this_read; processed_bytes += this_read; } - + /* fill the stripe buffer with stored, virtual data */ if (s->duplex_rear_valid) { size_t this_read = stripe_size - stripe_fill; size_t got; - + /* limit reads to max_read and global data boundaries */ if (this_read > max_bytes_per_read) this_read = max_bytes_per_read; - + if (processed_bytes + this_read > total_size) this_read = total_size - processed_bytes; - + DBG (5, "reader_process: virtual processed_bytes: %lu, total_size: %lu\n", (u_long) processed_bytes, (u_long) total_size); DBG (5, "reader_process: virtual this_read: %lu\n", (u_long) this_read); - + got = fread (stripe_data + stripe_fill, 1, this_read, rear_fp); stripe_fill += got; processed_bytes += got; if (got != this_read) exit_status = SANE_STATUS_EOF; } - + DBG (5, "reader_process: stripe filled: %d\n", stripe_fill); - + useful_bytes = stripe_fill; if (color_mode_is_color (s->c_mode)) useful_bytes -= 2 * s->avdimen.line_difference * s->avdimen.hw_bytes_per_line; - + DBG (3, "reader_process: useful_bytes %i\n", useful_bytes); - + /* Deinterlace, save the rear stripes. For some scanners (AV220) that is every 2nd stripe, the 2nd half of the transferred data ((AV83xx), or every 2nd line (AV122)). */ @@ -7078,12 +7077,12 @@ reader_process (void *data) DBG (9, "reader_process: after page flip: useful_bytes: %d, stripe_fill: %d\n", useful_bytes, stripe_fill); } else { - + /* * Perform needed data conversions (packing, ...) and/or copy the * image data. */ - + if (s->c_mode != AV_TRUECOLOR && s->c_mode != AV_TRUECOLOR16) /* simple copy */ { @@ -7098,11 +7097,11 @@ reader_process (void *data) /* TODO: add 16bit per sample code? */ unsigned int i; int c_offset = s->avdimen.line_difference * s->avdimen.hw_bytes_per_line; - + uint8_t* r_ptr = stripe_data; uint8_t* g_ptr = stripe_data + c_offset + 1; uint8_t* b_ptr = stripe_data + 2 * c_offset + 2; - + for (i = 0; i < useful_bytes;) { out_data [i++] = *r_ptr; r_ptr += 3; out_data [i++] = *g_ptr; g_ptr += 3; @@ -7110,17 +7109,17 @@ reader_process (void *data) } } /* end color pack */ else if (dev->inquiry_needs_line_pack) /* line-pack */ - { + { /* TODO: add 16bit per sample code? */ int i = 0, l, p; const int lines = useful_bytes / s->avdimen.hw_bytes_per_line; - + for (l = 0; l < lines; ++l) { uint8_t* r_ptr = stripe_data + (s->avdimen.hw_bytes_per_line * l); uint8_t* g_ptr = r_ptr + s->avdimen.hw_pixels_per_line; uint8_t* b_ptr = g_ptr + s->avdimen.hw_pixels_per_line; - + for (p = 0; p < s->avdimen.hw_pixels_per_line; ++p) { out_data [i++] = *(r_ptr++); out_data [i++] = *(g_ptr++); @@ -7129,13 +7128,13 @@ reader_process (void *data) } } /* end line pack */ else /* else no packing was required -> simple copy */ - { + { memcpy (out_data, stripe_data, useful_bytes); } } /* end if AV_TRUECOLOR* */ - + /* FURTHER POST-PROCESSING ON THE FINAL OUTPUT DATA */ - + /* maybe mirroring in ADF mode */ if (s->source_mode_dim == AV_ADF_DIM && dev->inquiry_adf_need_mirror) { @@ -7152,7 +7151,7 @@ reader_process (void *data) { uint8_t* begin_ptr = out_data + (l * s->avdimen.hw_bytes_per_line); uint8_t* end_ptr = begin_ptr + s->avdimen.hw_bytes_per_line; - + while (begin_ptr < end_ptr) { uint8_t tmp; tmp = *begin_ptr; @@ -7164,7 +7163,7 @@ reader_process (void *data) else /* non trivial mirroring */ { /* Non-trivial Mirroring with element swapping */ - + int l; int lines = useful_bytes / s->avdimen.hw_bytes_per_line; @@ -7172,25 +7171,25 @@ reader_process (void *data) { uint8_t* begin_ptr = out_data + (l * s->avdimen.hw_bytes_per_line); uint8_t* end_ptr = begin_ptr + s->avdimen.hw_bytes_per_line - 3; - + while (begin_ptr < end_ptr) { uint8_t tmp; - + /* R */ tmp = *begin_ptr; *begin_ptr++ = *end_ptr; *end_ptr++ = tmp; - + /* G */ tmp = *begin_ptr; *begin_ptr++ = *end_ptr; *end_ptr++ = tmp; - + /* B */ tmp = *begin_ptr; *begin_ptr++ = *end_ptr; *end_ptr = tmp; - + end_ptr -= 5; } } @@ -7202,13 +7201,13 @@ reader_process (void *data) s->c_mode == AV_GRAYSCALE16 || s->c_mode == AV_TRUECOLOR12 || s->c_mode == AV_TRUECOLOR16) { - + int l; int lines = useful_bytes / s->avdimen.hw_bytes_per_line; uint8_t* dark_avg_data = s->dark_avg_data; uint8_t* white_avg_data = s->white_avg_data; - + uint8_t* begin_ptr = out_data; uint8_t* end_ptr = begin_ptr + s->avdimen.hw_bytes_per_line; uint8_t* line_ptr; @@ -7216,16 +7215,16 @@ reader_process (void *data) double scale = 1.0; if (s->c_mode == AV_GRAYSCALE12 || s->c_mode == AV_TRUECOLOR12) scale = (double) (1<<4); - + while (begin_ptr < end_ptr) { uint16_t dark_avg = 0; uint16_t white_avg = WHITE_MAP_RANGE; - + if (dark_avg_data) dark_avg = get_double_le (dark_avg_data); if (white_avg_data) white_avg = get_double_le (white_avg_data); - + line_ptr = begin_ptr; for (l = 0; l < lines; ++ l) { @@ -7233,16 +7232,16 @@ reader_process (void *data) uint16_t v2; if (0) v = (v - dark_avg) * white_avg / WHITE_MAP_RANGE; - + v2 = v < 0xFFFF ? v : 0xFFFF; - + /* SANE Standard 3.2.1 "... bytes of each sample value are transmitted in the machine's native byte order." */ *line_ptr = v2; - + line_ptr += s->avdimen.hw_bytes_per_line; } - + begin_ptr += 2; if (dark_avg_data) dark_avg_data += 2; @@ -7250,9 +7249,9 @@ reader_process (void *data) white_avg_data += 2; } } - + /* SOFTWARE SCALING WITH INTERPOLATION (IF NECESSARY) */ - + if (s->avdimen.hw_xres == s->avdimen.xres && s->avdimen.hw_yres == s->avdimen.yres) /* No scaling */ { @@ -7280,22 +7279,22 @@ reader_process (void *data) int x; /* for convenience in the 16bit code path */ uint16_t* out_data16 = (uint16_t*) out_data; - + const int hw_line_end = hw_line + useful_bytes / s->avdimen.hw_bytes_per_line; - + /* on-the-fly bi-linear interpolation */ while (1) { double by = (-1.0 + s->avdimen.hw_lines) * line / (s->avdimen.hw_lines * s->avdimen.xres / s->avdimen.hw_xres + s->val[OPT_BACKGROUND].w); int sy = (int)floor(by); int ydist = (int) ((by - sy) * 256); int syy = sy + 1; - + const int hwbpl = s->avdimen.hw_bytes_per_line; - + uint8_t* dst = ip_data; uint16_t* dst16 = (uint16_t*) ip_data; unsigned int v; /* accumulator */ - + /* Break out if we do not have the hw source line - yet, or when we are past the end of wanted data (e.g. on the front page due to rear_offset). Also take the read_offset @@ -7312,35 +7311,35 @@ reader_process (void *data) syy += s->avdimen.rear_offset; } } - + if (sy >= hw_line_end || syy >= hw_line_end) { DBG (3, "reader_process: source line %d-%d not yet avail\n", sy, syy); break; } - + /* convert to offset in current stripe */ sy -= hw_line; syy -= hw_line; - + if (sy < -1) { DBG (1, "reader_process: need more history: %d???\n", sy); sy = -1; } - + DBG (8, "reader_process: out line: %d <- from: %d-%d\n", line, sy, syy); - + for (x = 0; x < s->params.pixels_per_line; ++x) { const double bx = (-1.0 + s->avdimen.hw_pixels_per_line) * x / s->params.pixels_per_line; const int sx = (int)floor(bx); const int xdist = (int) ((bx - sx) * 256); const int sxx = sx + 1; - + if (x == 0 || x == s->params.pixels_per_line - 1) DBG (8, "reader_process: x: %d <- from: %d-%d\n", x, sx, sxx); - + switch (s->c_mode) { case AV_THRESHOLDED: case AV_DITHERED: @@ -7348,13 +7347,13 @@ reader_process (void *data) /* Repeating this over and over again is not fast, but as a seldom used code-path we want it readable. x/8 is the byte, and x%8 the bit position. */ - v = + v = ( ((out_data [sy*hwbpl + sx/8 ] >> (7-sx%8 )) & 1) * (256-xdist) * (256-ydist) + ((out_data [sy*hwbpl + sxx/8] >> (7-sxx%8)) & 1) * xdist * (256-ydist) + ((out_data [syy*hwbpl + sx/8 ] >> (7-sx%8 )) & 1) * (256-xdist) * ydist + ((out_data [syy*hwbpl + sxx/8] >> (7-sxx%8)) & 1) * xdist * ydist ) / (1 + 1 * 256); - + /* Shift and or the result together and eventually jump to the next byte. */ *dst = (*dst << 1) | ((v>>7)&1); @@ -7362,10 +7361,10 @@ reader_process (void *data) ++dst; } break; - + case AV_GRAYSCALE: { - v = + v = ( out_data [sy*hwbpl + sx ] * (256-xdist) * (256-ydist) + out_data [sy*hwbpl + sxx] * xdist * (256-ydist) + out_data [syy*hwbpl + sx ] * (256-xdist) * ydist + @@ -7374,12 +7373,12 @@ reader_process (void *data) *dst++ = v; } break; - + case AV_GRAYSCALE12: case AV_GRAYSCALE16: { - /* TODO: test! */ - v = + /* TODO: test! */ + v = ( out_data16 [sy*hwbpl + sx ] * (256-xdist) * (256-ydist) + out_data16 [sy*hwbpl + sxx] * xdist * (256-ydist) + out_data16 [syy*hwbpl + sx ] * (256-xdist) * ydist + @@ -7388,13 +7387,13 @@ reader_process (void *data) *dst16++ = v; } break; - + case AV_TRUECOLOR: { int c; for (c = 0; c < 3; ++c) { - v = + v = ( out_data [sy*hwbpl + sx*3 + c] * (256-xdist) * (256-ydist) + out_data [sy*hwbpl + sxx*3 + c] * xdist * (256-ydist) + out_data [syy*hwbpl + sx*3 + c] * (256-xdist) * ydist + @@ -7404,7 +7403,7 @@ reader_process (void *data) } } break; - + case AV_TRUECOLOR12: case AV_TRUECOLOR16: { @@ -7412,7 +7411,7 @@ reader_process (void *data) int c; for (c = 0; c < 3; ++c) { - v = + v = ( out_data16 [sy*hwbpl + sx*3 + c] * (256-xdist) * (256-ydist) + out_data16 [sy*hwbpl + sxx*3 + c] * xdist * (256-ydist) + out_data16 [syy*hwbpl + sx*3 + c] * (256-xdist) * ydist + @@ -7422,7 +7421,7 @@ reader_process (void *data) } } break; - + case AV_COLOR_MODE_LAST: ; /* silence compiler warning */ } @@ -7436,29 +7435,29 @@ reader_process (void *data) s->avdimen.hw_bytes_per_line); } } - + /* save image date in stripe buffer for next next stripe */ stripe_fill -= useful_bytes; if (stripe_fill > 0) memcpy (stripe_data, stripe_data + useful_bytes, stripe_fill); - + hw_line += useful_bytes / s->avdimen.hw_bytes_per_line; - + DBG (3, "reader_process: end of iteration\n"); } /* end while not all lines or inf. mode */ - + DBG (3, "reader_process: i/o loop finished\n"); if (exit_status == SANE_STATUS_GOOD) exit_status = SANE_STATUS_EOF; - + if (raw_fp) fclose (raw_fp); - + /* maybe we need to fill in some white data */ if (exit_status == SANE_STATUS_EOF && line < s->params.lines) { DBG (3, "reader_process: padding with white data\n"); memset (out_data, gray_mode ? 0xff : 0x00, s->params.bytes_per_line); - + DBG (6, "reader_process: padding line %d - %d\n", line, s->params.lines); while (line < s->params.lines) { @@ -7466,7 +7465,7 @@ reader_process (void *data) ++line; } } - + /* Eject film holder and/or release_unit - but only for non-duplex-rear / non-virtual scans. */ if ((deinterlace != NONE && s->duplex_rear_valid) || @@ -7485,14 +7484,14 @@ reader_process (void *data) status = release_unit (s, 0); if (status != SANE_STATUS_GOOD) DBG (1, "reader_process: release_unit failed\n"); - + if (dev->inquiry_new_protocol && dev->scanner_type == AV_FILM) { status = object_position (s, AVISION_SCSI_OP_GO_HOME); if (status != SANE_STATUS_GOOD) DBG (1, "reader_process: object position go-home failed!\n"); } } - + if ((dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX) && s->source_mode == AV_ADF_DUPLEX && s->page % 2) { /* front page of flipping duplex */ if (exit_status == SANE_STATUS_EOF) { @@ -7507,10 +7506,15 @@ reader_process (void *data) return status; } } - /* we can set anything here without fear because the process will terminate soon and take our changes with it */ + /* We run in a separate process or thread. In the latter case, + any change we make to s before the reader_process invocation + needs to be reverted. */ + SANE_Int lines = s->params.lines; s->page += 1; s->params.lines = -line; exit_status = reader_process (s); + s->params.lines = lines; + s->page -= 1; } /* TODO: * else { @@ -7522,15 +7526,15 @@ reader_process (void *data) } if (rear_fp) fclose (rear_fp); - + if (ip_data) free (ip_data); if (ip_history) free (ip_history); else free (out_data); /* if we have ip_history out_data is included there */ - + free (stripe_data); - + DBG (3, "reader_process: returning success\n"); return exit_status; } @@ -7550,17 +7554,17 @@ attach_one_usb (const char* dev) attach (dev, AV_USB, 0); return SANE_STATUS_GOOD; } - + static SANE_Status sane_reload_devices (void) { FILE* fp; - + char line[PATH_MAX]; const char* cp = 0; char* word; int linenumber = 0; - int model_num = 0; + int model_num = 0; sanei_usb_init (); fp = sanei_config_open (AVISION_CONFIG_FILE); @@ -7574,15 +7578,15 @@ sane_reload_devices (void) while (sanei_config_read (line, sizeof (line), fp)) { attaching_hw = 0; - + word = NULL; ++ linenumber; - + DBG (5, "sane_reload_devices: parsing config line \"%s\"\n", line); - + cp = sanei_config_get_string (line, &word); - + if (!word || cp == line) { DBG (5, "sane_reload_devices: config file line %d: ignoring empty line\n", linenumber); @@ -7592,13 +7596,13 @@ sane_reload_devices (void) } continue; } - + if (!word) { DBG (1, "sane_reload_devices: config file line %d: could not be parsed\n", linenumber); continue; } - + if (word[0] == '#') { DBG (5, "sane_reload_devices: config file line %d: ignoring comment line\n", linenumber); @@ -7606,13 +7610,13 @@ sane_reload_devices (void) word = NULL; continue; } - + if (strcmp (word, "option") == 0) { free (word); word = NULL; cp = sanei_config_get_string (cp, &word); - + if (strcmp (word, "disable-gamma-table") == 0) { DBG (3, "sane_reload_devices: config file line %d: disable-gamma-table\n", linenumber); @@ -7656,7 +7660,7 @@ sane_reload_devices (void) else if (strcmp (word, "static-blue-calib") == 0) { DBG (3, "sane_reload_devices: config file line %d: static blue calibration\n", linenumber); - static_calib_list [2] = SANE_TRUE; + static_calib_list [2] = SANE_TRUE; } else DBG (1, "sane_reload_devices: config file line %d: options unknown!\n", @@ -7671,7 +7675,7 @@ sane_reload_devices (void) else if (strcmp (word, "scsi") == 0) { DBG (2, "sane_reload_devices: config file line %d: trying to attach SCSI: %s'\n", linenumber, line); - + /* the last time I verified (2003-03-18) this function only matches SCSI devices ... */ sanei_config_attach_matching_devices (line, attach_one_scsi); @@ -7681,7 +7685,7 @@ sane_reload_devices (void) linenumber); DBG (1, "sane_reload_devices: (see man sane-avision for details): trying to attach SCSI: %s'\n", line); - + /* the last time I verified (2003-03-18) this function only matched SCSI devices ... */ sanei_config_attach_matching_devices (line, attach_one_scsi); @@ -7689,13 +7693,13 @@ sane_reload_devices (void) free (word); word = NULL; } /* end while read */ - + fclose (fp); - + if (word) free (word); } /* end if fp */ - + /* search for all supported SCSI/USB devices */ while (Avision_Device_List [model_num].scsi_mfg != NULL || Avision_Device_List [model_num].real_mfg != NULL) @@ -7707,13 +7711,13 @@ sane_reload_devices (void) attaching_hw->scsi_model, NULL, -1, -1, -1, -1, attach_one_scsi); - + if (attaching_hw->usb_vendor != 0 && attaching_hw->usb_product != 0 ) { DBG (1, "sane_reload_devices: Trying to find USB device %.4x %.4x ...\n", attaching_hw->usb_vendor, attaching_hw->usb_product); - + /* TODO: check return value */ if (sanei_usb_find_devices (attaching_hw->usb_vendor, attaching_hw->usb_product, @@ -7723,7 +7727,7 @@ sane_reload_devices (void) } ++ model_num; } /* end for all devices in supported list */ - + attaching_hw = 0; return SANE_STATUS_GOOD; } @@ -7732,16 +7736,16 @@ SANE_Status sane_init (SANE_Int* version_code, SANE_Auth_Callback authorize) { authorize = authorize; /* silence gcc */ - + DBG_INIT(); #ifdef AVISION_STATIC_DEBUG_LEVEL DBG_LEVEL = AVISION_STATIC_DEBUG_LEVEL; #endif - + DBG (3, "sane_init:(Version: %i.%i Build: %i)\n", SANE_CURRENT_MAJOR, V_MINOR, BACKEND_BUILD); - + /* must come first */ sanei_thread_init (); @@ -7812,7 +7816,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) uint8_t inquiry_result[AVISION_INQUIRY_SIZE_V1]; DBG (3, "sane_open:\n"); - + if (devicename[0]) { for (dev = first_dev; dev; dev = dev->next) if (strcmp (dev->sane.name, devicename) == 0) @@ -7830,26 +7834,26 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) if (!dev) return SANE_STATUS_INVAL; - + s = malloc (sizeof (*s)); if (!s) return SANE_STATUS_NO_MEM; - + /* initialize ... */ /* the other states (scanning, ...) rely on this memset (0) */ memset (s, 0, sizeof (*s)); - + /* initialize connection state */ s->av_con.connection_type = dev->connection.connection_type; s->av_con.usb_status = dev->connection.usb_status; s->av_con.scsi_fd = -1; s->av_con.usb_dn = -1; - - s->reader_pid = -1; + + sanei_thread_initialize (s->reader_pid); s->read_fds = -1; s->hw = dev; - + /* We initialize the table to a gamma value of 2.22, since this is what papers about Colorimetry suggest. @@ -7859,17 +7863,17 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) { const double gamma = 2.22; const double one_over_gamma = 1. / gamma; - + for (i = 0; i < 4; ++ i) for (j = 0; j < 256; ++ j) s->gamma_table[i][j] = pow( (double) j / 255, one_over_gamma) * 255; } - + /* insert newly opened handle into list of open handles: */ s->next = first_handle; first_handle = s; *handle = s; - + /* open the device */ if (! avision_is_open (&s->av_con) ) { #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED @@ -7907,16 +7911,16 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) DBG (1, "sane_open: additional probe failed: %s\n", sane_strstatus (status)); return status; } - + /* initialize the options */ init_options (s); - + if (dev->inquiry_duplex_interlaced || dev->scanner_type == AV_FILM || dev->hw->feature_type & AV_ADF_FLIPPING_DUPLEX) { /* Might need at least *DOS (Windows flavour and OS/2) portability fix However, I was told Cygwin (et al.) takes care of it. */ strncpy(s->duplex_rear_fname, "/tmp/avision-rear-XXXXXX", PATH_MAX); - + if (! mktemp(s->duplex_rear_fname) ) { DBG (1, "sane_open: failed to generate temporary fname for duplex scans\n"); return SANE_STATUS_NO_MEM; @@ -7926,25 +7930,25 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) s->duplex_rear_fname); } } - + /* calibrate film scanners, as this must be done without the film holder and at the full resolution */ if (dev->scanner_type == AV_FILM) { int default_res = s->val[OPT_RESOLUTION].w; s->val[OPT_RESOLUTION].w = dev->inquiry_optical_res; - + DBG (1, "sane_open: early calibration for film scanner.\n"); - + compute_parameters (s); - + status = set_window (s); if (status != SANE_STATUS_GOOD) { DBG (1, "sane_open: set scan window command failed: %s\n", sane_strstatus (status)); return status; } - + if (!(dev->hw->feature_type & AV_NO_CALIB)) { status = normal_calibration (s); @@ -7954,16 +7958,16 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) return status; } } - + if (dev->scanner_type == AV_FILM) { status = object_position (s, AVISION_SCSI_OP_GO_HOME); if (status != SANE_STATUS_GOOD) DBG (1, "reader_open: object position go-home failed!\n"); } - + s->val[OPT_RESOLUTION].w = default_res; } - + return SANE_STATUS_GOOD; } @@ -7975,12 +7979,12 @@ sane_close (SANE_Handle handle) int i; DBG (3, "sane_close:\n"); - + /* close the device */ if (avision_is_open (&s->av_con) ) { avision_close (&s->av_con); } - + /* remove handle from list of open handles: */ prev = 0; for (s = first_handle; s; s = s->next) { @@ -8008,20 +8012,20 @@ sane_close (SANE_Handle handle) free (s->val[i].s); } } - + if (s->white_avg_data) free (s->white_avg_data); if (s->dark_avg_data) free (s->dark_avg_data); - + if (s->background_raster) free (s->background_raster); - + if (*(s->duplex_rear_fname)) { unlink (s->duplex_rear_fname); *(s->duplex_rear_fname) = 0; } - + free (handle); } @@ -8029,7 +8033,7 @@ const SANE_Option_Descriptor* sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) { Avision_Scanner* s = handle; - + DBG (3, "sane_get_option_descriptor: %d\n", option); if ((unsigned) option >= NUM_OPTIONS) @@ -8045,7 +8049,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, Avision_Device* dev = s->hw; SANE_Status status; SANE_Word cap; - + DBG (3, "sane_control_option: option=%d, action=%d\n", (int)option, (int)action); @@ -8060,7 +8064,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (s->scanning) return SANE_STATUS_DEVICE_BUSY; - + if (option >= NUM_OPTIONS) return SANE_STATUS_INVAL; @@ -8075,7 +8079,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { /* word options: */ case OPT_PREVIEW: - + case OPT_RESOLUTION: case OPT_SPEED: case OPT_TL_X: @@ -8086,7 +8090,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_OVERSCAN_BOTTOM: case OPT_BACKGROUND: case OPT_NUM_OPTS: - + case OPT_BRIGHTNESS: case OPT_CONTRAST: case OPT_EXPOSURE: @@ -8098,19 +8102,19 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_ADF_FLIP: *(SANE_Word*) val = s->val[option].w; return SANE_STATUS_GOOD; - + /* specially treated word options */ - + case OPT_FRAME: status = get_frame_info (s); *(SANE_Word*) val = s->val[option].w; return status; - + case OPT_POWER_SAVE_TIME: get_power_save_time (s, &(s->val[option].w)); *(SANE_Word*) val = s->val[option].w; return SANE_STATUS_GOOD; - + /* word-array options: */ case OPT_GAMMA_VECTOR: case OPT_GAMMA_VECTOR_R: @@ -8118,7 +8122,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_GAMMA_VECTOR_B: memcpy (val, s->val[option].wa, s->opt[option].size); return SANE_STATUS_GOOD; - + /* string options: */ case OPT_MODE: case OPT_SOURCE: @@ -8129,28 +8133,28 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_MESSAGE: if (dev->inquiry_button_control || dev->inquiry_buttons) status = get_button_status (s); - + strcpy (val, s->val[option].s); s->val[option].s[0] = 0; return SANE_STATUS_GOOD; case OPT_NVRAM: get_and_parse_nvram (s, s->val[option].s, 1024); - + strcpy (val, s->val[option].s); return SANE_STATUS_GOOD; - + } /* end switch option */ } /* end if GET_ACTION_GET_VALUE */ else if (action == SANE_ACTION_SET_VALUE) { if (!SANE_OPTION_IS_SETTABLE (cap)) return SANE_STATUS_INVAL; - + status = constrain_value (s, option, val, info); if (status != SANE_STATUS_GOOD) return status; - + switch (option) { /* side-effect-free word options: */ @@ -8170,7 +8174,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_ADF_FLIP: s->val[option].w = *(SANE_Word*) val; return SANE_STATUS_GOOD; - + /* side-effect-free word-array options: */ case OPT_GAMMA_VECTOR: case OPT_GAMMA_VECTOR_R: @@ -8178,7 +8182,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_GAMMA_VECTOR_B: memcpy (s->val[option].wa, val, s->opt[option].size); return SANE_STATUS_GOOD; - + /* options with side-effects: */ case OPT_RESOLUTION: case OPT_TL_X: @@ -8195,14 +8199,14 @@ sane_control_option (SANE_Handle handle, SANE_Int option, /* string options with side-effects: */ case OPT_SOURCE: - + if (s->val[option].s) { free(s->val[option].s); } s->val[option].s = strdup(val); s->source_mode = match_source_mode (dev, s->val[option].s); s->source_mode_dim = match_source_mode_dim (s->source_mode); - + /* set side-effects */ dev->x_range.max = SANE_FIX ( dev->inquiry_x_ranges[s->source_mode_dim]); @@ -8214,22 +8218,22 @@ sane_control_option (SANE_Handle handle, SANE_Int option, } else { s->opt[OPT_ADF_FLIP].cap |= SANE_CAP_INACTIVE; } - + if (info) *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; - + return SANE_STATUS_GOOD; - + case OPT_MODE: { if (s->val[option].s) free (s->val[option].s); - + s->val[option].s = strdup (val); s->c_mode = match_color_mode (dev, s->val[OPT_MODE].s); - + /* set to mode specific values */ - + /* the gamma table related */ if (!disable_gamma_table) { @@ -8246,7 +8250,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; } - } + } if (info) *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; return SANE_STATUS_GOOD; @@ -8254,7 +8258,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_FRAME: { SANE_Word frame = *((SANE_Word *) val); - + status = set_frame (s, frame); if (status == SANE_STATUS_GOOD) { s->val[OPT_FRAME].w = frame; @@ -8292,9 +8296,9 @@ SANE_Status sane_get_parameters (SANE_Handle handle, SANE_Parameters* params) { Avision_Scanner* s = handle; - + DBG (3, "sane_get_parameters:\n"); - + /* During an actual scan these parameters will have been computed in sane_start(). Otherwise, the values must be computed on demand. The values cannot be changed during a scan to avoid inconsistency. */ @@ -8309,7 +8313,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters* params) /* add background raster lines */ params->lines += s->val[OPT_BACKGROUND].w; } - + return SANE_STATUS_GOOD; } @@ -8318,25 +8322,25 @@ sane_start (SANE_Handle handle) { Avision_Scanner* s = handle; Avision_Device* dev = s->hw; - + SANE_Status status; int fds [2]; DBG (1, "sane_start:\n"); - + /* Make sure there is no scan running!!! */ if (s->scanning) return SANE_STATUS_DEVICE_BUSY; /* Clear cancellation status */ s->cancelled = 0; - + /* Make sure we have a current parameter set. Some of the parameters will be overwritten below, but that's OK. */ status = sane_get_parameters (s, &s->params); if (status != SANE_STATUS_GOOD) { return status; } - + /* for non ADF scans (e.g. scanimage --batch-prompt on a Flatbed scanner) make sure we do not assume it's an ADF scan and optimize something away*/ @@ -8347,7 +8351,7 @@ sane_start (SANE_Handle handle) DBG (1, "sane_start: virtual duplex rear data valid.\n"); goto start_scan_end; } - + /* Check for paper during ADF scans and for sheetfed scanners. */ if (is_adf_scan (s)) { status = media_check (s); @@ -8359,7 +8363,7 @@ sane_start (SANE_Handle handle) else DBG (1, "sane_start: media_check ok\n"); } - + /* Check the light early, to return to the GUI and notify the user. */ if (s->prepared == SANE_FALSE) { if (dev->inquiry_light_control) { @@ -8397,28 +8401,28 @@ sane_start (SANE_Handle handle) { size_t size = 16; uint8_t result[16]; - + DBG (5, "sane_start: reading scanner window size\n"); - + status = simple_read (s, 0x80, 0, &size, result); - + if (status != SANE_STATUS_GOOD) { DBG (1, "sane_start: get pixel size command failed: %s\n", sane_strstatus (status)); goto stop_scanner_and_return; - } + } debug_print_raw (5, "sane_start: pixel_size:", result, size); DBG (5, "sane_start: x-pixels: %d, y-pixels: %d\n", get_quad (&(result[0])), get_quad (&(result[4]))); } #endif - + /* no calibration for ADF pages */ if (s->page > 0) { DBG (1, "sane_start: optimized calibration away.\n"); goto calib_end; } - + /* check whether the user enforces calibration */ if (force_calibration) { DBG (1, "sane_start: calibration enforced in config!\n"); @@ -8431,12 +8435,12 @@ sane_start (SANE_Handle handle) DBG (1, "sane_start: old protocol no calibration needed!\n"); goto calib_end; } - + if (!dev->inquiry_needs_calibration) { DBG (1, "sane_start: due to inquiry no calibration needed!\n"); goto calib_end; } - + /* calibration allowed for this scanner? */ if (dev->hw->feature_type & AV_NO_CALIB) { DBG (1, "sane_start: calibration disabled in device list!!\n"); @@ -8448,28 +8452,28 @@ sane_start (SANE_Handle handle) DBG (1, "sane_start: no calibration for film scanner!\n"); goto calib_end; } - + /* check whether calibration is disabled by the user */ if (disable_calibration) { DBG (1, "sane_start: calibration disabled in config - skipped!\n"); goto calib_end; } - + /* R² reminder: We must not skip the calibration for ADF scans, some scanner (HP 53xx/74xx ASIC series) rely on a calibration data read (and will hang otherwise) */ calib: status = normal_calibration (s); - + if (status != SANE_STATUS_GOOD) { DBG (1, "sane_start: perform calibration failed: %s\n", sane_strstatus (status)); goto stop_scanner_and_return; } - + calib_end: - + if (dev->inquiry_3x3_matrix && dev->inquiry_asic_type >= AV_ASIC_C6 && s->page == 0) { @@ -8478,13 +8482,13 @@ sane_start (SANE_Handle handle) return status; } } - + /* check whether gamma-table is disabled by the user? */ if (disable_gamma_table) { DBG (1, "sane_start: gamma-table disabled in config - skipped!\n"); goto gamma_end; } - + if (dev->hw->feature_type & AV_NO_GAMMA) { DBG (1, "sane_start: gamma table skipped due to device-list!!\n"); goto gamma_end; @@ -8501,9 +8505,9 @@ sane_start (SANE_Handle handle) goto stop_scanner_and_return; } } - + gamma_end: - + if (dev->inquiry_tune_scan_length && is_adf_scan (s)) { status = send_tune_scan_length (s); if (status != SANE_STATUS_GOOD) { @@ -8512,7 +8516,7 @@ sane_start (SANE_Handle handle) goto stop_scanner_and_return; } } - + /* if the device supports retrieving background raster data inquire the data no matter if the user/applications asks for it in order to use it for bottom padding */ @@ -8524,11 +8528,11 @@ sane_start (SANE_Handle handle) goto stop_scanner_and_return; } } - + /* check film holder */ if (dev->scanner_type == AV_FILM && dev->holder_type == 0xff) { DBG (1, "sane_start: no film holder or APS cassette!\n"); - + /* Normally "go_home" is executed from the reader process, but as it will not start we have to reset things here */ if (dev->inquiry_new_protocol) { @@ -8539,33 +8543,33 @@ sane_start (SANE_Handle handle) } goto stop_scanner_and_return; } - + start_scan_end: - + s->scanning = SANE_TRUE; s->page += 1; /* processing next page */ - + if (pipe (fds) < 0) { return SANE_STATUS_IO_ERROR; } - + s->read_fds = fds[0]; s->write_fds = fds[1]; /* create reader routine as new process or thread */ DBG (3, "sane_start: starting thread\n"); s->reader_pid = sanei_thread_begin (reader_process, (void *) s); - + if (sanei_thread_is_forked()) close (s->write_fds); - + return SANE_STATUS_GOOD; - + stop_scanner_and_return: - + /* cancel the scan nicely */ do_cancel (s); - + return status; } @@ -8588,7 +8592,7 @@ sane_read (SANE_Handle handle, SANE_Byte* buf, SANE_Int max_len, SANE_Int* len) if (!s->scanning) return SANE_STATUS_CANCELLED; - + if (nread < 0) { if (errno == EAGAIN) { return SANE_STATUS_GOOD; @@ -8597,9 +8601,9 @@ sane_read (SANE_Handle handle, SANE_Byte* buf, SANE_Int max_len, SANE_Int* len) return SANE_STATUS_IO_ERROR; } } - + *len = nread; - + /* if all data was passed through */ if (nread == 0) return do_eof (s); @@ -8621,16 +8625,16 @@ SANE_Status sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) { Avision_Scanner* s = handle; - + DBG (3, "sane_set_io_mode:\n"); if (!s->scanning) { DBG (3, "sane_set_io_mode: not yet scanning\n"); return SANE_STATUS_INVAL; } - + if (fcntl (s->read_fds, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) return SANE_STATUS_IO_ERROR; - + return SANE_STATUS_GOOD; } @@ -8638,14 +8642,14 @@ SANE_Status sane_get_select_fd (SANE_Handle handle, SANE_Int* fd) { Avision_Scanner* s = handle; - + DBG (3, "sane_get_select_fd:\n"); - + if (!s->scanning) { DBG (3, "sane_get_select_fd: not yet scanning\n"); return SANE_STATUS_INVAL; } - + *fd = s->read_fds; return SANE_STATUS_GOOD; } diff --git a/backend/avision.conf.in b/backend/avision.conf.in index 0862d5c..33e2683 100644 --- a/backend/avision.conf.in +++ b/backend/avision.conf.in @@ -20,4 +20,3 @@ #scsi /dev/scanner # usb libusb:002:003 # usb 0x03f0 0x0701 - diff --git a/backend/avision.h b/backend/avision.h index b26907f..3f42ff6 100644 --- a/backend/avision.h +++ b/backend/avision.h @@ -1,7 +1,7 @@ /******************************************************************************* * SANE - Scanner Access Now Easy. - avision.h + avision.h This file is part of the SANE package. @@ -41,7 +41,7 @@ This backend is based upon the Tamarack backend and adapted to the Avision scanners by René Rebe and Meino Cramer. - + Check the avision.c file for detailed copyright and change-log information. @@ -78,7 +78,7 @@ typedef struct Avision_Connection { AVISION_USB_INT_STATUS, /* interrupt endp. (USB 1.x device) status */ AVISION_USB_BULK_STATUS /* bulk endp. (USB 2.0 device) status */ } usb_status; - + } Avision_Connection; typedef struct Avision_HWEntry { @@ -90,33 +90,33 @@ typedef struct Avision_HWEntry { const char* real_mfg; const char* real_model; - + /* feature overwrites - as embedded CPUs have 16bit enums - this would need a change ... */ /* force no calibration */ #define AV_NO_CALIB ((uint64_t)1<<0) - + /* force all in one command calibration */ #define AV_ONE_CALIB_CMD ((uint64_t)1<<1) - + /* no gamma table */ #define AV_NO_GAMMA ((uint64_t)1<<2) - + /* light check is bogus */ #define AV_LIGHT_CHECK_BOGUS ((uint64_t)1<<3) - + /* no button though the device advertise it */ #define AV_NO_BUTTON ((uint64_t)1<<4) - + /* if the scan area needs to be forced to A3 */ #define AV_FORCE_A3 ((uint64_t)1<<5) - + /* if the scan area and resolution needs to be forced for films */ #define AV_FORCE_FILM ((uint64_t)1<<6) - + /* does not suport, or very broken background (added for AV610C2) */ #define AV_NO_BACKGROUND ((uint64_t)1<<7) - + /* is film scanner - no detection yet */ #define AV_FILMSCANNER ((uint64_t)1<<8) @@ -125,7 +125,7 @@ typedef struct Avision_HWEntry { /* gray calibration data has to be uploaded on the blue channel ... ? */ #define AV_GRAY_CALIB_BLUE ((uint64_t)1<<10) - + /* Interrupt endpoint button readout (so far AV220) */ #define AV_INT_BUTTON ((uint64_t)1<<11) @@ -161,35 +161,35 @@ typedef struct Avision_HWEntry { /* very broken background raster */ #define AV_BACKGROUND_QUIRK ((uint64_t)1<<22) - + /* though marked as GRAY only the scanner can do GRAY modes */ #define AV_GRAY_MODES ((uint64_t)1<<23) /* no seperate, single REAR scan (AV122, DM152, ...) */ #define AV_NO_REAR ((uint64_t)1<<24) - + /* only scan with some known good hardware resolutions, as the scanner fails to properly interpoloate in between (e.g. AV121, DM152 on duplex scans - but also the AV600), software scale and interpolate to all the others */ #define AV_SOFT_SCALE ((uint64_t)1<<25) - + /* does keep window though it does not advertice it - the AV122/DM152 mess up image data if window is resend between ADF pages */ #define AV_DOES_KEEP_WINDOW ((uint64_t)1<<26) - + /* does keep gamma though it does not advertice it */ #define AV_DOES_KEEP_GAMMA ((uint64_t)1<<27) - + /* does the scanner contain a Cancel button? */ #define AV_CANCEL_BUTTON ((uint64_t)1<<28) - + /* is the rear image offset? */ #define AV_REAR_OFFSET ((uint64_t)1<<29) /* some devices do not need a START_SCAN, even hang with it */ #define AV_NO_START_SCAN ((uint64_t)1<<30) - + #define AV_INT_STATUS ((uint64_t)1<<31) /* force no calibration */ @@ -203,7 +203,7 @@ typedef struct Avision_HWEntry { /* For scanners which need to have their firmware read to properly function. */ #define AV_FIRMWARE ((uint64_t)1<<35) - + /* maybe more ...*/ uint64_t feature_type; @@ -252,32 +252,32 @@ typedef enum { enum Avision_Option { OPT_NUM_OPTS = 0, /* must come first */ - + OPT_MODE_GROUP, OPT_MODE, OPT_RESOLUTION, #define OPT_RESOLUTION_DEFAULT 150 OPT_SPEED, OPT_PREVIEW, - + OPT_SOURCE, /* scan source normal, transparency, ADF */ - + OPT_GEOMETRY_GROUP, OPT_TL_X, /* top-left x */ OPT_TL_Y, /* top-left y */ OPT_BR_X, /* bottom-right x */ OPT_BR_Y, /* bottom-right y */ - + OPT_OVERSCAN_TOP, /* overscan for auto-crop/deskew, if supported */ OPT_OVERSCAN_BOTTOM, OPT_BACKGROUND, /* background raster lines to read out */ - + OPT_ENHANCEMENT_GROUP, OPT_BRIGHTNESS, OPT_CONTRAST, OPT_QSCAN, OPT_QCALIB, - + OPT_GAMMA_VECTOR, /* first must be gray */ OPT_GAMMA_VECTOR_R, /* then r g b vector */ OPT_GAMMA_VECTOR_G, @@ -286,15 +286,15 @@ enum Avision_Option OPT_EXPOSURE, /* film exposure adjustment */ OPT_IR, /* infra-red */ OPT_MULTISAMPLE, /* multi-sample */ - + OPT_MISC_GROUP, OPT_FRAME, /* Film holder control */ OPT_POWER_SAVE_TIME, /* set power save time to the scanner */ - OPT_MESSAGE, /* optional message from the scanner display */ + OPT_MESSAGE, /* optional message from the scanner display */ OPT_NVRAM, /* retrieve NVRAM values as pretty printed text */ - + OPT_PAPERLEN, /* Use paper_length field to detect double feeds */ OPT_ADF_FLIP, /* For flipping duplex, reflip the document */ @@ -306,28 +306,28 @@ typedef struct Avision_Dimensions /* in dpi */ int xres; int yres; - + /* in pixels */ long tlx; long tly; long brx; long bry; - + /* in pixels */ int line_difference; int rear_offset; /* in pixels of HW res */ /* interlaced duplex scan */ SANE_Bool interlaced_duplex; - + /* in dpi, likewise - different if software scaling required */ int hw_xres; int hw_yres; - + int hw_pixels_per_line; int hw_bytes_per_line; int hw_lines; - + } Avision_Dimensions; /* this contains our low-level info - not relevant for the SANE interface */ @@ -336,7 +336,7 @@ typedef struct Avision_Device struct Avision_Device* next; SANE_Device sane; Avision_Connection connection; - + /* structs used to store config options */ SANE_Range dpi_range; SANE_Range x_range; @@ -369,34 +369,34 @@ typedef struct Avision_Device SANE_Bool inquiry_light_detect; SANE_Bool inquiry_light_control; SANE_Bool inquiry_exposure_control; - + int inquiry_max_shading_target; SANE_Bool inquiry_button_control; unsigned int inquiry_buttons; SANE_Bool inquiry_tune_scan_length; SANE_Bool inquiry_background_raster; int inquiry_background_raster_pixel; - + enum {AV_FLATBED, AV_FILM, AV_SHEETFEED } scanner_type; - + /* the list of available color modes */ SANE_String_Const color_list[AV_COLOR_MODE_LAST + 1]; color_mode color_list_num[AV_COLOR_MODE_LAST]; color_mode color_list_default; - + /* the list of available source modes */ SANE_String_Const source_list[AV_SOURCE_MODE_LAST + 1]; source_mode source_list_num[AV_SOURCE_MODE_LAST]; - + int inquiry_optical_res; /* in dpi */ int inquiry_max_res; /* in dpi */ - + double inquiry_x_ranges [AV_SOURCE_MODE_DIM_LAST]; /* in mm */ double inquiry_y_ranges [AV_SOURCE_MODE_DIM_LAST]; /* in mm */ - + int inquiry_color_boundary; int inquiry_gray_boundary; int inquiry_dithered_boundary; @@ -406,7 +406,7 @@ typedef struct Avision_Device int inquiry_channels_per_pixel; int inquiry_bits_per_channel; int inquiry_no_gray_modes; - + int scsi_buffer_size; /* nice to have SCSI buffer size */ int read_stripe_size; /* stripes to be read at-a-time */ @@ -414,10 +414,10 @@ typedef struct Avision_Device SANE_Range frame_range; SANE_Word current_frame; SANE_Word holder_type; - + /* some versin corrections */ uint16_t data_dq; /* was ox0A0D - but hangs some new scanners */ - + Avision_HWEntry* hw; } Avision_Device; @@ -426,19 +426,19 @@ typedef struct Avision_Scanner { struct Avision_Scanner* next; Avision_Device* hw; - + SANE_Option_Descriptor opt [NUM_OPTIONS]; Option_Value val [NUM_OPTIONS]; SANE_Int gamma_table [4][256]; - + /* we now save the calib data because we might need it for 16bit software calibration :-( */ uint8_t* dark_avg_data; uint8_t* white_avg_data; - + /* background raster data, if duplex first front, then rear */ uint8_t* background_raster; - + /* Parsed option values and variables that are valid only during the actual scan: */ SANE_Bool prepared; /* first page marker */ @@ -448,22 +448,22 @@ typedef struct Avision_Scanner SANE_Parameters params; /* scan window */ Avision_Dimensions avdimen; /* scan window - detailed internals */ - + /* Internal data for duplex scans */ char duplex_rear_fname [PATH_MAX]; SANE_Bool duplex_rear_valid; - + color_mode c_mode; source_mode source_mode; source_mode_dim source_mode_dim; - + /* Avision HW Access Connection (SCSI/USB abstraction) */ Avision_Connection av_con; SANE_Pid reader_pid; /* process id of reader */ int read_fds; /* pipe reading end */ int write_fds; /* pipe writing end */ - + } Avision_Scanner; /* Some Avision driver internal defines */ @@ -549,7 +549,7 @@ typedef struct command_send uint8_t opc; uint8_t bitset1; uint8_t datatypecode; - uint8_t reserved0; + uint8_t reserved0; uint8_t datatypequal [2]; uint8_t transferlen [3]; uint8_t reserved1; @@ -602,7 +602,7 @@ typedef struct nvram_data uint8_t jam_count [4]; uint8_t reserved; - char identify_info[16]; + char identify_info[16]; char formal_name[16]; uint8_t reserved2 [10]; @@ -614,7 +614,7 @@ typedef struct command_set_window_window uint8_t reserved0 [6]; uint8_t desclen [2]; } header; - + struct { uint8_t winid; uint8_t reserved0; @@ -641,37 +641,37 @@ typedef struct command_set_window_window uint8_t vendor_specific; uint8_t paralen; /* bytes following after this byte */ } descriptor; - + struct { uint8_t bitset1; uint8_t highlight; uint8_t shadow; uint8_t line_width [2]; uint8_t line_count [2]; - + /* the tail is quite version and model specific */ union { struct { uint8_t bitset2; uint8_t reserved; } old; - + struct { uint8_t bitset2; uint8_t ir_exposure_time; - + /* optional */ uint8_t r_exposure_time [2]; uint8_t g_exposure_time [2]; uint8_t b_exposure_time [2]; - + uint8_t bitset3; /* reserved in the v2 */ uint8_t auto_focus; uint8_t line_width_msb; uint8_t line_count_msb; uint8_t background_lines; } normal; - + struct { uint8_t reserved0 [4]; uint8_t paper_size; @@ -716,7 +716,7 @@ typedef struct calibration_format uint16_t r_dark_shading_target; uint16_t g_dark_shading_target; uint16_t b_dark_shading_target; - + /* not returned but usefull in some places */ uint8_t channels; } calibration_format; @@ -726,7 +726,7 @@ typedef struct matrix_3x3 uint16_t v[9]; } matrix_3x3; -typedef struct acceleration_info +typedef struct acceleration_info { uint16_t total_steps; uint16_t stable_steps; diff --git a/backend/bh.c b/backend/bh.c index 9424bd6..60741cc 100644 --- a/backend/bh.c +++ b/backend/bh.c @@ -76,7 +76,7 @@ static SANE_Int fake_inquiry = 0; static int allblank(const char *s) { - while (s && *s) + while (s && *s) if (!isspace(*s++)) return 0; @@ -111,10 +111,10 @@ trim_spaces(char *s, size_t n) } static SANE_String_Const -print_devtype (SANE_Byte devtype) +print_devtype (SANE_Byte devtype) { static SANE_String devtypes[] = - { + { "disk", "tape", "printer", @@ -127,21 +127,21 @@ print_devtype (SANE_Byte devtype) "communicator" }; - return (devtype > 0 && devtype < NELEMS(devtypes)) ? - devtypes[devtype] : + return (devtype > 0 && devtype < NELEMS(devtypes)) ? + devtypes[devtype] : "unknown-device"; } static SANE_String_Const -print_barcodetype (SANE_Int i) +print_barcodetype (SANE_Int i) { - return (i > 0 && i < NELEMS(barcode_search_bar_list)) ? - barcode_search_bar_list[i] : + return (i > 0 && i < NELEMS(barcode_search_bar_list)) ? + barcode_search_bar_list[i] : (SANE_String_Const) "unknown"; } static SANE_String_Const -print_orientation (SANE_Int i) +print_orientation (SANE_Int i) { switch(i) { @@ -163,7 +163,7 @@ print_orientation (SANE_Int i) } static SANE_String_Const -print_read_type (SANE_Int i) +print_read_type (SANE_Int i) { static char buf[32]; SANE_Int n; @@ -249,72 +249,72 @@ print_read_type (SANE_Int i) return buf; } -static SANE_Int +static SANE_Int get_rotation_id(char *s) { SANE_Int i; - for (i = 0; rotation_list[i]; i++) - if (strcmp(s, rotation_list[i]) == 0) + for (i = 0; rotation_list[i]; i++) + if (strcmp(s, rotation_list[i]) == 0) break; /* unknown strings are treated as '0' */ return rotation_list[i] ? i : 0; } -static SANE_Int +static SANE_Int get_compression_id(char *s) { SANE_Int i; - for (i = 0; compression_list[i]; i++) - if (strcmp(s, compression_list[i]) == 0) + for (i = 0; compression_list[i]; i++) + if (strcmp(s, compression_list[i]) == 0) break; /* unknown strings are treated as 'none' */ return compression_list[i] ? i : 0; } -static SANE_Int +static SANE_Int get_barcode_id(char *s) { SANE_Int i; - for (i = 0; barcode_search_bar_list[i]; i++) - if (strcmp(s, barcode_search_bar_list[i]) == 0) + for (i = 0; barcode_search_bar_list[i]; i++) + if (strcmp(s, barcode_search_bar_list[i]) == 0) break; /* unknown strings are treated as 'none' */ return barcode_search_bar_list[i] ? i : 0; } -static SANE_Int +static SANE_Int get_scan_mode_id(char *s) { SANE_Int i; - for (i = 0; scan_mode_list[i]; i++) - if (strcmp(s, scan_mode_list[i]) == 0) + for (i = 0; scan_mode_list[i]; i++) + if (strcmp(s, scan_mode_list[i]) == 0) break; /* unknown strings are treated as 'lineart' */ return scan_mode_list[i] ? i : 0; } -static SANE_Int +static SANE_Int get_paper_id(char *s) { SANE_Int i; - for (i = 0; paper_list[i]; i++) - if (strcmp(s, paper_list[i]) == 0) + for (i = 0; paper_list[i]; i++) + if (strcmp(s, paper_list[i]) == 0) break; /* unknown strings are treated as 'custom' */ return paper_list[i] ? i : 0; } -static SANE_Int +static SANE_Int get_barcode_search_mode(char *s) { SANE_Int i; @@ -335,7 +335,7 @@ get_barcode_search_mode(char *s) { i = 9; } - else + else { /* unknown strings are treated as 'horiz-vert' */ DBG(1, "get_barcode_search_mode: unrecognized string `%s'\n", s); @@ -345,7 +345,7 @@ get_barcode_search_mode(char *s) return i; } -static void +static void appendStdList(BH_Info *sc, SANE_Int res) { /* append entry to resolution list - a SANE_WORD_LIST */ @@ -353,7 +353,7 @@ appendStdList(BH_Info *sc, SANE_Int res) sc->resStdList[0]++; } -static void +static void ScannerDump(BH_Scanner *s) { int i; @@ -370,9 +370,9 @@ ScannerDump(BH_Scanner *s) sdev->type); DBG (1, "Type: '%s' Vendor: '%s' Product: '%s' Revision: '%s'\n", - print_devtype(info->devtype), - info->vendor, - info->product, + print_devtype(info->devtype), + info->vendor, + info->product, info->revision); DBG (1, "Automatic Document Feeder:%s\n", @@ -399,8 +399,8 @@ ScannerDump(BH_Scanner *s) info->canBarCode ? " " : "", info->canIcon ? " " : "", info->canSection ? "
" : ""); - - DBG (1, "Max bytes per scan-line: %d (%d pixels)\n", + + DBG (1, "Max bytes per scan-line: %d (%d pixels)\n", info->lineMaxBytes, info->lineMaxBytes * 8); @@ -408,11 +408,11 @@ ScannerDump(BH_Scanner *s) info->resBasicX, info->resBasicY); - DBG (1, "Maximum resolution (X/Y): %d/%d\n", + DBG (1, "Maximum resolution (X/Y): %d/%d\n", info->resMaxX, info->resMaxY); - DBG (1, "Minimum resolution (X/Y): %d/%d\n", + DBG (1, "Minimum resolution (X/Y): %d/%d\n", info->resMinX, info->resMinY); @@ -421,8 +421,8 @@ ScannerDump(BH_Scanner *s) DBG (1, " %d\n", info->resStdList[i+1]); DBG (1, "Window Width/Height (in basic res) %d/%d (%.2f/%.2f inches)\n", - info->winWidth, - info->winHeight, + info->winWidth, + info->winHeight, (info->resBasicX != 0) ? ((float) info->winWidth) / info->resBasicX : 0.0, (info->resBasicY) ? ((float) info->winHeight) / info->resBasicY : 0.0); @@ -430,15 +430,15 @@ ScannerDump(BH_Scanner *s) info->canDuplex ? "Duplex Scanner" : "Simplex Scanner", info->canACE ? " (ACE capable)" : "", info->canCheckADF ? " (ADF Paper Sensor capable)" : ""); - + sprintf(inquiry_data, "Vendor: %s Product: %s Rev: %s %s%s%s\n", - info->vendor, - info->product, + info->vendor, + info->product, info->revision, info->canDuplex ? "Duplex Scanner" : "Simplex Scanner", info->canACE ? " (ACE capable)" : "", info->canCheckADF ? " (ADF Paper Sensor capable)" : ""); - + DBG (5, "autoborder_default=%d\n", info->autoborder_default); DBG (5, "batch_default=%d\n", info->batch_default); DBG (5, "deskew_default=%d\n", info->deskew_default); @@ -534,7 +534,7 @@ read_barcode_data (BH_Scanner *s, FILE *fp) l += (BH_DECODE_FUDGE * 4); /* write the decoded barcode data into the file */ - fprintf(fp, "\n
%s
\n", + fprintf(fp, "\n
%s
\n", print_read_type((int) s->readlist[s->readptr])); fprintf(fp, " %s\n %d\n", print_barcodetype((int) _2btol(buf.barcodetype)), @@ -558,7 +558,7 @@ read_barcode_data (BH_Scanner *s, FILE *fp) buf.barcodedata); } while (num_found <= BH_DECODE_TRIES); - DBG (3, "read_barcode_data: found %d barcodes, returning %s\n", + DBG (3, "read_barcode_data: found %d barcodes, returning %s\n", num_found, sane_strstatus(status)); return status; @@ -581,7 +581,7 @@ read_icon_data (BH_Scanner *s) memset (&buf, 0, sizeof(buf)); status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), &buf, &buf_size); - + /* set the fields in the scanner handle for later reference */ s->iconwidth = _4btol(buf.iconwidth); s->iconlength = _4btol(buf.iconlength); @@ -593,7 +593,7 @@ read_icon_data (BH_Scanner *s) _4btol(buf.iconwidth), _4btol(buf.iconlength), _4btol(buf.iconwidthbytes)); - DBG(3, "read_icon_data: bitordering:%02x, icondatalen:%lu\n", + DBG(3, "read_icon_data: bitordering:%02x, icondatalen:%lu\n", buf.bitordering, _4btol(buf.icondatalen)); @@ -611,7 +611,7 @@ read_barfile (BH_Scanner *s, void *buf, size_t *buf_size) if (s->barf != NULL) { - /* this function needs to set InvalidBytes so it looks + /* this function needs to set InvalidBytes so it looks * like a B&H scsi EOF */ if ((nread = fread(buf, 1, *buf_size, s->barf)) < *buf_size) @@ -802,7 +802,7 @@ mode_select_barcode_param1 (BH_Scanner *s) _lto2b((SANE_Int)_OPT_VAL_WORD_THOUSANDTHS(s, OPT_BARCODE_HMIN), select_cmd.mp.minbarheight); select_cmd.mp.searchcount = _OPT_VAL_WORD(s, OPT_BARCODE_SEARCH_COUNT); - select_cmd.mp.searchmode = + select_cmd.mp.searchmode = get_barcode_search_mode(_OPT_VAL_STRING(s, OPT_BARCODE_SEARCH_MODE)); _lto2b(_OPT_VAL_WORD(s, OPT_BARCODE_SEARCH_TIMEOUT), select_cmd.mp.searchtimeout); @@ -832,10 +832,10 @@ mode_select_barcode_param2 (BH_Scanner *s) select_cmd.cmd[4] = sizeof(select_cmd.mp); len = sizeof(select_cmd.mp); - status = sanei_scsi_cmd (s->fd, &select_cmd.cmd, sizeof (select_cmd.cmd), + status = sanei_scsi_cmd (s->fd, &select_cmd.cmd, sizeof (select_cmd.cmd), &select_cmd.mp, &len); - if (status == SANE_STATUS_GOOD) + if (status == SANE_STATUS_GOOD) { DBG(8, "mode_select_barcode_param2: sensed values: relmax:%d barmin:%d barmax:%d\n", (int) _2btol(select_cmd.mp.relmax), @@ -906,10 +906,10 @@ mode_select_barcode_param3 (BH_Scanner *s) select_cmd.cmd[4] = sizeof(select_cmd.mp); len = sizeof(select_cmd.mp); - status = sanei_scsi_cmd (s->fd, &select_cmd.cmd, sizeof (select_cmd.cmd), + status = sanei_scsi_cmd (s->fd, &select_cmd.cmd, sizeof (select_cmd.cmd), &select_cmd.mp, &len); - if (status == SANE_STATUS_GOOD) + if (status == SANE_STATUS_GOOD) { DBG(8, "mode_select_barcode_param3: sensed values: contrast:%d patchmode:%d\n", (int) _2btol(select_cmd.mp.barcodecontrast), @@ -992,10 +992,10 @@ set_window (BH_Scanner *s, SANE_Byte batchmode) memset (&set_window_cmd, 0, sizeof (set_window_cmd)); set_window_cmd.cmd[0] = BH_SCSI_SET_WINDOW; - DBG(3, "set_window: sizeof(hdr) %d, sizeof(window): %d\n", + DBG(3, "set_window: sizeof(hdr) %d, sizeof(window): %d\n", (int)sizeof(set_window_cmd.hdr), (int)sizeof(set_window_cmd.window)); - _lto3b(sizeof(set_window_cmd.hdr) + sizeof(set_window_cmd.window), + _lto3b(sizeof(set_window_cmd.hdr) + sizeof(set_window_cmd.window), &set_window_cmd.cmd[6]); _lto2b(256, &set_window_cmd.hdr[6]); @@ -1008,9 +1008,9 @@ set_window (BH_Scanner *s, SANE_Byte batchmode) _lto4b((int) _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_X), set_window_cmd.window.ulx); _lto4b((int) _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_Y), set_window_cmd.window.uly); - width = (SANE_Int) (_OPT_VAL_WORD_THOUSANDTHS(s, OPT_BR_X) - + width = (SANE_Int) (_OPT_VAL_WORD_THOUSANDTHS(s, OPT_BR_X) - _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_X)); - length = (SANE_Int) (_OPT_VAL_WORD_THOUSANDTHS(s, OPT_BR_Y) - + length = (SANE_Int) (_OPT_VAL_WORD_THOUSANDTHS(s, OPT_BR_Y) - _OPT_VAL_WORD_THOUSANDTHS(s, OPT_TL_Y)); _lto4b(width, set_window_cmd.window.windowwidth); @@ -1023,16 +1023,16 @@ set_window (BH_Scanner *s, SANE_Byte batchmode) /*!!! contrast (not used) */ /*!!! set_window_cmd.window.contrast = _OPT_VAL_WORD(s, OPT_CONTRAST); */ /* imagecomposition 0x00 lineart, 0x01 dithered/halftone, 0x02 grayscale*/ - set_window_cmd.window.imagecomposition = + set_window_cmd.window.imagecomposition = get_scan_mode_id(_OPT_VAL_STRING(s, OPT_SCAN_MODE)); - + set_window_cmd.window.bitsperpixel = 0x01; /*!!! halftone code (not used) */ /*!!! halftone id (not used) */ set_window_cmd.window.paddingtype = 0x03; /* truncate byte */ if (_OPT_VAL_WORD(s, OPT_NEGATIVE) == SANE_TRUE) { - /* reverse image format (valid when bitsperpixel=1) + /* reverse image format (valid when bitsperpixel=1) * 0x00 normal, 0x01 reversed. This is bit 7 of paddingtype. */ set_window_cmd.window.paddingtype |= 0x80; @@ -1134,7 +1134,7 @@ get_window (BH_Scanner *s, SANE_Int *w, SANE_Int *h, SANE_Bool backpage) autoborder = _OPT_VAL_WORD(s, OPT_AUTOBORDER) == 1; - while (1) + while (1) { i++; memset (&cmd, 0, sizeof (cmd)); @@ -1148,7 +1148,7 @@ get_window (BH_Scanner *s, SANE_Int *w, SANE_Int *h, SANE_Bool backpage) get_window_data.window.windowid = (backpage == SANE_TRUE) ? 1 : 0; len = sizeof(get_window_data); - status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), + status = sanei_scsi_cmd (s->fd, &cmd, sizeof (cmd), &get_window_data, &len); if (status == SANE_STATUS_GOOD) { @@ -1198,9 +1198,9 @@ get_parameters (SANE_Handle handle, SANE_Parameters *params) SANE_Frame format; DBG(3, "get_parameters called\n"); - + memset (&s->params, 0, sizeof (s->params)); - + res = _OPT_VAL_WORD(s, OPT_RESOLUTION); /* make best-effort guess at what parameters will look like once @@ -1242,7 +1242,7 @@ get_parameters (SANE_Handle handle, SANE_Parameters *params) /* update parameters based on the current item */ status = SANE_STATUS_GOOD; - if (itemtype == BH_SCSI_READ_TYPE_FRONT) + if (itemtype == BH_SCSI_READ_TYPE_FRONT) { DBG (3, "get_parameters: sending GET WINDOW (front)\n"); status = get_window (s, &w, &l, SANE_FALSE); @@ -1293,7 +1293,7 @@ get_parameters (SANE_Handle handle, SANE_Parameters *params) length = s->sections[sectnum - 1].length * res / 1000.0; } else if ( (itemtype >= BH_SCSI_READ_TYPE_BACK_BARCODE && - itemtype <= (BH_SCSI_READ_TYPE_BACK_BARCODE + NUM_SECTIONS)) || + itemtype <= (BH_SCSI_READ_TYPE_BACK_BARCODE + NUM_SECTIONS)) || (itemtype >= BH_SCSI_READ_TYPE_FRONT_BARCODE && itemtype <= (BH_SCSI_READ_TYPE_FRONT_BARCODE + NUM_SECTIONS)) ) { @@ -1331,7 +1331,7 @@ get_parameters (SANE_Handle handle, SANE_Parameters *params) res, width, length); return SANE_STATUS_INVAL; } - + /* we disable our compression/barcode formats in preview as well * as with the disable_optional_frames configuration option. NOTE: * we may still be delivering 'wierd' data and lying about it being _GRAY! @@ -1357,11 +1357,11 @@ get_parameters (SANE_Handle handle, SANE_Parameters *params) *params = s->params; DBG (1, "get_parameters: format=%d, pixels/line=%d, bytes/line=%d, " - "lines=%d, dpi=%d\n", - (int) s->params.format, - s->params.pixels_per_line, + "lines=%d, dpi=%d\n", + (int) s->params.format, + s->params.pixels_per_line, s->params.bytes_per_line, - s->params.lines, + s->params.lines, res); return SANE_STATUS_GOOD; @@ -1404,7 +1404,7 @@ section_parse(const char *val, BH_Section *sect, SANE_Int res, SANE_Int comp) if (y) f = strtok(NULL, seps); if (!x || !y || !w || !l) break; - mm = strtod(x, &ep); + mm = strtod(x, &ep); if (*ep != '\0' || errno == ERANGE || mm < 0.0) break; sect->left = mm * 1000.0 / MM_PER_INCH; @@ -1482,10 +1482,10 @@ section_parse(const char *val, BH_Section *sect, SANE_Int res, SANE_Int comp) DBG(3, "section_parse: converted '%s' (mm) to " "%ldx%ld+%ld+%ld (thousandths) " - "flags=%02x compression=[%d,%d] frame=%s\n", - val, + "flags=%02x compression=[%d,%d] frame=%s\n", + val, sect->width, sect->length, sect->left, sect->top, - sect->flags, + sect->flags, sect->compressiontype, sect->compressionarg, sane_strframe(sect->format)); @@ -1515,20 +1515,20 @@ setup_sections (BH_Scanner *s, const char *val) strcpy(buf, val); section = strtok(buf, ","); - while (section != NULL && sectnum < NUM_SECTIONS) + while (section != NULL && sectnum < NUM_SECTIONS) { - if (!allblank(section)) + if (!allblank(section)) { SANE_Int res = _OPT_VAL_WORD(s, OPT_RESOLUTION); - SANE_Int format = + SANE_Int format = get_compression_id(_OPT_VAL_STRING(s, OPT_COMPRESSION)); - status = section_parse(section, &s->sections[sectnum], + status = section_parse(section, &s->sections[sectnum], res, format); if (status != SANE_STATUS_GOOD) { - DBG(1, - "setup_sections: error parsing section `%s'\n", + DBG(1, + "setup_sections: error parsing section `%s'\n", section); break; } @@ -1562,12 +1562,12 @@ start_setup (BH_Scanner *s) status = setup_sections(s, _OPT_VAL_STRING(s, OPT_SECTION)); if (status != SANE_STATUS_GOOD) { - DBG(1, "start_setup: setup_sections failed: %s\n", + DBG(1, "start_setup: setup_sections failed: %s\n", sane_strstatus(status)); return status; } - /* see whether we'll be decoding barcodes and + /* see whether we'll be decoding barcodes and * set the barcodes flag appropriately */ if (s->search_bars[0] == 0) @@ -1655,10 +1655,10 @@ start_setup (BH_Scanner *s) SANE_Word flags = s->sections[i].flags; if (flags & BH_SECTION_FRONT_BAR) - s->readlist[s->readcnt++] = + s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_FRONT_BARCODE + i + 1; if (flags & BH_SECTION_BACK_BAR) - s->readlist[s->readcnt++] = + s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_BACK_BARCODE + i + 1; } } @@ -1687,10 +1687,10 @@ start_setup (BH_Scanner *s) SANE_Word flags = s->sections[i].flags; if (flags & BH_SECTION_FRONT_PATCH) - s->readlist[s->readcnt++] = + s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_FRONT_PATCHCODE + i + 1; if (flags & BH_SECTION_BACK_PATCH) - s->readlist[s->readcnt++] = + s->readlist[s->readcnt++] = BH_SCSI_READ_TYPE_BACK_PATCHCODE + i + 1; } } @@ -1707,7 +1707,7 @@ start_setup (BH_Scanner *s) if (_OPT_VAL_WORD(s, OPT_BATCH) == SANE_TRUE) { - /* if batchmode is enabled, then call set_window to + /* if batchmode is enabled, then call set_window to * abort the batch (even though there might not (and probably * isn't) a batch in progress). This avoids a batch start error * in the case where a previous batch was not aborted. @@ -1716,7 +1716,7 @@ start_setup (BH_Scanner *s) set_window(s, BH_BATCH_ABORT); batchmode = BH_BATCH_ENABLE; - } + } else { batchmode = BH_BATCH_DISABLE; @@ -1750,7 +1750,7 @@ start_setup (BH_Scanner *s) status = set_window(s, batchmode); if (status != SANE_STATUS_GOOD) { - DBG(1, "start_setup: SET WINDOW failed: %s\n", + DBG(1, "start_setup: SET WINDOW failed: %s\n", sane_strstatus(status)); return status; } @@ -1759,7 +1759,7 @@ start_setup (BH_Scanner *s) status = mode_select_timeout(s); if (status != SANE_STATUS_GOOD) { - DBG(1, "start_setup: mode_select_timeout failed: %s\n", + DBG(1, "start_setup: mode_select_timeout failed: %s\n", sane_strstatus(status)); return status; } @@ -1770,7 +1770,7 @@ start_setup (BH_Scanner *s) status = mode_select_icon(s); if (status != SANE_STATUS_GOOD) { - DBG(1, "start_setup: mode_select_icon failed: %s\n", + DBG(1, "start_setup: mode_select_icon failed: %s\n", sane_strstatus(status)); return status; } @@ -1782,7 +1782,7 @@ start_setup (BH_Scanner *s) status = mode_select_barcode_priority(s); if (status != SANE_STATUS_GOOD) { - DBG(1, "start_setup: mode_select_barcode_priority failed: %s\n", + DBG(1, "start_setup: mode_select_barcode_priority failed: %s\n", sane_strstatus(status)); return status; } @@ -1791,7 +1791,7 @@ start_setup (BH_Scanner *s) status = mode_select_barcode_param1(s); if (status != SANE_STATUS_GOOD) { - DBG(1, "start_setup: mode_select_barcode_param1 failed: %s\n", + DBG(1, "start_setup: mode_select_barcode_param1 failed: %s\n", sane_strstatus(status)); return status; } @@ -1800,7 +1800,7 @@ start_setup (BH_Scanner *s) status = mode_select_barcode_param2(s); if (status != SANE_STATUS_GOOD) { - DBG(1, "start_setup: mode_select_barcode_param2 failed: %s\n", + DBG(1, "start_setup: mode_select_barcode_param2 failed: %s\n", sane_strstatus(status)); return status; } @@ -1809,7 +1809,7 @@ start_setup (BH_Scanner *s) status = mode_select_barcode_param3(s); if (status != SANE_STATUS_GOOD) { - DBG(1, "start_setup: mode_select_barcode_param3 failed: %s\n", + DBG(1, "start_setup: mode_select_barcode_param3 failed: %s\n", sane_strstatus(status)); return status; } @@ -1829,13 +1829,13 @@ start_scan (BH_Scanner *s) /* SANE front ends will call this function between 'FRAMES'. * A single scan on the B&H may result in up to 56 different * things to read (20 are SANE image frames, 36 are non-SANE - * data - decoded bar/patch codes). + * data - decoded bar/patch codes). */ if (s->readcnt > 1 && s->scanning == SANE_TRUE) { DBG(3, "start_scan: any more items in the readlist?\n"); - /* we've been reading data from this scan, so we just + /* we've been reading data from this scan, so we just * move on to the next item in the readlist without * starting a new scan. */ @@ -1850,7 +1850,7 @@ start_scan (BH_Scanner *s) itemtype = s->readlist[s->readptr]; DBG(3, "start_scan: advance readlist(%d, %d)\n", - s->readptr, + s->readptr, (int) itemtype); /* 'dance' by the non-SANE data streams @@ -1869,12 +1869,12 @@ start_scan (BH_Scanner *s) { fprintf(fp, "\n"); - for (; - s->readptr < s->readcnt && - status == SANE_STATUS_GOOD; + for (; + s->readptr < s->readcnt && + status == SANE_STATUS_GOOD; s->readptr++) { - if (s->readlist[s->readptr] == + if (s->readlist[s->readptr] == BH_SCSI_READ_TYPE_SENDBARFILE) { break; } @@ -1888,14 +1888,14 @@ start_scan (BH_Scanner *s) fclose(fp); if ((s->barf = fopen(s->barfname, "r")) == NULL) { - DBG(1, "sane_start: error opening barfile `%s'\n", + DBG(1, "sane_start: error opening barfile `%s'\n", s->barfname); status = SANE_STATUS_IO_ERROR; } } else { - DBG(1, "sane_start: error opening barfile `%s'\n", + DBG(1, "sane_start: error opening barfile `%s'\n", s->barfname); status = SANE_STATUS_IO_ERROR; } @@ -1905,7 +1905,7 @@ start_scan (BH_Scanner *s) { /* read the icon header setting the iconwidth and iconlength * to the actual values so get_parameters will have them. - * Subsequent calls to sane_read will get pure image data + * Subsequent calls to sane_read will get pure image data * since the icon header has been consumed. */ @@ -1922,7 +1922,7 @@ start_scan (BH_Scanner *s) return status; } - /* if we reach here, we're finished with the readlist and + /* if we reach here, we're finished with the readlist and * will drop through to start a new scan */ } @@ -1990,7 +1990,7 @@ sense_handler (int scsi_fd, u_char *result, void *arg) EOM = (result[2] & 0x40) != 0; /* End Of Media */ ILI = (result[2] & 0x20) != 0; /* Invalid Length Indicator */ InvalidBytes = ValidData ? _4btol(&result[3]) : 0; - + DBG(3, "sense_handler: result=%x, sense=%x, asc=%x, ascq=%x\n", result[0], sense, asc, ascq); DBG(3, "sense_handler: ErrorCode %02x ValidData: %d " @@ -2010,8 +2010,8 @@ sense_handler (int scsi_fd, u_char *result, void *arg) return SANE_STATUS_IO_ERROR; /* error code is invalid */ } - /* handle each sense key; - * RSC supports 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0B + /* handle each sense key; + * RSC supports 0x00, 0x02, 0x03, 0x04, 0x05, 0x06, 0x0B */ switch (sense) { @@ -2303,7 +2303,7 @@ sense_handler (int scsi_fd, u_char *result, void *arg) break; } - DBG(3, "sense_handler: '%s' '%s' return:%d\n", + DBG(3, "sense_handler: '%s' '%s' return:%d\n", sense_str, as_str, status); return status; @@ -2712,7 +2712,7 @@ init_options (BH_Scanner * s) s->opt[OPT_BARCODE_SEARCH_BAR].constraint.string_list = barcode_search_bar_list; s->opt[OPT_BARCODE_SEARCH_BAR].size = max_string_size (barcode_search_bar_list); s->val[OPT_BARCODE_SEARCH_BAR].s = strdup (barcode_search_bar_list[0]); - + /* Barcode search count (1-7, default 1). */ s->opt[OPT_BARCODE_SEARCH_COUNT].name = SANE_NAME_BARCODE_SEARCH_COUNT; s->opt[OPT_BARCODE_SEARCH_COUNT].title = SANE_TITLE_BARCODE_SEARCH_COUNT; @@ -2762,7 +2762,7 @@ init_options (BH_Scanner * s) s->opt[OPT_SECTION].constraint_type = SANE_CONSTRAINT_NONE; s->opt[OPT_SECTION].size = 255; s->val[OPT_SECTION].s = strdup (""); - + /* Barcode_Relmax */ s->opt[OPT_BARCODE_RELMAX].name = SANE_NAME_BARCODE_RELMAX; s->opt[OPT_BARCODE_RELMAX].title = SANE_TITLE_BARCODE_RELMAX; @@ -2907,7 +2907,7 @@ attach (const char *devnam, BH_Device ** devp) BH_INQUIRY_STANDARD_PAGE_CODE); if (status != SANE_STATUS_GOOD) { - DBG (1, "attach: inquiry (standard data) failed: %s\n", + DBG (1, "attach: inquiry (standard data) failed: %s\n", sane_strstatus (status)); sanei_scsi_close (fd); return status; @@ -2922,7 +2922,7 @@ attach (const char *devnam, BH_Device ** devp) || strncmp ((char *)ibuf.vendor, "B&H SCSI", 8) != 0 || strncmp ((char *)ibuf.product, "COPISCAN ", 9) != 0) { - DBG (1, + DBG (1, "attach: device is not a recognized Bell and Howell scanner\n"); sanei_scsi_close (fd); return SANE_STATUS_INVAL; @@ -2931,11 +2931,11 @@ attach (const char *devnam, BH_Device ** devp) DBG (3, "attach: sending INQUIRY (vpd data)\n"); memset (&vbuf, 0, sizeof (vbuf)); buf_size = sizeof(vbuf); - status = inquiry (fd, &vbuf, &buf_size, 1, + status = inquiry (fd, &vbuf, &buf_size, 1, BH_INQUIRY_VPD_PAGE_CODE); if (status != SANE_STATUS_GOOD) { - DBG (1, "attach: inquiry (vpd data) failed: %s\n", + DBG (1, "attach: inquiry (vpd data) failed: %s\n", sane_strstatus (status)); sanei_scsi_close (fd); return status; @@ -2944,7 +2944,7 @@ attach (const char *devnam, BH_Device ** devp) DBG (3, "attach: sending INQUIRY (jis data)\n"); memset (&jbuf, 0, sizeof (jbuf)); buf_size = sizeof(jbuf); - status = inquiry (fd, &jbuf, &buf_size, 1, + status = inquiry (fd, &jbuf, &buf_size, 1, BH_INQUIRY_JIS_PAGE_CODE); if (status != SANE_STATUS_GOOD) { @@ -3044,7 +3044,7 @@ attach (const char *devnam, BH_Device ** devp) if (jbuf.standardres[1] & 0x04) appendStdList(&dev->info, 600); if (jbuf.standardres[1] & 0x02) appendStdList(&dev->info, 800); if (jbuf.standardres[1] & 0x01) appendStdList(&dev->info, 1200); - if (dev->info.resStdList[0] == 0) + if (dev->info.resStdList[0] == 0) { /* make a default standard resolutions for 200 and 300dpi */ DBG(1, "attach: no standard resolutions reported\n"); @@ -3053,29 +3053,29 @@ attach (const char *devnam, BH_Device ** devp) dev->info.resStdList[2] = 300; dev->info.resBasicX = dev->info.resBasicY = 300; } - + dev->info.winWidth = _4btol(jbuf.windowwidth); dev->info.winHeight = _4btol(jbuf.windowlength); - if (dev->info.winWidth <= 0) + if (dev->info.winWidth <= 0) { dev->info.winWidth = (SANE_Int) (dev->info.resBasicX * 8.5); DBG(1, "attach: invalid window width reported, using %d\n", dev->info.winWidth); } - if (dev->info.winHeight <= 0) + if (dev->info.winHeight <= 0) { dev->info.winHeight = dev->info.resBasicY * 14; DBG(1, "attach: invalid window height reported, using %d\n", dev->info.winHeight); } - mm = (dev->info.resBasicX > 0) ? + mm = (dev->info.resBasicX > 0) ? ((double) dev->info.winWidth / (double) dev->info.resBasicX * MM_PER_INCH) : 0.0; dev->info.x_range.min = SANE_FIX(0.0); dev->info.x_range.max = SANE_FIX(mm); dev->info.x_range.quant = SANE_FIX(0.0); - mm = (dev->info.resBasicY > 0) ? + mm = (dev->info.resBasicY > 0) ? ((double) dev->info.winHeight / (double) dev->info.resBasicY * MM_PER_INCH) : 0.0; dev->info.y_range.min = SANE_FIX(0.0); @@ -3157,35 +3157,35 @@ sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize) if (version_code) *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD); - + fp = sanei_config_open(BH_CONFIG_FILE); if (fp) { char line[PATH_MAX]; const char *lp; size_t len; - + /* read config file */ while (sanei_config_read (line, sizeof (line), fp)) { if (line[0] == '#') /* ignore line comments */ continue; len = strlen (line); - + if (!len) continue; /* ignore empty lines */ - + lp = sanei_config_skip_whitespace (line); - DBG(16, + DBG(16, "sane_init: processing config file line '%s'\n", line); - if (strncmp(lp, "option", 6) == 0 && + if (strncmp(lp, "option", 6) == 0 && (isspace (lp[6]) || lp[6] == '\0')) { lp += 6; lp = sanei_config_skip_whitespace (lp); - + if (strncmp(lp, "disable-optional-frames", 23) == 0) { DBG(1, "sane_init: configuration option " @@ -3205,15 +3205,15 @@ sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize) lp); } } - else + else { - DBG(16, + DBG(16, "sane_init: found a device: line '%s'\n", lp); strncpy (devnam, lp, sizeof(devnam)); devnam[sizeof(devnam)-1] = '\0'; - - sanei_config_attach_matching_devices(devnam, + + sanei_config_attach_matching_devices(devnam, attach_one); } } @@ -3228,7 +3228,7 @@ sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize) return SANE_STATUS_GOOD; } -SANE_Status +SANE_Status sane_get_devices (const SANE_Device ***device_list, SANE_Bool local) { BH_Device *dev; @@ -3259,7 +3259,7 @@ sane_open (SANE_String_Const devnam, SANE_Handle *handle) BH_Device *dev; BH_Scanner *s; DBG(3, "sane_open called\n"); - + if (devnam[0] != '\0') { for (dev = first_dev; dev; dev = dev->next) @@ -3279,7 +3279,7 @@ sane_open (SANE_String_Const devnam, SANE_Handle *handle) { dev = first_dev; } - + if (!dev) return SANE_STATUS_INVAL; @@ -3432,22 +3432,22 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, { case SANE_TYPE_BOOL: case SANE_TYPE_INT: - DBG(16, "sane_control_option: set_value %s [#%d] to %d\n", + DBG(16, "sane_control_option: set_value %s [#%d] to %d\n", name, option, *(SANE_Word *) val); break; - + case SANE_TYPE_FIXED: - DBG(16, "sane_control_option: set_value %s [#%d] to %f\n", + DBG(16, "sane_control_option: set_value %s [#%d] to %f\n", name, option, SANE_UNFIX(*(SANE_Word *) val)); break; - + case SANE_TYPE_STRING: - DBG(16, "sane_control_option: set_value %s [#%d] to %s\n", + DBG(16, "sane_control_option: set_value %s [#%d] to %s\n", name, option, (char *) val); break; - + default: - DBG(16, "sane_control_option: set_value %s [#%d]\n", + DBG(16, "sane_control_option: set_value %s [#%d]\n", name, option); } @@ -3504,7 +3504,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, case OPT_NUM_OPTS: s->val[option].w = *(SANE_Word *) val; return SANE_STATUS_GOOD; - + /* string options */ case OPT_BARCODE_SEARCH_BAR: /*!!! we're supporting only a single barcode type via the option */ @@ -3584,7 +3584,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, if (info) *info |= SANE_INFO_RELOAD_OPTIONS; if (get_scan_mode_id((SANE_String) val) != 0) { - /* scan mode is not lineart, disable compression + /* scan mode is not lineart, disable compression * and set compression to 'none' */ s->opt[OPT_COMPRESSION].cap |= SANE_CAP_INACTIVE; @@ -3622,9 +3622,9 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, x_max = SANE_UNFIX(s->hw->info.x_range.max); y_max = SANE_UNFIX(s->hw->info.y_range.max); /* a dimension of 0.0 (or less) is replaced with the max value */ - x = (paper_sizes[paper_id].width <= 0.0) ? x_max : + x = (paper_sizes[paper_id].width <= 0.0) ? x_max : paper_sizes[paper_id].width; - y = (paper_sizes[paper_id].length <= 0.0) ? y_max : + y = (paper_sizes[paper_id].length <= 0.0) ? y_max : paper_sizes[paper_id].length; if (info) *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; @@ -3644,8 +3644,8 @@ sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, left = 0.0; } - s->val[OPT_TL_X].w = SANE_FIX(left); - s->val[OPT_TL_Y].w = SANE_FIX(0.0); + s->val[OPT_TL_X].w = SANE_FIX(left); + s->val[OPT_TL_Y].w = SANE_FIX(0.0); s->val[OPT_BR_X].w = SANE_FIX(MIN(x + left, x_max)); s->val[OPT_BR_Y].w = SANE_FIX(MIN(y, y_max)); } @@ -3670,7 +3670,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) SANE_Int status = SANE_STATUS_GOOD; DBG(3, "sane_get_parameters called\n"); - + if (params) { SANE_Int res; @@ -3686,11 +3686,11 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) res = _OPT_VAL_WORD(s, OPT_RESOLUTION); DBG (1, "get_parameters: format=%d, pixels/line=%d, bytes/line=%d, " - "lines=%d, dpi=%d\n", - (int) s->params.format, - s->params.pixels_per_line, + "lines=%d, dpi=%d\n", + (int) s->params.format, + s->params.pixels_per_line, s->params.bytes_per_line, - s->params.lines, + s->params.lines, res); } @@ -3718,7 +3718,7 @@ sane_start (SANE_Handle handle) } /* Do the setup once per 'batch'. The SANE standard requires the - * frontend to call sane_cancel once all desired frames have been + * frontend to call sane_cancel once all desired frames have been * acquired. That is when scanning is set back to SANE_FALSE and * the 'batch' is considered done. */ @@ -3739,7 +3739,7 @@ sane_start (SANE_Handle handle) return status; } - return SANE_STATUS_GOOD; + return SANE_STATUS_GOOD; } SANE_Status @@ -3795,13 +3795,13 @@ sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) DBG(3, "sane_set_io_mode called: non_blocking=%d\n", non_blocking); #ifdef NONBLOCKSUPPORTED - if (s->fd < 0) - { - return SANE_STATUS_INVAL; + if (s->fd < 0) + { + return SANE_STATUS_INVAL; } if (fcntl (s->fd, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) - { + { DBG(1, "sane_set_io_mode: error setting io mode\n"); return SANE_STATUS_IO_ERROR; } @@ -3823,8 +3823,8 @@ sane_get_select_fd (SANE_Handle handle, SANE_Int *fd) #ifdef NONBLOCKSUPPORTED if (s->fd < 0) - { - return SANE_STATUS_INVAL; + { + return SANE_STATUS_INVAL; } *fd = s->fd; @@ -3842,14 +3842,14 @@ sane_cancel (SANE_Handle handle) DBG(3, "sane_cancel called\n"); if (s->scanning) { - /* if batchmode is enabled, then call set_window to + /* if batchmode is enabled, then call set_window to * abort the batch */ if (_OPT_VAL_WORD(s, OPT_BATCH) == SANE_TRUE) { DBG(5, "sane_cancel: calling set_window to abort batch\n"); set_window(s, BH_BATCH_ABORT); - } + } } s->scanning = SANE_FALSE; s->cancelled = SANE_TRUE; @@ -3878,8 +3878,7 @@ sane_exit (void) next = dev->next; free (dev); } - + if (devlist) free (devlist); } - diff --git a/backend/bh.h b/backend/bh.h index 545ffb1..fcd833a 100644 --- a/backend/bh.h +++ b/backend/bh.h @@ -73,16 +73,16 @@ #define BH_SECTION_FRONT_PATCH (1 << 4) #define BH_SECTION_BACK_PATCH (1 << 5) -typedef enum -{ - BH_UNIT_INCH, - BH_UNIT_MM, +typedef enum +{ + BH_UNIT_INCH, + BH_UNIT_MM, BH_UNIT_POINT } bh_measureUnit; typedef enum { - BH_COMP_NONE, + BH_COMP_NONE, BH_COMP_G31D, BH_COMP_G32D, BH_COMP_G42D @@ -90,13 +90,13 @@ typedef enum typedef enum { - BH_ROTATION_0, + BH_ROTATION_0, BH_ROTATION_90, BH_ROTATION_180, BH_ROTATION_270 } bh_rotation; -typedef enum +typedef enum { OPT_NUM_OPTS = 0, @@ -171,30 +171,30 @@ typedef enum OPT_BARCODE_SEARCH_BAR, /* Barcode search count (1-7, default 3). */ OPT_BARCODE_SEARCH_COUNT, - /* Barcode search mode. - * (1 = horizontal,2 = vertical, 6 = v then h, 9 = h then v). + /* Barcode search mode. + * (1 = horizontal,2 = vertical, 6 = v then h, 9 = h then v). */ OPT_BARCODE_SEARCH_MODE, /* Patch code min height (def=127 (5mm)) */ - OPT_BARCODE_HMIN, - /* Barcode search timeout in ms - * (20-65535,default is disabled). + OPT_BARCODE_HMIN, + /* Barcode search timeout in ms + * (20-65535,default is disabled). */ OPT_BARCODE_SEARCH_TIMEOUT, /* Specify image sections and functions */ OPT_SECTION, - /* Specifies the maximum relation from the widest to - * the smallest bar + /* Specifies the maximum relation from the widest to + * the smallest bar */ OPT_BARCODE_RELMAX, /* Specifies the minimum number of bars in Bar/Patch code */ OPT_BARCODE_BARMIN, /* Specifies the maximum number of bars in a Bar/Patch code */ OPT_BARCODE_BARMAX, - /* Specifies the image contrast used in decoding. - * Use higher values when there are more white pixels - * in the code + /* Specifies the image contrast used in decoding. + * Use higher values when there are more white pixels + * in the code */ OPT_BARCODE_CONTRAST, /* Controls Patch Code detection. */ @@ -291,8 +291,8 @@ typedef struct _BH_Info SANE_Int resMaxY; /* maximum Y resolution */ SANE_Int resMinX; /* minimum X resolution */ SANE_Int resMinY; /* minimum Y resolution */ - SANE_Int resStdList[16+1]; /* list of available standard resolutions - * (first slot is the length) + SANE_Int resStdList[16+1]; /* list of available standard resolutions + * (first slot is the length) */ SANE_Int winWidth; /* length of window (in BasicX res DPI) */ SANE_Int winHeight; /* height of window (in BasicY res DPI) */ @@ -321,7 +321,7 @@ struct _BH_Scanner /* SCSI filedescriptor */ int fd; - + /* tempfile which is used to send decoded barcode data */ FILE *barf; char barfname[PATH_MAX+1]; @@ -337,7 +337,7 @@ struct _BH_Scanner /* SANE image parameters */ SANE_Parameters params; - + /* state information - not options */ /* Basic Measurement Unit */ @@ -394,9 +394,9 @@ static const SANE_Range barcode_search_timeout_range = static const SANE_Range barcode_hmin_range = { 1, /* minimum */ - 1660, /* maximum (when converted from mm - * to thousandths will still be less - * than 65536) + 1660, /* maximum (when converted from mm + * to thousandths will still be less + * than 65536) */ 0 /* quantization */ }; @@ -915,7 +915,7 @@ struct mode_page_03 { SANE_Byte mediumtype; SANE_Byte devicespecificparam; SANE_Byte blockdescriptorlen; - + SANE_Byte pagecode; SANE_Byte paramlen; SANE_Byte bmu; diff --git a/backend/canon-sane.c b/backend/canon-sane.c index a8efc7a..5d9ec99 100644 --- a/backend/canon-sane.c +++ b/backend/canon-sane.c @@ -1126,7 +1126,7 @@ sane_start (SANE_Handle handle) if (thistmpfile != NULL) { if (mktemp(thistmpfile) == 0) - { + { DBG(1, "mktemp(thistmpfile) is failed\n"); return (SANE_STATUS_INVAL); } diff --git a/backend/canon-scsi.c b/backend/canon-scsi.c index a83e518..0bddf51 100644 --- a/backend/canon-scsi.c +++ b/backend/canon-scsi.c @@ -623,7 +623,7 @@ wait_ready(int fd) while ((status = test_unit_ready (fd)) != SANE_STATUS_GOOD) { DBG(5, "wait_ready failed (%d)\n", retry); - if (retry++ > 15) + if (retry++ > 15) return SANE_STATUS_IO_ERROR; sleep(3); } diff --git a/backend/canon.c b/backend/canon.c index 168b2d6..ad738e8 100644 --- a/backend/canon.c +++ b/backend/canon.c @@ -62,7 +62,7 @@ . . - sane_get_parameters() : returns actual scan-parameters . . - sane_read() : read image-data (from pipe) . . - sane_cancel() : cancel operation, kill reader_process - + . - sane_close() : close opened scanner-device, do_cancel, free buffer and handle - sane_exit() : terminate use of backend, free devicename and device-struture */ @@ -140,7 +140,7 @@ static const SANE_String_Const mode_list[] = { SANE_VALUE_SCAN_MODE_HALFTONE, SANE_VALUE_SCAN_MODE_GRAY, SANE_VALUE_SCAN_MODE_COLOR, - 0 + 0 }; /* modification for FS2710 */ @@ -193,11 +193,6 @@ static const SANE_String_Const tpu_filmtype_list[] = { 0 }; -static const SANE_String_Const papersize_list[] = { - "A4", "Letter", "B5", "Maximal", - 0 -}; - /**************************************************/ static const SANE_Range u8_range = { diff --git a/backend/canon630u-common.c b/backend/canon630u-common.c index a46424a..27c34ff 100644 --- a/backend/canon630u-common.c +++ b/backend/canon630u-common.c @@ -35,15 +35,15 @@ 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. + If you do not wish that, delete this exception notice. */ /* Communication, calibration, and scanning with the Canon CanoScan FB630U flatbed scanner under linux. - + Reworked into SANE-compatible format. - + The usb-parallel port interface chip is GL640usb, on the far side of which is an LM9830 parallel-port scanner-on-a-chip. @@ -153,7 +153,7 @@ gl640ReadReq (int fd, GL640_Request req, byte * data) } -/* Write USB bulk data +/* Write USB bulk data setup is an apparently scanner-specific sequence: {(0=read, 1=write), 0x00, 0x00, 0x00, sizelo, sizehi, 0x00, 0x00} hp3400: setup[1] = 0x01 @@ -177,7 +177,7 @@ gl640WriteBulk (int fd, byte * setup, byte * data, size_t size) } -/* Read USB bulk data +/* Read USB bulk data setup is an apparently scanner-specific sequence: {(0=read, 1=write), 0x00, 0x00, 0x00, sizelo, sizehi, 0x00, 0x00} fb630u: setup[2] = 0x80 @@ -461,7 +461,7 @@ typedef struct CANON_Handle #define FLG_GRAY 0x01 /* grayscale */ #define FLG_FORCE_CAL 0x02 /* force calibration */ #define FLG_BUF 0x04 /* save scan to buffer instead of file */ -#define FLG_NO_INTERLEAVE 0x08 /* don't interleave r,g,b pixels; leave them +#define FLG_NO_INTERLEAVE 0x08 /* don't interleave r,g,b pixels; leave them in row format */ #define FLG_PPM_HEADER 0x10 /* include PPM header in scan file */ } @@ -501,7 +501,7 @@ init (int fd) { byte result, rv; - if (gl640WriteReq (fd, GL640_GPIO_OE, 0x71) != SANE_STATUS_GOOD) { + if (gl640WriteReq (fd, GL640_GPIO_OE, 0x71) != SANE_STATUS_GOOD) { DBG(1, "Initial write request failed.\n"); return -1; } @@ -653,7 +653,7 @@ do_scan (CANON_Handle * s) fwrite (redptr + s->width, 1, 1, fp); /* Green */ fwrite (redptr + s->width + s->width, 1, 1, fp); /* Blue */ /* for PPM ascii (P3) - fprintf(fp, "%3d %3d %3d\n", *redptr, + fprintf(fp, "%3d %3d %3d\n", *redptr, *(redptr + s->width), *(redptr + s->width + s->width)); */ @@ -869,8 +869,8 @@ plugin_cal (CANON_Handle * s) write_word (fd, LAMP_B_OFF, 0x0100); /* coming in, we've got 300dpi, data px start : 0x004b - data px end : 0x1437 for a total of 5100(13ec) 600-dpi pixels, - (8.5 inches) or 2550 300-dpi pixels (7653 bytes). + data px end : 0x1437 for a total of 5100(13ec) 600-dpi pixels, + (8.5 inches) or 2550 300-dpi pixels (7653 bytes). Interestingly, the scan head never moves, no matter how many rows are read. */ s->width = 2551; @@ -981,7 +981,7 @@ plugin_cal (CANON_Handle * s) somewhat more complicated than necessary because I don't hard-code the strip widths; I try to figure out the regions based on the scan data. Theoretically, the region-finder should work for any number of distinct - regions (but there are only 2 on this scanner.) + regions (but there are only 2 on this scanner.) This produces the CAL_FILE_OGN file, the final offset/gain table. */ static SANE_Status compute_ogn (char *calfilename) @@ -1132,7 +1132,7 @@ compute_ogn (char *calfilename) continue; } - /* Gain multiplier: + /* Gain multiplier: 255 : 1.5 times brighter 511 : 2 times brighter 1023: 3 times brighter */ @@ -1146,9 +1146,9 @@ compute_ogn (char *calfilename) offset would be bad. */ /* Enhanced offset and gain calculation by M.Reinelt - * These expressions were found by an iterative calibration process, + * These expressions were found by an iterative calibration process, * by changing gain and offset values for every pixel until the desired - * values for black and white were reached, and finding an approximation + * values for black and white were reached, and finding an approximation * formula. * Note that offset is linear, but gain isn't! */ @@ -1256,8 +1256,8 @@ scan (CANON_Handle * opt) read_byte (fd, STATUS, &result); /* wants 2f or 2d */ if (!(result & STATUS_HOME) /*0x2d */ ) return SANE_STATUS_DEVICE_BUSY; - /* or force it to return? - write_byte(fd, COMMAND, 0x02); + /* or force it to return? + write_byte(fd, COMMAND, 0x02); wait_for_return(fd); */ @@ -1439,9 +1439,9 @@ CANON_set_scan_parameters (CANON_Handle * scan, const int left, const int top, const int right, - const int bottom, - const int res, - const int gain, + const int bottom, + const int res, + const int gain, const double gamma) { DBG (2, "CANON_set_scan_parameters:\n"); @@ -1593,12 +1593,12 @@ CANON_start_scan (CANON_Handle * scanner) return SANE_STATUS_IO_ERROR; } if ((rv == 1) - || !check_ogn_file () + || !check_ogn_file () || (scanner->flags & FLG_FORCE_CAL)) { plugin_cal (scanner); wait_for_return (scanner->fd); } - + /* scan */ if ((status = scan (scanner)) != SANE_STATUS_GOOD) { diff --git a/backend/canon630u.c b/backend/canon630u.c index 5c1a711..c413253 100644 --- a/backend/canon630u.c +++ b/backend/canon630u.c @@ -703,7 +703,7 @@ attach_one (const char *name) } -/* +/* Find our devices */ SANE_Status @@ -995,7 +995,7 @@ sane_start (SANE_Handle handle) MM_IN_INCH * 600, SANE_UNFIX (optionBotRightYValue) / MM_IN_INCH * 600, - optionResolutionValue, + optionResolutionValue, optionAGainValue, SANE_UNFIX (optionGammaValue)); diff --git a/backend/canon_dr-cmd.h b/backend/canon_dr-cmd.h index b969c3b..51f2a06 100644 --- a/backend/canon_dr-cmd.h +++ b/backend/canon_dr-cmd.h @@ -1,7 +1,7 @@ #ifndef CANON_DR_CMD_H #define CANON_DR_CMD_H -/* +/* * Part of SANE - Scanner Access Now Easy. * Please see opening comments in canon_dr.c */ @@ -258,6 +258,11 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define R_FINE_uid_blue 0x09 #define R_FINE_uid_unknown 0x14 +/* get pixel size */ +#define R_PSIZE_len 16 +#define get_R_PSIZE_width(in) getnbyte(in + 0x08, 4) +#define get_R_PSIZE_length(in) getnbyte(in + 0x0c, 4) + /* ==================================================================== */ /* SEND */ #define SEND_code 0x2a @@ -431,6 +436,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define SM2_pc_df 0x00 #define SM2_pc_ultra 0x01 #define SM2_pc_buffer 0x02 +#define SM2_pc_hw_enhancement 0x03 #define SM2_pc_dropout 0x06 /* ==================================================================== */ @@ -447,6 +453,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) /* for DF (0x00) page */ #define set_SSM2_DF_thick(sb, val) setbitfield(sb+3, 1, 2, val) #define set_SSM2_DF_len(sb, val) setbitfield(sb+3, 1, 0, val) +#define set_SSM2_DF_staple(sb, val) setbitfield(sb+3, 1, 4, val) /* for ULTRA (0x01) page */ #define set_SSM2_ULTRA_top(sb, val) putnbyte(sb + 0x07, val, 2) @@ -457,9 +464,14 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define set_SSM2_BUFF_unk2(sb, val) sb[0x06] = val #define set_SSM2_BUFF_sync(sb, val) sb[0x09] = val +/* for HARDWARE ENHANCEMENT (0x03) */ +#define set_SSM2_roller_deskew(sb, val) setbitfield(sb+6, 1, 3, val) +#define set_SSM2_hw_crop(sb, val) setbitfield(sb+6, 1, 5, val) + /* for DROPOUT (0x06) page */ #define set_SSM2_DO_do(sb, val) sb[0x09] = val #define set_SSM2_DO_en(sb, val) sb[0x0a] = val +#define set_SSM2_DO_side(sb, val) sb[0x05] = val /* ==================================================================== */ /* window descriptor macros for SET_WINDOW and GET_WINDOW */ @@ -571,7 +583,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) /* FIXME: more params here? */ #define set_WD_reserved2(sb, val) sb[0x2a] = val #define get_WD_reserved2(sb) sb[0x2a] - + /* ==================================================================== */ diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 3c058ab..64aec31 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -10,6 +10,7 @@ Canon, USA. www.usa.canon.com loaned equipment HPrint hprint.com.br provided funding and testing for DR-2510 support Stone-IT www.stone-it.com provided funding for DR-2010 and DR-2050 support + Smartmatic www.smartmatic.com provided testing and changes for DR-X10C support -------------------------------------------------------------------------- @@ -165,7 +166,7 @@ - correct rgb padding macro - skip send_panel and ssm_df commands for DR-20xx scanners v22 2009-03-25, MAN - - add deinterlacing code for DR-2510C in duplex and color + - add deinterlacing code for DR-2510C in duplex and color v23 2009-03-27, MAN - rewrite all image data processing code - handle more image interlacing formats @@ -335,6 +336,8 @@ - rename all DUPLEX_INTERLACE_* to indicate start and end of line v56 2016-08-23, MAN - initial support for P-150 + v57 2019-02-24, manuarg + - complete support for X-10, including hardware cropping SANE FLOW DIAGRAM @@ -352,7 +355,7 @@ . . - sane_start() : start image acquisition . . - sane_get_parameters() : returns actual scan parameters . . - sane_read() : read image data (from pipe) - . . (sane_read called multiple times; after sane_read returns EOF, + . . (sane_read called multiple times; after sane_read returns EOF, . . loop may continue with sane_start which may return a 2nd page . . when doing duplex scans, or load the next page from the ADF) . . @@ -385,14 +388,14 @@ #include "canon_dr.h" #define DEBUG 1 -#define BUILD 56 +#define BUILD 57 /* values for SANE_DEBUG_CANON_DR env var: - errors 5 - function trace 10 - function detail 15 - get/setopt cmds 20 - - scsi/usb trace 25 + - scsi/usb trace 25 - scsi/usb writes 30 - scsi/usb reads 31 - useless noise 35 @@ -455,7 +458,7 @@ static struct scanner *scanner_devList = NULL; /* * Called by SANE initially. - * + * * From the SANE spec: * This function must be called before any other SANE function can be * called. The behavior of a SANE backend is undefined if this @@ -487,7 +490,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /* * Called by SANE to find out about supported devices. - * + * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a @@ -500,7 +503,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. - * + * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and @@ -544,42 +547,42 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) CANON_DR_CONFIG_FILE); while (sanei_config_read (line, PATH_MAX, fp)) { - + lp = line; - + /* ignore comments */ if (*lp == '#') continue; - + /* skip empty lines */ if (*lp == 0) continue; - + if (!strncmp ("option", lp, 6) && isspace (lp[6])) { - + lp += 6; lp = sanei_config_skip_whitespace (lp); - + /* BUFFERSIZE: > 4K */ if (!strncmp (lp, "buffer-size", 11) && isspace (lp[11])) { - + int buf; lp += 11; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - + if (buf < 4096) { DBG (5, "sane_get_devices: config option \"buffer-size\" " "(%d) is < 4096, ignoring!\n", buf); continue; } - + if (buf > global_buffer_size_default) { DBG (5, "sane_get_devices: config option \"buffer-size\" " "(%d) is > %d, scanning problems may result\n", buf, global_buffer_size_default); } - + DBG (15, "sane_get_devices: setting \"buffer-size\" to %d\n", buf); @@ -588,24 +591,24 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) /* PADDED READ: we clamp to 0 or 1 */ else if (!strncmp (lp, "padded-read", 11) && isspace (lp[11])) { - + int buf; lp += 11; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - + if (buf < 0) { DBG (5, "sane_get_devices: config option \"padded-read\" " "(%d) is < 0, ignoring!\n", buf); continue; } - + if (buf > 1) { DBG (5, "sane_get_devices: config option \"padded-read\" " "(%d) is > 1, ignoring!\n", buf); continue; } - + DBG (15, "sane_get_devices: setting \"padded-read\" to %d\n", buf); @@ -614,24 +617,24 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) /* EXTRA STATUS: we clamp to 0 or 1 */ else if (!strncmp (lp, "extra-status", 12) && isspace (lp[12])) { - + int buf; lp += 12; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - + if (buf < 0) { DBG (5, "sane_get_devices: config option \"extra-status\" " "(%d) is < 0, ignoring!\n", buf); continue; } - + if (buf > 1) { DBG (5, "sane_get_devices: config option \"extra-status\" " "(%d) is > 1, ignoring!\n", buf); continue; } - + DBG (15, "sane_get_devices: setting \"extra-status\" to %d\n", buf); @@ -640,18 +643,18 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) /* DUPLEXOFFSET: < 2400 */ else if (!strncmp (lp, "duplex-offset", 13) && isspace (lp[13])) { - + int buf; lp += 13; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - + if (buf > 2400) { DBG (5, "sane_get_devices: config option \"duplex-offset\" " "(%d) is > 2400, ignoring!\n", buf); continue; } - + if (buf < 0) { DBG (5, "sane_get_devices: config option \"duplex-offset\" " "(%d) is < 0, ignoring!\n", buf); @@ -671,7 +674,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) lp = sanei_config_skip_whitespace (lp); strncpy(global_vendor_name, lp, 8); global_vendor_name[8] = 0; - + DBG (15, "sane_get_devices: setting \"vendor-name\" to %s\n", global_vendor_name); } @@ -683,7 +686,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) lp = sanei_config_skip_whitespace (lp); strncpy(global_model_name, lp, 16); global_model_name[16] = 0; - + DBG (15, "sane_get_devices: setting \"model-name\" to %s\n", global_model_name); } @@ -695,7 +698,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) lp = sanei_config_skip_whitespace (lp); strncpy(global_version_name, lp, 4); global_version_name[4] = 0; - + DBG (15, "sane_get_devices: setting \"version-name\" to %s\n", global_version_name); } @@ -801,8 +804,8 @@ attach_one_usb (const char *device_name) return attach_one(device_name,CONNECTION_USB); } -/* build the scanner struct and link to global list - * unless struct is already loaded, then pretend +/* build the scanner struct and link to global list + * unless struct is already loaded, then pretend */ static SANE_Status attach_one (const char *device_name, int connType) @@ -974,8 +977,8 @@ connect_fd (struct scanner *s) if(ret == SANE_STATUS_GOOD){ - /* first generation usb scanners can get flaky if not closed - * properly after last use. very first commands sent to device + /* first generation usb scanners can get flaky if not closed + * properly after last use. very first commands sent to device * must be prepared to correct this- see wait_scanner() */ ret = wait_scanner(s); if (ret != SANE_STATUS_GOOD) { @@ -1016,9 +1019,9 @@ init_inquire (struct scanner *s) set_IN_return_size (cmd, inLen); set_IN_evpd (cmd, 0); set_IN_page_code (cmd, 0); - + ret = do_cmd ( - s, 1, 0, + s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen @@ -1323,7 +1326,7 @@ init_model (struct scanner *s) s->std_res_y[DPI_400]=1; s->std_res_x[DPI_600]=1; s->std_res_y[DPI_600]=1; - + /*weirdness*/ s->has_ssm = 0; s->has_ssm2 = 1; @@ -1522,7 +1525,7 @@ init_model (struct scanner *s) s->std_res_y[DPI_400]=1; s->std_res_x[DPI_600]=1; s->std_res_y[DPI_600]=1; - + s->has_comp_JPEG = 1; s->rgb_format = 1; s->has_df_ultra = 1; @@ -1562,7 +1565,7 @@ init_model (struct scanner *s) s->std_res_y[DPI_400]=1; s->std_res_x[DPI_600]=1; s->std_res_y[DPI_600]=1; - + s->has_comp_JPEG = 1; s->rgb_format = 1; s->has_df_ultra = 1; @@ -1690,6 +1693,31 @@ init_model (struct scanner *s) s->can_halftone = 0; } + else if (strstr (s->model_name,"DR-X10C")){ + + /* Required for USB coms */ + s->has_ssm = 0; + s->has_ssm2 = 1; + + /* missing */ + s->std_res_x[DPI_100]=1; + s->std_res_y[DPI_100]=1; + s->std_res_x[DPI_150]=1; + s->std_res_y[DPI_150]=1; + s->std_res_x[DPI_200]=1; + s->std_res_y[DPI_200]=1; + s->std_res_x[DPI_240]=1; + s->std_res_y[DPI_240]=1; + s->std_res_x[DPI_300]=1; + s->std_res_y[DPI_300]=1; + s->std_res_x[DPI_400]=1; + s->std_res_y[DPI_400]=1; + s->std_res_x[DPI_600]=1; + s->std_res_y[DPI_600]=1; + + s->has_hwcrop = 1; + } + DBG (10, "init_model: finish\n"); return SANE_STATUS_GOOD; @@ -1801,9 +1829,9 @@ init_options (struct scanner *s) s->opt[i].cap = SANE_CAP_INACTIVE; } - /* go ahead and setup the first opt, because - * frontend may call control_option on it - * before calling get_option_descriptor + /* go ahead and setup the first opt, because + * frontend may call control_option on it + * before calling get_option_descriptor */ s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; @@ -1831,7 +1859,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) struct scanner *dev = NULL; struct scanner *s = NULL; SANE_Status ret; - + DBG (10, "sane_open: start\n"); if(scanner_devList){ @@ -1852,7 +1880,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) } else{ DBG (15, "sane_open: device %s requested\n", name); - + for (dev = scanner_devList; dev; dev = dev->next) { if (strcmp (dev->sane.name, name) == 0 || strcmp (dev->device_name, name) == 0) { /*always allow sanei devname*/ @@ -1928,7 +1956,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) } if(s->has_adf){ s->source_list[i++]=STRING_ADFFRONT; - + if(s->has_back){ s->source_list[i++]=STRING_ADFBACK; } @@ -1938,7 +1966,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) } if(s->has_card){ s->source_list[i++]=STRING_CARDFRONT; - + if(s->has_back){ s->source_list[i++]=STRING_CARDBACK; } @@ -1974,7 +2002,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->mode_list[i++]=STRING_COLOR; } s->mode_list[i]=NULL; - + opt->name = SANE_NAME_SCAN_MODE; opt->title = SANE_TITLE_SCAN_MODE; opt->desc = SANE_DESC_SCAN_MODE; @@ -2041,14 +2069,14 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->res_list[++i] = 1200; } s->res_list[0] = i; - + opt->name = SANE_NAME_SCAN_RESOLUTION; opt->title = SANE_TITLE_SCAN_RESOLUTION; opt->desc = SANE_DESC_SCAN_RESOLUTION; opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_DPI; opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - + if(s->step_y_res){ s->res_range.min = s->min_y_res; s->res_range.max = s->max_y_res; @@ -2078,7 +2106,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->tl_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x); s->tl_x_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_width(s)); s->tl_x_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_TL_X; opt->title = SANE_TITLE_SCAN_TL_X; opt->desc = SANE_DESC_SCAN_TL_X; @@ -2096,7 +2124,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->tl_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y); s->tl_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s)); s->tl_y_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_TL_Y; opt->title = SANE_TITLE_SCAN_TL_Y; opt->desc = SANE_DESC_SCAN_TL_Y; @@ -2114,7 +2142,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->br_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x); s->br_x_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_width(s)); s->br_x_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_BR_X; opt->title = SANE_TITLE_SCAN_BR_X; opt->desc = SANE_DESC_SCAN_BR_X; @@ -2132,7 +2160,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->br_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y); s->br_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s)); s->br_y_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_BR_Y; opt->title = SANE_TITLE_SCAN_BR_Y; opt->desc = SANE_DESC_SCAN_BR_Y; @@ -2370,7 +2398,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*double feed by thickness */ if(option==OPT_DF_THICKNESS){ - + opt->name = "df-thickness"; opt->title = "DF by thickness"; opt->desc = "Detect double feeds using thickness sensor"; @@ -2482,7 +2510,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->do_color_list[5] = STRING_EN_GREEN; s->do_color_list[6] = STRING_EN_BLUE; s->do_color_list[7] = NULL; - + opt->name = "dropout-front"; opt->title = "Dropout color front"; opt->desc = "One-pass scanners use only one color during gray or binary scanning, useful for colored paper or ink"; @@ -2510,7 +2538,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->do_color_list[5] = STRING_EN_GREEN; s->do_color_list[6] = STRING_EN_BLUE; s->do_color_list[7] = NULL; - + opt->name = "dropout-back"; opt->title = "Dropout color back"; opt->desc = "One-pass scanners use only one color during gray or binary scanning, useful for colored paper or ink"; @@ -2551,6 +2579,18 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->constraint_type = SANE_CONSTRAINT_NONE; } + /*hardware crop*/ + if(option==OPT_HW_CROP){ + opt->name = "hwcrop"; + opt->title = "Hardware crop"; + opt->desc = "Request scanner to crop image automatically"; + opt->type = SANE_TYPE_BOOL; + if (s->has_hwcrop) + opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + else + opt->cap = SANE_CAP_INACTIVE; + } + /* "Sensor" group ------------------------------------------------------ */ if(option==OPT_SENSOR_GROUP){ opt->name = SANE_NAME_SENSORS; @@ -2671,7 +2711,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /** * Gets or sets an option value. - * + * * From the SANE spec: * This function is used to set or inquire the current value of option * number n of the device represented by handle h. The manner in which @@ -2682,7 +2722,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) * area pointed to by v must be big enough to hold the entire option * value (determined by member size in the corresponding option * descriptor). - * + * * The only exception to this rule is that when setting the value of a * string option, the string pointed to by argument v may be shorter * since the backend will stop reading the option value upon @@ -2918,6 +2958,10 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *val_p = s->side; return SANE_STATUS_GOOD; + case OPT_HW_CROP: + *val_p = s->hwcrop; + return SANE_STATUS_GOOD; + /* Sensor Group */ case OPT_START: ret = read_panel(s,OPT_START); @@ -2999,7 +3043,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, * below. */ switch (option) { - + /* Mode Group */ case OPT_SOURCE: if (!strcmp (val, STRING_ADFFRONT)) { @@ -3024,7 +3068,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, tmp = SOURCE_FLATBED; } - if (s->u.source == tmp) + if (s->u.source == tmp) return SANE_STATUS_GOOD; s->u.source = tmp; @@ -3056,7 +3100,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_RES: - if (s->u.dpi_x == val_c && s->u.dpi_y == val_c) + if (s->u.dpi_x == val_c && s->u.dpi_y == val_c) return SANE_STATUS_GOOD; s->u.dpi_x = val_c; @@ -3237,6 +3281,10 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->buffermode = val_c; return SANE_STATUS_GOOD; + case OPT_HW_CROP: + s->hwcrop = val_c; + return SANE_STATUS_GOOD; + } } /* else */ @@ -3251,25 +3299,25 @@ ssm_buffer (struct scanner *s) DBG (10, "ssm_buffer: start\n"); if(s->has_ssm){ - + unsigned char cmd[SET_SCAN_MODE_len]; size_t cmdLen = SET_SCAN_MODE_len; - + unsigned char out[SSM_PAY_len]; size_t outLen = SSM_PAY_len; - + memset(cmd,0,cmdLen); set_SCSI_opcode(cmd, SET_SCAN_MODE_code); set_SSM_pf(cmd, 1); set_SSM_pay_len(cmd, outLen); - + memset(out,0,outLen); if(s->has_ssm_pay_head_len){ set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); } set_SSM_page_code(out, SM_pc_buffer); set_SSM_page_len(out, SSM_PAGE_len); - + if(s->s.source == SOURCE_ADF_DUPLEX || s->s.source == SOURCE_CARD_DUPLEX){ set_SSM_BUFF_duplex(out, 1); } @@ -3288,7 +3336,7 @@ ssm_buffer (struct scanner *s) if(0){ set_SSM_BUFF_unk(out,1); } - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -3301,20 +3349,20 @@ ssm_buffer (struct scanner *s) unsigned char cmd[SET_SCAN_MODE2_len]; size_t cmdLen = SET_SCAN_MODE2_len; - + unsigned char out[SSM2_PAY_len]; size_t outLen = SSM2_PAY_len; - + memset(cmd,0,cmdLen); set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); set_SSM2_page_code(cmd, SM2_pc_buffer); set_SSM2_pay_len(cmd, outLen); - + memset(out,0,outLen); set_SSM2_BUFF_unk(out, !s->buffermode); set_SSM2_BUFF_unk2(out, 0x40); set_SSM2_BUFF_sync(out, !s->buffermode); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -3338,52 +3386,52 @@ ssm_df (struct scanner *s) SANE_Status ret = SANE_STATUS_GOOD; DBG (10, "ssm_df: start\n"); - + if(!s->has_df){ DBG (10, "ssm_df: unsupported, finishing\n"); return ret; } - + if(s->has_ssm){ unsigned char cmd[SET_SCAN_MODE_len]; size_t cmdLen = SET_SCAN_MODE_len; - + unsigned char out[SSM_PAY_len]; size_t outLen = SSM_PAY_len; - + memset(cmd,0,cmdLen); set_SCSI_opcode(cmd, SET_SCAN_MODE_code); set_SSM_pf(cmd, 1); set_SSM_pay_len(cmd, outLen); - + memset(out,0,outLen); if(s->has_ssm_pay_head_len){ set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); } set_SSM_page_code(out, SM_pc_df); set_SSM_page_len(out, SSM_PAGE_len); - + /* deskew by roller */ if(s->rollerdeskew){ set_SSM_DF_deskew_roll(out, 1); } - + /* staple detection */ if(s->stapledetect){ set_SSM_DF_staple(out, 1); } - + /* thickness */ if(s->df_thickness){ set_SSM_DF_thick(out, 1); } - + /* length */ if(s->df_length){ set_SSM_DF_len(out, 1); } - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -3397,7 +3445,7 @@ ssm_df (struct scanner *s) unsigned char cmd[SET_SCAN_MODE2_len]; size_t cmdLen = SET_SCAN_MODE2_len; - + unsigned char out[SSM2_PAY_len]; size_t outLen = SSM2_PAY_len; @@ -3407,11 +3455,11 @@ ssm_df (struct scanner *s) set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); set_SSM2_page_code(cmd, SM2_pc_ultra); set_SSM2_pay_len(cmd, outLen); - + memset(out,0,outLen); set_SSM2_ULTRA_top(out, 0); set_SSM2_ULTRA_bot(out, 0); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -3424,19 +3472,24 @@ ssm_df (struct scanner *s) set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); set_SSM2_page_code(cmd, SM2_pc_df); set_SSM2_pay_len(cmd, outLen); - + memset(out,0,outLen); - + /* thickness */ if(s->df_thickness){ set_SSM2_DF_thick(out, 1); } - + /* length */ if(s->df_length){ set_SSM2_DF_len(out, 1); } - + + /* staple detection */ + if(s->stapledetect){ + set_SSM2_DF_staple(out, 1); + } + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -3455,6 +3508,53 @@ ssm_df (struct scanner *s) return ret; } +static SANE_Status +ssm2_hw_enhancement (struct scanner *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + DBG (10, "ssm2_hw_enhancement: start\n"); + + if(s->has_ssm2){ + unsigned char cmd[SET_SCAN_MODE2_len]; + size_t cmdLen = SET_SCAN_MODE2_len; + + unsigned char out[SSM2_PAY_len]; + size_t outLen = SSM2_PAY_len; + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd, SM2_pc_hw_enhancement); + set_SSM2_pay_len(cmd, outLen); + + memset(out,0,outLen); + + if(s->rollerdeskew){ + set_SSM2_roller_deskew(out, 1); + } + + if(s->hwcrop){ + set_SSM2_hw_crop(out, 1); + } + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); + + } + + else{ + DBG (10, "ssm2_hw_enhancement: unsupported\n"); + } + + DBG (10, "ssm2_hw_enhancement: finish\n"); + + return ret; +} + static SANE_Status ssm_do (struct scanner *s) { @@ -3466,7 +3566,7 @@ ssm_do (struct scanner *s) DBG (10, "ssm_do: unsupported, finishing\n"); return ret; } - + if(s->s.mode == MODE_COLOR){ DBG (10, "ssm_do: unneeded, finishing\n"); return ret; @@ -3476,24 +3576,24 @@ ssm_do (struct scanner *s) unsigned char cmd[SET_SCAN_MODE_len]; size_t cmdLen = SET_SCAN_MODE_len; - + unsigned char out[SSM_PAY_len]; size_t outLen = SSM_PAY_len; - + memset(cmd,0,cmdLen); set_SCSI_opcode(cmd, SET_SCAN_MODE_code); set_SSM_pf(cmd, 1); set_SSM_pay_len(cmd, outLen); - + memset(out,0,outLen); if(s->has_ssm_pay_head_len){ set_SSM_pay_head_len(out, SSM_PAY_HEAD_len); } set_SSM_page_code(out, SM_pc_dropout); set_SSM_page_len(out, SSM_PAGE_len); - + set_SSM_DO_unk1(out, 0x03); - + switch(s->dropout_color[SIDE_FRONT]){ case COLOR_RED: set_SSM_DO_unk2(out, 0x05); @@ -3520,7 +3620,7 @@ ssm_do (struct scanner *s) set_SSM_DO_f_en(out,SSM_DO_blue); break; } - + switch(s->dropout_color[SIDE_BACK]){ case COLOR_RED: set_SSM_DO_unk2(out, 0x05); @@ -3547,7 +3647,7 @@ ssm_do (struct scanner *s) set_SSM_DO_b_en(out,SSM_DO_blue); break; } - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -3561,17 +3661,17 @@ ssm_do (struct scanner *s) unsigned char cmd[SET_SCAN_MODE2_len]; size_t cmdLen = SET_SCAN_MODE2_len; - + unsigned char out[SSM2_PAY_len]; size_t outLen = SSM2_PAY_len; - + memset(cmd,0,cmdLen); set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); set_SSM2_page_code(cmd, SM2_pc_dropout); set_SSM2_pay_len(cmd, outLen); - + memset(out,0,outLen); - + switch(s->dropout_color[SIDE_FRONT]){ case COLOR_RED: set_SSM2_DO_do(out,SSM_DO_red); @@ -3599,6 +3699,46 @@ ssm_do (struct scanner *s) out, outLen, NULL, NULL ); + + if(ret == SANE_STATUS_GOOD && + (s->s.source == SOURCE_ADF_DUPLEX || s->s.source == SOURCE_CARD_DUPLEX)){ + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, SET_SCAN_MODE2_code); + set_SSM2_page_code(cmd, SM2_pc_dropout); + set_SSM2_DO_side(cmd, SIDE_BACK); + set_SSM2_pay_len(cmd, outLen); + + memset(out,0,outLen); + + switch(s->dropout_color[SIDE_BACK]){ + case COLOR_RED: + set_SSM2_DO_do(out,SSM_DO_red); + break; + case COLOR_GREEN: + set_SSM2_DO_do(out,SSM_DO_green); + break; + case COLOR_BLUE: + set_SSM2_DO_do(out,SSM_DO_blue); + break; + case COLOR_EN_RED: + set_SSM2_DO_en(out,SSM_DO_red); + break; + case COLOR_EN_GREEN: + set_SSM2_DO_en(out,SSM_DO_green); + break; + case COLOR_EN_BLUE: + set_SSM2_DO_en(out,SSM_DO_blue); + break; + } + + ret = do_cmd ( + s, 1, 0, + cmd, cmdLen, + out, outLen, + NULL, NULL + ); + } } else{ @@ -3622,7 +3762,7 @@ read_sensors(struct scanner *s,SANE_Int option) size_t inLen = R_SENSORS_len; DBG (10, "read_sensors: start %d\n", option); - + if(!s->can_read_sensors){ DBG (10, "read_sensors: unsupported, finishing\n"); return ret; @@ -3638,14 +3778,14 @@ read_sensors(struct scanner *s,SANE_Int option) set_SCSI_opcode(cmd, READ_code); set_R_datatype_code (cmd, SR_datatype_sensors); set_R_xfer_length (cmd, inLen); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen ); - + if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { /*set flags indicating there is data to read*/ memset(s->sensors_read,1,sizeof(s->sensors_read)); @@ -3656,12 +3796,12 @@ read_sensors(struct scanner *s,SANE_Int option) ret = SANE_STATUS_GOOD; } } - + if(option) s->sensors_read[option-OPT_ADF_LOADED] = 0; DBG (10, "read_sensors: finish\n"); - + return ret; } @@ -3677,7 +3817,7 @@ read_panel(struct scanner *s,SANE_Int option) size_t inLen = R_PANEL_len; DBG (10, "read_panel: start %d\n", option); - + if(!s->can_read_panel){ DBG (10, "read_panel: unsupported, finishing\n"); return ret; @@ -3693,14 +3833,14 @@ read_panel(struct scanner *s,SANE_Int option) set_SCSI_opcode(cmd, READ_code); set_R_datatype_code (cmd, SR_datatype_panel); set_R_xfer_length (cmd, inLen); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen ); - + if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { /*set flags indicating there is data to read*/ memset(s->panel_read,1,sizeof(s->panel_read)); @@ -3717,12 +3857,12 @@ read_panel(struct scanner *s,SANE_Int option) ret = SANE_STATUS_GOOD; } } - + if(option) s->panel_read[option-OPT_START] = 0; DBG (10, "read_panel: finish %d\n",s->panel_counter); - + return ret; } @@ -3752,23 +3892,111 @@ send_panel(struct scanner *s) memset(out,0,outLen); set_S_PANEL_enable_led(out,s->panel_enable_led); set_S_PANEL_counter(out,s->panel_counter); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, out, outLen, NULL, NULL ); - + if (ret == SANE_STATUS_EOF) { ret = SANE_STATUS_GOOD; } - + DBG (10, "send_panel: finish %d\n", ret); - + return ret; } +/* + * Request the size of the scanned image + */ +/* we should really be updating s->s and s->i instead */ +static SANE_Status +get_pixelsize(struct scanner *s) +{ + SANE_Status ret = SANE_STATUS_GOOD; + + unsigned char cmd[READ_len]; + size_t cmdLen = READ_len; + + unsigned char in[R_PSIZE_len]; + size_t inLen = R_PSIZE_len; + + int i = 0; + const int MAX_TRIES = 5; + + DBG (10, "get_pixelsize: start\n"); + + if(!s->hwcrop){ + DBG (10, "get_pixelsize: unneeded, finishing\n"); + return ret; + } + + memset(cmd,0,cmdLen); + set_SCSI_opcode(cmd, READ_code); + set_R_datatype_code(cmd, SR_datatype_pixelsize); + set_R_xfer_lid(cmd, 0x02); + set_R_xfer_length(cmd, inLen); + + /* May need to retry/block until the scanner is done */ + for(i=0;i 0 && + get_R_PSIZE_length(in) > 0){ + + DBG (15, "get_pixelsize: w:%d h:%d\n", + get_R_PSIZE_width(in) * s->u.dpi_x / 1200, + get_R_PSIZE_length(in) * s->u.dpi_y / 1200); + + /* + * Round up to byte boundary if needed. + * For 1 bpp the resulting size may not fit in a byte boundary. + */ + int remainder = (get_R_PSIZE_width(in) * s->u.dpi_x / 1200) % 8; + + if (s->u.mode < MODE_GRAYSCALE && remainder) + { + int rounded_up = (8 - remainder) + (get_R_PSIZE_width(in) * s->u.dpi_x / 1200); + + s->u.br_x = rounded_up * 1200 / s->u.dpi_x; + } + else{ + s->u.br_x = get_R_PSIZE_width(in); + } + + s->u.tl_x = 0; + s->u.br_y = get_R_PSIZE_length(in); + s->u.tl_y = 0; + + s->u.page_x = s->u.br_x; + s->u.page_y = s->u.br_y; + + update_params(s,0); + clean_params(s); + break; + } + + else{ + DBG (10, "get_pixelsize: error reading, status = %d w:%d h:%d\n", + ret, get_R_PSIZE_width(in), get_R_PSIZE_length(in)); + ret = SANE_STATUS_INVAL; + usleep(1000000); + } + } + DBG (10, "get_pixelsize: finish\n"); + + return ret; +} + /* * @@ Section 4 - SANE scanning functions */ @@ -3783,7 +4011,7 @@ send_panel(struct scanner *s) * completion of that request. Outside of that window, the returned * values are best-effort estimates of what the parameters will be * when sane_start() gets invoked. - * + * * Calling this function before a scan has actually started allows, * for example, to get an estimate of how big the scanned image will * be. The parameters passed to this function are the handle h of the @@ -3795,7 +4023,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) { SANE_Status ret = SANE_STATUS_GOOD; struct scanner *s = (struct scanner *) handle; - + DBG (10, "sane_get_parameters: start\n"); if(!s->started){ @@ -3825,14 +4053,14 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) DBG(15,"sane_get_parameters: area: tlx=%d, brx=%d, tly=%d, bry=%d\n", s->i.tl_x, s->i.br_x, s->i.tl_y, s->i.br_y); - DBG (15, "sane_get_parameters: params: ppl=%d, Bpl=%d, lines=%d\n", + DBG (15, "sane_get_parameters: params: ppl=%d, Bpl=%d, lines=%d\n", params->pixels_per_line, params->bytes_per_line, params->lines); - DBG (15, "sane_get_parameters: params: format=%d, depth=%d, last=%d\n", + DBG (15, "sane_get_parameters: params: format=%d, depth=%d, last=%d\n", params->format, params->depth, params->last_frame); DBG (10, "sane_get_parameters: finish\n"); - + return ret; } @@ -3840,9 +4068,9 @@ SANE_Status update_params(struct scanner *s, int calib) { SANE_Status ret = SANE_STATUS_GOOD; - + DBG (10, "update_params: start\n"); - + s->u.width = (s->u.br_x - s->u.tl_x) * s->u.dpi_x / 1200; s->u.height = (s->u.br_y - s->u.tl_y) * s->u.dpi_y / 1200; @@ -3884,7 +4112,7 @@ update_params(struct scanner *s, int calib) s->u.br_x, s->u.tl_x, s->u.dpi_x, s->u.br_y, s->u.tl_y, s->u.dpi_y); /* some scanners are limited in their valid scan params - * make a second version of the params struct, but + * make a second version of the params struct, but * override the user's values with what the scanner can actually do */ memcpy(&s->s,&s->u,sizeof(struct img_params)); @@ -3971,7 +4199,7 @@ update_params(struct scanner *s, int calib) /* round lines up to even number */ s->s.height += s->s.height % 2; - + DBG (15, "update_params: scan params: w:%d h:%d m:%d f:%d b:%d\n", s->s.width, s->s.height, s->s.mode, s->s.format, s->s.bpp); DBG (15, "update_params: scan params: B:%d vB:%d vw:%d\n", @@ -4011,12 +4239,12 @@ SANE_Status update_i_params(struct scanner *s) { SANE_Status ret = SANE_STATUS_GOOD; - + DBG (10, "update_i_params: start\n"); s->i.width = s->u.width; s->i.Bpl = s->u.Bpl; - + DBG (10, "update_i_params: finish\n"); return ret; } @@ -4105,6 +4333,16 @@ sane_start (SANE_Handle handle) DBG (5, "sane_start: ERROR: cannot send panel\n"); } + /* we should really be updating s->s and s->i instead */ + if(s->hwcrop){ + s->u.br_x = s->max_x; + s->u.tl_x = 0; + s->u.br_y = s->max_y; + s->u.tl_y = 0; + s->u.page_x = s->max_x; + s->u.page_y = s->max_y; + } + /* load our own private copy of scan params */ ret = update_params(s,0); if (ret != SANE_STATUS_GOOD) { @@ -4140,6 +4378,12 @@ sane_start (SANE_Handle handle) goto errors; } + ret = ssm2_hw_enhancement(s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "sane_start: ERROR: cannot ssm2 hw enhancement\n"); + goto errors; + } + /* clean scan params for new scan */ ret = clean_params(s); if (ret != SANE_STATUS_GOOD) { @@ -4169,7 +4413,7 @@ sane_start (SANE_Handle handle) DBG (5, "sane_start: ERROR: cannot load page\n"); goto errors; } - + /* wait for scanner to finish load */ ret = wait_scanner (s); if (ret != SANE_STATUS_GOOD) { @@ -4185,6 +4429,12 @@ sane_start (SANE_Handle handle) goto errors; } + ret = get_pixelsize(s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "sane_start: ERROR: cannot get pixel size\n"); + goto errors; + } + s->started = 1; } @@ -4235,7 +4485,7 @@ sane_start (SANE_Handle handle) } } } - + /* small, buffering scanners check for more pages by reading counter */ else{ ret = read_panel (s, OPT_COUNTER); @@ -4251,6 +4501,12 @@ sane_start (SANE_Handle handle) DBG (5, "sane_start: diff counter (%d/%d)\n", s->prev_page,s->panel_counter); } + + ret = get_pixelsize(s); + if (ret != SANE_STATUS_GOOD) { + DBG (5, "sane_start: ERROR: cannot get pixel size\n"); + goto errors; + } } } @@ -4261,9 +4517,9 @@ sane_start (SANE_Handle handle) DBG (15, "started=%d, side=%d, source=%d\n", s->started, s->side, s->u.source); - /* certain options require the entire image to + /* certain options require the entire image to * be collected from the scanner before we can - * tell the user the size of the image. the sane + * tell the user the size of the image. the sane * API has no way to inform the frontend of this, * so we block and buffer. yuck */ if(must_fully_buffer(s)){ @@ -4294,7 +4550,7 @@ sane_start (SANE_Handle handle) } if(s->swskip){ /* Skipping means throwing out this image. - * Pretend the user read the whole thing + * Pretend the user read the whole thing * and call sane_start again. * This assumes we are running in batch mode. */ if(buffer_isblank(s,s->side)){ @@ -4349,7 +4605,7 @@ clean_params (struct scanner *s) s->s.bytes_tot[0]=0; s->s.bytes_tot[1]=0; - /* store the number of front bytes */ + /* store the number of front bytes */ if ( s->u.source != SOURCE_ADF_BACK && s->u.source != SOURCE_CARD_BACK ) s->u.bytes_tot[SIDE_FRONT] = s->u.Bpl * s->u.height; @@ -4359,8 +4615,8 @@ clean_params (struct scanner *s) if ( s->s.source != SOURCE_ADF_BACK && s->s.source != SOURCE_CARD_BACK ) s->s.bytes_tot[SIDE_FRONT] = s->s.Bpl * s->s.height; - /* store the number of back bytes */ - if ( s->u.source == SOURCE_ADF_DUPLEX || s->u.source == SOURCE_ADF_BACK + /* store the number of back bytes */ + if ( s->u.source == SOURCE_ADF_DUPLEX || s->u.source == SOURCE_ADF_BACK || s->u.source == SOURCE_CARD_DUPLEX || s->u.source == SOURCE_CARD_BACK ) s->u.bytes_tot[SIDE_BACK] = s->u.Bpl * s->u.height; @@ -4421,14 +4677,14 @@ set_window (struct scanner *s) { SANE_Status ret = SANE_STATUS_GOOD; - /* The command specifies the number of bytes in the data phase - * the data phase has a header, followed by 1 window desc block + /* The command specifies the number of bytes in the data phase + * the data phase has a header, followed by 1 window desc block * the header specifies the number of bytes in 1 window desc block */ unsigned char cmd[SET_WINDOW_len]; size_t cmdLen = SET_WINDOW_len; - + unsigned char out[SW_header_len + SW_desc_len]; size_t outLen = SW_header_len + SW_desc_len; @@ -4484,9 +4740,9 @@ set_window (struct scanner *s) /*convert our common -127 to +127 range into HW's range *FIXME: this code assumes hardware range of 0-255 */ set_WD_brightness (desc1, s->brightness+128); - + set_WD_threshold (desc1, s->threshold); - + /*convert our common -127 to +127 range into HW's range *FIXME: this code assumes hardware range of 0-255 */ set_WD_contrast (desc1, s->contrast+128); @@ -4593,7 +4849,7 @@ object_position (struct scanner *s, int i_load) /* * Issues SCAN command. - * + * * (This doesn't actually read anything, it just tells the scanner * to start scanning.) */ @@ -4641,7 +4897,7 @@ start_scan (struct scanner *s, int type) /* * Called by SANE to read data. - * + * * From the SANE spec: * This function is used to read image data from the device * represented by handle h. Argument buf is a pointer to a memory @@ -4649,7 +4905,7 @@ start_scan (struct scanner *s, int type) * returned is stored in *len. A backend must set this to zero when * the call fails (i.e., when a status other than SANE_STATUS_GOOD is * returned). - * + * * When the call succeeds, the number of bytes returned can be * anywhere in the range from 0 to maxlen bytes. */ @@ -4698,7 +4954,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len } } } - + /* simplex or non-alternating duplex */ else{ if(!s->s.eof[s->side]){ @@ -4719,7 +4975,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len ret = read_from_buffer(s,buf,max_len,len,s->side); if(ret) goto errors; - + ret = check_for_cancel(s); s->reading = 0; @@ -4813,13 +5069,13 @@ read_from_scanner(struct scanner *s, int side, int exact) size_t i; for(i=0;ijpeg_stage == JPEG_STAGE_NONE && in[i] == 0xff){ s->jpeg_ff_offset=0; continue; } - + s->jpeg_ff_offset++; /* last byte was an ff, this byte is SOF */ @@ -4827,7 +5083,7 @@ read_from_scanner(struct scanner *s, int side, int exact) s->jpeg_stage = JPEG_STAGE_SOF; continue; } - + if(s->jpeg_stage == JPEG_STAGE_SOF){ /* lines in start of frame, overwrite it */ @@ -4839,7 +5095,7 @@ read_from_scanner(struct scanner *s, int side, int exact) in[i] = s->s.height & 0xff; continue; } - + /* width in start of frame, overwrite it */ if(s->jpeg_ff_offset == 7){ in[i] = (s->s.width >> 8) & 0xff; @@ -4883,7 +5139,7 @@ read_from_scanner(struct scanner *s, int side, int exact) s->s.bytes_tot[side] = s->s.bytes_sent[side]; s->i.bytes_tot[side] = s->i.bytes_sent[side]; s->u.bytes_tot[side] = s->i.bytes_sent[side]; - } + } /* this is non-jpeg data, fill remainder, change rx'd size */ else{ @@ -5025,7 +5281,7 @@ read_from_scanner_duplex(struct scanner *s,int exact) return ret; } -/* these functions copy image data from input buffer to scanner struct +/* these functions copy image data from input buffer to scanner struct * descrambling it, and putting it in the right side buffer */ /* NOTE: they assume buffer is scanline aligned */ static SANE_Status @@ -5051,7 +5307,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) s->s.bytes_sent[side] += len; return ret; } - + DBG (15, "copy_simplex: per-line copy\n"); line = malloc(bwidth); @@ -5061,7 +5317,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) for(i=0; is.bytes_sent[side] / bwidth; - + /*increment number of bytes rx'd from scanner*/ s->s.bytes_sent[side] += bwidth; @@ -5075,9 +5331,9 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) line_next = 0; if(s->s.format == SANE_FRAME_GRAY){ - + switch (s->gray_interlace[side]) { - + /* one line has the following format: ggg...GGG * where the 'capital' letters are the beginning of the line */ case GRAY_INTERLACE_gG: @@ -5086,10 +5342,10 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) line[line_next++] = buf[i+j]; } break; - + case GRAY_INTERLACE_2510: DBG (17, "copy_simplex: gray, 2510\n"); - + /* first read head (third byte of every three) */ for(j=bwidth-1;j>=0;j-=3){ line[line_next++] = buf[i+j]; @@ -5109,11 +5365,11 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) break; } } - + else if (s->s.format == SANE_FRAME_RGB){ - + switch (inter) { - + /* scanner returns color data as bgrbgr... */ case COLOR_INTERLACE_BGR: DBG (17, "copy_simplex: color, BGR\n"); @@ -5123,7 +5379,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) line[line_next++] = buf[i+j*3]; } break; - + /* scanner returns color data as gbrgbr... */ case COLOR_INTERLACE_GBR: DBG (17, "copy_simplex: color, GBR\n"); @@ -5133,7 +5389,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) line[line_next++] = buf[i+j*3+1]; } break; - + /* scanner returns color data as brgbrg... */ case COLOR_INTERLACE_BRG: DBG (17, "copy_simplex: color, BRG\n"); @@ -5143,7 +5399,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) line[line_next++] = buf[i+j*3]; } break; - + /* one line has the following format: RRR...rrrGGG...gggBBB...bbb */ case COLOR_INTERLACE_RRGGBB: DBG (17, "copy_simplex: color, RRGGBB\n"); @@ -5153,7 +5409,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) line[line_next++] = buf[i+2*pwidth+j]; } break; - + /* one line has the following format: rrr...RRRggg...GGGbbb...BBB * where the 'capital' letters are the beginning of the line */ case COLOR_INTERLACE_rRgGbB: @@ -5164,10 +5420,10 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) line[line_next++] = buf[i+2*pwidth+j]; } break; - + case COLOR_INTERLACE_2510: DBG (17, "copy_simplex: color, 2510\n"); - + /* first read head (third byte of every three) */ for(j=t-1;j>=0;j-=3){ line[line_next++] = buf[i+j]; @@ -5193,7 +5449,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) break; } } - + /* nothing sent above? just copy one line of the block */ /* used by uninterlaced gray/color */ if(!line_next){ @@ -5201,14 +5457,14 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) memcpy(line+line_next,buf+i,bwidth); line_next = bwidth; } - + /* invert image if scanner needs it for this mode */ if(s->reverse_by_mode[s->s.mode]){ for(j=0; jf_offset[side]){ DBG (17, "copy_simplex: apply offset\n"); @@ -5227,7 +5483,7 @@ copy_simplex(struct scanner *s, unsigned char * buf, int len, int side) line[j] = curr; } } - + /* apply brightness and contrast if hardware cannot do it */ if(s->sw_lut && (s->s.mode == MODE_COLOR || s->s.mode == MODE_GRAYSCALE)){ DBG (17, "copy_simplex: apply brightness/contrast\n"); @@ -5283,7 +5539,7 @@ copy_duplex(struct scanner *s, unsigned char * buf, int len) DBG (10, "copy_duplex: 2510\n"); for(i=0; ii.width != s->s.width){ offset = ((s->valid_x-s->i.page_x) / 2 + s->i.tl_x) * s->i.dpi_x/1200; @@ -5481,12 +5737,12 @@ copy_line(struct scanner *s, unsigned char * buff, int side) /* change mode, store line in buffer */ switch (s->i.mode) { - + case MODE_COLOR: memcpy(s->buffers[side]+s->i.bytes_sent[side], line+(offset*3), ibwidth); s->i.bytes_sent[side] += ibwidth; break; - + case MODE_GRAYSCALE: for(i=0;i remain) bytes = remain; - + *len = bytes; - + /*FIXME this needs to timeout eventually */ if(!bytes){ DBG(5,"read_from_buffer: nothing to do\n"); return SANE_STATUS_GOOD; } - + DBG(15, "read_from_buffer: si:%d to:%d tx:%d bu:%d pa:%d\n", side, s->i.bytes_tot[side], s->u.bytes_sent[side], max_len, bytes); @@ -5701,7 +5957,7 @@ calibrate_AFE (struct scanner *s) DBG (5, "calibrate_AFE: ERROR: cannot set window\n"); goto cleanup; } - + /* first pass (black offset), lamp off, no offset/gain/exposure */ DBG (15, "calibrate_AFE: offset\n"); @@ -5925,7 +6181,7 @@ calibrate_fine_buffer (struct scanner *s) DBG (5, "calibrate_fine_buffer: ERROR: cannot load offset buffers\n"); goto cleanup; } - + DBG (5, "calibrate_fine_buffer: %d %x\n", s->s.dpi_x/10, s->s.dpi_x/10); memset(cmd,0,cmdLen); @@ -5952,13 +6208,13 @@ calibrate_fine_buffer (struct scanner *s) /*color mode, expand offset across all three channels? */ if(s->s.format == SANE_FRAME_RGB){ for(j=0; js.valid_width; j++){ - - /*red*/ + + /*red*/ s->f_offset[i][j*3] = in[j*2+i]; if(s->f_offset[i][j*3] < 1) s->f_offset[i][j*3] = 1; - /*green and blue, same as red*/ + /*green and blue, same as red*/ s->f_offset[i][j*3+1] = s->f_offset[i][j*3+2] = s->f_offset[i][j*3]; } } @@ -5995,10 +6251,10 @@ calibrate_fine_buffer (struct scanner *s) int codes[] = {R_FINE_uid_red,R_FINE_uid_green,R_FINE_uid_blue}; for(k=0;k<3;k++){ - + set_R_xfer_uid (cmd, codes[k]); inLen = reqLen; - + hexdump(15, "cmd:", cmd, cmdLen); ret = do_cmd ( @@ -6009,12 +6265,12 @@ calibrate_fine_buffer (struct scanner *s) ); if (ret != SANE_STATUS_GOOD) goto cleanup; - + for(i=0;i<2;i++){ for(j=0; js.valid_width; j++){ - + s->f_gain[i][j*3+k] = in[j*2+i]*3/4; - + if(s->f_gain[i][j*3+k] < 1) s->f_gain[i][j*3+k] = 1; } @@ -6027,7 +6283,7 @@ calibrate_fine_buffer (struct scanner *s) set_R_xfer_uid (cmd, R_FINE_uid_gray); inLen = reqLen; - + hexdump(15, "cmd:", cmd, cmdLen); ret = do_cmd ( @@ -6038,12 +6294,12 @@ calibrate_fine_buffer (struct scanner *s) ); if (ret != SANE_STATUS_GOOD) goto cleanup; - + for(i=0;i<2;i++){ for(j=0; js.valid_width; j++){ - + s->f_gain[i][j] = in[j*2+i]*3/4; - + if(s->f_gain[i][j] < 1) s->f_gain[i][j] = 1; } @@ -6127,7 +6383,7 @@ calibrate_fine (struct scanner *s) DBG (5, "calibrate_fine: ERROR: cannot load buffers\n"); goto cleanup; } - + /*blast the existing fine cal data so reading code wont apply it*/ ret = offset_buffers(s,0); ret = gain_buffers(s,0); @@ -6138,14 +6394,14 @@ calibrate_fine (struct scanner *s) DBG (5, "calibrate_fine: ERROR: cannot ssm buffer\n"); goto cleanup; } - + /* set window command */ ret = set_window(s); if (ret != SANE_STATUS_GOOD) { DBG (5, "calibrate_fine: ERROR: cannot set window\n"); goto cleanup; } - + /*handle fifth pass (fine offset), lamp off*/ DBG (15, "calibrate_fine: offset\n"); ret = calibration_scan(s,0xff); @@ -6159,7 +6415,7 @@ calibrate_fine (struct scanner *s) DBG (5, "calibrate_fine: ERROR: cannot load offset buffers\n"); goto cleanup; } - + for(i=0;i<2;i++){ for(j=0; js.valid_Bpl; j++){ min = 0; @@ -6184,7 +6440,7 @@ calibrate_fine (struct scanner *s) DBG (5, "calibrate_fine: ERROR: cannot load gain buffers\n"); goto cleanup; } - + for(i=0;i<2;i++){ for(j=0; js.valid_Bpl; j++){ max = 0; @@ -6231,14 +6487,14 @@ calibration_scan (struct scanner *s, int scan) DBG (5, "calibration_scan: ERROR: cannot clean_params\n"); return ret; } - + /* start scanning */ ret = start_scan (s,scan); if (ret != SANE_STATUS_GOOD) { DBG (5, "calibration_scan: ERROR: cannot start_scan\n"); return ret; } - + while(!s->s.eof[SIDE_FRONT] && !s->s.eof[SIDE_BACK]){ ret = read_from_scanner_duplex(s,1); } @@ -6260,7 +6516,7 @@ write_AFE(struct scanner *s) size_t cmdLen = COR_CAL_len; /*use the longest payload for buffer*/ - unsigned char pay[CC3_pay_len]; + unsigned char pay[CC3_pay_len]; size_t payLen = CC3_pay_len; DBG (10, "write_AFE: start\n"); @@ -6272,7 +6528,7 @@ write_AFE(struct scanner *s) set_SCSI_opcode(cmd, COR_CAL_code); set_CC_version(cmd,CC3_pay_ver); set_CC_xferlen(cmd,payLen); - + memset(pay,0,payLen); set_CC3_gain_f_r(pay,s->c_gain[SIDE_FRONT]); @@ -6282,7 +6538,7 @@ write_AFE(struct scanner *s) set_CC3_off_f_r(pay,s->c_offset[SIDE_FRONT]); set_CC3_off_f_g(pay,s->c_offset[SIDE_FRONT]); set_CC3_off_f_b(pay,s->c_offset[SIDE_FRONT]); - + set_CC3_exp_f_r(pay,s->c_exposure[SIDE_FRONT][CHAN_RED]); set_CC3_exp_f_g(pay,s->c_exposure[SIDE_FRONT][CHAN_GREEN]); set_CC3_exp_f_b(pay,s->c_exposure[SIDE_FRONT][CHAN_BLUE]); @@ -6307,7 +6563,7 @@ write_AFE(struct scanner *s) set_SCSI_opcode(cmd, COR_CAL_code); set_CC_version(cmd,CC_pay_ver); set_CC_xferlen(cmd,payLen); - + memset(pay,0,payLen); set_CC_f_gain(pay,s->c_gain[SIDE_FRONT]); set_CC_unk1(pay,1); @@ -6319,7 +6575,7 @@ write_AFE(struct scanner *s) set_CC_exp_f_r2(pay,s->c_exposure[SIDE_FRONT][CHAN_RED]); set_CC_exp_f_g2(pay,s->c_exposure[SIDE_FRONT][CHAN_GREEN]); set_CC_exp_f_b2(pay,s->c_exposure[SIDE_FRONT][CHAN_BLUE]); - + set_CC_b_gain(pay,s->c_gain[SIDE_BACK]); set_CC_b_offset(pay,s->c_offset[SIDE_BACK]); set_CC_exp_b_r1(pay,s->c_exposure[SIDE_BACK][CHAN_RED]); @@ -6414,26 +6670,26 @@ gain_buffers (struct scanner *s, int setup) * @@ Section 6 - SANE cleanup functions */ /* - * Cancels a scan. + * Cancels a scan. * * It has been said on the mailing list that sane_cancel is a bit of a * misnomer because it is routinely called to signal the end of a * batch - quoting David Mosberger-Tang: - * + * * > In other words, the idea is to have sane_start() be called, and * > collect as many images as the frontend wants (which could in turn * > consist of multiple frames each as indicated by frame-type) and - * > when the frontend is done, it should call sane_cancel(). + * > when the frontend is done, it should call sane_cancel(). * > Sometimes it's better to think of sane_cancel() as "sane_stop()" * > but that name would have had some misleading connotations as * > well, that's why we stuck with "cancel". - * + * * The current consensus regarding duplex and ADF scans seems to be * the following call sequence: sane_start; sane_read (repeat until * EOF); sane_start; sane_read... and then call sane_cancel if the * batch is at an end. I.e. do not call sane_cancel during the run but * as soon as you get a SANE_STATUS_NO_DOCS. - * + * * From the SANE spec: * This function is used to immediately or as quickly as possible * cancel the currently pending operation of the device represented by @@ -6478,13 +6734,13 @@ check_for_cancel(struct scanner *s) if(s->started && s->cancelled){ unsigned char cmd[CANCEL_len]; size_t cmdLen = CANCEL_len; - + DBG (15, "check_for_cancel: cancelling\n"); - + /* cancel scan */ memset(cmd,0,cmdLen); set_SCSI_opcode(cmd, CANCEL_code); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -6494,7 +6750,7 @@ check_for_cancel(struct scanner *s) if(ret){ DBG (5, "check_for_cancel: ignoring bad cancel: %d\n",ret); } - + ret = object_position(s,SANE_FALSE); if(ret){ DBG (5, "check_for_cancel: ignoring bad eject: %d\n",ret); @@ -6516,7 +6772,7 @@ check_for_cancel(struct scanner *s) /* * Ends use of the scanner. - * + * * From the SANE spec: * This function terminates the association between the device handle * passed in argument h and the device it represents. If the device is @@ -6560,7 +6816,7 @@ disconnect_fd (struct scanner *s) /* * Terminates the backend. - * + * * From the SANE spec: * This function must be called to terminate use of a backend. The * function will first close all device handles that still might be @@ -6983,19 +7239,19 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, DBG(5,"cmd: no mem\n"); return SANE_STATUS_NO_MEM; } - + /* build a USB packet around the SCSI command */ cmdBuffer[3] = cmdLength-4; cmdBuffer[5] = 1; cmdBuffer[6] = 0x90; memcpy(cmdBuffer+cmdOffset,cmdBuff,cmdLen); - + /* write the command out */ DBG(25, "cmd: writing %d bytes, timeout %d\n", (int)cmdLength, cmdTimeout); hexdump(30, "cmd: >>", cmdBuffer, cmdLength); ret = sanei_usb_write_bulk(s->fd, cmdBuffer, &cmdActual); DBG(25, "cmd: wrote %d bytes, retVal %d\n", (int)cmdActual, ret); - + if(cmdLength != cmdActual){ DBG(5,"cmd: wrong size %d/%d\n", (int)cmdLength, (int)cmdActual); free(cmdBuffer); @@ -7043,19 +7299,19 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, DBG(5,"out: no mem\n"); return SANE_STATUS_NO_MEM; } - + /* build a USB packet around the SCSI command */ outBuffer[3] = outLength-4; outBuffer[5] = 2; outBuffer[6] = 0xb0; memcpy(outBuffer+outOffset,outBuff,outLen); - + /* write the command out */ DBG(25, "out: writing %d bytes, timeout %d\n", (int)outLength, outTimeout); hexdump(30, "out: >>", outBuffer, outLength); ret = sanei_usb_write_bulk(s->fd, outBuffer, &outActual); DBG(25, "out: wrote %d bytes, retVal %d\n", (int)outActual, ret); - + if(outLength != outActual){ DBG(5,"out: wrong size %d/%d\n", (int)outLength, (int)outActual); free(outBuffer); @@ -7102,7 +7358,7 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, DBG(5,"in: no mem\n"); return SANE_STATUS_NO_MEM; } - + DBG(25, "in: reading %d bytes, timeout %d\n", (int)inActual, inTimeout); ret = sanei_usb_read_bulk(s->fd, inBuffer, &inActual); DBG(25, "in: read %d bytes, retval %d\n", (int)inActual, ret); @@ -7161,11 +7417,11 @@ do_usb_cmd(struct scanner *s, int runRS, int shortTime, ret = SANE_STATUS_EOF; DBG(5,"in: short read, %d/%d\n", (int)inLength,(int)inActual); } - + /* ignore the USB packet around the SCSI command */ *inLen = inActual - inOffset; memcpy(inBuff,inBuffer+inOffset,*inLen); - + free(inBuffer); } @@ -7214,12 +7470,12 @@ do_usb_status(struct scanner *s, int runRS, int shortTime, size_t * extraLength) DBG(5,"stat: no mem\n"); return SANE_STATUS_NO_MEM; } - + DBG(25, "stat: reading %d bytes, timeout %d\n", (int)statLength, statTimeout); ret = sanei_usb_read_bulk(s->fd, statBuffer, &statActual); DBG(25, "stat: read %d bytes, retval %d\n", (int)statActual, ret); hexdump(30, "stat: <<", statBuffer, statActual); - + /*weird status*/ if(ret != SANE_STATUS_GOOD){ DBG(5,"stat: clearing error '%s'\n",sane_strstatus(ret)); @@ -7232,7 +7488,7 @@ do_usb_status(struct scanner *s, int runRS, int shortTime, size_t * extraLength) } /*inspect the status byte of the response*/ else if(statBuffer[statOffset]){ - DBG(5,"stat: status %d\n",statBuffer[statLength-1-4]); + DBG(5,"stat: status %d\n",statBuffer[statOffset]); ret = do_usb_clear(s,0,runRS); } @@ -7286,7 +7542,7 @@ do_usb_clear(struct scanner *s, int clear, int runRS) rs_in, &rs_inLen ); DBG(25,"rs sub call <<\n"); - + if(ret2 == SANE_STATUS_EOF){ DBG(5,"rs: got EOF, returning IO_ERROR\n"); return SANE_STATUS_IO_ERROR; @@ -7309,7 +7565,7 @@ do_usb_clear(struct scanner *s, int clear, int runRS) } static SANE_Status -wait_scanner(struct scanner *s) +wait_scanner(struct scanner *s) { SANE_Status ret = SANE_STATUS_GOOD; @@ -7360,11 +7616,11 @@ wait_scanner(struct scanner *s) /* Some scanners have per-resolution * color interlacing values, but most - * don't. This helper can tell the + * don't. This helper can tell the * difference. */ static int -get_color_inter(struct scanner *s, int side, int res) +get_color_inter(struct scanner *s, int side, int res) { int i; for(i=0;iu.page_x; @@ -7408,7 +7664,7 @@ get_page_width(struct scanner *s) * due to using FB or overscan. */ static int -get_page_height(struct scanner *s) +get_page_height(struct scanner *s) { int height = s->u.page_y; @@ -7600,7 +7856,7 @@ buffer_crop(struct scanner *s, int side) /* if we will later binarize this image, make sure the width * is a multiple of 8 pixels, by adjusting the right side */ - if ( must_downsample(s) && s->u.mode < MODE_GRAYSCALE ){ + if ( must_downsample(s) && s->u.mode < MODE_GRAYSCALE ){ s->crop_vals[3] -= (s->crop_vals[3]-s->crop_vals[2]) % 8; } @@ -7618,13 +7874,13 @@ buffer_crop(struct scanner *s, int side) s->i.width = s->s_params.pixels_per_line; s->i.height = s->s_params.lines; s->i.Bpl = s->s_params.bytes_per_line; - + /* update image size counter to new, smaller size */ s->i.bytes_tot[side] = s->s_params.lines * s->s_params.bytes_per_line; s->i.bytes_sent[side] = s->i.bytes_tot[side]; s->u.bytes_sent[side] = 0; - - cleanup: + + cleanup: DBG (10, "buffer_crop: finish\n"); return ret; } @@ -7679,7 +7935,7 @@ buffer_isblank(struct scanner *s, int side) return status; } -/* certain options require the entire image to +/* certain options require the entire image to * be collected from the scanner before we can * tell the user the size of the image. */ static int @@ -7696,7 +7952,7 @@ must_fully_buffer(struct scanner *s) return 0; } -/* certain scanners require the mode of the +/* certain scanners require the mode of the * image to be changed in software. */ static int must_downsample(struct scanner *s) @@ -7714,7 +7970,7 @@ must_downsample(struct scanner *s) used by scanners to implement brightness/contrast/gamma or by backends to speed binarization/thresholding - offset and slope inputs are -127 to +127 + offset and slope inputs are -127 to +127 slope rotates line around central input/output val, 0 makes horizontal line @@ -7730,9 +7986,9 @@ must_downsample(struct scanner *s) offset moves line vertically, and clamps to output range 0 keeps the line crossing the center of the table - pos zero neg + pos zero neg . xxxxxxxx . xx . - . x . x . + . x . x . out x . x . x . . x . x ............ xx.......... xxxxxxxx.... @@ -7761,7 +8017,7 @@ load_lut (unsigned char * lut, * first [-127,127] to [-.999,.999] * then to [-PI/4,PI/4] then [0,PI/2] * then take the tangent (T.O.A) - * then multiply by the normal linear slope + * then multiply by the normal linear slope * because the table may not be square, i.e. 1024x256*/ rise = tan((double)slope/128 * M_PI_4 + M_PI_4) * max_out_val / max_in_val; @@ -7793,4 +8049,3 @@ load_lut (unsigned char * lut, DBG (10, "load_lut: finish\n"); return ret; } - diff --git a/backend/canon_dr.conf.in b/backend/canon_dr.conf.in index 29b6db1..2f9d4e4 100644 --- a/backend/canon_dr.conf.in +++ b/backend/canon_dr.conf.in @@ -1,6 +1,6 @@ ####################################################################### # NOTE: 'option' lines only apply to the devices found by -# the NEXT 'usb' or 'scsi' line. You may repeat the option line if +# the NEXT 'usb' or 'scsi' line. You may repeat the option line if # required for multiple scanners of different models/connections. ####################################################################### diff --git a/backend/canon_dr.h b/backend/canon_dr.h index d96fbba..4ffb360 100644 --- a/backend/canon_dr.h +++ b/backend/canon_dr.h @@ -1,12 +1,12 @@ #ifndef CANON_DR_H #define CANON_DR_H -/* +/* * Part of SANE - Scanner Access Now Easy. * Please see opening comments in canon_dr.c */ -/* ------------------------------------------------------------------------- +/* ------------------------------------------------------------------------- * This option list has to contain all options for all scanners supported by * this driver. If a certain scanner cannot handle a certain option, there's * still the possibility to say so, later. @@ -49,6 +49,7 @@ enum scanner_Option OPT_DROPOUT_COLOR_B, OPT_BUFFERMODE, OPT_SIDE, + OPT_HW_CROP, /*sensor group*/ OPT_SENSOR_GROUP, @@ -89,7 +90,7 @@ struct img_params int Bpl; /* in bytes */ int valid_width; /*some machines have black padding*/ - int valid_Bpl; + int valid_Bpl; /* done yet? */ int eof[2]; @@ -183,9 +184,10 @@ struct scanner int has_df; int has_df_ultra; int has_btc; - int has_ssm; /* older scanners use this set scan mode command */ + int has_ssm; /* older scanners use this set scan mode command */ int has_ssm2; /* newer scanners user this similar command */ int has_ssm_pay_head_len; /* newer scanners put the length twice in ssm */ + int has_hwcrop; int can_read_sensors; int can_read_panel; int can_write_panel; @@ -286,6 +288,7 @@ struct scanner int swcrop; int swskip; int stapledetect; + int hwcrop; /* --------------------------------------------------------------------- */ /* values which are derived from setting the options above */ @@ -454,8 +457,8 @@ enum { #define DUPLEX_INTERLACE_2510 3 #define DUPLEX_INTERLACE_fFBb 4 -#define JPEG_INTERLACE_ALT 0 -#define JPEG_INTERLACE_NONE 1 +#define JPEG_INTERLACE_ALT 0 +#define JPEG_INTERLACE_NONE 1 #define CROP_RELATIVE 0 #define CROP_ABSOLUTE 1 diff --git a/backend/canon_pp-dev.c b/backend/canon_pp-dev.c index a357cf0..df7c4aa 100644 --- a/backend/canon_pp-dev.c +++ b/backend/canon_pp-dev.c @@ -40,12 +40,12 @@ ----- - This file is part of the canon_pp backend, supporting Canon CanoScan - Parallel scanners and also distributed as part of the stand-alone driver. + This file is part of the canon_pp backend, supporting Canon CanoScan + Parallel scanners and also distributed as part of the stand-alone driver. canon_pp-dev.c: $Revision$ - Misc constants for Canon CanoScan Parallel scanners and high-level scan + Misc constants for Canon CanoScan Parallel scanners and high-level scan functions. Simon Krix @@ -105,7 +105,7 @@ struct scanner_hardware_desc { unsigned int type; }; -static const struct scanner_hardware_desc +static const struct scanner_hardware_desc /* The known scanner types */ hw_fb320p = { "FB320P", 2, 2, 3508, 2552, 0 }, hw_fb330p = { "FB330P", 2, 2, 3508, 0, 1 }, @@ -124,7 +124,7 @@ struct scanner_id { char *id; const struct scanner_hardware_desc *hw; }; -static const struct scanner_id scanner_id_table[] = { +static const struct scanner_id scanner_id_table[] = { { "CANON IX-03055C", &hw_fb320p }, { "CANON IX-06025C", &hw_fb620p }, { "CANON IX-03075E", &hw_fb330p }, @@ -139,15 +139,15 @@ static const int fileversion = 3; /* Internal functions */ static unsigned long column_sum(image_segment *image, int x); -static int adjust_output(image_segment *image, scan_parameters *scanp, +static int adjust_output(image_segment *image, scan_parameters *scanp, scanner_parameters *scannerp); static int check8(unsigned char *p, int s); /* Converts from weird scanner format -> sequential data */ -static void convdata(unsigned char *srcbuffer, unsigned char *dstbuffer, +static void convdata(unsigned char *srcbuffer, unsigned char *dstbuffer, int width, int mode); /* Sets up the scan command. This could use a better name (and a rewrite). */ -static int scanner_setup_params(unsigned char *buf, scanner_parameters *sp, +static int scanner_setup_params(unsigned char *buf, scanner_parameters *sp, scan_parameters *scanp); /* file reading and writing helpers */ @@ -155,7 +155,7 @@ static int safe_write(int fd, const char *p, unsigned long len); static int safe_read(int fd, char *p, unsigned long len); /* Command sending loop (waiting for ready status) */ -static int send_command(struct parport *port, unsigned char *buf, int bufsize, +static int send_command(struct parport *port, unsigned char *buf, int bufsize, int delay, int timeout); /* Commands ================================================ */ @@ -219,8 +219,8 @@ static unsigned char command_14[32] = 0, 0, 0, 0, 0x12, 0xd1, 0x14, 0x82, 0, 0, 0, 0, - 0x0f, 0xff, - 0x0f, 0xff, + 0x0f, 0xff, + 0x0f, 0xff, 0x0f, 0xff, 0, 0 }; #endif @@ -229,15 +229,15 @@ static unsigned char command_14[32] = /* * safe_write(): a small wrapper which ensures all the data is written in calls - * to write(), since the POSIX call doesn't ensure it. + * to write(), since the POSIX call doesn't ensure it. */ static int safe_write(int fd, const char *p, unsigned long len) { - int diff; + int diff; unsigned long total = 0; do { diff = write(fd, p+total, len-total); - if (diff < 0) + if (diff < 0) { if (errno == EINTR) continue; return -1; @@ -249,7 +249,7 @@ static int safe_write(int fd, const char *p, unsigned long len) { } -/* same dealie for read, except in the case of read the return of 0 bytes with +/* same dealie for read, except in the case of read the return of 0 bytes with * no INTR error indicates EOF */ static int safe_read(int fd, char *p, unsigned long len) { int diff; @@ -257,7 +257,7 @@ static int safe_read(int fd, char *p, unsigned long len) { do { diff = read(fd, p+total, len-total); - if (diff <= 0) + if (diff <= 0) { if (errno == EINTR) continue; if (diff == 0) return -2; @@ -282,7 +282,7 @@ int sanei_canon_pp_init_scan(scanner_parameters *sp, scan_parameters *scanp) /* Buffer for buffer info block */ unsigned char buffer_info_block[6]; - /* The image size the scanner says we asked for + /* The image size the scanner says we asked for (based on the scanner's replies) */ int true_scanline_size, true_scanline_count; @@ -301,7 +301,7 @@ int sanei_canon_pp_init_scan(scanner_parameters *sp, scan_parameters *scanp) if (send_command(sp->port, command_b, 56, 50000, 1000000)) return -1; - + /* Ask the scanner about the buffer */ if (send_command(sp->port, cmd_buf_status, 10, 50000, 1000000)) return -1; @@ -309,7 +309,7 @@ int sanei_canon_pp_init_scan(scanner_parameters *sp, scan_parameters *scanp) /* Read buffer information block */ sanei_canon_pp_read(sp->port, 6, buffer_info_block); - if (check8(buffer_info_block, 6)) + if (check8(buffer_info_block, 6)) DBG(1, "init_scan: ** Warning: Checksum error reading buffer " "info block.\n"); @@ -321,7 +321,7 @@ int sanei_canon_pp_init_scan(scanner_parameters *sp, scan_parameters *scanp) expected_scanline_size = scanp->width * 1.25; break; case 1: /* true-colour; 30 bits per pixel */ expected_scanline_size = scanp->width * 3.75; break; - default: + default: DBG(1, "init_scan: Illegal mode %i requested in " "init_scan().\n", scanp->mode); DBG(1, "This is a bug. Please report it.\n"); @@ -329,29 +329,29 @@ int sanei_canon_pp_init_scan(scanner_parameters *sp, scan_parameters *scanp) } /* The scanner's idea of the length of each scanline in bytes */ - true_scanline_size = (buffer_info_block[0]<<8) | buffer_info_block[1]; + true_scanline_size = (buffer_info_block[0]<<8) | buffer_info_block[1]; /* The scanner's idea of the number of scanlines in total */ - true_scanline_count = (buffer_info_block[2]<<8) | buffer_info_block[3]; + true_scanline_count = (buffer_info_block[2]<<8) | buffer_info_block[3]; - if ((expected_scanline_size != true_scanline_size) + if ((expected_scanline_size != true_scanline_size) || (expected_scanline_count != true_scanline_count)) { DBG(10, "init_scan: Warning: Scanner is producing an image " "of unexpected size:\n"); - DBG(10, "expected: %i bytes wide, %i scanlines tall.\n", - expected_scanline_size, + DBG(10, "expected: %i bytes wide, %i scanlines tall.\n", + expected_scanline_size, expected_scanline_count); - DBG(10, "true: %i bytes wide, %i scanlines tall.\n", + DBG(10, "true: %i bytes wide, %i scanlines tall.\n", true_scanline_size, true_scanline_count); if (scanp->mode == 0) scanp->width = true_scanline_size / 1.25; else - scanp->width = true_scanline_size / 3.75; + scanp->width = true_scanline_size / 3.75; scanp->height = true_scanline_count; } - return 0; + return 0; } @@ -373,7 +373,7 @@ int sanei_canon_pp_initialise(scanner_parameters *sp, int mode) DBG(50, "initialise: >> scanner_init\n"); if (sanei_canon_pp_scanner_init(sp->port)) { - /* If we're using an unsupported ieee1284 mode here, this is + /* If we're using an unsupported ieee1284 mode here, this is * where it will fail, so fall back to nibble. */ sanei_canon_pp_set_ieee1284_mode(M1284_NIBBLE); if (sanei_canon_pp_scanner_init(sp->port)) @@ -416,12 +416,12 @@ int sanei_canon_pp_initialise(scanner_parameters *sp, int mode) { hw = cur_id->hw; } - else if (sp->scanheadwidth == 5104) + else if (sp->scanheadwidth == 5104) { /* Guess 600dpi scanner */ hw = &hw_alien600; } - else if (sp->scanheadwidth == 2552) + else if (sp->scanheadwidth == 2552) { /* Guess 300dpi scanner */ hw = &hw_alien300; @@ -433,24 +433,24 @@ int sanei_canon_pp_initialise(scanner_parameters *sp, int mode) } strcpy(sp->name, hw->name); - sp->natural_xresolution = hw->natural_xresolution; - sp->natural_yresolution = hw->natural_yresolution; + sp->natural_xresolution = hw->natural_xresolution; + sp->natural_yresolution = hw->natural_yresolution; sp->scanbedlength = hw->scanbedlength; if (hw->scanheadwidth) sp->scanheadwidth = hw->scanheadwidth; sp->type = hw->type; - return 0; + return 0; } /* Shut scanner down */ int sanei_canon_pp_close_scanner(scanner_parameters *sp) { - /* Put scanner in transparent mode */ + /* Put scanner in transparent mode */ sanei_canon_pp_sleep_scanner(sp->port); /* Free memory (with purchase of memory of equal or greater value) */ - if (sp->blackweight != NULL) + if (sp->blackweight != NULL) { free(sp->blackweight); sp->blackweight = NULL; @@ -471,7 +471,7 @@ int sanei_canon_pp_close_scanner(scanner_parameters *sp) sp->blueweight = NULL; } - return 0; + return 0; } /* Read the calibration information from file */ @@ -497,7 +497,7 @@ int sanei_canon_pp_load_weights(const char *filename, scanner_parameters *sp) return -2; } - /* Read and check file version (the calibrate file + /* Read and check file version (the calibrate file format changes from time to time) */ ret = safe_read(fd, (char *)&temp, sizeof(int)); @@ -512,7 +512,7 @@ int sanei_canon_pp_load_weights(const char *filename, scanner_parameters *sp) if (((sp->blueweight = malloc(cal_data_size)) == NULL) || ((sp->redweight = malloc(cal_data_size)) == NULL) || ((sp->greenweight = malloc(cal_data_size)) == NULL) - || ((sp->blackweight = malloc(cal_data_size)) == NULL)) + || ((sp->blackweight = malloc(cal_data_size)) == NULL)) return -4; /* Read width of calibration data */ @@ -555,20 +555,20 @@ int sanei_canon_pp_load_weights(const char *filename, scanner_parameters *sp) } /* Read white-balance/gamma data */ - + if (safe_read(fd, (char *)&(sp->gamma), 32) < 0) { close(fd); return -10; } - close(fd); + close(fd); return 0; } /* Mode is 0 for greyscale source data or 1 for RGB */ -static void convert_to_rgb(image_segment *dest, unsigned char *src, +static void convert_to_rgb(image_segment *dest, unsigned char *src, int width, int scanlines, int mode) { int curline; @@ -581,23 +581,23 @@ static void convert_to_rgb(image_segment *dest, unsigned char *src, if (mode == 0) /* Grey */ { - convdata(src + (curline * scanline_size), - dest->image_data + + convdata(src + (curline * scanline_size), + dest->image_data + (curline * width * 2), width, 1); } else if (mode == 1) /* Truecolour */ { /* Red */ - convdata(src + (curline * scanline_size), - dest->image_data + + convdata(src + (curline * scanline_size), + dest->image_data + (curline * width *3*2) + 4, width, 2); /* Green */ - convdata(src + (curline * scanline_size) + colour_size, - dest->image_data + + convdata(src + (curline * scanline_size) + colour_size, + dest->image_data + (curline * width *3*2) + 2, width, 2); /* Blue */ - convdata(src + (curline * scanline_size) + - (2 * colour_size), dest->image_data + + convdata(src + (curline * scanline_size) + + (2 * colour_size), dest->image_data + (curline * width *3*2), width, 2); } @@ -605,7 +605,7 @@ static void convert_to_rgb(image_segment *dest, unsigned char *src, } -int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, +int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, scan_parameters *scanp, int scanline_number, int do_adjust, int scanlines_left) { @@ -646,8 +646,8 @@ int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, /* Allocate memory for dest image segment */ - output_image->image_data = - malloc(output_image->width * output_image->height * + output_image->image_data = + malloc(output_image->width * output_image->height * (scanp->mode ? 3 : 1) * 2); if (output_image->image_data == NULL) @@ -679,17 +679,17 @@ int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, if ((packet_header[2]<<8) + packet_header[3] != read_data_size) { - DBG(1, "read_segment: Error: Expected data size: %i bytes.\n", + DBG(1, "read_segment: Error: Expected data size: %i bytes.\n", read_data_size); DBG(1, "read_segment: Expecting %i bytes times %i " "scanlines.\n", scanline_size, scanline_number); - DBG(1, "read_segment: Actual data size: %i bytes.\n", + DBG(1, "read_segment: Actual data size: %i bytes.\n", (packet_header[2] << 8) + packet_header[3]); goto error_out; } /* Read scanlines_this_packet scanlines into the input buf */ - + if (sanei_canon_pp_read(sp->port, read_data_size, input_buffer)) { DBG(1, "read_segment: Segment read incorrectly, and we don't " @@ -697,11 +697,11 @@ int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, goto error_out; } - /* This is the only place we can abort safely - + /* This is the only place we can abort safely - * between reading one segment and requesting the next one. */ if (sp->abort_now) goto error_out; - if (scanlines_left >= (scanline_number * 2)) + if (scanlines_left >= (scanline_number * 2)) { DBG(100, "read_segment: Speculatively starting more scanning " "(%d left)\n", scanlines_left); @@ -711,7 +711,7 @@ int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, DBG(100, "read_segment: Convert to RGB\n"); /* Convert data */ - convert_to_rgb(output_image, input_buffer, scanp->width, + convert_to_rgb(output_image, input_buffer, scanp->width, scanline_number, scanp->mode); /* Adjust pixel readings according to calibration data */ @@ -724,10 +724,10 @@ int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, *dest = output_image; /* finished with this now */ free(input_buffer); - return 0; + return 0; error_out: - if (output_image && output_image->image_data) + if (output_image && output_image->image_data) free(output_image->image_data); if (output_image) free(output_image); if (input_buffer) free(input_buffer); @@ -735,13 +735,13 @@ int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, return -1; } -/* +/* check8: Calculates the checksum-8 for s bytes pointed to by p. For messages from the scanner, this should normally end up returning -0, since the last byte of most packets is the value that makes the +0, since the last byte of most packets is the value that makes the total up to 0 (or 256 if you're left-handed). -Hence, usage: if (check8(buffer, size)) {DBG(10, "checksum error!\n");} +Hence, usage: if (check8(buffer, size)) {DBG(10, "checksum error!\n");} Can also be used to generate valid checksums for sending to the scanner. */ @@ -756,13 +756,13 @@ static int check8(unsigned char *p, int s) { /* Converts from scanner format -> linear width is in pixels, not bytes. */ /* This function could use a rewrite */ -static void convdata(unsigned char *srcbuffer, unsigned char *dstbuffer, +static void convdata(unsigned char *srcbuffer, unsigned char *dstbuffer, int width, int mode) -/* This is a tricky (read: crap) function (read: hack) which is why I probably - spent more time commenting it than programming it. The thing to remember +/* This is a tricky (read: crap) function (read: hack) which is why I probably + spent more time commenting it than programming it. The thing to remember here is that the scanner uses interpolated scanlines, so it's - RRRRRRRGGGGGGBBBBBB not RGBRGBRGBRGBRGB. So, the calling function just - increments the destination pointer slightly to handle green, then a bit + RRRRRRRGGGGGGBBBBBB not RGBRGBRGBRGBRGB. So, the calling function just + increments the destination pointer slightly to handle green, then a bit more for blue. If you don't understand, tough. */ { int count; @@ -770,13 +770,13 @@ static void convdata(unsigned char *srcbuffer, unsigned char *dstbuffer, for (count = 0; count < width; count++) { - /* The scanner stores data in a bizzare butchered 10-bit + /* The scanner stores data in a bizzare butchered 10-bit format. I'll try to explain it in 100 words or less: - Scanlines are made up of groups of 4 pixels. Each group of - 4 is stored inside 5 bytes. The first 4 bytes of the group - contain the lowest 8 bits of one pixel each (in the right - order). The 5th byte contains the most significant 2 bits + Scanlines are made up of groups of 4 pixels. Each group of + 4 is stored inside 5 bytes. The first 4 bytes of the group + contain the lowest 8 bits of one pixel each (in the right + order). The 5th byte contains the most significant 2 bits of each pixel in the same order. */ i = srcbuffer[count + (count >> 2)]; /* Low byte for pixel */ @@ -784,7 +784,7 @@ static void convdata(unsigned char *srcbuffer, unsigned char *dstbuffer, j = j >> ((count % 4) * 2); /* Get upper 2 bits of intensity */ j = j & 0x03; /* Can't hurt */ /* And the final 10-bit pixel value is: */ - k = (j << 8) | i; + k = (j << 8) | i; /* now we return this as a 16 bit value */ k = k << 6; @@ -797,17 +797,17 @@ static void convdata(unsigned char *srcbuffer, unsigned char *dstbuffer, else if (mode == 2) /* Scanner -> RGB */ { dstbuffer[count * 3 * 2] = HIGH_BYTE(k); - dstbuffer[(count * 3 * 2) + 1] = LOW_BYTE(k); + dstbuffer[(count * 3 * 2) + 1] = LOW_BYTE(k); } } } -static int adjust_output(image_segment *image, scan_parameters *scanp, +static int adjust_output(image_segment *image, scan_parameters *scanp, scanner_parameters *scannerp) /* Needing a good cleanup */ { - /* light and dark points for the CCD sensor in question + /* light and dark points for the CCD sensor in question * (stored in file as 0-1024, scaled to 0-65536) */ unsigned long hi, lo; /* The result of our calculations */ @@ -827,70 +827,70 @@ static int adjust_output(image_segment *image, scan_parameters *scanp, { /* Figure out CCD sensor number */ /* MAGIC FORMULA ALERT! */ - ccd = (pixelnum << (scannerp->natural_xresolution - - scanp->xresolution)) + (1 << - (scannerp->natural_xresolution + ccd = (pixelnum << (scannerp->natural_xresolution - + scanp->xresolution)) + (1 << + (scannerp->natural_xresolution - scanp->xresolution)) - 1; - scaled_xoff = scanp->xoffset << - (scannerp->natural_xresolution - + scaled_xoff = scanp->xoffset << + (scannerp->natural_xresolution - scanp->xresolution); - ccd += scaled_xoff; + ccd += scaled_xoff; for (colour = 0; colour < cols; colour++) { /* Address of pixel under scrutiny */ - pixel_address = + pixel_address = (scanline * image->width * cols * 2) + (pixelnum * cols * 2) + (colour * 2); - /* Dark value is easy + /* Dark value is easy * Range of lo is 0-18k */ lo = (scannerp->blackweight[ccd]) * 3; - /* Light value depends on the colour, + /* Light value depends on the colour, * and is an average in greyscale mode. */ if (scanp->mode == 1) /* RGB */ { switch (colour) { - case 0: hi = scannerp->redweight[ccd] * 3; + case 0: hi = scannerp->redweight[ccd] * 3; break; - case 1: hi = scannerp->greenweight[ccd] * 3; + case 1: hi = scannerp->greenweight[ccd] * 3; break; - default: hi = scannerp->blueweight[ccd] * 3; + default: hi = scannerp->blueweight[ccd] * 3; break; } } else /* Grey - scanned using green */ { - hi = scannerp->greenweight[ccd] * 3; + hi = scannerp->greenweight[ccd] * 3; } - /* Check for bad calibration data as it + /* Check for bad calibration data as it can cause a divide-by-0 error */ if (hi <= lo) { DBG(1, "adjust_output: Bad cal data!" " hi: %ld lo: %ld\n" "Recalibrate, that " - "should fix it.\n", + "should fix it.\n", hi, lo); return -1; } /* Start with the pixel value in result */ - result = MAKE_SHORT(*(image->image_data + - pixel_address), - *(image->image_data + + result = MAKE_SHORT(*(image->image_data + + pixel_address), + *(image->image_data + pixel_address + 1)); result = result >> 6; /* Range now = 0-1023 */ /* if (scanline == 10) DBG(200, "adjust_output: Initial pixel" - " value: %ld\n", + " value: %ld\n", result); */ result *= 54; /* Range now = 0-54k */ @@ -913,13 +913,13 @@ static int adjust_output(image_segment *image, scan_parameters *scanp, { DBG(200, "adjust_output: %d: base = " "%lu, result %lu (%lu " - "- %lu)\n", pixelnum, + "- %lu)\n", pixelnum, result, temp, lo, hi); - } + } */ result = temp; - /* Store the value back where it came + /* Store the value back where it came * from (always bigendian) */ *(image->image_data + pixel_address) = HIGH_BYTE(result); @@ -934,7 +934,7 @@ static int adjust_output(image_segment *image, scan_parameters *scanp, /* Calibration run. Aborting allowed at "safe" points where the scanner won't * be left in a crap state. */ -int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) +int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) { int count, readnum, colournum, scanlinenum; int outfile; @@ -962,11 +962,11 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) if (sp->abort_now) return -1; DBG(40, "Calibrating %ix%i pixels calibration image " - "(%i bytes each scan).\n", - sp->scanheadwidth, scanline_count, + "(%i bytes each scan).\n", + sp->scanheadwidth, scanline_count, scanline_size * scanline_count); - /* Allocate memory for calibration data */ + /* Allocate memory for calibration data */ sp->blackweight = (unsigned long *) calloc(sizeof(unsigned long), sp->scanheadwidth); sp->redweight = (unsigned long *) @@ -981,7 +981,7 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) databuf = malloc(scanline_size * scanline_count * calibration_reads*3); /* And allocate space for converted image data in this image_segment */ - image.image_data = malloc(scanline_count * sp->scanheadwidth * 2 * + image.image_data = malloc(scanline_count * sp->scanheadwidth * 2 * calibration_reads); image.width = sp->scanheadwidth; image.height = scanline_count * calibration_reads; @@ -996,7 +996,7 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) DBG(40, "Step 1/3: Calibrating black level...\n"); for (readnum = 0; readnum < calibration_reads; readnum++) { - DBG(40, " * Black scan number %d/%d.\n", readnum + 1, + DBG(40, " * Black scan number %d/%d.\n", readnum + 1, calibration_reads); if (sp->abort_now) return -1; @@ -1007,32 +1007,32 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) free (image.image_data); free(databuf); return -1; - + } /* Black reference data */ sanei_canon_pp_read(sp->port, scanline_size * scanline_count, - databuf + + databuf + (readnum * scanline_size * scanline_count)); } /* Convert scanner format to a greyscale 16bpp image */ - for (scanlinenum = 0; - scanlinenum < scanline_count * calibration_reads; + for (scanlinenum = 0; + scanlinenum < scanline_count * calibration_reads; scanlinenum++) { - convdata(databuf + (scanlinenum * scanline_size), - image.image_data + - (scanlinenum * sp->scanheadwidth*2), + convdata(databuf + (scanlinenum * scanline_size), + image.image_data + + (scanlinenum * sp->scanheadwidth*2), sp->scanheadwidth, 1); } /* Take column totals */ for (count = 0; count < sp->scanheadwidth; count++) { - /* Value is normalised as if we took 6 scanlines, even if we + /* Value is normalised as if we took 6 scanlines, even if we * didn't (620P I'm looking at you!) */ - sp->blackweight[count] = (column_sum(&image, count) * 6) + sp->blackweight[count] = (column_sum(&image, count) * 6) / scanline_count >> 6; } @@ -1057,7 +1057,7 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) DBG(20, " * Snoozing for 15 seconds while the scanner calibrates..."); usleep(15000000); DBG(40, "done.\n"); - + DBG(40, " * Requesting gamma table values..."); if (send_command(sp->port, cmd_readgamma, 10, 100000, 10000000)) { @@ -1088,7 +1088,7 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) command_buffer[3] = colournum; for (readnum = 0; readnum < 3; readnum++) { - DBG(10, " * %s sensors, scan number %d/%d.\n", + DBG(10, " * %s sensors, scan number %d/%d.\n", colours[colournum-1], readnum + 1, calibration_reads); @@ -1102,20 +1102,20 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) return -1; } - sanei_canon_pp_read(sp->port, scanline_size * - scanline_count, databuf + - (readnum * scanline_size * + sanei_canon_pp_read(sp->port, scanline_size * + scanline_count, databuf + + (readnum * scanline_size * scanline_count)); } /* Convert colour data from scanner format to RGB data */ - for (scanlinenum = 0; scanlinenum < scanline_count * + for (scanlinenum = 0; scanlinenum < scanline_count * calibration_reads; scanlinenum++) { - convdata(databuf + (scanlinenum * scanline_size), - image.image_data + - (scanlinenum * sp->scanheadwidth * 2), + convdata(databuf + (scanlinenum * scanline_size), + image.image_data + + (scanlinenum * sp->scanheadwidth * 2), sp->scanheadwidth, 1); } @@ -1123,14 +1123,14 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) for (count = 0; count < sp->scanheadwidth; count++) { if (colournum == 1) - sp->redweight[count] = - column_sum(&image, count) >> 6; + sp->redweight[count] = + column_sum(&image, count) >> 6; else if (colournum == 2) - sp->greenweight[count] = - column_sum(&image, count) >> 6; + sp->greenweight[count] = + column_sum(&image, count) >> 6; else - sp->blueweight[count] = - column_sum(&image, count) >> 6; + sp->blueweight[count] = + column_sum(&image, count) >> 6; } } @@ -1154,19 +1154,19 @@ int sanei_canon_pp_calibrate(scanner_parameters *sp, char *cal_file) DBG(10, "Write error on calibration file %s", cal_file); /* Data */ - if (safe_write(outfile, (char *)&(sp->scanheadwidth), + if (safe_write(outfile, (char *)&(sp->scanheadwidth), sizeof(sp->scanheadwidth)) < 0) DBG(10, "Write error on calibration file %s", cal_file); - if (safe_write(outfile, (char *)(sp->blackweight), + if (safe_write(outfile, (char *)(sp->blackweight), sp->scanheadwidth * sizeof(long)) < 0) DBG(10, "Write error on calibration file %s", cal_file); - if (safe_write(outfile, (char *)(sp->redweight), + if (safe_write(outfile, (char *)(sp->redweight), sp->scanheadwidth * sizeof(long)) < 0) DBG(10, "Write error on calibration file %s", cal_file); - if (safe_write(outfile, (char *)(sp->greenweight), + if (safe_write(outfile, (char *)(sp->greenweight), sp->scanheadwidth * sizeof(long)) < 0) DBG(10, "Write error on calibration file %s", cal_file); - if (safe_write(outfile, (char *)(sp->blueweight), + if (safe_write(outfile, (char *)(sp->blueweight), sp->scanheadwidth * sizeof(long)) < 0) DBG(10, "Write error on calibration file %s", cal_file); if (safe_write(outfile, (char *)(sp->gamma), 32) < 0) @@ -1198,7 +1198,7 @@ static unsigned long column_sum(image_segment *image, int x) } -static int scanner_setup_params(unsigned char *buf, scanner_parameters *sp, +static int scanner_setup_params(unsigned char *buf, scanner_parameters *sp, scan_parameters *scanp) { int scaled_width, scaled_height; @@ -1218,14 +1218,14 @@ static int scanner_setup_params(unsigned char *buf, scanner_parameters *sp, buf[3] = 0x58; } - scaled_width = scanp->width << + scaled_width = scanp->width << (sp->natural_xresolution - scanp->xresolution); /* YO! This needs fixing if we ever use yresolution! */ - scaled_height = scanp->height << + scaled_height = scanp->height << (sp->natural_xresolution - scanp->xresolution); - scaled_xoff = scanp->xoffset << + scaled_xoff = scanp->xoffset << (sp->natural_xresolution - scanp->xresolution); - scaled_yoff = scanp->yoffset << + scaled_yoff = scanp->yoffset << (sp->natural_xresolution - scanp->xresolution); /* Input resolution */ @@ -1247,7 +1247,7 @@ static int scanner_setup_params(unsigned char *buf, scanner_parameters *sp, buf[14] = (scaled_yoff & 0xff00) >> 8; buf[15] = scaled_yoff & 0xff; - /* Width of image to be scanned */ + /* Width of image to be scanned */ buf[16] = (scaled_width & 0xff000000) >> 24; buf[17] = (scaled_width & 0xff0000) >> 16; buf[18] = (scaled_width & 0xff00) >> 8; @@ -1260,7 +1260,7 @@ static int scanner_setup_params(unsigned char *buf, scanner_parameters *sp, buf[23] = scaled_height & 0xff; - /* These appear to be the only two colour mode possibilities. + /* These appear to be the only two colour mode possibilities. Pure black-and-white mode probably just uses greyscale and then gets its contrast adjusted by the driver. I forget. */ if (scanp->mode == 1) /* Truecolour */ @@ -1307,15 +1307,15 @@ int sanei_canon_pp_sleep_scanner(struct parport *port) int sanei_canon_pp_detect(struct parport *port, int mode) { /*int caps;*/ - /* This code needs to detect whether or not a scanner is present on - * the port, quickly and reliably. Fast version of - * sanei_canon_pp_initialise() + /* This code needs to detect whether or not a scanner is present on + * the port, quickly and reliably. Fast version of + * sanei_canon_pp_initialise() * - * If this detect returns true, a more comprehensive check will + * If this detect returns true, a more comprehensive check will * be conducted - * Return values: + * Return values: * 0 = scanner present - * anything else = scanner not present + * anything else = scanner not present * PRE: port is open/unclaimed * POST: port is closed/unclaimed */ @@ -1343,9 +1343,9 @@ int sanei_canon_pp_detect(struct parport *port, int mode) return 0; } -static int send_command(struct parport *port, unsigned char *buf, int bufsize, +static int send_command(struct parport *port, unsigned char *buf, int bufsize, int delay, int timeout) -/* Sends a command until the scanner says it is ready. +/* Sends a command until the scanner says it is ready. * sleeps for delay microsecs between reads * returns -1 on error, -2 on timeout */ { @@ -1359,7 +1359,7 @@ static int send_command(struct parport *port, unsigned char *buf, int bufsize, /* sleep a bit */ usleep(delay); - } while (sanei_canon_pp_check_status(port) && + } while (sanei_canon_pp_check_status(port) && retries++ < (timeout/delay)); if (retries >= (timeout/delay)) return -2; diff --git a/backend/canon_pp-dev.h b/backend/canon_pp-dev.h index e8f36a8..4ad2e45 100644 --- a/backend/canon_pp-dev.h +++ b/backend/canon_pp-dev.h @@ -42,7 +42,7 @@ canon_pp-dev.h: $Revision$ - This file is part of the canon_pp backend, supporting Canon FBX30P + This file is part of the canon_pp backend, supporting Canon FBX30P and NX40P scanners and also part of the stand-alone driver. Simon Krix @@ -105,9 +105,9 @@ typedef struct scanner_parameter_struct int max_xresolution; int max_yresolution; - /* ID String. Should only be 38(?) bytes long, so we can + /* ID String. Should only be 38(?) bytes long, so we can reduce the size later. */ - char id_string[80]; + char id_string[80]; /* Short, readable scanner name, such as "FB330P" */ char name[40]; @@ -120,7 +120,7 @@ typedef struct scanner_parameter_struct unsigned long *blueweight; /* Not understood white-balance/gain values */ - unsigned char gamma[32]; + unsigned char gamma[32]; /* Type of scanner ( 0 = *20P, 1 = [*30P|*40P] ) */ unsigned char type; @@ -154,7 +154,7 @@ typedef struct image_segment_struct /* Scan-related functions ========================= */ -/* Brings the scanner in and out of transparent mode +/* Brings the scanner in and out of transparent mode and detects model information */ int sanei_canon_pp_initialise(scanner_parameters *sp, int mode); int sanei_canon_pp_close_scanner(scanner_parameters *sp); @@ -162,7 +162,7 @@ int sanei_canon_pp_close_scanner(scanner_parameters *sp); /* Image scanning functions */ int sanei_canon_pp_init_scan(scanner_parameters *sp, scan_parameters *scanp); -int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, +int sanei_canon_pp_read_segment(image_segment **dest, scanner_parameters *sp, scan_parameters *scanp, int scanline_count, int do_adjust, int scanlines_left); diff --git a/backend/canon_pp-io.c b/backend/canon_pp-io.c index 881ac24..97ee526 100644 --- a/backend/canon_pp-io.c +++ b/backend/canon_pp-io.c @@ -41,7 +41,7 @@ ----- This file is part of the canon_pp backend, supporting Canon CanoScan - Parallel scanners and also distributed as part of the stand-alone driver. + Parallel scanners and also distributed as part of the stand-alone driver. canon_pp-io.c: $Revision$ @@ -89,8 +89,8 @@ static void DBG(int level, const char *format, ...) /* 0x00 = Nibble Mode (M1284_NIBBLE) 0x10 = ECP Mode (M1284_ECP) - The scanner driver seems not to support ECP RLE mode - (which is a huge bummer because compression would be + The scanner driver seems not to support ECP RLE mode + (which is a huge bummer because compression would be ace) nor EPP mode. */ static int ieee_mode = M1284_NIBBLE; @@ -109,12 +109,12 @@ static void scanner_chessboard_control(struct parport *port); static void scanner_chessboard_data(struct parport *port, int mode); /* Used by read_data */ -static int ieee_transfer(struct parport *port, int length, +static int ieee_transfer(struct parport *port, int length, unsigned char *data); /* Low level functions */ static int readstatus(struct parport *port); -static int expect(struct parport *port, const char *step, int s, +static int expect(struct parport *port, const char *step, int s, int mask, unsigned int delay); /* Port-level functions */ @@ -124,7 +124,7 @@ static void outboth(struct parport *port, int d, int c); /************************************/ -/* +/* * IEEE 1284 defines many values for m, * but these scanners only support 2: nibble and ECP modes. * And no data compression either (argh!) @@ -144,7 +144,7 @@ int sanei_canon_pp_wake_scanner(struct parport *port, int mode) int i = 0; int tmp; int max_cycles = 3; - + tmp = readstatus(port); /* Reset only works on 30/40 models */ @@ -171,7 +171,7 @@ int sanei_canon_pp_wake_scanner(struct parport *port, int mode) scanner_chessboard_control(port); scanner_chessboard_data(port, mode); - if (expect(port, NULL, 0x03, 0x1f, 800000) && + if (expect(port, NULL, 0x03, 0x1f, 800000) && (mode == INITMODE_AUTO)) { /* 630 Style init failed, try 620 style */ @@ -187,7 +187,7 @@ int sanei_canon_pp_wake_scanner(struct parport *port, int mode) usleep(100000); } - } while ((i < max_cycles) && (!expect(port,"Scanner wakeup reply 2", + } while ((i < max_cycles) && (!expect(port,"Scanner wakeup reply 2", 0x03, 0x1f, 100000) == 0)); /* Block just after chessboarding @@ -201,7 +201,7 @@ int sanei_canon_pp_wake_scanner(struct parport *port, int mode) return -1; outboth(port, 0, NSELECTIN | NINIT | HOSTCLK); /* Clear D, C3+, C1- */ - /* If we had to try the wakeup cycle more than once, we should wait + /* If we had to try the wakeup cycle more than once, we should wait * here for 10 seconds to let the scanner pull itself together - * it can actually take longer, but I can't wait that long! */ if (i > 1) @@ -227,7 +227,7 @@ int sanei_canon_pp_write(struct parport *port, int length, unsigned char *data) DBG(10,"%02x ", data[count]); if (count % 20 == 19) DBG(10,"\n "); - } + } if (count % 20 != 19) DBG(10,"\n"); #endif @@ -238,20 +238,20 @@ int sanei_canon_pp_write(struct parport *port, int length, unsigned char *data) case M1284_BECP: case M1284_ECPRLE: case M1284_ECPSWE: - case M1284_ECP: + case M1284_ECP: ieee1284_negotiate(port, ieee_mode); - if (ieee1284_ecp_write_data(port, 0, (char *)data, + if (ieee1284_ecp_write_data(port, 0, (char *)data, length) != length) return -1; break; - case M1284_NIBBLE: - if (ieee1284_compat_write(port, 0, (char *)data, + case M1284_NIBBLE: + if (ieee1284_compat_write(port, 0, (char *)data, length) != length) return -1; break; default: DBG(0, "Invalid mode in write!\n"); - } + } DBG(100, "<< write"); @@ -265,7 +265,7 @@ int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data) DBG(200, "NEW read_data (%i bytes):\n", length); ieee1284_negotiate(port, ieee_mode); - /* This is special; Nibble mode needs a little + /* This is special; Nibble mode needs a little extra help from us. */ if (ieee_mode == M1284_NIBBLE) @@ -275,7 +275,7 @@ int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data) if (expect(port, "Read Data 1", 0, NDATAAVAIL, 6000000)) { DBG(10,"Error 1\n"); - ieee1284_terminate(port); + ieee1284_terminate(port); return 1; } outcont(port, HOSTBUSY, HOSTBUSY); @@ -283,7 +283,7 @@ int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data) if (expect(port, "Read Data 2", NACK, NACK, 1000000)) { DBG(1,"Error 2\n"); - ieee1284_terminate(port); + ieee1284_terminate(port); return 1; } if (expect(port, "Read Data 3 (Ready?)", 0, PERROR, 1000000)) @@ -319,7 +319,7 @@ int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data) /* If 0 bytes were transferred, it's a legal "No data" condition (I think). Otherwise, it may have run out of buffer.. keep reading*/ - + if (count < 0) { DBG(10, "Couldn't read enough data (need %d more " "of %d)\n", length+count,length+offset); @@ -344,14 +344,14 @@ int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data) DBG(10,"%02x ", data[count]); if (count % 20 == 19) DBG(10,"\n "); - } + } if (count % 20 != 19) DBG(10,"\n"); } else { DBG(10,"Read: %i bytes\n", length); - } + } #endif if (ieee_mode == M1284_NIBBLE) @@ -367,17 +367,17 @@ static int ieee_transfer(struct parport *port, int length, unsigned char *data) DBG(100, "IEEE transfer (%i bytes)\n", length); - switch (ieee_mode) + switch (ieee_mode) { case M1284_BECP: case M1284_ECP: case M1284_ECPRLE: case M1284_ECPSWE: - result = ieee1284_ecp_read_data(port, 0, (char *)data, + result = ieee1284_ecp_read_data(port, 0, (char *)data, length); break; case M1284_NIBBLE: - result = ieee1284_nibble_read(port, 0, (char *)data, + result = ieee1284_nibble_read(port, 0, (char *)data, length); break; default: @@ -405,22 +405,22 @@ int sanei_canon_pp_check_status(struct parport *port) { case 0x0606: DBG(200, "Ready - 0x0606\n"); - return 0; + return 0; break; case 0x1414: - DBG(200, "Busy - 0x1414\n"); + DBG(200, "Busy - 0x1414\n"); return 1; break; case 0x0805: - DBG(200, "Resetting - 0x0805\n"); + DBG(200, "Resetting - 0x0805\n"); return 3; break; case 0x1515: DBG(1, "!! Invalid Command - 0x1515\n"); - return 2; + return 2; break; case 0x0000: - DBG(200, "Nothing - 0x0000"); + DBG(200, "Nothing - 0x0000"); return 4; break; @@ -451,9 +451,9 @@ static void outboth(struct parport *port, int d, int c) { ieee1284_write_data(port, d & 0xff); outcont(port, c, 0x0f); -} +} -/* readstatus(): +/* readstatus(): Returns the LOGIC value of the S register (ie: all input lines) shifted right to to make it easier to read. Note: S5 is inverted by ieee1284_read_status so we don't need to */ @@ -472,7 +472,7 @@ static void scanner_chessboard_control(struct parport *port) outcont(port, 13, 0xf); usleep(10); outcont(port, 7, 0xf); - usleep(10); + usleep(10); } static void scanner_chessboard_data(struct parport *port, int mode) @@ -490,28 +490,28 @@ static void scanner_chessboard_data(struct parport *port, int mode) outdata(port, 0x55); else outdata(port, 0x33); - outcont(port, HOSTBUSY, HOSTBUSY); + outcont(port, HOSTBUSY, HOSTBUSY); usleep(10); - outcont(port, 0, HOSTBUSY); + outcont(port, 0, HOSTBUSY); usleep(10); - outcont(port, HOSTBUSY, HOSTBUSY); + outcont(port, HOSTBUSY, HOSTBUSY); usleep(10); if (mode == INITMODE_20P) outdata(port, 0xaa); else outdata(port, 0xcc); - outcont(port, HOSTBUSY, HOSTBUSY); + outcont(port, HOSTBUSY, HOSTBUSY); usleep(10); - outcont(port, 0, HOSTBUSY); + outcont(port, 0, HOSTBUSY); usleep(10); - outcont(port, HOSTBUSY, HOSTBUSY); + outcont(port, HOSTBUSY, HOSTBUSY); usleep(10); } } /* Reset the scanner. At least, it works 50% of the time. */ -static int scanner_reset(struct parport *port) +static int scanner_reset(struct parport *port) { /* Resetting only works for the *30Ps, sorry */ @@ -545,7 +545,7 @@ static int scanner_reset(struct parport *port) outcont(port, 0x0f, 0xf); /* All lines must be 1. */ /* All lines 1 */ - if (expect(port, "Reset 2 response 2 (READY)", + if (expect(port, "Reset 2 response 2 (READY)", 0x1f, 0x1f, 500000)) return 1; @@ -556,9 +556,9 @@ static int scanner_reset(struct parport *port) return 0; } -/* A timed version of expect, which will wait for delay before erroring +/* A timed version of expect, which will wait for delay before erroring This is the one and only one we should be using */ -static int expect(struct parport *port, const char *msg, int s, +static int expect(struct parport *port, const char *msg, int s, int mask, unsigned int delay) { struct timeval tv; @@ -591,7 +591,7 @@ int sanei_canon_pp_scanner_init(struct parport *port) /* In Windows, this is always ECP (or an attempt at it) */ if (sanei_canon_pp_write(port, 10, cmd_init)) return -1; - /* Note that we don't really mind what the status was as long as it + /* Note that we don't really mind what the status was as long as it * wasn't a read error (returns -1) */ /* In fact, the 620P gives an error on that last command, but they * keep going anyway */ @@ -605,7 +605,7 @@ int sanei_canon_pp_scanner_init(struct parport *port) if (tmp < 0) return -1; DBG(10, "scanner_init: Giving the scanner a snooze...\n"); - usleep(500000); + usleep(500000); tries++; diff --git a/backend/canon_pp-io.h b/backend/canon_pp-io.h index 376af8a..ad04180 100644 --- a/backend/canon_pp-io.h +++ b/backend/canon_pp-io.h @@ -42,7 +42,7 @@ canon_pp-io.h: $Revision$ - This file is part of the canon_pp backend, supporting Canon FBX30P + This file is part of the canon_pp backend, supporting Canon FBX30P and NX40P scanners and also distributed as part of the stand-alone driver. @@ -50,14 +50,14 @@ */ #ifndef CANON_PP_IO_H -#define CANON_PP_IO_H +#define CANON_PP_IO_H /* Actual Interface */ void sanei_canon_pp_set_ieee1284_mode(int m); int sanei_canon_pp_wake_scanner(struct parport *port, int mode); -int sanei_canon_pp_write(struct parport *port, int length, +int sanei_canon_pp_write(struct parport *port, int length, unsigned char *data); -int sanei_canon_pp_read(struct parport *port, int length, +int sanei_canon_pp_read(struct parport *port, int length, unsigned char *data); int sanei_canon_pp_check_status(struct parport *port); int sanei_canon_pp_scanner_init(struct parport *port); diff --git a/backend/canon_pp.c b/backend/canon_pp.c index cc7c27e..822eaf1 100644 --- a/backend/canon_pp.c +++ b/backend/canon_pp.c @@ -42,7 +42,7 @@ canon_pp.c: $Revision$ - This file is part of the canon_pp backend, supporting Canon FBX30P + This file is part of the canon_pp backend, supporting Canon FBX30P and NX40P scanners */ @@ -114,9 +114,9 @@ static SANE_Bool force_nibble = SANE_FALSE; /* Constants */ /* Colour Modes */ -static const SANE_String_Const cmodes[] = { - SANE_VALUE_SCAN_MODE_GRAY, - SANE_VALUE_SCAN_MODE_COLOR, +static const SANE_String_Const cmodes[] = { + SANE_VALUE_SCAN_MODE_GRAY, + SANE_VALUE_SCAN_MODE_COLOR, NULL }; /* bit depths */ @@ -139,7 +139,7 @@ static const SANE_Int res600[] = {4, 75, 150, 300, 600}; sane_init (SANE_Int *vc, SANE_Auth_Callback cb) { SANE_Status status = SANE_STATUS_GOOD; - int i, tmp; + int i, tmp; int tmp_im = INITMODE_AUTO; FILE *fp; char line[81]; /* plus 1 for a null */ @@ -150,7 +150,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) DBG_INIT(); #if defined PACKAGE && defined VERSION - DBG(2, ">> sane_init (version %s null, authorize %s null): " PACKAGE " " VERSION "\n", + DBG(2, ">> sane_init (version %s null, authorize %s null): " PACKAGE " " VERSION "\n", (vc) ? "!=" : "==", (cb) ? "!=" : "=="); #endif @@ -192,8 +192,8 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) /* just to be extra sure, the line will always have an end: */ line[sizeof(line)-1] = '\0'; - /* - * Read information from config file: pixel weight location and default + /* + * Read information from config file: pixel weight location and default * port. */ if((fp = sanei_config_open(CANONP_CONFIG_FILE))) @@ -208,24 +208,24 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) if(strncmp(line,"calibrate ", 10) == 0) { - /* warning: pointer trickyness ahead + /* warning: pointer trickyness ahead * Do not free tmp_port! */ - DBG(40, "sane_init: calibrate line, %s\n", + 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 + /* 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", + "a port argument.\n", line); /* first_dev should never be null here - * because we found at least one + * because we found at least one * parallel port above */ first_dev->weights_file = tmp_wf; DBG(100, "sane_init: Successfully " @@ -236,7 +236,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) } - /* Now find which scanner wants + /* Now find which scanner wants * this calibration file */ s_tmp = first_dev; DBG(100, "sane_init: Finding scanner on port " @@ -247,7 +247,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) tmp_port+1)) { DBG(100, "sane_init: Found!\n"); - /* Now terminate the weight + /* Now terminate the weight * file string */ *tmp_port = '\0'; s_tmp->weights_file = tmp_wf; @@ -255,7 +255,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) "cal, for port" " '%s', weight" " file is '%s'" - ".\n", + ".\n", s_tmp->params. port->name, tmp_wf); @@ -295,7 +295,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) if(strncmp(line,"init_mode ", 10) == 0) { - /* parse what sort of initialisation mode to + /* parse what sort of initialisation mode to * use */ if (strncmp(line+10, "FB620P", 6) == 0) tmp_im = INITMODE_20P; @@ -311,7 +311,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) if (tmp_port == NULL) { /* first_dev should never be null here - * because we found at least one + * because we found at least one * parallel port above */ first_dev->init_mode = tmp_im; DBG(100, "sane_init: Parsed init-1.\n"); @@ -344,9 +344,9 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) } DBG(1, "sane_init: Unknown configuration command!"); - } + } fclose (fp); - } + } /* There should now be a LL of ports starting at first_dev */ @@ -355,23 +355,23 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) /* 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, + /* 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) + 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, + tmp = sanei_canon_pp_detect(s_tmp->params.port, s_tmp->init_mode); @@ -383,7 +383,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) 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, + tmp = sanei_canon_pp_detect(s_tmp->params.port, s_tmp->init_mode); } /* still no go? */ @@ -395,7 +395,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) 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) { @@ -405,9 +405,9 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) ieee1284_close(s_tmp->params.port); continue; } - + DBG(2, "sane_init: >> initialise\n"); - tmp = sanei_canon_pp_initialise(&(s_tmp->params), + tmp = sanei_canon_pp_initialise(&(s_tmp->params), s_tmp->init_mode); DBG(2, "sane_init: << %d initialise\n", tmp); if (tmp) { @@ -420,13 +420,13 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) continue; } - /* put it back to sleep until we're ready to + /* put it back to sleep until we're ready to * open for business again - this will only work * if we actually have a scanner there! */ DBG(100, "sane_init: And back to sleep again\n"); sanei_canon_pp_sleep_scanner(s_tmp->params.port); - /* leave the port open but not claimed - this is regardless + /* leave the port open but not claimed - this is regardless * of the return value of initialise */ ieee1284_release(s_tmp->params.port); @@ -435,7 +435,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) if (fix_weights_file(s_tmp) != SANE_STATUS_GOOD) { DBG(1, "sane_init: Eeek! fix_weights_file failed for " - "scanner on port %s!\n", + "scanner on port %s!\n", s_tmp->params.port->name); /* non-fatal.. scans will look ugly as sin unless * they calibrate */ @@ -462,7 +462,7 @@ sane_init (SANE_Int *vc, SANE_Auth_Callback cb) *************************************************************************/ SANE_Status sane_get_devices (const SANE_Device ***dl, SANE_Bool local) -{ +{ static const SANE_Device **devlist; CANONP_Scanner *dev; int i; @@ -521,7 +521,7 @@ sane_open (SANE_String_Const name, SANE_Handle *h) DBG(2, ">> sane_open (h=%p, name=\"%s\")\n", (void *)h, name); - if ((h == NULL) || (name == NULL)) + if ((h == NULL) || (name == NULL)) { DBG(2,"sane_open: Null pointer received!\n"); return SANE_STATUS_INVAL; @@ -543,12 +543,12 @@ sane_open (SANE_String_Const name, SANE_Handle *h) 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 + /* 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) && + while((cs != NULL) && (cs->scanner_present == SANE_FALSE)) cs = cs->next; } @@ -563,7 +563,7 @@ sane_open (SANE_String_Const name, SANE_Handle *h) } - if (cs == NULL) + if (cs == NULL) { DBG(2,"sane_open: No scanner found or requested port " "doesn't exist (%s)\n", name); @@ -575,15 +575,15 @@ sane_open (SANE_String_Const name, SANE_Handle *h) "(%s)\n", name); return SANE_STATUS_IO_ERROR; } - if (cs->opened == SANE_TRUE) + 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 + /* If the scanner has already been opened once, we don't have to do * this setup again */ - if (cs->setup == SANE_TRUE) + if (cs->setup == SANE_TRUE) { cs->opened = SANE_TRUE; *h = (SANE_Handle)cs; @@ -613,11 +613,11 @@ sane_open (SANE_String_Const name, SANE_Handle *h) } if (cs->weights_file != NULL) - DBG(2, "sane_open: >> load_weights(%s, %p)\n", - cs->weights_file, + DBG(2, "sane_open: >> load_weights(%s, %p)\n", + cs->weights_file, (const void *)(&(cs->params))); else - DBG(2, "sane_open: >> load_weights(NULL, %p)\n", + DBG(2, "sane_open: >> load_weights(NULL, %p)\n", (const void *)(&(cs->params))); tmp = sanei_canon_pp_load_weights(cs->weights_file, &(cs->params)); DBG(2, "sane_open: << %d load_weights\n", tmp); @@ -638,10 +638,10 @@ sane_open (SANE_String_Const name, SANE_Handle *h) DBG(1, "sane_open: WARNING: adjust_gamma returned " "%d!\n", tmp); - DBG(10, "sane_open: after adjust_gamma Status = %i\n", + DBG(10, "sane_open: after adjust_gamma Status = %i\n", sanei_canon_pp_check_status(cs->params.port)); } - + /* Configure ranges etc */ @@ -744,11 +744,11 @@ sane_control_option (SANE_Handle h, SANE_Int opt, SANE_Action act, 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 + 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.. + 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! " @@ -757,7 +757,7 @@ sane_control_option (SANE_Handle h, SANE_Int opt, SANE_Action act, return SANE_STATUS_INVAL; } - if (((unsigned)opt) >= NUM_OPTIONS) + if (((unsigned)opt) >= NUM_OPTIONS) { DBG(1,"sane_control_option: I don't do option %d.\n", opt); return SANE_STATUS_INVAL; @@ -777,17 +777,17 @@ sane_control_option (SANE_Handle h, SANE_Int opt, SANE_Action act, return SANE_STATUS_DEVICE_BUSY; } - switch(act) + switch(act) { case SANE_ACTION_GET_VALUE: - switch (opt) + switch (opt) { case OPT_COLOUR_MODE: - strcpy((char *)val, + strcpy((char *)val, cmodes[cs->vals[opt]]); break; case OPT_DEPTH: - strcpy((char *)val, + strcpy((char *)val, depths[cs->vals[opt]]); break; case OPT_RESOLUTION: @@ -812,40 +812,40 @@ sane_control_option (SANE_Handle h, SANE_Int opt, SANE_Action act, maxresi = cs->opt[OPT_RESOLUTION]. constraint.word_list[0]; - while ((cs->vals[opt] <= maxresi) && + while ((cs->vals[opt] <= maxresi) && (res600[cs->vals[opt]] < *((int *)val))) { cs->vals[opt] += 1; } - if (res600[cs->vals[opt]] != + if (res600[cs->vals[opt]] != *((int *)val)) { - if (info != NULL) *info |= + 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]], + && strcmp(cmodes[cs->vals[opt]], (char *)val)) { cs->vals[opt] += 1; } - if (info != NULL) *info |= + 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]], + && strcmp(depths[cs->vals[opt]], (char *)val)) { cs->vals[opt] += 1; } - if (info != NULL) *info |= + if (info != NULL) *info |= SANE_INFO_RELOAD_PARAMS; break; case OPT_TL_X: @@ -861,34 +861,34 @@ sane_control_option (SANE_Handle h, SANE_Int opt, SANE_Action act, if ((cs->weights_file==NULL) || cs->cal_readonly ) - DBG(2, ">> calibrate(x, " + DBG(2, ">> calibrate(x, " "NULL)\n"); else DBG(2, ">> calibrate(x," "%s)\n", cs->weights_file); - if (cs->cal_readonly) tmp = + if (cs->cal_readonly) tmp = sanei_canon_pp_calibrate( - &(cs->params), + &(cs->params), NULL); else tmp = sanei_canon_pp_calibrate( - &(cs->params), + &(cs->params), cs->weights_file); - DBG(2, "<< %d calibrate\n", + DBG(2, "<< %d calibrate\n", tmp); if (tmp != 0) { DBG(1, "sane_control_option: " "WARNING: " "calibrate " - "returned %d!", + "returned %d!", tmp); - cs->cal_valid = + cs->cal_valid = SANE_FALSE; return SANE_STATUS_IO_ERROR; } else { - cs->cal_valid = + cs->cal_valid = SANE_TRUE; } @@ -930,7 +930,7 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params) { int res, max_width, max_height, max_res; CANONP_Scanner *cs = ((CANONP_Scanner *)h); - DBG(2, ">> sane_get_parameters (h=%p, params=%p)\n", (void*)h, + DBG(2, ">> sane_get_parameters (h=%p, params=%p)\n", (void*)h, (void*)params); if (h == NULL) return SANE_STATUS_INVAL; @@ -946,16 +946,16 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params) * version, so this will always work. */ res = res600[cs->vals[OPT_RESOLUTION]]; - /* - * These don't change whether we're scanning or not + /* + * These don't change whether we're scanning or not * NOTE: Assumes options don't change after scanning commences, which * is part of the standard */ /* Copy the options stored in the vals into the scaninfo */ - params->pixels_per_line = + params->pixels_per_line = ((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) * res) / MM_PER_IN; - params->lines = ((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) * res) + params->lines = ((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) * res) / MM_PER_IN; /* FIXME: Magic numbers ahead! */ @@ -970,17 +970,17 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params) max_width = cs->params.scanheadwidth / (max_res / res); - max_height = (cs->params.scanheadwidth == 2552 ? 3508 : 7016) / + max_height = (cs->params.scanheadwidth == 2552 ? 3508 : 7016) / (max_res / res); - if(params->pixels_per_line > max_width) + if(params->pixels_per_line > max_width) params->pixels_per_line = max_width; if(params->lines > max_height) params->lines = max_height; params->depth = cs->vals[OPT_DEPTH] ? 16 : 8; - switch (cs->vals[OPT_COLOUR_MODE]) + switch (cs->vals[OPT_COLOUR_MODE]) { case 0: params->format = SANE_FRAME_GRAY; @@ -997,7 +997,7 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params) if (!(params->pixels_per_line)) { params->last_frame = SANE_TRUE; params->lines = 0; - } + } /* Always the "last frame" */ params->last_frame = SANE_TRUE; @@ -1009,7 +1009,7 @@ sane_get_parameters (SANE_Handle h, SANE_Parameters *params) "max_res=%d, res=%d, max_height=%d, br_y=%d, tl_y=%d, " "mm_per_in=%f\n", params->bytes_per_line, params->pixels_per_line, params->lines, - max_res, res, max_height, cs->vals[OPT_BR_Y], + max_res, res, max_height, cs->vals[OPT_BR_Y], cs->vals[OPT_TL_Y], MM_PER_IN); DBG(2, "<< sane_get_parameters\n"); @@ -1047,18 +1047,18 @@ sane_start (SANE_Handle h) res = res600[cs->vals[OPT_RESOLUTION]]; /* Copy the options stored in the vals into the scaninfo */ - cs->scan.width = ((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) * res) + cs->scan.width = ((cs->vals[OPT_BR_X] - cs->vals[OPT_TL_X]) * res) / MM_PER_IN; - cs->scan.height = ((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) * res) + cs->scan.height = ((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) * res) / MM_PER_IN; cs->scan.xoffset = (cs->vals[OPT_TL_X] * res) / MM_PER_IN; cs->scan.yoffset = (cs->vals[OPT_TL_Y] * res) / MM_PER_IN; - /* - * These values have to pass the requirements of not exceeding - * dimensions (simple clipping) and both width values have to be some - * integer multiple of 4 + /* + * These values have to pass the requirements of not exceeding + * dimensions (simple clipping) and both width values have to be some + * integer multiple of 4 */ /* FIXME: Magic numbers ahead! */ @@ -1074,11 +1074,11 @@ sane_start (SANE_Handle h) max_width = cs->params.scanheadwidth / (max_res / res); - max_height = (cs->params.scanheadwidth == 2552 ? 3508 : 7016) / + max_height = (cs->params.scanheadwidth == 2552 ? 3508 : 7016) / (max_res / res); if (cs->scan.width > max_width) cs->scan.width = max_width; - if (cs->scan.width + cs->scan.xoffset > max_width) cs->scan.xoffset = + if (cs->scan.width + cs->scan.xoffset > max_width) cs->scan.xoffset = max_width - cs->scan.width; if (cs->scan.height > max_height) cs->scan.height = max_height; @@ -1104,7 +1104,7 @@ sane_start (SANE_Handle h) cs->scan.xresolution = i; cs->scan.yresolution = i; - if (((cs->vals[OPT_BR_Y] - cs->vals[OPT_TL_Y]) <= 0) || + 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. " @@ -1156,26 +1156,26 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) static SANE_Byte *lbuf; static unsigned int bytesleft; - DBG(2, ">> sane_read (h=%p, buf=%p, maxlen=%d)\n", h, + DBG(2, ">> sane_read (h=%p, buf=%p, maxlen=%d)\n", h, (const void *)buf, maxlen); /* default to returning 0 - for errors */ *lenp = 0; - if ((h == NULL) || (buf == NULL) || (lenp == NULL)) + 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=%p, buf=%p, lenp=%p)\n", (void*)h, (void*)buf, (void*)lenp); return SANE_STATUS_INVAL; } /* Now we have to see if we have some leftover from last time */ - if (read_leftover != NULL) + 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, + /* 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 */ DBG(200, "sane_read: didn't send it all last time\n"); @@ -1204,11 +1204,11 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) return SANE_STATUS_GOOD; } - } + } /* Has the last scan ended (other than by cancelling)? */ - if (((unsigned)cs->scan.height <= (unsigned)cs->lines_scanned) + if (((unsigned)cs->scan.height <= (unsigned)cs->lines_scanned) || (cs->sent_eof) || !(cs->scanning)) { cs->sent_eof = SANE_TRUE; @@ -1220,7 +1220,7 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) return SANE_STATUS_EOF; } - /* At this point we have to read more data from the scanner - or the + /* At this point we have to read more data from the scanner - or the * scan has been cancelled, which means we have to call read_segment * to leave the scanner consistant */ @@ -1230,17 +1230,17 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) else bpl = cs->scan.width * (cs->vals[OPT_COLOUR_MODE] ? 6 : 2); - /* New way: scan a whole scanner buffer full, and return as much as - * the frontend wants. It's faster and more reliable since the + /* New way: scan a whole scanner buffer full, and return as much as + * the frontend wants. It's faster and more reliable since the * scanners crack the shits if we ask for too many small packets */ lines = (BUF_MAX * 4 / 5) / bpl; - if (lines > (cs->scan.height - cs->lines_scanned)) + if (lines > (cs->scan.height - cs->lines_scanned)) lines = cs->scan.height - cs->lines_scanned; if (!lines) { - /* can't fit a whole line into the buffer + /* can't fit a whole line into the buffer * (should never happen!) */ lines = 1; } @@ -1268,16 +1268,16 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) DBG(10, "scan_params->: width=%d, height=%d, xoffset=%d, " "yoffset=%d\n\txresolution=%d, yresolution=%d, " "mode=%d, (lines=%d)\n", - cs->scan.width, cs->scan.height, + cs->scan.width, cs->scan.height, cs->scan.xoffset, cs->scan.yoffset, cs->scan.xresolution, cs->scan.yresolution, cs->scan.mode, lines); DBG(2, ">> read_segment(x, x, x, %d, %d, %d)\n", - lines, cs->cal_valid, + lines, cs->cal_valid, cs->scan.height - cs->lines_scanned); - tmp = sanei_canon_pp_read_segment(&is, &(cs->params), &(cs->scan), - lines, cs->cal_valid, + tmp = sanei_canon_pp_read_segment(&is, &(cs->params), &(cs->scan), + lines, cs->cal_valid, cs->scan.height - cs->lines_scanned); DBG(2, "<< %d read_segment\n", tmp); @@ -1361,7 +1361,7 @@ sane_read (SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) if ((unsigned)cs->lines_scanned >= cs->scan.height) { - /* The scan is over! Don't need to call anything in the + /* 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; @@ -1392,7 +1392,7 @@ sane_cancel (SANE_Handle h) read_leftover = NULL; - if (!(cs->scanning)) + if (!(cs->scanning)) { DBG(2, "<< sane_cancel (not scanning)\n"); return; @@ -1431,7 +1431,7 @@ sane_close (SANE_Handle h) 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; @@ -1461,9 +1461,9 @@ sane_exit (void) 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 + * 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 */ @@ -1513,17 +1513,17 @@ sane_exit (void) * (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 + * NOTE: The device is not ready to scan until initialise() has been * called in scan library! * *************************************************************************/ -static SANE_Status init_device(struct parport *pp) +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_NUM_OPTIONS, SANE_NAME_SCAN_RESOLUTION, SANE_NAME_SCAN_MODE, SANE_NAME_BIT_DEPTH, @@ -1539,7 +1539,7 @@ static SANE_Status init_device(struct parport *pp) #endif }; static const char *opt_titles[] = { - SANE_TITLE_NUM_OPTIONS, + SANE_TITLE_NUM_OPTIONS, SANE_TITLE_SCAN_RESOLUTION, SANE_TITLE_SCAN_MODE, SANE_TITLE_BIT_DEPTH, @@ -1555,7 +1555,7 @@ static SANE_Status init_device(struct parport *pp) #endif }; static const char *opt_descs[] = { - SANE_DESC_NUM_OPTIONS, + SANE_DESC_NUM_OPTIONS, SANE_DESC_SCAN_RESOLUTION, SANE_DESC_SCAN_MODE, SANE_DESC_BIT_DEPTH, @@ -1583,7 +1583,7 @@ static SANE_Status init_device(struct parport *pp) memset(cs, 0, sizeof(*cs)); #if 0 - if ((cs->params.port = malloc(sizeof(*(cs->params.port)))) == NULL) + if ((cs->params.port = malloc(sizeof(*(cs->params.port)))) == NULL) return SANE_STATUS_NO_MEM; memcpy(cs->params.port, pp, sizeof(*pp)); @@ -1637,7 +1637,7 @@ static SANE_Status init_device(struct parport *pp) 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; + cs->vals[OPT_RESOLUTION] = 1; DBG(100, "init_device: configuring opt: colour mode\n"); @@ -1689,8 +1689,8 @@ static SANE_Status init_device(struct parport *pp) /* 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 (cs->cal_readonly) + cs->opt[OPT_CAL].cap |= SANE_CAP_INACTIVE; #if 0 /* the gamma values (once we do them) */ @@ -1700,8 +1700,8 @@ static SANE_Status init_device(struct parport *pp) #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 + * 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"); @@ -1720,7 +1720,7 @@ static SANE_Status init_device(struct parport *pp) /************************************************************************* * - * These two are optional ones... maybe if I get really keen? + * These two are optional ones... maybe if I get really keen? * *************************************************************************/ SANE_Status @@ -1739,7 +1739,7 @@ sane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking) SANE_Status sane_get_select_fd (SANE_Handle h, SANE_Int *fdp) { - DBG(2, ">> sane_get_select_fd (%p, %p) (not supported)\n", h, + DBG(2, ">> sane_get_select_fd (%p, %p) (not supported)\n", h, (const void *)fdp); DBG(2, "<< sane_get_select_fd\n"); return SANE_STATUS_UNSUPPORTED; @@ -1762,7 +1762,7 @@ static int init_cal(char *file) if (errno == ENOENT) { /* we need to try and make ~/.sane perhaps - - * find the last / in the file path, and try + * find the last / in the file path, and try * to create it */ if ((tmp = strrchr(file, '/')) == NULL) return -1; @@ -1775,9 +1775,9 @@ static int init_cal(char *file) if ((f = open(file, O_CREAT | O_WRONLY, 0600)) < 0) return -1; } - else + else { - /* Error is something like access denied - too + /* Error is something like access denied - too * hard to fix, so i give up... */ return -1; } @@ -1789,7 +1789,7 @@ static int init_cal(char *file) /************************************************************************* * - * fix_weights_file(): Ensures that the weights_file setting for a given + * fix_weights_file(): Ensures that the weights_file setting for a given * scanner is valid * ************************************************************************/ @@ -1821,7 +1821,7 @@ static SANE_Status fix_weights_file(CANONP_Scanner *cs) /* Get the user's home dir if they used ~ */ if (cs->weights_file[0] == '~') { - if ((tmp = malloc(PATH_MAX)) == NULL) + if ((tmp = malloc(PATH_MAX)) == NULL) return SANE_STATUS_NO_MEM; if ((myhome = getenv("HOME")) == NULL) { @@ -1832,7 +1832,7 @@ static SANE_Status fix_weights_file(CANONP_Scanner *cs) return SANE_STATUS_INVAL; } strncpy(tmp, myhome, PATH_MAX); - strncpy(tmp+strlen(tmp), (cs->weights_file)+1, + strncpy(tmp+strlen(tmp), (cs->weights_file)+1, PATH_MAX-strlen(tmp)); free(cs->weights_file); @@ -1869,8 +1869,8 @@ static SANE_Status fix_weights_file(CANONP_Scanner *cs) i = open(cs->weights_file, O_RDONLY); if (i <= 0) { - /* - * Open failed (do i care why?) + /* + * Open failed (do i care why?) */ DBG(2,"fix_weights_file: error opening cal " "(%s)\n", strerror(errno)); @@ -1904,10 +1904,10 @@ static SANE_Status fix_weights_file(CANONP_Scanner *cs) * PRE: * cs->params.port is not open * POST: - * cs->params.port is left opened iff SANE_STATUS_GOOD returned. + * cs->params.port is left opened iff SANE_STATUS_GOOD returned. */ -SANE_Status detect_mode(CANONP_Scanner *cs) +SANE_Status detect_mode(CANONP_Scanner *cs) { int capabilities, tmp; @@ -1925,7 +1925,7 @@ SANE_Status detect_mode(CANONP_Scanner *cs) DBG(1, "detect_mode: Invalid port.\n"); break; case E1284_SYS: - DBG(1, "detect_mode: System error: %s\n", + DBG(1, "detect_mode: System error: %s\n", strerror(errno)); break; case E1284_INIT: @@ -1973,7 +1973,7 @@ SANE_Status detect_mode(CANONP_Scanner *cs) { cs->ieee1284_mode = M1284_ECP; DBG(10, "detect_mode: Using ECP-H Mode\n"); - } + } else if (capabilities & CAP1284_ECPSWE) { cs->ieee1284_mode = M1284_ECPSWE; @@ -1993,11 +1993,11 @@ SANE_Status detect_mode(CANONP_Scanner *cs) } /* Check to make sure ECP mode really is supported */ - /* Have disabled the hardware ECP check because it's always supported - * by libieee1284 now, and it's too prone to hitting a ppdev bug + /* Have disabled the hardware ECP check because it's always supported + * by libieee1284 now, and it's too prone to hitting a ppdev bug */ - /* Disabled check entirely.. check now in initialise when we + /* Disabled check entirely.. check now in initialise when we * actually do a read */ #if 0 if ((cs->ieee1284_mode == M1284_ECP) || @@ -2005,17 +2005,17 @@ SANE_Status detect_mode(CANONP_Scanner *cs) { DBG(1, "detect_mode: attempting a 0 byte read, if we hang " "here, it's a ppdev bug!\n"); - /* - * 29/06/02 + /* + * 29/06/02 * NOTE: - * This causes an infinite loop in ppdev on 2.4.18. - * Not checking on hardware ECP mode should work-around + * This causes an infinite loop in ppdev on 2.4.18. + * Not checking on hardware ECP mode should work-around * effectively. * - * I have sent email to twaugh about it, should be fixed in + * I have sent email to twaugh about it, should be fixed in * 2.4.19 and above. */ - if (ieee1284_ecp_read_data(cs->params.port, 0, NULL, 0) == + if (ieee1284_ecp_read_data(cs->params.port, 0, NULL, 0) == E1284_NOTIMPL) { DBG(10, "detect_mode: Your version of libieee1284 " diff --git a/backend/canon_pp.conf.in b/backend/canon_pp.conf.in index 14b3110..c12d763 100644 --- a/backend/canon_pp.conf.in +++ b/backend/canon_pp.conf.in @@ -1,4 +1,4 @@ -# Define which port to use if one isn't specified - you should only have +# Define which port to use if one isn't specified - you should only have # one of these lines! # This is the default port to be used - others will be detected ieee1284 parport0 @@ -21,7 +21,7 @@ calibrate ~/.sane/canon_pp-calibration-pp0 parport0 # calibrate /etc/sane/my_calibration parport1 -# Enable the next line if you're having trouble with ECP mode such as I/O +# Enable the next line if you're having trouble with ECP mode such as I/O # errors. Nibble mode is slower, but more reliable. #force_nibble diff --git a/backend/canon_pp.h b/backend/canon_pp.h index 4797924..2dfee98 100644 --- a/backend/canon_pp.h +++ b/backend/canon_pp.h @@ -42,7 +42,7 @@ canon_pp.h: $Revision$ - This file is part of the canon_pp backend, supporting Canon FBX30P + This file is part of the canon_pp backend, supporting Canon FBX30P and NX40P scanners */ @@ -69,7 +69,7 @@ #define CANONP_CONFIG_FILE "canon_pp.conf" /* options: num,res,colour,depth,tl-x,tl-y,br-x,br-y,cal */ /* preview option disabled */ -#define NUM_OPTIONS 9 +#define NUM_OPTIONS 9 #define BUF_MAX 64000 /* Indexes into options array */ @@ -122,4 +122,3 @@ struct CANONP_Scanner_Struct #endif - diff --git a/backend/cardscan.c b/backend/cardscan.c index eab6500..ec776d1 100644 --- a/backend/cardscan.c +++ b/backend/cardscan.c @@ -199,7 +199,7 @@ four times { . . - sane_start() : start image acquisition . . - sane_get_parameters() : returns actual scan parameters . . - sane_read() : read image data (from pipe) - . . (sane_read called multiple times; after sane_read returns EOF, + . . (sane_read called multiple times; after sane_read returns EOF, . . loop may continue with sane_start which may return a 2nd page . . when doing duplex scans, or load the next page from the ADF) . . @@ -226,14 +226,14 @@ four times { #include "cardscan.h" #define DEBUG 1 -#define BUILD 3 +#define BUILD 3 /* values for SANE_DEBUG_CARDSCAN env var: - errors 5 - function trace 10 - function detail 15 - get/setopt cmds 20 - - usb cmd trace 25 + - usb cmd trace 25 - usb cmd detail 30 - useless noise 35 */ @@ -259,7 +259,7 @@ static struct scanner *scanner_devList = NULL; /* * Called by SANE initially. - * + * * From the SANE spec: * This function must be called before any other SANE function can be * called. The behavior of a SANE backend is undefined if this @@ -274,26 +274,26 @@ SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { authorize = authorize; /* get rid of compiler warning */ - + DBG_INIT (); DBG (10, "sane_init: start\n"); - + sanei_usb_init(); - + if (version_code) *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD); - + DBG (5, "sane_init: cardscan backend %d.%d.%d, from %s\n", SANE_CURRENT_MAJOR, V_MINOR, BUILD, PACKAGE_STRING); - + DBG (10, "sane_init: finish\n"); - + return SANE_STATUS_GOOD; } /* * Called by SANE to find out about supported devices. - * + * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a @@ -306,7 +306,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. - * + * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and @@ -324,64 +324,64 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) FILE *fp; int num_devices=0; int i=0; - + local_only = local_only; /* get rid of compiler warning */ - + DBG (10, "sane_get_devices: start\n"); - + global_has_cal_buffer = 1; global_lines_per_block = 16; fp = sanei_config_open (CONFIG_FILE); - + if (fp) { - + DBG (15, "sane_get_devices: reading config file %s\n", CONFIG_FILE); - + while (sanei_config_read (line, PATH_MAX, fp)) { - + lp = line; /* ignore comments */ if (*lp == '#') continue; - + /* skip empty lines */ if (*lp == 0) continue; - + if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) { DBG (15, "sane_get_devices: looking for '%s'\n", lp); sanei_usb_attach_matching_devices(lp, attach_one); } else if (!strncmp(lp, "has_cal_buffer", 14) && isspace (lp[14])) { - + int buf; lp += 14; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - + if(buf){ global_has_cal_buffer = 1; } else{ global_has_cal_buffer = 0; } - + DBG (15, "sane_get_devices: setting \"has_cal_buffer\" to %d\n", global_has_cal_buffer); } else if (!strncmp(lp, "lines_per_block", 15) && isspace (lp[15])) { - + int buf; lp += 15; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - + if(buf < 1 || buf > 32){ - DBG (15, + DBG (15, "sane_get_devices: \"lines_per_block\"=%d\n out of range", buf ); @@ -398,42 +398,42 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) } fclose (fp); } - + else { DBG (5, "sane_get_devices: no config file '%s', using defaults\n", CONFIG_FILE); - + DBG (15, "sane_get_devices: looking for 'usb 0x08F0 0x0005'\n"); sanei_usb_attach_matching_devices("usb 0x08F0 0x0005", attach_one); } - + for (dev = scanner_devList; dev; dev=dev->next) { DBG (15, "sane_get_devices: found scanner %s\n",dev->device_name); num_devices++; } - + DBG (15, "sane_get_devices: found %d scanner(s)\n",num_devices); - + sane_devArray = calloc (num_devices + 1, sizeof (SANE_Device*)); if (!sane_devArray) return SANE_STATUS_NO_MEM; - + for (dev = scanner_devList; dev; dev=dev->next) { sane_devArray[i++] = (SANE_Device *)&dev->sane; } - + sane_devArray[i] = 0; - + *device_list = sane_devArray; - + DBG (10, "sane_get_devices: finish\n"); - + return SANE_STATUS_GOOD; } /* callback used by sane_get_devices - * build the scanner struct and link to global list - * unless struct is already loaded, then pretend + * build the scanner struct and link to global list + * unless struct is already loaded, then pretend */ static SANE_Status attach_one (const char *device_name) @@ -441,32 +441,32 @@ attach_one (const char *device_name) struct scanner *s; int ret, i; SANE_Word vid, pid; - + DBG (10, "attach_one: start '%s'\n", device_name); - + for (s = scanner_devList; s; s = s->next) { if (strcmp (s->sane.name, device_name) == 0) { DBG (10, "attach_one: already attached!\n"); return SANE_STATUS_GOOD; } } - + /* build a scanner struct to hold it */ DBG (15, "attach_one: init struct\n"); - + if ((s = calloc (sizeof (*s), 1)) == NULL) return SANE_STATUS_NO_MEM; - + /* copy the device name */ s->device_name = strdup (device_name); if (!s->device_name){ free (s); return SANE_STATUS_NO_MEM; } - + /* connect the fd */ DBG (15, "attach_one: connect fd\n"); - + s->fd = -1; ret = connect_fd(s); if(ret != SANE_STATUS_GOOD){ @@ -474,11 +474,11 @@ attach_one (const char *device_name) free (s); return ret; } - + /* clean up the scanner struct based on model */ /* this is the only piece of model specific code */ sanei_usb_get_vendor_product(s->fd,&vid,&pid); - + if(vid == 0x08f0){ s->vendor_name = "CardScan"; if(pid == 0x0005){ @@ -507,10 +507,10 @@ attach_one (const char *device_name) s->vendor_name = "Unknown"; s->product_name = "Unknown"; } - + DBG (15, "attach_one: Found %s scanner %s at %s\n", s->vendor_name, s->product_name, s->device_name); - + /*copy config file settings*/ s->has_cal_buffer = global_has_cal_buffer; s->lines_per_block = global_lines_per_block; @@ -520,7 +520,7 @@ attach_one (const char *device_name) /* try to get calibration */ if(s->has_cal_buffer){ DBG (15, "attach_one: scanner calibration\n"); - + ret = load_calibration(s); if (ret != SANE_STATUS_GOOD) { DBG (5, "sane_start: ERROR: cannot calibrate, incompatible?\n"); @@ -532,13 +532,13 @@ attach_one (const char *device_name) else{ DBG (15, "attach_one: skipping calibration\n"); } - + /* set SANE option 'values' to good defaults */ DBG (15, "attach_one: init options\n"); - - /* go ahead and setup the first opt, because - * frontend may call control_option on it - * before calling get_option_descriptor + + /* go ahead and setup the first opt, because + * frontend may call control_option on it + * before calling get_option_descriptor */ memset (s->opt, 0, sizeof (s->opt)); for (i = 0; i < NUM_OPTIONS; ++i) { @@ -546,29 +546,29 @@ attach_one (const char *device_name) s->opt[i].size = sizeof (SANE_Word); s->opt[i].cap = SANE_CAP_INACTIVE; } - + s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; - + DBG (15, "attach_one: init settings\n"); - + /* we close the connection, so that another backend can talk to scanner */ disconnect_fd(s); - + /* load info into sane_device struct */ s->sane.name = s->device_name; s->sane.vendor = s->vendor_name; s->sane.model = s->product_name; s->sane.type = "scanner"; - + s->next = scanner_devList; scanner_devList = s; - + DBG (10, "attach_one: finish\n"); - + return SANE_STATUS_GOOD; } @@ -579,9 +579,9 @@ static SANE_Status connect_fd (struct scanner *s) { SANE_Status ret; - + DBG (10, "connect_fd: start\n"); - + if(s->fd > -1){ DBG (5, "connect_fd: already open\n"); ret = SANE_STATUS_GOOD; @@ -590,13 +590,13 @@ connect_fd (struct scanner *s) DBG (15, "connect_fd: opening USB device\n"); ret = sanei_usb_open (s->device_name, &(s->fd)); } - + if(ret != SANE_STATUS_GOOD){ DBG (5, "connect_fd: could not open device: %d\n", ret); } - + DBG (10, "connect_fd: finish\n"); - + return ret; } @@ -608,25 +608,25 @@ load_calibration(struct scanner *s) unsigned char * buf; size_t bytes = HEADER_SIZE + CAL_COLOR_SIZE*2 + CAL_GRAY_SIZE*2; int j; - + DBG (10, "load_calibration: start\n"); - + buf = malloc(bytes); if(!buf){ DBG(5, "load_calibration: not enough mem for buffer: %ld\n",(long)bytes); return SANE_STATUS_NO_MEM; } - + ret = do_cmd( s, 0, cmd, sizeof(cmd), NULL, 0, buf, &bytes ); - + if (ret == SANE_STATUS_GOOD) { DBG(15, "load_calibration: got GOOD\n"); - + /* * color cal data comes from scaner like: * bbbbbbbBBBBBBBgggggggGGGGGGGrrrrrrrRRRRRRR @@ -634,40 +634,40 @@ load_calibration(struct scanner *s) * reorder the data into two buffers * bbbbbbbgggggggrrrrrrr and BBBBBBBGGGGGGGRRRRRRR */ - + /*dark/light blue*/ memcpy(s->cal_color_b, buf+HEADER_SIZE, PIXELS_PER_LINE); memcpy(s->cal_color_w, buf+HEADER_SIZE+PIXELS_PER_LINE, PIXELS_PER_LINE); - + /*dark/light green*/ memcpy(s->cal_color_b+PIXELS_PER_LINE, buf+HEADER_SIZE+(PIXELS_PER_LINE*2), PIXELS_PER_LINE); memcpy(s->cal_color_w+PIXELS_PER_LINE, buf+HEADER_SIZE+(PIXELS_PER_LINE*3), PIXELS_PER_LINE); - + /*dark/light red*/ memcpy(s->cal_color_b+(PIXELS_PER_LINE*2), buf+HEADER_SIZE+(PIXELS_PER_LINE*4), PIXELS_PER_LINE); memcpy(s->cal_color_w+(PIXELS_PER_LINE*2), buf+HEADER_SIZE+(PIXELS_PER_LINE*5), PIXELS_PER_LINE); - + /* then slide the light data down using the dark offset */ for(j=0;jcal_color_w[j] -= s->cal_color_b[j]; } - + /*dark/light gray*/ memcpy(s->cal_gray_b, buf+HEADER_SIZE+(CAL_COLOR_SIZE*2), PIXELS_PER_LINE); memcpy(s->cal_gray_w, buf+HEADER_SIZE+(CAL_COLOR_SIZE*2)+PIXELS_PER_LINE, PIXELS_PER_LINE); - + /* then slide the light data down using the dark offset */ for(j=0;jcal_gray_w[j] -= s->cal_gray_b[j]; } - + hexdump(35, "cal_color_b:", s->cal_color_b, CAL_COLOR_SIZE); hexdump(35, "cal_color_w:", s->cal_color_w, CAL_COLOR_SIZE); hexdump(35, "cal_gray_b:", s->cal_gray_b, CAL_GRAY_SIZE); @@ -676,9 +676,9 @@ load_calibration(struct scanner *s) else { DBG(5, "load_calibration: error reading data block status = %d\n", ret); } - + DBG (10, "load_calibration: finish\n"); - + return ret; } @@ -697,9 +697,9 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) struct scanner *dev = NULL; struct scanner *s = NULL; SANE_Status ret; - + DBG (10, "sane_open: start\n"); - + if(name[0] == 0){ if(scanner_devList){ DBG (15, "sane_open: no device requested, using first\n"); @@ -725,24 +725,24 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) } } } - + if (!s) { DBG (5, "sane_open: no device found\n"); return SANE_STATUS_INVAL; } - + DBG (15, "sane_open: device %s found\n", s->sane.name); - + *handle = s; - + /* connect the fd so we can talk to scanner */ ret = connect_fd(s); if(ret != SANE_STATUS_GOOD){ return ret; } - + DBG (10, "sane_open: finish\n"); - + return SANE_STATUS_GOOD; } @@ -789,7 +789,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->mode_list[i++]=STRING_GRAYSCALE; s->mode_list[i++]=STRING_COLOR; s->mode_list[i]=NULL; - + opt->name = SANE_NAME_SCAN_MODE; opt->title = SANE_TITLE_SCAN_MODE; opt->desc = SANE_DESC_SCAN_MODE; @@ -805,7 +805,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /** * Gets or sets an option value. - * + * * From the SANE spec: * This function is used to set or inquire the current value of option * number n of the device represented by handle h. The manner in which @@ -816,7 +816,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) * area pointed to by v must be big enough to hold the entire option * value (determined by member size in the corresponding option * descriptor). - * + * * The only exception to this rule is that when setting the value of a * string option, the string pointed to by argument v may be shorter * since the backend will stop reading the option value upon @@ -902,7 +902,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, * below. */ switch (option) { - + /* Mode Group */ case OPT_MODE: if (!strcmp (val, STRING_GRAYSCALE)) { @@ -939,7 +939,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, * completion of that request. Outside of that window, the returned * values are best-effort estimates of what the parameters will be * when sane_start() gets invoked. - * + * * Calling this function before a scan has actually started allows, * for example, to get an estimate of how big the scanned image will * be. The parameters passed to this function are the handle h of the @@ -986,38 +986,38 @@ sane_start (SANE_Handle handle) { struct scanner *s = handle; SANE_Status ret; - + DBG (10, "sane_start: start\n"); - + /* first page of batch */ if(s->started){ DBG(5,"sane_start: previous transfer not finished?"); sane_cancel((SANE_Handle)s); return SANE_STATUS_CANCELLED; } - + /* set clean defaults */ s->started=1; s->bytes_rx=0; s->bytes_tx=0; s->paperless_lines=0; - - /* heat up the lamp */ + + /* heat up the lamp */ if(s->mode == MODE_COLOR){ ret = heat_lamp_color(s); } else{ ret = heat_lamp_gray(s); } - + if (ret != SANE_STATUS_GOOD) { DBG (5, "sane_start: ERROR: failed to heat lamp\n"); sane_cancel((SANE_Handle)s); return ret; } - + DBG (10, "sane_start: finish\n"); - + return SANE_STATUS_GOOD; } @@ -1031,9 +1031,9 @@ heat_lamp_gray(struct scanner *s) size_t bytes = HEADER_SIZE + 1; unsigned char * buf; int i; - + DBG (10, "heat_lamp_gray: start\n"); - + buf = malloc(bytes); if(!buf){ DBG(5, "heat_lamp_gray: not enough mem for buffer: %lu\n", @@ -1042,26 +1042,26 @@ heat_lamp_gray(struct scanner *s) } for(i=0;i<10;i++){ - + ret2 = do_cmd( s, 0, cmd, sizeof(cmd), NULL, 0, buf, &bytes ); - + if (ret2 != SANE_STATUS_GOOD) { DBG(5, "heat_lamp_gray: %d error\n",i); ret = ret2; break; } - + if(!buf[1]){ DBG(5, "heat_lamp_gray: %d got no docs\n",i); ret = SANE_STATUS_NO_DOCS; break; } - + DBG(15, "heat_lamp_gray: %d got: %d %d\n",i, buf[HEADER_SIZE],s->cal_gray_b[0]); @@ -1075,11 +1075,11 @@ heat_lamp_gray(struct scanner *s) ret = SANE_STATUS_DEVICE_BUSY; } } - + free(buf); - + DBG (10, "heat_lamp_gray: finish %d\n",ret); - + return ret; } @@ -1093,9 +1093,9 @@ heat_lamp_color(struct scanner *s) size_t bytes = HEADER_SIZE + 3; unsigned char * buf; int i; - + DBG (10, "heat_lamp_color: start\n"); - + buf = malloc(bytes); if(!buf){ DBG(5, "heat_lamp_color: not enough mem for buffer: %lu\n", @@ -1104,26 +1104,26 @@ heat_lamp_color(struct scanner *s) } for(i=0;i<10;i++){ - + ret2 = do_cmd( s, 0, cmd, sizeof(cmd), NULL, 0, buf, &bytes ); - + if (ret2 != SANE_STATUS_GOOD) { DBG(5, "heat_lamp_color: %d error\n",i); ret = ret2; break; } - + if(!buf[1]){ DBG(5, "heat_lamp_color: %d got no docs\n",i); ret = SANE_STATUS_NO_DOCS; break; } - + DBG(15, "heat_lamp_color: %d got: %d,%d,%d %d,%d,%d\n",i, buf[HEADER_SIZE],buf[HEADER_SIZE+1],buf[HEADER_SIZE+2], s->cal_color_b[0],s->cal_color_b[1],s->cal_color_b[2]); @@ -1140,17 +1140,17 @@ heat_lamp_color(struct scanner *s) ret = SANE_STATUS_DEVICE_BUSY; } } - + free(buf); - + DBG (10, "heat_lamp_color: finish %d\n",ret); - + return ret; } /* * Called by SANE to read data. - * + * * From the SANE spec: * This function is used to read image data from the device * represented by handle h. Argument buf is a pointer to a memory @@ -1158,7 +1158,7 @@ heat_lamp_color(struct scanner *s) * returned is stored in *len. A backend must set this to zero when * the call fails (i.e., when a status other than SANE_STATUS_GOOD is * returned). - * + * * When the call succeeds, the number of bytes returned can be * anywhere in the range from 0 to maxlen bytes. */ @@ -1167,55 +1167,55 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len { struct scanner *s = (struct scanner *) handle; SANE_Status ret=SANE_STATUS_GOOD; - + DBG (10, "sane_read: start\n"); - + *len = 0; - + /* cancelled? */ if(!s->started){ DBG (5, "sane_read: call sane_start first\n"); return SANE_STATUS_CANCELLED; } - + /* have sent all of current buffer */ if(s->bytes_tx == s->bytes_rx){ - + /* at end of data, stop */ if(s->paperless_lines >= MAX_PAPERLESS_LINES){ DBG (15, "sane_read: returning eof\n"); power_down(s); return SANE_STATUS_EOF; } - + /* more to get, reset and go */ s->bytes_tx = 0; s->bytes_rx = 0; - + if(s->mode == MODE_COLOR){ ret = read_from_scanner_color(s); } else{ ret = read_from_scanner_gray(s); } - + if(ret){ DBG(5,"sane_read: returning %d\n",ret); return ret; } } - + /* data in current buffer, send some of it */ *len = s->bytes_rx - s->bytes_tx; if(*len > max_len){ *len = max_len; } - + memcpy(buf,s->buffer+s->bytes_tx,*len); s->bytes_tx += *len; - + DBG (10, "sane_read: %d,%d,%d finish\n", *len,s->bytes_rx,s->bytes_tx); - + return ret; } @@ -1229,9 +1229,9 @@ read_from_scanner_gray(struct scanner *s) size_t bytes = HEADER_SIZE + s->gray_block_size; unsigned char * buf; int i,j; - + DBG (10, "read_from_scanner_gray: start\n"); - + cmd[4] = s->lines_per_block; buf = malloc(bytes); @@ -1240,14 +1240,14 @@ read_from_scanner_gray(struct scanner *s) (long unsigned)bytes); return SANE_STATUS_NO_MEM; } - + ret = do_cmd( s, 0, cmd, sizeof(cmd), NULL, 0, buf, &bytes ); - + if (ret == SANE_STATUS_GOOD) { DBG(15, "read_from_scanner_gray: got GOOD\n"); @@ -1255,19 +1255,19 @@ read_from_scanner_gray(struct scanner *s) if(!buf[1]){ s->paperless_lines += s->lines_per_block; } - + s->bytes_rx = s->gray_block_size; - + /*memcpy(s->buffer,buf+HEADER_SIZE,s->gray_block_size);*/ - + /* reorder the gray data into the struct's buffer */ for(i=0;igray_block_size;i+=PIXELS_PER_LINE){ for(j=0;jcal_gray_b[j]; unsigned char wcal = s->cal_gray_w[j]; - + byte = (byte <= bcal)?0:(byte-bcal); byte = (byte >= wcal)?255:(byte*255/wcal); s->buffer[i+j] = byte; @@ -1277,11 +1277,11 @@ read_from_scanner_gray(struct scanner *s) else { DBG(5, "read_from_scanner_gray: error reading status = %d\n", ret); } - + free(buf); - + DBG (10, "read_from_scanner_gray: finish\n"); - + return ret; } @@ -1294,9 +1294,9 @@ read_from_scanner_color(struct scanner *s) size_t bytes = HEADER_SIZE + s->color_block_size; unsigned char * buf; int i,j,k; - + DBG (10, "read_from_scanner_color: start\n"); - + cmd[4] = s->lines_per_block; buf = malloc(bytes); @@ -1305,14 +1305,14 @@ read_from_scanner_color(struct scanner *s) (long unsigned)bytes); return SANE_STATUS_NO_MEM; } - + ret = do_cmd( s, 0, cmd, sizeof(cmd), NULL, 0, buf, &bytes ); - + if (ret == SANE_STATUS_GOOD) { DBG(15, "read_from_scanner_color: got GOOD\n"); @@ -1320,21 +1320,21 @@ read_from_scanner_color(struct scanner *s) if(!buf[1]){ s->paperless_lines += s->lines_per_block; } - + s->bytes_rx = s->color_block_size; - + /*memcpy(s->buffer,buf+HEADER_SIZE,s->color_block_size);*/ - + /* reorder the color data into the struct's buffer */ for(i=0;icolor_block_size;i+=PIXELS_PER_LINE*3){ for(j=0;jcal_color_b[offset]; unsigned char wcal = s->cal_color_w[offset]; - + byte = (byte <= bcal)?0:(byte-bcal); byte = (byte >= wcal)?255:(byte*255/wcal); s->buffer[i+j*3+k] = byte; @@ -1345,11 +1345,11 @@ read_from_scanner_color(struct scanner *s) else { DBG(5, "read_from_scanner_color: error reading status = %d\n", ret); } - + free(buf); - + DBG (10, "read_from_scanner_color: finish\n"); - + return ret; } @@ -1357,7 +1357,7 @@ read_from_scanner_color(struct scanner *s) * @@ Section 4 - SANE cleanup functions */ /* - * Cancels a scan. + * Cancels a scan. * * From the SANE spec: * This function is used to immediately or as quickly as possible @@ -1393,7 +1393,7 @@ power_down(struct scanner *s) unsigned char buf[6]; size_t bytes = sizeof(buf); int i; - + DBG (10, "power_down: start\n"); for(i=0;i<5;i++){ @@ -1413,9 +1413,9 @@ power_down(struct scanner *s) unsigned char cmd[] = {0x35, 0x01, 0x00, 0xff}; unsigned char buf[5]; size_t bytes = sizeof(buf); - + DBG (10, "power_down: start\n"); - + ret = do_cmd( s, 0, cmd, sizeof(cmd), @@ -1423,15 +1423,15 @@ power_down(struct scanner *s) buf, &bytes ); #endif - + DBG (10, "power_down: finish %d\n",ret); - + return ret; } /* * Ends use of the scanner. - * + * * From the SANE spec: * This function terminates the association between the device handle * passed in argument h and the device it represents. If the device is @@ -1467,7 +1467,7 @@ disconnect_fd (struct scanner *s) /* * Terminates the backend. - * + * * From the SANE spec: * This function must be called to terminate use of a backend. The * function will first close all device handles that still might be diff --git a/backend/cardscan.h b/backend/cardscan.h index a673dc6..56bd08d 100644 --- a/backend/cardscan.h +++ b/backend/cardscan.h @@ -1,12 +1,12 @@ #ifndef CARDSCAN_H #define CARDSCAN_H -/* +/* * Part of SANE - Scanner Access Now Easy. * Please see opening comment in cardscan.c */ -/* ------------------------------------------------------------------------- +/* ------------------------------------------------------------------------- * This option list has to contain all options for all scanners supported by * this driver. If a certain scanner cannot handle a certain option, there's * still the possibility to say so, later. @@ -48,10 +48,10 @@ struct scanner /* --------------------------------------------------------------------- */ /* immutable values which are set during reading of config file. */ - int has_cal_buffer; - int lines_per_block; - int color_block_size; - int gray_block_size; + int has_cal_buffer; + int lines_per_block; + int color_block_size; + int gray_block_size; /* --------------------------------------------------------------------- */ /* changeable SANE_Option structs provide our interface to frontend. */ diff --git a/backend/coolscan-scsidef.h b/backend/coolscan-scsidef.h index 4f1a27e..da7eaa6 100644 --- a/backend/coolscan-scsidef.h +++ b/backend/coolscan-scsidef.h @@ -179,7 +179,7 @@ static scsiblk inquiry = /* ==================================================================== */ /* static unsigned char mode_selectC[] = { - MODE_SELECT, 0x10, 0x00, 0x00, 0x00, 0x00 + MODE_SELECT, 0x10, 0x00, 0x00, 0x00, 0x00 static scsiblk mode_select = { mode_selectC,sizeof(mode_selectC) }; */ @@ -518,7 +518,7 @@ static scsiblk window_descriptor_block = -/* LS-30 has different window-descriptor ! +/* LS-30 has different window-descriptor ! */ static unsigned char window_descriptor_blockC_LS30[] = @@ -529,11 +529,11 @@ static unsigned char window_descriptor_blockC_LS30[] = 0x00, /* 0x00 */ /* Window Identifier */ #define WD_wid_0 0x00 /* Only one supported */ -#define WD_wid_1 0x01 -#define WD_wid_2 0x02 -#define WD_wid_3 0x03 -#define WD_wid_4 0x04 -#define WD_wid_9 0x09 +#define WD_wid_1 0x01 +#define WD_wid_2 0x02 +#define WD_wid_3 0x03 +#define WD_wid_4 0x04 +#define WD_wid_9 0x09 0x00, /* reserved, AUTO */ 0x00, 0x00, /* 0x02 */ @@ -784,7 +784,7 @@ static unsigned char autofocusLS30C[] = static unsigned char autofocuspos[] = { - 0x00, + 0x00, 0x00, 0x00, 0x05, 0x10, /* x-position */ 0x00, 0x00, 0x07, 0x9b, /* y-position */ }; diff --git a/backend/coolscan.c b/backend/coolscan.c index 239b546..4904afc 100644 --- a/backend/coolscan.c +++ b/backend/coolscan.c @@ -35,7 +35,7 @@ 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. @@ -267,10 +267,10 @@ request_sense_parse (unsigned char *sensed_data) return ret; } -/* +/* * wait_scanner should spin until TEST_UNIT_READY returns 0 (GOOD) * returns 0 on success, - * returns -1 on error. + * returns -1 on error. */ static int wait_scanner (Coolscan_t * s) @@ -319,7 +319,7 @@ wait_scanner (Coolscan_t * s) * GOOD * RESERVE UNIT * GOOD - * + * * It is then responsible for installing appropriate signal handlers * to call emergency_give_scanner() if user aborts. */ @@ -331,7 +331,7 @@ coolscan_grab_scanner (Coolscan_t * s) DBG (10, "grabbing scanner\n"); - wait_scanner (s); /* wait for scanner ready, if not print + wait_scanner (s); /* wait for scanner ready, if not print sense and return 1 */ ret = do_scsi_cmd (s->sfd, reserve_unit.cmd, reserve_unit.size, NULL, 0); if (ret) @@ -341,15 +341,15 @@ coolscan_grab_scanner (Coolscan_t * s) return 0; } -/* +/* * Convert a size in ilu to the units expected by the scanner */ static int resDivToVal (int res_div) -{ +{ if (res_div < 1 || res_div > resolution_list[0]) - { + { DBG (1, "Invalid resolution divisor %d \n", res_div); return 2700; } @@ -379,7 +379,7 @@ resValToDiv (int res_val) return res_div; } } -/* +/* * use mode select to force a mesurement divisor of 2700 */ static unsigned char mode_select[] = @@ -414,7 +414,7 @@ coolscan_autofocus_LS30 (Coolscan_t * s) /* Trashes when used in combination with scsi-driver AM53C974.o */ do_scsi_cmd (s->sfd, command_c1.cmd, command_c1.size, NULL, 0); - + DBG (10, "\tWaiting end of Autofocus\n"); wait_scanner (s); DBG (10, "AutoFocused.\n"); @@ -662,7 +662,7 @@ coolscan_set_window_param_LS20 (Coolscan_t * s, int prescan) set_WD_shift_G (buffer_r, s->shift_G); set_WD_shift_B (buffer_r, s->shift_B); - + /* FIXME: LUT-[RGB] */ /* FIXME: stop on/off */ } @@ -738,7 +738,7 @@ coolscan_set_window_param_LS30 (Coolscan_t * s, int wid, int prescan) { set_WD_scanmode_LS30 (buffer_r, WD_Scan); - /* the coolscan LS-30 uses the upper left corner + /* the coolscan LS-30 uses the upper left corner as the origin of coordinates */ /* xmax and ymax are given in 1200 dpi */ set_WD_ULX (buffer_r, s->tlx); @@ -787,11 +787,11 @@ coolscan_set_window_param_LS30 (Coolscan_t * s, int wid, int prescan) set_WD_negative_LS30(buffer_r, s->negative); /* Negative/positive slide */ switch(wid) - { case 1: set_gain_LS30(buffer_r,(s->exposure_R*s->pretv_r)/50); + { case 1: set_gain_LS30(buffer_r,(s->exposure_R*s->pretv_r)/50); break; - case 2: set_gain_LS30(buffer_r,(s->exposure_G*s->pretv_g)/50); + case 2: set_gain_LS30(buffer_r,(s->exposure_G*s->pretv_g)/50); break; - case 3: set_gain_LS30(buffer_r,(s->exposure_B*s->pretv_b)/50); + case 3: set_gain_LS30(buffer_r,(s->exposure_B*s->pretv_b)/50); break; } @@ -837,7 +837,7 @@ coolscan_set_window_param (Coolscan_t * s, int prescan) int ret; ret=0; DBG (10, "set_window_param\n"); - + if(s->LS<2) /* distinquish between old and new scanners */ { ret=coolscan_set_window_param_LS20 (s,prescan); } @@ -847,7 +847,7 @@ coolscan_set_window_param (Coolscan_t * s, int prescan) wait_scanner (s); coolscan_set_window_param_LS30(s,1,prescan); ret=coolscan_set_window_param_LS30(s,2,prescan); - ret=coolscan_set_window_param_LS30(s,3,prescan); + ret=coolscan_set_window_param_LS30(s,3,prescan); if(s->colormode&0x08) { ret=coolscan_set_window_param_LS30(s,9,prescan); } @@ -856,9 +856,9 @@ coolscan_set_window_param (Coolscan_t * s, int prescan) } -/* +/* * The only purpose of get_window is debugging. None of the return parameters - * is currently used. + * is currently used. */ static int coolscan_get_window_param_LS30 (Coolscan_t * s, int wid,int prescanok) @@ -896,11 +896,11 @@ coolscan_get_window_param_LS30 (Coolscan_t * s, int wid,int prescanok) if(prescanok) { switch(wid) - { case 1: s->pretv_r = get_gain_LS30(buf); + { case 1: s->pretv_r = get_gain_LS30(buf); break; - case 2: s->pretv_g = get_gain_LS30(buf); + case 2: s->pretv_g = get_gain_LS30(buf); break; - case 3: s->pretv_b = get_gain_LS30(buf); + case 3: s->pretv_b = get_gain_LS30(buf); break; } } @@ -920,9 +920,9 @@ coolscan_get_window_param_LS30 (Coolscan_t * s, int wid,int prescanok) return 0; } -/* +/* * The only purpose of get_window is debugging. None of the return parameters - * is currently used. + * is currently used. */ static int coolscan_get_window_param_LS20 (Coolscan_t * s) @@ -982,9 +982,9 @@ coolscan_get_window_param_LS20 (Coolscan_t * s) return 0; } -/* +/* * The only purpose of get_window is debugging. None of the return parameters - * is currently used. + * is currently used. */ static int coolscan_get_window_param (Coolscan_t * s, int prescanok) @@ -992,12 +992,12 @@ coolscan_get_window_param (Coolscan_t * s, int prescanok) int ret; DBG (10, "get_window_param\n"); - ret=0; + ret=0; if(s->LS<2) /* distinquish between old and new scanners */ { ret=coolscan_get_window_param_LS20 (s); } else - { + { ret=coolscan_get_window_param_LS30(s,1,prescanok); ret=coolscan_get_window_param_LS30(s,2,prescanok); ret=coolscan_get_window_param_LS30(s,3,prescanok); @@ -1017,24 +1017,24 @@ coolscan_start_scanLS30 (Coolscan_t * s) memcpy (s->buffer, scan.cmd, scan.size); switch(s->colormode) { case RGB: - case GREYSCALE: + case GREYSCALE: channels=s->buffer[4]=0x03; /* window 1 */ s->buffer[6]=0x01; /* window 1 */ s->buffer[7]=0x02; /* window 2 */ - s->buffer[8]=0x03; /* window 3 */ - - break; + s->buffer[8]=0x03; /* window 3 */ + + break; case RGBI: channels=s->buffer[4]=0x04; /* window 1 */ s->buffer[6]=0x01; /* window 1 */ s->buffer[7]=0x02; /* window 2 */ - s->buffer[8]=0x03; /* window 3 */ - s->buffer[9]=0x09; /* window 3 */ - break; + s->buffer[8]=0x03; /* window 3 */ + s->buffer[9]=0x09; /* window 3 */ + break; case IRED: channels=s->buffer[4]=0x01; /* window 1 */ - s->buffer[8]=0x09; /* window 3 */ - break; + s->buffer[8]=0x09; /* window 3 */ + break; } return do_scsi_cmd (s->sfd, s->buffer, scan.size+channels, NULL, 0); @@ -1061,14 +1061,14 @@ prescan (Coolscan_t * s) { coolscan_set_window_param (s, 1); } else - { + { do_scsi_cmd (s->sfd,commande1.cmd,commande1.size,s->buffer,0x0d); wait_scanner (s); wait_scanner (s); coolscan_set_window_param_LS30 (s,1,1); coolscan_set_window_param_LS30 (s,2,1); coolscan_set_window_param_LS30 (s,3,1); - + } ret = coolscan_start_scan(s); @@ -1119,7 +1119,7 @@ do_prescan_now (Coolscan_t * scanner) return SANE_STATUS_DEVICE_BUSY; } - prescan (scanner); + prescan (scanner); if(scanner->LS<2) { get_internal_info(scanner); } @@ -1157,7 +1157,7 @@ send_one_LUT (Coolscan_t * s, SANE_Word * LUT, int reg) gamma = alloca (send.size + s->lutlength*2); memcpy (gamma, send.cmd, send.size); - if(s->LS<2) + if(s->LS<2) { gamma_p = &gamma[send.size]; for (i = 0; i < s->lutlength; i++) { @@ -1166,45 +1166,45 @@ send_one_LUT (Coolscan_t * s, SANE_Word * LUT, int reg) *gamma_p++ = (unsigned char) LUT[i]; } } - else if(s->LS==2) + else if(s->LS==2) { gamma_s = (unsigned short*)( &gamma[send.size]); for (i = 0; i < s->lutlength; i++) { if(s->negative) { - lutval=(unsigned short)(LUT[(s->lutlength-i)]); + lutval=(unsigned short)(LUT[(s->lutlength-i)]); } - else + else { - lutval=(unsigned short)(LUT[i]); - } + lutval=(unsigned short)(LUT[i]); + } if (LUT[i] >= s->max_lut_val) LUT[i] = s->max_lut_val-1; /* broken gtk */ if(s->low_byte_first) /* if on little endian machine: */ { - lutval=((lutval&0x00ff)<<8)+((lutval&0xff00)>>8); /* inverse byteorder */ + lutval=((lutval&0x00ff)<<8)+((lutval&0xff00)>>8); /* inverse byteorder */ } - *gamma_s++ = lutval; + *gamma_s++ = lutval; } } - else if(s->LS==3) + else if(s->LS==3) { gamma_s = (unsigned short*)( &gamma[send.size]); for (i = 0; i < s->lutlength; i++) { if(s->negative) { - lutval=(unsigned short)(LUT[s->lutlength-i]); + lutval=(unsigned short)(LUT[s->lutlength-i]); } - else + else { - lutval=(unsigned short)(LUT[i]); - } + lutval=(unsigned short)(LUT[i]); + } if (LUT[i] >= s->max_lut_val) LUT[i] = s->max_lut_val-1; /* broken gtk */ if(s->low_byte_first) /* if on little endian machine: */ - { lutval=((lutval&0x00ff)<<8)+((lutval&0xff00)>>8); /* inverse byteorder */ + { lutval=((lutval&0x00ff)<<8)+((lutval&0xff00)>>8); /* inverse byteorder */ } - *gamma_s++ = lutval; + *gamma_s++ = lutval; } } return do_scsi_cmd (s->sfd, gamma, send.size + s->lutlength*bytesperval, NULL, 0); @@ -1223,7 +1223,7 @@ send_LUT (Coolscan_t * s) send_one_LUT (s, s->gamma, S_DQ_Reg3); if(s->colormode&0x08) { send_one_LUT (s, s->gamma, S_DQ_Reg9); - } + } } } @@ -1234,7 +1234,7 @@ send_LUT (Coolscan_t * s) send_one_LUT (s, s->gamma_b, S_DQ_Reg3); if(s->colormode&0x08) { send_one_LUT (s, s->gamma_r, S_DQ_Reg9); - } + } } return 0; } @@ -1352,10 +1352,10 @@ pixels_per_line (Coolscan_t * s) { int pic_dot; if(s->LS<2) - { pic_dot = (s->brx - s->tlx + s->x_nres) / s->x_nres; + { pic_dot = (s->brx - s->tlx + s->x_nres) / s->x_nres; } else - { pic_dot = (s->brx - s->tlx + 1) / s->x_nres; + { pic_dot = (s->brx - s->tlx + 1) / s->x_nres; } DBG (10, "pic_dot=%d\n", pic_dot); return pic_dot; @@ -1366,10 +1366,10 @@ lines_per_scan (Coolscan_t * s) { int pic_line; if(s->LS<2) - { pic_line = (s->bry - s->tly + s->y_nres) / s->y_nres; + { pic_line = (s->bry - s->tly + s->y_nres) / s->y_nres; } else - { pic_line = (( s->bry - s->tly + 1.0 ) / s->y_nres); + { pic_line = (( s->bry - s->tly + 1.0 ) / s->y_nres); } DBG (10, "pic_line=%d\n", pic_line); return pic_line; @@ -1384,13 +1384,13 @@ scan_bytes_per_line (Coolscan_t * s) bpl=pixels_per_line (s) * 3; if(s->bits_per_color>8) bpl=bpl*2; return bpl; - break; + break; case RGBI: case IRED: bpl=pixels_per_line (s) * 4; if(s->bits_per_color>8) bpl=bpl*2; return bpl; - break; + break; } return 0; } @@ -1403,18 +1403,18 @@ write_bytes_per_line (Coolscan_t * s) bpl=pixels_per_line (s) * 3; if(s->bits_per_color>8) bpl=bpl*2; return bpl; - break; + break; case RGBI: bpl=pixels_per_line (s) * 4; if(s->bits_per_color>8) bpl=bpl*2; return bpl; - break; + break; case IRED: case GREYSCALE: bpl= pixels_per_line (s) ; if(s->bits_per_color>8) bpl=bpl*2; return bpl; - break; + break; } return 0; } @@ -1449,7 +1449,7 @@ coolscan_check_values (Coolscan_t * s) /* test_little_endian */ -static SANE_Bool +static SANE_Bool coolscan_test_little_endian(void) { SANE_Int testvalue = 255; @@ -1463,7 +1463,7 @@ coolscan_test_little_endian(void) static int get_inquiery_part_LS30 (Coolscan_t * s, unsigned char part) -{ +{ int size; /* Get length of reponse */ @@ -1473,7 +1473,7 @@ get_inquiery_part_LS30 (Coolscan_t * s, unsigned char part) set_inquiry_return_size (inquiry.cmd, size); do_scsi_cmd (s->sfd, inquiry.cmd, inquiry.size, s->buffer, size); - size=get_inquiry_length(s->buffer); + size=get_inquiry_length(s->buffer); size+=4; /* then get inquiry with actual size */ set_inquiry_return_size (inquiry.cmd, size); @@ -1498,7 +1498,7 @@ coolscan_read_var_data_block (Coolscan_t * s,int datatype) set_R_xfer_length (sread.cmd, size); r = do_scsi_cmd (s->sfd, sread.cmd, sread.size, s->buffer, size); - size=s->buffer[5]; + size=s->buffer[5]; set_R_xfer_length (sread.cmd, size); r = do_scsi_cmd (s->sfd, sread.cmd, sread.size, s->buffer, size); @@ -1507,14 +1507,14 @@ coolscan_read_var_data_block (Coolscan_t * s,int datatype) static int get_inquiery_LS30 (Coolscan_t * s) -{ +{ unsigned char part; unsigned char parts[5]; int i; /* Get vector of inquiery parts */ get_inquiery_part_LS30(s, (unsigned char) 0); - /* Get the parts of inquiery */ + /* Get the parts of inquiery */ for(i=0;i<5;i++) { parts[i]=((unsigned char *)s->buffer)[4+11+i]; } @@ -1522,7 +1522,7 @@ get_inquiery_LS30 (Coolscan_t * s) { part=parts[i]; get_inquiery_part_LS30 (s, part); switch(part) - { case 0x0c1:/* max size and resolution */ + { case 0x0c1:/* max size and resolution */ s->adbits = 8; s->outputbits = 8; s->maxres = getnbyte(s->buffer+0x12,2)-1; @@ -1537,7 +1537,7 @@ get_inquiery_LS30 (Coolscan_t * s) break; case 0x0f8: break; - } + } } /* get windows */ @@ -1556,7 +1556,7 @@ get_inquiery_LS30 (Coolscan_t * s) static int get_feeder_type_LS30 (Coolscan_t * s) -{ +{ int size; unsigned char *ptr; int ima; @@ -1668,7 +1668,7 @@ get_internal_info_LS20 (Coolscan_t * s) "\tdevice error code = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n" "\tpower-on errors = 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x 0x%x\n", s->offsetdata_r, s->offsetdata_g, s->offsetdata_b, - s->limitcondition, + s->limitcondition, s->derr[0], s->derr[1], s->derr[2], s->derr[3], s->derr[4], s->derr[5], s->derr[6], s->derr[7], s->power_on_errors[0], s->power_on_errors[1], @@ -1685,7 +1685,7 @@ get_internal_info (Coolscan_t * s) int ret; DBG (10, "get_internal_info\n"); - + if(s->LS<2) /* distinquish between old and new scanners */ { ret=get_internal_info_LS20 (s); } @@ -1734,7 +1734,7 @@ coolscan_initialize_values (Coolscan_t * s) } if(s->LS>=2) /* LS-30 */ { - get_inquiery_LS30(s); /* Info about scanner*/ + get_inquiery_LS30(s); /* Info about scanner*/ select_MUD (s); /* must be before mode_sense */ get_feeder_type_LS30(s); s->wdb_len = 117; @@ -1773,7 +1773,7 @@ coolscan_initialize_values (Coolscan_t * s) s->exposure_B = 50; s->pretv_r=40000; - s->pretv_g=40000; + s->pretv_g=40000; s->pretv_b=40000; s->shift_R = 128; @@ -1808,7 +1808,7 @@ coolscan_initialize_values (Coolscan_t * s) s->gamma_r[i] = s->gamma[i]; s->gamma_g[i] = s->gamma[i]; s->gamma_b[i] = s->gamma[i]; - } + } if (coolscan_test_little_endian() == SANE_TRUE) { @@ -1863,7 +1863,7 @@ sense_handler (int scsi_fd, unsigned char * result, void *arg) return SANE_STATUS_IO_ERROR; /* we only know about this one */ } return request_sense_parse(result); - + } @@ -1904,7 +1904,7 @@ static SANE_String_Const scan_mode_list_LS30[] = { colorStr, grayStr, -#ifdef HAS_IRED +#ifdef HAS_IRED rgbiStr, #endif /* HAS_IRED */ NULL @@ -1928,7 +1928,7 @@ static SANE_String_Const autofocus_mode_list[] = static SANE_String_Const source_list[4] = {NULL, NULL, NULL, NULL}; -static const SANE_Range gamma_range_8 = +static const SANE_Range gamma_range_8 = { 0, /* minimum */ 255, /* maximum */ @@ -1936,21 +1936,21 @@ static const SANE_Range gamma_range_8 = }; -static const SANE_Range gamma_range_9 = +static const SANE_Range gamma_range_9 = { 0, /* minimum */ 511, /* maximum */ 1 /* quantization */ }; -static const SANE_Range gamma_range_10 = +static const SANE_Range gamma_range_10 = { 0, /* minimum */ 1023, /* maximum */ 1 /* quantization */ }; -static const SANE_Range gamma_range_12 = +static const SANE_Range gamma_range_12 = { 0, /* minimum */ 4096, /* maximum */ @@ -2037,7 +2037,7 @@ do_cancel (Coolscan_t * scanner) sanei_thread_kill (scanner->reader_pid); while (sanei_thread_waitpid(scanner->reader_pid, &exit_status) != scanner->reader_pid ); - scanner->reader_pid = -1; + sanei_thread_invalidate (scanner->reader_pid); } if (scanner->sfd >= 0) @@ -2082,10 +2082,10 @@ attach_scanner (const char *devicename, Coolscan_t ** devp) if (NULL == (dev = malloc (sizeof (*dev)))) return SANE_STATUS_NO_MEM; - + dev->row_bufsize = (sanei_scsi_max_request_size < (64 * 1024)) ? sanei_scsi_max_request_size : 64 * 1024; - + if ((dev->buffer = malloc (dev->row_bufsize)) == NULL) /* if ((dev->buffer = malloc (sanei_scsi_max_request_size)) == NULL)*/ return SANE_STATUS_NO_MEM; @@ -2170,16 +2170,16 @@ typedef struct Color_correct_s double sumri; /* sum of red*ired pixel values*/ double sumii; /* sum of ired*ired pixel values*/ double sumrr; /* sum of ired*ired pixel values*/ - int mr; /* factor between red and ired values (*256) */ - int br; /* offset of ired values */ + int mr; /* factor between red and ired values (*256) */ + int br; /* offset of ired values */ } ColorCorrect; -/* --------------------------------------------------------------- +/* --------------------------------------------------------------- function: RGBIfix taks: Correct the infrared channel - + import: unsigned char * rgbimat - RGBI - matrix from scanner int size - number of pixels to correct int *lutr - lookup table for red correction @@ -2188,13 +2188,13 @@ typedef struct Color_correct_s int *lutr - lookup table for red correction export: unsigned char * orgbimat - RGBI - corrected matrix - + written by: Andreas RICK 19.6.1999 - + ----------------------------------------------------------------*/ static int Calc_fix_LUT(Coolscan_t * s) -{ int uselutr,uselutg,uselutb,useluti; +{ int uselutr,uselutg,uselutb,useluti; /* static int irmulr= -34*25; */ int irmulr= -64*25; int irmulg= -1*25; @@ -2207,11 +2207,11 @@ static int Calc_fix_LUT(Coolscan_t * s) irmulg=s->ired_green*(25); irmulb=s->ired_blue*(25); irmuli=25*256; - + if(s->LS==2) /* TODO: right conversion factors for 10 and 12 bit */ { div=4; } - else if(s->LS==3) + else if(s->LS==3) { div=16; } else @@ -2233,10 +2233,10 @@ static int Calc_fix_LUT(Coolscan_t * s) uselutb=s->gamma_b[i]/div; useluti=s->gamma_r[i]/div; } - s->lutr[uselutr]=(int)(irmulr*pow((double)i,(double)0.333333)); - s->lutg[uselutg]=(int)(irmulg*pow((double)i,(double)0.333333)); - s->lutb[uselutb]=(int)(irmulb*pow((double)i,(double)0.333333)); - s->luti[useluti]=(int)(irmuli*pow((double)i,(double)0.333333)); + s->lutr[uselutr]=(int)(irmulr*pow((double)i,(double)0.333333)); + s->lutg[uselutg]=(int)(irmulg*pow((double)i,(double)0.333333)); + s->lutb[uselutb]=(int)(irmulb*pow((double)i,(double)0.333333)); + s->luti[useluti]=(int)(irmuli*pow((double)i,(double)0.333333)); if(uselutr<255) { if(s->lutr[uselutr+1]==0) s->lutr[uselutr+1]=s->lutr[uselutr]; } @@ -2261,12 +2261,12 @@ static int Calc_fix_LUT(Coolscan_t * s) -/* --------------------------------------------------------------- +/* --------------------------------------------------------------- function: RGBIfix taks: Correct the infrared channel - + import: unsigned char * rgbimat - RGBI - matrix from scanner int size - number of pixels to correct int *lutr - lookup table for red correction @@ -2275,20 +2275,20 @@ static int Calc_fix_LUT(Coolscan_t * s) int *lutr - lookup table for red correction export: unsigned char * orgbimat - RGBI - corrected matrix - + written by: Andreas RICK 19.6.1999 - + ----------------------------------------------------------------*/ static int RGBIfix(Coolscan_t * scanner, unsigned char* rgbimat, - unsigned char* orgbimat, + unsigned char* orgbimat, int size, int *lutr, int *lutg, int *lutb, int *luti) - + { unsigned char *pr,*pg,*pb,*pi; unsigned char *opr,*opg,*opb,*opi; @@ -2299,42 +2299,42 @@ static int RGBIfix(Coolscan_t * scanner, for(x=0;x255*256)ii=255*256; if(scanner->negative) { - (*opi)=(unsigned char)(255-(ii>>8)); + (*opi)=(unsigned char)(255-(ii>>8)); } else { - (*opi)=(unsigned char)(ii>>8); + (*opi)=(unsigned char)(ii>>8); } } return 1; } -/* --------------------------------------------------------------- +/* --------------------------------------------------------------- function: RGBIfix16 taks: Correct the infrared channel for 16 bit images (doesn't do anything for now) - + import: unsigned char * rgbimat - RGBI - matrix from scanner int size - number of pixels to correct int *lutr - lookup table for red correction @@ -2343,21 +2343,21 @@ static int RGBIfix(Coolscan_t * scanner, int *lutr - lookup table for red correction export: unsigned char * orgbimat - RGBI - corrected matrix - + written by: Andreas RICK 19.6.1999 - + ----------------------------------------------------------------*/ static int RGBIfix16(Coolscan_t * scanner, unsigned short* rgbimat, - unsigned short* orgbimat, + unsigned short* orgbimat, int size, int *lutr, int *lutg, int *lutb, int *luti) - -{ + +{ unsigned short *pr,*pg,*pb,*pi; unsigned short *opr,*opg,*opb,*opi; int x; @@ -2367,43 +2367,43 @@ static int RGBIfix16(Coolscan_t * scanner, for(x=0;x>8); - (*opg)=(((*pg)&0x00ff)<<8)+(((*pg)&0xff00)>>8); - (*opb)=(((*pb)&0x00ff)<<8)+(((*pb)&0xff00)>>8); - (*opi)=(((*pi)&0x00ff)<<8)+(((*pi)&0xff00)>>8); + (*opr)=(((*pr)&0x00ff)<<8)+(((*pr)&0xff00)>>8); + (*opg)=(((*pg)&0x00ff)<<8)+(((*pg)&0xff00)>>8); + (*opb)=(((*pb)&0x00ff)<<8)+(((*pb)&0xff00)>>8); + (*opi)=(((*pi)&0x00ff)<<8)+(((*pi)&0xff00)>>8); } return 1; } -/* --------------------------------------------------------------- +/* --------------------------------------------------------------- function: rgb2g taks: Convert RGB data to grey - + import: unsigned char * rgbimat - RGB - matrix from scanner int size - size of input data (num pixel) export: unsigned char * gomat - Grey matrix - + written by: Andreas RICK 13.7.1999 - + ----------------------------------------------------------------*/ #define RtoG ((int)(0.27*256)) #define GtoG ((int)(0.54*256)) #define BtoG ((int)(0.19*256)) -static int rgb2g(unsigned char* rgbimat,unsigned char* gomat, +static int rgb2g(unsigned char* rgbimat,unsigned char* gomat, int size) - + { unsigned char *pr,*pg,*pb; unsigned char *opg; @@ -2412,17 +2412,17 @@ static int rgb2g(unsigned char* rgbimat,unsigned char* gomat, for(x=0;x>8); + (*opg)=(unsigned char)(g>>8); } return 1; } -/* --------------------------------------------------------------- +/* --------------------------------------------------------------- function: RGBIfix1 @@ -2433,7 +2433,7 @@ static int rgb2g(unsigned char* rgbimat,unsigned char* gomat, The infrared values is corrected by: Ir=mr*lutr(r)+luti(i) - + import: unsigned char * rgbimat - RGBI - matrix from scanner int size - number of pixels to correct ColorCorrect *cc, @@ -2441,18 +2441,18 @@ static int rgb2g(unsigned char* rgbimat,unsigned char* gomat, int *luti - lookup table for ired correction export: unsigned char * orgbimat - RGBI - corrected matrix - + written by: Andreas RICK 3.7.1999 - + ----------------------------------------------------------------*/ #if 0 -static int RGBIfix1(unsigned char* rgbimat,unsigned char* orgbimat, +static int RGBIfix1(unsigned char* rgbimat,unsigned char* orgbimat, int size, int *lutr, int *lutg, int *lutb, int *luti) - + { unsigned char *pr,*pg,*pb,*pi; unsigned char *opr,*opg,*opb,*opi; ColorCorrect cc; @@ -2468,7 +2468,7 @@ static int RGBIfix1(unsigned char* rgbimat,unsigned char* orgbimat, cc.sumr=cc.sumii=cc.sumrr=cc.sumi=cc.sumri=0.0; for(x=0;x>10)-cc.br)>>2) +128; (*opr)=(*pr); (*opg)=(*pg); - (*opb)=(*pb); + (*opb)=(*pb); if(ii<0) ii=0; if(ii>255) ii=255; - (*opi)=(unsigned char)(ii); + (*opi)=(unsigned char)(ii); } return 1; } @@ -2582,7 +2582,7 @@ reader_process (void *data ) data_left = scan_bytes_per_line (scanner) * lines_per_scan (scanner); - + /*scanner->row_bufsize = sanei_scsi_max_request_size;*/ coolscan_trim_rowbufsize (scanner); /* trim bufsize */ @@ -2612,27 +2612,27 @@ reader_process (void *data ) fclose (fp); return (-1); } - + if (scanner->LS == 1) { /* mirror image for LS-1000 */ bpl = scan_bytes_per_line(scanner); linesPerBuf = data_to_read / bpl; - - for (line = 0, lineOffset = 0; line < linesPerBuf; + + for (line = 0, lineOffset = 0; line < linesPerBuf; line++, lineOffset += bpl ) { - + if (scanner->colormode == RGB) { for (j = 0; j < bpl/2 ; j += 3) { r_data=scanner->buffer[lineOffset + j]; g_data=scanner->buffer[lineOffset + j + 1]; b_data=scanner->buffer[lineOffset + j + 2]; - - scanner->buffer[lineOffset + j] = + + scanner->buffer[lineOffset + j] = scanner->buffer[lineOffset + bpl -1 - j - 2 ]; - scanner->buffer[lineOffset + j + 1] = + scanner->buffer[lineOffset + j + 1] = scanner->buffer[lineOffset + bpl -1 - j - 1 ]; - scanner->buffer[lineOffset + j + 2] = + scanner->buffer[lineOffset + j + 2] = scanner->buffer[lineOffset + bpl -1 - j ]; - + scanner->buffer[lineOffset + bpl -1 - j - 2 ] = r_data; scanner->buffer[lineOffset + bpl -1 - j - 1] = g_data; scanner->buffer[lineOffset + bpl -1 - j] = b_data; @@ -2641,18 +2641,18 @@ reader_process (void *data ) else { for (j = 0; j < bpl/2; j++) { r_data=scanner->buffer[lineOffset + j]; - scanner->buffer[lineOffset + j] = + scanner->buffer[lineOffset + j] = scanner->buffer[lineOffset + bpl - 1 - j]; scanner->buffer[lineOffset + bpl - 1 - j] = r_data; } } - } - } - if(scanner->colormode==RGBI) + } + } + if(scanner->colormode==RGBI) { /* Correct Infrared Channel */ if(scanner->bits_per_color>8) { - RGBIfix16(scanner, (unsigned short * ) scanner->buffer, + RGBIfix16(scanner, (unsigned short * ) scanner->buffer, (unsigned short * )scanner->obuffer, data_to_read/8,scanner->lutr, scanner->lutg,scanner->lutb,scanner->luti); @@ -2672,9 +2672,9 @@ reader_process (void *data ) else { /* or just copy */ memcpy (scanner->obuffer, scanner->buffer,data_to_read); - } + } if((!scanner->low_byte_first)&&(scanner->bits_per_color>8)) - { for(i=0;iobuffer[i]; scanner->obuffer[i]=scanner->obuffer[i+1]; i++; @@ -2682,7 +2682,7 @@ reader_process (void *data ) } } fwrite (scanner->obuffer, 1, data_to_write, fp); - fflush (fp); + fflush (fp); data_left -= data_to_read; DBG (10, "reader_process: buffer of %d bytes read; %d bytes to go\n", data_to_read, data_left); @@ -2786,7 +2786,7 @@ init_options (Coolscan_t * scanner) scanner->opt[OPT_PRESCAN_NOW].constraint.string_list = 0; /* bit depth */ - + bit_depths=0; bit_depth_list[++bit_depths] = 8; if (scanner->LS==2) @@ -2886,7 +2886,7 @@ init_options (Coolscan_t * scanner) scanner->opt[OPT_GAMMA_BIND].type = SANE_TYPE_BOOL; scanner->opt[OPT_GAMMA_BIND].unit = SANE_UNIT_NONE; - + scanner->opt[OPT_ANALOG_GAMMA].name = "analog_gamma"; scanner->opt[OPT_ANALOG_GAMMA].title = "Analog Gamma"; scanner->opt[OPT_ANALOG_GAMMA].desc = "Analog Gamma"; @@ -3243,7 +3243,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) DBG_INIT (); sanei_thread_init (); - + DBG (10, "sane_init\n"); if (version_code) *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0); @@ -3286,7 +3286,7 @@ sane_exit (void) free (dev->obuffer); free (dev); } - + if (devlist) free (devlist); } @@ -3468,11 +3468,11 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { case AF_NEVER: strcpy (val,neverStr); break; case AF_PREVIEW:strcpy (val,previewStr); - break; + break; case AF_SCAN:if(scanner->LS>=2) strcpy (val,scanStr); - break; + break; case AF_PREANDSCAN:if(scanner->LS>=2) strcpy (val,preandscanStr); - break; + break; } return SANE_STATUS_GOOD; @@ -3567,13 +3567,13 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { case RGB: strcpy (val,colorStr); break; case GREYSCALE:strcpy (val,grayStr); - break; + break; case RGBI:if(scanner->LS>=2) strcpy (val,rgbiStr); else strcpy (val,colorStr); - break; - case IRED:if(scanner->LS>=2) strcpy (val,iredStr); + break; + case IRED:if(scanner->LS>=2) strcpy (val,iredStr); else strcpy (val,grayStr); - break; + break; } if (info) { @@ -3586,7 +3586,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *(SANE_Word *) val = (scanner->prescan) ? SANE_TRUE : SANE_FALSE; return SANE_STATUS_GOOD; - case OPT_PRESCAN_NOW: + case OPT_PRESCAN_NOW: return SANE_STATUS_GOOD; case OPT_RGB_CONTROL: @@ -3598,7 +3598,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, return SANE_STATUS_GOOD; case OPT_ANALOG_GAMMA: - *(SANE_Word *) val = + *(SANE_Word *) val = (scanner->analog_gamma_r) ? SANE_TRUE : SANE_FALSE; return SANE_STATUS_GOOD; @@ -3692,7 +3692,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, return SANE_STATUS_GOOD; case OPT_PRESCAN_NOW: - do_prescan_now(scanner); + do_prescan_now(scanner); return SANE_STATUS_GOOD; case OPT_BIT_DEPTH: @@ -3811,16 +3811,16 @@ sane_control_option (SANE_Handle handle, SANE_Int option, return SANE_STATUS_GOOD; case OPT_AUTOFOCUS: - if(strcmp(val,neverStr)==0) + if(strcmp(val,neverStr)==0) { scanner->autofocus=AF_NEVER; } - if(strcmp(val,previewStr)==0) + if(strcmp(val,previewStr)==0) { scanner->autofocus=AF_PREVIEW; } - if(strcmp(val,scanStr)==0) + if(strcmp(val,scanStr)==0) { scanner->autofocus=AF_SCAN; } - if(strcmp(val,preandscanStr)==0) + if(strcmp(val,preandscanStr)==0) { scanner->autofocus=AF_PREANDSCAN;; } return SANE_STATUS_GOOD; @@ -3877,7 +3877,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, return SANE_STATUS_GOOD; case OPT_IRED_RED: - scanner->ired_red= *(SANE_Word *) val; + scanner->ired_red= *(SANE_Word *) val; return SANE_STATUS_GOOD; case OPT_SOURCE: @@ -3892,11 +3892,11 @@ sane_control_option (SANE_Handle handle, SANE_Int option, } return SANE_STATUS_GOOD; case OPT_MODE: - if(strcmp(val,colorStr)==0) + if(strcmp(val,colorStr)==0) { scanner->colormode=RGB; scanner->colormode_p=RGB; } - if(strcmp(val,grayStr)==0) + if(strcmp(val,grayStr)==0) { scanner->colormode=GREYSCALE; scanner->colormode_p=GREYSCALE; } @@ -3904,7 +3904,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { scanner->colormode=RGBI; scanner->colormode_p=RGB; } - if(strcmp(val,iredStr)==0) + if(strcmp(val,iredStr)==0) { scanner->colormode=IRED; scanner->colormode_p=GREYSCALE; } @@ -3951,8 +3951,8 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) break; #ifdef HAS_IRED case RGBI: - params->format = SANE_FRAME_RGBA; - break; + params->format = SANE_FRAME_RGBA; + break; #endif /* HAS_RGBI */ case GREYSCALE: params->format = SANE_FRAME_GRAY; @@ -4039,12 +4039,12 @@ sane_start (SANE_Handle handle) } } else - { + { if(scanner->autofocus & 0x01) { coolscan_autofocus (scanner); } if (scanner->prescan) { - prescan (scanner); + prescan (scanner); if(scanner->LS<2) { get_internal_info(scanner); } @@ -4155,7 +4155,7 @@ sane_cancel (SANE_Handle handle) { sanei_thread_kill ( s->reader_pid ); sanei_thread_waitpid( s->reader_pid, NULL ); - s->reader_pid = -1; + sanei_thread_invalidate (s->reader_pid); } swap_res (s); s->scanning = SANE_FALSE; diff --git a/backend/coolscan.h b/backend/coolscan.h index d3e4154..4f40aa4 100644 --- a/backend/coolscan.h +++ b/backend/coolscan.h @@ -110,7 +110,7 @@ typedef struct Image_Pos { int start; /* start position of image on film strip */ int end; /* end position of image on film strip */ int offset /* always 0 */; - int height; /* image height always 2591 */ + int height; /* image height always 2591 */ } Image_Pos_t; @@ -213,19 +213,19 @@ typedef struct Coolscan int adbits; /* Number of A/D bits [8 or 12] */ int outputbits; /* Number of output image data bits [8] */ int maxres; /* Maximum resolution [2700] (dpi) */ - int xmax; /* X-axis coordinate maximum value - (basic measurement unit when measurement + int xmax; /* X-axis coordinate maximum value + (basic measurement unit when measurement unit divisor = 1200) [1151] */ - int ymax; /* Y-axis coordinate maximum value - (basic measurement unit when measurement + int ymax; /* Y-axis coordinate maximum value + (basic measurement unit when measurement unit divisor = 1200) [1727] */ - int xmaxpix; /* X-axis coordinate maximum value (pixel + int xmaxpix; /* X-axis coordinate maximum value (pixel address value) [2591] */ - int ymaxpix; /* Y-axis coordinate maximum value (pixel + int ymaxpix; /* Y-axis coordinate maximum value (pixel address value) [3887] */ - int ycurrent; /* Current stage position (Y-axis direction + int ycurrent; /* Current stage position (Y-axis direction pixel address) [0-7652] */ - int currentfocus; /* Current focus position (focus direction + int currentfocus; /* Current focus position (focus direction address) [0-200] */ int currentscanpitch; /* Current scan pitch [1-25] */ int autofeeder; /* Provision of auto feeder [Yes: 1, No: 0] */ @@ -276,7 +276,7 @@ typedef struct Coolscan int analog_gamma_g; /* analog gamma green */ int analog_gamma_b; /* analog gamma blue */ - /* Infrared correction values */ + /* Infrared correction values */ int ired_red; int ired_green; int ired_blue; diff --git a/backend/coolscan2.c b/backend/coolscan2.c index d54bf39..04c4d10 100644 --- a/backend/coolscan2.c +++ b/backend/coolscan2.c @@ -36,14 +36,14 @@ 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. This file implements a SANE backend for Nikon Coolscan film scanners. - Written by András Major (andras@users.sourceforge.net), 2001-2002. + Written by András Major (andras@users.sourceforge.net), 2001-2002. The developers wish to express their thanks to Nikon Corporation for providing technical information and thus making this backend diff --git a/backend/coolscan3.c b/backend/coolscan3.c index 42814d1..6163ec9 100644 --- a/backend/coolscan3.c +++ b/backend/coolscan3.c @@ -4,7 +4,7 @@ * * This file implements a SANE backend for Nikon Coolscan film scanners. * - * coolscan3.c is based on coolscan2.c, a work of András Major, Ariel Garcia + * coolscan3.c is based on coolscan2.c, a work of András Major, Ariel Garcia * and Giuseppe Sacco. * * Copyright (C) 2007-08 Tower Technologies diff --git a/backend/dc210.c b/backend/dc210.c index 32da710..85ffb20 100644 --- a/backend/dc210.c +++ b/backend/dc210.c @@ -1,7 +1,7 @@ /*************************************************************************** * SANE - Scanner Access Now Easy. - dc210.c + dc210.c 11/11/98 @@ -43,17 +43,17 @@ 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. + If you do not wish that, delete this exception notice. *************************************************************************** This file implements a SANE backend for the Kodak DC-210 - digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! + digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! (feedback to: sane-dc210@interlinx.bc.ca This backend is based somewhat on the dc25 backend included in this - package by Peter Fales + package by Peter Fales ***************************************************************************/ @@ -395,7 +395,7 @@ init_dc210 (DC210 * camera) } /* send a break to get it back to a known state */ - /* Used to supply a non-zero argument to tcsendbreak(), TCSBRK, + /* Used to supply a non-zero argument to tcsendbreak(), TCSBRK, * and TCSBRKP, but that is system dependent. e.g. on irix a non-zero * value does a drain instead of a break. A zero value is universally * used to send a break. @@ -423,8 +423,8 @@ init_dc210 (DC210 * camera) if (send_pck (camera->fd, init_pck) == -1) { /* - * The camera always powers up at 9600, so we try - * that first. However, it may be already set to + * The camera always powers up at 9600, so we try + * that first. However, it may be already set to * a different speed. Try the entries in the table: */ @@ -455,7 +455,7 @@ init_dc210 (DC210 * camera) } } /* - Set speed to requested speed. + Set speed to requested speed. */ cfsetospeed (&tty_new, Camera.baud); cfsetispeed (&tty_new, Camera.baud); @@ -954,7 +954,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (dc210_opt_thumbnails) { - /* + /* * DC210 thumbnail are 96x72x8x3 */ parms.bytes_per_line = 96 * 3; @@ -1190,7 +1190,7 @@ sane_start (SANE_Handle handle) { /* - * Don't allow picture unless there is room in the + * Don't allow picture unless there is room in the * camera. */ if (Camera.pic_left == 0) diff --git a/backend/dc210.conf.in b/backend/dc210.conf.in index 9281043..8293170 100644 --- a/backend/dc210.conf.in +++ b/backend/dc210.conf.in @@ -18,7 +18,7 @@ port=/dev/ttyS0 ## This works for most UNIX's baud=38400 # Prints some extra information during the init phase. This can be -# handy, but note that printing anything to stderr breaks the saned +# handy, but note that printing anything to stderr breaks the saned # network scanning. #dumpinquiry # How many usec (1,000,000ths of a) between writing the command and reading the diff --git a/backend/dc210.h b/backend/dc210.h index fe2b633..2cbbf46 100644 --- a/backend/dc210.h +++ b/backend/dc210.h @@ -1,7 +1,7 @@ /*************************************************************************** * SANE - Scanner Access Now Easy. - dc210.c + dc210.c 11/11/98 @@ -43,17 +43,17 @@ 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. + If you do not wish that, delete this exception notice. *************************************************************************** This file implements a SANE backend for the Kodak DC-210 - digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! + digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! (feedback to: sane-dc210@interlinx.bc.ca This backend is based somewhat on the dc25 backend included in this - package by Peter Fales + package by Peter Fales ***************************************************************************/ diff --git a/backend/dc240.c b/backend/dc240.c index 74ab2e0..0a53405 100644 --- a/backend/dc240.c +++ b/backend/dc240.c @@ -1,13 +1,13 @@ /*************************************************************************** * _S_A_N_E - Scanner Access Now Easy. - dc240.c + dc240.c 03/12/01 - Peter Fales Based on the dc210 driver, (C) 1998 Brian J. Murrell (which is based on dc25 driver (C) 1998 by Peter Fales) - + This file (C) 2001 by Peter Fales This file is part of the SANE package. @@ -46,12 +46,12 @@ 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. + If you do not wish that, delete this exception notice. *************************************************************************** This file implements a SANE backend for the Kodak DC-240 - digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! + digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! (feedback to: dc240-devel@fales-lorenz.net) @@ -440,7 +440,7 @@ init_dc240 (DC240 * camera) } /* send a break to get it back to a known state */ - /* Used to supply a non-zero argument to tcsendbreak(), TCSBRK, + /* Used to supply a non-zero argument to tcsendbreak(), TCSBRK, * and TCSBRKP, but that is system dependent. e.g. on irix a non-zero * value does a drain instead of a break. A zero value is universally * used to send a break. @@ -465,7 +465,7 @@ init_dc240 (DC240 * camera) sleep (1); #endif - /* We seem to get some garbage following the break, so + /* We seem to get some garbage following the break, so * read anything pending */ n = read (camera->fd, buf, 5); @@ -476,8 +476,8 @@ init_dc240 (DC240 * camera) if (send_pck (camera->fd, init_pck) == -1) { /* - * The camera always powers up at 9600, so we try - * that first. However, it may be already set to + * The camera always powers up at 9600, so we try + * that first. However, it may be already set to * a different speed. Try the entries in the table: */ @@ -491,7 +491,7 @@ init_dc240 (DC240 * camera) buf[1], buf[2], buf[3], buf[4]); /* - Set speed to requested speed. + Set speed to requested speed. */ cfsetospeed (&tty_new, Camera.baud); cfsetispeed (&tty_new, Camera.baud); @@ -597,7 +597,7 @@ get_info (DC240 * camera) n = read_dir ("\\PCCARD\\DCIM\\*.*"); /* If we've already got a folder_list, free it up before starting - * the new one + * the new one */ if (folder_list != NULL) { @@ -1083,8 +1083,8 @@ sane_control_option (SANE_Handle handle, SANE_Int option, myinfo |= SANE_INFO_RELOAD_PARAMS; - /* get the image's resolution, unless the camera has no - * pictures yet + /* get the image's resolution, unless the camera has no + * pictures yet */ if (Camera.pic_taken != 0) { @@ -1367,7 +1367,7 @@ sane_start (SANE_Handle handle) if (dc240_opt_snap) { /* - * Don't allow picture unless there is room in the + * Don't allow picture unless there is room in the * camera. */ if (Camera.pic_left == 0) @@ -1719,7 +1719,7 @@ get_picture_info (PictureInfo * pic, SANE_Int p) read_info (e->name); - /* Validate picture info + /* Validate picture info * byte 0 - 1 == picture info * byte 1 - 5 == DC240 Camera * byte 2 - 3 == JFIF file @@ -1736,7 +1736,7 @@ get_picture_info (PictureInfo * pic, SANE_Int p) pic->low_res = info_buf[3] == 0 ? SANE_TRUE : SANE_FALSE; - /* + /* * byte 12 - Year MSB * byte 13 - Year LSB * byte 14 - Month @@ -1991,8 +1991,8 @@ read_info (SANE_String fname) /* - * send_data - Send a data block - assumes all data blocks to camera - * are 60 bytes long + * send_data - Send a data block - assumes all data blocks to camera + * are 60 bytes long */ static SANE_Int @@ -2090,7 +2090,7 @@ dir_insert (struct cam_dirent *entry) } /* - * dir_delete - Delete a directory entry from the linked list of file + * dir_delete - Delete a directory entry from the linked list of file * names */ static SANE_Int @@ -2123,7 +2123,7 @@ dir_delete (SANE_String fname) } /* - * set_res - set picture size depending on resolution settings + * set_res - set picture size depending on resolution settings */ static void set_res (SANE_Int lowres) diff --git a/backend/dc240.conf.in b/backend/dc240.conf.in index 9281043..8293170 100644 --- a/backend/dc240.conf.in +++ b/backend/dc240.conf.in @@ -18,7 +18,7 @@ port=/dev/ttyS0 ## This works for most UNIX's baud=38400 # Prints some extra information during the init phase. This can be -# handy, but note that printing anything to stderr breaks the saned +# handy, but note that printing anything to stderr breaks the saned # network scanning. #dumpinquiry # How many usec (1,000,000ths of a) between writing the command and reading the diff --git a/backend/dc240.h b/backend/dc240.h index fae3628..27e2ee9 100644 --- a/backend/dc240.h +++ b/backend/dc240.h @@ -46,12 +46,12 @@ 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. + If you do not wish that, delete this exception notice. *************************************************************************** This file implements a SANE backend for the Kodak DC-240 - digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! + digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! (feedback to: dc240-devel@fales-lorenz.net) @@ -143,16 +143,16 @@ static SANE_Int get_info (DC240 *); * Resolution: 0x00 = low, 0x01 = high */ #define THUMBS_PCK {0x93, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x1A} -/* - * +/* + * */ #define PICS_PCK {0x9A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A} -/* - * +/* + * */ #define PICS_INFO_PCK {0x91, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A} -/* - * +/* + * */ #define OPEN_CARD_PCK {0x96, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A} #define READ_DIR_PCK {0x99, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1A} diff --git a/backend/dc25.c b/backend/dc25.c index fd7a0db..3bb81f5 100644 --- a/backend/dc25.c +++ b/backend/dc25.c @@ -1,7 +1,7 @@ /*************************************************************************** * SANE - Scanner Access Now Easy. - dc25.c + dc25.c $Id$ @@ -43,13 +43,13 @@ 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. + If you do not wish that, delete this exception notice. *************************************************************************** - This file implements a SANE backend for the Kodak DC-25 (and + This file implements a SANE backend for the Kodak DC-25 (and probably the DC-20) digital cameras. THIS IS EXTREMELY ALPHA CODE! - USE AT YOUR OWN RISK!! + USE AT YOUR OWN RISK!! (feedback to: dc25-devel@fales-lorenz.net) @@ -73,7 +73,7 @@ * conversion routine written by YOSHIDA Hideki * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published + * it under the terms of the GNU General Public License as published * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * @@ -148,12 +148,6 @@ static SANE_Byte contrast_table[256]; static struct pixmap *pp; -static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 0 << SANE_FIXED_SCALE_SHIFT /* quantization */ -}; - static const SANE_Range contrast_range = { 0 << SANE_FIXED_SCALE_SHIFT, /* minimum */ 3 << SANE_FIXED_SCALE_SHIFT, /* maximum */ @@ -352,9 +346,9 @@ static SANE_Parameters parms = { static unsigned char init_pck[] = INIT_PCK; /* - * List of speeds to try to establish connection with the camera. + * List of speeds to try to establish connection with the camera. * Check 9600 first, as it's the speed the camera comes up in, then - * 115200, as that is the one most likely to be configured from a + * 115200, as that is the one most likely to be configured from a * previous run */ static struct pkt_speed speeds[] = { {B9600, {0x96, 0x00}}, @@ -468,8 +462,8 @@ init_dc20 (char *device, speed_t speed) if (send_pck (tfd, init_pck) == -1) { /* - * The camera always powers up at 9600, so we try - * that first. However, it may be already set to + * The camera always powers up at 9600, so we try + * that first. However, it may be already set to * a different speed. Try the entries in the table: */ @@ -594,7 +588,7 @@ get_info (int fd) { /* Not sure where the previous line came from. All the * information I have says that even on the DC20 the number of - * standard res pics left is in byte 23 and the number of high res + * standard res pics left is in byte 23 and the number of high res * pics left is in byte 21. It seems to me that the conservative * approach is to report the number of high res pics left. */ @@ -1114,7 +1108,7 @@ if (verbose) printf ("%s: determine_limits: low_i = %d, high_i = %d\n", __progna /* * The original dc20ctrl program used a default gamma of 0.35, but I thougt - * 0.45 looks better. In addition, since xscanimage seems to always force + * 0.45 looks better. In addition, since xscanimage seems to always force * a resolution of 0.1, I multiply everything by 10 and make the default * 4.5. */ @@ -1689,8 +1683,8 @@ shoot (int fd) cfsetispeed (&tty_temp, B9600); cfsetospeed (&tty_temp, B9600); - /* - * Apparently there is a bug in the DC20 where the response to + /* + * Apparently there is a bug in the DC20 where the response to * the shoot request is always at 9600. The DC25 does not have * this bug, so we skip this block. */ @@ -1728,7 +1722,7 @@ shoot (int fd) { if (CameraInfo.model == 0x25) { - /* + /* * If we don't put this in, the next read will time out * and return failure. Does the DC-20 need it too? */ @@ -1771,7 +1765,7 @@ erase (int fd) * This block may really apply to the DC20 also, but since I * don't have one, it's hard to say for sure. On the DC25, erase * takes long enought that the read may timeout without returning - * any data before the erase is complete. We let this happen + * any data before the erase is complete. We let this happen * up to 4 times, then give up. */ while (count < 4) @@ -2121,7 +2115,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (dc25_opt_thumbnails) { - /* + /* * DC20 thumbnail are 80x60 grayscale, DC25 * thumbnails are color. */ @@ -2200,7 +2194,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, /* * erase and erase_one are mutually exclusive. If - * this one is turned on, the other must be off + * this one is turned on, the other must be off */ if (dc25_opt_erase && dc25_opt_erase_one) { @@ -2214,7 +2208,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, /* * erase and erase_one are mutually exclusive. If - * this one is turned on, the other must be off + * this one is turned on, the other must be off */ if (dc25_opt_erase_one && dc25_opt_erase) { @@ -2350,7 +2344,7 @@ sane_start (SANE_Handle handle) { /* - * Don't allow picture unless there is room in the + * Don't allow picture unless there is room in the * camera. */ if (CameraInfo.pic_left == 0) @@ -2359,7 +2353,7 @@ sane_start (SANE_Handle handle) return SANE_STATUS_INVAL; } - /* + /* * DC-20 can only change resolution when camer is empty. * DC-25 can do it any time. */ @@ -2403,7 +2397,7 @@ sane_start (SANE_Handle handle) /* * For thumbnails, we can do things right where we - * start the download, and grab the first block + * start the download, and grab the first block * from the camera. The reamining blocks will be * fetched as necessary by sane_read(). */ @@ -2421,7 +2415,7 @@ sane_start (SANE_Handle handle) return SANE_STATUS_INVAL; } - /* + /* * DC20 thumbnail are 80x60 grayscale, DC25 * thumbnails are color. */ @@ -2439,10 +2433,10 @@ sane_start (SANE_Handle handle) { /* * We do something a little messy, and violates the SANE - * philosophy. However, since it is fairly tricky to + * philosophy. However, since it is fairly tricky to * convert the DC2x "comet" files on the fly, we read in * the entire data stream in sane_open(), and use convert_pic - * to convert it to an in-memory pixpmap. Then when + * to convert it to an in-memory pixpmap. Then when * sane_read() is called, we fill the requests from * memory. A good project for me (or some kind volunteer) * would be to rewrite this and move the actual download @@ -2450,7 +2444,7 @@ sane_start (SANE_Handle handle) * this way is that the data comes down pretty fast, and * it helps to dedicate the processor to this task. We * might get serial port overruns if we try to do other - * things at the same time. + * things at the same time. * * Also, as a side note, I was constantly getting serial * port overruns on a 90MHz pentium until I used hdparm @@ -2634,7 +2628,7 @@ sane_read (SANE_Handle __sane_unused__ handle, SANE_Byte * data, int i; int filesize = parms.bytes_per_line * parms.lines; - /* + /* * If outbytes is zero, then this is the first time * we've been called, so update the contrast table. * The formula is something I came up with that has the @@ -2642,10 +2636,10 @@ sane_read (SANE_Handle __sane_unused__ handle, SANE_Byte * data, * 1) It's a smooth curve that provides the effect I wanted * (bright pixels are made brighter, dim pixels are made * dimmer) - * 2) The contrast parameter can be adjusted to provide + * 2) The contrast parameter can be adjusted to provide * different amounts of contrast. * 3) A parameter of 1.0 can be used to pass the data - * through unchanged (but values around 1.75 look + * through unchanged (but values around 1.75 look * a lot better */ if (outbytes == 0) diff --git a/backend/dc25.conf.in b/backend/dc25.conf.in index 33cfd89..af2cfb1 100644 --- a/backend/dc25.conf.in +++ b/backend/dc25.conf.in @@ -18,6 +18,6 @@ port=/dev/ttyS0 ## This works for most UNIX's baud=38400 # Prints some extra information during the init phase. This can be -# handy, but note that printing anything to stderr breaks the saned +# handy, but note that printing anything to stderr breaks the saned # network scanning. #dumpinquiry diff --git a/backend/dc25.h b/backend/dc25.h index fe12f74..b323835 100644 --- a/backend/dc25.h +++ b/backend/dc25.h @@ -43,13 +43,13 @@ 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. + If you do not wish that, delete this exception notice. *************************************************************************** - This file implements a SANE backend for the Kodak DC-25 (and + This file implements a SANE backend for the Kodak DC-25 (and probably the DC-20) digital cameras. THIS IS EXTREMELY ALPHA CODE! - USE AT YOUR OWN RISK!! + USE AT YOUR OWN RISK!! (feedback to: dc25-devel@fales-lorenz.net) @@ -73,7 +73,7 @@ * conversion routine written by YOSHIDA Hideki * * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published + * it under the terms of the GNU General Public License as published * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * @@ -97,7 +97,7 @@ #include #ifndef TRUE -#define TRUE (1==1) +#define TRUE (1==1) #endif #ifndef FALSE @@ -255,7 +255,7 @@ static int read_data (int fd, unsigned char *buf, int sz); static int end_of_data (int fd); -static int set_pixel_rgb (struct pixmap *, int, int, unsigned char, unsigned char, unsigned char); +static int set_pixel_rgb (struct pixmap *, int, int, unsigned char, unsigned char, unsigned char); static struct pixmap *alloc_pixmap (int x, int y, int d); @@ -266,5 +266,3 @@ static int zoom_x (struct pixmap *source, struct pixmap *dest); static int zoom_y (struct pixmap *source, struct pixmap *dest); static int comet_to_pixmap (unsigned char *, struct pixmap *); - - diff --git a/backend/dell1600n_net.c b/backend/dell1600n_net.c index 3586215..c8717d4 100644 --- a/backend/dell1600n_net.c +++ b/backend/dell1600n_net.c @@ -1,47 +1,47 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2006 Jon Chambers - + 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. - + Dell 1600n network scan driver for SANE. - + To debug: SANE_DEBUG_DELL1600N_NET=255 scanimage --verbose 2>scan.errs 1>scan.png */ @@ -136,8 +136,8 @@ struct ScannerState unsigned int m_currentPageBytes;/* number of bytes of current page read (host byte order) */ }; -/* state data for a single page - NOTE: all ints are in host byte order +/* state data for a single page + NOTE: all ints are in host byte order */ struct PageInfo { @@ -199,7 +199,7 @@ static void FinalisePacket (struct ComBuf *pBuf); static int MessageIsComplete (unsigned char *pData, size_t size); /* process a registration broadcast response - \return DeviceRecord pointer on success (caller frees), NULL on failure + \return DeviceRecord pointer on success (caller frees), NULL on failure */ static struct DeviceRecord *ProcessFindResponse (unsigned char *pData, size_t size); @@ -400,7 +400,7 @@ sane_get_devices (const SANE_Device *** device_list, remoteAddr.sin_addr.s_addr = 0xFFFFFFFF; /* broadcast */ if (sendto (sock, queryPacket.m_pBuf, queryPacket.m_used, 0, - &remoteAddr, sizeof (remoteAddr)) == -1) + (struct sockaddr *) &remoteAddr, sizeof (remoteAddr)) == -1) { DBG (1, "Error sending broadcast packet\n"); ret = SANE_STATUS_NO_MEM; @@ -638,7 +638,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) height = pageInfo.m_height; imageSize = width * height * 3; - DBG( 5, "sane_get_parameters: bytes remaining on this page: %d, num pages: %d, size: %dx%d\n", + DBG( 5, "sane_get_parameters: bytes remaining on this page: %d, num pages: %d, size: %dx%d\n", pageInfo.m_bytesRemaining, gOpenScanners[iHandle]->m_numPages, width, @@ -705,7 +705,7 @@ sane_start (SANE_Handle handle) /* determine local IP address */ addrSize = sizeof (myAddr); - if (getsockname (gOpenScanners[iHandle]->m_udpFd, &myAddr, &addrSize)) + if (getsockname (gOpenScanners[iHandle]->m_udpFd, (struct sockaddr *) &myAddr, &addrSize)) { DBG (1, "sane_start: Error getting own IP address\n"); return SANE_STATUS_IO_ERROR; @@ -781,7 +781,7 @@ sane_start (SANE_Handle handle) cleanup: FreeComBuf (&buf); - + return status; } /* sane_start */ @@ -805,7 +805,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, return SANE_STATUS_INVAL; /* check for end of data (no further pages) */ - if ( ( ! gOpenScanners[iHandle]->m_imageData.m_used ) + if ( ( ! gOpenScanners[iHandle]->m_imageData.m_used ) || ( ! gOpenScanners[iHandle]->m_numPages ) ) { /* remove empty page if there are no more cached pages */ @@ -845,7 +845,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, DBG (5, "sane_read: sending %d bytes, image total %d, %d page bytes remaining, %lu total remaining, image: %dx%d\n", dataSize, gOpenScanners[iHandle]->m_bytesRead, pageInfo.m_bytesRemaining , - (unsigned long)(gOpenScanners[iHandle]->m_imageData.m_used - dataSize), + (unsigned long)(gOpenScanners[iHandle]->m_imageData.m_used - dataSize), pageInfo.m_width, pageInfo.m_height); @@ -1037,7 +1037,7 @@ FreeComBuf (struct ComBuf *pBuf) /* add data to a ComBuf struct \return 0 on success, >0 on failure \note If pData is NULL then buffer size will be increased but no copying will take place - \note In case of failure pBuf will be released using FreeComBuf + \note In case of failure pBuf will be released using FreeComBuf */ int AppendToComBuf (struct ComBuf *pBuf, const unsigned char *pData, @@ -1178,7 +1178,7 @@ MessageIsComplete (unsigned char *pData, size_t size) /***********************************************************/ /* process a registration broadcast response - \return struct DeviceRecord pointer on success (caller frees), NULL on failure + \return struct DeviceRecord pointer on success (caller frees), NULL on failure */ struct DeviceRecord * ProcessFindResponse (unsigned char *pData, size_t size) @@ -1730,7 +1730,7 @@ ProcessTcpResponse (struct ScannerState *pState, struct ComBuf *pTcpBuf) } /* if */ } /* while */ - /* process page data if required */ + /* process page data if required */ if ( bProcessImage ) errorCheck |= ProcessPageData (pState); cleanup: @@ -1824,10 +1824,10 @@ ProcessPageData (struct ScannerState *pState) jpegCinfo.m_cinfo.src = &jpegSrcMgr; jpegCinfo.m_bytesRemaining = pState->m_buf.m_used; jpegCinfo.m_pData = pState->m_buf.m_pBuf; - + jpeg_read_header (&jpegCinfo.m_cinfo, TRUE); jpeg_start_decompress (&jpegCinfo.m_cinfo); - + /* allocate space for a single scanline */ scanLineSize = jpegCinfo.m_cinfo.output_width * jpegCinfo.m_cinfo.output_components; diff --git a/backend/dell1600n_net.conf.in b/backend/dell1600n_net.conf.in index 35d4eae..615549b 100644 --- a/backend/dell1600n_net.conf.in +++ b/backend/dell1600n_net.conf.in @@ -10,5 +10,3 @@ #named_scanner: printer #named_scanner: 192.168.0.20 #named_scanner: myscanner.somewhere.else.org - - diff --git a/backend/dll.c b/backend/dll.c index 5eaa046..8f0983d 100644 --- a/backend/dll.c +++ b/backend/dll.c @@ -42,7 +42,7 @@ allows managing an arbitrary number of SANE backends by using dynamic linking to load backends on demand. */ -/* Please increase version number with every change +/* Please increase version number with every change (don't forget to update dll.desc) */ #define DLL_VERSION "1.0.13" @@ -353,7 +353,7 @@ load (struct backend *be) image_id id = -1; int i, w; directory_which which[3] = { B_USER_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY }; - + /* look for config files in SANE/conf */ for (w = 0; (w < 3) && (id < 0) && (find_directory(which[w],0,true,path,PATH_MAX) == 0); w++) { @@ -373,7 +373,7 @@ load (struct backend *be) continue; /* try next path */ } be->handle=(void *)id; - + for (i = 0; i < NUM_OPS; ++i) { void *(*op) (); @@ -492,7 +492,7 @@ load (struct backend *be) break; DBG (4, "load: couldn't open `%s' (%s)\n", libname, strerror (errno)); -#ifdef ALT_POSTFIX +#ifdef ALT_POSTFIX /* Some platforms have two ways of storing their libraries, try both postfixes */ snprintf (libname, sizeof (libname), "%s/" PREFIX "%s" ALT_POSTFIX, @@ -882,7 +882,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) char path[1024]; directory_which which[3] = { B_USER_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY }; int i; -#endif +#endif DBG_INIT (); @@ -934,7 +934,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) } fclose (fp); -#else +#else /* no ugly config files, just get scanners from their ~/config/add-ons/SANE */ /* look for drivers */ for (i = 0; i < 3; i++) @@ -943,13 +943,13 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) continue; strcat(path,"/SANE/"); dir=opendir(path); - if(!dir) continue; + if(!dir) continue; while((dirent=readdir(dir))) { if((strcmp(dirent->d_name,".")==0) || (strcmp(dirent->d_name,"..")==0)) continue; if((strcmp(dirent->d_name,"dll")==0)) continue; - add_backend(dirent->d_name,0); + add_backend(dirent->d_name,0); } closedir(dir); } @@ -1155,7 +1155,8 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) SANE_Status sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) { - const char *be_name, *dev_name; + char *be_name; + const char *dev_name; struct meta_scanner *s; SANE_Handle handle; struct backend *be; @@ -1178,16 +1179,7 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) dev_name = strchr (full_name, ':'); if (dev_name) { -#ifdef strndupa - be_name = strndupa (full_name, dev_name - full_name); -#else - char *tmp; - - tmp = alloca (dev_name - full_name + 1); - memcpy (tmp, full_name, dev_name - full_name); - tmp[dev_name - full_name] = '\0'; - be_name = tmp; -#endif + be_name = strndup(full_name, dev_name - full_name); ++dev_name; /* skip colon */ } else @@ -1195,10 +1187,13 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) /* if no colon interpret full_name as the backend name; an empty backend device name will cause us to open the first device of that backend. */ - be_name = full_name; + be_name = strdup(full_name); dev_name = ""; } + if (!be_name) + return SANE_STATUS_NO_MEM; + if (!be_name[0]) be = first_backend; else @@ -1210,8 +1205,12 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) { status = add_backend (be_name, &be); if (status != SANE_STATUS_GOOD) - return status; + { + free(be_name); + return status; + } } + free(be_name); if (!be->inited) { diff --git a/backend/dll.conf.in b/backend/dll.conf.in index 3ee5428..8d459ab 100644 --- a/backend/dll.conf.in +++ b/backend/dll.conf.in @@ -73,6 +73,7 @@ plustek #pnm qcam ricoh +ricoh2 rts8891 s9036 sceptre diff --git a/backend/dmc.c b/backend/dmc.c index c5c57c4..ddc76c3 100644 --- a/backend/dmc.c +++ b/backend/dmc.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. Copyright (C) 1998 David F. Skoll - Heavily based on "hp.c" driver for HP Scanners, by + Heavily based on "hp.c" driver for HP Scanners, by David Mosberger-Tang. This file is part of the SANE package. @@ -425,7 +425,7 @@ DMCInitOptions(DMC_Camera *c) c->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; c->opt[OPT_TL_X].constraint.range = &c->tl_x_range; c->val[OPT_TL_X].w = c->tl_x_range.min; - + /* top-left y */ c->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; c->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; @@ -435,7 +435,7 @@ DMCInitOptions(DMC_Camera *c) c->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; c->opt[OPT_TL_Y].constraint.range = &c->tl_y_range; c->val[OPT_TL_Y].w = c->tl_y_range.min; - + /* bottom-right x */ c->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; c->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; @@ -445,7 +445,7 @@ DMCInitOptions(DMC_Camera *c) c->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; c->opt[OPT_BR_X].constraint.range = &c->br_x_range; c->val[OPT_BR_X].w = c->br_x_range.min; - + /* bottom-right y */ c->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; c->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; @@ -485,7 +485,7 @@ DMCInitOptions(DMC_Camera *c) c->opt[OPT_SHUTTER_SPEED].constraint_type = SANE_CONSTRAINT_RANGE; c->opt[OPT_SHUTTER_SPEED].constraint.range = &c->hw->shutterSpeedRange; c->val[OPT_SHUTTER_SPEED].w = c->hw->shutterSpeed; - + c->opt[OPT_WHITE_BALANCE].name = "whitebalance"; c->opt[OPT_WHITE_BALANCE].title = "White Balance"; c->opt[OPT_WHITE_BALANCE].desc = "Selects white balance"; @@ -618,7 +618,7 @@ DMCSetASA(int fd, unsigned int asa) if (i > ASA_100+1) return SANE_STATUS_INVAL; - status = DMCRead(fd, 0x87, 0x4, exposureCalculationResults, + status = DMCRead(fd, 0x87, 0x4, exposureCalculationResults, sizeof(exposureCalculationResults), &len); if (status != SANE_STATUS_GOOD) return status; if (len < sizeof(exposureCalculationResults)) return SANE_STATUS_IO_ERROR; @@ -647,7 +647,7 @@ DMCSetWhiteBalance(int fd, int mode) size_t len; DBG(3, "DMCSetWhiteBalance: %d\n", mode); - status = DMCRead(fd, 0x82, 0x0, userInterfaceSettings, + status = DMCRead(fd, 0x82, 0x0, userInterfaceSettings, sizeof(userInterfaceSettings), &len); if (status != SANE_STATUS_GOOD) return status; if (len < sizeof(userInterfaceSettings)) return SANE_STATUS_IO_ERROR; @@ -749,7 +749,7 @@ DMCReadTwoSuperResolutionLines(DMC_Camera *c, SANE_Byte *buf, int lastLine) greenCoeff = ADVANCE_COEFF(greenCoeff); blueCoeff = ADVANCE_COEFF(blueCoeff); } - + /* Do the next super-resolution line and interpolate vertically */ if (lastLine) { memcpy(buf+BYTES_PER_RAW_LINE*3, buf, BYTES_PER_RAW_LINE*3); @@ -868,7 +868,7 @@ sane_exit(void) free(dev); dev = next; } - + if (devlist) free (devlist); } @@ -1103,7 +1103,7 @@ sane_control_option(SANE_Handle handle, SANE_Int option, if (c->val[OPT_SHUTTER_SPEED].w != * (SANE_Int *) val) { if (info) *info |= SANE_INFO_INEXACT; } - + return SANE_STATUS_GOOD; default: @@ -1328,7 +1328,7 @@ sane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len) *len = max_len; return SANE_STATUS_GOOD; } - + if (c->imageMode == IMAGE_MFI || c->imageMode == IMAGE_RAW) { /* We have to read complete rows... */ max_len = (max_len / c->params.bytes_per_line) * c->params.bytes_per_line; diff --git a/backend/epjitsu-cmd.h b/backend/epjitsu-cmd.h index 40a5c1a..b71c7b0 100644 --- a/backend/epjitsu-cmd.h +++ b/backend/epjitsu-cmd.h @@ -720,4 +720,3 @@ static unsigned char setWindowScan_S1100_600_U[] = { 0x00, 0x80, 0x80, 0x01, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; - diff --git a/backend/epjitsu.c b/backend/epjitsu.c index ce79a20..bee4310 100644 --- a/backend/epjitsu.c +++ b/backend/epjitsu.c @@ -1,7 +1,7 @@ /* sane - Scanner Access Now Easy. This file implements a SANE backend for the Fujitsu fi-60F, the - ScanSnap S300/S1300, and (hopefully) other Epson-based scanners. + ScanSnap S300/S1300, and (hopefully) other Epson-based scanners. Copyright 2007-2015 by m. allan noah Copyright 2009 by Richard Goedeken @@ -174,7 +174,7 @@ . . - sane_start() : start image acquisition . . - sane_get_parameters() : returns actual scan parameters . . - sane_read() : read image data (from pipe) - . . (sane_read called multiple times; after sane_read returns EOF, + . . (sane_read called multiple times; after sane_read returns EOF, . . loop may continue with sane_start which may return a 2nd page . . when doing duplex scans, or load the next page from the ADF) . . @@ -218,7 +218,7 @@ unsigned char global_firmware_filename[PATH_MAX]; - function trace 10 - function detail 15 - get/setopt cmds 20 - - usb cmd trace 25 + - usb cmd trace 25 - usb cmd detail 30 - useless noise 35 */ @@ -253,7 +253,7 @@ static struct scanner *scanner_devList = NULL; /* * Called by SANE initially. - * + * * From the SANE spec: * This function must be called before any other SANE function can be * called. The behavior of a SANE backend is undefined if this @@ -271,21 +271,21 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) DBG_INIT (); DBG (10, "sane_init: start\n"); - + if (version_code) *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD); - + DBG (5, "sane_init: epjitsu backend %d.%d.%d, from %s\n", SANE_CURRENT_MAJOR, V_MINOR, BUILD, PACKAGE_STRING); DBG (10, "sane_init: finish\n"); - + return SANE_STATUS_GOOD; } /* * Called by SANE to find out about supported devices. - * + * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a @@ -298,7 +298,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. - * + * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and @@ -318,36 +318,36 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) FILE *fp; int num_devices=0; int i=0; - + local_only = local_only; /* get rid of compiler warning */ - + DBG (10, "sane_get_devices: start\n"); - + /* mark all existing scanners as missing, attach_one will remove mark */ for (s = scanner_devList; s; s = s->next) { s->missing = 1; } sanei_usb_init(); - + fp = sanei_config_open (CONFIG_FILE); - + if (fp) { - + DBG (15, "sane_get_devices: reading config file %s\n", CONFIG_FILE); - + while (sanei_config_read (line, PATH_MAX, fp)) { - + lp = line; /* ignore comments */ if (*lp == '#') continue; - + /* skip empty lines */ if (*lp == 0) continue; - + if ((strncmp ("firmware", lp, 8) == 0) && isspace (lp[8])) { lp += 8; lp = sanei_config_skip_whitespace (lp); @@ -364,7 +364,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) } fclose (fp); } - + else { DBG (5, "sane_get_devices: no config file '%s'!\n", CONFIG_FILE); @@ -374,7 +374,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) for (s = scanner_devList; s;) { if(s->missing){ DBG (5, "sane_get_devices: missing scanner %s\n",s->sane.name); - + /*splice s out of list by changing pointer in prev to next*/ if(prev){ prev->next = s->next; @@ -387,7 +387,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) s = s->next; free(prev); prev=NULL; - + /*reset head to next s*/ scanner_devList = s; } @@ -397,21 +397,21 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) s=prev->next; } } - + for (s = scanner_devList; s; s=s->next) { DBG (15, "sane_get_devices: found scanner %s\n",s->sane.name); num_devices++; } - + DBG (15, "sane_get_devices: found %d scanner(s)\n",num_devices); if (sane_devArray) free (sane_devArray); - + sane_devArray = calloc (num_devices + 1, sizeof (SANE_Device*)); if (!sane_devArray) return SANE_STATUS_NO_MEM; - + for (s = scanner_devList; s; s=s->next) { sane_devArray[i++] = (SANE_Device *)&s->sane; } @@ -420,24 +420,24 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) if(device_list){ *device_list = sane_devArray; } - + DBG (10, "sane_get_devices: finish\n"); - + return ret; } /* callback used by sane_init - * build the scanner struct and link to global list - * unless struct is already loaded, then pretend + * build the scanner struct and link to global list + * unless struct is already loaded, then pretend */ static SANE_Status attach_one (const char *name) { struct scanner *s; int ret, i; - + DBG (10, "attach_one: start '%s'\n", name); - + for (s = scanner_devList; s; s = s->next) { if (strcmp (s->sane.name, name) == 0) { DBG (10, "attach_one: already attached!\n"); @@ -445,30 +445,30 @@ attach_one (const char *name) return SANE_STATUS_GOOD; } } - + /* build a scanner struct to hold it */ DBG (15, "attach_one: init struct\n"); - + if ((s = calloc (sizeof (*s), 1)) == NULL) return SANE_STATUS_NO_MEM; - + /* copy the device name */ s->sane.name = strdup (name); if (!s->sane.name){ destroy(s); return SANE_STATUS_NO_MEM; } - + /* connect the fd */ DBG (15, "attach_one: connect fd\n"); - + s->fd = -1; ret = connect_fd(s); if(ret != SANE_STATUS_GOOD){ destroy(s); return ret; } - + /* load the firmware file into scanner */ ret = load_fw(s); if (ret != SANE_STATUS_GOOD) { @@ -487,7 +487,7 @@ attach_one (const char *name) DBG (15, "attach_one: Found %s scanner %s at %s\n", s->sane.vendor, s->sane.model, s->sane.name); - + if (strstr (s->sane.model, "S1300i")){ unsigned char stat; @@ -498,7 +498,7 @@ attach_one (const char *name) DBG (5, "attach_one: on USB power?\n"); s->usb_power=1; } - + s->model = MODEL_S1300i; s->has_adf = 1; @@ -530,7 +530,7 @@ attach_one (const char *name) DBG (5, "attach_one: on USB power?\n"); s->usb_power=1; } - + s->model = MODEL_S300; s->has_adf = 1; @@ -624,13 +624,13 @@ attach_one (const char *name) else{ DBG (15, "attach_one: Found other\n"); } - + /* set SANE option 'values' to good defaults */ DBG (15, "attach_one: init options\n"); - - /* go ahead and setup the first opt, because - * frontend may call control_option on it - * before calling get_option_descriptor + + /* go ahead and setup the first opt, because + * frontend may call control_option on it + * before calling get_option_descriptor */ memset (s->opt, 0, sizeof (s->opt)); for (i = 0; i < NUM_OPTIONS; ++i) { @@ -638,23 +638,23 @@ attach_one (const char *name) s->opt[i].size = sizeof (SANE_Word); s->opt[i].cap = SANE_CAP_INACTIVE; } - + s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; - + DBG (15, "attach_one: init settings\n"); ret = change_params(s); /* we close the connection, so that another backend can talk to scanner */ disconnect_fd(s); - + s->next = scanner_devList; scanner_devList = s; - + DBG (10, "attach_one: finish\n"); - + return SANE_STATUS_GOOD; } @@ -665,9 +665,9 @@ static SANE_Status connect_fd (struct scanner *s) { SANE_Status ret; - + DBG (10, "connect_fd: start\n"); - + if(s->fd > -1){ DBG (5, "connect_fd: already open\n"); ret = SANE_STATUS_GOOD; @@ -676,13 +676,13 @@ connect_fd (struct scanner *s) DBG (15, "connect_fd: opening USB device\n"); ret = sanei_usb_open (s->sane.name, &(s->fd)); } - + if(ret != SANE_STATUS_GOOD){ DBG (5, "connect_fd: could not open device: %d\n", ret); } - + DBG (10, "connect_fd: finish\n"); - + return ret; } @@ -701,7 +701,7 @@ load_fw (struct scanner *s) size_t cmdLen; unsigned char stat[2]; size_t statLen; - + DBG (10, "load_fw: start\n"); /*check status*/ @@ -712,7 +712,7 @@ load_fw (struct scanner *s) DBG (5, "load_fw: firmware already loaded?\n"); return SANE_STATUS_GOOD; } - + if(!global_firmware_filename[0]){ DBG (5, "load_fw: missing filename\n"); return SANE_STATUS_NO_DOCS; @@ -757,7 +757,7 @@ load_fw (struct scanner *s) cmd[1] = 0x06; cmdLen = 2; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -774,14 +774,14 @@ load_fw (struct scanner *s) free(buf); return SANE_STATUS_IO_ERROR; } - + /*length/data*/ cmd[0] = 0x01; cmd[1] = 0x00; cmd[2] = 0x01; cmd[3] = 0x00; cmdLen = 4; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -803,7 +803,7 @@ load_fw (struct scanner *s) cmdLen = 1; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -818,13 +818,13 @@ load_fw (struct scanner *s) DBG (5, "load_fw: bad stat on cmd 3\n"); return SANE_STATUS_IO_ERROR; } - + /*reinit*/ cmd[0] = 0x1b; cmd[1] = 0x16; cmdLen = 2; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -843,7 +843,7 @@ load_fw (struct scanner *s) cmd[0] = 0x80; cmdLen = 1; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -882,7 +882,7 @@ get_stat(struct scanner *s) size_t cmdLen; unsigned char stat[2]; size_t statLen; - + DBG (10, "get_stat: start\n"); /*check status*/ @@ -890,7 +890,7 @@ get_stat(struct scanner *s) cmd[1] = 0x03; cmdLen = 2; statLen = 2; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -928,7 +928,7 @@ get_ident(struct scanner *s) NULL, 0, in, &inLen ); - + if (ret != SANE_STATUS_GOOD){ return ret; } @@ -945,7 +945,7 @@ get_ident(struct scanner *s) s->sane.model= strndup((char *)in+8, 24); s->sane.type = "scanner"; - + DBG (10, "get_ident: finish\n"); return ret; } @@ -965,7 +965,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) struct scanner *dev = NULL; struct scanner *s = NULL; SANE_Status ret; - + DBG (10, "sane_open: start\n"); if(scanner_devList){ @@ -973,13 +973,13 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) } else{ DBG (15, "sane_open: no scanners currently attached, attaching\n"); - + ret = sane_get_devices(NULL,0); if(ret != SANE_STATUS_GOOD){ return ret; } } - + if(name[0] == 0){ DBG (15, "sane_open: no device requested, using default\n"); s = scanner_devList; @@ -994,24 +994,24 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) } } } - + if (!s) { DBG (5, "sane_open: no device found\n"); return SANE_STATUS_INVAL; } - + DBG (15, "sane_open: device %s found\n", s->sane.name); - + *handle = s; - + /* connect the fd so we can talk to scanner */ ret = connect_fd(s); if(ret != SANE_STATUS_GOOD){ return ret; } - + DBG (10, "sane_open: finish\n"); - + return SANE_STATUS_GOOD; } @@ -1086,7 +1086,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->mode_list[i++]=STRING_GRAYSCALE; s->mode_list[i++]=STRING_COLOR; s->mode_list[i]=NULL; - + opt->name = SANE_NAME_SCAN_MODE; opt->title = SANE_TITLE_SCAN_MODE; opt->desc = SANE_DESC_SCAN_MODE; @@ -1130,7 +1130,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->tl_x_range.min = SCANNER_UNIT_TO_FIXED_MM(0); s->tl_x_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_width(s)-s->min_x); s->tl_x_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_TL_X; opt->title = SANE_TITLE_SCAN_TL_X; opt->desc = SANE_DESC_SCAN_TL_X; @@ -1149,7 +1149,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->tl_y_range.min = SCANNER_UNIT_TO_FIXED_MM(0); s->tl_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s)-s->min_y); s->tl_y_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_TL_Y; opt->title = SANE_TITLE_SCAN_TL_Y; opt->desc = SANE_DESC_SCAN_TL_Y; @@ -1167,7 +1167,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->br_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x); s->br_x_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_width(s)); s->br_x_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_BR_X; opt->title = SANE_TITLE_SCAN_BR_X; opt->desc = SANE_DESC_SCAN_BR_X; @@ -1186,7 +1186,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->br_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y); s->br_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s)); s->br_y_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_BR_Y; opt->title = SANE_TITLE_SCAN_BR_Y; opt->desc = SANE_DESC_SCAN_BR_Y; @@ -1377,7 +1377,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_adf) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -1389,7 +1389,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_adf) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -1401,7 +1401,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_adf) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -1413,7 +1413,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_adf) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -1425,7 +1425,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_adf) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -1434,7 +1434,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /** * Gets or sets an option value. - * + * * From the SANE spec: * This function is used to set or inquire the current value of option * number n of the device represented by handle h. The manner in which @@ -1445,7 +1445,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) * area pointed to by v must be big enough to hold the entire option * value (determined by member size in the corresponding option * descriptor). - * + * * The only exception to this rule is that when setting the value of a * string option, the string pointed to by argument v may be shorter * since the backend will stop reading the option value upon @@ -1574,22 +1574,22 @@ sane_control_option (SANE_Handle handle, SANE_Int option, get_hardware_status(s); *val_p = s->hw_scan_sw; return SANE_STATUS_GOOD; - + case OPT_HOPPER: get_hardware_status(s); *val_p = s->hw_hopper; return SANE_STATUS_GOOD; - + case OPT_TOP: get_hardware_status(s); *val_p = s->hw_top; return SANE_STATUS_GOOD; - + case OPT_ADF_OPEN: get_hardware_status(s); *val_p = s->hw_adf_open; return SANE_STATUS_GOOD; - + case OPT_SLEEP: get_hardware_status(s); *val_p = s->hw_sleep; @@ -1630,7 +1630,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, * below. */ switch (option) { - + /* Mode Group */ case OPT_SOURCE: if (!strcmp (val, STRING_ADFFRONT)) { @@ -1766,7 +1766,7 @@ static void update_transfer_totals(struct transfer * t) { if (t->image == NULL) return; - + t->total_bytes = t->line_stride * t->image->height; t->rx_bytes = 0; t->done = 0; @@ -1810,7 +1810,7 @@ static struct model_res settings[] = { /*S300 AC*/ /* model mode xres yres u mxx mnx mxy mny lin_s pln_s pln_w bh cls cps cpw */ - { MODEL_S300, MODE_COLOR, 150, 150, 0, 1296, 32, 2662, 32, 4256*3, 1480*3, 1296, 41, 8512*3, 2960*3, 2592, + { MODEL_S300, MODE_COLOR, 150, 150, 0, 1296, 32, 2662, 32, 4256*3, 1480*3, 1296, 41, 8512*3, 2960*3, 2592, setWindowCoarseCal_S300_150, setWindowFineCal_S300_150, setWindowSendCal_S300_150, sendCal1Header_S300_150, sendCal2Header_S300_150, setWindowScan_S300_150 }, @@ -2056,7 +2056,7 @@ change_params(struct scanner *s) s->page_width = s->min_x; s->tl_x = (s->max_x - s->page_width)/2; s->br_x = (s->max_x + s->page_width)/2; - + /*=============================================================*/ /* set up the calibration scan structs */ /* generally full width, short height, full resolution */ @@ -2102,7 +2102,7 @@ change_params(struct scanner *s) s->sendcal.y_res = settings[i].y_res; s->sendcal.pages = img_pages; s->sendcal.buffer = NULL; - + /*=============================================================*/ /* set up the fullscan parameters */ /* this is bookkeeping for what we actually pull from the scanner */ @@ -2230,7 +2230,7 @@ change_params(struct scanner *s) s->pages[SIDE_BACK].done = 0; DBG (10, "change_params: finish\n"); - + return ret; } @@ -2238,7 +2238,7 @@ change_params(struct scanner *s) used by scanners to implement brightness/contrast/gamma or by backends to speed binarization/thresholding - offset and slope inputs are -127 to +127 + offset and slope inputs are -127 to +127 slope rotates line around central input/output val, 0 makes horizontal line @@ -2254,9 +2254,9 @@ change_params(struct scanner *s) offset moves line vertically, and clamps to output range 0 keeps the line crossing the center of the table - high low + high low . xxxxxxxx . - . x . + . x . out x . x . . x ............ xxxxxxxx.... @@ -2285,7 +2285,7 @@ load_lut (unsigned char * lut, * 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 + * 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; @@ -2332,7 +2332,7 @@ load_lut (unsigned char * lut, * completion of that request. Outside of that window, the returned * values are best-effort estimates of what the parameters will be * when sane_start() gets invoked. - * + * * Calling this function before a scan has actually started allows, * for example, to get an estimate of how big the scanned image will * be. The parameters passed to this function are the handle h of the @@ -2389,9 +2389,9 @@ sane_start (SANE_Handle handle) struct scanner *s = handle; SANE_Status ret; int i; - + DBG (10, "sane_start: start\n"); - + /* set side marker on first page */ if(!s->started){ if(s->source == SOURCE_ADF_BACK){ @@ -2462,7 +2462,7 @@ sane_start (SANE_Handle handle) sane_cancel((SANE_Handle)s); return ret; } - + ret = finecal(s); if (ret != SANE_STATUS_GOOD) { DBG (5, "sane_start: ERROR: failed to finecal\n"); @@ -2476,14 +2476,14 @@ sane_start (SANE_Handle handle) sane_cancel((SANE_Handle)s); return ret; } - + ret = lamp(s,1); if (ret != SANE_STATUS_GOOD) { DBG (5, "sane_start: ERROR: failed to heat lamp\n"); sane_cancel((SANE_Handle)s); return ret; } - + /*should this be between each page*/ ret = set_window(s,WINDOW_SCAN); if (ret != SANE_STATUS_GOOD) { @@ -2491,7 +2491,7 @@ sane_start (SANE_Handle handle) sane_cancel((SANE_Handle)s); return ret; } - + } /* reset everything when starting any front, or just back */ @@ -2503,7 +2503,7 @@ sane_start (SANE_Handle handle) s->fullscan.done = 0; s->fullscan.rx_bytes = 0; s->fullscan.total_bytes = s->fullscan.width_bytes * s->fullscan.height; - + /* reset block */ update_transfer_totals(&s->block_xfr); @@ -2532,7 +2532,7 @@ sane_start (SANE_Handle handle) } DBG (10, "sane_start: finish\n"); - + return SANE_STATUS_GOOD; } @@ -2644,7 +2644,7 @@ coarsecal_send_cal(struct scanner *s, unsigned char *pay) unsigned char cmd[2]; unsigned char stat[1]; size_t cmdLen,statLen,payLen; - + DBG (5, "coarsecal_send_cal: start\n"); /* send coarse cal (c6) */ cmd[0] = 0x1b; @@ -2652,7 +2652,7 @@ coarsecal_send_cal(struct scanner *s, unsigned char *pay) cmdLen = 2; stat[0] = 0; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -2667,7 +2667,7 @@ coarsecal_send_cal(struct scanner *s, unsigned char *pay) DBG (5, "coarsecal_send_cal: cmd bad c6 status?\n"); return SANE_STATUS_IO_ERROR; } - + /*send coarse cal payload*/ stat[0] = 0; statLen = 1; @@ -2708,7 +2708,7 @@ coarsecal_get_line(struct scanner *s, struct image *img) cmdLen = 2; stat[0] = 0; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -2726,7 +2726,7 @@ coarsecal_get_line(struct scanner *s, struct image *img) s->cal_image.image = img; update_transfer_totals(&s->cal_image); - + while(!s->cal_image.done){ ret = read_from_scanner(s,&s->cal_image); if(ret){ @@ -2782,7 +2782,7 @@ coarsecal_dark(struct scanner *s, unsigned char *pay) } ret = coarsecal_send_cal(s, pay); - + DBG(15, "coarsecal_dark offset: parameter front: %i back: %i\n", param[0], param[1]); ret = coarsecal_get_line(s, &s->coarsecal); @@ -2857,7 +2857,7 @@ coarsecal_light(struct scanner *s, unsigned char *pay) return ret; } - try_count = 8; + try_count = 8; param[0] = pay[11]; param[1] = pay[13]; low_param[0] = low_param[1] = 0; @@ -2872,7 +2872,7 @@ coarsecal_light(struct scanner *s, unsigned char *pay) DBG(15, "coarsecal_light gain: parameter front: %i back: %i\n", param[0], param[1]); ret = coarsecal_get_line(s, &s->coarsecal); - + /* gather statistics: count the proportion of 255-valued pixels in each color channel */ /* count the average pixel value in each color channel */ for (i = 0; i < s->coarsecal.pages; i++) @@ -3119,7 +3119,7 @@ finecal_send_cal(struct scanner *s) /*second unknown cal block*/ cmd[1] = 0xc4; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -3441,13 +3441,13 @@ lamp(struct scanner *s, unsigned char set) size_t cmdLen = 2; unsigned char stat[1]; size_t statLen = 1; - + DBG (10, "lamp: start (%d)\n", set); /*send cmd*/ cmd[0] = 0x1b; cmd[1] = 0xd0; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -3467,7 +3467,7 @@ lamp(struct scanner *s, unsigned char set) cmd[0] = set; cmdLen = 1; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -3542,7 +3542,7 @@ set_window(struct scanner *s, int window) /*send payload*/ statLen = 1; - + ret = do_cmd( s, 0, payload, paylen, @@ -3565,7 +3565,7 @@ set_window(struct scanner *s, int window) /* instead of internal brightness/contrast/gamma scanners uses 12bit x 12bit LUT default is linear table of slope 1 - brightness and contrast inputs are -127 to +127 + brightness and contrast inputs are -127 to +127 contrast rotates slope of line around central input val @@ -3581,7 +3581,7 @@ set_window(struct scanner *s, int window) bright dark . xxxxxxxx . - . x . + . x . out x . x . . x ............ xxxxxxxx.... @@ -3598,12 +3598,12 @@ send_lut (struct scanner *s) size_t statLen = 1; unsigned char *out; size_t outLen; - + int i, j; double b, slope, offset; int width; int height; - + DBG (10, "send_lut: start\n"); if (s->model == MODEL_S1100){ @@ -3630,7 +3630,7 @@ send_lut (struct scanner *s) * first [-127,127] to [0,254] then to [0,1] * then multiply by PI/2 to convert to radians * then take the tangent to get slope (T.O.A) - * then multiply by the normal linear slope + * then multiply by the normal linear slope * because the table may not be square, i.e. 1024x256*/ slope = tan(((double)s->contrast+127)/254 * M_PI/2); @@ -3642,17 +3642,17 @@ send_lut (struct scanner *s) * into a scale that covers the range required * to slide the contrast curve entirely off the table */ b = ((double)s->brightness/127) * (slope*(width-1) + offset); - + DBG (15, "send_lut: %d %f %d %f %f\n", s->brightness, b, s->contrast, slope, offset); - + for(i=0;i(height-1)){ j=height-1; } @@ -3675,7 +3675,7 @@ send_lut (struct scanner *s) out[width*4 + i*2] = (j >> 8) & 0xff; out[width*4 + i*2+1] = j & 0xff; } - else { + else { /*first table, le order*/ out[i*2] = j & 0xff; out[i*2+1] = (j >> 8) & 0x0f; @@ -3745,7 +3745,7 @@ get_hardware_status (struct scanner *s) cmd[0] = 0x1b; cmd[1] = 0x33; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -3790,12 +3790,12 @@ object_position(struct scanner *s, int ingest) i = (ingest)?5:1; - while(i--){ + while(i--){ /*send paper load cmd*/ cmd[0] = 0x1b; cmd[1] = 0xd4; statLen = 1; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -3810,12 +3810,12 @@ object_position(struct scanner *s, int ingest) DBG (5, "object_position: cmd bad status? %d\n",stat[0]); continue; } - + /*send payload*/ statLen = 1; payLen = 1; pay[0] = ingest; - + ret = do_cmd( s, 0, pay, payLen, @@ -3853,7 +3853,7 @@ scan(struct scanner *s) size_t cmdLen = 2; unsigned char stat[1]; size_t statLen = 1; - + DBG (10, "scan: start\n"); if(s->model == MODEL_S300 || s->model == MODEL_S1100 || s->model == MODEL_S1300i){ @@ -3876,13 +3876,13 @@ scan(struct scanner *s) } DBG (10, "scan: finish\n"); - + return ret; } /* * Called by SANE to read data. - * + * * From the SANE spec: * This function is used to read image data from the device * represented by handle h. Argument buf is a pointer to a memory @@ -3890,7 +3890,7 @@ scan(struct scanner *s) * returned is stored in *len. A backend must set this to zero when * the call fails (i.e., when a status other than SANE_STATUS_GOOD is * returned). - * + * * When the call succeeds, the number of bytes returned can be * anywhere in the range from 0 to maxlen bytes. */ @@ -3900,7 +3900,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len struct scanner *s = (struct scanner *) handle; SANE_Status ret=SANE_STATUS_GOOD; struct page * page; - + DBG (10, "sane_read: start si:%d len:%d max:%d\n",s->side,*len,max_len); *len = 0; @@ -3910,7 +3910,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len DBG (5, "sane_read: call sane_start first\n"); return SANE_STATUS_CANCELLED; } - + page = &s->pages[s->side]; /* have sent all of current buffer */ @@ -3920,14 +3920,14 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len /*S1100 needs help to turn off button*/ if(s->model == MODEL_S1100){ usleep(15000); - + /* eject paper */ ret = object_position(s,EPJITSU_PAPER_EJECT); if (ret != SANE_STATUS_GOOD && ret != SANE_STATUS_NO_DOCS) { DBG (5, "sane_read: ERROR: failed to eject\n"); return ret; } - + /* reset flashing button? */ ret = six5(s); if (ret != SANE_STATUS_GOOD) { @@ -3937,12 +3937,12 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len } return SANE_STATUS_EOF; - } + } /* scan not finished, get more into block buffer */ if(!s->fullscan.done) { - /* block buffer currently empty, clean up */ + /* block buffer currently empty, clean up */ if(!s->block_xfr.rx_bytes) { /* block buffer bigger than remainder of scan, shrink block */ @@ -3959,9 +3959,9 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len size_t cmdLen = 2; unsigned char stat[1]; size_t statLen = 1; - + DBG (15, "sane_read: d3\n"); - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -4002,7 +4002,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len size_t cmdLen = 2; unsigned char in[10]; size_t inLen = 10; - + ret = do_cmd( s, 0, cmd, cmdLen, @@ -4010,7 +4010,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len in, &inLen ); hexdump(15, "cmd 43: ", in, inLen); - + if(ret){ DBG (5, "sane_read: error sending 43 cmd\n"); return ret; @@ -4076,19 +4076,19 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len if(*len){ DBG (10, "sane_read: copy rx:%d tx:%d tot:%d len:%d\n", page->bytes_scanned, page->bytes_read, page->bytes_total,*len); - + memcpy(buf, page->image->buffer + page->bytes_read, *len); page->bytes_read += *len; - + /* sent it all, return eof on next read */ if(page->bytes_read == page->bytes_scanned && s->fullscan.done){ DBG (10, "sane_read: side done\n"); page->done = 1; } - } + } DBG (10, "sane_read: finish si:%d len:%d max:%d\n",s->side,*len,max_len); - + return ret; } @@ -4152,39 +4152,39 @@ descramble_raw(struct scanner *s, struct transfer * tp) for (j = 0; j < height; j++){ /* row (y)*/ int curr_col = 0; int r=0, g=0, b=0, ppc=0; - + for (k = 0; k <= tp->plane_width; k++){ /* column (x) */ int this_col = k*tp->image->x_res/tp->x_res; - + /* going to change output pixel, dump rgb and reset */ if(ppc && curr_col != this_col){ *p_out = r/ppc; p_out++; - + *p_out = g/ppc; p_out++; - + *p_out = b/ppc; p_out++; - + r = g = b = ppc = 0; - + curr_col = this_col; } - + if(k == tp->plane_width || this_col >= tp->image->width_pix){ break; } - + /*red is first*/ r += tp->raw_data[j*tp->line_stride + k*3 + i]; - + /*green is second*/ g += tp->raw_data[j*tp->line_stride + tp->plane_stride + k*3 + i]; - + /*blue is third*/ b += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k*3 + i]; - + ppc++; } } @@ -4194,39 +4194,39 @@ descramble_raw(struct scanner *s, struct transfer * tp) for (j = 0; j < height; j++){ /* row (y)*/ int curr_col = 0; int r=0, g=0, b=0, ppc=0; - + for (k = 0; k <= tp->plane_width; k++){ /* column (x) */ int this_col = k*tp->image->x_res/tp->x_res; - + /* going to change output pixel, dump rgb and reset */ if(ppc && curr_col != this_col){ *p_out = r/ppc; p_out++; - + *p_out = g/ppc; p_out++; - + *p_out = b/ppc; p_out++; - + r = g = b = ppc = 0; - + curr_col = this_col; } - + if(k == tp->plane_width || this_col >= tp->image->width_pix){ break; } /*red is second*/ r += tp->raw_data[j*tp->line_stride + tp->plane_stride + k]; - + /*green is third*/ g += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k]; - + /*blue is first*/ b += tp->raw_data[j*tp->line_stride + k]; - + ppc++; } } @@ -4238,39 +4238,39 @@ descramble_raw(struct scanner *s, struct transfer * tp) for (i = 0; i < 3; i++){ /* read head */ int r=0, g=0, b=0, ppc=0; - + for (k = 0; k <= tp->plane_width; k++){ /* column (x) within the read head */ int this_col = (k+i*tp->plane_width)*tp->image->x_res/tp->x_res; - + /* going to change output pixel, dump rgb and reset */ if(ppc && curr_col != this_col){ *p_out = r/ppc; p_out++; - + *p_out = g/ppc; p_out++; - + *p_out = b/ppc; p_out++; - + r = g = b = ppc = 0; - + curr_col = this_col; } - + if(k == tp->plane_width || this_col >= tp->image->width_pix){ break; } - + /*red is first*/ r += tp->raw_data[j*tp->line_stride + k*3 + i]; - + /*green is second*/ g += tp->raw_data[j*tp->line_stride + tp->plane_stride + k*3 + i]; - + /*blue is third*/ b += tp->raw_data[j*tp->line_stride + 2*tp->plane_stride + k*3 + i]; - + ppc++; } } @@ -4297,15 +4297,15 @@ descramble_raw_gray(struct scanner *s, struct transfer * tp) if (s->model == MODEL_FI60F || s->model == MODEL_FI65F) { for (row = 0; row < height; row++){ - + unsigned char *p_in = tp->raw_data + row * tp->line_stride; unsigned char *p_out = tp->image->buffer + row * tp->image->width_pix; - + for (col_out = 0; col_out < tp->image->width_pix; col_out++){ int col_in = col_out * tp->x_res/tp->image->x_res; int offset = col_in%tp->plane_width; int step = col_in/tp->plane_width; - + *p_out = *(p_in + offset*3 + step); p_out++; } @@ -4388,12 +4388,12 @@ read_from_scanner(struct scanner *s, struct transfer * tp) else { DBG(5, "read_from_scanner: error reading status = %d\n", ret); } - + free(buf); DBG (10, "read_from_scanner: finish rB:%lu len:%lu\n", (unsigned long)(tp->total_bytes - tp->rx_bytes + 8), (unsigned long)bytes); - + return ret; } @@ -4439,7 +4439,7 @@ copy_block_to_page(struct scanner *s,int side) int this_out_row = (this_in_row - page->image->y_skip_offset) * page->image->y_res / s->fullscan.y_res; DBG (15, "copy_block_to_page: in %d out %d lastout %d\n", this_in_row, this_out_row, last_out_row); DBG (15, "copy_block_to_page: bs %d wb %d\n", page->bytes_scanned, page->image->width_bytes); - + /* don't walk off the end of the output buffer */ if(this_out_row >= page->image->height || this_out_row < 0){ DBG (10, "copy_block_to_page: out of space? %d\n", side); @@ -4447,7 +4447,7 @@ copy_block_to_page(struct scanner *s,int side) page->bytes_scanned, page->bytes_read, page->bytes_total,page->image->width_bytes); return ret; } - + /* ok, different output row, so we do the math */ if(this_out_row > last_out_row){ @@ -4459,11 +4459,11 @@ copy_block_to_page(struct scanner *s,int side) last_out_row = this_out_row; if (block->mode == MODE_COLOR){ - + /* reverse order for back side or FI-60F scanner */ if (line_reverse) p_in += (page_width - 1) * 3; - + /* convert all of the pixels in this row */ for (j = 0; j < page_width; j++) { @@ -4492,18 +4492,18 @@ copy_block_to_page(struct scanner *s,int side) p_in += 3; } } - + /* grayscale input */ else{ unsigned char * p_in = block->image->buffer + (side * block_page_stride) + (i * block->image->width_bytes) + page->image->x_start_offset; - + /* reverse order for back side or FI-60F scanner */ if (line_reverse) p_in += (page_width - 1); - + //memcpy(p_out,p_in,page->image->width_bytes); - + for (j = 0; j < page_width; j++) { if (s->mode == MODE_GRAYSCALE) @@ -4570,7 +4570,7 @@ binarize_line(struct scanner *s, unsigned char *lineOut, int width) { int addCol = j + windowX/2; int dropCol = addCol - windowX; - + if (dropCol >= 0 && addCol < width) { sum -= s->dt.buffer[dropCol]; @@ -4584,7 +4584,7 @@ binarize_line(struct scanner *s, unsigned char *lineOut, int width) *lineOut &= ~mask; /* white */ else *lineOut |= mask; /* black */ - + if (offset == 7) lineOut++; } @@ -4596,7 +4596,7 @@ binarize_line(struct scanner *s, unsigned char *lineOut, int width) * @@ Section 4 - SANE cleanup functions */ /* - * Cancels a scan. + * Cancels a scan. * * From the SANE spec: * This function is used to immediately or as quickly as possible @@ -4626,7 +4626,7 @@ sane_cancel (SANE_Handle handle) /* * Ends use of the scanner. - * + * * From the SANE spec: * This function terminates the association between the device handle * passed in argument h and the device it represents. If the device is @@ -4684,7 +4684,7 @@ destroy(struct scanner *s) if(s->sane.model){ free((void *) s->sane.model); } - + free(s); DBG (10, "destroy: finish\n"); @@ -4758,7 +4758,7 @@ teardown_buffers(struct scanner *s) /* * Terminates the backend. - * + * * From the SANE spec: * This function must be called to terminate use of a backend. The * function will first close all device handles that still might be @@ -4828,13 +4828,13 @@ do_cmd(struct scanner *s, int shortTime, /* change timeout */ sanei_usb_set_timeout(cmdTime); - + /* write the command out */ DBG(25, "cmd: writing %ld bytes, timeout %d\n", (long)cmdLen, cmdTime); hexdump(30, "cmd: >>", cmdBuff, cmdLen); ret = sanei_usb_write_bulk(s->fd, cmdBuff, &cmdLen); DBG(25, "cmd: wrote %ld bytes, retVal %d\n", (long)cmdLen, ret); - + if(ret == SANE_STATUS_EOF){ DBG(5,"cmd: got EOF, returning IO_ERROR\n"); return SANE_STATUS_IO_ERROR; @@ -4993,7 +4993,7 @@ sane_get_select_fd (SANE_Handle h, SANE_Int *fdp) * due to using FB */ static int -get_page_width(struct scanner *s) +get_page_width(struct scanner *s) { /* scanner max for fb */ if(s->source == SOURCE_FLATBED){ @@ -5009,7 +5009,7 @@ get_page_width(struct scanner *s) * due to using FB. */ static int -get_page_height(struct scanner *s) +get_page_height(struct scanner *s) { /* scanner max for fb */ if(s->source == SOURCE_FLATBED){ @@ -5018,4 +5018,3 @@ get_page_height(struct scanner *s) return s->page_height; } - diff --git a/backend/epjitsu.conf.in b/backend/epjitsu.conf.in index 3ba1c15..4dc9dfc 100644 --- a/backend/epjitsu.conf.in +++ b/backend/epjitsu.conf.in @@ -12,7 +12,7 @@ # extracted from the Fujitsu Windows driver. Presumably the Mac versions # contain the firmware as well, but the author has no access such a machine. -# Firmware is installed in several different locations by the fujitsu software, +# Firmware is installed in several different locations by the fujitsu software, # using the windows 'search' feature to look for '*.nal' is the easiest way to # find them. They should be ~65K, and have the scanner's name as part of the # file name. They are often inside a .cab file. @@ -80,4 +80,3 @@ usb 0x04c5 0x128d # Fujitsu S1100i firmware @DATADIR@/sane/epjitsu/1100i_0A00.nal usb 0x04c5 0x1447 - diff --git a/backend/epjitsu.h b/backend/epjitsu.h index 6dfaf67..87d6836 100644 --- a/backend/epjitsu.h +++ b/backend/epjitsu.h @@ -1,12 +1,12 @@ #ifndef EPJITSU_H #define EPJITSU_H -/* +/* * Part of SANE - Scanner Access Now Easy. * Please see opening comment in epjitsu.c */ -/* ------------------------------------------------------------------------- +/* ------------------------------------------------------------------------- * This option list has to contain all options for all scanners supported by * this driver. If a certain scanner cannot handle a certain option, there's * still the possibility to say so, later. @@ -197,7 +197,7 @@ struct scanner unsigned char * setWindowScan; /* sent before scan */ size_t setWindowScanLen; - + /* --------------------------------------------------------------------- */ /* values which are set by scanning functions to keep track of pages, etc */ int started; diff --git a/backend/epson.c b/backend/epson.c index 3fc264f..20cafc4 100644 --- a/backend/epson.c +++ b/backend/epson.c @@ -1,4 +1,4 @@ -/* +/* epson.c - SANE library for Epson flatbed scanners. Based on Kazuhiro Sasayama previous @@ -63,7 +63,7 @@ 2006-08-21 Fix buffer overflow error (submitted by Johannes Meixner) 2006-06-11 Applied patch from Henning. Fixed a number of compiler warnings 2006-03-12 Added support for perfetion 4990 photo 4800 dpi - 2005-01-09 "flaming hack to get USB scanners working without timeouts under linux" + 2005-01-09 "flaming hack to get USB scanners working without timeouts under linux" submitted by "Steve" (in comment to bug #300830) 2004-12-18 Added USB IDs for CX-4600 and CX-3650 2004-10-16 Added USB ID for Expression 10000XL @@ -78,7 +78,7 @@ Added EPSON Kowa copyright message 2003-08-15 Added support for GT-30000, with support for the ADF in simplex mode Borrowed some code from the EPSON Kowa IScan version of the backend - Use sanei_scsi_cmd2() to send commands. This makes this backend + Use sanei_scsi_cmd2() to send commands. This makes this backend useable for SBP-2 under FreeBSD 2003-05-11 Initialize OPT_LIMIT_RESOLUTION before first call to filter_resolution_list() Fix memory problem in get_identity_information(). Both problems were @@ -88,14 +88,14 @@ 2003-02-15 Move sanei_usb_init() to sane_init(). Thanks to Ron Cemer for providing the patch. 2003-02-15 Fix problem with "usb syntax in config file - 2002-12-28 Added advanced option to display only short resolution list for + 2002-12-28 Added advanced option to display only short resolution list for displays that can not show the complete list. 2002-11-23 Fixed problem with dropout color. 2002-11-03 Full libusb support. 2002-10-05 Fixed problem with incorrect response to sane_get_parameters() in certain situations. 2002-09-01 USB scanners are now using libsane-usb funtions - 2002-08-17 Fixed typo in variable name. + 2002-08-17 Fixed typo in variable name. Fixed IEEE-1394 problem with Perfection-2450. Fixed problem with older B3 level SCSI scanners that do not support the extended status request. @@ -104,12 +104,12 @@ 2002-04-13 Check if scanner needs to be opened for the reset call. (Thanks to Thomas Wenrich for pointing this out) Added product IDs for Perfection 1650 and 2450 - 2002-01-18 Recognize GT-xxxx type scanners also when using the SCSI + 2002-01-18 Recognize GT-xxxx type scanners also when using the SCSI or IEEE-1394 interface 2002-01-06 Disable TEST_IOCTL again, which was enabled by accident. Also protect the ioctl portion with an #ifdef __linux__ 2002-01-05 Version 0.2.17 - Check for and set s->fd to -1 when device is closed. + Check for and set s->fd to -1 when device is closed. Removed black gamma table - only use RGB even for grayscale 2002-01-01 Do not call access() for OS/2 systems 2001-11-13 Version 0.2.16 @@ -126,8 +126,8 @@ 2001-06-09 Version 0.2.09 Changed debug level for sense handler from 0 to 2 2001-05-25 Version 0.2.07 - Allow more than 8 bit color depth even for preview mode - since Xsane can handle this. Some code cleanup. + Allow more than 8 bit color depth even for preview mode + since Xsane can handle this. Some code cleanup. 2001-05-24 Removed ancient code that was used to determine the resolution back when the backend still had a slider for the resolution selection. @@ -156,12 +156,12 @@ Fixed problem with bilevel scanning with Perfection610: The line count has to be an even number with this scanner. Several initialization fixes regarding bit depth selection. - This version goes back into the CVS repository, the 1.0.4 + This version goes back into the CVS repository, the 1.0.4 release is out and therefore the code freeze is over. Some general cleanup, added more comments. 2000-12-09 Version 0.2.00 Cleaned up printing of gamma table data. 16 elements - are now printed in one line without the [epson] in + are now printed in one line without the [epson] in between the values. Values are only printed for Debug levels >= 10. 2000-12-04 We've introduced the concept of inverting images @@ -175,7 +175,7 @@ 2000-12-03 added the 12/14/16 bit support again. 2000-12-03 Version 0.1.38 removed changes regarding 12/14 bit support because - of SANE feature freeze for 1.0.4. The D1 fix for + of SANE feature freeze for 1.0.4. The D1 fix for reading the values from the scanner instead of using hardcoded values and the fix for the off-by-one error in the reorder routine are still in the code base. @@ -194,13 +194,13 @@ sane/... include files. 2000-07-26 Fixed problem with Perfection610: The variable s->color_shuffle_line was never correctly initialized - 2000-06-28 When closing the scanner device the data that's + 2000-06-28 When closing the scanner device the data that's still in the scanner, waiting to be transferred is flushed. This fixes the problem with scanimage -T 2000-06-13 Invert image when scanning negative with TPU, Show film type only when TPU is selected 2000-06-13 Initialize optical_res to 0 (Dave Hill) - 2000-06-07 Fix in sane_close() - found by Henning Meier-Geinitz + 2000-06-07 Fix in sane_close() - found by Henning Meier-Geinitz 2000-06-01 Threshhold should only be active when scan depth is 1 and halftoning is off. (mjp) 2000-05-28 Turned on scanner based color correction. @@ -212,16 +212,16 @@ Help prevent extraneous option reloads. Split sane_control_option in getvalue and setvalue. Further split up setvalue into several different - routines. (mjp) - 2000-05-21 In sane_close use close_scanner instead of just the + routines. (mjp) + 2000-05-21 In sane_close use close_scanner instead of just the SCSI close function. 2000-05-20 ... finally fixed the problem with the 610 Added resolution_list to Epson_Device structure in - epson.h - this fixes a bug that caused problems when + epson.h - this fixes a bug that caused problems when more than one EPSON scanner was connected. 2000-05-13 Fixed the color problem with the Perfection 610. The few lines with "garbage" at the beginning of the scan are not - yet removed. + yet removed. 2000-05-06 Added support for multiple EPSON scanners. At this time this may not be bug free, but it's a start and it seems to work well with just one scanner. @@ -235,21 +235,21 @@ fix an OS/2 bug. It now turned out that they are not necessary. The real fix was in the repository for a long time (2000-01-25). - 2000-03-19 Fixed problem with A4 level devices - they use the - line mode instead of the block mode. The routine to - handle this was screwed up pretty bad. Now I have + 2000-03-19 Fixed problem with A4 level devices - they use the + line mode instead of the block mode. The routine to + handle this was screwed up pretty bad. Now I have a solid version that handles all variations of line mode (automatically deals with the order the color lines are sent). 2000-03-06 Fixed occasional crash after warm up when the "in warmup state" went away in between doing ESC G and getting the - extended status message. - 2000-03-02 Code cleanup, disabled ZOOM until I have time to + extended status message. + 2000-03-02 Code cleanup, disabled ZOOM until I have time to deal with all the side effects. 2000-03-01 More D1 fixes. In the future I have to come up with a more elegant solution to destinguish between different function levels. The level > n does not work anymore with - D1. + D1. Added support for "set threshold" and "set zoom". 2000-02-23 First stab at level D1 support, also added a test for valid "set halftone" command to enable OPT_HALFTONE @@ -275,11 +275,11 @@ because of hte changes to attach a few days ago. (KHK) 2000-01-29 fixed core dump with xscanimage by moving the gamma curves to the standard interface (no longer advanced) - Removed pragma pack() from source code to make it + Removed pragma pack() from source code to make it easier to compile on non-gcc compilers (KHK) 2000-01-26 fixed problem with resolution selection when using the resolution list in xsane (KHK) - 2000-01-25 moved the section where the device name is assigned + 2000-01-25 moved the section where the device name is assigned in attach. This avoids the core dump of frontend applications when no scanner is found (Dave Hill) 2000-01-24 reorganization of SCSI related "helper" functions @@ -395,7 +395,7 @@ #define EPSON_LEVEL_D7 12 #define EPSON_LEVEL_D8 13 -/* there is also a function level "A5", which I'm igoring here until somebody can +/* there is also a function level "A5", which I'm igoring here until somebody can convince me that this is still needed. The A5 level was for the GT-300, which was (is) a monochrome only scanner. So if somebody really wants to use this scanner with SANE get in touch with me and we can work something out - khk */ @@ -437,7 +437,7 @@ static EpsonCmdRec epson_cmd[] = { * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | set bay * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | set threshold * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | set focus position - * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | request focus position + * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | request focus position * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | */ @@ -460,7 +460,7 @@ static EpsonCmdRec epson_cmd[] = { /* - * Definition of the mode_param struct, that is used to + * Definition of the mode_param struct, that is used to * specify the valid parameters for the different scan modes. * * The depth variable gets updated when the bit depth is modified. @@ -508,10 +508,10 @@ static const SANE_String_Const adf_mode_list[] = { * of the scanner. */ -static SANE_String_Const source_list[] = { - FBF_STR, - NULL, - NULL, +static SANE_String_Const source_list[] = { + FBF_STR, + NULL, + NULL, NULL }; @@ -519,9 +519,9 @@ static SANE_String_Const source_list[] = { #define FILM_TYPE_POSITIVE (0) #define FILM_TYPE_NEGATIVE (1) -static const SANE_String_Const film_list[] = { - SANE_I18N ("Positive Film"), - SANE_I18N ("Negative Film"), +static const SANE_String_Const film_list[] = { + SANE_I18N ("Positive Film"), + SANE_I18N ("Negative Film"), NULL }; @@ -538,67 +538,67 @@ static const SANE_String_Const focus_list[] = { #define HALFTONE_NONE 0x01 #define HALFTONE_TET 0x03 -static int halftone_params[] = { - HALFTONE_NONE, - 0x00, - 0x10, - 0x20, - 0x80, - 0x90, - 0xa0, - 0xb0, +static int halftone_params[] = { + HALFTONE_NONE, + 0x00, + 0x10, + 0x20, + 0x80, + 0x90, + 0xa0, + 0xb0, HALFTONE_TET, - 0xc0, + 0xc0, 0xd0 }; -static const SANE_String_Const halftone_list[] = { - SANE_I18N ("None"), +static const SANE_String_Const halftone_list[] = { + SANE_I18N ("None"), SANE_I18N ("Halftone A (Hard Tone)"), - SANE_I18N ("Halftone B (Soft Tone)"), + SANE_I18N ("Halftone B (Soft Tone)"), SANE_I18N ("Halftone C (Net Screen)"), NULL }; -static const SANE_String_Const halftone_list_4[] = { - SANE_I18N ("None"), +static const SANE_String_Const halftone_list_4[] = { + SANE_I18N ("None"), SANE_I18N ("Halftone A (Hard Tone)"), - SANE_I18N ("Halftone B (Soft Tone)"), + SANE_I18N ("Halftone B (Soft Tone)"), SANE_I18N ("Halftone C (Net Screen)"), SANE_I18N ("Dither A (4x4 Bayer)"), SANE_I18N ("Dither B (4x4 Spiral)"), SANE_I18N ("Dither C (4x4 Net Screen)"), - SANE_I18N ("Dither D (8x4 Net Screen)"), + SANE_I18N ("Dither D (8x4 Net Screen)"), NULL }; -static const SANE_String_Const halftone_list_7[] = { - SANE_I18N ("None"), +static const SANE_String_Const halftone_list_7[] = { + SANE_I18N ("None"), SANE_I18N ("Halftone A (Hard Tone)"), - SANE_I18N ("Halftone B (Soft Tone)"), + SANE_I18N ("Halftone B (Soft Tone)"), SANE_I18N ("Halftone C (Net Screen)"), SANE_I18N ("Dither A (4x4 Bayer)"), SANE_I18N ("Dither B (4x4 Spiral)"), SANE_I18N ("Dither C (4x4 Net Screen)"), SANE_I18N ("Dither D (8x4 Net Screen)"), - SANE_I18N ("Text Enhanced Technology"), + SANE_I18N ("Text Enhanced Technology"), SANE_I18N ("Download pattern A"), - SANE_I18N ("Download pattern B"), + SANE_I18N ("Download pattern B"), NULL }; -static int dropout_params[] = { +static int dropout_params[] = { 0x00, /* none */ 0x10, /* red */ 0x20, /* green */ 0x30 /* blue */ }; -static const SANE_String_Const dropout_list[] = { - SANE_I18N ("None"), - SANE_I18N ("Red"), +static const SANE_String_Const dropout_list[] = { + SANE_I18N ("None"), + SANE_I18N ("Red"), SANE_I18N ("Green"), - SANE_I18N ("Blue"), + SANE_I18N ("Blue"), NULL }; @@ -606,34 +606,34 @@ static const SANE_String_Const dropout_list[] = { * Color correction: * One array for the actual parameters that get sent to the scanner (color_params[]), * one array for the strings that get displayed in the user interface (color_list[]) - * and one array to mark the user defined color correction (dolor_userdefined[]). + * and one array to mark the user defined color correction (dolor_userdefined[]). */ -static int color_params[] = { - 0x00, - 0x01, - 0x10, - 0x20, - 0x40, +static int color_params[] = { + 0x00, + 0x01, + 0x10, + 0x20, + 0x40, 0x80 }; -static SANE_Bool color_userdefined[] = { - SANE_FALSE, - SANE_TRUE, - SANE_FALSE, - SANE_FALSE, - SANE_FALSE, +static SANE_Bool color_userdefined[] = { + SANE_FALSE, + SANE_TRUE, + SANE_FALSE, + SANE_FALSE, + SANE_FALSE, SANE_FALSE }; -static const SANE_String_Const color_list[] = { - SANE_I18N ("No Correction"), +static const SANE_String_Const color_list[] = { + SANE_I18N ("No Correction"), SANE_I18N ("User defined"), - SANE_I18N ("Impact-dot printers"), + SANE_I18N ("Impact-dot printers"), SANE_I18N ("Thermal printers"), SANE_I18N ("Ink-jet printers"), - SANE_I18N ("CRT monitors"), + SANE_I18N ("CRT monitors"), NULL }; @@ -644,20 +644,20 @@ static const SANE_String_Const color_list[] = { * the actally used params and list arrays at runtime. */ -static int gamma_params_ab[] = { - 0x01, - 0x03, - 0x00, - 0x10, +static int gamma_params_ab[] = { + 0x01, + 0x03, + 0x00, + 0x10, 0x20 }; -static const SANE_String_Const gamma_list_ab[] = { - SANE_I18N ("Default"), +static const SANE_String_Const gamma_list_ab[] = { + SANE_I18N ("Default"), SANE_I18N ("User defined"), - SANE_I18N ("High density printing"), + SANE_I18N ("High density printing"), SANE_I18N ("Low density printing"), - SANE_I18N ("High contrast printing"), + SANE_I18N ("High contrast printing"), NULL }; @@ -669,14 +669,14 @@ static SANE_Bool gamma_userdefined_ab[] = { SANE_FALSE, }; -static int gamma_params_d[] = { - 0x03, +static int gamma_params_d[] = { + 0x03, 0x04 }; -static const SANE_String_Const gamma_list_d[] = { +static const SANE_String_Const gamma_list_d[] = { SANE_I18N ("User defined (Gamma=1.0)"), - SANE_I18N ("User defined (Gamma=1.8)"), + SANE_I18N ("User defined (Gamma=1.8)"), NULL }; @@ -701,13 +701,13 @@ static unsigned int w_cmd_count = 0; * this is used for the FilmScan */ -static const SANE_String_Const bay_list[] = { - " 1 ", - " 2 ", - " 3 ", - " 4 ", - " 5 ", - " 6 ", +static const SANE_String_Const bay_list[] = { + " 1 ", + " 2 ", + " 3 ", + " 4 ", + " 5 ", + " 6 ", NULL }; @@ -744,7 +744,7 @@ struct qf_param }; /* gcc don't like to overwrite const field */ -static /*const */ struct qf_param qf_params[] = { +static /*const */ struct qf_param qf_params[] = { {0, 0, SANE_FIX (120.0), SANE_FIX (120.0)}, {0, 0, SANE_FIX (148.5), SANE_FIX (210.0)}, {0, 0, SANE_FIX (210.0), SANE_FIX (148.5)}, @@ -753,13 +753,13 @@ static /*const */ struct qf_param qf_params[] = { {0, 0, 0, 0} }; -static const SANE_String_Const qf_list[] = { - SANE_I18N ("CD"), - SANE_I18N ("A5 portrait"), +static const SANE_String_Const qf_list[] = { + SANE_I18N ("CD"), + SANE_I18N ("A5 portrait"), SANE_I18N ("A5 landscape"), - SANE_I18N ("Letter"), - SANE_I18N ("A4"), - SANE_I18N ("Max"), + SANE_I18N ("Letter"), + SANE_I18N ("A4"), + SANE_I18N ("Max"), NULL }; @@ -770,7 +770,7 @@ static SANE_Word *bitDepthList = NULL; /* * List of pointers to devices - will be dynamically allocated depending - * on the number of devices found. + * on the number of devices found. */ static const SANE_Device **devlist = 0; @@ -1199,10 +1199,10 @@ set_resolution (Epson_Scanner * s, int xres, int yres) } /* - * set_scan_area() + * set_scan_area() * - * Sends the "set scan area" command to the scanner with the currently selected - * scan area. This scan area is already corrected for "color shuffling" if + * Sends the "set scan area" command to the scanner with the currently selected + * scan area. This scan area is already corrected for "color shuffling" if * necessary. */ static SANE_Status @@ -1472,7 +1472,7 @@ DetectSize: * is reported as a warning (only visible if debug level is set to 10 or greater) - * every other condition is reported as an error. * - * This function only gets called when we are dealing with a scanner that supports the + * This function only gets called when we are dealing with a scanner that supports the * "warming up" code, so it's not a problem for B3 level scanners, that don't handle * request extended status commands. */ @@ -1650,7 +1650,7 @@ close_scanner (Epson_Scanner * s) if (s->fd == -1) return; - if (r_cmd_count % 2) + if (r_cmd_count % 2) { /* send a request_status. This toggles w_cmd_count and r_cmd_count */ u_char param[3]; @@ -1668,7 +1668,7 @@ close_scanner (Epson_Scanner * s) DBG (5, "w_cmd_count = %d\n",w_cmd_count); DBG (5, "r_cmd_count = %d\n",r_cmd_count); - if (w_cmd_count % 2) + if (w_cmd_count % 2) { int junk1,junk2; @@ -1700,8 +1700,8 @@ close_scanner (Epson_Scanner * s) /* * open_scanner() * - * Open the scanner device. Depending on the connection method, - * different open functions are called. + * Open the scanner device. Depending on the connection method, + * different open functions are called. */ static SANE_Status @@ -1798,7 +1798,7 @@ feed (Epson_Scanner * s) /* * eject() - * + * * Eject the current page from the ADF. The scanner is opened prior to * sending the command and closed afterwards. * @@ -2011,7 +2011,7 @@ attach (const char *dev_name, Epson_Device * *devp, int type) } /* check for PIO devices */ - /* can we convert the device name to an integer? This is only possible + /* can we convert the device name to an integer? This is only possible with PIO devices */ port = atoi (dev_name); if (port != 0) @@ -2088,7 +2088,7 @@ attach (const char *dev_name, Epson_Device * *devp, int type) buf[INQUIRY_BUF_SIZE] = 0; DBG (1, ">%s<\n", buf + 8); - /* + /* * For USB and PIO scanners this will be done later, once * we have communication established with the device. */ @@ -2140,7 +2140,7 @@ attach (const char *dev_name, Epson_Device * *devp, int type) status = sanei_usb_find_devices (vendor, product, attach_one_usb); } - return SANE_STATUS_INVAL; /* return - the attach_one_usb() + return SANE_STATUS_INVAL; /* return - the attach_one_usb() will take care of this */ } @@ -2179,7 +2179,7 @@ attach (const char *dev_name, Epson_Device * *devp, int type) is_valid = SANE_FALSE; i = 0; - /* check all known product IDs to verify that we know + /* check all known product IDs to verify that we know about the device */ while (i != numIds && !is_valid) { @@ -2287,7 +2287,7 @@ attach (const char *dev_name, Epson_Device * *devp, int type) /* - * Check for "request focus position" command. If this command is + * Check for "request focus position" command. If this command is * supported, then the scanner does also support the "set focus * position" command. */ @@ -2350,10 +2350,10 @@ attach (const char *dev_name, Epson_Device * *devp, int type) * this also requests the scanner device name from the scanner */ /* - * because we are also using the device name from this command, + * because we are also using the device name from this command, * we have to run this block even if the scanner does not report * an extension. The extensions are only reported if the ADF or - * the TPU are actually detected. + * the TPU are actually detected. */ if (s->hw->cmd->request_extended_status != 0) { @@ -2493,7 +2493,7 @@ attach (const char *dev_name, Epson_Device * *devp, int type) SANE_FIX ((buf[10] << 8 | buf[9]) * 25.4 / dev->dpi_range.max); dev->tpu_y_range.quant = 0; - /* + /* * Check for Perfection 4990 photo/GT-X800 scanner. * This scanner only report 3200 dpi back. * The scanner fysical supports 4800 dpi. @@ -2503,11 +2503,11 @@ attach (const char *dev_name, Epson_Device * *devp, int type) */ if (strncmp((char *) buf + 0x1A,"GT-X800",7) == 0) { - dev->tpu_x_range.max = (dev->tpu_x_range.max/32)*48; - dev->tpu_y_range.max = (dev->tpu_y_range.max/32)*48; + dev->tpu_x_range.max = (dev->tpu_x_range.max/32)*48; + dev->tpu_y_range.max = (dev->tpu_y_range.max/32)*48; DBG (5, "dpi_range.max %x \n", dev->dpi_range.max); } - + DBG (5, "tpu tlx %f tly %f brx %f bry %f [mm]\n", SANE_UNFIX (dev->tpu_x_range.min), SANE_UNFIX (dev->tpu_y_range.min), @@ -2597,8 +2597,8 @@ attach (const char *dev_name, Epson_Device * *devp, int type) close_scanner (s); - /* - * we are done with this one, prepare for the next scanner: + /* + * we are done with this one, prepare for the next scanner: */ ++num_devices; @@ -2689,7 +2689,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { int numIds; - /* add the vendor and product IDs to the list of + /* add the vendor and product IDs to the list of known devices before we call the attach function */ numIds = sanei_epson_getNumberOfUSBProductIds (); if (vendor != 0x4b8) @@ -2723,7 +2723,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /* * void sane_exit(void) * - * Clean up the list of attached scanners. + * Clean up the list of attached scanners. */ void @@ -2914,11 +2914,11 @@ init_options (Epson_Scanner * s) s->opt[OPT_GAMMA_CORRECTION].type = SANE_TYPE_STRING; s->opt[OPT_GAMMA_CORRECTION].constraint_type = SANE_CONSTRAINT_STRING_LIST; - /* + /* * special handling for D1 function level - at this time I'm not * testing for D1, I'm just assuming that all D level scanners will * behave the same way. This has to be confirmed with the next D-level - * scanner + * scanner */ if (s->hw->cmd->level[0] == 'D') { @@ -2944,7 +2944,7 @@ init_options (Epson_Scanner * s) /* gamma vector */ -/* +/* s->opt[ OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; s->opt[ OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; s->opt[ OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR; @@ -3585,7 +3585,7 @@ sane_close (SANE_Handle handle) Epson_Scanner *s, *prev; /* - * Test if there is still data pending from + * Test if there is still data pending from * the scanner. If so, then do a cancel */ @@ -3828,14 +3828,14 @@ handle_source (Epson_Scanner * s, SANE_Int optindex, char *value) Handles setting the source (flatbed, transparency adapter (TPU), or auto document feeder (ADF)). - For newer scanners it also sets the focus according to the + For newer scanners it also sets the focus according to the glass / TPU settings. */ { int force_max = SANE_FALSE; SANE_Bool dummy; - /* reset the scanner when we are changing the source setting - + /* reset the scanner when we are changing the source setting - this is necessary for the Perfection 1650 */ if (s->hw->need_reset_on_source_change) reset (s); @@ -4237,7 +4237,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) DBG (5, "sane_get_parameters()\n"); - /* + /* * If sane_start was already called, then just retrieve the parameters * from the scanner data structure */ @@ -4275,7 +4275,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) s->params.lines = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w) / 25.4 * ndpi + 0.5; - /* + /* * Make sure that the number of lines is correct for color shuffling: * The shuffling alghorithm produces 2xline_distance lines at the * beginning and the same amount at the end of the scan that are not @@ -4302,10 +4302,10 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) SANE_UNFIX (s->val[OPT_BR_Y].w)); - /* - * Calculate bytes_per_pixel and bytes_per_line for + /* + * Calculate bytes_per_pixel and bytes_per_line for * any color depths. - * + * * The default color depth is stored in mode_params.depth: */ @@ -4320,8 +4320,8 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) if (s->params.depth > 8) { - s->params.depth = 16; /* - * The frontends can only handle 8 or 16 bits + s->params.depth = 16; /* + * The frontends can only handle 8 or 16 bits * for gray or color - so if it's more than 8, * it gets automatically set to 16. This works * as long as EPSON does not come out with a @@ -4366,7 +4366,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) /* * sane_start() * - * This function is part of the SANE API and gets called from the front end to + * This function is part of the SANE API and gets called from the front end to * start the scan process. * */ @@ -4396,7 +4396,7 @@ sane_start (SANE_Handle handle) * off 0 ACK * off 1 NAK * - * It makes no sense to scan with TPU powered on and source flatbed, because + * It makes no sense to scan with TPU powered on and source flatbed, because * light will come from both sides. */ @@ -4447,7 +4447,7 @@ sane_start (SANE_Handle handle) } - /* + /* * set the focus position according to the extension used: * if the TPU is selected, then focus 2.5mm above the glass, * otherwise focus on the glass. Scanners that don't support @@ -4499,7 +4499,7 @@ sane_start (SANE_Handle handle) } /* - * The byte sequence mode was introduced in B5, for B[34] we need line sequence mode + * The byte sequence mode was introduced in B5, for B[34] we need line sequence mode */ if ((s->hw->cmd->level[0] == 'D' || @@ -4641,7 +4641,7 @@ sane_start (SANE_Handle handle) if (s->hw->cmd->level[0] == 'D') { /* - * The D1 level has only the two user defined gamma + * The D1 level has only the two user defined gamma * settings. */ val = gamma_params[s->val[OPT_GAMMA_CORRECTION].w]; @@ -4652,8 +4652,8 @@ sane_start (SANE_Handle handle) /* * If "Default" is selected then determine the actual value - * to send to the scanner: If bilevel mode, just send the - * value from the table (0x01), for grayscale or color mode + * to send to the scanner: If bilevel mode, just send the + * value from the table (0x01), for grayscale or color mode * add one and send 0x02. */ /* if( s->val[ OPT_GAMMA_CORRECTION].w <= 1) { */ @@ -4766,7 +4766,7 @@ sane_start (SANE_Handle handle) /* - * If WAIT_FOR_BUTTON is active, then do just that: Wait until the button is + * If WAIT_FOR_BUTTON is active, then do just that: Wait until the button is * pressed. If the button was already pressed, then we will get the button * Pressed event right away. */ @@ -4841,8 +4841,8 @@ sane_start (SANE_Handle handle) s->hw->color_shuffle = SANE_FALSE; } -/* - * for debugging purposes: +/* + * for debugging purposes: */ #ifdef FORCE_COLOR_SHUFFLE DBG (1, "Test mode: FORCE_COLOR_SHUFFLE = TRUE\n"); @@ -4850,7 +4850,7 @@ sane_start (SANE_Handle handle) #endif - /* + /* * Modify the scan area: If the scanner requires color shuffling, then we try to * scan more lines to compensate for the lines that will be removed from the scan * due to the color shuffling alghorithm. @@ -4872,7 +4872,7 @@ sane_start (SANE_Handle handle) s->params.lines += 4 * s->line_distance; } - /* + /* * If (top + s->params.lines) is larger than the max scan area, reset * the number of scan lines: */ @@ -4897,7 +4897,7 @@ sane_start (SANE_Handle handle) lcount = 1; /* - * The set line count commands needs to be sent for certain scanners in + * The set line count commands needs to be sent for certain scanners in * color mode. The D1 level requires it, we are however only testing for * 'D' and not for the actual numeric level. */ @@ -5167,7 +5167,7 @@ read_data_block (Epson_Scanner * s, EpsonDataRec * result) /* * Hack Alert!!! - * If the status is SANE_STATUS_DEVICE_BUSY then we need to + * If the status is SANE_STATUS_DEVICE_BUSY then we need to * re-issue the command again. We can assume that the command that * caused this problem was ESC G, so in a loop with a sleep 1 we * are testing this over and over and over again, until the lamp @@ -5319,7 +5319,7 @@ START_READ: */ - /* + /* * read the first color line - the number of bytes to read * is already known (from last call to read_data_block() * We determine where to write the line from the color information @@ -5345,7 +5345,7 @@ START_READ: if (SANE_STATUS_GOOD != status) return status; - /* + /* * send the ACK signal to the scanner in order to make * it ready for the next data block. */ @@ -5484,7 +5484,7 @@ START_READ: */ /* - * Some scaners (e.g. the Perfection 1640 and GT-2200) seem + * Some scaners (e.g. the Perfection 1640 and GT-2200) seem * to have the R and G channels swapped. * The GT-8700 is the Asian version of the Perfection1640. * If the scanner name is one of these, and the scan mode is @@ -5499,9 +5499,9 @@ START_READ: s->params.format == SANE_FRAME_RGB; /* - * Certain Perfection 1650 also need this re-ordering of the two - * color channels. These scanners are identified by the problem - * with the half vertical scanning area. When we corrected this, + * Certain Perfection 1650 also need this re-ordering of the two + * color channels. These scanners are identified by the problem + * with the half vertical scanning area. When we corrected this, * we also set the variable s->hw->need_color_reorder */ if (s->hw->need_color_reorder) @@ -5551,7 +5551,7 @@ START_READ: } } - /* + /* * Do the color_shuffle if everything else is correct - at this time * most of the stuff is hardcoded for the Perfection 610 */ @@ -5562,8 +5562,8 @@ START_READ: status = color_shuffle (s, &new_length); - /* - * If no bytes are returned, check if the scanner is already done, if so, + /* + * If no bytes are returned, check if the scanner is already done, if so, * we'll probably just return, but if there is more data to process get * the next batch. */ @@ -5584,7 +5584,7 @@ START_READ: - /* + /* * copy the image data to the data memory area */ @@ -5689,10 +5689,10 @@ color_shuffle (SANE_Handle handle, int *new_length) /* - * Initialize the variables we are going to use for the + * Initialize the variables we are going to use for the * copying of the data. data_ptr is the pointer to * the currently worked on scan line. data_end is the - * end of the data area as calculated from adding *length + * end of the data area as calculated from adding *length * to the start of data. * out_data_ptr is used when writing out the processed data * and always points to the beginning of the next line to @@ -5709,7 +5709,7 @@ color_shuffle (SANE_Handle handle, int *new_length) /* * The buffer area is supposed to have a number of full scan - * lines, let's test if this is the case. + * lines, let's test if this is the case. */ if (length % s->params.bytes_per_line != 0) @@ -5785,7 +5785,7 @@ color_shuffle (SANE_Handle handle, int *new_length) */ /* - * Strip the first and last n lines and limit to + * Strip the first and last n lines and limit to */ if ((s->current_output_line >= s->line_distance) && (s->current_output_line < s->params.lines + s->line_distance)) @@ -5800,9 +5800,9 @@ color_shuffle (SANE_Handle handle, int *new_length) /* - * Now remove the 0-entry and move all other - * lines up by one. There are 2*line_distance + 1 - * buffers, * therefore the loop has to run from 0 + * Now remove the 0-entry and move all other + * lines up by one. There are 2*line_distance + 1 + * buffers, * therefore the loop has to run from 0 * to * 2*line_distance, and because we want to * copy every n+1st entry to n the loop runs * from - to 2*line_distance-1! @@ -6008,7 +6008,7 @@ get_identity_information (SANE_Handle handle) DBG (1, "maximum scan area: x %d y %d\n", x, y); k = 5; - /* + /* * Check for Perfection 4990 photo/GT-X800 scanner. * This scanner only report 3200 dpi back. * The scanner fysical supports 4800 dpi. @@ -6031,8 +6031,8 @@ get_identity_information (SANE_Handle handle) DBG (1, "product name %x %x %x %x %x %x %x %x \n", buf[0], buf[1],buf[2],buf[3],buf[4], buf[5],buf[6], buf[7] ); if (strncmp((char *) buf,"GT-X800",7) == 0) { - int val = 0x12 << 8 | 0xC0; - + int val = 0x12 << 8 | 0xC0; + s->hw->res_list_size++; s->hw->res_list = (SANE_Int *) realloc (s->hw->res_list, @@ -6169,7 +6169,7 @@ get_identity2_information (SANE_Handle handle) /* * void sane_cancel(SANE_Handle handle) - * + * * Set the cancel flag to true. The next time the backend requests data * from the scanner the CAN message will be sent. */ @@ -6260,7 +6260,7 @@ request_focus_position (SANE_Handle handle, u_char * position) /* - * Request the push button status + * Request the push button status * returns SANE_TRUE if the button was pressed * and SANE_FALSE if the button was not pressed * it also returns SANE_TRUE in case of an error. diff --git a/backend/epson.conf.in b/backend/epson.conf.in index 2cd505f..796541b 100644 --- a/backend/epson.conf.in +++ b/backend/epson.conf.in @@ -16,7 +16,7 @@ scsi "EPSON SC" # There are two different methods of configuring a USB scanner: libusb and the kernel module # For any system with libusb support (which is pretty much any recent Linux distribution) the # following line is sufficient. This however assumes that the connected scanner (or to be more -# accurate, it's device ID) is known to the backend. +# accurate, it's device ID) is known to the backend. usb # For libusb support for unknown scanners use the following command # usb diff --git a/backend/epson2-commands.c b/backend/epson2-commands.c index eccd4ba..836080a 100644 --- a/backend/epson2-commands.c +++ b/backend/epson2-commands.c @@ -199,7 +199,7 @@ round_cct(double org_cct[], int rnd_cct[]) mult_cct[i] = org_cct[i] * 32; rnd_cct[i] = (int) floor(mult_cct[i] + 0.5); } - + do { for (i = 0; i < 3; i++) { @@ -265,8 +265,8 @@ profile_to_colorcoeff(double *profile, unsigned char *color_coeff) for (i = 0; i < 9; i++) color_coeff[i] = int2cpt(color_table[cc_idx[i]]); } - - + + /* * Sends the "set color correction coefficients" command with the * currently selected parameters to the scanner. @@ -825,7 +825,7 @@ esci_request_command_parameter(SANE_Handle handle, unsigned char *buf) return status; } -/* ESC q - Request Focus Position +/* ESC q - Request Focus Position * -> ESC q * <- Information block * <- Focus position status (2) diff --git a/backend/epson2-ops.c b/backend/epson2-ops.c index 1ba2292..ba0d9cb 100644 --- a/backend/epson2-ops.c +++ b/backend/epson2-ops.c @@ -66,7 +66,7 @@ * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | set bay * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | set threshold * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | set focus position - * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | request focus position + * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | request focus position * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | request extended identity * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | request scanner status * | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | @@ -160,7 +160,7 @@ e2_dev_init(Epson_Device *dev, const char *devname, int conntype) dev->need_double_vertical = SANE_FALSE; dev->cct_profile = &epson_cct_profiles[0]; /* default profile */ - + dev->cmd = &epson_cmd[EPSON_LEVEL_DEFAULT]; /* Change default level when using a network connection */ @@ -936,8 +936,8 @@ e2_set_extended_scanning_parameters(Epson_Scanner * s) } if (s->val[OPT_MODE].w == MODE_INFRARED) { - /* only infrared in TPU mode (NOT in TPU2 or flatbeth) - * XXX investigate this ... only tested on GT-X800 + /* only infrared in TPU mode (NOT in TPU2 or flatbeth) + * XXX investigate this ... only tested on GT-X800 */ if (extensionCtrl == 1) /* test for TPU */ diff --git a/backend/epson2.c b/backend/epson2.c index df84b1d..f119018 100644 --- a/backend/epson2.c +++ b/backend/epson2.c @@ -241,7 +241,7 @@ enum { * therefore I define two different sets of arrays, plus one set of * variables that get set to the actally used params and list arrays at runtime. */ - + static int gamma_params_ab[] = { 0x01, 0x03, @@ -303,7 +303,6 @@ static const SANE_String_Const bay_list[] = { /* minimum, maximum, quantization */ static const SANE_Range u8_range = { 0, 255, 0 }; -static const SANE_Range s8_range = { -127, 127, 0 }; static const SANE_Range fx_range = { SANE_FIX(-2.0), SANE_FIX(2.0), 0 }; static const SANE_Range outline_emphasis_range = { -2, 2, 0 }; @@ -497,7 +496,7 @@ open_scanner(Epson_Scanner *s) DBG(32, "scanner locked\n"); } - + } else if (s->hw->connection == SANE_EPSON_SCSI) status = sanei_scsi_open(s->hw->sane.name, &s->fd, sanei_epson2_scsi_sense_handler, @@ -515,7 +514,7 @@ open_scanner(Epson_Scanner *s) DBG(1, "disable any conflicting driver (like usblp).\n"); } - if (status != SANE_STATUS_GOOD) + if (status != SANE_STATUS_GOOD) DBG(1, "%s open failed: %s\n", s->hw->sane.name, sane_strstatus(status)); else @@ -604,7 +603,7 @@ detect_usb(struct Epson_Scanner *s, SANE_Bool assume_valid) DBG(1, "the device cannot be verified - will continue\n"); return SANE_STATUS_GOOD; } - + /* check the vendor ID to see if we are dealing with an EPSON device */ if (vendor != SANE_EPSON_VENDOR_ID) { /* this is not a supported vendor ID */ @@ -631,11 +630,11 @@ detect_usb(struct Epson_Scanner *s, SANE_Bool assume_valid) s->hw->sane.name, product); return SANE_STATUS_INVAL; } - + DBG(1, "found valid Epson scanner: 0x%x/0x%x (vendorID/productID)\n", vendor, product); - return SANE_STATUS_GOOD; + return SANE_STATUS_GOOD; } static int num_devices; /* number of scanners attached to backend */ @@ -684,7 +683,7 @@ device_detect(const char *name, int type, SANE_Bool assume_valid, SANE_Status *s *status = SANE_STATUS_INVAL; return NULL; } - + /* alloc and clear our device structure */ dev = malloc(sizeof(*dev)); if (!dev) { @@ -797,7 +796,7 @@ attach_one_usb(const char *dev) static SANE_Status attach_one_net(const char *dev) { - char name[39+4]; + char name[39+4]; DBG(7, "%s: dev = %s\n", __func__, dev); @@ -821,7 +820,7 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line) int len = strlen(line); DBG(7, "%s: len = %d, line = %s\n", __func__, len, line); - + if (sscanf(line, "usb %i %i", &vendor, &product) == 2) { /* add the vendor and product IDs to the list of @@ -1248,7 +1247,7 @@ init_options(Epson_Scanner *s) /* if (!s->hw->cmd->set_color_correction) s->opt[OPT_FILM_TYPE].cap |= SANE_CAP_INACTIVE; -*/ +*/ /* mirror */ s->opt[OPT_MIRROR].name = "mirror"; @@ -1501,12 +1500,12 @@ sane_open(SANE_String_Const name, SANE_Handle *handle) if (s == NULL) return status; } else { - + /* as a last resort, check for a match * in the device list. This should handle SCSI * devices and platforms without libusb. */ - + if (first_dev == NULL) probe_devices(); @@ -1515,7 +1514,7 @@ sane_open(SANE_String_Const name, SANE_Handle *handle) DBG(1, "invalid device name: %s\n", name); return SANE_STATUS_INVAL; } - } + } } @@ -1538,7 +1537,7 @@ sane_open(SANE_String_Const name, SANE_Handle *handle) } *handle = (SANE_Handle)s; - + return SANE_STATUS_GOOD; } @@ -2132,7 +2131,7 @@ sane_start(SANE_Handle handle) return status; } - + if (s->val[OPT_COLOR_CORRECTION].w == CORR_AUTO) { /* Automatic */ DBG(1, "using built in CCT profile\n"); @@ -2142,7 +2141,7 @@ sane_start(SANE_Handle handle) if (0) { /* XXX TPU */ - + /* XXX check this */ if (s->val[OPT_FILM_TYPE].w == 0) e2_load_cct_profile(s, CCTP_COLORPOS); @@ -2153,7 +2152,7 @@ sane_start(SANE_Handle handle) e2_load_cct_profile(s, CCTP_REFLECTIVE); } } - + /* ESC m, user defined color correction */ if (s->hw->cmd->set_color_correction_coefficients && correction_userdefined[s->val[OPT_COLOR_CORRECTION].w]) { diff --git a/backend/epson2.conf.in b/backend/epson2.conf.in index 797df2d..b41c862 100644 --- a/backend/epson2.conf.in +++ b/backend/epson2.conf.in @@ -21,7 +21,6 @@ usb # usb 0x4b8 0x110 # Network -# +# # net 192.168.1.123 net autodiscovery - diff --git a/backend/epson2_net.c b/backend/epson2_net.c index 4b3e7e9..8d0fe9e 100644 --- a/backend/epson2_net.c +++ b/backend/epson2_net.c @@ -124,7 +124,7 @@ sanei_epson_net_read(Epson_Scanner *s, unsigned char *buf, ssize_t wanted, if (read < 0) { return 0; } - + /* } else if (wanted < size && s->netlen == size) { */ } else { DBG(23, "%s: partial read\n", __func__); @@ -187,7 +187,7 @@ sanei_epson_net_write(Epson_Scanner *s, unsigned int cmd, const unsigned char *b DBG(24, "H1[0]: %02x %02x %02x %02x\n", h1[0], h1[1], h1[2], h1[3]); if((cmd >> 8) == 0x20) { - htobe32a(&h1[6], buf_size + 8); + htobe32a(&h1[6], buf_size + 8); htobe32a(&h2[0], buf_size); htobe32a(&h2[4], reply_len); diff --git a/backend/epson2_usb.c b/backend/epson2_usb.c index 8e29943..87830c6 100644 --- a/backend/epson2_usb.c +++ b/backend/epson2_usb.c @@ -17,7 +17,11 @@ SANE_Word sanei_epson_usb_product_ids[] = { 0x10c, /* GT-6700U, Perfection 640U */ 0x10e, /* ES-2200, Expression 1680 */ 0x110, /* GT-8200U, GT-8200UF, Perfection 1650, Perfection 1650 PHOTO */ + 0x1116, /* XP-243 245 247 Series, XP-427 */ 0x112, /* GT-9700F, Perfection 2450 PHOTO */ + 0x1120, /* L380 */ + 0x1121, /* ET-2650, L495 */ + 0x113d, /* XP-255 */ 0x11b, /* GT-9300UF, Perfection 2400 PHOTO */ 0x11c, /* GT-9800F, Perfection 3200 PHOTO */ 0x11e, /* GT-8300UF, Perfection 1660 PHOTO */ @@ -31,6 +35,7 @@ SANE_Word sanei_epson_usb_product_ids[] = { 0x138, /* ES-H7200, GT-20000 */ 0x14b, /* ES-G11000, Expression 11000XL */ 0x151, /* GT-X980, Perfection V800 Photo, Perfection V850 Pro */ + 0x15b, /* DS-G20000, Expression 12000XL */ 0x801, /* CC-600PX, Stylus CX5100, Stylus CX5200 */ 0x802, /* CC-570L, Stylus CX3100, Stylus CX3200 */ 0x805, /* Stylus CX6300, Stylus CX6400 */ @@ -171,7 +176,7 @@ SANE_Word sanei_epson_usb_product_ids[] = { 0x8ca, /* L850 Series */ 0x8cd, /* WF-R4640 Series, WF-R5690 Series */ 0x8d0, /* PX-M350F, WF-M5690 Series */ - 0 /* last entry - this is used for devices that are specified + 0 /* last entry - this is used for devices that are specified in the config file as "usb " */ }; diff --git a/backend/epson_usb.c b/backend/epson_usb.c index 520b49f..7fc5c91 100644 --- a/backend/epson_usb.c +++ b/backend/epson_usb.c @@ -41,7 +41,7 @@ SANE_Word sanei_epson_usb_product_ids[] = { 0x82e, /* DX-6000 */ 0x82f, /* DX-4050 */ 0x838, /* DX-7400 */ - 0 /* last entry - this is used for devices that are specified + 0 /* last entry - this is used for devices that are specified in the config file as "usb " */ }; diff --git a/backend/epsonds-cmd.h b/backend/epsonds-cmd.h index 923e811..973609a 100644 --- a/backend/epsonds-cmd.h +++ b/backend/epsonds-cmd.h @@ -26,4 +26,3 @@ SANE_Status esci2_trdt(epsonds_scanner *s); SANE_Status esci2_img(struct epsonds_scanner *s, SANE_Int *length) ; #endif - diff --git a/backend/epsonds-io.c b/backend/epsonds-io.c index e153ad4..0baa125 100644 --- a/backend/epsonds-io.c +++ b/backend/epsonds-io.c @@ -186,5 +186,3 @@ SANE_Status eds_lock(epsonds_scanner *s) return status; } - - diff --git a/backend/epsonds-io.h b/backend/epsonds-io.h index 1bb67c6..b3b3735 100644 --- a/backend/epsonds-io.h +++ b/backend/epsonds-io.h @@ -30,4 +30,3 @@ SANE_Status eds_fsx(epsonds_scanner *s); SANE_Status eds_lock(epsonds_scanner *s); #endif - diff --git a/backend/epsonds-jpeg.c b/backend/epsonds-jpeg.c index 62e8bb5..244f442 100644 --- a/backend/epsonds-jpeg.c +++ b/backend/epsonds-jpeg.c @@ -224,5 +224,3 @@ eds_jpeg_read(SANE_Handle handle, SANE_Byte *data, memcpy(data, src->linebuffer + src->linebuffer_index, *length); src->linebuffer_index += *length; } - - diff --git a/backend/epsonds-ops.c b/backend/epsonds-ops.c index f7a07fb..8b9d115 100644 --- a/backend/epsonds-ops.c +++ b/backend/epsonds-ops.c @@ -490,5 +490,3 @@ void eds_ring_flush(ring_buffer *ring) { eds_ring_skip(ring, ring->fill); } - - diff --git a/backend/epsonds-ops.h b/backend/epsonds-ops.h index ac5e71b..fe503d6 100644 --- a/backend/epsonds-ops.h +++ b/backend/epsonds-ops.h @@ -38,4 +38,3 @@ extern SANE_Int eds_ring_read(ring_buffer *ring, SANE_Byte *buf, SANE_Int size); extern SANE_Int eds_ring_skip(ring_buffer *ring, SANE_Int size); extern SANE_Int eds_ring_avail(ring_buffer *ring); extern void eds_ring_flush(ring_buffer *ring) ; - diff --git a/backend/epsonds.c b/backend/epsonds.c index 218e08c..d402f58 100644 --- a/backend/epsonds.c +++ b/backend/epsonds.c @@ -41,6 +41,12 @@ #include "sane/config.h" #include +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif #include #include "sane/saneopts.h" diff --git a/backend/fujitsu-scsi.h b/backend/fujitsu-scsi.h index 42598cb..38425a6 100644 --- a/backend/fujitsu-scsi.h +++ b/backend/fujitsu-scsi.h @@ -1,9 +1,9 @@ #ifndef FUJITSU_SCSI_H #define FUJITSU_SCSI_H -/* +/* * Part of SANE - Scanner Access Now Easy. - * + * * Please see to opening comments in fujitsu.c */ @@ -233,7 +233,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_IN_has_cmd_sdiag(in) getbitfield(in+0x28, 1, 2) #define get_IN_has_cmd_rdiag(in) getbitfield(in+0x28, 1, 1) #define get_IN_has_cmd_scan(in) getbitfield(in+0x28, 1, 0) - + #define get_IN_has_cmd_msen6(in) getbitfield(in+0x29, 1, 7) #define get_IN_has_cmd_copy(in) getbitfield(in+0x29, 1, 6) #define get_IN_has_cmd_rel(in) getbitfield(in+0x29, 1, 5) @@ -244,7 +244,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_IN_has_cmd_tur(in) getbitfield(in+0x29, 1, 0) /* more stuff here? (vendor commands) */ -#define get_IN_has_cmd_subwindow(in) getbitfield(in+0x2b, 1, 0) +#define get_IN_has_cmd_subwindow(in) getbitfield(in+0x2b, 1, 0) #define get_IN_has_cmd_endorser(in) getbitfield(in+0x2b, 1, 1) #define get_IN_has_cmd_hw_status(in) getbitfield(in+0x2b, 1, 2) #define get_IN_has_cmd_hw_status_2(in) getbitfield(in+0x2b, 1, 3) @@ -276,7 +276,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_IN_ipc_ipc3(in) getbitfield(in+0x59, 1, 5) #define get_IN_ipc_rotation(in) getbitfield(in+0x59, 1, 4) #define get_IN_ipc_hybrid_crop_deskew(in) getbitfield(in+0x59, 1, 3) -#define get_IN_ipc_ipc2_byte67(in) getbitfield(in+0x59, 1, 0) +#define get_IN_vpd_thru_byte_6f(in) getbitfield(in+0x59, 1, 0) #define get_IN_compression_MH(in) getbitfield(in+0x5a, 1, 7) #define get_IN_compression_MR(in) getbitfield(in+0x5a, 1, 6) @@ -383,9 +383,6 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_IN_op_halt(in) getbitfield(in+0x7a, 1, 7) -/* some scanners need evpd inquiry data manipulated */ -#define set_IN_page_length(in,val) in[0x04]=val - /* ==================================================================== */ /* page codes used by mode_sense and mode_select */ #define MS_pc_unk 0x2c /* Used by iX500 */ @@ -413,7 +410,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define set_MSEL_pf(sb, val) setbitfield(sb + 1, 1, 4, val) #define set_MSEL_xferlen(sb, val) sb[0x04] = (unsigned char)val -/* MS payloads are combined 4 byte header and 8 or 10 byte page +/* MS payloads are combined 4 byte header and 8 or 10 byte page * there is also 'descriptor block' & 'vendor-specific block' * but fujitsu seems not to use these */ /* 10 byte page only used by dropout? */ @@ -439,7 +436,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define set_MSEL_df_thickness(sb, val) setbitfield(sb + 2, 1, 4, val) #define set_MSEL_df_length(sb, val) setbitfield(sb + 2, 1, 3, val) #define set_MSEL_df_diff(sb, val) setbitfield(sb + 2, 3, 0, val) -#define MSEL_df_diff_DEFAULT 0 +#define MSEL_df_diff_DEFAULT 0 #define MSEL_df_diff_10MM 1 #define MSEL_df_diff_15MM 2 #define MSEL_df_diff_20MM 3 @@ -940,7 +937,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_WD_contrast(sb) sb[0x18] /* 0x19 - Image Composition (color mode) - * 3091 - use 0x00 for line art, 0x01 for halftone, + * 3091 - use 0x00 for line art, 0x01 for halftone, * 0x02 for grayscale, 0x05 for color. * 3096 - same but minus color. */ @@ -961,9 +958,9 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_WD_bitsperpixel(sb) sb[0x1a] /* 0x1b,0x1c - Halftone Pattern - * 3091 byte 1b: 00h default(=dither), 01h dither, + * 3091 byte 1b: 00h default(=dither), 01h dither, * 02h error dispersion - * 1c: 00 dark images, 01h dark text+images, + * 1c: 00 dark images, 01h dark text+images, * 02h light images, * 03h light text+images, 80h download pattern * 3096: 1b unused; 1c bit 7=1: use downloadable pattern, @@ -983,8 +980,8 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) /* 0x1d - Reverse image, padding type * 3091: bit 7=1: reverse black&white * bits 0-2: padding type, must be 0 - * 3096: the same; bit 7 must be set for gray and not - * set for b/w. + * 3096: the same; bit 7 must be set for gray and not + * set for b/w. */ #define set_WD_rif(sb, val) setbitfield(sb + 0x1d, 1, 7, val) #define get_WD_rif(sb) getbitfield(sb + 0x1d, 1, 7) diff --git a/backend/fujitsu.c b/backend/fujitsu.c index 433f75a..3ac4c8e 100644 --- a/backend/fujitsu.c +++ b/backend/fujitsu.c @@ -107,7 +107,7 @@ - removed SP15 code - sane_open actually opens the device you request v11 2003-06-11, MAN - - fixed bug in that code when a scanner is disconnected + - fixed bug in that code when a scanner is disconnected v12 2003-10-06, MAN - added code to support color modes of more recent scanners v13 2003-11-07, OS @@ -136,7 +136,7 @@ v19 2004-06-28, MAN - 4220 use model code not strcmp (stan a t saticed.me.uk) v20 2004-08-24, OS - - bugfix: 3091 did not work since 15.12.2003 + - bugfix: 3091 did not work since 15.12.2003 - M4099 supported (bw only) v21 2006-05-01, MAN - Complete rewrite, half code size @@ -264,7 +264,7 @@ - change window_gamma determination - add fi-5650C usb id and color mode v48 2007-04-16, MAN - - re-enable brightness/contrast for built-in models + - re-enable brightness/contrast for built-in models v49 2007-06-28, MAN - add fi-5750C usb id and color mode v50 2007-07-10, MAN @@ -600,6 +600,9 @@ - initial support for fi-7600/7700 - autodetect various double feed capabilities using VPD - call send_lut if we are using a downloaded gamma table + v134 2019-02-23, MAN + - rewrite init_vpd for scanners which fail to report + overscan correctly SANE FLOW DIAGRAM @@ -617,7 +620,7 @@ . . - sane_start() : start image acquisition . . - sane_get_parameters() : returns actual scan parameters . . - sane_read() : read image data (from pipe) - . . (sane_read called multiple times; after sane_read returns EOF, + . . (sane_read called multiple times; after sane_read returns EOF, . . loop may continue with sane_start which may return a 2nd page . . when doing duplex scans, or load the next page from the ADF) . . @@ -649,14 +652,14 @@ #include "fujitsu.h" #define DEBUG 1 -#define BUILD 133 +#define BUILD 134 /* values for SANE_DEBUG_FUJITSU env var: - errors 5 - function trace 10 - function detail 15 - get/setopt cmds 20 - - scsi/usb trace 25 + - scsi/usb trace 25 - scsi/usb writes 30 - scsi/usb reads 31 - useless noise 35 @@ -736,7 +739,7 @@ static struct fujitsu *fujitsu_devList = NULL; /* * Called by SANE initially. - * + * * From the SANE spec: * This function must be called before any other SANE function can be * called. The behavior of a SANE backend is undefined if this @@ -770,7 +773,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /* * Called by SANE to find out about supported devices. - * + * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a @@ -783,7 +786,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. - * + * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and @@ -827,39 +830,39 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) FUJITSU_CONFIG_FILE); while (sanei_config_read (line, PATH_MAX, fp)) { - + lp = line; - + /* ignore comments */ if (*lp == '#') continue; - + /* skip empty lines */ if (*lp == 0) continue; - + if ((strncmp ("option", lp, 6) == 0) && isspace (lp[6])) { - + lp += 6; lp = sanei_config_skip_whitespace (lp); - + /* we allow setting buffersize too big */ if ((strncmp (lp, "buffer-size", 11) == 0) && isspace (lp[11])) { - + int buf; lp += 11; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - + if (buf < 4096) { DBG (5, "sane_get_devices: config option \"buffer-size\" (%d) is < 4096, ignoring!\n", buf); continue; } - + if (buf > 64*1024) { DBG (5, "sane_get_devices: config option \"buffer-size\" (%d) is > %d, warning!\n", buf, 64*1024); } - + DBG (15, "sane_get_devices: setting \"buffer-size\" to %d\n", buf); global_buffer_size = buf; } @@ -956,8 +959,8 @@ attach_one_usb (const char *device_name) return attach_one(device_name,CONNECTION_USB); } -/* build the scanner struct and link to global list - * unless struct is already loaded, then pretend +/* build the scanner struct and link to global list + * unless struct is already loaded, then pretend */ static SANE_Status attach_one (const char *device_name, int connType) @@ -1105,7 +1108,7 @@ connect_fd (struct fujitsu *s) } else { DBG (15, "connect_fd: opening SCSI device\n"); - ret = sanei_scsi_open_extended (s->device_name, &(s->fd), sense_handler, s, + ret = sanei_scsi_open_extended (s->device_name, &(s->fd), sense_handler, s, &s->buffer_size); if(!ret && buffer_size != s->buffer_size){ DBG (5, "connect_fd: cannot get requested buffer size (%d/%d)\n", @@ -1115,8 +1118,8 @@ connect_fd (struct fujitsu *s) if(ret == SANE_STATUS_GOOD){ - /* first generation usb scanners can get flaky if not closed - * properly after last use. very first commands sent to device + /* first generation usb scanners can get flaky if not closed + * properly after last use. very first commands sent to device * must be prepared to correct this- see wait_scanner() */ ret = wait_scanner(s); if (ret != SANE_STATUS_GOOD) { @@ -1157,9 +1160,9 @@ init_inquire (struct fujitsu *s) set_IN_return_size (cmd, inLen); set_IN_evpd (cmd, 0); set_IN_page_code (cmd, 0); - + ret = do_cmd ( - s, 1, 0, + s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen @@ -1238,6 +1241,8 @@ init_vpd (struct fujitsu *s) unsigned char in[INQUIRY_vpd_len]; size_t inLen = INQUIRY_vpd_len; + int payload_len, payload_off; + DBG (10, "init_vpd: start\n"); /* get EVPD */ @@ -1254,531 +1259,573 @@ init_vpd (struct fujitsu *s) in, &inLen ); + /*FIXME no vpd, set some defaults? */ + if (ret != SANE_STATUS_GOOD && ret != SANE_STATUS_EOF) { + DBG (5, "init_vpd: Your scanner does not support VPD?\n"); + DBG (5, "init_vpd: Please contact kitno455 at gmail dot com\n"); + DBG (5, "init_vpd: with details of your scanner model.\n"); + return ret; + } + + /* In byte 4, the scanner sends the length of the remainder of + * the payload. But, this value is often bogus. */ + payload_len = get_IN_page_length(in); + + DBG (15, "init_vpd: length=%0x\n", payload_len); + /* M3099 gives all data, but wrong length */ - if (strstr (s->model_name, "M3099") - && (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) - && get_IN_page_length (in) == 0x19){ - DBG (5, "init_vpd: M3099 repair\n"); - set_IN_page_length(in,0x5f); + if (strstr (s->model_name, "M3099") && payload_len == 0x19){ + DBG (5, "init_vpd: M3099 repair\n"); + payload_len = 0x5f; } /* M3097G has short vpd, fill in missing part */ - else if (strstr (s->model_name, "M3097G") - && (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) - && get_IN_page_length (in) == 0x19){ - unsigned char vpd3097g[] = { + else if (strstr (s->model_name, "M3097G") && payload_len == 0x19){ + unsigned char vpd3097g[] = { 0, 0, 0xc2, 0x08, 0, 0, 0, 0, 0, 0, 0xed, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0, 0x45, 0x35, 0, 0xe0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - DBG (5, "init_vpd: M3097G repair\n"); - set_IN_page_length(in,0x5f); - memcpy(in+0x1e,vpd3097g,sizeof(vpd3097g)); + }; - /*IPC*/ - if(strstr (s->model_name, "i")){ - DBG (5, "init_vpd: M3097G IPC repair\n"); + DBG (5, "init_vpd: M3097G repair\n"); + payload_len = 0x5f; + memcpy(in+0x1e,vpd3097g,sizeof(vpd3097g)); - /*subwin cmd*/ - in[0x2b] = 1; + /*IPC*/ + if(strstr (s->model_name, "i")){ + DBG (5, "init_vpd: M3097G IPC repair\n"); - /*rif/dtc/sdtc/outline/emph/sep/mirr/wlf*/ - in[0x58] = 0xff; + /*subwin cmd*/ + in[0x2b] = 1; - /*subwin/diffusion*/ - in[0x59] = 0xc0; - } + /*rif/dtc/sdtc/outline/emph/sep/mirr/wlf*/ + in[0x58] = 0xff; - /*CMP*/ - if(strstr (s->model_name, "m")){ - DBG (5, "init_vpd: M3097G CMP repair\n"); + /*subwin/diffusion*/ + in[0x59] = 0xc0; + } - /*4megs*/ - in[0x23] = 0x40; + /*CMP*/ + if(strstr (s->model_name, "m")){ + DBG (5, "init_vpd: M3097G CMP repair\n"); - /*mh/mr/mmr*/ - in[0x5a] = 0xe0; - } + /*4megs*/ + in[0x23] = 0x40; + + /*mh/mr/mmr*/ + in[0x5a] = 0xe0; + } } - DBG (15, "init_vpd: length=%0x\n",get_IN_page_length (in)); + /* all other known scanners have at least 0x5f, + * less would require software changes like above */ + else if (payload_len < 0x5f) { + DBG (5, "init_vpd: Your scanner supports only partial VPD?\n"); + DBG (5, "init_vpd: Please contact kitno455 at gmail dot com\n"); + DBG (5, "init_vpd: with details of your scanner model.\n"); + return SANE_STATUS_INVAL; + } - /* This scanner supports vital product data. - * Use this data to set dpi-lists etc. */ - if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { + /* Special case- some scanners will under-report the amount of + * valid vpd that they send, and return the default length. + * Adding 4 more bytes allows us to include the overscan info. + * Scanners that don't support overscan seem to have all zeros + * in these bytes, so no harm is done. + * This may be an 'off-by-four' error in the firmware. */ + else if (payload_len == 0x5f){ + payload_len += 4; + } - DBG (15, "standard options\n"); + /* Having an offset from the beginning of the payload + * is more useful than from byte 4, as that matches the + * documentation more closely. */ + payload_off = payload_len + 4; - s->basic_x_res = get_IN_basic_x_res (in); - DBG (15, " basic x res: %d dpi\n",s->basic_x_res); + /* everything that appears in bytes 0 to 0x1d */ + DBG (15, "standard options\n"); - s->basic_y_res = get_IN_basic_y_res (in); - DBG (15, " basic y res: %d dpi\n",s->basic_y_res); + s->basic_x_res = get_IN_basic_x_res (in); + DBG (15, " basic x res: %d dpi\n",s->basic_x_res); - s->step_x_res[MODE_LINEART] = get_IN_step_x_res (in); - DBG (15, " step x res: %d dpi\n", s->step_x_res[MODE_LINEART]); + s->basic_y_res = get_IN_basic_y_res (in); + DBG (15, " basic y res: %d dpi\n",s->basic_y_res); - s->step_y_res[MODE_LINEART] = get_IN_step_y_res (in); - DBG (15, " step y res: %d dpi\n", s->step_y_res[MODE_LINEART]); + s->step_x_res[MODE_LINEART] = get_IN_step_x_res (in); + DBG (15, " step x res: %d dpi\n", s->step_x_res[MODE_LINEART]); - s->max_x_res = get_IN_max_x_res (in); - DBG (15, " max x res: %d dpi\n", s->max_x_res); + s->step_y_res[MODE_LINEART] = get_IN_step_y_res (in); + DBG (15, " step y res: %d dpi\n", s->step_y_res[MODE_LINEART]); - s->max_y_res = get_IN_max_y_res (in); - DBG (15, " max y res: %d dpi\n", s->max_y_res); + s->max_x_res = get_IN_max_x_res (in); + DBG (15, " max x res: %d dpi\n", s->max_x_res); - s->min_x_res = get_IN_min_x_res (in); - DBG (15, " min x res: %d dpi\n", s->min_x_res); + s->max_y_res = get_IN_max_y_res (in); + DBG (15, " max y res: %d dpi\n", s->max_y_res); - s->min_y_res = get_IN_min_y_res (in); - DBG (15, " min y res: %d dpi\n", s->min_y_res); + s->min_x_res = get_IN_min_x_res (in); + DBG (15, " min x res: %d dpi\n", s->min_x_res); - /* some scanners list B&W resolutions. */ - s->std_res[0] = get_IN_std_res_60 (in); - DBG (15, " 60 dpi: %d\n", s->std_res[0]); + s->min_y_res = get_IN_min_y_res (in); + DBG (15, " min y res: %d dpi\n", s->min_y_res); - s->std_res[1] = get_IN_std_res_75 (in); - DBG (15, " 75 dpi: %d\n", s->std_res[1]); + /* some scanners list B&W resolutions. */ + s->std_res[0] = get_IN_std_res_60 (in); + DBG (15, " 60 dpi: %d\n", s->std_res[0]); - s->std_res[2] = get_IN_std_res_100 (in); - DBG (15, " 100 dpi: %d\n", s->std_res[2]); + s->std_res[1] = get_IN_std_res_75 (in); + DBG (15, " 75 dpi: %d\n", s->std_res[1]); - s->std_res[3] = get_IN_std_res_120 (in); - DBG (15, " 120 dpi: %d\n", s->std_res[3]); + s->std_res[2] = get_IN_std_res_100 (in); + DBG (15, " 100 dpi: %d\n", s->std_res[2]); - s->std_res[4] = get_IN_std_res_150 (in); - DBG (15, " 150 dpi: %d\n", s->std_res[4]); + s->std_res[3] = get_IN_std_res_120 (in); + DBG (15, " 120 dpi: %d\n", s->std_res[3]); - s->std_res[5] = get_IN_std_res_160 (in); - DBG (15, " 160 dpi: %d\n", s->std_res[5]); + s->std_res[4] = get_IN_std_res_150 (in); + DBG (15, " 150 dpi: %d\n", s->std_res[4]); - s->std_res[6] = get_IN_std_res_180 (in); - DBG (15, " 180 dpi: %d\n", s->std_res[6]); + s->std_res[5] = get_IN_std_res_160 (in); + DBG (15, " 160 dpi: %d\n", s->std_res[5]); - s->std_res[7] = get_IN_std_res_200 (in); - DBG (15, " 200 dpi: %d\n", s->std_res[7]); + s->std_res[6] = get_IN_std_res_180 (in); + DBG (15, " 180 dpi: %d\n", s->std_res[6]); - s->std_res[8] = get_IN_std_res_240 (in); - DBG (15, " 240 dpi: %d\n", s->std_res[8]); + s->std_res[7] = get_IN_std_res_200 (in); + DBG (15, " 200 dpi: %d\n", s->std_res[7]); - s->std_res[9] = get_IN_std_res_300 (in); - DBG (15, " 300 dpi: %d\n", s->std_res[9]); + s->std_res[8] = get_IN_std_res_240 (in); + DBG (15, " 240 dpi: %d\n", s->std_res[8]); - s->std_res[10] = get_IN_std_res_320 (in); - DBG (15, " 320 dpi: %d\n", s->std_res[10]); + s->std_res[9] = get_IN_std_res_300 (in); + DBG (15, " 300 dpi: %d\n", s->std_res[9]); - s->std_res[11] = get_IN_std_res_400 (in); - DBG (15, " 400 dpi: %d\n", s->std_res[11]); + s->std_res[10] = get_IN_std_res_320 (in); + DBG (15, " 320 dpi: %d\n", s->std_res[10]); - s->std_res[12] = get_IN_std_res_480 (in); - DBG (15, " 480 dpi: %d\n", s->std_res[12]); + s->std_res[11] = get_IN_std_res_400 (in); + DBG (15, " 400 dpi: %d\n", s->std_res[11]); - s->std_res[13] = get_IN_std_res_600 (in); - DBG (15, " 600 dpi: %d\n", s->std_res[13]); + s->std_res[12] = get_IN_std_res_480 (in); + DBG (15, " 480 dpi: %d\n", s->std_res[12]); - s->std_res[14] = get_IN_std_res_800 (in); - DBG (15, " 800 dpi: %d\n", s->std_res[14]); + s->std_res[13] = get_IN_std_res_600 (in); + DBG (15, " 600 dpi: %d\n", s->std_res[13]); - s->std_res[15] = get_IN_std_res_1200 (in); - DBG (15, " 1200 dpi: %d\n", s->std_res[15]); + s->std_res[14] = get_IN_std_res_800 (in); + DBG (15, " 800 dpi: %d\n", s->std_res[14]); - /* maximum window width and length are reported in basic units.*/ - s->max_x_basic = get_IN_window_width(in); - DBG(15, " max width: %2.2f inches\n",(float)s->max_x_basic/s->basic_x_res); + s->std_res[15] = get_IN_std_res_1200 (in); + DBG (15, " 1200 dpi: %d\n", s->std_res[15]); - s->max_y_basic = get_IN_window_length(in); - DBG(15, " max length: %2.2f inches\n",(float)s->max_y_basic/s->basic_y_res); + /* maximum window width and length are reported in basic units.*/ + s->max_x_basic = get_IN_window_width(in); + DBG(15, " max width: %2.2f inches\n",(float)s->max_x_basic/s->basic_x_res); - /* known modes */ - s->can_overflow = get_IN_overflow(in); - DBG (15, " overflow: %d\n", s->can_overflow); + s->max_y_basic = get_IN_window_length(in); + DBG(15, " max length: %2.2f inches\n",(float)s->max_y_basic/s->basic_y_res); - s->can_mode[MODE_LINEART] = get_IN_monochrome (in); - DBG (15, " monochrome: %d\n", s->can_mode[MODE_LINEART]); + /* known modes */ + s->can_overflow = get_IN_overflow(in); + DBG (15, " overflow: %d\n", s->can_overflow); - s->can_mode[MODE_HALFTONE] = get_IN_half_tone (in); - DBG (15, " halftone: %d\n", s->can_mode[MODE_HALFTONE]); + s->can_mode[MODE_LINEART] = get_IN_monochrome (in); + DBG (15, " monochrome: %d\n", s->can_mode[MODE_LINEART]); - s->can_mode[MODE_GRAYSCALE] = get_IN_multilevel (in); - DBG (15, " grayscale: %d\n", s->can_mode[MODE_GRAYSCALE]); + s->can_mode[MODE_HALFTONE] = get_IN_half_tone (in); + DBG (15, " halftone: %d\n", s->can_mode[MODE_HALFTONE]); - DBG (15, " color_monochrome: %d\n", get_IN_monochrome_rgb(in)); - DBG (15, " color_halftone: %d\n", get_IN_half_tone_rgb(in)); + s->can_mode[MODE_GRAYSCALE] = get_IN_multilevel (in); + DBG (15, " grayscale: %d\n", s->can_mode[MODE_GRAYSCALE]); - s->can_mode[MODE_COLOR] = get_IN_multilevel_rgb (in); - DBG (15, " color_grayscale: %d\n", s->can_mode[MODE_COLOR]); + DBG (15, " color_monochrome: %d\n", get_IN_monochrome_rgb(in)); + DBG (15, " color_halftone: %d\n", get_IN_half_tone_rgb(in)); - /* now we look at vendor specific data */ - if (get_IN_page_length (in) >= 0x5f) { + s->can_mode[MODE_COLOR] = get_IN_multilevel_rgb (in); + DBG (15, " color_grayscale: %d\n", s->can_mode[MODE_COLOR]); - DBG (15, "vendor options\n"); + /* now we look at vendor specific data in bytes 0x1e onward */ + DBG (15, "vendor options\n"); - s->has_adf = get_IN_adf(in); - DBG (15, " adf: %d\n", s->has_adf); + s->has_adf = get_IN_adf(in); + DBG (15, " adf: %d\n", s->has_adf); - s->has_flatbed = get_IN_flatbed(in); - DBG (15, " flatbed: %d\n", s->has_flatbed); + s->has_flatbed = get_IN_flatbed(in); + DBG (15, " flatbed: %d\n", s->has_flatbed); - s->has_transparency = get_IN_transparency(in); - DBG (15, " transparency: %d\n", s->has_transparency); + s->has_transparency = get_IN_transparency(in); + DBG (15, " transparency: %d\n", s->has_transparency); - s->has_duplex = get_IN_duplex(in); - s->has_back = s->has_duplex; - DBG (15, " duplex: %d\n", s->has_duplex); + s->has_duplex = get_IN_duplex(in); + s->has_back = s->has_duplex; + DBG (15, " duplex: %d\n", s->has_duplex); - s->has_endorser_b = get_IN_endorser_b(in); - DBG (15, " back endorser: %d\n", s->has_endorser_b); + s->has_endorser_b = get_IN_endorser_b(in); + DBG (15, " back endorser: %d\n", s->has_endorser_b); - s->has_barcode = get_IN_barcode(in); - DBG (15, " barcode: %d\n", s->has_barcode); + s->has_barcode = get_IN_barcode(in); + DBG (15, " barcode: %d\n", s->has_barcode); - s->has_operator_panel = get_IN_operator_panel(in); - DBG (15, " operator panel: %d\n", s->has_operator_panel); + s->has_operator_panel = get_IN_operator_panel(in); + DBG (15, " operator panel: %d\n", s->has_operator_panel); - s->has_endorser_f = get_IN_endorser_f(in); - DBG (15, " front endorser: %d\n", s->has_endorser_f); + s->has_endorser_f = get_IN_endorser_f(in); + DBG (15, " front endorser: %d\n", s->has_endorser_f); - DBG (15, " multi-purpose stacker: %d\n", get_IN_mp_stacker(in)); + DBG (15, " multi-purpose stacker: %d\n", get_IN_mp_stacker(in)); - DBG (15, " prepick: %d\n", get_IN_prepick(in)); - DBG (15, " mf detect: %d\n", get_IN_mf_detect(in)); + DBG (15, " prepick: %d\n", get_IN_prepick(in)); + DBG (15, " mf detect: %d\n", get_IN_mf_detect(in)); - s->has_paper_protect = get_IN_paperprot(in); - DBG (15, " paper protection: %d\n", s->has_paper_protect); + s->has_paper_protect = get_IN_paperprot(in); + DBG (15, " paper protection: %d\n", s->has_paper_protect); - s->adbits = get_IN_adbits(in); - DBG (15, " A/D bits: %d\n",s->adbits); + s->adbits = get_IN_adbits(in); + DBG (15, " A/D bits: %d\n",s->adbits); - s->buffer_bytes = get_IN_buffer_bytes(in); - DBG (15, " buffer bytes: %d\n",s->buffer_bytes); + s->buffer_bytes = get_IN_buffer_bytes(in); + DBG (15, " buffer bytes: %d\n",s->buffer_bytes); - DBG (15, "Standard commands\n"); + DBG (15, "Standard commands\n"); - /* std scsi command support byte 26*/ - s->has_cmd_msen10 = get_IN_has_cmd_msen10(in); - DBG (15, " mode_sense_10 cmd: %d\n", s->has_cmd_msen10); + /* std scsi command support byte 26*/ + s->has_cmd_msen10 = get_IN_has_cmd_msen10(in); + DBG (15, " mode_sense_10 cmd: %d\n", s->has_cmd_msen10); - s->has_cmd_msel10 = get_IN_has_cmd_msel10(in); - DBG (15, " mode_select_10 cmd: %d\n", s->has_cmd_msel10); + s->has_cmd_msel10 = get_IN_has_cmd_msel10(in); + DBG (15, " mode_select_10 cmd: %d\n", s->has_cmd_msel10); - /* std scsi command support byte 27*/ - s->has_cmd_lsen = get_IN_has_cmd_lsen(in); - DBG (15, " log_sense cmd: %d\n", s->has_cmd_lsen); + /* std scsi command support byte 27*/ + s->has_cmd_lsen = get_IN_has_cmd_lsen(in); + DBG (15, " log_sense cmd: %d\n", s->has_cmd_lsen); - s->has_cmd_lsel = get_IN_has_cmd_lsel(in); - DBG (15, " log_select cmd: %d\n", s->has_cmd_lsel); + s->has_cmd_lsel = get_IN_has_cmd_lsel(in); + DBG (15, " log_select cmd: %d\n", s->has_cmd_lsel); - s->has_cmd_change = get_IN_has_cmd_change(in); - DBG (15, " change cmd: %d\n", s->has_cmd_change); + s->has_cmd_change = get_IN_has_cmd_change(in); + DBG (15, " change cmd: %d\n", s->has_cmd_change); - s->has_cmd_rbuff = get_IN_has_cmd_rbuff(in); - DBG (15, " read_buffer cmd: %d\n", s->has_cmd_rbuff); + s->has_cmd_rbuff = get_IN_has_cmd_rbuff(in); + DBG (15, " read_buffer cmd: %d\n", s->has_cmd_rbuff); - s->has_cmd_wbuff = get_IN_has_cmd_wbuff(in); - DBG (15, " write_buffer cmd: %d\n", s->has_cmd_wbuff); + s->has_cmd_wbuff = get_IN_has_cmd_wbuff(in); + DBG (15, " write_buffer cmd: %d\n", s->has_cmd_wbuff); - s->has_cmd_cav = get_IN_has_cmd_cav(in); - DBG (15, " copy_and_verify cmd: %d\n", s->has_cmd_cav); + s->has_cmd_cav = get_IN_has_cmd_cav(in); + DBG (15, " copy_and_verify cmd: %d\n", s->has_cmd_cav); - s->has_cmd_comp = get_IN_has_cmd_comp(in); - DBG (15, " compare cmd: %d\n", s->has_cmd_comp); + s->has_cmd_comp = get_IN_has_cmd_comp(in); + DBG (15, " compare cmd: %d\n", s->has_cmd_comp); - s->has_cmd_gdbs = get_IN_has_cmd_gdbs(in); - DBG (15, " get_d_b_status cmd: %d\n", s->has_cmd_gdbs); + s->has_cmd_gdbs = get_IN_has_cmd_gdbs(in); + DBG (15, " get_d_b_status cmd: %d\n", s->has_cmd_gdbs); - /* std scsi command support byte 28*/ - s->has_cmd_op = get_IN_has_cmd_op(in); - DBG (15, " object_pos cmd: %d\n", s->has_cmd_op); + /* std scsi command support byte 28*/ + s->has_cmd_op = get_IN_has_cmd_op(in); + DBG (15, " object_pos cmd: %d\n", s->has_cmd_op); - s->has_cmd_send = get_IN_has_cmd_send(in); - DBG (15, " send cmd: %d\n", s->has_cmd_send); + s->has_cmd_send = get_IN_has_cmd_send(in); + DBG (15, " send cmd: %d\n", s->has_cmd_send); - s->has_cmd_read = get_IN_has_cmd_read(in); - DBG (15, " read cmd: %d\n", s->has_cmd_read); + s->has_cmd_read = get_IN_has_cmd_read(in); + DBG (15, " read cmd: %d\n", s->has_cmd_read); - s->has_cmd_gwin = get_IN_has_cmd_gwin(in); - DBG (15, " get_window cmd: %d\n", s->has_cmd_gwin); + s->has_cmd_gwin = get_IN_has_cmd_gwin(in); + DBG (15, " get_window cmd: %d\n", s->has_cmd_gwin); - s->has_cmd_swin = get_IN_has_cmd_swin(in); - DBG (15, " set_window cmd: %d\n", s->has_cmd_swin); + s->has_cmd_swin = get_IN_has_cmd_swin(in); + DBG (15, " set_window cmd: %d\n", s->has_cmd_swin); - s->has_cmd_sdiag = get_IN_has_cmd_sdiag(in); - DBG (15, " send_diag cmd: %d\n", s->has_cmd_sdiag); + s->has_cmd_sdiag = get_IN_has_cmd_sdiag(in); + DBG (15, " send_diag cmd: %d\n", s->has_cmd_sdiag); - s->has_cmd_rdiag = get_IN_has_cmd_rdiag(in); - DBG (15, " read_diag cmd: %d\n", s->has_cmd_rdiag); + s->has_cmd_rdiag = get_IN_has_cmd_rdiag(in); + DBG (15, " read_diag cmd: %d\n", s->has_cmd_rdiag); - s->has_cmd_scan = get_IN_has_cmd_scan(in); - DBG (15, " scan cmd: %d\n", s->has_cmd_scan); + s->has_cmd_scan = get_IN_has_cmd_scan(in); + DBG (15, " scan cmd: %d\n", s->has_cmd_scan); - /* std scsi command support byte 29*/ - s->has_cmd_msen6 = get_IN_has_cmd_msen6(in); - DBG (15, " mode_sense_6 cmd: %d\n", s->has_cmd_msen6); + /* std scsi command support byte 29*/ + s->has_cmd_msen6 = get_IN_has_cmd_msen6(in); + DBG (15, " mode_sense_6 cmd: %d\n", s->has_cmd_msen6); - s->has_cmd_copy = get_IN_has_cmd_copy(in); - DBG (15, " copy cmd: %d\n", s->has_cmd_copy); + s->has_cmd_copy = get_IN_has_cmd_copy(in); + DBG (15, " copy cmd: %d\n", s->has_cmd_copy); - s->has_cmd_rel = get_IN_has_cmd_rel(in); - DBG (15, " release cmd: %d\n", s->has_cmd_rel); + s->has_cmd_rel = get_IN_has_cmd_rel(in); + DBG (15, " release cmd: %d\n", s->has_cmd_rel); - s->has_cmd_runit = get_IN_has_cmd_runit(in); - DBG (15, " reserve_unit cmd: %d\n", s->has_cmd_runit); + s->has_cmd_runit = get_IN_has_cmd_runit(in); + DBG (15, " reserve_unit cmd: %d\n", s->has_cmd_runit); - s->has_cmd_msel6 = get_IN_has_cmd_msel6(in); - DBG (15, " mode_select_6 cmd: %d\n", s->has_cmd_msel6); + s->has_cmd_msel6 = get_IN_has_cmd_msel6(in); + DBG (15, " mode_select_6 cmd: %d\n", s->has_cmd_msel6); - s->has_cmd_inq = get_IN_has_cmd_inq(in); - DBG (15, " inquiry cmd: %d\n", s->has_cmd_inq); + s->has_cmd_inq = get_IN_has_cmd_inq(in); + DBG (15, " inquiry cmd: %d\n", s->has_cmd_inq); - s->has_cmd_rs = get_IN_has_cmd_rs(in); - DBG (15, " request_sense cmd: %d\n", s->has_cmd_rs); + s->has_cmd_rs = get_IN_has_cmd_rs(in); + DBG (15, " request_sense cmd: %d\n", s->has_cmd_rs); - s->has_cmd_tur = get_IN_has_cmd_tur(in); - DBG (15, " test_unit_ready cmd: %d\n", s->has_cmd_tur); + s->has_cmd_tur = get_IN_has_cmd_tur(in); + DBG (15, " test_unit_ready cmd: %d\n", s->has_cmd_tur); - /* vendor added scsi command support */ - /* FIXME: there are more of these... */ - DBG (15, "Vendor commands\n"); + /* vendor added scsi command support */ + /* FIXME: there are more of these... */ + DBG (15, "Vendor commands\n"); - s->has_cmd_subwindow = get_IN_has_cmd_subwindow(in); - DBG (15, " subwindow cmd: %d\n", s->has_cmd_subwindow); + s->has_cmd_subwindow = get_IN_has_cmd_subwindow(in); + DBG (15, " subwindow cmd: %d\n", s->has_cmd_subwindow); - s->has_cmd_endorser = get_IN_has_cmd_endorser(in); - DBG (15, " endorser cmd: %d\n", s->has_cmd_endorser); + s->has_cmd_endorser = get_IN_has_cmd_endorser(in); + DBG (15, " endorser cmd: %d\n", s->has_cmd_endorser); - s->has_cmd_hw_status = get_IN_has_cmd_hw_status (in); - DBG (15, " hardware status cmd: %d\n", s->has_cmd_hw_status); + s->has_cmd_hw_status = get_IN_has_cmd_hw_status (in); + DBG (15, " hardware status cmd: %d\n", s->has_cmd_hw_status); - s->has_cmd_hw_status_2 = get_IN_has_cmd_hw_status_2 (in); - DBG (15, " hardware status 2 cmd: %d\n", s->has_cmd_hw_status_2); + s->has_cmd_hw_status_2 = get_IN_has_cmd_hw_status_2 (in); + DBG (15, " hardware status 2 cmd: %d\n", s->has_cmd_hw_status_2); - s->has_cmd_hw_status_3 = get_IN_has_cmd_hw_status_3 (in); - DBG (15, " hardware status 3 cmd: %d\n", s->has_cmd_hw_status_3); + s->has_cmd_hw_status_3 = get_IN_has_cmd_hw_status_3 (in); + DBG (15, " hardware status 3 cmd: %d\n", s->has_cmd_hw_status_3); - s->has_cmd_scanner_ctl = get_IN_has_cmd_scanner_ctl(in); - DBG (15, " scanner control cmd: %d\n", s->has_cmd_scanner_ctl); + s->has_cmd_scanner_ctl = get_IN_has_cmd_scanner_ctl(in); + DBG (15, " scanner control cmd: %d\n", s->has_cmd_scanner_ctl); - s->has_cmd_device_restart = get_IN_has_cmd_device_restart(in); - DBG (15, " device restart cmd: %d\n", s->has_cmd_device_restart); + s->has_cmd_device_restart = get_IN_has_cmd_device_restart(in); + DBG (15, " device restart cmd: %d\n", s->has_cmd_device_restart); - /* get threshold, brightness and contrast ranges. */ - s->brightness_steps = get_IN_brightness_steps(in); - DBG (15, " brightness steps: %d\n", s->brightness_steps); + /* get threshold, brightness and contrast ranges. */ + s->brightness_steps = get_IN_brightness_steps(in); + DBG (15, " brightness steps: %d\n", s->brightness_steps); - s->threshold_steps = get_IN_threshold_steps(in); - DBG (15, " threshold steps: %d\n", s->threshold_steps); + s->threshold_steps = get_IN_threshold_steps(in); + DBG (15, " threshold steps: %d\n", s->threshold_steps); - s->contrast_steps = get_IN_contrast_steps(in); - DBG (15, " contrast steps: %d\n", s->contrast_steps); + s->contrast_steps = get_IN_contrast_steps(in); + DBG (15, " contrast steps: %d\n", s->contrast_steps); - /* dither/gamma patterns */ - s->num_internal_gamma = get_IN_num_gamma_internal (in); - DBG (15, " built in gamma patterns: %d\n", s->num_internal_gamma); + /* dither/gamma patterns */ + s->num_internal_gamma = get_IN_num_gamma_internal (in); + DBG (15, " built in gamma patterns: %d\n", s->num_internal_gamma); - s->num_download_gamma = get_IN_num_gamma_download (in); - DBG (15, " download gamma patterns: %d\n", s->num_download_gamma); + s->num_download_gamma = get_IN_num_gamma_download (in); + DBG (15, " download gamma patterns: %d\n", s->num_download_gamma); - s->num_internal_dither = get_IN_num_dither_internal (in); - DBG (15, " built in dither patterns: %d\n", s->num_internal_dither); + s->num_internal_dither = get_IN_num_dither_internal (in); + DBG (15, " built in dither patterns: %d\n", s->num_internal_dither); - s->num_download_dither = get_IN_num_dither_download (in); - DBG (15, " download dither patterns: %d\n", s->num_download_dither); + s->num_download_dither = get_IN_num_dither_download (in); + DBG (15, " download dither patterns: %d\n", s->num_download_dither); - /* ipc functions */ - s->has_rif = get_IN_ipc_bw_rif (in); - DBG (15, " RIF: %d\n", s->has_rif); + /* ipc functions */ + s->has_rif = get_IN_ipc_bw_rif (in); + DBG (15, " RIF: %d\n", s->has_rif); - s->has_dtc = get_IN_ipc_dtc(in); - DBG (15, " DTC (AutoI): %d\n", s->has_dtc); + s->has_dtc = get_IN_ipc_dtc(in); + DBG (15, " DTC (AutoI): %d\n", s->has_dtc); - s->has_sdtc = get_IN_ipc_sdtc(in); - DBG (15, " SDTC (AutoII): %d\n", s->has_sdtc); + s->has_sdtc = get_IN_ipc_sdtc(in); + DBG (15, " SDTC (AutoII): %d\n", s->has_sdtc); - s->has_outline = get_IN_ipc_outline_extraction (in); - DBG (15, " outline extraction: %d\n", s->has_outline); + s->has_outline = get_IN_ipc_outline_extraction (in); + DBG (15, " outline extraction: %d\n", s->has_outline); - s->has_emphasis = get_IN_ipc_image_emphasis (in); - DBG (15, " image emphasis: %d\n", s->has_emphasis); + s->has_emphasis = get_IN_ipc_image_emphasis (in); + DBG (15, " image emphasis: %d\n", s->has_emphasis); - s->has_autosep = get_IN_ipc_auto_separation (in); - DBG (15, " automatic separation: %d\n", s->has_autosep); + s->has_autosep = get_IN_ipc_auto_separation (in); + DBG (15, " automatic separation: %d\n", s->has_autosep); - s->has_mirroring = get_IN_ipc_mirroring (in); - DBG (15, " mirror image: %d\n", s->has_mirroring); + s->has_mirroring = get_IN_ipc_mirroring (in); + DBG (15, " mirror image: %d\n", s->has_mirroring); - s->has_wl_follow = get_IN_ipc_wl_follow (in); - DBG (15, " white level follower: %d\n", s->has_wl_follow); + s->has_wl_follow = get_IN_ipc_wl_follow (in); + DBG (15, " white level follower: %d\n", s->has_wl_follow); - /* byte 58 */ - s->has_subwindow = get_IN_ipc_subwindow (in); - DBG (15, " subwindow: %d\n", s->has_subwindow); + /* byte 58 */ + s->has_subwindow = get_IN_ipc_subwindow (in); + DBG (15, " subwindow: %d\n", s->has_subwindow); - s->has_diffusion = get_IN_ipc_diffusion (in); - DBG (15, " diffusion: %d\n", s->has_diffusion); + s->has_diffusion = get_IN_ipc_diffusion (in); + DBG (15, " diffusion: %d\n", s->has_diffusion); - s->has_ipc3 = get_IN_ipc_ipc3 (in); - DBG (15, " ipc3: %d\n", s->has_ipc3); + s->has_ipc3 = get_IN_ipc_ipc3 (in); + DBG (15, " ipc3: %d\n", s->has_ipc3); - s->has_rotation = get_IN_ipc_rotation (in); - DBG (15, " rotation: %d\n", s->has_rotation); + s->has_rotation = get_IN_ipc_rotation (in); + DBG (15, " rotation: %d\n", s->has_rotation); - s->has_hybrid_crop_deskew = get_IN_ipc_hybrid_crop_deskew(in); - DBG (15, " hybrid crop deskew: %d\n", s->has_hybrid_crop_deskew); + s->has_hybrid_crop_deskew = get_IN_ipc_hybrid_crop_deskew(in); + DBG (15, " hybrid crop deskew: %d\n", s->has_hybrid_crop_deskew); - DBG (15, " ipc2 byte 67: %d\n", get_IN_ipc_ipc2_byte67(in)); + /* this one is weird, overrides the payload length from scanner */ + DBG (15, " vpd extends to byte 6f: %d\n", get_IN_vpd_thru_byte_6f(in)); + if(get_IN_vpd_thru_byte_6f(in) && payload_off < 0x6f){ + payload_off = 0x6f; + } - /* compression modes */ - s->has_comp_MH = get_IN_compression_MH (in); - DBG (15, " compression MH: %d\n", s->has_comp_MH); + /* compression modes */ + s->has_comp_MH = get_IN_compression_MH (in); + DBG (15, " compression MH: %d\n", s->has_comp_MH); - s->has_comp_MR = get_IN_compression_MR (in); - DBG (15, " compression MR: %d\n", s->has_comp_MR); + s->has_comp_MR = get_IN_compression_MR (in); + DBG (15, " compression MR: %d\n", s->has_comp_MR); - s->has_comp_MMR = get_IN_compression_MMR (in); - DBG (15, " compression MMR: %d\n", s->has_comp_MMR); + s->has_comp_MMR = get_IN_compression_MMR (in); + DBG (15, " compression MMR: %d\n", s->has_comp_MMR); - s->has_comp_JBIG = get_IN_compression_JBIG (in); - DBG (15, " compression JBIG: %d\n", s->has_comp_JBIG); + s->has_comp_JBIG = get_IN_compression_JBIG (in); + DBG (15, " compression JBIG: %d\n", s->has_comp_JBIG); - s->has_comp_JPG1 = get_IN_compression_JPG_BASE (in); - DBG (15, " compression JPG1: %d\n", s->has_comp_JPG1); + s->has_comp_JPG1 = get_IN_compression_JPG_BASE (in); + DBG (15, " compression JPG1: %d\n", s->has_comp_JPG1); #ifdef SANE_JPEG_DISABLED - DBG (15, " (Disabled)\n"); + DBG (15, " (Disabled)\n"); #endif - s->has_comp_JPG2 = get_IN_compression_JPG_EXT (in); - DBG (15, " compression JPG2: %d\n", s->has_comp_JPG2); - - s->has_comp_JPG3 = get_IN_compression_JPG_INDEP (in); - DBG (15, " compression JPG3: %d\n", s->has_comp_JPG3); - - /* FIXME: we dont store these? */ - DBG (15, " back endorser mech: %d\n", get_IN_endorser_b_mech(in)); - DBG (15, " back endorser stamp: %d\n", get_IN_endorser_b_stamp(in)); - DBG (15, " back endorser elec: %d\n", get_IN_endorser_b_elec(in)); - DBG (15, " endorser max id: %d\n", get_IN_endorser_max_id(in)); - - DBG (15, " front endorser mech: %d\n", get_IN_endorser_f_mech(in)); - DBG (15, " front endorser stamp: %d\n", get_IN_endorser_f_stamp(in)); - DBG (15, " front endorser elec: %d\n", get_IN_endorser_f_elec(in)); - - s->endorser_type_b = get_IN_endorser_b_type(in); - DBG (15, " back endorser type: %d\n", s->endorser_type_b); - - s->endorser_type_f = get_IN_endorser_f_type(in); - DBG (15, " back endorser type: %d\n", s->endorser_type_f); - - /*not all scanners go this far*/ - if (get_IN_page_length (in) >= 0x67-5) { - DBG (15, " connection type: %d\n", get_IN_connection(in)); - - DBG (15, " endorser ext: %d\n", get_IN_endorser_type_ext(in)); - DBG (15, " endorser pr_b: %d\n", get_IN_endorser_pre_back(in)); - DBG (15, " endorser pr_f: %d\n", get_IN_endorser_pre_front(in)); - DBG (15, " endorser po_b: %d\n", get_IN_endorser_post_back(in)); - DBG (15, " endorser po_f: %d\n", get_IN_endorser_post_front(in)); - - s->os_x_basic = get_IN_x_overscan_size(in); - DBG (15, " horizontal overscan: %d\n", s->os_x_basic); - - s->os_y_basic = get_IN_y_overscan_size(in); - DBG (15, " vertical overscan: %d\n", s->os_y_basic); - } + s->has_comp_JPG2 = get_IN_compression_JPG_EXT (in); + DBG (15, " compression JPG2: %d\n", s->has_comp_JPG2); - if (get_IN_page_length (in) >= 0x70-5) { - DBG (15, " default bg adf b: %d\n", get_IN_default_bg_adf_b(in)); - DBG (15, " default bg adf f: %d\n", get_IN_default_bg_adf_f(in)); - DBG (15, " default bg fb: %d\n", get_IN_default_bg_fb(in)); + s->has_comp_JPG3 = get_IN_compression_JPG_INDEP (in); + DBG (15, " compression JPG3: %d\n", s->has_comp_JPG3); - DBG (15, " auto color: %d\n", get_IN_auto_color(in)); - DBG (15, " blank skip: %d\n", get_IN_blank_skip(in)); - DBG (15, " multi image: %d\n", get_IN_multi_image(in)); - DBG (15, " f b type indep: %d\n", get_IN_f_b_type_indep(in)); - DBG (15, " f b res indep: %d\n", get_IN_f_b_res_indep(in)); + /* FIXME: we dont store these? */ + DBG (15, " back endorser mech: %d\n", get_IN_endorser_b_mech(in)); + DBG (15, " back endorser stamp: %d\n", get_IN_endorser_b_stamp(in)); + DBG (15, " back endorser elec: %d\n", get_IN_endorser_b_elec(in)); + DBG (15, " endorser max id: %d\n", get_IN_endorser_max_id(in)); - DBG (15, " dropout spec: %d\n", get_IN_dropout_spec(in)); - DBG (15, " dropout non: %d\n", get_IN_dropout_non(in)); - DBG (15, " dropout white: %d\n", get_IN_dropout_white(in)); + DBG (15, " front endorser mech: %d\n", get_IN_endorser_f_mech(in)); + DBG (15, " front endorser stamp: %d\n", get_IN_endorser_f_stamp(in)); + DBG (15, " front endorser elec: %d\n", get_IN_endorser_f_elec(in)); - DBG (15, " skew check: %d\n", get_IN_skew_check(in)); - DBG (15, " new feed roller: %d\n", get_IN_new_fd_roll(in)); + s->endorser_type_b = get_IN_endorser_b_type(in); + DBG (15, " back endorser type: %d\n", s->endorser_type_b); - s->has_adv_paper_prot = get_IN_paper_prot_2(in); - DBG (15, " paper protection: %d\n", s->has_adv_paper_prot); - } + s->endorser_type_f = get_IN_endorser_f_type(in); + DBG (15, " back endorser type: %d\n", s->endorser_type_f); - if (get_IN_page_length (in) > 0x70-5) { + DBG (15, " connection type: %d\n", get_IN_connection(in)); - DBG (15, " paper count: %d\n", get_IN_paper_count(in)); - DBG (15, " paper number: %d\n", get_IN_paper_number(in)); - DBG (15, " ext send to: %d\n", get_IN_ext_send_to(in)); + DBG (15, " endorser ext: %d\n", get_IN_endorser_type_ext(in)); + DBG (15, " endorser pr_b: %d\n", get_IN_endorser_pre_back(in)); + DBG (15, " endorser pr_f: %d\n", get_IN_endorser_pre_front(in)); + DBG (15, " endorser po_b: %d\n", get_IN_endorser_post_back(in)); + DBG (15, " endorser po_f: %d\n", get_IN_endorser_post_front(in)); - s->has_staple_detect = get_IN_staple_det(in); - DBG (15, " staple det: %d\n", s->has_staple_detect); + s->os_x_basic = get_IN_x_overscan_size(in); + DBG (15, " horizontal overscan: %d\n", s->os_x_basic); - DBG (15, " pause host: %d\n", get_IN_pause_host(in)); - DBG (15, " pause panel: %d\n", get_IN_pause_panel(in)); - DBG (15, " pause conf: %d\n", get_IN_pause_conf(in)); - DBG (15, " hq print: %d\n", get_IN_hq_print(in)); + s->os_y_basic = get_IN_y_overscan_size(in); + DBG (15, " vertical overscan: %d\n", s->os_y_basic); - DBG (15, " ext GHS len: %d\n", get_IN_ext_GHS_len(in)); + /* not all scanners go this far */ + if (payload_off >= 0x68) { + DBG (15, " default bg adf b: %d\n", get_IN_default_bg_adf_b(in)); + DBG (15, " default bg adf f: %d\n", get_IN_default_bg_adf_f(in)); + DBG (15, " default bg fb: %d\n", get_IN_default_bg_fb(in)); + } - DBG (15, " smbc func: %d\n", get_IN_smbc_func(in)); - DBG (15, " imprint chk b: %d\n", get_IN_imprint_chk_b(in)); - DBG (15, " imprint chk f: %d\n", get_IN_imprint_chk_f(in)); - DBG (15, " force w bg: %d\n", get_IN_force_w_bg(in)); + if (payload_off >= 0x69) { + DBG (15, " auto color: %d\n", get_IN_auto_color(in)); + DBG (15, " blank skip: %d\n", get_IN_blank_skip(in)); + DBG (15, " multi image: %d\n", get_IN_multi_image(in)); + DBG (15, " f b type indep: %d\n", get_IN_f_b_type_indep(in)); + DBG (15, " f b res indep: %d\n", get_IN_f_b_res_indep(in)); + } - s->has_df_recovery = get_IN_mf_recover_lvl(in); - DBG (15, " mf recover lvl: %d\n", s->has_df_recovery); + if (payload_off >= 0x6a) { + DBG (15, " dropout spec: %d\n", get_IN_dropout_spec(in)); + DBG (15, " dropout non: %d\n", get_IN_dropout_non(in)); + DBG (15, " dropout white: %d\n", get_IN_dropout_white(in)); + } - DBG (15, " first read time: %d\n", get_IN_first_read_time(in)); - DBG (15, " div scanning: %d\n", get_IN_div_scanning(in)); - DBG (15, " start job: %d\n", get_IN_start_job(in)); - DBG (15, " lifetime log: %d\n", get_IN_lifetime_log(in)); - DBG (15, " imff save rest: %d\n", get_IN_imff_save_rest(in)); - DBG (15, " wide scsi type: %d\n", get_IN_wide_scsi_type(in)); + if (payload_off >= 0x6d) { + DBG (15, " skew check: %d\n", get_IN_skew_check(in)); + DBG (15, " new feed roller: %d\n", get_IN_new_fd_roll(in)); + s->has_adv_paper_prot = get_IN_paper_prot_2(in); + DBG (15, " paper protection: %d\n", s->has_adv_paper_prot); + } - DBG (15, " lut hybrid crop: %d\n", get_IN_lut_hybrid_crop(in)); - DBG (15, " over under amt: %d\n", get_IN_over_under_amt(in)); - DBG (15, " rgb lut: %d\n", get_IN_rgb_lut(in)); - DBG (15, " num lut dl: %d\n", get_IN_num_lut_dl(in)); + /* this one is weird, overrides the payload length from scanner, + * but the enlarged area is just null bytes, so we ignore this */ + if (payload_off >= 0x6f) { + DBG (15, " extra evpd length: %d\n", get_IN_evpd_len(in)); + } - s->has_off_mode = get_IN_erp_lot6_supp(in); - DBG (15, " ErP Lot6 (power off timer): %d\n", s->has_off_mode); - DBG (15, " sync next feed: %d\n", get_IN_sync_next_feed(in)); + if (payload_off >= 0x70) { + DBG (15, " paper count: %d\n", get_IN_paper_count(in)); + DBG (15, " paper number: %d\n", get_IN_paper_number(in)); + DBG (15, " ext send to: %d\n", get_IN_ext_send_to(in)); - s->has_op_halt = get_IN_op_halt(in); - DBG (15, " object position halt: %d\n", s->has_op_halt); - } + s->has_staple_detect = get_IN_staple_det(in); + DBG (15, " staple det: %d\n", s->has_staple_detect); - ret = SANE_STATUS_GOOD; - } + DBG (15, " pause host: %d\n", get_IN_pause_host(in)); + DBG (15, " pause panel: %d\n", get_IN_pause_panel(in)); + DBG (15, " pause conf: %d\n", get_IN_pause_conf(in)); + DBG (15, " hq print: %d\n", get_IN_hq_print(in)); + } - /*FIXME no vendor vpd, set some defaults? */ - else{ - DBG (5, "init_vpd: Your scanner supports only partial VPD?\n"); - DBG (5, "init_vpd: Please contact kitno455 at gmail dot com\n"); - DBG (5, "init_vpd: with details of your scanner model.\n"); - ret = SANE_STATUS_INVAL; - } + if (payload_off >= 0x71) { + DBG (15, " ext GHS len: %d\n", get_IN_ext_GHS_len(in)); } - /*FIXME no vpd, set some defaults? */ - else{ - DBG (5, "init_vpd: Your scanner does not support VPD?\n"); - DBG (5, "init_vpd: Please contact kitno455 at gmail dot com\n"); - DBG (5, "init_vpd: with details of your scanner model.\n"); + + if (payload_off >= 0x72) { + DBG (15, " smbc func: %d\n", get_IN_smbc_func(in)); + DBG (15, " imprint chk b: %d\n", get_IN_imprint_chk_b(in)); + DBG (15, " imprint chk f: %d\n", get_IN_imprint_chk_f(in)); + DBG (15, " force w bg: %d\n", get_IN_force_w_bg(in)); + + s->has_df_recovery = get_IN_mf_recover_lvl(in); + DBG (15, " mf recover lvl: %d\n", s->has_df_recovery); + } + + if (payload_off >= 0x73) { + DBG (15, " first read time: %d\n", get_IN_first_read_time(in)); + DBG (15, " div scanning: %d\n", get_IN_div_scanning(in)); + DBG (15, " start job: %d\n", get_IN_start_job(in)); + DBG (15, " lifetime log: %d\n", get_IN_lifetime_log(in)); + DBG (15, " imff save rest: %d\n", get_IN_imff_save_rest(in)); + DBG (15, " wide scsi type: %d\n", get_IN_wide_scsi_type(in)); + } + + if (payload_off >= 0x74) { + DBG (15, " lut hybrid crop: %d\n", get_IN_lut_hybrid_crop(in)); + DBG (15, " over under amt: %d\n", get_IN_over_under_amt(in)); + DBG (15, " rgb lut: %d\n", get_IN_rgb_lut(in)); + DBG (15, " num lut dl: %d\n", get_IN_num_lut_dl(in)); + } + + /* Various items below are poorly documented or missing */ + + if (payload_off >= 0x76) { + s->has_off_mode = get_IN_erp_lot6_supp(in); + DBG (15, " ErP Lot6 (power off timer): %d\n", s->has_off_mode); + DBG (15, " sync next feed: %d\n", get_IN_sync_next_feed(in)); + } + + if (payload_off >= 0x79) { + DBG (15, " battery: %d\n", get_IN_battery(in)); + DBG (15, " battery save: %d\n", get_IN_battery_save(in)); + DBG (15, " object position reverse: %d\n", get_IN_op_reverse(in)); + } + + if (payload_off >= 0x7a) { + s->has_op_halt = get_IN_op_halt(in); + DBG (15, " object position halt: %d\n", s->has_op_halt); } DBG (10, "init_vpd: finish\n"); - return ret; + return SANE_STATUS_GOOD; } static SANE_Status -init_ms(struct fujitsu *s) +init_ms(struct fujitsu *s) { int ret; int oldDbg=0; @@ -2543,9 +2590,9 @@ init_options (struct fujitsu *s) s->opt[i].cap = SANE_CAP_INACTIVE; } - /* go ahead and setup the first opt, because - * frontend may call control_option on it - * before calling get_option_descriptor + /* go ahead and setup the first opt, because + * frontend may call control_option on it + * before calling get_option_descriptor */ s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; @@ -2660,11 +2707,11 @@ init_serial (struct fujitsu *s) set_SCSI_opcode(cmd, SEND_DIAGNOSTIC_code); set_SD_slftst(cmd, 0); set_SD_xferlen(cmd, outLen); - + memcpy(out,SD_gdi_string,outLen); ret = do_cmd ( - s, 1, 0, + s, 1, 0, cmd, cmdLen, out, outLen, NULL, NULL @@ -2680,7 +2727,7 @@ init_serial (struct fujitsu *s) set_RD_xferlen(cmd, inLen); ret = do_cmd ( - s, 1, 0, + s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen @@ -2719,7 +2766,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) struct fujitsu *dev = NULL; struct fujitsu *s = NULL; SANE_Status ret; - + DBG (10, "sane_open: start\n"); if(fujitsu_devList){ @@ -2740,7 +2787,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) } else{ DBG (15, "sane_open: device %s requested\n", name); - + for (dev = fujitsu_devList; dev; dev = dev->next) { if (strcmp (dev->sane.name, name) == 0 || strcmp (dev->device_name, name) == 0) { /*always allow sanei devname*/ @@ -2816,7 +2863,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) } if(s->has_adf){ s->source_list[i++]=STRING_ADFFRONT; - + if(s->has_back){ s->source_list[i++]=STRING_ADFBACK; } @@ -2852,7 +2899,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->mode_list[i++]=STRING_COLOR; } s->mode_list[i]=NULL; - + opt->name = SANE_NAME_SCAN_MODE; opt->title = SANE_TITLE_SCAN_MODE; opt->desc = SANE_DESC_SCAN_MODE; @@ -2873,7 +2920,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_DPI; opt->cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - + if(s->step_x_res[s->s_mode] && s->step_y_res[s->s_mode]){ s->res_range.min = s->min_x_res; s->res_range.max = s->max_x_res; @@ -2895,7 +2942,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) } } s->res_list[0] = i; - + opt->constraint_type = SANE_CONSTRAINT_WORD_LIST; opt->constraint.word_list = s->res_list; } @@ -2917,7 +2964,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->tl_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x); s->tl_x_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_width(s)); s->tl_x_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_TL_X; opt->title = SANE_TITLE_SCAN_TL_X; opt->desc = SANE_DESC_SCAN_TL_X; @@ -2935,7 +2982,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->tl_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y); s->tl_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s)); s->tl_y_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_TL_Y; opt->title = SANE_TITLE_SCAN_TL_Y; opt->desc = SANE_DESC_SCAN_TL_Y; @@ -2953,7 +3000,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->br_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_x); s->br_x_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_width(s)); s->br_x_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_BR_X; opt->title = SANE_TITLE_SCAN_BR_X; opt->desc = SANE_DESC_SCAN_BR_X; @@ -2971,7 +3018,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->br_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->min_y); s->br_y_range.max = SCANNER_UNIT_TO_FIXED_MM(get_page_height(s)); s->br_y_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_BR_Y; opt->title = SANE_TITLE_SCAN_BR_Y; opt->desc = SANE_DESC_SCAN_BR_Y; @@ -3160,7 +3207,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->ht_type_list[i++]=STRING_DITHER; s->ht_type_list[i++]=STRING_DIFFUSION; s->ht_type_list[i]=NULL; - + opt->name = "ht-type"; opt->title = SANE_I18N ("Halftone type"); opt->desc = SANE_I18N ("Control type of halftone filter"); @@ -3265,7 +3312,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->wl_follow_list[i++]=STRING_ON; s->wl_follow_list[i++]=STRING_OFF; s->wl_follow_list[i]=NULL; - + opt->name = "wl-follow"; opt->title = SANE_I18N ("White level follower"); opt->desc = SANE_I18N ("Control white level follower"); @@ -3503,7 +3550,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*automatic width detection */ if(option==OPT_AWD){ - + opt->name = "awd"; opt->title = SANE_I18N ("Auto width detection"); opt->desc = SANE_I18N ("Scanner detects paper sides. May reduce scanning speed."); @@ -3521,7 +3568,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*automatic length detection */ if(option==OPT_ALD){ - + opt->name = "ald"; opt->title = SANE_I18N ("Auto length detection"); opt->desc = SANE_I18N ("Scanner detects paper lower edge. May confuse some frontends."); @@ -3600,7 +3647,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->df_action_list[1] = STRING_CONTINUE; s->df_action_list[2] = STRING_STOP; s->df_action_list[3] = NULL; - + opt->name = "df-action"; opt->title = SANE_I18N ("DF action"); opt->desc = SANE_I18N ("Action following double feed error"); @@ -3617,7 +3664,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*double feed by skew*/ if(option==OPT_DF_SKEW){ - + opt->name = "df-skew"; opt->title = SANE_I18N ("DF skew"); opt->desc = SANE_I18N ("Enable double feed error due to skew"); @@ -3636,7 +3683,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*double feed by thickness */ if(option==OPT_DF_THICKNESS){ - + opt->name = "df-thickness"; opt->title = SANE_I18N ("DF thickness"); opt->desc = SANE_I18N ("Enable double feed error due to paper thickness"); @@ -3655,7 +3702,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /*double feed by length*/ if(option==OPT_DF_LENGTH){ - + opt->name = "df-length"; opt->title = SANE_I18N ("DF length"); opt->desc = SANE_I18N ("Enable double feed error due to paper length"); @@ -3679,7 +3726,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->df_diff_list[2] = STRING_15MM; s->df_diff_list[3] = STRING_20MM; s->df_diff_list[4] = NULL; - + opt->name = "df-diff"; opt->title = SANE_I18N ("DF length difference"); opt->desc = SANE_I18N ("Difference in page length to trigger double feed error"); @@ -3703,7 +3750,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->df_recovery_list[1] = STRING_OFF; s->df_recovery_list[2] = STRING_ON; s->df_recovery_list[3] = NULL; - + opt->name = "df-recovery"; opt->title = SANE_I18N ("DF recovery mode"); opt->desc = SANE_I18N ("Request scanner to reverse feed on paper jam"); @@ -3723,7 +3770,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->paper_protect_list[1] = STRING_OFF; s->paper_protect_list[2] = STRING_ON; s->paper_protect_list[3] = NULL; - + opt->name = "paper-protect"; opt->title = SANE_I18N ("Paper protection"); opt->desc = SANE_I18N ("Request scanner to predict jams in the ADF"); @@ -3743,7 +3790,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->adv_paper_prot_list[1] = STRING_OFF; s->adv_paper_prot_list[2] = STRING_ON; s->adv_paper_prot_list[3] = NULL; - + opt->name = "adv-paper-protect"; opt->title = SANE_I18N ("Advanced paper protection"); opt->desc = SANE_I18N ("Request scanner to predict jams in the ADF using improved sensors"); @@ -3763,7 +3810,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->staple_detect_list[1] = STRING_OFF; s->staple_detect_list[2] = STRING_ON; s->staple_detect_list[3] = NULL; - + opt->name = "staple-detect"; opt->title = SANE_I18N ("Staple detection"); opt->desc = SANE_I18N ("Request scanner to detect jams in the ADF caused by staples"); @@ -3783,7 +3830,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->bg_color_list[1] = STRING_WHITE; s->bg_color_list[2] = STRING_BLACK; s->bg_color_list[3] = NULL; - + opt->name = "bgcolor"; opt->title = SANE_I18N ("Background color"); opt->desc = SANE_I18N ("Set color of background for scans. May conflict with overscan option"); @@ -3804,7 +3851,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->do_color_list[2] = STRING_GREEN; s->do_color_list[3] = STRING_BLUE; s->do_color_list[4] = NULL; - + opt->name = "dropoutcolor"; opt->title = SANE_I18N ("Dropout color"); opt->desc = SANE_I18N ("One-pass scanners use only one color during gray or binary scanning, useful for colored paper or ink"); @@ -3828,7 +3875,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->buff_mode_list[1] = STRING_OFF; s->buff_mode_list[2] = STRING_ON; s->buff_mode_list[3] = NULL; - + opt->name = "buffermode"; opt->title = SANE_I18N ("Buffer mode"); opt->desc = SANE_I18N ("Request scanner to read pages quickly from ADF into internal memory"); @@ -3848,7 +3895,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->prepick_list[1] = STRING_OFF; s->prepick_list[2] = STRING_ON; s->prepick_list[3] = NULL; - + opt->name = "prepick"; opt->title = SANE_I18N ("Prepick"); opt->desc = SANE_I18N ("Request scanner to grab next page from ADF"); @@ -3868,7 +3915,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->overscan_list[1] = STRING_OFF; s->overscan_list[2] = STRING_ON; s->overscan_list[3] = NULL; - + opt->name = "overscan"; opt->title = SANE_I18N ("Overscan"); opt->desc = SANE_I18N ("Collect a few mm of background on top side of scan, before paper enters ADF, and increase maximum scan area beyond paper size, to allow collection on remaining sides. May conflict with bgcolor option"); @@ -3887,10 +3934,10 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->sleep_time_range.min = 0; s->sleep_time_range.max = 60; s->sleep_time_range.quant = 1; - + opt->name = "sleeptimer"; opt->title = SANE_I18N ("Sleep timer"); - opt->desc = SANE_I18N ("Time in minutes until the internal power supply switches to sleep mode"); + opt->desc = SANE_I18N ("Time in minutes until the internal power supply switches to sleep mode"); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3906,10 +3953,10 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->off_time_range.min = 0; s->off_time_range.max = 960; s->off_time_range.quant = 1; - + opt->name = "offtimer"; opt->title = SANE_I18N ("Off timer"); - opt->desc = SANE_I18N ("Time in minutes until the internal power supply switches the scanner off. Will be rounded to nearest 15 minutes. Zero means never power off."); + opt->desc = SANE_I18N ("Time in minutes until the internal power supply switches the scanner off. Will be rounded to nearest 15 minutes. Zero means never power off."); opt->type = SANE_TYPE_INT; opt->unit = SANE_UNIT_NONE; opt->constraint_type = SANE_CONSTRAINT_RANGE; @@ -3925,7 +3972,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->duplex_offset_range.min = -16; s->duplex_offset_range.max = 16; s->duplex_offset_range.quant = 1; - + opt->name = "duplexoffset"; opt->title = SANE_I18N ("Duplex offset"); opt->desc = SANE_I18N ("Adjust front/back offset"); @@ -3943,7 +3990,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->green_offset_range.min = -16; s->green_offset_range.max = 16; s->green_offset_range.quant = 1; - + opt->name = "greenoffset"; opt->title = SANE_I18N ("Green offset"); opt->desc = SANE_I18N ("Adjust green/red offset"); @@ -3956,12 +4003,12 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) else opt->cap = SANE_CAP_INACTIVE; } - + if(option==OPT_BLUE_OFFSET){ s->blue_offset_range.min = -16; s->blue_offset_range.max = 16; s->blue_offset_range.quant = 1; - + opt->name = "blueoffset"; opt->title = SANE_I18N ("Blue offset"); opt->desc = SANE_I18N ("Adjust blue/red offset"); @@ -3974,7 +4021,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) else opt->cap = SANE_CAP_INACTIVE; } - + if(option==OPT_LOW_MEM){ opt->name = "lowmemory"; opt->title = SANE_I18N ("Low Memory"); @@ -3985,7 +4032,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if (1) opt->cap= SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; opt->constraint_type = SANE_CONSTRAINT_NONE; @@ -4112,7 +4159,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if (s->has_endorser_f || s->has_endorser_b) opt->cap= SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; opt->constraint_type = SANE_CONSTRAINT_NONE; @@ -4335,7 +4382,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4347,7 +4394,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4359,7 +4406,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4371,7 +4418,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4383,7 +4430,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4395,7 +4442,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4407,7 +4454,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4419,7 +4466,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4431,7 +4478,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4443,7 +4490,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4455,7 +4502,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4467,7 +4514,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4479,7 +4526,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4491,7 +4538,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status && (s->has_endorser_f || s->has_endorser_b)) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4503,7 +4550,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4515,7 +4562,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4527,7 +4574,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4539,7 +4586,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status && (s->has_endorser_f || s->has_endorser_b)) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4551,7 +4598,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4563,7 +4610,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) opt->unit = SANE_UNIT_NONE; if (s->ghs_in_rs) opt->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else + else opt->cap = SANE_CAP_INACTIVE; } @@ -4572,7 +4619,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /** * Gets or sets an option value. - * + * * From the SANE spec: * This function is used to set or inquire the current value of option * number n of the device represented by handle h. The manner in which @@ -4583,7 +4630,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) * area pointed to by v must be big enough to hold the entire option * value (determined by member size in the corresponding option * descriptor). - * + * * The only exception to this rule is that when setting the value of a * string option, the string pointed to by argument v may be shorter * since the backend will stop reading the option value upon @@ -5056,23 +5103,23 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_ENDORSER: *val_p = s->u_endorser; return SANE_STATUS_GOOD; - + case OPT_ENDORSER_BITS: *val_p = s->u_endorser_bits; return SANE_STATUS_GOOD; - + case OPT_ENDORSER_VAL: *val_p = s->u_endorser_val; return SANE_STATUS_GOOD; - + case OPT_ENDORSER_STEP: *val_p = s->u_endorser_step; return SANE_STATUS_GOOD; - + case OPT_ENDORSER_Y: *val_p = SCANNER_UNIT_TO_FIXED_MM(s->u_endorser_y); return SANE_STATUS_GOOD; - + case OPT_ENDORSER_FONT: switch (s->u_endorser_font) { case FONT_H: @@ -5092,7 +5139,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, break; } return SANE_STATUS_GOOD; - + case OPT_ENDORSER_DIR: switch (s->u_endorser_dir) { case DIR_TTB: @@ -5103,7 +5150,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, break; } return SANE_STATUS_GOOD; - + case OPT_ENDORSER_SIDE: switch (s->u_endorser_side) { case ED_front: @@ -5114,7 +5161,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, break; } return SANE_STATUS_GOOD; - + case OPT_ENDORSER_STRING: strncpy( (SANE_String)val, @@ -5128,102 +5175,102 @@ sane_control_option (SANE_Handle handle, SANE_Int option, ret = get_hardware_status(s,option); *val_p = s->hw_top; return ret; - + case OPT_A3: ret = get_hardware_status(s,option); *val_p = s->hw_A3; return ret; - + case OPT_B4: ret = get_hardware_status(s,option); *val_p = s->hw_B4; return ret; - + case OPT_A4: ret = get_hardware_status(s,option); *val_p = s->hw_A4; return ret; - + case OPT_B5: ret = get_hardware_status(s,option); *val_p = s->hw_B5; return ret; - + case OPT_HOPPER: ret = get_hardware_status(s,option); *val_p = s->hw_hopper; return ret; - + case OPT_OMR: ret = get_hardware_status(s,option); *val_p = s->hw_omr; return ret; - + case OPT_ADF_OPEN: ret = get_hardware_status(s,option); *val_p = s->hw_adf_open; return ret; - + case OPT_SLEEP: ret = get_hardware_status(s,option); *val_p = s->hw_sleep; return ret; - + case OPT_SEND_SW: ret = get_hardware_status(s,option); *val_p = s->hw_send_sw; return ret; - + case OPT_MANUAL_FEED: ret = get_hardware_status(s,option); *val_p = s->hw_manual_feed; return ret; - + case OPT_SCAN_SW: ret = get_hardware_status(s,option); *val_p = s->hw_scan_sw; return ret; - + case OPT_FUNCTION: ret = get_hardware_status(s,option); *val_p = s->hw_function; return ret; - + case OPT_INK_EMPTY: ret = get_hardware_status(s,option); *val_p = s->hw_ink_empty; return ret; - + case OPT_DOUBLE_FEED: ret = get_hardware_status(s,option); *val_p = s->hw_double_feed; return ret; - + case OPT_ERROR_CODE: ret = get_hardware_status(s,option); *val_p = s->hw_error_code; return ret; - + case OPT_SKEW_ANGLE: ret = get_hardware_status(s,option); *val_p = s->hw_skew_angle; return ret; - + case OPT_INK_REMAIN: ret = get_hardware_status(s,option); *val_p = s->hw_ink_remain; return ret; - + case OPT_DENSITY_SW: ret = get_hardware_status(s,option); *val_p = s->hw_density_sw; return ret; - + case OPT_DUPLEX_SW: ret = get_hardware_status(s,option); *val_p = s->hw_duplex_sw; return ret; - + } } else if (action == SANE_ACTION_SET_VALUE) { @@ -5260,7 +5307,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, * below. */ switch (option) { - + /* Mode Group */ case OPT_SOURCE: if (!strcmp (val, STRING_ADFFRONT)) { @@ -5276,7 +5323,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, tmp = SOURCE_FLATBED; } - if (s->source == tmp) + if (s->source == tmp) return SANE_STATUS_GOOD; s->source = tmp; @@ -5307,7 +5354,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_RES: - if (s->resolution_x == val_c) + if (s->resolution_x == val_c) return SANE_STATUS_GOOD; s->resolution_x = val_c; @@ -5703,24 +5750,24 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->u_endorser = val_c; *info |= SANE_INFO_RELOAD_OPTIONS; return SANE_STATUS_GOOD; - + case OPT_ENDORSER_BITS: s->u_endorser_bits = val_c; return SANE_STATUS_GOOD; - + /*this val not used in send_endorser*/ case OPT_ENDORSER_VAL: s->u_endorser_val = val_c; return SANE_STATUS_GOOD; - + case OPT_ENDORSER_STEP: s->u_endorser_step = val_c; return SANE_STATUS_GOOD; - + case OPT_ENDORSER_Y: s->u_endorser_y = FIXED_MM_TO_SCANNER_UNIT(val_c); return SANE_STATUS_GOOD; - + case OPT_ENDORSER_FONT: if (!strcmp (val, STRING_HORIZONTAL)){ @@ -5739,7 +5786,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->u_endorser_font = FONT_VB; } return SANE_STATUS_GOOD; - + case OPT_ENDORSER_DIR: if (!strcmp (val, STRING_TOPTOBOTTOM)){ s->u_endorser_dir = DIR_TTB; @@ -5748,7 +5795,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->u_endorser_dir = DIR_BTT; } return SANE_STATUS_GOOD; - + /*this val not used in send_endorser*/ case OPT_ENDORSER_SIDE: if (!strcmp (val, STRING_FRONT)){ @@ -5758,7 +5805,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->u_endorser_side = ED_back; } return SANE_STATUS_GOOD; - + case OPT_ENDORSER_STRING: strncpy( (SANE_String)s->u_endorser_string, @@ -5773,7 +5820,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, } static SANE_Status -set_sleep_mode(struct fujitsu *s) +set_sleep_mode(struct fujitsu *s) { SANE_Status ret = SANE_STATUS_GOOD; @@ -5830,13 +5877,13 @@ set_off_mode(struct fujitsu *s) set_SCSI_opcode(cmd, SEND_DIAGNOSTIC_code); set_SD_slftst(cmd, 0); set_SD_xferlen(cmd, outLen); - + memcpy(out,SD_powoff_string,SD_powoff_stringlen); set_SD_powoff_disable(out,!s->off_time); set_SD_powoff_interval(out,s->off_time/15); ret = do_cmd ( - s, 1, 0, + s, 1, 0, cmd, cmdLen, out, outLen, NULL, NULL @@ -5880,14 +5927,14 @@ get_hardware_status (struct fujitsu *s, SANE_Int option) set_GHS_allocation_length(cmd, inLen); DBG (15, "get_hardware_status: calling ghs\n"); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen ); - + if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { s->hw_top = get_GHS_top(in); @@ -5895,23 +5942,23 @@ get_hardware_status (struct fujitsu *s, SANE_Int option) s->hw_B4 = get_GHS_B4(in); s->hw_A4 = get_GHS_A4(in); s->hw_B5 = get_GHS_B5(in); - + s->hw_hopper = get_GHS_hopper(in); s->hw_omr = get_GHS_omr(in); s->hw_adf_open = get_GHS_adf_open(in); - + s->hw_sleep = get_GHS_sleep(in); s->hw_send_sw = get_GHS_send_sw(in); s->hw_manual_feed = get_GHS_manual_feed(in); s->hw_scan_sw = get_GHS_scan_sw(in); - + s->hw_function = get_GHS_function(in); s->hw_ink_empty = get_GHS_ink_empty(in); s->hw_double_feed = get_GHS_double_feed(in); - + s->hw_error_code = get_GHS_error_code(in); - + s->hw_skew_angle = get_GHS_skew_angle(in); if(inLen > 9){ @@ -5942,7 +5989,7 @@ get_hardware_status (struct fujitsu *s, SANE_Int option) NULL,0, in, &inLen ); - + /* parse the rs data */ if(ret == SANE_STATUS_GOOD){ if(get_RS_sense_key(in)==0 && get_RS_ASC(in)==0x80){ @@ -5972,13 +6019,13 @@ get_hardware_status (struct fujitsu *s, SANE_Int option) } static SANE_Status -send_endorser(struct fujitsu *s) +send_endorser(struct fujitsu *s) { SANE_Status ret = SANE_STATUS_GOOD; unsigned char cmd[SEND_len]; size_t cmdLen = SEND_len; - + size_t strLen = strlen(s->u_endorser_string); unsigned char out[S_e_data_max_len]; /*we probably send less below*/ @@ -6080,7 +6127,7 @@ send_endorser(struct fujitsu *s) /* instead of internal brightness/contrast/gamma most scanners use a 256x256 or 1024x256 LUT default is linear table of slope 1 or 1/4 resp. - brightness and contrast inputs are -127 to +127 + brightness and contrast inputs are -127 to +127 contrast rotates slope of line around central input val @@ -6096,7 +6143,7 @@ send_endorser(struct fujitsu *s) bright dark . xxxxxxxx . - . x . + . x . out x . x . . x ............ xxxxxxxx.... @@ -6128,7 +6175,7 @@ send_lut (struct fujitsu *s) * first [-127,127] to [0,254] then to [0,1] * then multiply by PI/2 to convert to radians * then take the tangent to get slope (T.O.A) - * then multiply by the normal linear slope + * then multiply by the normal linear slope * because the table may not be square, i.e. 1024x256*/ slope = tan(((double)s->contrast+127)/254 * M_PI/2) * 256/bytes; @@ -6156,7 +6203,7 @@ send_lut (struct fujitsu *s) set_S_lut_order (out, S_lut_order_single); set_S_lut_ssize (out, bytes); set_S_lut_dsize (out, 256); - + for(i=0;iresolution_x); set_SD_preread_yres(out,s->resolution_y); @@ -6322,7 +6369,7 @@ diag_preread (struct fujitsu *s) set_SD_preread_composition(out, s->s_mode); ret = do_cmd ( - s, 1, 0, + s, 1, 0, cmd, cmdLen, out, outLen, NULL, NULL @@ -6374,17 +6421,17 @@ mode_select_df (struct fujitsu *s) if(s->df_action == DF_CONTINUE){ set_MSEL_df_continue (page, 1); } - + /* skew */ if(s->df_skew){ set_MSEL_df_skew (page, 1); } - + /* thickness */ if(s->df_thickness){ set_MSEL_df_thickness (page, 1); } - + /* length */ if(s->df_length){ set_MSEL_df_length (page, 1); @@ -6446,7 +6493,7 @@ mode_select_bg (struct fujitsu *s) set_MSEL_bg_fb (page, 1); } } - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -6489,7 +6536,7 @@ mode_select_dropout (struct fujitsu *s) set_MSEL_dropout_front (page, s->dropout_color); set_MSEL_dropout_back (page, s->dropout_color); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -6574,7 +6621,7 @@ mode_select_prepick (struct fujitsu *s) set_MSEL_page_len(page, MSEL_data_min_len-2); set_MSEL_prepick(page, s->prepick); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -6620,7 +6667,7 @@ mode_select_auto (struct fujitsu *s) set_MSEL_awd(page, s->awd || s->hwdeskewcrop); set_MSEL_req_driv_crop(page, s->hwdeskewcrop && (s->swcrop || s->swdeskew)); set_MSEL_deskew(page, s->hwdeskewcrop); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -6648,7 +6695,7 @@ mode_select_auto (struct fujitsu *s) * completion of that request. Outside of that window, the returned * values are best-effort estimates of what the parameters will be * when sane_start() gets invoked. - * + * * Calling this function before a scan has actually started allows, * for example, to get an estimate of how big the scanned image will * be. The parameters passed to this function are the handle h of the @@ -6660,9 +6707,9 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) { SANE_Status ret = SANE_STATUS_GOOD; struct fujitsu *s = (struct fujitsu *) handle; - + DBG (10, "sane_get_parameters: start\n"); - + /* not started? update param data from user settings */ if(!s->started){ ret = update_params(s); @@ -6760,10 +6807,10 @@ update_params (struct fujitsu * s) DBG(15,"update_params: area: tlx=%d, brx=%d, tly=%d, bry=%d\n", s->tl_x, s->br_x, s->tl_y, s->br_y); - DBG(15,"update_params: params: ppl=%d, Bpl=%d, lines=%d\n", + DBG(15,"update_params: params: ppl=%d, Bpl=%d, lines=%d\n", params->pixels_per_line, params->bytes_per_line, params->lines); - DBG(15,"update_params: params: format=%d, depth=%d, last=%d\n", + DBG(15,"update_params: params: format=%d, depth=%d, last=%d\n", params->format, params->depth, params->last_frame); /* second, we setup u_params to describe the image to the user */ @@ -6801,20 +6848,20 @@ update_u_params (struct fujitsu * s) params->format = SANE_FRAME_GRAY; params->bytes_per_line = params->pixels_per_line / 8; } - + DBG(15,"update_u_params: x: max=%d, page=%d, gpw=%d, res=%d\n", s->max_x, s->page_width, get_page_width(s), s->resolution_x); - + DBG(15,"update_u_params: y: max=%d, page=%d, gph=%d, res=%d\n", s->max_y, s->page_height, get_page_height(s), s->resolution_y); - + DBG(15,"update_u_params: area: tlx=%d, brx=%d, tly=%d, bry=%d\n", s->tl_x, s->br_x, s->tl_y, s->br_y); - - DBG(15,"update_u_params: params: ppl=%d, Bpl=%d, lines=%d\n", + + DBG(15,"update_u_params: params: ppl=%d, Bpl=%d, lines=%d\n", params->pixels_per_line, params->bytes_per_line, params->lines); - - DBG(15,"update_u_params: params: format=%d, depth=%d, last=%d\n", + + DBG(15,"update_u_params: params: format=%d, depth=%d, last=%d\n", params->format, params->depth, params->last_frame); } @@ -6939,14 +6986,14 @@ sane_start (SANE_Handle handle) if (ret != SANE_STATUS_GOOD) DBG (5, "sane_start: WARNING: cannot early send_lut %d\n", ret); } - + /* set window command */ ret = set_window(s); if (ret != SANE_STATUS_GOOD) { DBG (5, "sane_start: ERROR: cannot set window\n"); goto errors; } - + /* send lut if scanner has no hardware brightness/contrast, * or we are going to ask it to use a downloaded gamma table */ if (s->late_lut && (!s->brightness_steps || !s->contrast_steps || s->window_gamma & 0x80)){ @@ -6954,7 +7001,7 @@ sane_start (SANE_Handle handle) if (ret != SANE_STATUS_GOOD) DBG (5, "sane_start: WARNING: cannot late send_lut %d\n", ret); } - + /* some scanners need the q table sent, even when not scanning jpeg */ if (s->need_q_table){ ret = send_q_table(s); @@ -6968,7 +7015,7 @@ sane_start (SANE_Handle handle) DBG (5, "sane_start: ERROR: cannot start/stop endorser\n"); goto errors; } - + /* turn lamp on */ ret = scanner_control(s, SC_function_lamp_on); if (ret != SANE_STATUS_GOOD) { @@ -7043,7 +7090,7 @@ sane_start (SANE_Handle handle) goto errors; } - /* store the number of front bytes */ + /* store the number of front bytes */ if ( s->source != SOURCE_ADF_BACK ){ s->bytes_tot[SIDE_FRONT] = s->s_params.bytes_per_line * s->s_params.lines; s->buff_tot[SIDE_FRONT] = s->buffer_size; @@ -7062,7 +7109,7 @@ sane_start (SANE_Handle handle) s->buff_tot[SIDE_FRONT] = 0; } - /* store the number of back bytes */ + /* store the number of back bytes */ if ( s->source == SOURCE_ADF_DUPLEX || s->source == SOURCE_ADF_BACK ){ s->bytes_tot[SIDE_BACK] = s->s_params.bytes_per_line * s->s_params.lines; s->buff_tot[SIDE_BACK] = s->bytes_tot[SIDE_BACK]; @@ -7087,7 +7134,7 @@ sane_start (SANE_Handle handle) DBG (5, "sane_start: ERROR: cannot load buffers\n"); goto errors; } - + s->started=1; } } @@ -7102,9 +7149,9 @@ sane_start (SANE_Handle handle) DBG (15, "started=%d, side=%d, source=%d\n", s->started, s->side, s->source); - /* certain options require the entire image to + /* certain options require the entire image to * be collected from the scanner before we can - * tell the user the size of the image. the sane + * tell the user the size of the image. the sane * API has no way to inform the frontend of this, * so we block and buffer. yuck */ if( must_fully_buffer(s) ){ @@ -7142,7 +7189,7 @@ sane_start (SANE_Handle handle) } if(s->swskip){ /* Skipping means throwing out this image. - * Pretend the user read the whole thing + * Pretend the user read the whole thing * and call sane_start again. * This assumes we are running in batch mode. */ if(buffer_isblank(s,s->side)){ @@ -7166,7 +7213,7 @@ sane_start (SANE_Handle handle) errors: DBG (10, "sane_start: error %d\n", ret); - /* if we are started, but something went wrong, + /* if we are started, but something went wrong, * chances are there is image data inside scanner, * which should be discarded via cancel command */ if(s->started){ @@ -7181,7 +7228,7 @@ sane_start (SANE_Handle handle) } static SANE_Status -endorser(struct fujitsu *s) +endorser(struct fujitsu *s) { SANE_Status ret = SANE_STATUS_GOOD; @@ -7243,7 +7290,7 @@ endorser(struct fujitsu *s) } static SANE_Status -scanner_control (struct fujitsu *s, int function) +scanner_control (struct fujitsu *s, int function) { SANE_Status ret = SANE_STATUS_GOOD; int tries = 0; @@ -7283,7 +7330,7 @@ scanner_control (struct fujitsu *s, int function) } usleep(500000); - } + } if(ret == SANE_STATUS_GOOD){ DBG (15, "scanner_control: success, tries %d, ret %d\n",tries,ret); @@ -7299,7 +7346,7 @@ scanner_control (struct fujitsu *s, int function) } static SANE_Status -scanner_control_ric (struct fujitsu *s, int bytes, int side) +scanner_control_ric (struct fujitsu *s, int bytes, int side) { SANE_Status ret = SANE_STATUS_GOOD; int tries = 0; @@ -7325,7 +7372,7 @@ scanner_control_ric (struct fujitsu *s, int bytes, int side) set_SC_ric_len(cmd, bytes); DBG (15, "scanner_control_ric: %d %d\n",bytes,side); - + /* extremely long retry period */ while(tries++ < 120){ @@ -7341,7 +7388,7 @@ scanner_control_ric (struct fujitsu *s, int bytes, int side) } usleep(500000); - } + } if(ret == SANE_STATUS_GOOD){ DBG (15, "scanner_control_ric: success, tries %d, ret %d\n",tries,ret); @@ -7408,14 +7455,14 @@ set_window (struct fujitsu *s) { SANE_Status ret = SANE_STATUS_GOOD; - /* The command specifies the number of bytes in the data phase - * the data phase has a header, followed by 1 or 2 window desc blocks + /* The command specifies the number of bytes in the data phase + * the data phase has a header, followed by 1 or 2 window desc blocks * the header specifies the number of bytes in 1 window desc block */ unsigned char cmd[SET_WINDOW_len]; size_t cmdLen = SET_WINDOW_len; - + /*this is max size, we might send less below*/ unsigned char out[SW_header_len + SW_desc_len + SW_desc_len]; size_t outLen = SW_header_len + SW_desc_len + SW_desc_len; @@ -7687,7 +7734,7 @@ get_pixelsize(struct fujitsu *s, int actual) set_R_window_id (cmd, WD_wid_front); } set_R_xfer_length (cmd, inLen); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -7732,7 +7779,7 @@ get_pixelsize(struct fujitsu *s, int actual) else { s->s_params.bytes_per_line = s->s_params.pixels_per_line / 8; } - + /* some scanners can request that the driver clean img */ if(!s->has_short_pixelsize && get_PSIZE_req_driv_valid(in)){ s->req_driv_crop = get_PSIZE_req_driv_crop(in); @@ -7741,7 +7788,7 @@ get_pixelsize(struct fujitsu *s, int actual) s->req_driv_crop,s->req_driv_lut); } - DBG (15, "get_pixelsize: scan_x=%d, Bpl=%d, scan_y=%d\n", + DBG (15, "get_pixelsize: scan_x=%d, Bpl=%d, scan_y=%d\n", s->s_params.pixels_per_line, s->s_params.bytes_per_line, s->s_params.lines ); /* the user params are usually the same */ @@ -7758,7 +7805,7 @@ get_pixelsize(struct fujitsu *s, int actual) else { s->u_params.bytes_per_line = s->u_params.pixels_per_line / 8; } - + } else{ DBG (10, "get_pixelsize: got bad status %d, ignoring\n", ret); @@ -7812,7 +7859,7 @@ object_position (struct fujitsu *s, int action) /* * Issues SCAN command. - * + * * (This doesn't actually read anything, it just tells the scanner * to start scanning.) */ @@ -7897,7 +7944,7 @@ check_for_cancel(struct fujitsu *s) /* * Called by SANE to read data. - * + * * From the SANE spec: * This function is used to read image data from the device * represented by handle h. Argument buf is a pointer to a memory @@ -7905,7 +7952,7 @@ check_for_cancel(struct fujitsu *s) * returned is stored in *len. A backend must set this to zero when * the call fails (i.e., when a status other than SANE_STATUS_GOOD is * returned). - * + * * When the call succeeds, the number of bytes returned can be * anywhere in the range from 0 to maxlen bytes. */ @@ -7963,7 +8010,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len /* alternating jpeg duplex interlacing */ else if(s->source == SOURCE_ADF_DUPLEX - && s->s_params.format == SANE_FRAME_JPEG + && s->s_params.format == SANE_FRAME_JPEG && s->jpeg_interlace == JPEG_INTERLACE_ALT ){ ret = read_from_JPEGduplex(s); @@ -7985,7 +8032,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int * len DBG(5,"sane_read: front returning %d\n",ret); return ret; } - + /* buffer back side, but don't get too far ahead of the front! */ if(s->bytes_rx[SIDE_BACK] < s->bytes_rx[SIDE_FRONT] + s->buffer_size){ ret = read_from_scanner(s, SIDE_BACK); @@ -8084,9 +8131,9 @@ read_from_JPEGduplex(struct fujitsu *s) int bytes = s->buffer_size; int i = 0; - + DBG (10, "read_from_JPEGduplex: start\n"); - + if(s->eof_rx[SIDE_FRONT] && s->eof_rx[SIDE_BACK]){ DBG (10, "read_from_JPEGduplex: already have eofs, done\n"); return ret; @@ -8112,7 +8159,7 @@ read_from_JPEGduplex(struct fujitsu *s) bytes -= JFIF_APP0_LENGTH; } } - + DBG(15, "read_from_JPEGduplex: fto:%d frx:%d bto:%d brx:%d pa:%d\n", s->bytes_tot[SIDE_FRONT], s->bytes_rx[SIDE_FRONT], s->bytes_tot[SIDE_BACK], s->bytes_rx[SIDE_BACK], @@ -8123,7 +8170,7 @@ read_from_JPEGduplex(struct fujitsu *s) DBG(5, "read_from_JPEGduplex: Warning: no bytes this pass\n"); return ret; } - + /* fi-6770A gets mad if you 'read' too soon on usb, see if it is ready */ if(!s->bytes_rx[SIDE_FRONT] && s->connection == CONNECTION_USB){ DBG (15, "read: start of usb page, checking RIC\n"); @@ -8147,14 +8194,14 @@ read_from_JPEGduplex(struct fujitsu *s) /* interlaced jpeg duplex always reads from front */ set_R_window_id (cmd, WD_wid_front); set_R_xfer_length (cmd, inLen); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen ); - + if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { DBG(15, "read_from_JPEGduplex: got GOOD/EOF, returning GOOD\n"); } @@ -8167,7 +8214,7 @@ read_from_JPEGduplex(struct fujitsu *s) DBG(5, "read_from_JPEGduplex: error reading data status = %d\n", ret); inLen = 0; } - + for(i=0;i<(int)inLen;i++){ /* about to change stage */ @@ -8359,9 +8406,9 @@ read_from_JPEGduplex(struct fujitsu *s) s->eof_rx[SIDE_BACK] = 1; } } - + free(in); - + /* jpeg uses in-band EOI marker, so this is ususally redundant */ if(ret == SANE_STATUS_EOF){ DBG(15, "read_from_JPEGduplex: got EOF, finishing\n"); @@ -8372,7 +8419,7 @@ read_from_JPEGduplex(struct fujitsu *s) } DBG (10, "read_from_JPEGduplex: finish\n"); - + return ret; } @@ -8411,7 +8458,7 @@ read_from_3091duplex(struct fujitsu *s) if(bytes > avail) bytes = avail; } - + /* all requests must end on a line boundary */ bytes -= (bytes % s->s_params.bytes_per_line); @@ -8534,9 +8581,9 @@ read_from_scanner(struct fujitsu *s, int side) int bytes = s->buffer_size; int avail = s->buff_tot[side] - s->buff_rx[side]; int remain = s->bytes_tot[side] - s->bytes_rx[side]; - + DBG (10, "read_from_scanner: start %d\n", side); - + if(s->eof_rx[side]){ DBG (10, "read_from_scanner: already have eof, done\n"); return ret; @@ -8545,7 +8592,7 @@ read_from_scanner(struct fujitsu *s, int side) /* figure out the max amount to transfer */ if(bytes > avail) bytes = avail; - + /* all requests must end on line boundary */ bytes -= (bytes % s->s_params.bytes_per_line); @@ -8559,7 +8606,7 @@ read_from_scanner(struct fujitsu *s, int side) /* jpeg scans leave space for JFIF header at start of image */ if(s->s_params.format == SANE_FRAME_JPEG && s->bytes_rx[side] < 2) bytes -= JFIF_APP0_LENGTH; - + DBG(15, "read_from_scanner: si:%d re:%d bs:%d by:%d av:%d\n", side, remain, s->buffer_size, bytes, avail); @@ -8569,13 +8616,13 @@ read_from_scanner(struct fujitsu *s, int side) DBG(15, "read_from_scanner: buf to:%d rx:%d tx:%d\n", s->buff_tot[side], s->buff_rx[side], s->buff_tx[side]); - + /* this will happen if buffer is not drained yet */ if(bytes < 1){ DBG(5, "read_from_scanner: no bytes this pass\n"); return ret; } - + /* fi-6770A gets mad if you 'read' too soon on usb, see if it is ready */ if(!s->bytes_rx[side] && s->connection == CONNECTION_USB){ DBG (15, "read_from_scanner: start of usb page, checking RIC\n"); @@ -8592,27 +8639,27 @@ read_from_scanner(struct fujitsu *s, int side) DBG(5, "read_from_scanner: not enough mem for buffer: %d\n",(int)inLen); return SANE_STATUS_NO_MEM; } - + memset(cmd,0,cmdLen); set_SCSI_opcode(cmd, READ_code); set_R_datatype_code (cmd, R_datatype_imagedata); - + if (side == SIDE_BACK) { set_R_window_id (cmd, WD_wid_back); } else{ set_R_window_id (cmd, WD_wid_front); } - + set_R_xfer_length (cmd, inLen); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen ); - + if (ret == SANE_STATUS_GOOD || ret == SANE_STATUS_EOF) { DBG(15, "read_from_scanner: got GOOD/EOF, returning GOOD\n"); ret = SANE_STATUS_GOOD; @@ -8626,7 +8673,7 @@ read_from_scanner(struct fujitsu *s, int side) DBG(5, "read_from_scanner: error reading data block status = %d\n",ret); inLen = 0; } - + DBG(15, "read_from_scanner: read %lu bytes\n",(unsigned long)inLen); if(inLen){ @@ -8640,7 +8687,7 @@ read_from_scanner(struct fujitsu *s, int side) copy_buffer (s, in, inLen, side); } } - + free(in); /* if this was a short read or not, log it */ @@ -8655,7 +8702,7 @@ read_from_scanner(struct fujitsu *s, int side) s->eom_rx = 1; } - /* paper ran out. lets try to set the eof flag on both sides, + /* paper ran out. lets try to set the eof flag on both sides, * but only if that side had a short read last time */ if(s->eom_rx){ int i; @@ -8668,7 +8715,7 @@ read_from_scanner(struct fujitsu *s, int side) } DBG (10, "read_from_scanner: finish\n"); - + return ret; } @@ -8682,7 +8729,7 @@ copy_3091(struct fujitsu *s, unsigned char * buf, int len, int side) /* Data is RR...GG...BB... on each line, * green is back 8 lines from red at 300 dpi - * blue is back 4 lines from red at 300 dpi. + * blue is back 4 lines from red at 300 dpi. * * Here, we get things on correct line, and * interlace to make RGBRGB. @@ -8726,12 +8773,12 @@ copy_3091(struct fujitsu *s, unsigned char * buf, int len, int side) s->lines_rx[side]++; } - /* even if we have read data, we may not have any + /* even if we have read data, we may not have any * full lines loaded yet, so we may have to lie */ i = (s->lines_rx[side]-goff) * s->s_params.bytes_per_line; if(i < 0){ i = 0; - } + } s->bytes_rx[side] = i; s->buff_rx[side] = i; @@ -8753,11 +8800,11 @@ copy_JPEG(struct fujitsu *s, unsigned char * buf, int len, int side) { SANE_Status ret=SANE_STATUS_GOOD; int i, seen = 0; - + DBG (10, "copy_JPEG: start\n"); /* A jpeg image starts with the SOI marker, FF D8. - * This is optionally followed by the JFIF APP0 + * This is optionally followed by the JFIF APP0 * marker, FF E0. If that marker is not present, * we add it, so we can insert the resolution */ @@ -8797,7 +8844,7 @@ copy_buffer(struct fujitsu *s, unsigned char * buf, int len, int side) int i, j; int bwidth = s->s_params.bytes_per_line; int pwidth = s->s_params.pixels_per_line; - + DBG (10, "copy_buffer: start\n"); /* invert image if scanner needs it for this mode */ @@ -8810,9 +8857,9 @@ copy_buffer(struct fujitsu *s, unsigned char * buf, int len, int side) /* scanners interlace colors in many different ways */ if(s->s_params.format == SANE_FRAME_RGB){ - + switch (s->color_interlace) { - + /* scanner returns pixel data as bgrbgr... */ case COLOR_INTERLACE_BGR: for(i=0; ibuffers[side]+s->buff_rx[side],buf,len); s->buff_rx[side] += len; @@ -8847,7 +8894,7 @@ copy_buffer(struct fujitsu *s, unsigned char * buf, int len, int side) memcpy(s->buffers[side]+s->buff_rx[side],buf,len); s->buff_rx[side] += len; } - + s->bytes_rx[side] += len; s->lines_rx[side] += len/s->s_params.bytes_per_line; @@ -8867,16 +8914,16 @@ read_from_buffer(struct fujitsu *s, SANE_Byte * buf, SANE_Status ret=SANE_STATUS_GOOD; int bytes = max_len; int remain = s->buff_rx[side] - s->buff_tx[side]; - + DBG (10, "read_from_buffer: start\n"); - + /* figure out the max amount to transfer */ if(bytes > remain){ bytes = remain; } - + *len = bytes; - + DBG(15, "read_from_buffer: si:%d re:%d ml:%d by:%d\n", side, remain, max_len, bytes); @@ -8885,19 +8932,19 @@ read_from_buffer(struct fujitsu *s, SANE_Byte * buf, DBG(15, "read_from_buffer: buf to:%d rx:%d tx:%d\n", s->buff_tot[side], s->buff_rx[side], s->buff_tx[side]); - + /*FIXME this needs to timeout eventually */ if(!bytes){ DBG(5,"read_from_buffer: nothing to do\n"); return SANE_STATUS_GOOD; } - + memcpy(buf,s->buffers[side]+s->buff_tx[side],bytes); s->buff_tx[side] += bytes; s->bytes_tx[side] += bytes; DBG (10, "read_from_buffer: finish\n"); - + return ret; } @@ -8911,7 +8958,7 @@ downsample_from_buffer(struct fujitsu *s, SANE_Byte * buf, SANE_Status ret=SANE_STATUS_GOOD; DBG (10, "downsample_from_buffer: start %d %d %d %d\n", s->bytes_rx[side], s->bytes_tx[side], s->buff_rx[side], s->buff_tx[side]); - + if(s->s_mode == MODE_COLOR && s->u_mode == MODE_GRAYSCALE){ while(*len < max_len && s->buff_rx[side] - s->buff_tx[side] >= 3){ @@ -8959,7 +9006,7 @@ downsample_from_buffer(struct fujitsu *s, SANE_Byte * buf, for(i=0; i<8; i++){ int gray = 0; - + switch (s->dropout_color) { case COLOR_RED: gray = *(s->buffers[side]+s->buff_tx[side]) * 3; @@ -8999,7 +9046,7 @@ downsample_from_buffer(struct fujitsu *s, SANE_Byte * buf, } DBG (10, "downsample_from_buffer: finish %d %d %d %d\n", s->bytes_rx[side], s->bytes_tx[side], s->buff_rx[side], s->buff_tx[side]); - + return ret; } @@ -9008,26 +9055,26 @@ downsample_from_buffer(struct fujitsu *s, SANE_Byte * buf, * @@ Section 5 - SANE cleanup functions */ /* - * Cancels a scan. + * Cancels a scan. * * It has been said on the mailing list that sane_cancel is a bit of a * misnomer because it is routinely called to signal the end of a * batch - quoting David Mosberger-Tang: - * + * * > In other words, the idea is to have sane_start() be called, and * > collect as many images as the frontend wants (which could in turn * > consist of multiple frames each as indicated by frame-type) and - * > when the frontend is done, it should call sane_cancel(). + * > when the frontend is done, it should call sane_cancel(). * > Sometimes it's better to think of sane_cancel() as "sane_stop()" * > but that name would have had some misleading connotations as * > well, that's why we stuck with "cancel". - * + * * The current consensus regarding duplex and ADF scans seems to be * the following call sequence: sane_start; sane_read (repeat until * EOF); sane_start; sane_read... and then call sane_cancel if the * batch is at an end. I.e. do not call sane_cancel during the run but * as soon as you get a SANE_STATUS_NO_DOCS. - * + * * From the SANE spec: * This function is used to immediately or as quickly as possible * cancel the currently pending operation of the device represented by @@ -9061,7 +9108,7 @@ sane_cancel (SANE_Handle handle) /* * Ends use of the scanner. - * + * * From the SANE spec: * This function terminates the association between the device handle * passed in argument h and the device it represents. If the device is @@ -9104,7 +9151,7 @@ disconnect_fd (struct fujitsu *s) /* * Terminates the backend. - * + * * From the SANE spec: * This function must be called to terminate use of a backend. The * function will first close all device handles that still might be @@ -9703,7 +9750,7 @@ do_usb_cmd(struct fujitsu *s, int runRS, int shortTime, rs_in, &rs_inLen ); DBG(25,"rs sub call <<\n"); - + if(ret2 == SANE_STATUS_EOF){ DBG(5,"rs: got EOF, returning IO_ERROR\n"); return SANE_STATUS_IO_ERROR; @@ -9736,7 +9783,7 @@ do_usb_cmd(struct fujitsu *s, int runRS, int shortTime, } static SANE_Status -wait_scanner(struct fujitsu *s) +wait_scanner(struct fujitsu *s) { SANE_Status ret = SANE_STATUS_GOOD; @@ -9754,7 +9801,7 @@ wait_scanner(struct fujitsu *s) NULL, 0, NULL, NULL ); - + if (ret != SANE_STATUS_GOOD) { DBG(5,"WARNING: Brain-dead scanner. Hitting with stick\n"); ret = do_cmd ( @@ -9783,7 +9830,7 @@ wait_scanner(struct fujitsu *s) return ret; } -/* certain options require the entire image to +/* certain options require the entire image to * be collected from the scanner before we can * tell the user the size of the image. */ static int @@ -9803,7 +9850,7 @@ must_fully_buffer(struct fujitsu *s) return 0; } -/* certain scanners require the mode of the +/* certain scanners require the mode of the * image to be changed in software. */ static int must_downsample(struct fujitsu *s) @@ -9823,7 +9870,7 @@ must_downsample(struct fujitsu *s) * due to using FB or overscan. */ static int -get_page_width(struct fujitsu *s) +get_page_width(struct fujitsu *s) { int width = s->page_width + 2 * (s->os_x_basic*1200/s->basic_x_res); @@ -9852,7 +9899,7 @@ get_page_width(struct fujitsu *s) * due to using FB or overscan. */ static int -get_page_height(struct fujitsu *s) +get_page_height(struct fujitsu *s) { int height = s->page_height + 2 * (s->os_y_basic*1200/s->basic_y_res); @@ -9883,7 +9930,7 @@ get_page_height(struct fujitsu *s) * and pick the right mode to match. */ static int -get_ipc_mode(struct fujitsu *s) +get_ipc_mode(struct fujitsu *s) { if ( s->bp_filter || s->smoothing @@ -9912,10 +9959,10 @@ get_ipc_mode(struct fujitsu *s) return WD_ipc_DEFAULT; } -/* s->max_y gives the maximum height of paper which can be scanned +/* s->max_y gives the maximum height of paper which can be scanned * this actually varies by resolution, so a helper to change it */ static int -set_max_y(struct fujitsu *s) +set_max_y(struct fujitsu *s) { int i; @@ -10046,7 +10093,7 @@ buffer_deskew(struct fujitsu *s, int side) s->deskew_stat = sanei_magic_findSkew( &s->s_params,s->buffers[side],s->resolution_x,s->resolution_y, &s->deskew_vals[0],&s->deskew_vals[1],&s->deskew_slope); - + if(s->deskew_stat){ DBG (5, "buffer_deskew: bad findSkew, bailing\n"); goto cleanup; @@ -10101,7 +10148,7 @@ buffer_crop(struct fujitsu *s, int side) ret = SANE_STATUS_GOOD; goto cleanup; } - + DBG (15, "buffer_crop: t:%d b:%d l:%d r:%d\n", s->crop_vals[0],s->crop_vals[1],s->crop_vals[2],s->crop_vals[3]); @@ -10127,7 +10174,7 @@ buffer_crop(struct fujitsu *s, int side) /* update image size counter to new, smaller size */ s->bytes_rx[side] = s->s_params.lines * s->s_params.bytes_per_line; s->buff_rx[side] = s->bytes_rx[side]; - + cleanup: DBG (10, "buffer_crop: finish\n"); return ret; @@ -10178,4 +10225,3 @@ buffer_isblank(struct fujitsu *s, int side) DBG (10, "buffer_isblank: finished\n"); return status; } - diff --git a/backend/fujitsu.conf.in b/backend/fujitsu.conf.in index 5fa0003..cb33f15 100644 --- a/backend/fujitsu.conf.in +++ b/backend/fujitsu.conf.in @@ -121,12 +121,6 @@ usb 0x04c5 0x119e #S1500 & S1500M usb 0x04c5 0x11a2 -#fi-6125 -usb 0x04c5 0x11ee - -#fi-6225 -usb 0x04c5 0x11ef - #fi-6140Z/fi-6160ZLA usb 0x04c5 0x11f1 @@ -169,15 +163,6 @@ usb 0x04c5 0x13f3 #ScanSnap iX100 usb 0x04c5 0x13f4 -#ScanPartner SP25 -usb 0x04c5 0x1409 - -#ScanPartner SP30 -usb 0x04c5 0x140a - -#ScanPartner SP30F -usb 0x04c5 0x140c - #fi-6140ZLA usb 0x04c5 0x145f @@ -267,4 +252,3 @@ usb 0x04c5 0x1521 #fi-7700S usb 0x04c5 0x1522 - diff --git a/backend/fujitsu.h b/backend/fujitsu.h index 916f069..4c20474 100644 --- a/backend/fujitsu.h +++ b/backend/fujitsu.h @@ -1,12 +1,12 @@ #ifndef FUJITSU_H #define FUJITSU_H -/* +/* * Part of SANE - Scanner Access Now Easy. * Please see opening comment in fujitsu.c */ -/* ------------------------------------------------------------------------- +/* ------------------------------------------------------------------------- * This option list has to contain all options for all scanners supported by * this driver. If a certain scanner cannot handle a certain option, there's * still the possibility to say so, later. @@ -219,7 +219,7 @@ struct fujitsu int has_cmd_sdiag; int has_cmd_rdiag; int has_cmd_scan; - + int has_cmd_msen6; int has_cmd_copy; int has_cmd_rel; @@ -330,8 +330,8 @@ struct fujitsu int broken_diag_serial; /* some scanners are just plain borked */ int need_q_table; /* some scanners wont work without these */ - int need_diag_preread; - int late_lut; + int need_diag_preread; + int late_lut; int hopper_before_op; /* some scanners dont like OP when hopper empty */ int no_wait_after_op; /* some scanners dont like TUR after OP */ @@ -669,15 +669,15 @@ struct fujitsu #define COLOR_INTERLACE_RRGGBB 3 #define COLOR_INTERLACE_3091 4 -#define DUPLEX_INTERLACE_ALT 0 -#define DUPLEX_INTERLACE_NONE 1 -#define DUPLEX_INTERLACE_3091 2 +#define DUPLEX_INTERLACE_ALT 0 +#define DUPLEX_INTERLACE_NONE 1 +#define DUPLEX_INTERLACE_3091 2 -#define JPEG_INTERLACE_ALT 0 -#define JPEG_INTERLACE_NONE 1 +#define JPEG_INTERLACE_ALT 0 +#define JPEG_INTERLACE_NONE 1 -#define CROP_RELATIVE 0 -#define CROP_ABSOLUTE 1 +#define CROP_RELATIVE 0 +#define CROP_ABSOLUTE 1 #define DF_DEFAULT 0 #define DF_CONTINUE 1 diff --git a/backend/genesys.c b/backend/genesys.c deleted file mode 100644 index db0a2b2..0000000 --- a/backend/genesys.c +++ /dev/null @@ -1,8047 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003, 2004 Henning Meier-Geinitz - Copyright (C) 2004, 2005 Gerhard Jaeger - Copyright (C) 2004-2016 Stéphane Voltz - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2006 Laurent Charpentier - Copyright (C) 2007 Luke - Copyright (C) 2010 Chris Berry and Michael Rickmann - for Plustek Opticbook 3600 support - - Dynamic rasterization code was taken from the epjistsu backend by - m. allan noah - - Software processing for deskew, crop and dspeckle are inspired by allan's - noah work in the fujitsu backend - - 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. -*/ - -/* - * SANE backend for Genesys Logic GL646/GL841/GL842/GL843/GL846/GL847/GL124 based scanners - */ - -#define BUILD 2511 -#define BACKEND_NAME genesys - -#include "genesys.h" -#include "../include/sane/sanei_config.h" -#include "../include/sane/sanei_magic.h" -#include "genesys_devices.c" - -static SANE_Int num_devices = 0; -static Genesys_Device *first_dev = 0; -static Genesys_Scanner *first_handle = 0; -static const SANE_Device **devlist = 0; -/* Array of newly attached devices */ -static Genesys_Device **new_dev = 0; -/* Length of new_dev array */ -static SANE_Int new_dev_len = 0; -/* Number of entries alloced for new_dev */ -static SANE_Int new_dev_alloced = 0; - -static SANE_String_Const mode_list[] = { - SANE_VALUE_SCAN_MODE_COLOR, - SANE_VALUE_SCAN_MODE_GRAY, - /* SANE_TITLE_HALFTONE, currently unused */ - SANE_VALUE_SCAN_MODE_LINEART, - 0 -}; - -static SANE_String_Const color_filter_list[] = { - SANE_I18N ("Red"), - SANE_I18N ("Green"), - SANE_I18N ("Blue"), - 0 -}; - -static SANE_String_Const cis_color_filter_list[] = { - SANE_I18N ("Red"), - SANE_I18N ("Green"), - SANE_I18N ("Blue"), - SANE_I18N ("None"), - 0 -}; - -static SANE_String_Const source_list[] = { - SANE_I18N (FLATBED), - SANE_I18N (TRANSPARENCY_ADAPTER), - 0 -}; - -static SANE_Range swdespeck_range = { - 1, - 9, - 1 -}; - -static SANE_Range time_range = { - 0, /* minimum */ - 60, /* maximum */ - 0 /* quantization */ -}; - -static const SANE_Range u12_range = { - 0, /* minimum */ - 4095, /* maximum */ - 0 /* quantization */ -}; - -static const SANE_Range u14_range = { - 0, /* minimum */ - 16383, /* maximum */ - 0 /* quantization */ -}; - -static const SANE_Range u16_range = { - 0, /* minimum */ - 65535, /* maximum */ - 0 /* quantization */ -}; - -static const SANE_Range percentage_range = { - SANE_FIX (0), /* minimum */ - SANE_FIX (100), /* maximum */ - SANE_FIX (1) /* quantization */ -}; - -static const SANE_Range threshold_curve_range = { - 0, /* minimum */ - 127, /* maximum */ - 1 /* quantization */ -}; - -/** - * range for brightness and contrast - */ -static const SANE_Range enhance_range = { - -100, /* minimum */ - 100, /* maximum */ - 1 /* quantization */ -}; - -/** - * range for expiration time - */ -static const SANE_Range expiration_range = { - -1, /* minimum */ - 30000, /* maximum */ - 1 /* quantization */ -}; - -void -sanei_genesys_init_structs (Genesys_Device * dev) -{ - unsigned int i, sensor_ok = 0, gpo_ok = 0, motor_ok = 0; - - /* initialize the sensor data stuff */ - for (i = 0; i < sizeof (Sensor) / sizeof (Genesys_Sensor); i++) - { - if (dev->model->ccd_type == Sensor[i].sensor_id) - { - memcpy (&dev->sensor, &Sensor[i], sizeof (Genesys_Sensor)); - sensor_ok = 1; - } - } - - /* initialize the GPO data stuff */ - for (i = 0; i < sizeof (Gpo) / sizeof (Genesys_Gpo); i++) - { - if (dev->model->gpo_type == Gpo[i].gpo_id) - { - memcpy (&dev->gpo, &Gpo[i], sizeof (Genesys_Gpo)); - gpo_ok = 1; - } - } - - /* initialize the motor data stuff */ - for (i = 0; i < sizeof (Motor) / sizeof (Genesys_Motor); i++) - { - if (dev->model->motor_type == Motor[i].motor_id) - { - memcpy (&dev->motor, &Motor[i], sizeof (Genesys_Motor)); - motor_ok = 1; - } - } - - /* sanity check */ - if (sensor_ok == 0 || motor_ok == 0 || gpo_ok == 0) - { - DBG (DBG_error0, - "sanei_genesys_init_structs: bad description(s) for ccd/gpo/motor=%d/%d/%d\n", - dev->model->ccd_type, dev->model->gpo_type, - dev->model->motor_type); - } - - /* set up initial line distance shift */ - dev->ld_shift_r = dev->model->ld_shift_r; - dev->ld_shift_g = dev->model->ld_shift_g; - dev->ld_shift_b = dev->model->ld_shift_b; -} - -void -sanei_genesys_init_fe (Genesys_Device * dev) -{ - unsigned int i; - - DBGSTART; - for (i = 0; i < sizeof (Wolfson) / sizeof (Genesys_Frontend); i++) - { - if (dev->model->dac_type == Wolfson[i].fe_id) - { - memcpy (&dev->frontend, &Wolfson[i], sizeof (Genesys_Frontend)); - return; - } - } - DBG (DBG_error0, - "sanei_genesys_init_fe: failed to find description for dac_type %d\n", - dev->model->dac_type); - DBG (DBG_info, "sanei_genesys_init_fe: dac_type %d set up\n", - dev->model->dac_type); - DBGCOMPLETED; -} - -/* main function for slope creation */ -/** - * This function generates a slope table using the given slope - * truncated at the given exposure time or step count, whichever comes first. - * The reached step time is then stored in final_exposure and used for the rest - * of the table. The summed time of the acceleration steps is returned, and the - * number of accerelation steps is put into used_steps. - * - * @param slope_table Table to write to - * @param max_steps Size of slope_table in steps - * @param use_steps Maximum number of steps to use for acceleration - * @param stop_at Minimum step time to use - * @param vstart Start step time of default slope - * @param vend End step time of default slope - * @param steps Step count of default slope - * @param g Power for default slope - * @param used_steps Final number of steps is stored here - * @param vfinal Final step time is stored here - * @return Time for acceleration - * @note All times in pixel time. Correction for other motor timings is not - * done. - */ -SANE_Int -sanei_genesys_generate_slope_table (uint16_t * slope_table, - unsigned int max_steps, - unsigned int use_steps, - uint16_t stop_at, - uint16_t vstart, - uint16_t vend, - unsigned int steps, - double g, - unsigned int *used_steps, - unsigned int *vfinal) -{ - double t; - SANE_Int sum = 0; - unsigned int i; - unsigned int c = 0; - uint16_t t2; - unsigned int dummy; - unsigned int _vfinal; - if (!used_steps) - used_steps = &dummy; - if (!vfinal) - vfinal = &_vfinal; - - DBG (DBG_proc, "sanei_genesys_generate_slope_table: table size: %d\n", - max_steps); - - DBG (DBG_proc, - "sanei_genesys_generate_slope_table: stop at time: %d, use %d steps max\n", - stop_at, use_steps); - - DBG (DBG_proc, - "sanei_genesys_generate_slope_table: target slope: " - "vstart: %d, vend: %d, steps: %d, g: %g\n", vstart, vend, steps, g); - - sum = 0; - c = 0; - *used_steps = 0; - - if (use_steps < 1) - use_steps = 1; - - if (stop_at < vstart) - { - t2 = vstart; - for (i = 0; i < steps && i < use_steps - 1 && i < max_steps; i++, c++) - { - t = pow (((double) i) / ((double) (steps - 1)), g); - t2 = vstart * (1 - t) + t * vend; - if (t2 < stop_at) - break; - *slope_table++ = t2; - /* DBG (DBG_io, "slope_table[%3d] = %5d\n", c, t2); */ - sum += t2; - } - if (t2 > stop_at) - { - DBG (DBG_warn, "Can not reach target speed(%d) in %d steps.\n", - stop_at, use_steps); - DBG (DBG_warn, "Expect image to be distorted. " - "Ignore this if only feeding.\n"); - } - *vfinal = t2; - *used_steps += i; - max_steps -= i; - } - else - *vfinal = stop_at; - - for (i = 0; i < max_steps; i++, c++) - { - *slope_table++ = *vfinal; - /* DBG (DBG_io, "slope_table[%3d] = %5d\n", c, *vfinal); */ - } - - (*used_steps)++; - sum += *vfinal; - - DBG (DBG_proc, - "sanei_genesys_generate_slope_table: returns sum=%d, used %d steps, completed\n", - sum, *used_steps); - - return sum; -} - -/* Generate slope table for motor movement */ -/** - * This function generates a slope table using the slope from the motor struct - * truncated at the given exposure time or step count, whichever comes first. - * The reached step time is then stored in final_exposure and used for the rest - * of the table. The summed time of the acceleration steps is returned, and the - * number of accerelation steps is put into used_steps. - * - * @param dev Device struct - * @param slope_table Table to write to - * @param max_step Size of slope_table in steps - * @param use_steps Maximum number of steps to use for acceleration - * @param step_type Generate table for this step_type. 0=>full, 1=>half, - * 2=>quarter - * @param exposure_time Minimum exposure time of a scan line - * @param yres Resolution of a scan line - * @param used_steps Final number of steps is stored here - * @param final_exposure Final step time is stored here - * @param power_mode Power mode (related to the Vref used) of the motor - * @return Time for acceleration - * @note all times in pixel time - */ -SANE_Int -sanei_genesys_create_slope_table3 (Genesys_Device * dev, - uint16_t * slope_table, - int max_step, - unsigned int use_steps, - int step_type, - int exposure_time, - double yres, - unsigned int *used_steps, - unsigned int *final_exposure, - int power_mode) -{ - unsigned int sum_time = 0; - unsigned int vtarget; - unsigned int vend; - unsigned int vstart; - unsigned int vfinal; - - DBG (DBG_proc, - "%s: step_type = %d, " - "exposure_time = %d, yres = %g, power_mode = %d\n", __func__, step_type, - exposure_time, yres, power_mode); - - /* final speed */ - vtarget = (exposure_time * yres) / dev->motor.base_ydpi; - - vstart = dev->motor.slopes[power_mode][step_type].maximum_start_speed; - vend = dev->motor.slopes[power_mode][step_type].maximum_speed; - - vtarget >>= step_type; - if (vtarget > 65535) - vtarget = 65535; - - vstart >>= step_type; - if (vstart > 65535) - vstart = 65535; - - vend >>= step_type; - if (vend > 65535) - vend = 65535; - - sum_time = sanei_genesys_generate_slope_table (slope_table, - max_step, - use_steps, - vtarget, - vstart, - vend, - dev->motor.slopes[power_mode][step_type].minimum_steps << step_type, - dev->motor.slopes[power_mode][step_type].g, - used_steps, - &vfinal); - - if (final_exposure) - *final_exposure = (vfinal * dev->motor.base_ydpi) / yres; - - DBG (DBG_proc, - "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", - sum_time); - - return sum_time; -} - - -/* alternate slope table creation function */ -/* the hardcoded values (g and vstart) will go in a motor struct */ -static SANE_Int -genesys_create_slope_table2 (Genesys_Device * dev, - uint16_t * slope_table, int steps, - int step_type, int exposure_time, - SANE_Bool same_speed, double yres, - int power_mode) -{ - double t, g; - SANE_Int sum = 0; - int vstart, vend; - int i; - - DBG (DBG_proc, - "sanei_genesys_create_slope_table2: %d steps, step_type = %d, " - "exposure_time = %d, same_speed = %d, yres = %.2f, power_mode = %d\n", - steps, step_type, exposure_time, same_speed, yres, power_mode); - - /* start speed */ - if (dev->model->motor_type == MOTOR_5345) - { - if (yres < dev->motor.base_ydpi / 6) - vstart = 2500; - else - vstart = 2000; - } - else - { - if (steps == 2) - vstart = exposure_time; - else if (steps == 3) - vstart = 2 * exposure_time; - else if (steps == 4) - vstart = 1.5 * exposure_time; - else if (steps == 120) - vstart = 1.81674 * exposure_time; - else - vstart = exposure_time; - } - - /* final speed */ - vend = (exposure_time * yres) / (dev->motor.base_ydpi * (1 << step_type)); - - /* - type=1 : full - type=2 : half - type=4 : quarter - vend * type * base_ydpi / exposure = yres - */ - - /* acceleration */ - switch (steps) - { - case 255: - /* test for special case: fast moving slope */ - /* todo: a 'fast' boolean parameter should be better */ - if (vstart == 2000) - g = 0.2013; - else - g = 0.1677; - break; - case 120: - g = 0.5; - break; - case 67: - g = 0.5; - break; - case 64: - g = 0.2555; - break; - case 44: - g = 0.5; - break; - case 4: - g = 0.5; - break; - case 3: - g = 1; - break; - case 2: - vstart = vend; - g = 1; - break; - default: - g = 0.2635; - } - - /* if same speed, no 'g' */ - sum = 0; - if (same_speed) - { - for (i = 0; i < 255; i++) - { - slope_table[i] = vend; - sum += slope_table[i]; - DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); - } - } - else - { - for (i = 0; i < steps; i++) - { - t = pow (((double) i) / ((double) (steps - 1)), g); - slope_table[i] = vstart * (1 - t) + t * vend; - DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); - sum += slope_table[i]; - } - for (i = steps; i < 255; i++) - { - slope_table[i] = vend; - DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); - sum += slope_table[i]; - } - } - - DBG (DBG_proc, - "sanei_genesys_create_slope_table2: returns sum=%d, completed\n", sum); - - return sum; -} - -/* Generate slope table for motor movement */ -/* todo: check details */ -SANE_Int -sanei_genesys_create_slope_table (Genesys_Device * dev, - uint16_t * slope_table, int steps, - int step_type, int exposure_time, - SANE_Bool same_speed, double yres, - int power_mode) -{ - double t; - double start_speed; - double g; - uint32_t time_period; - int sum_time = 0; - int i, divider; - int same_step; - - if (dev->model->motor_type == MOTOR_5345 - || dev->model->motor_type == MOTOR_HP2300 - || dev->model->motor_type == MOTOR_HP2400) - return genesys_create_slope_table2 (dev, slope_table, steps, - step_type, exposure_time, - same_speed, yres, power_mode); - - DBG (DBG_proc, - "sanei_genesys_create_slope_table: %d steps, step_type = %d, " - "exposure_time = %d, same_speed =%d\n", steps, step_type, - exposure_time, same_speed); - DBG (DBG_proc, "sanei_genesys_create_slope_table: yres = %.2f\n", yres); - - g = 0.6; - start_speed = 0.01; - same_step = 4; - divider = 1 << step_type; - - time_period = - (uint32_t) (yres * exposure_time / dev->motor.base_ydpi /*MOTOR_GEAR */ ); - if ((time_period < 2000) && (same_speed)) - same_speed = SANE_FALSE; - - time_period = time_period / divider; - - if (same_speed) - { - for (i = 0; i < steps; i++) - { - slope_table[i] = (uint16_t) time_period; - sum_time += time_period; - - DBG (DBG_io, "slope_table[%d] = %d\n", i, time_period); - } - DBG (DBG_info, - "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", - sum_time); - return sum_time; - } - - if (time_period > MOTOR_SPEED_MAX * 5) - { - g = 1.0; - start_speed = 0.05; - same_step = 2; - } - else if (time_period > MOTOR_SPEED_MAX * 4) - { - g = 0.8; - start_speed = 0.04; - same_step = 2; - } - else if (time_period > MOTOR_SPEED_MAX * 3) - { - g = 0.7; - start_speed = 0.03; - same_step = 2; - } - else if (time_period > MOTOR_SPEED_MAX * 2) - { - g = 0.6; - start_speed = 0.02; - same_step = 3; - } - - if (dev->model->motor_type == MOTOR_ST24) - { - steps = 255; - switch ((int) yres) - { - case 2400: - g = 0.1672; - start_speed = 1.09; - break; - case 1200: - g = 1; - start_speed = 6.4; - break; - case 600: - g = 0.1672; - start_speed = 1.09; - break; - case 400: - g = 0.2005; - start_speed = 20.0 / 3.0 /*7.5 */ ; - break; - case 300: - g = 0.253; - start_speed = 2.182; - break; - case 150: - g = 0.253; - start_speed = 4.367; - break; - default: - g = 0.262; - start_speed = 7.29; - } - same_step = 1; - } - - if (steps <= same_step) - { - time_period = - (uint32_t) (yres * exposure_time / - dev->motor.base_ydpi /*MOTOR_GEAR */ ); - time_period = time_period / divider; - - if (time_period > 65535) - time_period = 65535; - - for (i = 0; i < same_step; i++) - { - slope_table[i] = (uint16_t) time_period; - sum_time += time_period; - - DBG (DBG_io, "slope_table[%d] = %d\n", i, time_period); - } - - DBG (DBG_proc, - "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", - sum_time); - return sum_time; - } - - for (i = 0; i < steps; i++) - { - double j = ((double) i) - same_step + 1; /* start from 1/16 speed */ - - if (j <= 0) - t = 0; - else - t = pow (j / (steps - same_step), g); - - time_period = /* time required for full steps */ - (uint32_t) (yres * exposure_time / - dev->motor.base_ydpi /*MOTOR_GEAR */ * - (start_speed + (1 - start_speed) * t)); - - time_period = time_period / divider; - if (time_period > 65535) - time_period = 65535; - - slope_table[i] = (uint16_t) time_period; - sum_time += time_period; - - DBG (DBG_io, "slope_table[%d] = %d\n", i, slope_table[i]); - } - - DBG (DBG_proc, - "sanei_genesys_create_slope_table: returns sum_time=%d, completed\n", - sum_time); - - return sum_time; -} - -/** @brief computes gamma table - * Generates a gamma table of the given length within 0 and the given - * maximum value - * @param gamma_table gamma table to fill - * @param size size of the table - * @param maximum value allowed for gamma - * @param gamma_max maximum gamma value - * @param gamma gamma to compute values - * @return a gamma table filled with the computed values - * */ -void -sanei_genesys_create_gamma_table (uint16_t * gamma_table, int size, - float maximum, float gamma_max, float gamma) -{ - int i; - float value; - - if(gamma_table==NULL) - { - DBG (DBG_proc, "sanei_genesys_create_gamma_table: gamma table is NULL\n"); - return; - } - DBG (DBG_proc, - "sanei_genesys_create_gamma_table: size = %d, " - "maximum = %g, gamma_max = %g, gamma = %g\n", - size, maximum, gamma_max, gamma); - for (i = 0; i < size; i++) - { - value = gamma_max * pow ((float) i / size, 1.0 / gamma); - if (value > maximum) - value = maximum; - gamma_table[i] = value; - } - DBG (DBG_proc, "sanei_genesys_create_gamma_table: completed\n"); -} - - -/* computes the exposure_time on the basis of the given vertical dpi, - the number of pixels the ccd needs to send, - the step_type and the corresponding maximum speed from the motor struct */ -/* - Currently considers maximum motor speed at given step_type, minimum - line exposure needed for conversion and led exposure time. - - TODO: Should also consider maximum transfer rate: ~6.5MB/s. - Note: The enhance option of the scanners does _not_ help. It only halves - the amount of pixels transfered. - */ -SANE_Int -sanei_genesys_exposure_time2 (Genesys_Device * dev, float ydpi, - int step_type, int endpixel, - int exposure_by_led, int power_mode) -{ - int exposure_by_ccd = endpixel + 32; - int exposure_by_motor = - (dev->motor.slopes[power_mode][step_type].maximum_speed - * dev->motor.base_ydpi) / ydpi; - - int exposure = exposure_by_ccd; - - if (exposure < exposure_by_motor) - exposure = exposure_by_motor; - - if (exposure < exposure_by_led && dev->model->is_cis) - exposure = exposure_by_led; - - DBG (DBG_info, "%s: ydpi=%d, step=%d, endpixel=%d led=%d, power=%d => exposure=%d\n", - __func__, (int)ydpi, step_type, endpixel, exposure_by_led, power_mode, exposure); - return exposure; -} - -/* computes the exposure_time on the basis of the given horizontal dpi */ -/* we will clean/simplify it by using constants from a future motor struct */ -SANE_Int -sanei_genesys_exposure_time (Genesys_Device * dev, Genesys_Register_Set * reg, - int xdpi) -{ - if (dev->model->motor_type == MOTOR_5345) - { - if (dev->model->cmd_set->get_filter_bit (reg)) - { - /* monochrome */ - switch (xdpi) - { - case 600: - return 8500; - case 500: - case 400: - case 300: - case 250: - case 200: - case 150: - return 5500; - case 100: - return 6500; - case 50: - return 12000; - default: - return 11000; - } - } - else - { - /* color scan */ - switch (xdpi) - { - case 300: - case 250: - case 200: - return 5500; - case 50: - return 12000; - default: - return 11000; - } - } - } - else if (dev->model->motor_type == MOTOR_HP2400) - { - if (dev->model->cmd_set->get_filter_bit (reg)) - { - /* monochrome */ - switch (xdpi) - { - case 200: - return 7210; - default: - return 11111; - } - } - else - { - /* color scan */ - switch (xdpi) - { - case 600: - return 8751; /*11902; 19200 */ - default: - return 11111; - } - } - } - else if (dev->model->motor_type == MOTOR_HP2300) - { - if (dev->model->cmd_set->get_filter_bit (reg)) - { - /* monochrome */ - switch (xdpi) - { - case 600: - return 8699; /* 3200; */ - case 300: - return 3200; /*10000;, 3200 -> too dark */ - case 150: - return 4480; /* 3200 ???, warmup needs 4480 */ - case 75: - return 5500; - default: - return 11111; - } - } - else - { - /* color scan */ - switch (xdpi) - { - case 600: - return 8699; - case 300: - return 4349; - case 150: - case 75: - return 4480; - default: - return 11111; - } - } - } - return dev->settings.exposure_time; -} - - - -/* Sends a block of shading information to the scanner. - The data is placed at address 0x0000 for color mode, gray mode and - unconditionally for the following CCD chips: HP2300, HP2400 and HP5345 - In the other cases (lineart, halftone on ccd chips not mentioned) the - addresses are 0x2a00 for dpihw==0, 0x5500 for dpihw==1 and 0xa800 for - dpihw==2. //Note: why this? - - The data needs to be of size "size", and in little endian byte order. - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -genesys_send_offset_and_shading (Genesys_Device * dev, uint8_t * data, - int size) -{ - int dpihw; - int start_address; - SANE_Status status; - - DBG (DBG_proc, "%s: (size = %d)\n", __func__, size); - - /* ASIC higher than gl843 doesn't have register 2A/2B, so we route to - * a per ASIC shading data loading function if available. - * It is also used for scanners using SHDAREA */ - if(dev->model->cmd_set->send_shading_data!=NULL) - { - status=dev->model->cmd_set->send_shading_data(dev, data, size); - DBGCOMPLETED; - return status; - } - - /* gl646, gl84[123] case */ - dpihw = sanei_genesys_read_reg_from_set (dev->reg, 0x05) >> 6; - - /* TODO invert the test so only the 2 models behaving like that are - * tested instead of adding all the others */ - /* many scanners send coefficient for lineart/gray like in color mode */ - if (dev->settings.scan_mode < 2 - && dev->model->ccd_type != CCD_PLUSTEK3800 - && dev->model->ccd_type != CCD_KVSS080 - && dev->model->ccd_type != CCD_G4050 - && dev->model->ccd_type != CCD_CS4400F - && dev->model->ccd_type != CCD_CS8400F - && dev->model->ccd_type != CCD_DSMOBILE600 - && dev->model->ccd_type != CCD_XP300 - && dev->model->ccd_type != CCD_DP665 - && dev->model->ccd_type != CCD_DP685 - && dev->model->ccd_type != CIS_CANONLIDE80 - && dev->model->ccd_type != CCD_ROADWARRIOR - && dev->model->ccd_type != CCD_HP2300 - && dev->model->ccd_type != CCD_HP2400 - && dev->model->ccd_type != CCD_HP3670 - && dev->model->ccd_type != CCD_5345) /* lineart, halftone */ - { - if (dpihw == 0) /* 600 dpi */ - start_address = 0x02a00; - else if (dpihw == 1) /* 1200 dpi */ - start_address = 0x05500; - else if (dpihw == 2) /* 2400 dpi */ - start_address = 0x0a800; - else /* reserved */ - return SANE_STATUS_INVAL; - } - else /* color */ - start_address = 0x00; - - status = sanei_genesys_set_buffer_address (dev, start_address); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set buffer address: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send shading table: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/* ? */ -SANE_Status -sanei_genesys_init_shading_data (Genesys_Device * dev, int pixels_per_line) -{ - SANE_Status status; - uint8_t *shading_data, *shading_data_ptr; - int channels; - int i; - - /* these models don't need to init shading data due to the use of specific send shading data - function */ - if (dev->model->ccd_type==CCD_KVSS080 - || dev->model->ccd_type==CCD_G4050 - || dev->model->ccd_type==CCD_CS4400F - || dev->model->ccd_type==CCD_CS8400F - || dev->model->cmd_set->send_shading_data!=NULL) - return SANE_STATUS_GOOD; - - DBG (DBG_proc, "sanei_genesys_init_shading_data (pixels_per_line = %d)\n", - pixels_per_line); - - if (dev->settings.scan_mode >= 2) /* 3 pass or single pass color */ - channels = 3; - else - channels = 1; - - shading_data = malloc (pixels_per_line * 4 * channels); /* 16 bit black, 16 bit white */ - if (!shading_data) - { - DBG (DBG_error, - "sanei_genesys_init_shading_data: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - shading_data_ptr = shading_data; - - for (i = 0; i < pixels_per_line * channels; i++) - { - *shading_data_ptr++ = 0x00; /* dark lo */ - *shading_data_ptr++ = 0x00; /* dark hi */ - *shading_data_ptr++ = 0x00; /* white lo */ - *shading_data_ptr++ = 0x40; /* white hi -> 0x4000 */ - } - - status = genesys_send_offset_and_shading (dev, - shading_data, - pixels_per_line * 4 * channels); - free (shading_data); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send shading data: %s\n", __func__, - sane_strstatus (status)); - } - - DBGCOMPLETED; - return status; -} - - -/* Find the position of the reference point: - takes gray level 8 bits data and find - first CCD usable pixel and top of scanning area */ -SANE_Status -sanei_genesys_search_reference_point (Genesys_Device * dev, uint8_t * data, - int start_pixel, int dpi, int width, - int height) -{ - int x, y; - int current, left, top = 0; - uint8_t *image; - int size, count; - int level = 80; /* edge threshold level */ - - /*sanity check */ - if ((width < 3) || (height < 3)) - return SANE_STATUS_INVAL; - - /* transformed image data */ - size = width * height; - image = malloc (size); - if (!image) - { - DBG (DBG_error, - "sanei_genesys_search_reference_point: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - /* laplace filter to denoise picture */ - memcpy (image, data, size); /* to initialize unprocessed part of the image buffer */ - for (y = 1; y < height - 1; y++) - for (x = 1; x < width - 1; x++) - { - image[y * width + x] = - (data[(y - 1) * width + x + 1] + 2 * data[(y - 1) * width + x] + - data[(y - 1) * width + x - 1] + 2 * data[y * width + x + 1] + - 4 * data[y * width + x] + 2 * data[y * width + x - 1] + - data[(y + 1) * width + x + 1] + 2 * data[(y + 1) * width + x] + - data[(y + 1) * width + x - 1]) / 16; - } - - memcpy (data, image, size); - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("laplace.pnm", image, 8, 1, width, height); - - /* apply X direction sobel filter - -1 0 1 - -2 0 2 - -1 0 1 - and finds threshold level - */ - level = 0; - for (y = 2; y < height - 2; y++) - for (x = 2; x < width - 2; x++) - { - current = - data[(y - 1) * width + x + 1] - data[(y - 1) * width + x - 1] + - 2 * data[y * width + x + 1] - 2 * data[y * width + x - 1] + - data[(y + 1) * width + x + 1] - data[(y + 1) * width + x - 1]; - if (current < 0) - current = -current; - if (current > 255) - current = 255; - image[y * width + x] = current; - if (current > level) - level = current; - } - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("xsobel.pnm", image, 8, 1, width, height); - - /* set up detection level */ - level = level / 3; - - /* find left black margin first - todo: search top before left - we average the result of N searches */ - left = 0; - count = 0; - for (y = 2; y < 11; y++) - { - x = 8; - while ((x < width / 2) && (image[y * width + x] < level)) - { - image[y * width + x] = 255; - x++; - } - count++; - left += x; - } - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("detected-xsobel.pnm", image, 8, 1, width, - height); - left = left / count; - - /* turn it in CCD pixel at full sensor optical resolution */ - dev->sensor.CCD_start_xoffset = - start_pixel + (left * dev->sensor.optical_res) / dpi; - - /* find top edge by detecting black strip */ - /* apply Y direction sobel filter - -1 -2 -1 - 0 0 0 - 1 2 1 - */ - level = 0; - for (y = 2; y < height - 2; y++) - for (x = 2; x < width - 2; x++) - { - current = - -data[(y - 1) * width + x + 1] - 2 * data[(y - 1) * width + x] - - data[(y - 1) * width + x - 1] + data[(y + 1) * width + x + 1] + - 2 * data[(y + 1) * width + x] + data[(y + 1) * width + x - 1]; - if (current < 0) - current = -current; - if (current > 255) - current = 255; - image[y * width + x] = current; - if (current > level) - level = current; - } - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("ysobel.pnm", image, 8, 1, width, height); - - /* set up detection level */ - level = level / 3; - - /* search top of horizontal black stripe : TODO yet another flag */ - if (dev->model->ccd_type == CCD_5345 - && dev->model->motor_type == MOTOR_5345) - { - top = 0; - count = 0; - for (x = width / 2; x < width - 1; x++) - { - y = 2; - while ((y < height) && (image[x + y * width] < level)) - { - image[y * width + x] = 255; - y++; - } - count++; - top += y; - } - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("detected-ysobel.pnm", image, 8, 1, - width, height); - top = top / count; - - /* bottom of black stripe is of fixed witdh, this hardcoded value - * will be moved into device struct if more such values are needed */ - top += 10; - dev->model->y_offset_calib = SANE_FIX ((top * MM_PER_INCH) / dpi); - DBG (DBG_info, - "sanei_genesys_search_reference_point: black stripe y_offset = %f mm \n", - SANE_UNFIX (dev->model->y_offset_calib)); - } - - /* find white corner in dark area : TODO yet another flag */ - if ((dev->model->ccd_type == CCD_HP2300 - && dev->model->motor_type == MOTOR_HP2300) - || (dev->model->ccd_type == CCD_HP2400 - && dev->model->motor_type == MOTOR_HP2400) - || (dev->model->ccd_type == CCD_HP3670 - && dev->model->motor_type == MOTOR_HP3670)) - { - top = 0; - count = 0; - for (x = 10; x < 60; x++) - { - y = 2; - while ((y < height) && (image[x + y * width] < level)) - y++; - top += y; - count++; - } - top = top / count; - dev->model->y_offset_calib = SANE_FIX ((top * MM_PER_INCH) / dpi); - DBG (DBG_info, - "sanei_genesys_search_reference_point: white corner y_offset = %f mm\n", - SANE_UNFIX (dev->model->y_offset_calib)); - } - - free (image); - DBG (DBG_proc, - "sanei_genesys_search_reference_point: CCD_start_xoffset = %d, left = %d, top = %d\n", - dev->sensor.CCD_start_xoffset, left, top); - - return SANE_STATUS_GOOD; -} - - -void -sanei_genesys_calculate_zmode2 (SANE_Bool two_table, - uint32_t exposure_time, - uint16_t * slope_table, - int reg21, - int move, int reg22, uint32_t * z1, - uint32_t * z2) -{ - int i; - int sum; - DBG (DBG_info, "sanei_genesys_calculate_zmode2: two_table=%d\n", two_table); - - /* acceleration total time */ - sum = 0; - for (i = 0; i < reg21; i++) - sum += slope_table[i]; - - /* compute Z1MOD */ - /* c=sum(slope_table;reg21) - d=reg22*cruising speed - Z1MOD=(c+d) % exposure_time */ - *z1 = (sum + reg22 * slope_table[reg21 - 1]) % exposure_time; - - /* compute Z2MOD */ - /* a=sum(slope_table;reg21), b=move or 1 if 2 tables */ - /* Z2MOD=(a+b) % exposure_time */ - if (!two_table) - sum = sum + (move * slope_table[reg21 - 1]); - else - sum = sum + slope_table[reg21 - 1]; - *z2 = sum % exposure_time; -} - - -/* huh? */ -/* todo: double check */ -/* Z1 and Z2 seem to be a time to synchronize with clock or a phase correction */ -/* steps_sum is the result of create_slope_table */ -/* last_speed is the last entry of the slope_table */ -/* feedl is registers 3d,3e,3f */ -/* fastfed is register 02 bit 3 */ -/* scanfed is register 1f */ -/* fwdstep is register 22 */ -/* tgtime is register 6c bit 6+7 >> 6 */ - -void -sanei_genesys_calculate_zmode (uint32_t exposure_time, - uint32_t steps_sum, uint16_t last_speed, - uint32_t feedl, uint8_t fastfed, - uint8_t scanfed, uint8_t fwdstep, - uint8_t tgtime, uint32_t * z1, uint32_t * z2) -{ - uint8_t exposure_factor; - - exposure_factor = pow (2, tgtime); /* todo: originally, this is always 2^0 ! */ - - /* Z1 is for buffer-full backward forward moving */ - *z1 = - exposure_factor * ((steps_sum + fwdstep * last_speed) % exposure_time); - - /* Z2 is for acceleration before scan */ - if (fastfed) /* two curve mode */ - { - *z2 = - exposure_factor * ((steps_sum + scanfed * last_speed) % - exposure_time); - } - else /* one curve mode */ - { - *z2 = - exposure_factor * ((steps_sum + feedl * last_speed) % exposure_time); - } -} - - -static void -genesys_adjust_gain (double *applied_multi, - uint8_t * new_gain, double multi, uint8_t gain) -{ - double voltage, original_voltage; - - DBG (DBG_proc, "genesys_adjust_gain: multi=%f, gain=%d\n", multi, gain); - - voltage = 0.5 + gain * 0.25; - original_voltage = voltage; - - voltage *= multi; - - *new_gain = (uint8_t) ((voltage - 0.5) * 4); - if (*new_gain > 0x0e) - *new_gain = 0x0e; - - voltage = 0.5 + (*new_gain) * 0.25; - - *applied_multi = voltage / original_voltage; - - DBG (DBG_proc, - "genesys_adjust_gain: orig voltage=%.2f, new voltage=%.2f, " - "*applied_multi=%f, *new_gain=%d\n", original_voltage, voltage, - *applied_multi, *new_gain); - return; -} - - -/* todo: is return status necessary (unchecked?) */ -static SANE_Status -genesys_average_white (Genesys_Device * dev, int channels, int channel, - uint8_t * data, int size, int *max_average) -{ - int gain_white_ref, sum, range; - int average; - int i; - - DBG (DBG_proc, - "genesys_average_white: channels=%d, channel=%d, size=%d\n", - channels, channel, size); - - range = size / 50; - - if (dev->settings.scan_method == SCAN_METHOD_TRANSPARENCY) /* transparency mode */ - gain_white_ref = dev->sensor.fau_gain_white_ref * 256; - else - gain_white_ref = dev->sensor.gain_white_ref * 256; - - if (range < 1) - range = 1; - - size = size / (2 * range * channels); - - data += (channel * 2); - - *max_average = 0; - - while (size--) - { - sum = 0; - for (i = 0; i < range; i++) - { - sum += (*data); - sum += *(data + 1) * 256; - data += (2 * channels); /* byte based */ - } - - average = (sum / range); - if (average > *max_average) - *max_average = average; - } - - DBG (DBG_proc, - "genesys_average_white: max_average=%d, gain_white_ref = %d, finished\n", - *max_average, gain_white_ref); - - if (*max_average >= gain_white_ref) - return SANE_STATUS_INVAL; - - return SANE_STATUS_GOOD; -} - -/* todo: understand, values are too high */ -static int -genesys_average_black (Genesys_Device * dev, int channel, - uint8_t * data, int pixels) -{ - int i; - int sum; - int pixel_step; - - DBG (DBG_proc, "genesys_average_black: channel=%d, pixels=%d\n", - channel, pixels); - - sum = 0; - - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - { - data += (channel * 2); - pixel_step = 3 * 2; - } - else - { - pixel_step = 2; - } - - for (i = 0; i < pixels; i++) - { - sum += *data; - sum += *(data + 1) * 256; - - data += pixel_step; - } - - DBG (DBG_proc, "genesys_average_black = %d\n", sum / pixels); - - return (int) (sum / pixels); -} - - -/* todo: check; it works but the lines 1, 2, and 3 are too dark even with the - same offset and gain settings? */ -static SANE_Status -genesys_coarse_calibration (Genesys_Device * dev) -{ - int size; - int black_pixels; - int white_average; - int channels; - SANE_Status status; - uint8_t offset[4] = { 0xa0, 0x00, 0xa0, 0x40 }; /* first value isn't used */ - uint16_t white[12], dark[12]; - int i, j; - uint8_t *calibration_data, *all_data; - - DBG (DBG_info, "genesys_coarse_calibration (scan_mode = %d)\n", - dev->settings.scan_mode); - - black_pixels = dev->sensor.black_pixels - * dev->settings.xres / dev->sensor.optical_res; - - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - DBG (DBG_info, "channels %d y_size %d xres %d\n", - channels, dev->model->y_size, dev->settings.xres); - size = - channels * 2 * SANE_UNFIX (dev->model->y_size) * dev->settings.xres / - 25.4; - /* 1 1 mm 1/inch inch/mm */ - - calibration_data = malloc (size); - if (!calibration_data) - { - DBG (DBG_error, - "genesys_coarse_calibration: failed to allocate memory(%d bytes)\n", - size); - return SANE_STATUS_NO_MEM; - } - - all_data = calloc (1, size * 4); - - status = dev->model->cmd_set->set_fe (dev, AFE_INIT); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, - sane_strstatus (status)); - free(all_data); - free(calibration_data); - return status; - } - - dev->frontend.sign[0] = 0; - dev->frontend.sign[1] = 0; - dev->frontend.sign[2] = 0; - dev->frontend.gain[0] = 2; - dev->frontend.gain[1] = 2; - dev->frontend.gain[2] = 2; /* todo: ? was 2 */ - dev->frontend.offset[0] = offset[0]; - dev->frontend.offset[1] = offset[0]; - dev->frontend.offset[2] = offset[0]; - - for (i = 0; i < 4; i++) /* read 4 lines */ - { - if (i < 3) /* first 3 lines */ - { - dev->frontend.offset[0] = offset[i]; - dev->frontend.offset[1] = offset[i]; - dev->frontend.offset[2] = offset[i]; - } - - if (i == 1) /* second line */ - { - double applied_multi; - double gain_white_ref; - - if (dev->settings.scan_method == SCAN_METHOD_TRANSPARENCY) /* Transparency */ - gain_white_ref = dev->sensor.fau_gain_white_ref * 256; - else - gain_white_ref = dev->sensor.gain_white_ref * 256; - /* white and black are defined downwards */ - - genesys_adjust_gain (&applied_multi, - &dev->frontend.gain[0], - gain_white_ref / (white[0] - dark[0]), - dev->frontend.gain[0]); - genesys_adjust_gain (&applied_multi, - &dev->frontend.gain[1], - gain_white_ref / (white[1] - dark[1]), - dev->frontend.gain[1]); - genesys_adjust_gain (&applied_multi, - &dev->frontend.gain[2], - gain_white_ref / (white[2] - dark[2]), - dev->frontend.gain[2]); - - dev->frontend.gain[0] = dev->frontend.gain[1] = - dev->frontend.gain[2] = 2; - - status = - sanei_genesys_fe_write_data (dev, 0x28, dev->frontend.gain[0]); - if (status != SANE_STATUS_GOOD) /* todo: this was 0x28 + 3 ? */ - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to write gain[0]: %s\n", - sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x29, dev->frontend.gain[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to write gain[1]: %s\n", - sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x2a, dev->frontend.gain[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to write gain[2]: %s\n", - sane_strstatus (status)); - return status; - } - } - - if (i == 3) /* last line */ - { - double x, y, rate; - - for (j = 0; j < 3; j++) - { - - x = - (double) (dark[(i - 2) * 3 + j] - - dark[(i - 1) * 3 + j]) * 254 / (offset[i - 1] / 2 - - offset[i - 2] / 2); - y = x - x * (offset[i - 1] / 2) / 254 - dark[(i - 1) * 3 + j]; - rate = (x - DARK_VALUE - y) * 254 / x + 0.5; - - dev->frontend.offset[j] = (uint8_t) (rate); - - if (dev->frontend.offset[j] > 0x7f) - dev->frontend.offset[j] = 0x7f; - dev->frontend.offset[j] <<= 1; - } - } - status = - sanei_genesys_fe_write_data (dev, 0x20, dev->frontend.offset[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to write offset[0]: %s\n", - sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x21, dev->frontend.offset[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to write offset[1]: %s\n", - sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x22, dev->frontend.offset[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to write offset[2]: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_info, - "genesys_coarse_calibration: doing scan: sign: %d/%d/%d, gain: %d/%d/%d, offset: %d/%d/%d\n", - dev->frontend.sign[0], dev->frontend.sign[1], - dev->frontend.sign[2], dev->frontend.gain[0], - dev->frontend.gain[1], dev->frontend.gain[2], - dev->frontend.offset[0], dev->frontend.offset[1], - dev->frontend.offset[2]); - - status = - dev->model->cmd_set->begin_scan (dev, dev->calib_reg, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_read_data_from_scanner (dev, calibration_data, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - memcpy (all_data + i * size, calibration_data, size); - if (i == 3) /* last line */ - { - SANE_Byte *all_data_8 = malloc (size * 4 / 2); - unsigned int count; - - for (count = 0; count < (unsigned int) (size * 4 / 2); count++) - all_data_8[count] = all_data[count * 2 + 1]; - status = - sanei_genesys_write_pnm_file ("coarse.pnm", all_data_8, 8, - channels, size / 6, 4); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: sanei_genesys_write_pnm_file failed: %s\n", - sane_strstatus (status)); - return status; - } - } - - status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_coarse_calibration: Failed to end scan: %s\n", - sane_strstatus (status)); - return status; - } - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - { - for (j = 0; j < 3; j++) - { - genesys_average_white (dev, 3, j, calibration_data, size, - &white_average); - white[i * 3 + j] = white_average; - dark[i * 3 + j] = - genesys_average_black (dev, j, calibration_data, - black_pixels); - DBG (DBG_info, - "genesys_coarse_calibration: white[%d]=%d, black[%d]=%d\n", - i * 3 + j, white[i * 3 + j], i * 3 + j, dark[i * 3 + j]); - } - } - else /* one color-component modes */ - { - genesys_average_white (dev, 1, 0, calibration_data, size, - &white_average); - white[i * 3 + 0] = white[i * 3 + 1] = white[i * 3 + 2] = - white_average; - dark[i * 3 + 0] = dark[i * 3 + 1] = dark[i * 3 + 2] = - genesys_average_black (dev, 0, calibration_data, black_pixels); - } - - if (i == 3) - { - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - { - /* todo: huh? */ - dev->dark[0] = - (uint16_t) (1.6925 * dark[i * 3 + 0] + 0.1895 * 256); - dev->dark[1] = - (uint16_t) (1.4013 * dark[i * 3 + 1] + 0.3147 * 256); - dev->dark[2] = - (uint16_t) (1.2931 * dark[i * 3 + 2] + 0.1558 * 256); - } - else /* one color-component modes */ - { - switch (dev->settings.color_filter) - { - case 0: - default: - dev->dark[0] = - (uint16_t) (1.6925 * dark[i * 3 + 0] + - (1.1895 - 1.0) * 256); - dev->dark[1] = dev->dark[2] = dev->dark[0]; - break; - - case 1: - dev->dark[1] = - (uint16_t) (1.4013 * dark[i * 3 + 1] + - (1.3147 - 1.0) * 256); - dev->dark[0] = dev->dark[2] = dev->dark[1]; - break; - - case 2: - dev->dark[2] = - (uint16_t) (1.2931 * dark[i * 3 + 2] + - (1.1558 - 1.0) * 256); - dev->dark[0] = dev->dark[1] = dev->dark[2]; - break; - } - } - } - } /* for (i = 0; i < 4; i++) */ - - free(all_data); - DBG (DBG_info, - "genesys_coarse_calibration: final: sign: %d/%d/%d, gain: %d/%d/%d, offset: %d/%d/%d\n", - dev->frontend.sign[0], dev->frontend.sign[1], dev->frontend.sign[2], - dev->frontend.gain[0], dev->frontend.gain[1], dev->frontend.gain[2], - dev->frontend.offset[0], dev->frontend.offset[1], - dev->frontend.offset[2]); - DBGCOMPLETED; - - return status; -} - -/* Averages image data. - average_data and calibration_data are little endian 16 bit words. - */ -#ifndef UNIT_TESTING -static -#endif -void -genesys_average_data (uint8_t * average_data, - uint8_t * calibration_data, - uint32_t lines, - uint32_t pixel_components_per_line) -{ - uint32_t x, y; - uint32_t sum; - - for (x = 0; x < pixel_components_per_line; x++) - { - sum = 0; - for (y = 0; y < lines; y++) - { - sum += calibration_data[(x + y * pixel_components_per_line) * 2]; - sum += - calibration_data[(x + y * pixel_components_per_line) * 2 + - 1] * 256; - } - sum /= lines; - *average_data++ = sum & 255; - *average_data++ = sum / 256; - } -} - -/** - * scans a white area with motor and lamp off to get the per CCD pixel offset - * that will be used to compute shading coefficient - * @param dev scanner's device - * @return SANE_STATUS_GOOD if OK, else an error - */ -static SANE_Status -genesys_dark_shading_calibration (Genesys_Device * dev) -{ - SANE_Status status; - size_t size; - uint32_t pixels_per_line; - uint8_t channels; - uint8_t *calibration_data; - SANE_Bool motor; - - DBGSTART; - - /* end pixel - start pixel */ - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - FREE_IFNOT_NULL (dev->dark_average_data); - - dev->average_size = channels * 2 * pixels_per_line; - - dev->dark_average_data = malloc (dev->average_size); - if (!dev->dark_average_data) - { - DBG (DBG_error, - "genesys_dark_shading_calibration: failed to allocate average memory\n"); - return SANE_STATUS_NO_MEM; - } - - /* size is size in bytes for scanarea: bytes_per_line * lines */ - size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); - - calibration_data = malloc (size); - if (!calibration_data) - { - DBG (DBG_error, - "genesys_dark_shading_calibration: failed to allocate calibration data memory\n"); - return SANE_STATUS_NO_MEM; - } - - motor=SANE_TRUE; - if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) - { - motor=SANE_FALSE; - } - - /* turn off motor and lamp power for flatbed scanners, but not for sheetfed scanners - * because they have a calibration sheet with a sufficient black strip */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_FALSE); - dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); - } - else - { - dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE); - dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); - } - - status = - dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, - dev->model-> - cmd_set->bulk_full_size ()); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, - "genesys_dark_shading_calibration: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - usleep (200 * 1000); /* wait 200 ms: lamp needs some time to get dark */ - - status = dev->model->cmd_set->begin_scan (dev, dev->calib_reg, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, - "genesys_dark_shading_calibration: Failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_read_data_from_scanner (dev, calibration_data, size); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, - "genesys_dark_shading_calibration: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, - "genesys_dark_shading_calibration: failed to end scan: %s\n", - sane_strstatus (status)); - return status; - } - - genesys_average_data (dev->dark_average_data, calibration_data, - dev->calib_lines, - pixels_per_line * channels); - - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file ("black_shading.pnm", calibration_data, 16, - channels, pixels_per_line, - dev->calib_lines); - sanei_genesys_write_pnm_file ("black_average.pnm", - dev->dark_average_data, 16, channels, - pixels_per_line, 1); - } - - free (calibration_data); - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/* - * this function builds dummy dark calibration data so that we can - * compute shading coefficient in a clean way - * todo: current values are hardcoded, we have to find if they - * can be computed from previous calibration data (when doing offset - * calibration ?) - */ -static SANE_Status -genesys_dummy_dark_shading (Genesys_Device * dev) -{ - uint32_t pixels_per_line; - uint8_t channels; - uint32_t x, skip, xend; - int dummy1, dummy2, dummy3; /* dummy black average per channel */ - - DBGSTART; - - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - FREE_IFNOT_NULL (dev->dark_average_data); - - dev->average_size = channels * 2 * pixels_per_line; - dev->dark_average_data = malloc (dev->average_size); - if (!dev->dark_average_data) - { - DBG (DBG_error, - "genesys_dummy_dark_shading: failed to allocate average memory\n"); - return SANE_STATUS_NO_MEM; - } - memset (dev->dark_average_data, 0x00, channels * 2 * pixels_per_line); - - /* we average values on 'the left' where CCD pixels are under casing and - give darkest values. We then use these as dummy dark calibration */ - if (dev->settings.xres <= dev->sensor.optical_res / 2) - { - skip = 4; - xend = 36; - } - else - { - skip = 4; - xend = 68; - } - if (dev->model->ccd_type==CCD_G4050 - || dev->model->ccd_type==CCD_CS4400F - || dev->model->ccd_type==CCD_CS8400F - || dev->model->ccd_type==CCD_KVSS080) - { - skip = 2; - xend = dev->sensor.black_pixels; - } - - /* average each channels on half left margin */ - dummy1 = 0; - dummy2 = 0; - dummy3 = 0; - - for (x = skip + 1; x <= xend; x++) - { - dummy1 += - dev->white_average_data[channels * 2 * x] + - 256 * dev->white_average_data[channels * 2 * x + 1]; - if (channels > 1) - { - dummy2 += - (dev->white_average_data[channels * 2 * x + 2] + - 256 * dev->white_average_data[channels * 2 * x + 3]); - dummy3 += - (dev->white_average_data[channels * 2 * x + 4] + - 256 * dev->white_average_data[channels * 2 * x + 5]); - } - } - - dummy1 /= (xend - skip); - if (channels > 1) - { - dummy2 /= (xend - skip); - dummy3 /= (xend - skip); - } - DBG (DBG_proc, - "genesys_dummy_dark_shading: dummy1=%d, dummy2=%d, dummy3=%d \n", - dummy1, dummy2, dummy3); - - /* fill dark_average */ - for (x = 0; x < pixels_per_line; x++) - { - dev->dark_average_data[channels * 2 * x] = dummy1 & 0xff; - dev->dark_average_data[channels * 2 * x + 1] = dummy1 >> 8; - if (channels > 1) - { - dev->dark_average_data[channels * 2 * x + 2] = dummy2 & 0xff; - dev->dark_average_data[channels * 2 * x + 3] = dummy2 >> 8; - dev->dark_average_data[channels * 2 * x + 4] = dummy3 & 0xff; - dev->dark_average_data[channels * 2 * x + 5] = dummy3 >> 8; - } - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -genesys_white_shading_calibration (Genesys_Device * dev) -{ - SANE_Status status; - size_t size; - uint32_t pixels_per_line; - uint8_t *calibration_data; - uint8_t channels; - SANE_Bool motor; - - DBG (DBG_proc, "genesys_white_shading_calibration (lines = %d)\n", - (unsigned int)dev->calib_lines); - - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - if (dev->white_average_data) - free (dev->white_average_data); - - dev->white_average_data = malloc (channels * 2 * pixels_per_line); - if (!dev->white_average_data) - { - DBG (DBG_error, - "genesys_white_shading_calibration: failed to allocate average memory\n"); - return SANE_STATUS_NO_MEM; - } - - size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); - - calibration_data = malloc (size); - if (!calibration_data) - { - DBG (DBG_error, - "genesys_white_shading_calibration: failed to allocate calibration memory\n"); - return SANE_STATUS_NO_MEM; - } - - motor=SANE_TRUE; - if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) - { - motor=SANE_FALSE; - } - - /* turn on motor and lamp power */ - dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE); - dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); - - /* if needed, go back before doin next scan, by using rewind, registers and - * slopes table are kept intact from previous scan */ - if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK && dev->model->cmd_set->rewind) - { - status = dev->model->cmd_set->rewind (dev); - } - - status = - dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, - dev->model-> - cmd_set->bulk_full_size ()); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, - "genesys_white_shading_calibration: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) - usleep (500 * 1000); /* wait 500ms to make sure lamp is bright again */ - - status = dev->model->cmd_set->begin_scan (dev, dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, - "genesys_white_shading_calibration: Failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_read_data_from_scanner (dev, calibration_data, size); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, - "genesys_white_shading_calibration: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, - "genesys_white_shading_calibration: failed to end scan: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("white_shading.pnm", calibration_data, 16, - channels, pixels_per_line, - dev->calib_lines); - - genesys_average_data (dev->white_average_data, calibration_data, - dev->calib_lines, - pixels_per_line * channels); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("white_average.pnm", - dev->white_average_data, 16, channels, - pixels_per_line, 1); - - free (calibration_data); - - /* in case we haven't done dark calibration, build dummy data from white_average */ - if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) - { - status = genesys_dummy_dark_shading (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_white_shading_calibration: failed to do dummy dark shading calibration: %s\n", - sane_strstatus (status)); - return status; - } - } - - if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) - { - status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); - } - - DBGCOMPLETED; - - return status; -} - -/* This calibration uses a scan over the calibration target, comprising a - * black and a white strip. (So the motor must be on.) - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -genesys_dark_white_shading_calibration (Genesys_Device * dev) -{ - SANE_Status status; - size_t size; - uint32_t pixels_per_line; - uint8_t *calibration_data, *average_white, *average_dark; - uint8_t channels; - unsigned int x; - int y; - uint32_t dark, white, dark_sum, white_sum, dark_count, white_count, col, - dif; - SANE_Bool motor; - - - DBG (DBG_proc, "%s: (lines = %d)\n", __func__, (unsigned int)dev->calib_lines); - - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - if (dev->white_average_data) - free (dev->white_average_data); - - dev->average_size = channels * 2 * pixels_per_line; - - dev->white_average_data = malloc (dev->average_size); - if (!dev->white_average_data) - { - DBG (DBG_error, "%s: failed to allocate white average memory\n", __func__); - return SANE_STATUS_NO_MEM; - } - - if (dev->dark_average_data) - free (dev->dark_average_data); - - dev->dark_average_data = malloc (channels * 2 * pixels_per_line); - if (!dev->dark_average_data) - { - DBG (DBG_error, "%s: failed to allocate dark average memory\n", __func__); - return SANE_STATUS_NO_MEM; - } - - size = channels * 2 * pixels_per_line * dev->calib_lines; - - calibration_data = malloc (size); - if (!calibration_data) - { - DBG (DBG_error, "%s: failed to allocate calibration memory\n", __func__); - return SANE_STATUS_NO_MEM; - } - - motor=SANE_TRUE; - if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) - { - motor=SANE_FALSE; - } - - /* turn on motor and lamp power */ - dev->model->cmd_set->set_lamp_power (dev, dev->calib_reg, SANE_TRUE); - dev->model->cmd_set->set_motor_power (dev->calib_reg, motor); - - status = - dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, - dev->model-> - cmd_set->bulk_full_size ()); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - status = dev->model->cmd_set->begin_scan (dev, dev->calib_reg, SANE_FALSE); - - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, "%s: failed to begin scan: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_read_data_from_scanner (dev, calibration_data, size); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, "%s: failed to read data: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - status = dev->model->cmd_set->end_scan (dev, dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (calibration_data); - DBG (DBG_error, "%s: Failed to end scan: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - if (dev->model->is_cis) - { - sanei_genesys_write_pnm_file ("black_white_shading.pnm", calibration_data, - 16, 1, pixels_per_line*channels, - dev->calib_lines); - } - else - { - sanei_genesys_write_pnm_file ("black_white_shading.pnm", calibration_data, - 16, channels, pixels_per_line, - dev->calib_lines); - } - } - - - average_white = dev->white_average_data; - average_dark = dev->dark_average_data; - - for (x = 0; x < pixels_per_line * channels; x++) - { - dark = 0xffff; - white = 0; - - for (y = 0; y < (int)dev->calib_lines; y++) - { - col = calibration_data[(x + y * pixels_per_line * channels) * 2]; - col |= - calibration_data[(x + y * pixels_per_line * channels) * 2 + - 1] << 8; - - if (col > white) - white = col; - if (col < dark) - dark = col; - } - - dif = white - dark; - - dark = dark + dif / 8; - white = white - dif / 8; - - dark_count = 0; - dark_sum = 0; - - white_count = 0; - white_sum = 0; - - for (y = 0; y < (int)dev->calib_lines; y++) - { - col = calibration_data[(x + y * pixels_per_line * channels) * 2]; - col |= - calibration_data[(x + y * pixels_per_line * channels) * 2 + - 1] << 8; - - if (col >= white) - { - white_sum += col; - white_count++; - } - if (col <= dark) - { - dark_sum += col; - dark_count++; - } - - } - - dark_sum /= dark_count; - white_sum /= white_count; - - *average_dark++ = dark_sum & 255; - *average_dark++ = dark_sum >> 8; - - *average_white++ = white_sum & 255; - *average_white++ = white_sum >> 8; - } - - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file ("white_average.pnm", - dev->white_average_data, 16, channels, - pixels_per_line, 1); - sanei_genesys_write_pnm_file ("dark_average.pnm", - dev->dark_average_data, 16, channels, - pixels_per_line, 1); - } - - free (calibration_data); - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/* computes one coefficient given bright-dark value - * @param coeff factor giving 1.00 gain - * @param target desired target code - * @param value brght-dark value - * */ -static unsigned int -compute_coefficient (unsigned int coeff, unsigned int target, unsigned int value) -{ - int result; - - if (value > 0) - { - result = (coeff * target) / value; - if (result >= 65535) - { - result = 65535; - } - } - else - { - result = coeff; - } - return result; -} - -/** @brief compute shading coefficients for LiDE scanners - * The dark/white shading is actually performed _after_ reducing - * resolution via averaging. only dark/white shading data for what would be - * first pixel at full resolution is used. - * - * scanner raw input to output value calculation: - * o=(i-off)*(gain/coeff) - * - * from datasheet: - * off=dark_average - * gain=coeff*bright_target/(bright_average-dark_average) - * works for dark_target==0 - * - * what we want is these: - * bright_target=(bright_average-off)*(gain/coeff) - * dark_target=(dark_average-off)*(gain/coeff) - * leading to - * off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) - * gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff - * - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param pixels_per_line number of pixels per line - * @param words_per_color memory words per color channel - * @param channels number of color channels (actually 1 or 3) - * @param o shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not (GAIN4 bit) - * @param target_bright value of the white target code - * @param target_dark value of the black target code -*/ -#ifndef UNIT_TESTING -static -#endif -void -compute_averaged_planar (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int words_per_color, - unsigned int channels, - unsigned int o, - unsigned int coeff, - unsigned int target_bright, - unsigned int target_dark) -{ - unsigned int x, i, j, br, dk, res, avgpixels, basepixels, val; - unsigned int fill,factor; - - DBG (DBG_info, "%s: pixels=%d, offset=%d\n", __func__, pixels_per_line, o); - - /* initialize result */ - memset (shading_data, 0xff, words_per_color * 3 * 2); - - /* - strangely i can write 0x20000 bytes beginning at 0x00000 without overwriting - slope tables - which begin at address 0x10000(for 1200dpi hw mode): - memory is organized in words(2 bytes) instead of single bytes. explains - quite some things - */ -/* - another one: the dark/white shading is actually performed _after_ reducing - resolution via averaging. only dark/white shading data for what would be - first pixel at full resolution is used. - */ -/* - scanner raw input to output value calculation: - o=(i-off)*(gain/coeff) - - from datasheet: - off=dark_average - gain=coeff*bright_target/(bright_average-dark_average) - works for dark_target==0 - - what we want is these: - bright_target=(bright_average-off)*(gain/coeff) - dark_target=(dark_average-off)*(gain/coeff) - leading to - off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) - gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff - */ - res = dev->settings.xres; - - /* duplicate half-ccd logic */ - if ((dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE) && - dev->settings.xres <= dev->sensor.optical_res / 2) - res *= 2; - - /* this should be evenly dividable */ - basepixels = dev->sensor.optical_res / res; - - /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ - if (basepixels < 1) - avgpixels = 1; - else if (basepixels < 6) - avgpixels = basepixels; - else if (basepixels < 8) - avgpixels = 6; - else if (basepixels < 10) - avgpixels = 8; - else if (basepixels < 12) - avgpixels = 10; - else if (basepixels < 15) - avgpixels = 12; - else - avgpixels = 15; - - /* LiDE80 packs shading data */ - if(dev->model->ccd_type != CIS_CANONLIDE80) - { - factor=1; - fill=avgpixels; - } - else - { - factor=avgpixels; - fill=1; - } - - DBG (DBG_info, "%s: averaging over %d pixels\n", __func__, avgpixels); - DBG (DBG_info, "%s: packing factor is %d\n", __func__, factor); - DBG (DBG_info, "%s: fill length is %d\n", __func__, fill); - - for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) - { - if ((x + o) * 2 * 2 + 3 > words_per_color * 2) - break; - - for (j = 0; j < channels; j++) - { - - dk = 0; - br = 0; - for (i = 0; i < avgpixels; i++) - { - /* dark data */ - dk += - (dev->dark_average_data[(x + i + - pixels_per_line * j) * - 2] | - (dev->dark_average_data - [(x + i + pixels_per_line * j) * 2 + 1] << 8)); - - /* white data */ - br += - (dev->white_average_data[(x + i + - pixels_per_line * j) * - 2] | - (dev->white_average_data - [(x + i + pixels_per_line * j) * 2 + 1] << 8)); - } - - br /= avgpixels; - dk /= avgpixels; - - if (br * target_dark > dk * target_bright) - val = 0; - else if (dk * target_bright - br * target_dark > - 65535 * (target_bright - target_dark)) - val = 65535; - else - { - val = (dk * target_bright - br * target_dark) / (target_bright - target_dark); - } - - /*fill all pixels, even if only the last one is relevant*/ - for (i = 0; i < fill; i++) - { - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j] = val & 0xff; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = val >> 8; - } - - val = br - dk; - - if (65535 * val > (target_bright - target_dark) * coeff) - { - val = (coeff * (target_bright - target_dark)) / val; - } - else - { - val = 65535; - } - - /*fill all pixels, even if only the last one is relevant*/ - for (i = 0; i < fill; i++) - { - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = val & 0xff; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = val >> 8; - } - } - - /* fill remaining channels */ - for (j = channels; j < 3; j++) - { - for (i = 0; i < fill; i++) - { - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j ] = shading_data[(x/factor + o + i) * 2 * 2 ]; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = shading_data[(x/factor + o + i) * 2 * 2 + 1]; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = shading_data[(x/factor + o + i) * 2 * 2 + 2]; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = shading_data[(x/factor + o + i) * 2 * 2 + 3]; - } - } - } -} - -/** - * Computes shading coefficient using formula in data sheet. 16bit data values - * manipulated here are little endian. For now we assume deletion scanning type - * and that there is always 3 channels. - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param pixels_per_line number of pixels per line - * @param channels number of color channels (actually 1 or 3) - * @param cmat color transposition matrix - * @param offset shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not - * @param target value of the target code - */ -#ifndef UNIT_TESTING -static -#endif -void -compute_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int channels, - unsigned int cmat[3], - int offset, - unsigned int coeff, - unsigned int target) -{ - uint8_t *ptr; /* contain 16bit words in little endian */ - unsigned int x, c; - unsigned int val, br, dk; - unsigned int start, end; - - DBG (DBG_io, - "compute_coefficients: pixels_per_line=%d, coeff=0x%04x\n", pixels_per_line, coeff); - - /* compute start & end values depending of the offset */ - if (offset < 0) - { - start = -1 * offset; - end = pixels_per_line; - } - else - { - start = 0; - end = pixels_per_line - offset; - } - - for (c = 0; c < channels; c++) - { - for (x = start; x < end; x++) - { - /* TODO if channels=1 , use filter to know the base addr */ - ptr = shading_data + 4 * ((x + offset) * channels + cmat[c]); - - /* dark data */ - dk = dev->dark_average_data[x * 2 * channels + c * 2]; - dk += 256 * dev->dark_average_data[x * 2 * channels + c * 2 + 1]; - - /* white data */ - br = dev->white_average_data[x * 2 * channels + c * 2]; - br += 256 * dev->white_average_data[x * 2 * channels + c * 2 + 1]; - - /* compute coeff */ - val=compute_coefficient(coeff,target,br-dk); - - /* assign it */ - ptr[0] = dk & 255; - ptr[1] = dk / 256; - ptr[2] = val & 0xff; - ptr[3] = val / 256; - - } - } -} - -/** - * Computes shading coefficient using formula in data sheet. 16bit data values - * manipulated here are little endian. Data is in planar form, ie grouped by - * lines of the same color component. - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param factor averaging factor when the calibration scan is done at a higher resolution - * than the final scan - * @param pixels_per_line number of pixels per line - * @param words_per_color total number of shading data words for one color element - * @param channels number of color channels (actually 1 or 3) - * @param cmat transcoding matrix for color channel order - * @param offset shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not - * @param target white target value - */ -#ifndef UNIT_TESTING -static -#endif -void -compute_planar_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int factor, - unsigned int pixels_per_line, - unsigned int words_per_color, - unsigned int channels, - unsigned int cmat[3], - unsigned int offset, - unsigned int coeff, - unsigned int target) -{ - uint8_t *ptr; /* contains 16bit words in little endian */ - uint32_t x, c, i; - uint32_t val, dk, br; - - DBG (DBG_io, - "compute_planar_coefficients: factor=%d, pixels_per_line=%d, words=0x%X, coeff=0x%04x\n", factor, - pixels_per_line, words_per_color, coeff); - for (c = 0; c < channels; c++) - { - /* shading data is larger than pixels_per_line so offset can be neglected */ - for (x = 0; x < pixels_per_line; x+=factor) - { - /* x2 because of 16 bit values, and x2 since one coeff for dark - * and another for white */ - ptr = shading_data + words_per_color * cmat[c] * 2 + (x + offset) * 4; - - dk = 0; - br = 0; - - /* average case */ - for(i=0;idark_average_data[((x+i) + pixels_per_line * c) * 2 + 1]; - dk += dev->dark_average_data[((x+i) + pixels_per_line * c) * 2]; - br += - 256 * dev->white_average_data[((x+i) + pixels_per_line * c) * 2 + 1]; - br += dev->white_average_data[((x+i) + pixels_per_line * c) * 2]; - } - dk /= factor; - br /= factor; - - val = compute_coefficient (coeff, target, br - dk); - - /* we duplicate the information to have calibration data at optical resolution */ - for (i = 0; i < factor; i++) - { - ptr[0 + 4 * i] = dk & 255; - ptr[1 + 4 * i] = dk / 256; - ptr[2 + 4 * i] = val & 0xff; - ptr[3 + 4 * i] = val / 256; - } - } - } - /* in case of gray level scan, we duplicate shading information on all - * three color channels */ - if(channels==1) - { - memcpy(shading_data+cmat[1]*2*words_per_color, - shading_data+cmat[0]*2*words_per_color, - words_per_color*2); - memcpy(shading_data+cmat[2]*2*words_per_color, - shading_data+cmat[0]*2*words_per_color, - words_per_color*2); - } -} - -#ifndef UNIT_TESTING -static -#endif -void -compute_shifted_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int channels, - unsigned int cmat[3], - int offset, - unsigned int coeff, - unsigned int target_dark, - unsigned int target_bright, - unsigned int patch_size) /* contigous extent */ -{ - unsigned int x, avgpixels, basepixels, i, j, val1, val2; - unsigned int br_tmp [3], dk_tmp [3]; - uint8_t *ptr = shading_data + offset * 3 * 4; /* contain 16bit words in little endian */ - unsigned int patch_cnt = offset * 3; /* at start, offset of first patch */ - - x = dev->settings.xres; - if ((dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE) && - (dev->settings.xres <= dev->sensor.optical_res / 2)) - x *= 2; /* scanner is using half-ccd mode */ - basepixels = dev->sensor.optical_res / x; /*this should be evenly dividable */ - - /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ - if (basepixels < 1) - avgpixels = 1; - else if (basepixels < 6) - avgpixels = basepixels; - else if (basepixels < 8) - avgpixels = 6; - else if (basepixels < 10) - avgpixels = 8; - else if (basepixels < 12) - avgpixels = 10; - else if (basepixels < 15) - avgpixels = 12; - else - avgpixels = 15; - DBG (DBG_info, "compute_shifted_coefficients: pixels_per_line=%d, coeff=0x%04x, averaging over %d pixels\n", pixels_per_line, coeff, avgpixels); - - for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) { - memset (&br_tmp, 0, sizeof(br_tmp)); - memset (&dk_tmp, 0, sizeof(dk_tmp)); - - for (i = 0; i < avgpixels; i++) { - for (j = 0; j < channels; j++) { - br_tmp[j] += (dev->white_average_data[((x + i) * channels + j) * 2] | - (dev->white_average_data[((x + i) * channels + j) * 2 + 1] << 8)); - dk_tmp[i] += (dev->dark_average_data[((x + i) * channels + j) * 2] | - (dev->dark_average_data[((x + i) * channels + j) * 2 + 1] << 8)); - } - } - for (j = 0; j < channels; j++) { - br_tmp[j] /= avgpixels; - dk_tmp[j] /= avgpixels; - - if (br_tmp[j] * target_dark > dk_tmp[j] * target_bright) - val1 = 0; - else if (dk_tmp[j] * target_bright - br_tmp[j] * target_dark > 65535 * (target_bright - target_dark)) - val1 = 65535; - else - val1 = (dk_tmp[j] * target_bright - br_tmp[j] * target_dark) / (target_bright - target_dark); - - val2 = br_tmp[j] - dk_tmp[j]; - if (65535 * val2 > (target_bright - target_dark) * coeff) - val2 = (coeff * (target_bright - target_dark)) / val2; - else - val2 = 65535; - - br_tmp[j] = val1; - dk_tmp[j] = val2; - } - for (i = 0; i < avgpixels; i++) { - for (j = 0; j < channels; j++) { - * ptr++ = br_tmp[ cmat[j] ] & 0xff; - * ptr++ = br_tmp[ cmat[j] ] >> 8; - * ptr++ = dk_tmp[ cmat[j] ] & 0xff; - * ptr++ = dk_tmp[ cmat[j] ] >> 8; - patch_cnt++; - if (patch_cnt == patch_size) { - patch_cnt = 0; - val1 = cmat[2]; - cmat[2] = cmat[1]; - cmat[1] = cmat[0]; - cmat[0] = val1; - } - } - } - } -} - -GENESYS_STATIC SANE_Status -genesys_send_shading_coefficient (Genesys_Device * dev) -{ - SANE_Status status; - uint32_t pixels_per_line; - uint8_t *shading_data; /**> contains 16bit words in little endian */ - uint8_t channels; - int o; - unsigned int length; /**> number of shading calibration data words */ - unsigned int factor; - unsigned int cmat[3]; /**> matrix of color channels */ - unsigned int coeff, target_code, words_per_color = 0; - - DBGSTART; - - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - /* we always build data for three channels, even for gray - * we make the shading data such that each color channel data line is contiguous - * to the next one, which allow to write the 3 channels in 1 write - * during genesys_send_shading_coefficient, some values are words, other bytes - * hence the x2 factor */ - switch (sanei_genesys_read_reg_from_set (dev->reg, 0x05) >> 6) - { - /* 600 dpi */ - case 0: - words_per_color = 0x2a00; - break; - /* 1200 dpi */ - case 1: - words_per_color = 0x5500; - break; - /* 2400 dpi */ - case 2: - words_per_color = 0xa800; - break; - /* 4800 dpi */ - case 3: - words_per_color = 0x15000; - break; - } - - /* special case, memory is aligned on 0x5400, this has yet to be explained */ - /* could be 0xa800 because sensor is truly 2400 dpi, then halved because - * we only set 1200 dpi */ - if(dev->model->ccd_type==CIS_CANONLIDE80) - { - words_per_color = 0x5400; - } - - length = words_per_color * 3 * 2; - - /* allocate computed size */ - shading_data = malloc (length); - if (!shading_data) - { - DBG (DBG_error, "%s: failed to allocate memory\n", __func__); - return SANE_STATUS_NO_MEM; - } - memset (shading_data, 0, length); - - /* TARGET/(Wn-Dn) = white gain -> ~1.xxx then it is multiplied by 0x2000 - or 0x4000 to give an integer - Wn = white average for column n - Dn = dark average for column n - */ - if (dev->model->cmd_set->get_gain4_bit (dev->calib_reg)) - coeff = 0x4000; - else - coeff = 0x2000; - - /* compute avg factor */ - if(dev->settings.xres>dev->sensor.optical_res) - { - factor=1; - } - else - { - factor=dev->sensor.optical_res/dev->settings.xres; - } - - /* for GL646, shading data is planar if REG01_FASTMOD is set and - * chunky if not. For now we rely on the fact that we know that - * each sensor is used only in one mode. Currently only the CIS_XP200 - * sets REG01_FASTMOD. - */ - - /* TODO setup a struct in genesys_devices that - * will handle these settings instead of having this switch growing up */ - cmat[0] = 0; - cmat[1] = 1; - cmat[2] = 2; - switch (dev->model->ccd_type) - { - case CCD_XP300: - case CCD_ROADWARRIOR: - case CCD_DP665: - case CCD_DP685: - case CCD_DSMOBILE600: - target_code = 0xdc00; - o = 4; - compute_planar_coefficients (dev, - shading_data, - factor, - pixels_per_line, - words_per_color, - channels, - cmat, - o, - coeff, - target_code); - break; - case CIS_XP200: - target_code = 0xdc00; - o = 2; - cmat[0] = 2; /* red is last */ - cmat[1] = 0; /* green is first */ - cmat[2] = 1; /* blue is second */ - compute_planar_coefficients (dev, - shading_data, - 1, - pixels_per_line, - words_per_color, - channels, - cmat, - o, - coeff, - target_code); - break; - case CCD_HP2300: - target_code = 0xdc00; - o = 2; - if(dev->settings.xres<=dev->sensor.optical_res/2) - { - o = o - dev->sensor.dummy_pixel / 2; - } - compute_coefficients (dev, - shading_data, - pixels_per_line, - 3, - cmat, - o, - coeff, - target_code); - break; - case CCD_5345: - target_code = 0xe000; - o = 4; - if(dev->settings.xres<=dev->sensor.optical_res/2) - { - o = o - dev->sensor.dummy_pixel; - } - compute_coefficients (dev, - shading_data, - pixels_per_line, - 3, - cmat, - o, - coeff, - target_code); - break; - case CCD_HP3670: - case CCD_HP2400: - target_code = 0xe000; - /* offset is cksel dependent, but we can't use this in common code */ - if(dev->settings.xres<=300) - { - o = -10; /* OK for <=300 */ - } - else if(dev->settings.xres<=600) - { - o = -6; /* ok at 600 */ - } - else - { - o = +2; - } - compute_coefficients (dev, - shading_data, - pixels_per_line, - 3, - cmat, - o, - coeff, - target_code); - break; - case CCD_KVSS080: - case CCD_PLUSTEK3800: - case CCD_G4050: - case CCD_CS4400F: - case CCD_CS8400F: - target_code = 0xe000; - o = 0; - compute_coefficients (dev, - shading_data, - pixels_per_line, - 3, - cmat, - o, - coeff, - target_code); - break; - case CIS_CANONLIDE700: - case CIS_CANONLIDE100: - case CIS_CANONLIDE200: - case CIS_CANONLIDE110: - case CIS_CANONLIDE120: - case CIS_CANONLIDE210: - case CIS_CANONLIDE220: - /* TODO store this in a data struct so we avoid - * growing this switch */ - if(dev->model->ccd_type!=CIS_CANONLIDE110 - && dev->model->ccd_type!=CIS_CANONLIDE210 - && dev->model->ccd_type!=CIS_CANONLIDE120 - && dev->model->ccd_type!=CIS_CANONLIDE220) - target_code=0xdc00; - else - target_code=0xf000; - words_per_color=pixels_per_line*2; - length = words_per_color * 3 * 2; - free(shading_data); - shading_data = malloc (length); - if (!shading_data) - { - DBG (DBG_error, "%s: failed to allocate memory\n", __func__); - return SANE_STATUS_NO_MEM; - } - memset (shading_data, 0, length); - compute_planar_coefficients (dev, - shading_data, - 1, - pixels_per_line, - words_per_color, - channels, - cmat, - 0, - coeff, - target_code); - break; - case CCD_CANONLIDE35: - compute_averaged_planar (dev, - shading_data, - pixels_per_line, - words_per_color, - channels, - 4, - coeff, - 0xe000, - 0x0a00); - break; - case CIS_CANONLIDE80: - compute_averaged_planar (dev, - shading_data, - pixels_per_line, - words_per_color, - channels, - 0, - coeff, - 0xd000, - 0x0800); - break; - case CCD_PLUSTEK_3600: - compute_shifted_coefficients (dev, - shading_data, - pixels_per_line, - channels, - cmat, - 12, /* offset */ - coeff, - 0x0001, /* target_dark */ - 0xf900, /* target_bright */ - 256); /* patch_size: contigous extent */ - break; - default: - DBG (DBG_error, "%s: sensor %d not supported\n", __func__, dev->model->ccd_type); - return SANE_STATUS_UNSUPPORTED; - break; - } - - /* do the actual write of shading calibration data to the scanner */ - status = genesys_send_offset_and_shading (dev, shading_data, length); - free (shading_data); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send shading data: %s\n", __func__, - sane_strstatus (status)); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** - * search calibration cache list for an entry matching required scan. - * If one is found, set device calibration with it - * @param dev scanner's device - * @return SANE_STATUS_UNSUPPORTED if no matching cache entry has been - * found, SANE_STATUS_GOOD if one has been found and used. - */ -static SANE_Status -genesys_restore_calibration (Genesys_Device * dev) -{ - SANE_Status status; - Genesys_Calibration_Cache *cache; - - DBGSTART; - - /* if no cache or no function to evaluate cache entry ther can be no match */ - if (!dev->model->cmd_set->is_compatible_calibration - || dev->calibration_cache == NULL) - return SANE_STATUS_UNSUPPORTED; - - /* we walk the link list of calibration cache in search for a - * matching one */ - for (cache = dev->calibration_cache; cache; cache = cache->next) - { - status = dev->model->cmd_set->is_compatible_calibration (dev, cache, SANE_FALSE); - /* SANE_STATUS_GOOD, a matching cache has been found - * so we use it to populate calibration data - */ - if (status == SANE_STATUS_GOOD) - { - memcpy (&dev->frontend, &cache->frontend, sizeof (dev->frontend)); - /* we don't restore the gamma fields */ - memcpy (dev->sensor.regs_0x10_0x1d, cache->sensor.regs_0x10_0x1d, 6); - free (dev->dark_average_data); - free (dev->white_average_data); - - dev->average_size = cache->average_size; - dev->calib_pixels = cache->calib_pixels; - dev->calib_channels = cache->calib_channels; - - dev->dark_average_data = (uint8_t *) malloc (cache->average_size); - dev->white_average_data = (uint8_t *) malloc (cache->average_size); - - if (!dev->dark_average_data || !dev->white_average_data) - return SANE_STATUS_NO_MEM; - - memcpy (dev->dark_average_data, - cache->dark_average_data, dev->average_size); - memcpy (dev->white_average_data, - cache->white_average_data, dev->average_size); - - - if(dev->model->cmd_set->send_shading_data==NULL) - { - status = genesys_send_shading_coefficient (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_restore_calibration: failed to send shading calibration coefficients: %s\n", - sane_strstatus (status)); - return status; - } - } - - DBG (DBG_proc, "genesys_restore_calibration: restored\n"); - return SANE_STATUS_GOOD; - } - - /* here status is either SANE_STATUS_UNSUPPORTED which mean tested cache - * entry doesn't match, or an fatal error */ - if (status != SANE_STATUS_UNSUPPORTED) - { - DBG (DBG_error, - "genesys_restore_calibration: fail while checking compatibility: %s\n", - sane_strstatus (status)); - return status; - } - } - DBG (DBG_proc, "genesys_restore_calibration: completed(nothing found)\n"); - return SANE_STATUS_UNSUPPORTED; -} - - -static SANE_Status -genesys_save_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_UNSUPPORTED; - Genesys_Calibration_Cache *cache = NULL; -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - - DBGSTART; - - if (!dev->model->cmd_set->is_compatible_calibration) - return SANE_STATUS_UNSUPPORTED; - - if (dev->calibration_cache != NULL) - { - for (cache = dev->calibration_cache; cache; cache = cache->next) - { - status = dev->model->cmd_set->is_compatible_calibration (dev, cache, SANE_TRUE); - if (status == SANE_STATUS_UNSUPPORTED) - { - continue; - } - else if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_save_calibration: fail while checking compatibility: %s\n", - sane_strstatus (status)); - return status; - } - break; - } - } - - /* if we found on overridable cache, we reuse it */ - if (cache) - { - free(cache->dark_average_data); - free(cache->white_average_data); - } - else - { - /* create a new cache entry and insert it in the linked list */ - cache = malloc (sizeof (Genesys_Calibration_Cache)); - if (!cache) - return SANE_STATUS_NO_MEM; - - memset (cache, 0, sizeof (Genesys_Calibration_Cache)); - - cache->next = dev->calibration_cache; - dev->calibration_cache = cache; - } - - cache->average_size = dev->average_size; - - cache->dark_average_data = (uint8_t *) malloc (cache->average_size); - if (!cache->dark_average_data) - return SANE_STATUS_NO_MEM; - cache->white_average_data = (uint8_t *) malloc (cache->average_size); - if (!cache->white_average_data) - return SANE_STATUS_NO_MEM; - - memcpy (&cache->used_setup, &dev->current_setup, sizeof (cache->used_setup)); - memcpy (&cache->frontend, &dev->frontend, sizeof (cache->frontend)); - memcpy (&cache->sensor, &dev->sensor, sizeof (cache->sensor)); - - cache->calib_pixels = dev->calib_pixels; - cache->calib_channels = dev->calib_channels; - memcpy (cache->dark_average_data, dev->dark_average_data, cache->average_size); - memcpy (cache->white_average_data, dev->white_average_data, cache->average_size); -#ifdef HAVE_SYS_TIME_H - gettimeofday(&time,NULL); - cache->last_calibration = time.tv_sec; -#endif - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * does the calibration process for a flatbed scanner - * - offset calibration - * - gain calibration - * - shading calibration - * @param dev device to calibrate - * @return SANE_STATUS_GOOD if everything when all right, else the error code. - */ -GENESYS_STATIC SANE_Status -genesys_flatbed_calibration (Genesys_Device * dev) -{ - SANE_Status status; - uint32_t pixels_per_line; - int yres; - - DBG (DBG_info, "genesys_flatbed_calibration\n"); - - yres = dev->sensor.optical_res; - if (dev->settings.yres <= dev->sensor.optical_res / 2) - yres /= 2; - - /* do offset calibration if needed */ - if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) - { - status = dev->model->cmd_set->offset_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: offset calibration failed: %s\n", - sane_strstatus (status)); - return status; - } - - /* since all the registers are set up correctly, just use them */ - status = dev->model->cmd_set->coarse_gain_calibration (dev, yres); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: coarse gain calibration: %s\n", - sane_strstatus (status)); - return status; - } - - } - else - /* since we have 2 gain calibration proc, skip second if first one was - used. */ - { - status = dev->model->cmd_set->init_regs_for_coarse_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to send calibration registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = genesys_coarse_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to do coarse gain calibration: %s\n", - sane_strstatus (status)); - return status; - } - - } - - if (dev->model->is_cis) - { - /* the afe now sends valid data for doing led calibration */ - status = dev->model->cmd_set->led_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: led calibration failed: %s\n", - sane_strstatus (status)); - return status; - } - - /* calibrate afe again to match new exposure */ - if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) - { - status = dev->model->cmd_set->offset_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: offset calibration failed: %s\n", - sane_strstatus (status)); - return status; - } - - /* since all the registers are set up correctly, just use them */ - - status = dev->model->cmd_set->coarse_gain_calibration (dev, yres); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: coarse gain calibration: %s\n", - sane_strstatus (status)); - return status; - } - } - else - /* since we have 2 gain calibration proc, skip second if first one was - used. */ - { - status = - dev->model->cmd_set->init_regs_for_coarse_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to send calibration registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = genesys_coarse_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to do static calibration: %s\n", - sane_strstatus (status)); - return status; - } - } - } - - /* we always use sensor pixel number when the ASIC can't handle multi-segments sensor */ - if (!(dev->model->flags & GENESYS_FLAG_SIS_SENSOR)) - { - pixels_per_line = (SANE_UNFIX (dev->model->x_size) * dev->settings.xres) / MM_PER_INCH; - } - else - { - pixels_per_line = dev->sensor.sensor_pixels; - } - - /* send default shading data */ - status = sanei_genesys_init_shading_data (dev, pixels_per_line); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to init shading process: %s\n", - sane_strstatus (status)); - return status; - } - - /* shading calibration */ - status = dev->model->cmd_set->init_regs_for_shading (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "genesys_flatbed_calibration: failed to send shading " - "registers: %s\n", sane_strstatus (status)); - return status; - } - - if (dev->model->flags & GENESYS_FLAG_DARK_WHITE_CALIBRATION) - { - status = genesys_dark_white_shading_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to do dark+white shading calibration: %s\n", - sane_strstatus (status)); - return status; - } - } - else - { - if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) - { - status = genesys_dark_shading_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to do dark shading calibration: %s\n", - sane_strstatus (status)); - return status; - } - } - - status = genesys_white_shading_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to do white shading calibration: %s\n", - sane_strstatus (status)); - return status; - } - } - - if(dev->model->cmd_set->send_shading_data==NULL) - { - status = genesys_send_shading_coefficient (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_flatbed_calibration: failed to send shading calibration coefficients: %s\n", - sane_strstatus (status)); - return status; - } - } - - DBG (DBG_info, "genesys_flatbed_calibration: completed\n"); - - return SANE_STATUS_GOOD; -} - -/** - * Does the calibration process for a sheetfed scanner - * - offset calibration - * - gain calibration - * - shading calibration - * During calibration a predefined calibration sheet with specific black and white - * areas is used. - * @param dev device to calibrate - * @return SANE_STATUS_GOOD if everything when all right, else the error code. - */ -static SANE_Status -genesys_sheetfed_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool forward = SANE_TRUE; - int xres; - - DBGSTART; - if (dev->model->cmd_set->search_strip == NULL) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: no strip searching function available\n"); - return SANE_STATUS_UNSUPPORTED; - } - - /* first step, load document */ - status = dev->model->cmd_set->load_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to load document: %s\n", - sane_strstatus (status)); - return status; - } - - - DBG (DBG_info, "genesys_sheetfed_calibration\n"); - - /* led, offset and gain calibration are influenced by scan - * settings. So we set it to sensor resolution */ - xres = dev->sensor.optical_res; - dev->settings.xres = dev->sensor.optical_res; - /* XP200 needs to calibrate a full and half sensor's resolution */ - if (dev->model->ccd_type == CIS_XP200 - && dev->settings.xres <= dev->sensor.optical_res / 2) - dev->settings.xres /= 2; - - /* the afe needs to sends valid data even before calibration */ - - /* go to a white area */ - status = dev->model->cmd_set->search_strip (dev, forward, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to find white strip: %s\n", - sane_strstatus (status)); - dev->model->cmd_set->eject_document (dev); - return status; - } - - if (dev->model->is_cis) - { - status = dev->model->cmd_set->led_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: led calibration failed: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* calibrate afe */ - if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) - { - status = dev->model->cmd_set->offset_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: offset calibration failed: %s\n", - sane_strstatus (status)); - return status; - } - - /* since all the registers are set up correctly, just use them */ - - status = dev->model->cmd_set->coarse_gain_calibration (dev, xres); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: coarse gain calibration: %s\n", - sane_strstatus (status)); - return status; - } - } - else - /* since we have 2 gain calibration proc, skip second if first one was - used. */ - { - status = - dev->model->cmd_set->init_regs_for_coarse_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to send calibration registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = genesys_coarse_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to do static calibration: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* search for a full width black strip and then do a 16 bit scan to - * gather black shading data */ - if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) - { - /* seek black/white reverse/forward */ - status = dev->model->cmd_set->search_strip (dev, forward, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to find black strip: %s\n", - sane_strstatus (status)); - dev->model->cmd_set->eject_document (dev); - return status; - } - - status = dev->model->cmd_set->init_regs_for_shading (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to do set up registers for shading calibration: %s\n", - sane_strstatus (status)); - return status; - } - status = genesys_dark_shading_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - dev->model->cmd_set->eject_document (dev); - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to do dark shading calibration: %s\n", - sane_strstatus (status)); - return status; - } - forward = SANE_FALSE; - } - - - /* go to a white area */ - status = dev->model->cmd_set->search_strip (dev, forward, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to find white strip: %s\n", - sane_strstatus (status)); - dev->model->cmd_set->eject_document (dev); - return status; - } - - status = dev->model->cmd_set->init_regs_for_shading (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to do set up registers for shading calibration: %s\n", - sane_strstatus (status)); - return status; - } - status = genesys_white_shading_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - dev->model->cmd_set->eject_document (dev); - DBG (DBG_error, "%s: failed eject target: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* in case we haven't black shading data, build it from black pixels - * of white calibration */ - if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) - { - FREE_IFNOT_NULL (dev->dark_average_data); - dev->dark_average_data = malloc (dev->average_size); - memset (dev->dark_average_data, 0x0f, dev->average_size); - /* XXX STEF XXX - * with black point in white shading, build an average black - * pixel and use it to fill the dark_average - * dev->calib_pixels - (dev->sensor.sensor_pixels * dev->settings.xres) / dev->sensor.optical_res, - dev->calib_lines, - */ - } - - /* send the shading coefficient when doing whole line shading - * but not when using SHDAREA like GL124 */ - if(dev->model->cmd_set->send_shading_data==NULL) - { - status = genesys_send_shading_coefficient (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to send shading calibration coefficients: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* save the calibration data */ - genesys_save_calibration (dev); - - /* and finally eject calibration sheet */ - status = dev->model->cmd_set->eject_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_sheetfed_calibration: failed to eject document: %s\n", - sane_strstatus (status)); - return status; - } - - /* resotre settings */ - dev->settings.xres = xres; - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * does the calibration process for a device - * @param dev device to calibrate - */ -static SANE_Status -genesys_scanner_calibration (Genesys_Device * dev) -{ - if (dev->model->is_sheetfed == SANE_FALSE) - { - return genesys_flatbed_calibration (dev); - } - return genesys_sheetfed_calibration (dev); -} - -/* unused function kept in case it may be usefull in the futur */ -#if 0 -static SANE_Status -genesys_wait_not_moving (Genesys_Device * dev, int mseconds) -{ - uint8_t value; - SANE_Status status; - - DBG (DBG_proc, - "genesys_wait_not_moving: waiting %d mseconds for motor to stop\n", - mseconds); - while (mseconds > 0) - { - RIE (sanei_genesys_get_status (dev, &value)); - - if (dev->model->cmd_set->test_motor_flag_bit (value)) - { - usleep (100 * 1000); - mseconds -= 100; - DBG (DBG_io, - "genesys_wait_not_moving: motor is moving, %d mseconds to go\n", - mseconds); - } - else - { - DBG (DBG_info, - "genesys_wait_not_moving: motor is not moving, exiting\n"); - return SANE_STATUS_GOOD; - } - - } - DBG (DBG_error, - "genesys_wait_not_moving: motor is still moving, timeout exceeded\n"); - return SANE_STATUS_DEVICE_BUSY; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* High level (exported) functions */ -/* ------------------------------------------------------------------------ */ - -/* - * wait lamp to be warm enough by scanning the same line until - * differences between two scans are below a threshold - */ -static SANE_Status -genesys_warmup_lamp (Genesys_Device * dev) -{ - uint8_t *first_line, *second_line; - int seconds = 0; - int pixel; - int channels, total_size; - double first_average = 0; - double second_average = 0; - int difference = 255; - int empty, lines = 3; - SANE_Status status = SANE_STATUS_IO_ERROR; - - DBGSTART; - - /* check if the current chipset implements warmup */ - if(dev->model->cmd_set->init_regs_for_warmup==NULL) - { - DBG (DBG_error, "%s: init_regs_for_warmup not implemented\n", __func__); - return status; - } - - dev->model->cmd_set->init_regs_for_warmup (dev, dev->reg, &channels, &total_size); - first_line = malloc (total_size); - if (!first_line) - return SANE_STATUS_NO_MEM; - - second_line = malloc (total_size); - if (!second_line) - { - free(first_line); - DBGCOMPLETED; - return SANE_STATUS_NO_MEM; - } - - do - { - DBG (DBG_info, "genesys_warmup_lamp: one more loop\n"); - RIEF2 (dev->model->cmd_set->begin_scan (dev, dev->reg, SANE_FALSE), first_line, second_line); - do - { - sanei_genesys_test_buffer_empty (dev, &empty); - } - while (empty); - - status = sanei_genesys_read_data_from_scanner (dev, first_line, total_size); - if (status != SANE_STATUS_GOOD) - { - RIEF2 (sanei_genesys_read_data_from_scanner - (dev, first_line, total_size), first_line, second_line); - } - - RIEF2 (dev->model->cmd_set->end_scan (dev, dev->reg, SANE_TRUE), first_line, second_line); - - sleep (1); /* sleep 1 s */ - seconds++; - - RIEF2 (dev->model->cmd_set->begin_scan (dev, dev->reg, SANE_FALSE), first_line, second_line); - do - { - sanei_genesys_test_buffer_empty (dev, &empty); - usleep (100 * 1000); - } - while (empty); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); - RIEF2 (dev->model->cmd_set->end_scan (dev, dev->reg, SANE_TRUE), first_line, second_line); - - /* compute difference between the two scans */ - for (pixel = 0; pixel < total_size; pixel++) - { - /* 16 bit data */ - if (dev->model->cmd_set->get_bitset_bit (dev->reg)) - { - first_average += (first_line[pixel] + first_line[pixel + 1] * 256); - second_average += (second_line[pixel] + second_line[pixel + 1] * 256); - pixel++; - } - else - { - first_average += first_line[pixel]; - second_average += second_line[pixel]; - } - } - if (dev->model->cmd_set->get_bitset_bit (dev->reg)) - { - first_average /= pixel; - second_average /= pixel; - difference = fabs (first_average - second_average); - DBG (DBG_info, - "genesys_warmup_lamp: average = %.2f, diff = %.3f\n", - 100 * ((second_average) / (256 * 256)), - 100 * (difference / second_average)); - - if (second_average > (100 * 256) - && (difference / second_average) < 0.002) - break; - } - else - { - first_average /= pixel; - second_average /= pixel; - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file ("warmup1.pnm", first_line, 8, - channels, - total_size / (lines * channels), - lines); - sanei_genesys_write_pnm_file ("warmup2.pnm", second_line, 8, - channels, - total_size / (lines * channels), - lines); - } - DBG (DBG_info, "genesys_warmup_lamp: average 1 = %.2f, average 2 = %.2f\n", first_average, second_average); - /* if delta below 15/255 ~= 5.8%, lamp is considred warm enough */ - if (fabs (first_average - second_average) < 15 - && second_average > 55) - break; - } - - /* sleep another second before next loop */ - sleep (1); - seconds++; - } - while (seconds < WARMUP_TIME); - - if (seconds >= WARMUP_TIME) - { - DBG (DBG_error, - "genesys_warmup_lamp: warmup timed out after %d seconds. Lamp defective?\n", - seconds); - status = SANE_STATUS_IO_ERROR; - } - else - { - DBG (DBG_info, - "genesys_warmup_lamp: warmup succeeded after %d seconds\n", - seconds); - } - - free (first_line); - free (second_line); - - DBGCOMPLETED; - - return status; -} - - -/* High-level start of scanning */ -static SANE_Status -genesys_start_scan (Genesys_Device * dev, SANE_Bool lamp_off) -{ - SANE_Status status; - unsigned int steps, expected; - SANE_Bool empty; - - DBGSTART; - - /* since not all scanners are set ot wait for head to park - * we check we are not still parking before starting a new scan */ - if (dev->parking == SANE_TRUE) - { - status = sanei_genesys_wait_for_home (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to wait for head to park: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* disable power saving*/ - status = dev->model->cmd_set->save_power (dev, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to disable power saving mode: %s\n", - sane_strstatus (status)); - return status; - } - - /* wait for lamp warmup : until a warmup for TRANSPARENCY is designed, skip - * it when scanning from XPA. */ - if (!(dev->model->flags & GENESYS_FLAG_SKIP_WARMUP) - && (dev->settings.scan_method == SCAN_METHOD_FLATBED)) - { - RIE (genesys_warmup_lamp (dev)); - } - - /* set top left x and y values by scanning the internals if flatbed scanners */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - /* do the geometry detection only once */ - if ((dev->model->flags & GENESYS_FLAG_SEARCH_START) - && (dev->model->y_offset_calib == 0)) - { - status = dev->model->cmd_set->search_start_position (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to search start position: %s\n", - sane_strstatus (status)); - return status; - } - - dev->parking = SANE_FALSE; - status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to move scanhead to " - "home position: %s\n", sane_strstatus (status)); - return status; - } - dev->scanhead_position_in_steps = 0; - } - else - { - /* Go home */ - /* TODO: check we can drop this since we cannot have the - scanner's head wandering here */ - dev->parking = SANE_FALSE; - status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to move scanhead to " - "home position: %s\n", sane_strstatus (status)); - return status; - } - dev->scanhead_position_in_steps = 0; - } - } - - /* move to calibration area for transparency adapter */ - if ((dev->settings.scan_method == SCAN_METHOD_TRANSPARENCY) - && dev->model->cmd_set->move_to_ta != NULL) - { - status=dev->model->cmd_set->move_to_ta(dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to move to start of transparency adapter: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* load document if needed (for sheetfed scanner for instance) */ - if (dev->model->is_sheetfed == SANE_TRUE - && dev->model->cmd_set->load_document != NULL) - { - status = dev->model->cmd_set->load_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to load document: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* send gamma tables. They have been set to device or user value - * when setting option value */ - status = dev->model->cmd_set->send_gamma_table (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to init gamma table: %s\n", - sane_strstatus (status)); - return status; - } - - /* try to use cached calibration first */ - status = genesys_restore_calibration (dev); - if (status == SANE_STATUS_UNSUPPORTED) - { - /* calibration : sheetfed scanners can't calibrate before each scan */ - /* and also those who have the NO_CALIBRATION flag */ - if (!(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) - &&dev->model->is_sheetfed == SANE_FALSE) - { - status = genesys_scanner_calibration (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to do scanner calibration: %s\n", - sane_strstatus (status)); - return status; - } - - genesys_save_calibration (dev); - } - else - { - DBG (DBG_warn, "genesys_start_scan: no calibration done\n"); - } - } - else if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to restore calibration: %s\n", - sane_strstatus (status)); - return status; - } - - /* build look up table for dynamic lineart */ - if(dev->settings.dynamic_lineart==SANE_TRUE) - { - status = sanei_genesys_load_lut(dev->lineart_lut, 8, 8, 50, 205, - dev->settings.threshold_curve, - dev->settings.threshold-127); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "genesys_start_scan: failed to build lut\n"); - return status; - } - } - - status = dev->model->cmd_set->init_regs_for_scan (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to do init registers for scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* no lamp during scan */ - if(lamp_off == SANE_TRUE) - { - dev->model->cmd_set->set_lamp_power (dev, dev->reg, SANE_FALSE); - } - - /* GL124 is using SHDAREA, so we have to wait for scan to be set up before - * sending shading data */ - if( (dev->model->cmd_set->send_shading_data!=NULL) - && !(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - status = genesys_send_shading_coefficient (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to send shading calibration coefficients: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* now send registers for scan */ - status = - dev->model->cmd_set->bulk_write_register (dev, dev->reg, - dev->model-> - cmd_set->bulk_full_size ()); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to bulk write registers, status = %d\n", - status); - return status; - } - - /* start effective scan */ - status = dev->model->cmd_set->begin_scan (dev, dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to begin scan: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - /*do we really need this? the valid data check should be sufficent -- pierre*/ - /* waits for head to reach scanning position */ - expected = sanei_genesys_read_reg_from_set (dev->reg, 0x3d) * 65536 - + sanei_genesys_read_reg_from_set (dev->reg, 0x3e) * 256 - + sanei_genesys_read_reg_from_set (dev->reg, 0x3f); - do - { - /* wait 1/10th of second between each test to avoid - overloading USB and CPU */ - usleep (100 * 1000); - status = sanei_genesys_read_feed_steps (dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: Failed to read feed steps: %s\n", - sane_strstatus (status)); - return status; - } - } - while (steps < expected); - - /* wait for buffers to be filled */ - do - { - RIE (sanei_genesys_test_buffer_empty (dev, &empty)); - } - while (empty); - - /* when doing one or two-table movement, let the motor settle to scanning speed */ - /* and scanning start before reading data */ -/* the valid data check already waits until the scanner delivers data. this here leads to unnecessary buffer full conditions in the scanner. - if (dev->model->cmd_set->get_fast_feed_bit (dev->reg)) - usleep (1000 * 1000); - else - usleep (500 * 1000); -*/ - /* then we wait for at least one word of valid scan data - - this is also done in sanei_genesys_read_data_from_scanner -- pierre */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - do - { - usleep (100 * 1000); - status = sanei_genesys_read_valid_words (dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_start_scan: failed to read valid words: %s\n", - sane_strstatus (status)); - return status; - } - } - while (steps < 1); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* this is _not_ a ringbuffer. - if we need a block which does not fit at the end of our available data, - we move the available data to the beginning. - */ - -SANE_Status -sanei_genesys_buffer_alloc (Genesys_Buffer * buf, size_t size) -{ - buf->buffer = (SANE_Byte *) malloc (size); - if (!buf->buffer) - return SANE_STATUS_NO_MEM; - buf->avail = 0; - buf->pos = 0; - buf->size = size; - return SANE_STATUS_GOOD; -} - -SANE_Status -sanei_genesys_buffer_free (Genesys_Buffer * buf) -{ - SANE_Byte *tmp = buf->buffer; - buf->avail = 0; - buf->size = 0; - buf->pos = 0; - buf->buffer = NULL; - if (tmp) - free (tmp); - return SANE_STATUS_GOOD; -} - -SANE_Byte * -sanei_genesys_buffer_get_write_pos (Genesys_Buffer * buf, size_t size) -{ - if (buf->avail + size > buf->size) - return NULL; - if (buf->pos + buf->avail + size > buf->size) - { - memmove (buf->buffer, buf->buffer + buf->pos, buf->avail); - buf->pos = 0; - } - return buf->buffer + buf->pos + buf->avail; -} - -SANE_Byte * -sanei_genesys_buffer_get_read_pos (Genesys_Buffer * buf) -{ - return buf->buffer + buf->pos; -} - -SANE_Status -sanei_genesys_buffer_produce (Genesys_Buffer * buf, size_t size) -{ - if (size > buf->size - buf->avail) - return SANE_STATUS_INVAL; - buf->avail += size; - return SANE_STATUS_GOOD; -} - -SANE_Status -sanei_genesys_buffer_consume (Genesys_Buffer * buf, size_t size) -{ - if (size > buf->avail) - return SANE_STATUS_INVAL; - buf->avail -= size; - buf->pos += size; - return SANE_STATUS_GOOD; -} - - -#include "genesys_conv.c" - -static SANE_Status accurate_line_read(Genesys_Device * dev, - SANE_Byte *buffer, - size_t size) -{ - SANE_Status status; - status = dev->model->cmd_set->bulk_read_data (dev, 0x45, buffer, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "accurate_line_read: failed to read %lu bytes (%s)\n", - (u_long) size, sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - /* done reading */ - dev->oe_buffer.avail = size; - dev->oe_buffer.pos = 0; - return status; -} - -/** @brief fill buffer while reducing vertical resolution - * This function fills a read buffer with scanned data from a sensor - * which puts odd and even pixels in 2 different data segment. So a complete - * must be read and bytes interleaved to get usable by the other stages - * of the backend - */ -static SANE_Status -genesys_fill_line_interp_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, size_t size) -{ - size_t count; - SANE_Status status; - - /* fill buffer if needed */ - if (dev->oe_buffer.avail == 0) - { - status = accurate_line_read(dev,dev->oe_buffer.buffer,dev->oe_buffer.size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read %lu bytes (%s)\n", __func__, - (u_long) dev->oe_buffer.size, sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - } - - /* copy size bytes of data, copying from a line when line count matches */ - count = 0; - while (count < size) - { - /* line counter */ - /* dev->line_interp holds the number of lines scanned for one line of data sent */ - if(((dev->line_count/dev->current_setup.channels) % dev->line_interp)==0) - { - /* copy pixel when line matches */ - work_buffer_dst[count] = dev->oe_buffer.buffer[dev->cur + dev->oe_buffer.pos]; - count++; - } - - /* always update pointer so we skip uncopied data */ - dev->cur++; - - /* go to next line if needed */ - if (dev->cur == dev->len) - { - dev->oe_buffer.pos += dev->bpl; - dev->cur = 0; - dev->line_count++; - } - - /* read a new buffer if needed */ - if (dev->oe_buffer.pos >= dev->oe_buffer.avail) - { - status = accurate_line_read(dev,dev->oe_buffer.buffer,dev->oe_buffer.size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read %lu bytes (%s)\n", __func__, - (u_long) dev->oe_buffer.size, sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - } - } - - return SANE_STATUS_GOOD; -} - -/** @brief fill buffer for segmented sensors - * This function fills a read buffer with scanned data from a sensor segmented - * in several parts (multi-lines sensors). Data of the same valid area is read - * back to back and must be interleaved to get usable by the other stages - * of the backend - */ -static SANE_Status -genesys_fill_segmented_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, size_t size) -{ - size_t count; - SANE_Status status; - int depth,i,n,k; - - depth = dev->settings.depth; - if (dev->settings.scan_mode == SCAN_MODE_LINEART && dev->settings.dynamic_lineart==SANE_FALSE) - depth = 1; - - /* fill buffer if needed */ - if (dev->oe_buffer.avail == 0) - { - status = accurate_line_read(dev,dev->oe_buffer.buffer,dev->oe_buffer.size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read %lu bytes (%s)\n", __func__, - (u_long) dev->oe_buffer.size, sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - } - - /* copy size bytes of data, copying from a subwindow of each line - * when last line of buffer is exhausted, read another one */ - count = 0; - while (count < size) - { - if(dev->settings.double_xres==SANE_TRUE) - { - /* copy only even pixel */ - work_buffer_dst[count] = dev->oe_buffer.buffer[dev->cur + dev->oe_buffer.pos]; - /* update counter and pointer */ - count++; - dev->cur++; - } - else - { - if(depth==1) - { - while (dev->cur < dev->len && count < size) - { - for(n=0;nsegnb;n++) - { - work_buffer_dst[count+n] = 0; - } - /* interleaving is at bit level */ - for(i=0;i<8;i++) - { - k=count+(i*dev->segnb)/8; - for(n=0;nsegnb;n++) - { - work_buffer_dst[k] = work_buffer_dst[k] << 1; - if((dev->oe_buffer.buffer[dev->cur + dev->skip + dev->dist*dev->order[n] + dev->oe_buffer.pos])&(128>>i)) - { - work_buffer_dst[k] |= 1; - } - } - } - - /* update counter and pointer */ - count += dev->segnb; - dev->cur++; - } - } - if(depth==8) - { - while (dev->cur < dev->len && count < size) - { - for(n=0;nsegnb;n++) - { - work_buffer_dst[count+n] = dev->oe_buffer.buffer[dev->cur + dev->skip + dev->dist*dev->order[n] + dev->oe_buffer.pos]; - } - /* update counter and pointer */ - count += dev->segnb; - dev->cur++; - } - } - if(depth==16) - { - while (dev->cur < dev->len && count < size) - { - for(n=0;nsegnb;n++) - { - work_buffer_dst[count+n*2] = dev->oe_buffer.buffer[dev->cur + dev->skip + dev->dist*dev->order[n] + dev->oe_buffer.pos]; - work_buffer_dst[count+n*2+1] = dev->oe_buffer.buffer[dev->cur + dev->skip + dev->dist*dev->order[n] + dev->oe_buffer.pos+1]; - } - /* update counter and pointer */ - count += dev->segnb*2; - dev->cur+=2; - } - } - } - - /* go to next line if needed */ - if (dev->cur == dev->len) - { - dev->oe_buffer.pos += dev->bpl; - dev->cur = 0; - } - - /* read a new buffer if needed */ - if (dev->oe_buffer.pos >= dev->oe_buffer.avail) - { - status = accurate_line_read(dev,dev->oe_buffer.buffer,dev->oe_buffer.size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read %lu bytes (%s)\n", __func__, - (u_long) dev->oe_buffer.size, sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - } - } - - return SANE_STATUS_GOOD; -} - -/** - * - */ -static SANE_Status -genesys_fill_read_buffer (Genesys_Device * dev) -{ - size_t size; - size_t space; - SANE_Status status; - uint8_t *work_buffer_dst; - - DBGSTART; - - /* for sheetfed scanner, we must check is document is shorter than - * the requested scan */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = dev->model->cmd_set->detect_document_end (dev); - if (status != SANE_STATUS_GOOD) - return status; - } - - space = dev->read_buffer.size - dev->read_buffer.avail; - - work_buffer_dst = sanei_genesys_buffer_get_write_pos (&(dev->read_buffer), - space); - - size = space; - - /* never read an odd number. exception: last read - the chip internal counter does not count half words. */ - size &= ~1; - /* Some setups need the reads to be multiples of 256 bytes */ - size &= ~0xff; - - if (dev->read_bytes_left < size) - { - size = dev->read_bytes_left; - /*round up to a multiple of 256 bytes */ - size += (size & 0xff) ? 0x100 : 0x00; - size &= ~0xff; - } - - /* early out if our remaining buffer capacity is too low */ - if (size == 0) - return SANE_STATUS_GOOD; - - DBG (DBG_io, "genesys_fill_read_buffer: reading %lu bytes\n", - (u_long) size); - - /* size is already maxed to our needs. for most models bulk_read_data - will read as much data as requested. */ - - /* due to sensors and motors, not all data can be directly used. It - * may have to be read from another intermediate buffer and then processed. - * There are currently 3 intermediate stages: - * - handling of odd/even sensors - * - handling of line interpolation for motors that can't have low - * enough dpi - * - handling of multi-segments sensors - * - * This is also the place where full duplex data will be handled. - */ - if (dev->line_interp>0) - { - /* line interpolation */ - status = genesys_fill_line_interp_buffer (dev, work_buffer_dst, size); - } - else if (dev->segnb>1) - { - /* multi-segment sensors processing */ - status = genesys_fill_segmented_buffer (dev, work_buffer_dst, size); - } - else /* regular case with no extra copy */ - { - status = dev->model->cmd_set->bulk_read_data (dev, 0x45, work_buffer_dst, size); - } - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_fill_read_buffer: failed to read %lu bytes (%s)\n", - (u_long) size, sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - if (size > dev->read_bytes_left) - size = dev->read_bytes_left; - - dev->read_bytes_left -= size; - - RIE (sanei_genesys_buffer_produce (&(dev->read_buffer), size)); - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/* this function does the effective data read in a manner that suits - the scanner. It does data reordering and resizing if need. - It also manages EOF and I/O errors, and line distance correction. - */ -static SANE_Status -genesys_read_ordered_data (Genesys_Device * dev, SANE_Byte * destination, - size_t * len) -{ - SANE_Status status; - size_t bytes, extra; - unsigned int channels, depth, src_pixels; - unsigned int ccd_shift[12], shift_count; - uint8_t *work_buffer_src; - uint8_t *work_buffer_dst; - unsigned int dst_lines; - unsigned int step_1_mode; - unsigned int needs_reorder; - unsigned int needs_ccd; - unsigned int needs_shrink; - unsigned int needs_reverse; - Genesys_Buffer *src_buffer; - Genesys_Buffer *dst_buffer; - - DBGSTART; - if (dev->read_active != SANE_TRUE) - { - DBG (DBG_error, "genesys_read_ordered_data: read not active!\n"); - *len = 0; - return SANE_STATUS_INVAL; - } - - - DBG (DBG_info, "genesys_read_ordered_data: dumping current_setup:\n" - "\tpixels: %d\n" - "\tlines: %d\n" - "\tdepth: %d\n" - "\tchannels: %d\n" - "\texposure_time: %d\n" - "\txres: %g\n" - "\tyres: %g\n" - "\thalf_ccd: %s\n" - "\tstagger: %d\n" - "\tmax_shift: %d\n", - dev->current_setup.pixels, - dev->current_setup.lines, - dev->current_setup.depth, - dev->current_setup.channels, - dev->current_setup.exposure_time, - dev->current_setup.xres, - dev->current_setup.yres, - dev->current_setup.half_ccd ? "yes" : "no", - dev->current_setup.stagger, dev->current_setup.max_shift); - - /* prepare conversion */ - /* current settings */ - channels = dev->current_setup.channels; - depth = dev->current_setup.depth; - - src_pixels = dev->current_setup.pixels; - - needs_reorder = 1; - if (channels != 3 && depth != 16) - needs_reorder = 0; -#ifndef WORDS_BIGENDIAN - if (channels != 3 && depth == 16) - needs_reorder = 0; - if (channels == 3 && depth == 16 && !dev->model->is_cis && - dev->model->line_mode_color_order == COLOR_ORDER_RGB) - needs_reorder = 0; -#endif - if (channels == 3 && depth == 8 && !dev->model->is_cis && - dev->model->line_mode_color_order == COLOR_ORDER_RGB) - needs_reorder = 0; - - needs_ccd = dev->current_setup.max_shift > 0; - needs_shrink = dev->settings.pixels != src_pixels; - needs_reverse = depth == 1; - - DBG (DBG_info, - "genesys_read_ordered_data: using filters:%s%s%s%s\n", - needs_reorder ? " reorder" : "", - needs_ccd ? " ccd" : "", - needs_shrink ? " shrink" : "", - needs_reverse ? " reverse" : ""); - - DBG (DBG_info, - "genesys_read_ordered_data: frontend requested %lu bytes\n", - (u_long) * len); - - DBG (DBG_info, - "genesys_read_ordered_data: bytes_to_read=%lu, total_bytes_read=%lu\n", - (u_long) dev->total_bytes_to_read, (u_long) dev->total_bytes_read); - /* is there data left to scan */ - if (dev->total_bytes_read >= dev->total_bytes_to_read) - { - DBG (DBG_proc, - "genesys_read_ordered_data: nothing more to scan: EOF\n"); - *len = 0; - - /* issue park command immediatly in case scanner can handle it - * so we save time */ - if (dev->model->is_sheetfed == SANE_FALSE - && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) - && dev->parking == SANE_FALSE) - { - dev->model->cmd_set->slow_back_home (dev, SANE_FALSE); - dev->parking = SANE_TRUE; - } - return SANE_STATUS_EOF; - } - - DBG (DBG_info, "genesys_read_ordered_data: %lu lines left by output\n", - ((dev->total_bytes_to_read - dev->total_bytes_read) * 8UL) / - (dev->settings.pixels * channels * depth)); - DBG (DBG_info, "genesys_read_ordered_data: %lu lines left by input\n", - ((dev->read_bytes_left + dev->read_buffer.avail) * 8UL) / - (src_pixels * channels * depth)); - - if (channels == 1) - { - ccd_shift[0] = 0; - ccd_shift[1] = dev->current_setup.stagger; - shift_count = 2; - } - else - { - ccd_shift[0] = - ((dev->ld_shift_r * dev->settings.yres) / - dev->motor.base_ydpi); - ccd_shift[1] = - ((dev->ld_shift_g * dev->settings.yres) / - dev->motor.base_ydpi); - ccd_shift[2] = - ((dev->ld_shift_b * dev->settings.yres) / - dev->motor.base_ydpi); - - ccd_shift[3] = ccd_shift[0] + dev->current_setup.stagger; - ccd_shift[4] = ccd_shift[1] + dev->current_setup.stagger; - ccd_shift[5] = ccd_shift[2] + dev->current_setup.stagger; - - shift_count = 6; - } - - -/* convert data */ -/* - 0. fill_read_buffer --------------- read_buffer ---------------------- - 1a). (opt)uncis (assumes color components to be laid out - planar) - 1b). (opt)reverse_RGB (assumes pixels to be BGR or BBGGRR)) --------------- lines_buffer ---------------------- - 2a). (opt)line_distance_correction (assumes RGB or RRGGBB) - 2b). (opt)unstagger (assumes pixels to be depth*channels/8 - bytes long, unshrinked) -------------- shrink_buffer --------------------- - 3. (opt)shrink_lines (assumes component separation in pixels) --------------- out_buffer ----------------------- - 4. memcpy to destination (for lineart with bit reversal) -*/ -/*FIXME: for lineart we need sub byte addressing in buffers, or conversion to - bytes at 0. and back to bits at 4. -Problems with the first approach: - - its not clear how to check if we need to output an incomplete byte - because it is the last one. - */ -/*FIXME: add lineart support for gl646. in the meantime add logic to convert - from gray to lineart at the end? would suffer the above problem, - total_bytes_to_read and total_bytes_read help in that case. - */ - - status = genesys_fill_read_buffer (dev); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_read_ordered_data: genesys_fill_read_buffer failed\n"); - return status; - } - - src_buffer = &(dev->read_buffer); - -/* maybe reorder components/bytes */ - if (needs_reorder) - { -/*not implemented for depth == 1.*/ - if (depth == 1) - { - DBG (DBG_error, "Can't reorder single bit data\n"); - return SANE_STATUS_INVAL; - } - - dst_buffer = &(dev->lines_buffer); - - work_buffer_src = sanei_genesys_buffer_get_read_pos (src_buffer); - bytes = src_buffer->avail; - -/*how many bytes can be processed here?*/ -/*we are greedy. we work as much as possible*/ - if (bytes > dst_buffer->size - dst_buffer->avail) - bytes = dst_buffer->size - dst_buffer->avail; - - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - bytes = (dst_lines * src_pixels * channels * depth) / 8; - - work_buffer_dst = sanei_genesys_buffer_get_write_pos (dst_buffer, - bytes); - - DBG (DBG_info, "genesys_read_ordered_data: reordering %d lines\n", - dst_lines); - - if (dst_lines != 0) - { - - if (channels == 3) - { - step_1_mode = 0; - - if (depth == 16) - step_1_mode |= 1; - - if (dev->model->is_cis) - step_1_mode |= 2; - - if (dev->model->line_mode_color_order == COLOR_ORDER_BGR) - step_1_mode |= 4; - - switch (step_1_mode) - { - case 1: /* RGB, chunky, 16 bit */ -#ifdef WORDS_BIGENDIAN - status = - genesys_reorder_components_endian_16 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, 3); - break; -#endif /*WORDS_BIGENDIAN */ - case 0: /* RGB, chunky, 8 bit */ - status = SANE_STATUS_GOOD; - break; - case 2: /* RGB, cis, 8 bit */ - status = - genesys_reorder_components_cis_8 (work_buffer_src, - work_buffer_dst, - dst_lines, src_pixels); - break; - case 3: /* RGB, cis, 16 bit */ - status = - genesys_reorder_components_cis_16 (work_buffer_src, - work_buffer_dst, - dst_lines, src_pixels); - break; - case 4: /* BGR, chunky, 8 bit */ - status = - genesys_reorder_components_bgr_8 (work_buffer_src, - work_buffer_dst, - dst_lines, src_pixels); - break; - case 5: /* BGR, chunky, 16 bit */ - status = - genesys_reorder_components_bgr_16 (work_buffer_src, - work_buffer_dst, - dst_lines, src_pixels); - break; - case 6: /* BGR, cis, 8 bit */ - status = - genesys_reorder_components_cis_bgr_8 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels); - break; - case 7: /* BGR, cis, 16 bit */ - status = - genesys_reorder_components_cis_bgr_16 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels); - break; - } - } - else - { -#ifdef WORDS_BIGENDIAN - if (depth == 16) - { - status = - genesys_reorder_components_endian_16 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, 1); - } - else - { - status = SANE_STATUS_GOOD; - } -#else /*!WORDS_BIGENDIAN */ - status = SANE_STATUS_GOOD; -#endif /*WORDS_BIGENDIAN */ - } - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_read_ordered_data: failed to convert byte ordering(%s)\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - RIE (sanei_genesys_buffer_produce (dst_buffer, bytes)); - - RIE (sanei_genesys_buffer_consume (src_buffer, bytes)); - } - src_buffer = dst_buffer; - } - -/* maybe reverse effects of ccd layout */ - if (needs_ccd) - { -/*should not happen with depth == 1.*/ - if (depth == 1) - { - DBG (DBG_error, "Can't reverse ccd for single bit data\n"); - return SANE_STATUS_INVAL; - } - - dst_buffer = &(dev->shrink_buffer); - - work_buffer_src = sanei_genesys_buffer_get_read_pos (src_buffer); - bytes = src_buffer->avail; - - extra = - (dev->current_setup.max_shift * src_pixels * channels * depth) / 8; - -/*extra bytes are reserved, and should not be consumed*/ - if (bytes < extra) - bytes = 0; - else - bytes -= extra; - -/*how many bytes can be processed here?*/ -/*we are greedy. we work as much as possible*/ - if (bytes > dst_buffer->size - dst_buffer->avail) - bytes = dst_buffer->size - dst_buffer->avail; - - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - bytes = (dst_lines * src_pixels * channels * depth) / 8; - - work_buffer_dst = - sanei_genesys_buffer_get_write_pos (dst_buffer, bytes); - - DBG (DBG_info, "genesys_read_ordered_data: un-ccd-ing %d lines\n", - dst_lines); - - if (dst_lines != 0) - { - - if (depth == 8) - status = genesys_reverse_ccd_8 (work_buffer_src, work_buffer_dst, - dst_lines, - src_pixels * channels, - ccd_shift, shift_count); - else - status = genesys_reverse_ccd_16 (work_buffer_src, work_buffer_dst, - dst_lines, - src_pixels * channels, - ccd_shift, shift_count); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_read_ordered_data: failed to reverse ccd effects(%s)\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - RIE (sanei_genesys_buffer_produce (dst_buffer, bytes)); - - RIE (sanei_genesys_buffer_consume (src_buffer, bytes)); - } - src_buffer = dst_buffer; - } - -/* maybe shrink(or enlarge) lines */ - if (needs_shrink) - { - - dst_buffer = &(dev->out_buffer); - - work_buffer_src = sanei_genesys_buffer_get_read_pos (src_buffer); - bytes = src_buffer->avail; - -/*lines in input*/ - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - - /* how many lines can be processed here? */ - /* we are greedy. we work as much as possible */ - bytes = dst_buffer->size - dst_buffer->avail; - - if (dst_lines > (bytes * 8) / (dev->settings.pixels * channels * depth)) - dst_lines = (bytes * 8) / (dev->settings.pixels * channels * depth); - - bytes = (dst_lines * dev->settings.pixels * channels * depth) / 8; - - work_buffer_dst = - sanei_genesys_buffer_get_write_pos (dst_buffer, bytes); - - DBG (DBG_info, "genesys_read_ordered_data: shrinking %d lines\n", - dst_lines); - - if (dst_lines != 0) - { - if (depth == 1) - status = genesys_shrink_lines_1 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, - dev->settings.pixels, - channels); - else if (depth == 8) - status = genesys_shrink_lines_8 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, - dev->settings.pixels, channels); - else - status = genesys_shrink_lines_16 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, - dev->settings.pixels, channels); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_read_ordered_data: failed to shrink lines(%s)\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - /* we just consumed this many bytes*/ - bytes = (dst_lines * src_pixels * channels * depth) / 8; - RIE (sanei_genesys_buffer_consume (src_buffer, bytes)); - - /* we just created this many bytes*/ - bytes = (dst_lines * dev->settings.pixels * channels * depth) / 8; - RIE (sanei_genesys_buffer_produce (dst_buffer, bytes)); - - } - src_buffer = dst_buffer; - } - - /* move data to destination */ - bytes = src_buffer->avail; - if (bytes > *len) - bytes = *len; - work_buffer_src = sanei_genesys_buffer_get_read_pos (src_buffer); - - if (needs_reverse) - { - status = genesys_reverse_bits (work_buffer_src, destination, bytes); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_read_ordered_data: failed to reverse bits(%s)\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - *len = bytes; - } - else - { - memcpy (destination, work_buffer_src, bytes); - *len = bytes; - } - - /* avoid signaling some extra data because we have treated a full block - * on the last block */ - if (dev->total_bytes_read + *len > dev->total_bytes_to_read) - *len = dev->total_bytes_to_read - dev->total_bytes_read; - - /* count bytes sent to frontend */ - dev->total_bytes_read += *len; - - RIE (sanei_genesys_buffer_consume (src_buffer, bytes)); - - /* end scan if all needed data have been read */ - if(dev->total_bytes_read >= dev->total_bytes_to_read) - { - dev->model->cmd_set->end_scan (dev, dev->reg, SANE_TRUE); - if (dev->model->is_sheetfed == SANE_TRUE) - { - dev->model->cmd_set->eject_document (dev); - } - } - - DBG (DBG_proc, "genesys_read_ordered_data: completed, %lu bytes read\n", - (u_long) bytes); - return SANE_STATUS_GOOD; -} - - - -/* ------------------------------------------------------------------------ */ -/* Start of higher level functions */ -/* ------------------------------------------------------------------------ */ - -static size_t -max_string_size (const SANE_String_Const strings[]) -{ - size_t size, max_size = 0; - SANE_Int i; - - for (i = 0; strings[i]; ++i) - { - size = strlen (strings[i]) + 1; - if (size > max_size) - max_size = size; - } - return max_size; -} - -static SANE_Status -calc_parameters (Genesys_Scanner * s) -{ - SANE_String mode, source, color_filter; - SANE_Status status = SANE_STATUS_GOOD; - SANE_Int depth = 0, resolution = 0; - double tl_x = 0, tl_y = 0, br_x = 0, br_y = 0; - - mode = s->val[OPT_MODE].s; - source = s->val[OPT_SOURCE].s; - color_filter = s->val[OPT_COLOR_FILTER].s; - depth = s->val[OPT_BIT_DEPTH].w; - resolution = s->val[OPT_RESOLUTION].w; - tl_x = SANE_UNFIX (s->val[OPT_TL_X].w); - tl_y = SANE_UNFIX (s->val[OPT_TL_Y].w); - br_x = SANE_UNFIX (s->val[OPT_BR_X].w); - br_y = SANE_UNFIX (s->val[OPT_BR_Y].w); - - s->params.last_frame = SANE_TRUE; /* only single pass scanning supported */ - - if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0 - || strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) - s->params.format = SANE_FRAME_GRAY; - else /* Color */ - s->params.format = SANE_FRAME_RGB; - - if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) - s->params.depth = 1; - else - s->params.depth = depth; - s->dev->settings.depth = depth; - - /* interpolation */ - s->dev->settings.disable_interpolation = - s->val[OPT_DISABLE_INTERPOLATION].w == SANE_TRUE; - - /* hardware settings */ - if (resolution > s->dev->sensor.optical_res && - s->dev->settings.disable_interpolation) - s->dev->settings.xres = s->dev->sensor.optical_res; - else - s->dev->settings.xres = resolution; - s->dev->settings.yres = resolution; - - s->params.lines = ((br_y - tl_y) * s->dev->settings.yres) / MM_PER_INCH; - s->params.pixels_per_line = - ((br_x - tl_x) * resolution) / MM_PER_INCH; - - /* we need an even pixels number - * TODO invert test logic or generalize behaviour across all ASICs */ - if ((s->dev->model->flags & GENESYS_FLAG_SIS_SENSOR) - || s->dev->model->asic_type == GENESYS_GL847 - || s->dev->model->asic_type == GENESYS_GL124 - || s->dev->model->asic_type == GENESYS_GL845 - || s->dev->model->asic_type == GENESYS_GL846 - || s->dev->model->asic_type == GENESYS_GL843) - { - if (s->dev->settings.xres <= 1200) - s->params.pixels_per_line = (s->params.pixels_per_line/4)*4; - else - s->params.pixels_per_line = (s->params.pixels_per_line/16)*16; - } - - /* corner case for true lineart for sensor with several segments - * or when xres is doubled to match yres */ - if (s->dev->settings.xres >= 1200 - && ( s->dev->model->asic_type == GENESYS_GL124 - || s->dev->model->asic_type == GENESYS_GL847 - || s->dev->current_setup.xres < s->dev->current_setup.yres - ) - ) - { - s->params.pixels_per_line = (s->params.pixels_per_line/16)*16; - } - - s->params.bytes_per_line = s->params.pixels_per_line; - if (s->params.depth > 8) - { - s->params.depth = 16; - s->params.bytes_per_line *= 2; - } - else if (s->params.depth == 1) - { - s->params.bytes_per_line /= 8; - /* round down pixel number - really? rounding down means loss of at most 7 pixels! -- pierre */ - s->params.pixels_per_line = 8 * s->params.bytes_per_line; - } - - if (s->params.format == SANE_FRAME_RGB) - s->params.bytes_per_line *= 3; - - if (strcmp (mode, SANE_VALUE_SCAN_MODE_COLOR) == 0) - s->dev->settings.scan_mode = SCAN_MODE_COLOR; - else if (strcmp (mode, SANE_VALUE_SCAN_MODE_GRAY) == 0) - s->dev->settings.scan_mode = SCAN_MODE_GRAY; - else if (strcmp (mode, SANE_TITLE_HALFTONE) == 0) - s->dev->settings.scan_mode = SCAN_MODE_HALFTONE; - else /* Lineart */ - s->dev->settings.scan_mode = SCAN_MODE_LINEART; - - /* TODO: change and check */ - if (strcmp (source, FLATBED) == 0) - s->dev->settings.scan_method = SCAN_METHOD_FLATBED; - else /* transparency */ - s->dev->settings.scan_method = SCAN_METHOD_TRANSPARENCY; - - s->dev->settings.lines = s->params.lines; - s->dev->settings.pixels = s->params.pixels_per_line; - s->dev->settings.tl_x = tl_x; - s->dev->settings.tl_y = tl_y; - - /* threshold setting */ - s->dev->settings.threshold = 2.55 * (SANE_UNFIX (s->val[OPT_THRESHOLD].w)); - - /* color filter */ - if (strcmp (color_filter, "Red") == 0) - s->dev->settings.color_filter = 0; - else if (strcmp (color_filter, "Green") == 0) - s->dev->settings.color_filter = 1; - else if (strcmp (color_filter, "Blue") == 0) - s->dev->settings.color_filter = 2; - else - s->dev->settings.color_filter = 3; - - /* true gray */ - if (strcmp (color_filter, "None") == 0) - s->dev->settings.true_gray = 1; - else - s->dev->settings.true_gray = 0; - - /* dynamic lineart */ - s->dev->settings.dynamic_lineart = SANE_FALSE; - s->dev->settings.threshold_curve=0; - if(s->val[OPT_DISABLE_DYNAMIC_LINEART].w ==SANE_FALSE - &&s->dev->settings.scan_mode == SCAN_MODE_LINEART) - { - s->dev->settings.dynamic_lineart = SANE_TRUE; - } - - /* hardware lineart works only when we don't have interleave data - * for GL847 scanners, ie up to 600 DPI, then we have to rely on - * dynamic_lineart */ - if(s->dev->settings.xres > 600 - && s->dev->model->asic_type==GENESYS_GL847 - && s->dev->settings.scan_mode == SCAN_MODE_LINEART) - { - s->dev->settings.dynamic_lineart = SANE_TRUE; - } - - /* threshold curve for dynamic rasterization */ - s->dev->settings.threshold_curve=s->val[OPT_THRESHOLD_CURVE].w; - - /* some digital processing requires the whole picture to be buffered */ - /* no digital processing takes place when doing preview, or when bit depth is - * higher than 8 bits */ - if ((s->val[OPT_SWDESPECK].b - || s->val[OPT_SWCROP].b - || s->val[OPT_SWDESKEW].b - || s->val[OPT_SWDEROTATE].b - ||(SANE_UNFIX(s->val[OPT_SWSKIP].w)>0)) - && (!s->val[OPT_PREVIEW].b) - && (s->val[OPT_BIT_DEPTH].w <= 8)) - { - s->dev->buffer_image=SANE_TRUE; - } - else - { - s->dev->buffer_image=SANE_FALSE; - } - - /* brigthness and contrast only for for 8 bit scans */ - if(s->val[OPT_BIT_DEPTH].w <= 8) - { - s->dev->settings.contrast=(s->val[OPT_CONTRAST].w*127)/100; - s->dev->settings.brightness=(s->val[OPT_BRIGHTNESS].w*127)/100; - } - else - { - s->dev->settings.contrast=0; - s->dev->settings.brightness=0; - } - - /* cache expiration time */ - s->dev->settings.expiration_time=s->val[OPT_EXPIRATION_TIME].w; - - return status; -} - - -static SANE_Status -create_bpp_list (Genesys_Scanner * s, SANE_Int * bpp) -{ - int count; - - for (count = 0; bpp[count] != 0; count++) - ; - s->bpp_list[0] = count; - for (count = 0; bpp[count] != 0; count++) - { - s->bpp_list[s->bpp_list[0] - count] = bpp[count]; - } - return SANE_STATUS_GOOD; -} - -/** @brief this function initialize a gamma vector based on the ASIC: - * Set up a default gamma table vector based on device description - * gl646: 12 or 14 bits gamma table depending on GENESYS_FLAG_14BIT_GAMMA - * gl84x: 16 bits - * gl12x: 16 bits - * @param scanner pointer to scanner session to get options - * @param option option number of the gamma table to set - */ -static void -init_gamma_vector_option (Genesys_Scanner * scanner, int option) -{ - /* the option is inactive until the custom gamma control - * is enabled */ - scanner->opt[option].type = SANE_TYPE_INT; - scanner->opt[option].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED; - scanner->opt[option].unit = SANE_UNIT_NONE; - scanner->opt[option].constraint_type = SANE_CONSTRAINT_RANGE; - if (scanner->dev->model->asic_type == GENESYS_GL646) - { - if ((scanner->dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) != 0) - { - scanner->opt[option].size = 16384 * sizeof (SANE_Word); - scanner->opt[option].constraint.range = &u14_range; - } - else - { /* 12 bits gamma tables */ - scanner->opt[option].size = 4096 * sizeof (SANE_Word); - scanner->opt[option].constraint.range = &u12_range; - } - } - else - { /* other asics have 16 bits words gamma table */ - scanner->opt[option].size = 256 * sizeof (SANE_Word); - scanner->opt[option].constraint.range = &u16_range; - } - /* default value is NULL */ - scanner->val[option].wa = NULL; -} - -/** - * allocate a geometry range - * @param size maximum size of the range - * @return a pointer to a valid range or NULL - */ -static SANE_Range *create_range(SANE_Fixed size) -{ -SANE_Range *range=NULL; - - range=(SANE_Range *)malloc(sizeof(SANE_Range)); - if(range!=NULL) - { - range->min = SANE_FIX (0.0); - range->max = size; - range->quant = SANE_FIX (0.0); - } - return range; -} - -/** @brief generate calibration cache file nam - * Generates the calibration cache file name to use. - * Tries to store the chache in $HOME/.sane or - * then fallbacks to $TMPDIR or TMP. The filename - * uses the model name if only one scanner is plugged - * else is uses the device name when several identical - * scanners are in use. - * @param currdev current scanner device - * @return an allocated string containing a file name - */ -GENESYS_STATIC char *calibration_filename(Genesys_Device *currdev) -{ - char *tmpstr; - char *ptr; - char filename[80]; - Genesys_Device *dev; - unsigned int count; - unsigned int i; - - /* allocate space for result */ - tmpstr=malloc(PATH_MAX); - if(tmpstr==NULL) - { - return NULL; - } - - /* first compute the DIR where we can store cache: - * 1 - home dir - * 2 - $TMPDIR - * 3 - $TMP - * 4 - tmp dir - * 5 - temp dir - * 6 - then resort to current dir - */ - ptr = getenv ("HOME"); - if(ptr==NULL) - { - ptr = getenv ("USERPROFILE"); - } - if(ptr==NULL) - { - ptr = getenv ("TMPDIR"); - } - if(ptr==NULL) - { - ptr = getenv ("TMP"); - } - - /* now choose filename: - * 1 - if only one scanner, name of the model - * 2 - if several scanners of the same model, use device name, - * replacing special chars - */ - count=0; - /* count models of the same names if several scanners attached */ - if(num_devices>1) - { - for (dev = first_dev; dev; dev = dev->next) - { - if(strcmp(dev->model->name,currdev->model->name)==0) - { - count++; - } - } - } - if(count>1) - { - snprintf(filename,sizeof(filename),"%s.cal",currdev->file_name); - for(i=0;imodel->name); - } - - /* build final final name : store dir + filename */ - if (NULL == ptr) - { - snprintf (tmpstr, PATH_MAX, "%s", filename); - } - else - { -#ifdef HAVE_MKDIR - /* make sure .sane directory exists in existing store dir */ - snprintf (tmpstr, PATH_MAX, "%s%c.sane", ptr, PATH_SEP); - mkdir(tmpstr,0700); -#endif - snprintf (tmpstr, PATH_MAX, "%s%c.sane%c%s", ptr, PATH_SEP, PATH_SEP, filename); - } - - DBG (DBG_info, "%s: calibration filename >%s<\n", __func__, tmpstr); - - return tmpstr; -} - - -static SANE_Status -init_options (Genesys_Scanner * s) -{ - SANE_Int option, count, min_dpi; - SANE_Status status; - SANE_Word *dpi_list; - Genesys_Model *model = s->dev->model; - SANE_Range *x_range, *y_range; - - DBGSTART; - - memset (s->opt, 0, sizeof (s->opt)); - memset (s->val, 0, sizeof (s->val)); - - for (option = 0; option < NUM_OPTIONS; ++option) - { - s->opt[option].size = sizeof (SANE_Word); - s->opt[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - } - s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; - s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; - s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; - s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; - s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; - s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; - - /* "Mode" group: */ - s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode"); - s->opt[OPT_MODE_GROUP].desc = ""; - s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_MODE_GROUP].size = 0; - s->opt[OPT_MODE_GROUP].cap = 0; - s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - /* scan mode */ - s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; - s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; - s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; - s->opt[OPT_MODE].type = SANE_TYPE_STRING; - s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; - s->opt[OPT_MODE].size = max_string_size (mode_list); - s->opt[OPT_MODE].constraint.string_list = mode_list; - s->val[OPT_MODE].s = strdup (SANE_VALUE_SCAN_MODE_GRAY); - - /* scan source */ - s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; - s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; - s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; - s->opt[OPT_SOURCE].type = SANE_TYPE_STRING; - s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; - s->opt[OPT_SOURCE].size = max_string_size (source_list); - s->opt[OPT_SOURCE].constraint.string_list = source_list; - s->val[OPT_SOURCE].s = strdup (FLATBED); - if (model->flags & GENESYS_FLAG_HAS_UTA) - { - ENABLE (OPT_SOURCE); - } - else - { - DISABLE (OPT_SOURCE); - } - - /* preview */ - s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; - s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; - s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; - s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; - s->opt[OPT_PREVIEW].unit = SANE_UNIT_NONE; - s->opt[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE; - s->val[OPT_PREVIEW].w = SANE_FALSE; - - /* bit depth */ - s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; - s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; - s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; - s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT; - s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; - s->opt[OPT_BIT_DEPTH].size = sizeof (SANE_Word); - s->opt[OPT_BIT_DEPTH].constraint.word_list = 0; - s->opt[OPT_BIT_DEPTH].constraint.word_list = s->bpp_list; - create_bpp_list (s, model->bpp_gray_values); - s->val[OPT_BIT_DEPTH].w = 8; - if (s->opt[OPT_BIT_DEPTH].constraint.word_list[0] < 2) - DISABLE (OPT_BIT_DEPTH); - - /* resolution */ - min_dpi=200000; - for (count = 0; model->xdpi_values[count] != 0; count++) - { - if(model->xdpi_values[count]xdpi_values[count]; - } - } - dpi_list = malloc ((count + 1) * sizeof (SANE_Word)); - if (!dpi_list) - return SANE_STATUS_NO_MEM; - dpi_list[0] = count; - for (count = 0; model->xdpi_values[count] != 0; count++) - dpi_list[count + 1] = model->xdpi_values[count]; - s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; - s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; - s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; - s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; - s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; - s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; - s->opt[OPT_RESOLUTION].constraint.word_list = dpi_list; - s->val[OPT_RESOLUTION].w = min_dpi; - - /* "Geometry" group: */ - s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry"); - s->opt[OPT_GEOMETRY_GROUP].desc = ""; - s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_GEOMETRY_GROUP].size = 0; - s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - x_range=create_range(model->x_size); - if(x_range==NULL) - { - return SANE_STATUS_NO_MEM; - } - - y_range=create_range(model->y_size); - if(y_range==NULL) - { - return SANE_STATUS_NO_MEM; - } - - /* top-left x */ - s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; - s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; - s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; - s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; - s->opt[OPT_TL_X].unit = SANE_UNIT_MM; - s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_TL_X].constraint.range = x_range; - s->val[OPT_TL_X].w = 0; - - /* top-left y */ - s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; - s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; - s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; - s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; - s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; - s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_TL_Y].constraint.range = y_range; - s->val[OPT_TL_Y].w = 0; - - /* bottom-right x */ - s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; - s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; - s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; - s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; - s->opt[OPT_BR_X].unit = SANE_UNIT_MM; - s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_BR_X].constraint.range = x_range; - s->val[OPT_BR_X].w = x_range->max; - - /* bottom-right y */ - s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; - s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; - s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; - s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; - s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; - s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_BR_Y].constraint.range = y_range; - s->val[OPT_BR_Y].w = y_range->max; - - /* "Enhancement" group: */ - s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement"); - s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; - s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_ENHANCEMENT_GROUP].size = 0; - s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - /* custom-gamma table */ - s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA; - s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA; - s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA; - s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL; - s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_ADVANCED; - s->val[OPT_CUSTOM_GAMMA].b = SANE_FALSE; - - /* grayscale gamma vector */ - s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; - s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; - s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR; - init_gamma_vector_option (s, OPT_GAMMA_VECTOR); - - /* red gamma vector */ - s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R; - s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R; - s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R; - init_gamma_vector_option (s, OPT_GAMMA_VECTOR_R); - - /* green gamma vector */ - s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G; - s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G; - s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G; - init_gamma_vector_option (s, OPT_GAMMA_VECTOR_G); - - /* blue gamma vector */ - s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B; - s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B; - s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B; - init_gamma_vector_option (s, OPT_GAMMA_VECTOR_B); - - /* currently, there are only gamma table options in this group, - * so if the scanner doesn't support gamma table, disable the - * whole group */ - if (!(model->flags & GENESYS_FLAG_CUSTOM_GAMMA)) - { - s->opt[OPT_ENHANCEMENT_GROUP].cap |= SANE_CAP_INACTIVE; - s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; - DBG (DBG_info, "init_options: custom gamma disabled\n"); - } - - /* software base image enhancements, these are consuming as many - * memory than used by the full scanned image and may fail at high - * resolution - */ - /* software deskew */ - s->opt[OPT_SWDESKEW].name = "swdeskew"; - s->opt[OPT_SWDESKEW].title = "Software deskew"; - s->opt[OPT_SWDESKEW].desc = "Request backend to rotate skewed pages digitally"; - s->opt[OPT_SWDESKEW].type = SANE_TYPE_BOOL; - s->opt[OPT_SWDESKEW].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->val[OPT_SWDESKEW].b = SANE_FALSE; - - /* software deskew */ - s->opt[OPT_SWDESPECK].name = "swdespeck"; - s->opt[OPT_SWDESPECK].title = "Software despeck"; - s->opt[OPT_SWDESPECK].desc = "Request backend to remove lone dots digitally"; - s->opt[OPT_SWDESPECK].type = SANE_TYPE_BOOL; - s->opt[OPT_SWDESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->val[OPT_SWDESPECK].b = SANE_FALSE; - - /* software despeckle radius */ - s->opt[OPT_DESPECK].name = "despeck"; - s->opt[OPT_DESPECK].title = "Software despeckle diameter"; - s->opt[OPT_DESPECK].desc = "Maximum diameter of lone dots to remove from scan"; - s->opt[OPT_DESPECK].type = SANE_TYPE_INT; - s->opt[OPT_DESPECK].unit = SANE_UNIT_NONE; - s->opt[OPT_DESPECK].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_DESPECK].constraint.range = &swdespeck_range; - s->opt[OPT_DESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED | SANE_CAP_INACTIVE; - s->val[OPT_DESPECK].w = 1; - - /* crop by software */ - s->opt[OPT_SWCROP].name = "swcrop"; - s->opt[OPT_SWCROP].title = SANE_I18N ("Software crop"); - s->opt[OPT_SWCROP].desc = SANE_I18N ("Request backend to remove border from pages digitally"); - s->opt[OPT_SWCROP].type = SANE_TYPE_BOOL; - s->opt[OPT_SWCROP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->opt[OPT_SWCROP].unit = SANE_UNIT_NONE; - s->val[OPT_SWCROP].b = SANE_FALSE; - - /* Software blank page skip */ - s->opt[OPT_SWSKIP].name = "swskip"; - s->opt[OPT_SWSKIP].title = SANE_I18N ("Software blank skip percentage"); - s->opt[OPT_SWSKIP].desc = SANE_I18N("Request driver to discard pages with low numbers of dark pixels"); - s->opt[OPT_SWSKIP].type = SANE_TYPE_FIXED; - s->opt[OPT_SWSKIP].unit = SANE_UNIT_PERCENT; - s->opt[OPT_SWSKIP].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_SWSKIP].constraint.range = &(percentage_range); - s->opt[OPT_SWSKIP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - /* disable by default */ - s->val[OPT_SWSKIP].w = 0; - - /* Software Derotate */ - s->opt[OPT_SWDEROTATE].name = "swderotate"; - s->opt[OPT_SWDEROTATE].title = SANE_I18N ("Software derotate"); - s->opt[OPT_SWDEROTATE].desc = SANE_I18N("Request driver to detect and correct 90 degree image rotation"); - s->opt[OPT_SWDEROTATE].type = SANE_TYPE_BOOL; - s->opt[OPT_SWDEROTATE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->opt[OPT_SWDEROTATE].unit = SANE_UNIT_NONE; - s->val[OPT_SWDEROTATE].b = SANE_FALSE; - - /* Software brightness */ - s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; - s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; - s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; - s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; - s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; - s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_BRIGHTNESS].constraint.range = &(enhance_range); - s->opt[OPT_BRIGHTNESS].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - /* disable by default */ - s->val[OPT_BRIGHTNESS].w = 0; - - /* Sowftware contrast */ - s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; - s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; - s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; - s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; - s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; - s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_CONTRAST].constraint.range = &(enhance_range); - s->opt[OPT_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - /* disable by default */ - s->val[OPT_CONTRAST].w = 0; - - /* "Extras" group: */ - s->opt[OPT_EXTRAS_GROUP].title = SANE_I18N ("Extras"); - s->opt[OPT_EXTRAS_GROUP].desc = ""; - s->opt[OPT_EXTRAS_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_EXTRAS_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_EXTRAS_GROUP].size = 0; - s->opt[OPT_EXTRAS_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - /* BW threshold */ - s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD; - s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; - s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; - s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED; - s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; - s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_THRESHOLD].constraint.range = &percentage_range; - s->val[OPT_THRESHOLD].w = SANE_FIX (50); - - /* BW threshold curve */ - s->opt[OPT_THRESHOLD_CURVE].name = "threshold-curve"; - s->opt[OPT_THRESHOLD_CURVE].title = SANE_I18N ("Threshold curve"); - s->opt[OPT_THRESHOLD_CURVE].desc = SANE_I18N ("Dynamic threshold curve, from light to dark, normally 50-65"); - s->opt[OPT_THRESHOLD_CURVE].type = SANE_TYPE_INT; - s->opt[OPT_THRESHOLD_CURVE].unit = SANE_UNIT_NONE; - s->opt[OPT_THRESHOLD_CURVE].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_THRESHOLD_CURVE].constraint.range = &threshold_curve_range; - s->val[OPT_THRESHOLD_CURVE].w = 50; - - /* dynamic linart */ - s->opt[OPT_DISABLE_DYNAMIC_LINEART].name = "disable-dynamic-lineart"; - s->opt[OPT_DISABLE_DYNAMIC_LINEART].title = SANE_I18N ("Disable dynamic lineart"); - s->opt[OPT_DISABLE_DYNAMIC_LINEART].desc = - SANE_I18N ("Disable use of a software adaptive algorithm to generate lineart relying instead on hardware lineart."); - s->opt[OPT_DISABLE_DYNAMIC_LINEART].type = SANE_TYPE_BOOL; - s->opt[OPT_DISABLE_DYNAMIC_LINEART].unit = SANE_UNIT_NONE; - s->opt[OPT_DISABLE_DYNAMIC_LINEART].constraint_type = SANE_CONSTRAINT_NONE; - s->val[OPT_DISABLE_DYNAMIC_LINEART].w = SANE_FALSE; - - /* fastmod is required for hw lineart to work */ - if ((s->dev->model->asic_type == GENESYS_GL646) - &&(s->dev->model->motor_type != MOTOR_XP200)) - { - s->opt[OPT_DISABLE_DYNAMIC_LINEART].cap = SANE_CAP_INACTIVE; - } - - /* disable_interpolation */ - s->opt[OPT_DISABLE_INTERPOLATION].name = "disable-interpolation"; - s->opt[OPT_DISABLE_INTERPOLATION].title = - SANE_I18N ("Disable interpolation"); - s->opt[OPT_DISABLE_INTERPOLATION].desc = - SANE_I18N - ("When using high resolutions where the horizontal resolution is smaller " - "than the vertical resolution this disables horizontal interpolation."); - s->opt[OPT_DISABLE_INTERPOLATION].type = SANE_TYPE_BOOL; - s->opt[OPT_DISABLE_INTERPOLATION].unit = SANE_UNIT_NONE; - s->opt[OPT_DISABLE_INTERPOLATION].constraint_type = SANE_CONSTRAINT_NONE; - s->val[OPT_DISABLE_INTERPOLATION].w = SANE_FALSE; - - /* color filter */ - s->opt[OPT_COLOR_FILTER].name = "color-filter"; - s->opt[OPT_COLOR_FILTER].title = SANE_I18N ("Color filter"); - s->opt[OPT_COLOR_FILTER].desc = - SANE_I18N - ("When using gray or lineart this option selects the used color."); - s->opt[OPT_COLOR_FILTER].type = SANE_TYPE_STRING; - s->opt[OPT_COLOR_FILTER].constraint_type = SANE_CONSTRAINT_STRING_LIST; - /* true gray not yet supported for GL847 and GL124 scanners */ - if(!model->is_cis || model->asic_type==GENESYS_GL847 || model->asic_type==GENESYS_GL124) - { - s->opt[OPT_COLOR_FILTER].size = max_string_size (color_filter_list); - s->opt[OPT_COLOR_FILTER].constraint.string_list = color_filter_list; - s->val[OPT_COLOR_FILTER].s = strdup (s->opt[OPT_COLOR_FILTER].constraint.string_list[1]); - } - else - { - s->opt[OPT_COLOR_FILTER].size = max_string_size (cis_color_filter_list); - s->opt[OPT_COLOR_FILTER].constraint.string_list = cis_color_filter_list; - /* default to "None" ie true gray */ - s->val[OPT_COLOR_FILTER].s = strdup (s->opt[OPT_COLOR_FILTER].constraint.string_list[3]); - } - - /* no support for color filter for cis+gl646 scanners */ - if (model->asic_type == GENESYS_GL646 && model->is_cis) - { - DISABLE (OPT_COLOR_FILTER); - } - - /* calibration store file name */ - s->opt[OPT_CALIBRATION_FILE].name = "calibration-file"; - s->opt[OPT_CALIBRATION_FILE].title = SANE_I18N ("Calibration file"); - s->opt[OPT_CALIBRATION_FILE].desc = SANE_I18N ("Specify the calibration file to use"); - s->opt[OPT_CALIBRATION_FILE].type = SANE_TYPE_STRING; - s->opt[OPT_CALIBRATION_FILE].unit = SANE_UNIT_NONE; - s->opt[OPT_CALIBRATION_FILE].size = PATH_MAX; - s->opt[OPT_CALIBRATION_FILE].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; - s->opt[OPT_CALIBRATION_FILE].constraint_type = SANE_CONSTRAINT_NONE; - s->val[OPT_CALIBRATION_FILE].s = NULL; - /* disable option if ran as root */ -#ifdef HAVE_GETUID - if(geteuid()==0) - { - DISABLE (OPT_CALIBRATION_FILE); - } -#endif - - /* expiration time for calibration cache entries */ - s->opt[OPT_EXPIRATION_TIME].name = "expiration-time"; - s->opt[OPT_EXPIRATION_TIME].title = SANE_I18N ("Calibration cache expiration time"); - s->opt[OPT_EXPIRATION_TIME].desc = SANE_I18N ("Time (in minutes) before a cached calibration expires. " - "A value of 0 means cache is not used. A negative value means cache never expires."); - s->opt[OPT_EXPIRATION_TIME].type = SANE_TYPE_INT; - s->opt[OPT_EXPIRATION_TIME].unit = SANE_UNIT_NONE; - s->opt[OPT_EXPIRATION_TIME].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_EXPIRATION_TIME].constraint.range = &expiration_range; - s->val[OPT_EXPIRATION_TIME].w = 60; /* 60 minutes by default */ - - /* Powersave time (turn lamp off) */ - s->opt[OPT_LAMP_OFF_TIME].name = "lamp-off-time"; - s->opt[OPT_LAMP_OFF_TIME].title = SANE_I18N ("Lamp off time"); - s->opt[OPT_LAMP_OFF_TIME].desc = - SANE_I18N - ("The lamp will be turned off after the given time (in minutes). " - "A value of 0 means, that the lamp won't be turned off."); - s->opt[OPT_LAMP_OFF_TIME].type = SANE_TYPE_INT; - s->opt[OPT_LAMP_OFF_TIME].unit = SANE_UNIT_NONE; - s->opt[OPT_LAMP_OFF_TIME].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_LAMP_OFF_TIME].constraint.range = &time_range; - s->val[OPT_LAMP_OFF_TIME].w = 15; /* 15 minutes */ - - /* turn lamp off during scan */ - s->opt[OPT_LAMP_OFF].name = "lamp-off-scan"; - s->opt[OPT_LAMP_OFF].title = SANE_I18N ("Lamp off during scan"); - s->opt[OPT_LAMP_OFF].desc = SANE_I18N ("The lamp will be turned off during scan. "); - s->opt[OPT_LAMP_OFF].type = SANE_TYPE_BOOL; - s->opt[OPT_LAMP_OFF].unit = SANE_UNIT_NONE; - s->opt[OPT_LAMP_OFF].constraint_type = SANE_CONSTRAINT_NONE; - s->val[OPT_LAMP_OFF].w = SANE_FALSE; - - s->opt[OPT_SENSOR_GROUP].title = SANE_TITLE_SENSORS; - s->opt[OPT_SENSOR_GROUP].desc = SANE_DESC_SENSORS; - s->opt[OPT_SENSOR_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_SENSOR_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_SENSOR_GROUP].size = 0; - s->opt[OPT_SENSOR_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - s->opt[OPT_SCAN_SW].name = SANE_NAME_SCAN; - s->opt[OPT_SCAN_SW].title = SANE_TITLE_SCAN; - s->opt[OPT_SCAN_SW].desc = SANE_DESC_SCAN; - s->opt[OPT_SCAN_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_SCAN_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_SCAN_SW) - s->opt[OPT_SCAN_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_SCAN_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_SCAN_SW].b = 0; - s->last_val[OPT_SCAN_SW].b = 0; - - /* SANE_NAME_FILE is not for buttons */ - s->opt[OPT_FILE_SW].name = "file"; - s->opt[OPT_FILE_SW].title = SANE_I18N ("File button"); - s->opt[OPT_FILE_SW].desc = SANE_I18N ("File button"); - s->opt[OPT_FILE_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_FILE_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_FILE_SW) - s->opt[OPT_FILE_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_FILE_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_FILE_SW].b = 0; - s->last_val[OPT_FILE_SW].b = 0; - - s->opt[OPT_EMAIL_SW].name = SANE_NAME_EMAIL; - s->opt[OPT_EMAIL_SW].title = SANE_TITLE_EMAIL; - s->opt[OPT_EMAIL_SW].desc = SANE_DESC_EMAIL; - s->opt[OPT_EMAIL_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_EMAIL_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_EMAIL_SW) - s->opt[OPT_EMAIL_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_EMAIL_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_EMAIL_SW].b = 0; - s->last_val[OPT_EMAIL_SW].b = 0; - - s->opt[OPT_COPY_SW].name = SANE_NAME_COPY; - s->opt[OPT_COPY_SW].title = SANE_TITLE_COPY; - s->opt[OPT_COPY_SW].desc = SANE_DESC_COPY; - s->opt[OPT_COPY_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_COPY_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_COPY_SW) - s->opt[OPT_COPY_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_COPY_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_COPY_SW].b = 0; - s->last_val[OPT_COPY_SW].b = 0; - - s->opt[OPT_PAGE_LOADED_SW].name = SANE_NAME_PAGE_LOADED; - s->opt[OPT_PAGE_LOADED_SW].title = SANE_TITLE_PAGE_LOADED; - s->opt[OPT_PAGE_LOADED_SW].desc = SANE_DESC_PAGE_LOADED; - s->opt[OPT_PAGE_LOADED_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_PAGE_LOADED_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_PAGE_LOADED_SW) - s->opt[OPT_PAGE_LOADED_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_PAGE_LOADED_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_PAGE_LOADED_SW].b = 0; - s->last_val[OPT_PAGE_LOADED_SW].b = 0; - - /* OCR button */ - s->opt[OPT_OCR_SW].name = "ocr"; - s->opt[OPT_OCR_SW].title = SANE_I18N ("OCR button"); - s->opt[OPT_OCR_SW].desc = SANE_I18N ("OCR button"); - s->opt[OPT_OCR_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_OCR_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_OCR_SW) - s->opt[OPT_OCR_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_OCR_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_OCR_SW].b = 0; - s->last_val[OPT_OCR_SW].b = 0; - - /* power button */ - s->opt[OPT_POWER_SW].name = "power"; - s->opt[OPT_POWER_SW].title = SANE_I18N ("Power button"); - s->opt[OPT_POWER_SW].desc = SANE_I18N ("Power button"); - s->opt[OPT_POWER_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_POWER_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_POWER_SW) - s->opt[OPT_POWER_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_POWER_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_POWER_SW].b = 0; - s->last_val[OPT_POWER_SW].b = 0; - - /* extra button */ - s->opt[OPT_EXTRA_SW].name = "extra"; - s->opt[OPT_EXTRA_SW].title = SANE_I18N ("Extra button"); - s->opt[OPT_EXTRA_SW].desc = SANE_I18N ("Extra button"); - s->opt[OPT_EXTRA_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_EXTRA_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_EXTRA_SW) - s->opt[OPT_EXTRA_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_EXTRA_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_EXTRA_SW].b = 0; - s->last_val[OPT_EXTRA_SW].b = 0; - - /* calibration needed */ - s->opt[OPT_NEED_CALIBRATION_SW].name = "need-calibration"; - s->opt[OPT_NEED_CALIBRATION_SW].title = SANE_I18N ("Need calibration"); - s->opt[OPT_NEED_CALIBRATION_SW].desc = SANE_I18N ("The scanner needs calibration for the current settings"); - s->opt[OPT_NEED_CALIBRATION_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_NEED_CALIBRATION_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_CALIBRATE) - s->opt[OPT_NEED_CALIBRATION_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_NEED_CALIBRATION_SW].cap = SANE_CAP_INACTIVE; - s->val[OPT_NEED_CALIBRATION_SW].b = 0; - s->last_val[OPT_NEED_CALIBRATION_SW].b = 0; - - /* button group */ - s->opt[OPT_BUTTON_GROUP].title = SANE_I18N ("Buttons"); - s->opt[OPT_BUTTON_GROUP].desc = ""; - s->opt[OPT_BUTTON_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_BUTTON_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_BUTTON_GROUP].size = 0; - s->opt[OPT_BUTTON_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - /* calibrate button */ - s->opt[OPT_CALIBRATE].name = "calibrate"; - s->opt[OPT_CALIBRATE].title = SANE_I18N ("Calibrate"); - s->opt[OPT_CALIBRATE].desc = - SANE_I18N ("Start calibration using special sheet"); - s->opt[OPT_CALIBRATE].type = SANE_TYPE_BUTTON; - s->opt[OPT_CALIBRATE].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_CALIBRATE) - s->opt[OPT_CALIBRATE].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED | - SANE_CAP_AUTOMATIC; - else - s->opt[OPT_CALIBRATE].cap = SANE_CAP_INACTIVE; - s->val[OPT_CALIBRATE].b = 0; - s->last_val[OPT_CALIBRATE].b = 0; - - /* clear calibration cache button */ - s->opt[OPT_CLEAR_CALIBRATION].name = "clear-calibration"; - s->opt[OPT_CLEAR_CALIBRATION].title = SANE_I18N ("Clear calibration"); - s->opt[OPT_CLEAR_CALIBRATION].desc = SANE_I18N ("Clear calibration cache"); - s->opt[OPT_CLEAR_CALIBRATION].type = SANE_TYPE_BUTTON; - s->opt[OPT_CLEAR_CALIBRATION].unit = SANE_UNIT_NONE; - s->opt[OPT_CLEAR_CALIBRATION].size = 0; - s->opt[OPT_CLEAR_CALIBRATION].constraint_type = SANE_CONSTRAINT_NONE; - s->opt[OPT_CLEAR_CALIBRATION].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; - s->val[OPT_CLEAR_CALIBRATION].b = 0; - s->last_val[OPT_CLEAR_CALIBRATION].b = 0; - - RIE (calc_parameters (s)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Bool present; -static SANE_Status -check_present (SANE_String_Const devname) -{ - present=SANE_TRUE; - DBG (DBG_io, "check_present: %s detected.\n",devname); - return SANE_STATUS_GOOD; -} - -/** @brief add a scanner device - * Insert the given device into the backend list of devices. - * @param dev device to add - */ -GENESYS_STATIC void add_device(Genesys_Device *dev) -{ - ++num_devices; - dev->next = first_dev; - first_dev = dev; -} - -static SANE_Status -attach (SANE_String_Const devname, Genesys_Device ** devp, SANE_Bool may_wait) -{ - Genesys_Device *dev = 0; - SANE_Int dn, vendor, product; - SANE_Status status; - unsigned int i; - - - DBG (DBG_proc, "attach: start: devp %s NULL, may_wait = %d\n", - devp ? "!=" : "==", may_wait); - - if (devp) - *devp = 0; - - if (!devname) - { - DBG (DBG_error, "attach: devname == NULL\n"); - return SANE_STATUS_INVAL; - } - - for (dev = first_dev; dev; dev = dev->next) - { - if (strcmp (dev->file_name, devname) == 0) - { - if (devp) - *devp = dev; - DBG (DBG_info, "attach: device `%s' was already in device list\n", - devname); - return SANE_STATUS_GOOD; - } - } - - DBG (DBG_info, "attach: trying to open device `%s'\n", devname); - - status = sanei_usb_open (devname, &dn); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_warn, "attach: couldn't open device `%s': %s\n", devname, - sane_strstatus (status)); - return status; - } - else - DBG (DBG_info, "attach: device `%s' successfully opened\n", devname); - - status = sanei_usb_get_vendor_product (dn, &vendor, &product); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "attach: couldn't get vendor and product ids of device `%s': %s\n", - devname, sane_strstatus (status)); - return status; - } - - /* KV-SS080 is an auxiliary device which requires a master device to be here */ - if(vendor == 0x04da && product == 0x100f) - { - present=SANE_FALSE; - sanei_usb_find_devices (vendor, 0x1006, check_present); - sanei_usb_find_devices (vendor, 0x1007, check_present); - sanei_usb_find_devices (vendor, 0x1010, check_present); - if(present==SANE_FALSE) - { - DBG (DBG_error,"attach: master device not present\n"); - return SANE_STATUS_INVAL; - } - } - - for (i = 0; i < MAX_SCANNERS && genesys_usb_device_list[i].model != 0; i++) - { - if (vendor == genesys_usb_device_list[i].vendor && - product == genesys_usb_device_list[i].product) - { - dev = malloc (sizeof (*dev)); - if (!dev) - return SANE_STATUS_NO_MEM; - break; - } - } - - if (!dev) - { - DBG (DBG_error, - "attach: vendor %d product %d is not supported by this backend\n", - vendor, product); - return SANE_STATUS_INVAL; - } - - dev->file_name = strdup (devname); - if (!dev->file_name) - { - free(dev); - return SANE_STATUS_NO_MEM; - } - - dev->model = genesys_usb_device_list[i].model; - dev->vendorId = genesys_usb_device_list[i].vendor; - dev->productId = genesys_usb_device_list[i].product; - dev->already_initialized = SANE_FALSE; - - DBG (DBG_info, "attach: found %s flatbed scanner %s at %s\n", - dev->model->vendor, dev->model->model, dev->file_name); - add_device(dev); - - if (devp) - *devp = dev; - sanei_usb_close (dn); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -attach_one_device (SANE_String_Const devname) -{ - Genesys_Device *dev; - SANE_Status status; - Genesys_Device **tmp_dev; - - RIE (attach (devname, &dev, SANE_FALSE)); - - if (dev) - { - /* Keep track of newly attached devices so we can set options as - necessary. */ - tmp_dev=NULL; - /* increase device list capacity if needed */ - if (new_dev_len >= new_dev_alloced) - { - new_dev_alloced += 4; - if (new_dev) - { - tmp_dev = new_dev; - new_dev = realloc (new_dev, new_dev_alloced * sizeof (new_dev[0])); - } - else - { - new_dev = malloc (new_dev_alloced * sizeof (new_dev[0])); - tmp_dev = NULL; - } - if (!new_dev) - { - FREE_IFNOT_NULL(tmp_dev) - DBG (DBG_error, "attach_one_device: out of memory\n"); - return SANE_STATUS_NO_MEM; - } - } - new_dev[new_dev_len++] = dev; - } - return SANE_STATUS_GOOD; -} - -/* configuration framework functions */ -static SANE_Status -config_attach_genesys (SANEI_Config __sane_unused__ *config, const char *devname) -{ - /* the devname has been processed and is ready to be used - * directly. Since the backend is an USB only one, we can - * call sanei_usb_attach_matching_devices straight */ - sanei_usb_attach_matching_devices (devname, attach_one_device); - - return SANE_STATUS_GOOD; -} - -/* probes for scanner to attach to the backend */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -probe_genesys_devices (void) -{ - SANEI_Config config; - SANE_Status status; - - DBGSTART; - - new_dev = 0; - new_dev_len = 0; - new_dev_alloced = 0; - - /* set configuration options structure : no option for this backend */ - config.descriptors = NULL; - config.values = NULL; - config.count = 0; - - /* generic configure and attach function */ - status = sanei_configure_attach (GENESYS_CONFIG_FILE, &config, - config_attach_genesys); - - if (new_dev_alloced > 0) - { - new_dev_len = new_dev_alloced = 0; - free (new_dev); - } - - DBG(DBG_info, "%s: %d devices currently attached\n", __func__, num_devices); - - DBGCOMPLETED; - - return status; -} - -/** - * This should be changed if one of the substructures of - Genesys_Calibration_Cache change, but it must be changed if there are - changes that don't change size -- at least for now, as we store most - of Genesys_Calibration_Cache as is. -*/ -#define CALIBRATION_VERSION 1 - -/** - * reads previously cached calibration data - * from file define in dev->calib_file - */ -SANE_Status -sanei_genesys_read_calibration (Genesys_Device * dev) -{ - FILE *fp; - uint8_t vers = 0; - uint32_t size = 0; - struct Genesys_Calibration_Cache *cache; - SANE_Status status=SANE_STATUS_GOOD; - - DBGSTART; - - /* open calibration cache file */ - fp = fopen (dev->calib_file, "rb"); - if (!fp) - { - DBG (DBG_info, "Calibration: Cannot open %s\n", dev->calib_file); - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; - } - - /* these two checks ensure that most bad things cannot happen */ - fread (&vers, 1, 1, fp); - if (vers != CALIBRATION_VERSION) - { - DBG (DBG_info, "Calibration: Bad version\n"); - fclose (fp); - DBGCOMPLETED; - return SANE_STATUS_INVAL; - } - fread (&size, 4, 1, fp); - if (size != sizeof (struct Genesys_Calibration_Cache)) - { - DBG (DBG_info, - "Calibration: Size of calibration cache struct differs\n"); - fclose (fp); - DBGCOMPLETED; - return SANE_STATUS_INVAL; - } - - /* clear device calibration cache */ - while(dev->calibration_cache!=NULL) - { - cache=dev->calibration_cache; - dev->calibration_cache=dev->calibration_cache->next; - free(cache); - } - - /* loop on cache records in file */ - while (!feof (fp) && status==SANE_STATUS_GOOD) - { - DBG (DBG_info, "sanei_genesys_read_calibration: reading one record\n"); - cache = (struct Genesys_Calibration_Cache *) malloc (sizeof (*cache)); - - if (!cache) - { - DBG (DBG_error, - "sanei_genesys_read_calibration: could not allocate cache struct\n"); - break; - } - -#define BILT1( x ) \ - do \ - { \ - if ((x) < 1) \ - { \ - free(cache); \ - DBG (DBG_warn, "sanei_genesys_read_calibration: partial calibration record\n"); \ - status=SANE_STATUS_EOF; \ - break; \ - } \ - } while(0) - - - if (fread (&cache->used_setup, sizeof (cache->used_setup), 1, fp) < 1) - { /* eof is only detected here */ - free (cache); - status=SANE_STATUS_GOOD; - break; - } - BILT1 (fread (&cache->last_calibration, sizeof (cache->last_calibration), 1, fp)); - BILT1 (fread (&cache->frontend, sizeof (cache->frontend), 1, fp)); - /* the gamma (and later) fields are not stored */ - BILT1 (fread (&cache->sensor, offsetof (Genesys_Sensor, gamma[0]), 1, fp)); - BILT1 (fread (&cache->calib_pixels, sizeof (cache->calib_pixels), 1, fp)); - BILT1 (fread (&cache->calib_channels, sizeof (cache->calib_channels), 1, fp)); - BILT1 (fread (&cache->average_size, sizeof (cache->average_size), 1, fp)); - - cache->white_average_data = (uint8_t *) malloc (cache->average_size); - cache->dark_average_data = (uint8_t *) malloc (cache->average_size); - - if (!cache->white_average_data || !cache->dark_average_data) - { - status=SANE_STATUS_NO_MEM; - FREE_IFNOT_NULL (cache->white_average_data); - FREE_IFNOT_NULL (cache->dark_average_data); - free (cache); - DBG (DBG_error, - "sanei_genesys_read_calibration: could not allocate space for average data\n"); - break; - } - - if (fread (cache->white_average_data, cache->average_size, 1, fp) < 1) - { - status=SANE_STATUS_EOF; - DBG (DBG_warn, "sanei_genesys_read_calibration: partial calibration record\n"); - free (cache->white_average_data); - free (cache->dark_average_data); - free (cache); - break; - } - if (fread (cache->dark_average_data, cache->average_size, 1, fp) < 1) - { - DBG (DBG_warn, "sanei_genesys_read_calibration: partial calibration record\n"); - free (cache->white_average_data); - free (cache->dark_average_data); - free (cache); - status=SANE_STATUS_EOF; - break; - } -#undef BILT1 - DBG (DBG_info, "sanei_genesys_read_calibration: adding record to list\n"); - cache->next = dev->calibration_cache; - dev->calibration_cache = cache; - } - - fclose (fp); - DBGCOMPLETED; - return status; -} - -static void -write_calibration (Genesys_Device * dev) -{ - FILE *fp; - uint8_t vers = 0; - uint32_t size = 0; - struct Genesys_Calibration_Cache *cache; - - DBGSTART; - fp = fopen (dev->calib_file, "wb"); - if (!fp) - { - DBG (DBG_info, "write_calibration: Cannot open %s for writing\n", dev->calib_file); - return; - } - - vers = CALIBRATION_VERSION; - fwrite (&vers, 1, 1, fp); - size = sizeof (struct Genesys_Calibration_Cache); - fwrite (&size, 4, 1, fp); - - for (cache = dev->calibration_cache; cache; cache = cache->next) - { - fwrite (&cache->used_setup, sizeof (cache->used_setup), 1, fp); - fwrite (&cache->last_calibration, sizeof (cache->last_calibration), 1, fp); - fwrite (&cache->frontend, sizeof (cache->frontend), 1, fp); - /* the gamma (and later) fields are not stored */ - fwrite (&cache->sensor, offsetof (Genesys_Sensor, gamma[0]), 1, fp); - - fwrite (&cache->calib_pixels, sizeof (cache->calib_pixels), 1, fp); - fwrite (&cache->calib_channels, sizeof (cache->calib_channels), 1, fp); - fwrite (&cache->average_size, sizeof (cache->average_size), 1, fp); - fwrite (cache->white_average_data, cache->average_size, 1, fp); - fwrite (cache->dark_average_data, cache->average_size, 1, fp); - } - DBGCOMPLETED; - fclose (fp); -} - -/** @brief buffer scanned picture - * In order to allow digital processing, we must be able to put all the - * scanned picture in a buffer. - */ -static SANE_Status -genesys_buffer_image(Genesys_Scanner *s) -{ - SANE_Status status = SANE_STATUS_GOOD; - size_t maximum; /**> maximum bytes size of the scan */ - size_t len; /**> length of scanned data read */ - size_t total; /**> total of butes read */ - size_t size; /**> size of image buffer */ - size_t read_size; /**> size of reads */ - int lines; /** number of lines of the scan */ - Genesys_Device *dev = s->dev; - SANE_Byte *lineart=NULL; - - /* compute maximum number of lines for the scan */ - if (s->params.lines > 0) - { - lines = s->params.lines; - } - else - { - lines = - (SANE_UNFIX (dev->model->y_size) * dev->settings.yres) / MM_PER_INCH; - } - DBG (DBG_info, "%s: buffering %d lines of %d bytes\n", __func__, lines, - s->params.bytes_per_line); - - /* maximum bytes to read */ - maximum = s->params.bytes_per_line * lines; - if(s->dev->settings.dynamic_lineart==SANE_TRUE) - { - maximum *= 8; - } - - /* initial size of the read buffer */ - size = - ((2048 * 2048) / s->params.bytes_per_line) * s->params.bytes_per_line; - - /* read size */ - read_size = size / 2; - - /* allocate memory */ - dev->img_buffer = (SANE_Byte *) malloc (size); - if (dev->img_buffer == NULL) - { - DBG (DBG_error, - "%s: digital processing requires too much memory.\nConsider disabling it\n", - __func__); - return SANE_STATUS_NO_MEM; - } - - /* loop reading data until we reach maximum or EOF */ - total = 0; - while (total < maximum && status != SANE_STATUS_EOF) - { - len = size - maximum; - if (len > read_size) - { - len = read_size; - } - status = genesys_read_ordered_data (dev, dev->img_buffer + total, &len); - if (status != SANE_STATUS_EOF && status != SANE_STATUS_GOOD) - { - free (s->dev->img_buffer); - DBG (DBG_error, "%s: %s buffering failed\n", __func__, - sane_strstatus (status)); - return status; - } - total += len; - - /* do we need to enlarge read buffer ? */ - if (total + read_size > size && status != SANE_STATUS_EOF) - { - size += read_size; - dev->img_buffer = (SANE_Byte *) realloc (dev->img_buffer, size); - if (dev->img_buffer == NULL) - { - DBG (DBG_error0, - "%s: digital processing requires too much memory.\nConsider disabling it\n", - __func__); - return SANE_STATUS_NO_MEM; - } - } - } - - /* since digital processing is going to take place, - * issue head parking command so that the head move while - * computing so we can save time - */ - if (dev->model->is_sheetfed == SANE_FALSE && - dev->parking == SANE_FALSE) - { - dev->model->cmd_set->slow_back_home (dev, dev->model->flags & GENESYS_FLAG_MUST_WAIT); - dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); - } - - /* in case of dynamic lineart, we have buffered gray data which - * must be converted to lineart first */ - if(s->dev->settings.dynamic_lineart==SANE_TRUE) - { - total/=8; - lineart=(SANE_Byte *)malloc(total); - if (lineart == NULL) - { - DBG (DBG_error0, - "%s: digital processing requires too much memory.\nConsider disabling it\n", - __func__); - return SANE_STATUS_NO_MEM; - } - genesys_gray_lineart (dev, - dev->img_buffer, - lineart, - dev->settings.pixels, - (total*8)/dev->settings.pixels, - dev->settings.threshold); - free(dev->img_buffer); - dev->img_buffer = lineart; - } - - /* update counters */ - dev->total_bytes_to_read = total; - dev->total_bytes_read = 0; - - /* update params */ - s->params.lines = total / s->params.bytes_per_line; - if (DBG_LEVEL >= DBG_io2) - { - sanei_genesys_write_pnm_file ("unprocessed.pnm", - dev->img_buffer, - s->params.depth, - s->params.format==SANE_FRAME_RGB ? 3:1, - s->params.pixels_per_line, - s->params.lines); - } - - return SANE_STATUS_GOOD; -} - -/* -------------------------- SANE API functions ------------------------- */ - -SANE_Status -sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) -{ - SANE_Status status; - - DBG_INIT (); - DBG (DBG_init, "SANE Genesys backend version %d.%d build %d from %s\n", - SANE_CURRENT_MAJOR, V_MINOR, BUILD, PACKAGE_STRING); -#ifdef HAVE_LIBUSB - DBG (DBG_init, "SANE Genesys backend built with libusb-1.0\n"); -#endif -#ifdef HAVE_LIBUSB_LEGACY - DBG (DBG_init, "SANE Genesys backend built with libusb\n"); -#endif - - if (version_code) - *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, BUILD); - - DBG (DBG_proc, "sane_init: authorize %s null\n", authorize ? "!=" : "=="); - - /* init usb use */ - sanei_usb_init (); - - /* init sanei_magic */ - sanei_magic_init(); - - DBG (DBG_info, "sane_init: %s endian machine\n", -#ifdef WORDS_BIGENDIAN - "big" -#else - "little" -#endif - ); - - /* set up to no devices at first */ - num_devices = 0; - first_dev = 0; - first_handle = 0; - devlist = 0; - - /* cold-plug case :detection of allready connected scanners */ - status = probe_genesys_devices (); - - DBGCOMPLETED; - - return status; -} - -void -sane_exit (void) -{ - Genesys_Device *dev, *next; - - DBGSTART; - for (dev = first_dev; dev; dev = next) - { - /* sane_close() free many fields, not much things left to - * do here */ - next = dev->next; - free (dev->file_name); - free (dev); - } - first_dev = 0; - first_handle = 0; - if (devlist) - free (devlist); - devlist = 0; - - sanei_usb_exit(); - - DBGCOMPLETED; -} - -SANE_Status -sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) -{ - Genesys_Device *dev, *prev; - SANE_Int index; - SANE_Device *sane_device; - - DBG (DBG_proc, "sane_get_devices: start: local_only = %s\n", - local_only == SANE_TRUE ? "true" : "false"); - - /* hot-plug case : detection of newly connected scanners */ - sanei_usb_scan_devices (); - probe_genesys_devices (); - - if (devlist) - free (devlist); - - devlist = malloc ((num_devices + 1) * sizeof (devlist[0])); - if (!devlist) - return SANE_STATUS_NO_MEM; - - prev = NULL; - index = 0; - dev = first_dev; - while (dev != NULL) - { - /* check if device removed */ - present = SANE_FALSE; - sanei_usb_find_devices (dev->vendorId, dev->productId, check_present); - if (present) - { - sane_device = malloc (sizeof (*sane_device)); - if (!sane_device) - return SANE_STATUS_NO_MEM; - sane_device->name = dev->file_name; - sane_device->vendor = dev->model->vendor; - sane_device->model = dev->model->model; - sane_device->type = strdup ("flatbed scanner"); - devlist[index] = sane_device; - index++; - prev = dev; - dev = dev->next; - } - else - { - /* remove device from internal list */ - /* case 1 : removed device is first_dev */ - if (prev == NULL) - { - /* test for another dev */ - if (dev->next == NULL) - { - /* empty the whole list */ - free (dev); - first_dev = NULL; - num_devices = 0; - dev = NULL; - } - else - { - /* assign new start */ - first_dev = dev->next; - num_devices--; - free (dev); - dev = first_dev; - } - } - /* case 2 : removed device is not first_dev */ - else - { - /* link previous dev to next dev */ - prev->next = dev->next; - free (dev); - num_devices--; - - /* next loop */ - dev = prev->next; - } - } - } - devlist[index] = 0; - - *device_list = devlist; - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -SANE_Status -sane_open (SANE_String_Const devicename, SANE_Handle * handle) -{ - Genesys_Device *dev; - SANE_Status status; - Genesys_Scanner *s; - char *tmpstr; - - DBG (DBG_proc, "sane_open: start (devicename = `%s')\n", devicename); - - /* devicename="" or devicename="genesys" are default values that use - * first available device - */ - if (devicename[0] && strcmp ("genesys", devicename) != 0) - { - /* search for the given devicename in the device list */ - for (dev = first_dev; dev; dev = dev->next) - if (strcmp (dev->file_name, devicename) == 0) - break; - - if (!dev) - { - DBG (DBG_info, - "sane_open: couldn't find `%s' in devlist, trying attach\n", - devicename); - RIE (attach (devicename, &dev, SANE_TRUE)); - } - else - DBG (DBG_info, "sane_open: found `%s' in devlist\n", - dev->model->name); - } - else - { - /* empty devicename or "genesys" -> use first device */ - dev = first_dev; - if (dev) - { - devicename = dev->file_name; - DBG (DBG_info, "sane_open: empty devicename, trying `%s'\n", - devicename); - } - } - - if (!dev) - return SANE_STATUS_INVAL; - - if (dev->model->flags & GENESYS_FLAG_UNTESTED) - { - DBG (DBG_error0, - "WARNING: Your scanner is not fully supported or at least \n"); - DBG (DBG_error0, - " had only limited testing. Please be careful and \n"); - DBG (DBG_error0, " report any failure/success to \n"); - DBG (DBG_error0, - " sane-devel@lists.alioth.debian.org. Please provide as many\n"); - DBG (DBG_error0, - " details as possible, e.g. the exact name of your\n"); - DBG (DBG_error0, " scanner and what does (not) work.\n"); - } - - status = sanei_usb_open (dev->file_name, &dev->dn); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_warn, "sane_open: couldn't open device `%s': %s\n", - dev->file_name, sane_strstatus (status)); - return status; - } - - - s = malloc (sizeof (*s)); - if (!s) - return SANE_STATUS_NO_MEM; - - s->dev = dev; - s->scanning = SANE_FALSE; - s->dev->read_buffer.buffer = NULL; - s->dev->lines_buffer.buffer = NULL; - s->dev->shrink_buffer.buffer = NULL; - s->dev->out_buffer.buffer = NULL; - s->dev->binarize_buffer.buffer = NULL; - s->dev->local_buffer.buffer = NULL; - s->dev->parking = SANE_FALSE; - s->dev->read_active = SANE_FALSE; - s->dev->white_average_data = NULL; - s->dev->dark_average_data = NULL; - s->dev->calibration_cache = NULL; - s->dev->calib_file = NULL; - s->dev->img_buffer = NULL; - s->dev->line_interp = 0; - s->dev->line_count = 0; - s->dev->segnb = 0; - s->dev->oe_buffer.buffer=NULL; - s->dev->binary=NULL; - - /* insert newly opened handle into list of open handles: */ - s->next = first_handle; - first_handle = s; - *handle = s; - - if (!dev->already_initialized) - sanei_genesys_init_structs (dev); - - RIE (init_options (s)); - - if (sanei_genesys_init_cmd_set (s->dev) != SANE_STATUS_GOOD) - { - DBG (DBG_error0, "This device doesn't have a valid command set!!\n"); - return SANE_STATUS_IO_ERROR; - } - - RIE (dev->model->cmd_set->init (dev)); - - /* some hardware capabilities are detected through sensors */ - RIE (s->dev->model->cmd_set->update_hardware_sensors (s)); - - /* here is the place to fetch a stored calibration cache */ - tmpstr=calibration_filename(s->dev); - s->val[OPT_CALIBRATION_FILE].s = strdup (tmpstr); - s->dev->calib_file = strdup (tmpstr); - DBG (DBG_info, "%s: Calibration filename set to:\n", __func__); - DBG (DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file); - free(tmpstr); - - /* now open file, fetch calibration records */ - - sanei_genesys_read_calibration (s->dev); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -void -sane_close (SANE_Handle handle) -{ - Genesys_Scanner *prev, *s; - Genesys_Calibration_Cache *cache, *next_cache; - SANE_Status status; - - DBGSTART; - - /* remove handle from list of open handles: */ - prev = 0; - for (s = first_handle; s; s = s->next) - { - if (s == handle) - break; - prev = s; - } - if (!s) - { - DBG (DBG_error, "sane_close: invalid handle %p\n", handle); - return; /* oops, not a handle we know about */ - } - - /* eject document for sheetfed scanners */ - if (s->dev->model->is_sheetfed == SANE_TRUE) - { - s->dev->model->cmd_set->eject_document (s->dev); - } - else - { - /* in case scanner is parking, wait for the head - * to reach home position */ - if(s->dev->parking==SANE_TRUE) - { - status = sanei_genesys_wait_for_home (s->dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sane_close: failed to wait for head to park: %s\n", - sane_strstatus (status)); - } - } - } - - /* enable power saving before leaving */ - status = s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sane_close: failed to enable power saving mode: %s\n", - sane_strstatus (status)); - } - - /* here is the place to store calibration cache */ - write_calibration (s->dev); - - for (cache = s->dev->calibration_cache; cache; cache = next_cache) - { - next_cache = cache->next; - free (cache->dark_average_data); - free (cache->white_average_data); - free (cache); - } - - sanei_genesys_buffer_free (&(s->dev->read_buffer)); - sanei_genesys_buffer_free (&(s->dev->lines_buffer)); - sanei_genesys_buffer_free (&(s->dev->shrink_buffer)); - sanei_genesys_buffer_free (&(s->dev->out_buffer)); - sanei_genesys_buffer_free (&(s->dev->binarize_buffer)); - sanei_genesys_buffer_free (&(s->dev->local_buffer)); - FREE_IFNOT_NULL (s->dev->white_average_data); - FREE_IFNOT_NULL (s->dev->dark_average_data); - FREE_IFNOT_NULL (s->dev->calib_file); - - /* free allocated gamma tables */ - FREE_IFNOT_NULL (s->dev->sensor.gamma_table[0]); - FREE_IFNOT_NULL (s->dev->sensor.gamma_table[1]); - FREE_IFNOT_NULL (s->dev->sensor.gamma_table[2]); - - s->dev->already_initialized = SANE_FALSE; - - /* for an handful of bytes .. */ - free ((void *)(size_t)s->opt[OPT_RESOLUTION].constraint.word_list); - free (s->val[OPT_SOURCE].s); - free (s->val[OPT_MODE].s); - free (s->val[OPT_COLOR_FILTER].s); - free ((void *)(size_t)s->opt[OPT_TL_X].constraint.range); - free ((void *)(size_t)s->opt[OPT_TL_Y].constraint.range); - - if (prev) - prev->next = s->next; - else - first_handle = s->next; - - /* LAMP OFF : same register across all the ASICs */ - sanei_genesys_write_register (s->dev, 0x03, 0x00); - - /* clear before closing */ - sanei_usb_clear_halt (s->dev->dn); - - /* we need this to avoid these ASIC getting stuck - * in bulk writes */ - sanei_usb_reset (s->dev->dn); - - sanei_usb_close (s->dev->dn); - free (s); - - DBGCOMPLETED; -} - -const SANE_Option_Descriptor * -sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) -{ - Genesys_Scanner *s = handle; - - if ((unsigned) option >= NUM_OPTIONS) - return 0; - DBG (DBG_io2, "sane_get_option_descriptor: option = %s (%d)\n", - s->opt[option].name, option); - return s->opt + option; -} - -/* gets an option , called by sane_control_option */ -static SANE_Status -get_option_value (Genesys_Scanner * s, int option, void *val) -{ - unsigned int i; - SANE_Word *table ,tmp; - uint16_t *gamma; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Calibration_Cache *cache; - - switch (option) - { - /* geometry */ - case OPT_TL_X: - case OPT_TL_Y: - case OPT_BR_X: - case OPT_BR_Y: - *(SANE_Word *) val = s->val[option].w; - /* switch coordinate to keep them coherent */ - if (s->val[OPT_TL_X].w >= s->val[OPT_BR_X].w) - { - tmp=s->val[OPT_BR_X].w; - s->val[OPT_BR_X].w=s->val[OPT_TL_X].w; - s->val[OPT_TL_X].w=tmp; - } - if (s->val[OPT_TL_Y].w >= s->val[OPT_BR_Y].w) - { - tmp=s->val[OPT_BR_Y].w; - s->val[OPT_BR_Y].w=s->val[OPT_TL_Y].w; - s->val[OPT_TL_Y].w=tmp; - } - break; - /* word options: */ - case OPT_NUM_OPTS: - case OPT_RESOLUTION: - case OPT_BIT_DEPTH: - case OPT_PREVIEW: - case OPT_THRESHOLD: - case OPT_THRESHOLD_CURVE: - case OPT_DISABLE_DYNAMIC_LINEART: - case OPT_DISABLE_INTERPOLATION: - case OPT_LAMP_OFF: - case OPT_LAMP_OFF_TIME: - case OPT_SWDESKEW: - case OPT_SWCROP: - case OPT_SWDESPECK: - case OPT_SWDEROTATE: - case OPT_SWSKIP: - case OPT_DESPECK: - case OPT_CONTRAST: - case OPT_BRIGHTNESS: - case OPT_EXPIRATION_TIME: - *(SANE_Word *) val = s->val[option].w; - break; - case OPT_CUSTOM_GAMMA: - *(SANE_Word *) val = s->val[option].w; - break; - - /* string options: */ - case OPT_MODE: - case OPT_COLOR_FILTER: - case OPT_CALIBRATION_FILE: - case OPT_SOURCE: - strcpy (val, s->val[option].s); - break; - - /* word array options */ - case OPT_GAMMA_VECTOR: - table = (SANE_Word *) val; - if (strcmp (s->val[OPT_COLOR_FILTER].s, "Red") == 0) - { - gamma = s->dev->sensor.gamma_table[GENESYS_RED]; - } - else if (strcmp (s->val[OPT_COLOR_FILTER].s, "Blue") == 0) - { - gamma = s->dev->sensor.gamma_table[GENESYS_BLUE]; - } - else - { - gamma = s->dev->sensor.gamma_table[GENESYS_GREEN]; - } - for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) - { - table[i] = gamma[i]; - } - break; - case OPT_GAMMA_VECTOR_R: - table = (SANE_Word *) val; - for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) - { - table[i] = s->dev->sensor.gamma_table[GENESYS_RED][i]; - } - break; - case OPT_GAMMA_VECTOR_G: - table = (SANE_Word *) val; - for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) - { - table[i] = s->dev->sensor.gamma_table[GENESYS_GREEN][i]; - } - break; - case OPT_GAMMA_VECTOR_B: - table = (SANE_Word *) val; - for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) - { - table[i] = s->dev->sensor.gamma_table[GENESYS_BLUE][i]; - } - break; - /* sensors */ - case OPT_SCAN_SW: - case OPT_FILE_SW: - case OPT_EMAIL_SW: - case OPT_COPY_SW: - case OPT_PAGE_LOADED_SW: - case OPT_OCR_SW: - case OPT_POWER_SW: - case OPT_EXTRA_SW: - RIE (s->dev->model->cmd_set->update_hardware_sensors (s)); - *(SANE_Bool *) val = s->val[option].b; - s->last_val[option].b = *(SANE_Bool *) val; - break; - case OPT_NEED_CALIBRATION_SW: - /* scanner needs calibration for current mode unless a matching - * calibration cache is found */ - *(SANE_Bool *) val = SANE_TRUE; - for (cache = s->dev->calibration_cache; cache; cache = cache->next) - { - if (s->dev->model-> - cmd_set->is_compatible_calibration (s->dev, cache, SANE_FALSE) == SANE_STATUS_GOOD) - { - *(SANE_Bool *) val = SANE_FALSE; - } - } - break; - default: - DBG (DBG_warn, "get_option_value: can't get unknown option %d\n", - option); - } - return status; -} - -/** @brief set calibration file value - * Set calibration file value. Load new cache values from file if it exists, - * else creates the file*/ -static SANE_Status set_calibration_value (Genesys_Scanner * s, int option, void *val) -{ - SANE_Status status=SANE_STATUS_GOOD; - char *tmp; - Genesys_Device *dev=s->dev; - - DBGSTART; - - /* try to load file */ - tmp=dev->calib_file; - dev->calib_file=val; - status=sanei_genesys_read_calibration (dev); - - /* file exists but is invalid, so fall back to previous cache file - * an re-read it */ - if (status!=SANE_STATUS_IO_ERROR && status!=SANE_STATUS_GOOD) - { - dev->calib_file=tmp; - status=sanei_genesys_read_calibration (dev); - return status; - } - - /* now we can set file name value */ - if (s->val[option].s) - free (s->val[option].s); - s->val[option].s = strdup (val); - if (tmp) - free (tmp); - dev->calib_file = strdup (val); - DBG (DBG_info, "%s: Calibration filename set to:\n", __func__); - DBG (DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* sets an option , called by sane_control_option */ -static SANE_Status -set_option_value (Genesys_Scanner * s, int option, void *val, - SANE_Int * myinfo) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Word *table; - unsigned int i; - SANE_Range *x_range, *y_range; - Genesys_Calibration_Cache *cache, *next_cache; - - switch (option) - { - case OPT_TL_X: - case OPT_TL_Y: - case OPT_BR_X: - case OPT_BR_Y: - s->val[option].w = *(SANE_Word *) val; - RIE (calc_parameters (s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_RESOLUTION: - case OPT_THRESHOLD: - case OPT_THRESHOLD_CURVE: - case OPT_DISABLE_DYNAMIC_LINEART: - case OPT_SWCROP: - case OPT_SWDESKEW: - case OPT_DESPECK: - case OPT_SWDEROTATE: - case OPT_SWSKIP: - case OPT_DISABLE_INTERPOLATION: - case OPT_LAMP_OFF: - case OPT_PREVIEW: - case OPT_BRIGHTNESS: - case OPT_CONTRAST: - s->val[option].w = *(SANE_Word *) val; - RIE (calc_parameters (s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_SWDESPECK: - s->val[option].w = *(SANE_Word *) val; - if (s->val[OPT_SWDESPECK].b == SANE_TRUE) - { - ENABLE(OPT_DESPECK); - } - else - { - DISABLE(OPT_DESPECK); - } - RIE (calc_parameters (s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - /* software enhancement functions only apply to 8 or 1 bits data */ - case OPT_BIT_DEPTH: - s->val[option].w = *(SANE_Word *) val; - if(s->val[OPT_BIT_DEPTH].w>8) - { - DISABLE(OPT_SWDESKEW); - DISABLE(OPT_SWDESPECK); - DISABLE(OPT_SWCROP); - DISABLE(OPT_DESPECK); - DISABLE(OPT_SWDEROTATE); - DISABLE(OPT_SWSKIP); - DISABLE(OPT_CONTRAST); - DISABLE(OPT_BRIGHTNESS); - } - else - { - ENABLE(OPT_SWDESKEW); - ENABLE(OPT_SWDESPECK); - ENABLE(OPT_SWCROP); - ENABLE(OPT_DESPECK); - ENABLE(OPT_SWDEROTATE); - ENABLE(OPT_SWSKIP); - ENABLE(OPT_CONTRAST); - ENABLE(OPT_BRIGHTNESS); - } - RIE (calc_parameters (s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - case OPT_SOURCE: - if (strcmp (s->val[option].s, val) != 0) - { /* something changed */ - if (s->val[option].s) - free (s->val[option].s); - s->val[option].s = strdup (val); - - /* change geometry constraint to the new source value */ - if (strcmp (s->val[option].s, FLATBED) == 0) - { - x_range=create_range(s->dev->model->x_size); - y_range=create_range(s->dev->model->y_size); - } - else - { - x_range=create_range(s->dev->model->x_size_ta); - y_range=create_range(s->dev->model->y_size_ta); - } - if(x_range==NULL || y_range==NULL) - { - return SANE_STATUS_NO_MEM; - } - - /* assign new values */ - free((void *)(size_t)s->opt[OPT_TL_X].constraint.range); - free((void *)(size_t)s->opt[OPT_TL_Y].constraint.range); - s->opt[OPT_TL_X].constraint.range = x_range; - s->val[OPT_TL_X].w = 0; - s->opt[OPT_TL_Y].constraint.range = y_range; - s->val[OPT_TL_Y].w = 0; - s->opt[OPT_BR_X].constraint.range = x_range; - s->val[OPT_BR_Y].w = y_range->max; - s->opt[OPT_BR_Y].constraint.range = y_range; - s->val[OPT_BR_X].w = x_range->max; - - /* signals reload */ - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - } - break; - case OPT_MODE: - if (s->val[option].s) - free (s->val[option].s); - s->val[option].s = strdup (val); - - if (strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_LINEART) == 0) - { - ENABLE (OPT_THRESHOLD); - ENABLE (OPT_THRESHOLD_CURVE); - DISABLE (OPT_BIT_DEPTH); - if (s->dev->model->asic_type != GENESYS_GL646 || !s->dev->model->is_cis) - { - ENABLE (OPT_COLOR_FILTER); - } - ENABLE (OPT_DISABLE_DYNAMIC_LINEART); - } - else - { - DISABLE (OPT_THRESHOLD); - DISABLE (OPT_THRESHOLD_CURVE); - DISABLE (OPT_DISABLE_DYNAMIC_LINEART); - if (strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_GRAY) == 0) - { - if (s->dev->model->asic_type != GENESYS_GL646 || !s->dev->model->is_cis) - { - ENABLE (OPT_COLOR_FILTER); - } - create_bpp_list (s, s->dev->model->bpp_gray_values); - } - else - { - DISABLE (OPT_COLOR_FILTER); - create_bpp_list (s, s->dev->model->bpp_color_values); - } - if (s->bpp_list[0] < 2) - DISABLE (OPT_BIT_DEPTH); - else - ENABLE (OPT_BIT_DEPTH); - } - RIE (calc_parameters (s)); - - /* if custom gamma, toggle gamma table options according to the mode */ - if (s->val[OPT_CUSTOM_GAMMA].b == SANE_TRUE) - { - if (strcmp (s->val[option].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) - { - DISABLE (OPT_GAMMA_VECTOR); - ENABLE (OPT_GAMMA_VECTOR_R); - ENABLE (OPT_GAMMA_VECTOR_G); - ENABLE (OPT_GAMMA_VECTOR_B); - } - else - { - ENABLE (OPT_GAMMA_VECTOR); - DISABLE (OPT_GAMMA_VECTOR_R); - DISABLE (OPT_GAMMA_VECTOR_G); - DISABLE (OPT_GAMMA_VECTOR_B); - } - } - - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - case OPT_COLOR_FILTER: - if (s->val[option].s) - free (s->val[option].s); - s->val[option].s = strdup (val); - RIE (calc_parameters (s)); - break; - case OPT_CALIBRATION_FILE: - RIE(set_calibration_value (s, option, val)); - break; - case OPT_LAMP_OFF_TIME: - case OPT_EXPIRATION_TIME: - if (*(SANE_Word *) val != s->val[option].w) - { - s->val[option].w = *(SANE_Word *) val; - RIE (s->dev->model->cmd_set-> - set_powersaving (s->dev, s->val[option].w)); - } - break; - - case OPT_CUSTOM_GAMMA: - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - s->val[OPT_CUSTOM_GAMMA].b = *(SANE_Bool *) val; - - if (s->val[OPT_CUSTOM_GAMMA].b == SANE_TRUE) - { - if (strcmp (s->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) - { - DISABLE (OPT_GAMMA_VECTOR); - ENABLE (OPT_GAMMA_VECTOR_R); - ENABLE (OPT_GAMMA_VECTOR_G); - ENABLE (OPT_GAMMA_VECTOR_B); - } - else - { - ENABLE (OPT_GAMMA_VECTOR); - DISABLE (OPT_GAMMA_VECTOR_R); - DISABLE (OPT_GAMMA_VECTOR_G); - DISABLE (OPT_GAMMA_VECTOR_B); - } - } - else - { - DISABLE (OPT_GAMMA_VECTOR); - DISABLE (OPT_GAMMA_VECTOR_R); - DISABLE (OPT_GAMMA_VECTOR_G); - DISABLE (OPT_GAMMA_VECTOR_B); - /* restore default sensor gamma table */ - /* currently there is no sensor's specific gamma table, - * tables are built by sanei_genesys_create_gamma_table */ - sanei_genesys_create_gamma_table (s->dev->sensor.gamma_table[GENESYS_RED], - s->opt[OPT_GAMMA_VECTOR_R].size / sizeof (SANE_Word), - s->opt[OPT_GAMMA_VECTOR_R].constraint.range->max, - s->opt[OPT_GAMMA_VECTOR_R].constraint.range->max, - s->dev->sensor.gamma[GENESYS_RED]); - sanei_genesys_create_gamma_table (s->dev->sensor.gamma_table[GENESYS_GREEN], - s->opt[OPT_GAMMA_VECTOR_G].size / sizeof (SANE_Word), - s->opt[OPT_GAMMA_VECTOR_G].constraint.range->max, - s->opt[OPT_GAMMA_VECTOR_G].constraint.range->max, - s->dev->sensor.gamma[GENESYS_GREEN]); - sanei_genesys_create_gamma_table (s->dev->sensor.gamma_table[GENESYS_BLUE], - s->opt[OPT_GAMMA_VECTOR_B].size / sizeof (SANE_Word), - s->opt[OPT_GAMMA_VECTOR_B].constraint.range->max, - s->opt[OPT_GAMMA_VECTOR_B].constraint.range->max, - s->dev->sensor.gamma[GENESYS_BLUE]); - } - break; - - case OPT_GAMMA_VECTOR: - table = (SANE_Word *) val; - for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) - { - s->dev->sensor.gamma_table[GENESYS_RED][i] = table[i]; - s->dev->sensor.gamma_table[GENESYS_GREEN][i] = table[i]; - s->dev->sensor.gamma_table[GENESYS_BLUE][i] = table[i]; - } - break; - case OPT_GAMMA_VECTOR_R: - table = (SANE_Word *) val; - for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) - { - s->dev->sensor.gamma_table[GENESYS_RED][i] = table[i]; - } - break; - case OPT_GAMMA_VECTOR_G: - table = (SANE_Word *) val; - for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) - { - s->dev->sensor.gamma_table[GENESYS_GREEN][i] = table[i]; - } - break; - case OPT_GAMMA_VECTOR_B: - table = (SANE_Word *) val; - for (i = 0; i < s->opt[option].size / sizeof (SANE_Word); i++) - { - s->dev->sensor.gamma_table[GENESYS_BLUE][i] = table[i]; - } - break; - case OPT_CALIBRATE: - status = s->dev->model->cmd_set->save_power (s->dev, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to disable power saving mode: %s\n", - __func__, sane_strstatus (status)); - } - else - status = genesys_scanner_calibration (s->dev); - /* not critical if this fails*/ - s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); - /* signals that sensors will have to be read again */ - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - case OPT_CLEAR_CALIBRATION: - /* clear calibration cache */ - if (s->dev->calibration_cache != NULL) - { - for (cache = s->dev->calibration_cache; cache; cache = next_cache) - { - next_cache = cache->next; - free (cache->dark_average_data); - free (cache->white_average_data); - free (cache); - } - } - s->dev->calibration_cache = NULL; - /* remove file */ - unlink (s->dev->calib_file); - /* signals that sensors will have to be read again */ - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - - default: - DBG (DBG_warn, "set_option_value: can't set unknown option %d\n", - option); - } - return status; -} - - -/* sets and gets scanner option values */ -SANE_Status -sane_control_option (SANE_Handle handle, SANE_Int option, - SANE_Action action, void *val, SANE_Int * info) -{ - Genesys_Scanner *s = handle; - SANE_Status status = SANE_STATUS_GOOD; - SANE_Word cap; - SANE_Int myinfo = 0; - - DBG (DBG_io2, - "sane_control_option: start: action = %s, option = %s (%d)\n", - (action == SANE_ACTION_GET_VALUE) ? "get" : (action == - SANE_ACTION_SET_VALUE) ? - "set" : (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown", - s->opt[option].name, option); - - if (info) - *info = 0; - - if (s->scanning) - { - DBG (DBG_warn, "sane_control_option: don't call this function while " - "scanning (option = %s (%d))\n", s->opt[option].name, option); - - return SANE_STATUS_DEVICE_BUSY; - } - if (option >= NUM_OPTIONS || option < 0) - { - DBG (DBG_warn, - "sane_control_option: option %d >= NUM_OPTIONS || option < 0\n", - option); - return SANE_STATUS_INVAL; - } - - cap = s->opt[option].cap; - - if (!SANE_OPTION_IS_ACTIVE (cap)) - { - DBG (DBG_warn, "sane_control_option: option %d is inactive\n", option); - return SANE_STATUS_INVAL; - } - - switch (action) - { - case SANE_ACTION_GET_VALUE: - status = get_option_value (s, option, val); - break; - - case SANE_ACTION_SET_VALUE: - if (!SANE_OPTION_IS_SETTABLE (cap)) - { - DBG (DBG_warn, "sane_control_option: option %d is not settable\n", - option); - return SANE_STATUS_INVAL; - } - - status = sanei_constrain_value (s->opt + option, val, &myinfo); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_warn, - "sane_control_option: sanei_constrain_value returned %s\n", - sane_strstatus (status)); - return status; - } - - status = set_option_value (s, option, val, &myinfo); - break; - - case SANE_ACTION_SET_AUTO: - DBG (DBG_error, - "sane_control_option: SANE_ACTION_SET_AUTO unsupported since no option has SANE_CAP_AUTOMATIC\n"); - status = SANE_STATUS_INVAL; - break; - - default: - DBG (DBG_warn, "sane_control_option: unknown action %d for option %d\n", - action, option); - status = SANE_STATUS_INVAL; - break; - } - - if (info) - *info = myinfo; - - DBG (DBG_io2, "sane_control_option: exit\n"); - return status; -} - - - -SANE_Status -sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) -{ - Genesys_Scanner *s = handle; - SANE_Status status; - - DBGSTART; - - /* don't recompute parameters once data reading is active, ie during scan */ - if(s->dev->read_active == SANE_FALSE) - { - RIE (calc_parameters (s)); - } - if (params) - { - *params = s->params; - - /* in the case of a sheetfed scanner, when full height is specified - * we override the computed line number with -1 to signal that we - * don't know the real document height. - * We don't do that doing buffering image for digital processing - */ - if (s->dev->model->is_sheetfed == SANE_TRUE - && s->dev->buffer_image == SANE_FALSE - && s->val[OPT_BR_Y].w == s->opt[OPT_BR_Y].constraint.range->max) - { - params->lines = -1; - } - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -SANE_Status -sane_start (SANE_Handle handle) -{ - Genesys_Scanner *s = handle; - SANE_Status status=SANE_STATUS_GOOD; - - DBGSTART; - - if (s->val[OPT_TL_X].w >= s->val[OPT_BR_X].w) - { - DBG (DBG_error0, - "sane_start: top left x >= bottom right x --- exiting\n"); - return SANE_STATUS_INVAL; - } - if (s->val[OPT_TL_Y].w >= s->val[OPT_BR_Y].w) - { - DBG (DBG_error0, - "sane_start: top left y >= bottom right y --- exiting\n"); - return SANE_STATUS_INVAL; - } - - /* First make sure we have a current parameter set. Some of the - parameters will be overwritten below, but that's OK. */ - - RIE (calc_parameters (s)); - RIE (genesys_start_scan (s->dev, s->val[OPT_LAMP_OFF].w)); - - s->scanning = SANE_TRUE; - - /* allocate intermediate buffer when doing dynamic lineart */ - if(s->dev->settings.dynamic_lineart==SANE_TRUE) - { - RIE (sanei_genesys_buffer_free (&(s->dev->binarize_buffer))); - RIE (sanei_genesys_buffer_alloc (&(s->dev->binarize_buffer), s->dev->settings.pixels)); - RIE (sanei_genesys_buffer_free (&(s->dev->local_buffer))); - RIE (sanei_genesys_buffer_alloc (&(s->dev->local_buffer), s->dev->binarize_buffer.size * 8)); - } - - /* if one of the software enhancement option is selected, - * we do the scan internally, process picture then put it an internal - * buffer. Since cropping may change scan parameters, we recompute them - * at the end */ - if (s->dev->buffer_image) - { - RIE(genesys_buffer_image(s)); - - /* check if we need to skip this page, sheetfed scanners - * can go to next doc while flatbed ones can't */ - if (s->val[OPT_SWSKIP].w && IS_ACTIVE(OPT_SWSKIP)) - { - status = sanei_magic_isBlank(&s->params, - s->dev->img_buffer, - SANE_UNFIX(s->val[OPT_SWSKIP].w)); - if(status == SANE_STATUS_NO_DOCS) - { - if (s->dev->model->is_sheetfed == SANE_TRUE) - { - DBG (DBG_info, "sane_start: blank page, recurse\n"); - return sane_start(handle); - } - return status; - } - } - - /* deskew image if required */ - if(s->val[OPT_SWDESKEW].b == SANE_TRUE) - { - RIE(genesys_deskew(s)); - } - - /* despeck image if required */ - if(s->val[OPT_SWDESPECK].b == SANE_TRUE) - { - RIE(genesys_despeck(s)); - } - - /* crop image if required */ - if(s->val[OPT_SWCROP].b == SANE_TRUE) - { - RIE(genesys_crop(s)); - } - - /* de-rotate image if required */ - if(s->val[OPT_SWDEROTATE].b == SANE_TRUE) - { - RIE(genesys_derotate(s)); - } - } - - DBGCOMPLETED; - return status; -} - -SANE_Status -sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, - SANE_Int * len) -{ - Genesys_Scanner *s = handle; - Genesys_Device *dev; - SANE_Status status=SANE_STATUS_GOOD; - size_t local_len; - - if (!s) - { - DBG (DBG_error, "sane_read: handle is null!\n"); - return SANE_STATUS_INVAL; - } - - dev=s->dev; - if (!dev) - { - DBG (DBG_error, "sane_read: dev is null!\n"); - return SANE_STATUS_INVAL; - } - - if (!buf) - { - DBG (DBG_error, "sane_read: buf is null!\n"); - return SANE_STATUS_INVAL; - } - - if (!len) - { - DBG (DBG_error, "sane_read: len is null!\n"); - return SANE_STATUS_INVAL; - } - - *len = 0; - - if (!s->scanning) - { - DBG (DBG_warn, "sane_read: scan was cancelled, is over or has not been " - "initiated yet\n"); - return SANE_STATUS_CANCELLED; - } - - DBG (DBG_proc, "sane_read: start, %d maximum bytes required\n", max_len); - DBG (DBG_io2, "sane_read: bytes_to_read=%lu, total_bytes_read=%lu\n", - (u_long) dev->total_bytes_to_read, (u_long) dev->total_bytes_read); - DBG (DBG_io2, "sane_read: physical bytes to read = %lu\n", (u_long) dev->read_bytes_left); - - if(dev->total_bytes_read>=dev->total_bytes_to_read) - { - DBG (DBG_proc, "sane_read: nothing more to scan: EOF\n"); - - /* issue park command immediatly in case scanner can handle it - * so we save time */ - if (dev->model->is_sheetfed == SANE_FALSE - && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) - && dev->parking == SANE_FALSE) - { - dev->model->cmd_set->slow_back_home (dev, SANE_FALSE); - dev->parking = SANE_TRUE; - } - return SANE_STATUS_EOF; - } - - local_len = max_len; - - /* in case of image processing, all data has been stored in - * buffer_image. So read data from it if it exists, else from scanner */ - if(!dev->buffer_image) - { - /* dynamic lineart is another kind of digital processing that needs - * another layer of buffering on top of genesys_read_ordered_data */ - if(dev->settings.dynamic_lineart==SANE_TRUE) - { - /* if buffer is empty, fill it with genesys_read_ordered_data */ - if(dev->binarize_buffer.avail==0) - { - /* store gray data */ - local_len=dev->local_buffer.size; - status = genesys_read_ordered_data (dev, dev->local_buffer.buffer, &local_len); - - /* binarize data is read successful */ - if(status==SANE_STATUS_GOOD) - { - dev->local_buffer.avail=local_len; - dev->local_buffer.pos=0; - dev->binarize_buffer.avail=local_len/8; - dev->binarize_buffer.pos=0; - genesys_gray_lineart (dev, - dev->local_buffer.buffer, - dev->binarize_buffer.buffer, - dev->settings.pixels, - local_len/dev->settings.pixels, - dev->settings.threshold); - } - - } - - /* return data from lineart buffer if any, up to the available amount */ - local_len = max_len; - if((size_t)max_len>dev->binarize_buffer.avail) - { - local_len=dev->binarize_buffer.avail; - } - if(local_len) - { - memcpy(buf,sanei_genesys_buffer_get_read_pos (&(dev->binarize_buffer)),local_len); - RIE (sanei_genesys_buffer_consume (&(dev->binarize_buffer), local_len)); - } - } - else - { - /* most usual case, direct read of data from scanner */ - status = genesys_read_ordered_data (dev, buf, &local_len); - } - } - else /* read data from buffer */ - { - if(dev->total_bytes_read+local_len>dev->total_bytes_to_read) - { - local_len=dev->total_bytes_to_read-dev->total_bytes_read; - } - memcpy(buf,dev->img_buffer+dev->total_bytes_read,local_len); - dev->total_bytes_read+=local_len; - } - - *len = local_len; - if(local_len>(size_t)max_len) - { - fprintf (stderr, "[genesys] sane_read: returning incorrect length!!\n"); - } - DBG (DBG_proc, "sane_read: %d bytes returned\n", *len); - return status; -} - -void -sane_cancel (SANE_Handle handle) -{ - Genesys_Scanner *s = handle; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - /* end binary logging if needed */ - if (s->dev->binary!=NULL) - { - fclose(s->dev->binary); - s->dev->binary=NULL; - } - - s->scanning = SANE_FALSE; - s->dev->read_active = SANE_FALSE; - if(s->dev->img_buffer!=NULL) - { - free(s->dev->img_buffer); - s->dev->img_buffer=NULL; - } - - /* no need to end scan if we are parking the head */ - if(s->dev->parking==SANE_FALSE) - { - status = s->dev->model->cmd_set->end_scan (s->dev, s->dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sane_cancel: failed to end scan: %s\n", - sane_strstatus (status)); - return; - } - } - - /* park head if flatbed scanner */ - if (s->dev->model->is_sheetfed == SANE_FALSE) - { - if(s->dev->parking==SANE_FALSE) - { - status = s->dev->model->cmd_set->slow_back_home (s->dev, s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sane_cancel: failed to move scanhead to home position: %s\n", - sane_strstatus (status)); - return; - } - s->dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); - } - } - else - { /* in case of sheetfed scanners, we have to eject the document if still present */ - status = s->dev->model->cmd_set->eject_document (s->dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sane_cancel: failed to eject document: %s\n", - sane_strstatus (status)); - return; - } - } - - /* enable power saving mode unless we are parking .... */ - if(s->dev->parking==SANE_FALSE) - { - status = s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sane_cancel: failed to enable power saving mode: %s\n", - sane_strstatus (status)); - return; - } - } - - DBGCOMPLETED; - return; -} - -SANE_Status -sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) -{ - Genesys_Scanner *s = handle; - - DBG (DBG_proc, "sane_set_io_mode: handle = %p, non_blocking = %s\n", - handle, non_blocking == SANE_TRUE ? "true" : "false"); - - if (!s->scanning) - { - DBG (DBG_error, "sane_set_io_mode: not scanning\n"); - return SANE_STATUS_INVAL; - } - if (non_blocking) - return SANE_STATUS_UNSUPPORTED; - return SANE_STATUS_GOOD; -} - -SANE_Status -sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) -{ - Genesys_Scanner *s = handle; - - DBG (DBG_proc, "sane_get_select_fd: handle = %p, fd = %p\n", handle, - (void *) fd); - - if (!s->scanning) - { - DBG (DBG_error, "sane_get_select_fd: not scanning\n"); - return SANE_STATUS_INVAL; - } - return SANE_STATUS_UNSUPPORTED; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys.cc b/backend/genesys.cc new file mode 100644 index 0000000..0368e21 --- /dev/null +++ b/backend/genesys.cc @@ -0,0 +1,7580 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003, 2004 Henning Meier-Geinitz + Copyright (C) 2004, 2005 Gerhard Jaeger + Copyright (C) 2004-2016 Stéphane Voltz + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2006 Laurent Charpentier + Copyright (C) 2007 Luke + Copyright (C) 2010 Chris Berry and Michael Rickmann + for Plustek Opticbook 3600 support + + Dynamic rasterization code was taken from the epjistsu backend by + m. allan noah + + Software processing for deskew, crop and dspeckle are inspired by allan's + noah work in the fujitsu backend + + 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. +*/ + +/* + * SANE backend for Genesys Logic GL646/GL841/GL842/GL843/GL846/GL847/GL124 based scanners + */ + +#define DEBUG_NOT_STATIC + +#include "genesys.h" +#include "genesys_sanei.h" +#include "../include/sane/sanei_config.h" +#include "../include/sane/sanei_magic.h" +#include "genesys_devices.cc" + +#include +#include +#include +#include +#include + +StaticInit> s_scanners; +StaticInit> s_sane_devices; +StaticInit> s_sane_devices_ptrs; +StaticInit> s_devices; + +static SANE_String_Const mode_list[] = { + SANE_VALUE_SCAN_MODE_COLOR, + SANE_VALUE_SCAN_MODE_GRAY, + /* SANE_TITLE_HALFTONE, currently unused */ + SANE_VALUE_SCAN_MODE_LINEART, + 0 +}; + +static SANE_String_Const color_filter_list[] = { + SANE_I18N ("Red"), + SANE_I18N ("Green"), + SANE_I18N ("Blue"), + 0 +}; + +static SANE_String_Const cis_color_filter_list[] = { + SANE_I18N ("Red"), + SANE_I18N ("Green"), + SANE_I18N ("Blue"), + SANE_I18N ("None"), + 0 +}; + +static SANE_String_Const source_list[] = { + SANE_I18N (STR_FLATBED), + SANE_I18N (STR_TRANSPARENCY_ADAPTER), + 0 +}; + +static const char* source_list_infrared[] = { + SANE_I18N(STR_FLATBED), + SANE_I18N(STR_TRANSPARENCY_ADAPTER), + SANE_I18N(STR_TRANSPARENCY_ADAPTER_INFRARED), + 0 +}; + +static SANE_Range swdespeck_range = { + 1, + 9, + 1 +}; + +static SANE_Range time_range = { + 0, /* minimum */ + 60, /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range u12_range = { + 0, /* minimum */ + 4095, /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range u14_range = { + 0, /* minimum */ + 16383, /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range u16_range = { + 0, /* minimum */ + 65535, /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range percentage_range = { + SANE_FIX (0), /* minimum */ + SANE_FIX (100), /* maximum */ + SANE_FIX (1) /* quantization */ +}; + +static const SANE_Range threshold_curve_range = { + 0, /* minimum */ + 127, /* maximum */ + 1 /* quantization */ +}; + +/** + * range for brightness and contrast + */ +static const SANE_Range enhance_range = { + -100, /* minimum */ + 100, /* maximum */ + 1 /* quantization */ +}; + +/** + * range for expiration time + */ +static const SANE_Range expiration_range = { + -1, /* minimum */ + 30000, /* maximum */ + 1 /* quantization */ +}; + +Genesys_Sensor& sanei_genesys_find_sensor_any_for_write(Genesys_Device* dev) +{ + for (auto& sensor : *s_sensors) { + if (dev->model->ccd_type == sensor.sensor_id) { + return sensor; + } + } + throw std::runtime_error("Given device does not have sensor defined"); +} + +const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev) +{ + for (const auto& sensor : *s_sensors) { + if (dev->model->ccd_type == sensor.sensor_id) { + return sensor; + } + } + throw std::runtime_error("Given device does not have sensor defined"); +} + +const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, int dpi, + ScanMethod scan_method) +{ + for (const auto& sensor : *s_sensors) { + if (dev->model->ccd_type == sensor.sensor_id && + (sensor.min_resolution == -1 || dpi >= sensor.min_resolution) && + (sensor.max_resolution == -1 || dpi <= sensor.max_resolution) && + sensor.method == scan_method) { + return sensor; + } + } + throw std::runtime_error("Given device does not have sensor defined"); +} + +Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, int dpi, + ScanMethod scan_method) +{ + for (auto& sensor : *s_sensors) { + if (dev->model->ccd_type == sensor.sensor_id && + (sensor.min_resolution == -1 || dpi >= sensor.min_resolution) && + (sensor.max_resolution == -1 || dpi <= sensor.max_resolution) && + sensor.method == scan_method) { + return sensor; + } + } + throw std::runtime_error("Given device does not have sensor defined"); +} + + +void +sanei_genesys_init_structs (Genesys_Device * dev) +{ + unsigned int i, gpo_ok = 0, motor_ok = 0; + bool fe_ok = false; + + /* initialize the GPO data stuff */ + for (i = 0; i < sizeof (Gpo) / sizeof (Genesys_Gpo); i++) + { + if (dev->model->gpo_type == Gpo[i].gpo_id) + { + dev->gpo = Gpo[i]; + gpo_ok = 1; + } + } + + /* initialize the motor data stuff */ + for (i = 0; i < sizeof (Motor) / sizeof (Genesys_Motor); i++) + { + if (dev->model->motor_type == Motor[i].motor_id) + { + dev->motor = Motor[i]; + motor_ok = 1; + } + } + + for (const auto& frontend : *s_frontends) { + if (dev->model->dac_type == frontend.fe_id) { + dev->frontend_initial = frontend; + fe_ok = true; + break; + } + } + + /* sanity check */ + if (motor_ok == 0 || gpo_ok == 0 || !fe_ok) + { + DBG(DBG_error0, "%s: bad description(s) for fe/gpo/motor=%d/%d/%d\n", __func__, + dev->model->ccd_type, dev->model->gpo_type, dev->model->motor_type); + } + + /* set up initial line distance shift */ + dev->ld_shift_r = dev->model->ld_shift_r; + dev->ld_shift_g = dev->model->ld_shift_g; + dev->ld_shift_b = dev->model->ld_shift_b; +} + +/* main function for slope creation */ +/** + * This function generates a slope table using the given slope + * truncated at the given exposure time or step count, whichever comes first. + * The reached step time is then stored in final_exposure and used for the rest + * of the table. The summed time of the acceleration steps is returned, and the + * number of accerelation steps is put into used_steps. + * + * @param slope_table Table to write to + * @param max_steps Size of slope_table in steps + * @param use_steps Maximum number of steps to use for acceleration + * @param stop_at Minimum step time to use + * @param vstart Start step time of default slope + * @param vend End step time of default slope + * @param steps Step count of default slope + * @param g Power for default slope + * @param used_steps Final number of steps is stored here + * @param vfinal Final step time is stored here + * @return Time for acceleration + * @note All times in pixel time. Correction for other motor timings is not + * done. + */ +SANE_Int +sanei_genesys_generate_slope_table (uint16_t * slope_table, + unsigned int max_steps, + unsigned int use_steps, + uint16_t stop_at, + uint16_t vstart, + uint16_t vend, + unsigned int steps, + double g, + unsigned int *used_steps, + unsigned int *vfinal) +{ + double t; + SANE_Int sum = 0; + unsigned int i; + unsigned int c = 0; + uint16_t t2; + unsigned int dummy; + unsigned int _vfinal; + if (!used_steps) + used_steps = &dummy; + if (!vfinal) + vfinal = &_vfinal; + + DBG(DBG_proc, "%s: table size: %d\n", __func__, max_steps); + + DBG(DBG_proc, "%s: stop at time: %d, use %d steps max\n", __func__, stop_at, use_steps); + + DBG(DBG_proc, "%s: target slope: vstart: %d, vend: %d, steps: %d, g: %g\n", __func__, vstart, + vend, steps, g); + + sum = 0; + c = 0; + *used_steps = 0; + + if (use_steps < 1) + use_steps = 1; + + if (stop_at < vstart) + { + t2 = vstart; + for (i = 0; i < steps && i < use_steps - 1 && i < max_steps; i++, c++) + { + t = pow (((double) i) / ((double) (steps - 1)), g); + t2 = vstart * (1 - t) + t * vend; + if (t2 < stop_at) + break; + *slope_table++ = t2; + /* DBG (DBG_io, "slope_table[%3d] = %5d\n", c, t2); */ + sum += t2; + } + if (t2 > stop_at) + { + DBG(DBG_warn, "Can not reach target speed(%d) in %d steps.\n", stop_at, use_steps); + DBG(DBG_warn, "Expect image to be distorted. Ignore this if only feeding.\n"); + } + *vfinal = t2; + *used_steps += i; + max_steps -= i; + } + else + *vfinal = stop_at; + + for (i = 0; i < max_steps; i++, c++) + { + *slope_table++ = *vfinal; + /* DBG (DBG_io, "slope_table[%3d] = %5d\n", c, *vfinal); */ + } + + (*used_steps)++; + sum += *vfinal; + + DBG(DBG_proc, "%s: returns sum=%d, used %d steps, completed\n", __func__, sum, *used_steps); + + return sum; +} + +/* Generate slope table for motor movement */ +/** + * This function generates a slope table using the slope from the motor struct + * truncated at the given exposure time or step count, whichever comes first. + * The reached step time is then stored in final_exposure and used for the rest + * of the table. The summed time of the acceleration steps is returned, and the + * number of accerelation steps is put into used_steps. + * + * @param dev Device struct + * @param slope_table Table to write to + * @param max_step Size of slope_table in steps + * @param use_steps Maximum number of steps to use for acceleration + * @param step_type Generate table for this step_type. 0=>full, 1=>half, + * 2=>quarter + * @param exposure_time Minimum exposure time of a scan line + * @param yres Resolution of a scan line + * @param used_steps Final number of steps is stored here + * @param final_exposure Final step time is stored here + * @param power_mode Power mode (related to the Vref used) of the motor + * @return Time for acceleration + * @note all times in pixel time + */ +SANE_Int +sanei_genesys_create_slope_table3 (Genesys_Device * dev, + uint16_t * slope_table, + int max_step, + unsigned int use_steps, + int step_type, + int exposure_time, + double yres, + unsigned int *used_steps, + unsigned int *final_exposure, + int power_mode) +{ + unsigned int sum_time = 0; + unsigned int vtarget; + unsigned int vend; + unsigned int vstart; + unsigned int vfinal; + + DBG(DBG_proc, "%s: step_type = %d, exposure_time = %d, yres = %g, power_mode = %d\n", __func__, + step_type, exposure_time, yres, power_mode); + + /* final speed */ + vtarget = (exposure_time * yres) / dev->motor.base_ydpi; + + vstart = dev->motor.slopes[power_mode][step_type].maximum_start_speed; + vend = dev->motor.slopes[power_mode][step_type].maximum_speed; + + vtarget >>= step_type; + if (vtarget > 65535) + vtarget = 65535; + + vstart >>= step_type; + if (vstart > 65535) + vstart = 65535; + + vend >>= step_type; + if (vend > 65535) + vend = 65535; + + sum_time = sanei_genesys_generate_slope_table (slope_table, + max_step, + use_steps, + vtarget, + vstart, + vend, + dev->motor.slopes[power_mode][step_type].minimum_steps << step_type, + dev->motor.slopes[power_mode][step_type].g, + used_steps, + &vfinal); + + if (final_exposure) + *final_exposure = (vfinal * dev->motor.base_ydpi) / yres; + + DBG(DBG_proc, "%s: returns sum_time=%d, completed\n", __func__, sum_time); + + return sum_time; +} + + +/* alternate slope table creation function */ +/* the hardcoded values (g and vstart) will go in a motor struct */ +static SANE_Int +genesys_create_slope_table2 (Genesys_Device * dev, + uint16_t * slope_table, int steps, + int step_type, int exposure_time, + SANE_Bool same_speed, double yres, + int power_mode) +{ + double t, g; + SANE_Int sum = 0; + int vstart, vend; + int i; + + DBG(DBG_proc, "%s: %d steps, step_type = %d, " + "exposure_time = %d, same_speed = %d, yres = %.2f, power_mode = %d\n", __func__, steps, + step_type, exposure_time, same_speed, yres, power_mode); + + /* start speed */ + if (dev->model->motor_type == MOTOR_5345) + { + if (yres < dev->motor.base_ydpi / 6) + vstart = 2500; + else + vstart = 2000; + } + else + { + if (steps == 2) + vstart = exposure_time; + else if (steps == 3) + vstart = 2 * exposure_time; + else if (steps == 4) + vstart = 1.5 * exposure_time; + else if (steps == 120) + vstart = 1.81674 * exposure_time; + else + vstart = exposure_time; + } + + /* final speed */ + vend = (exposure_time * yres) / (dev->motor.base_ydpi * (1 << step_type)); + + /* + type=1 : full + type=2 : half + type=4 : quarter + vend * type * base_ydpi / exposure = yres + */ + + /* acceleration */ + switch (steps) + { + case 255: + /* test for special case: fast moving slope */ + /* todo: a 'fast' boolean parameter should be better */ + if (vstart == 2000) + g = 0.2013; + else + g = 0.1677; + break; + case 120: + g = 0.5; + break; + case 67: + g = 0.5; + break; + case 64: + g = 0.2555; + break; + case 44: + g = 0.5; + break; + case 4: + g = 0.5; + break; + case 3: + g = 1; + break; + case 2: + vstart = vend; + g = 1; + break; + default: + g = 0.2635; + } + + /* if same speed, no 'g' */ + sum = 0; + if (same_speed) + { + for (i = 0; i < 255; i++) + { + slope_table[i] = vend; + sum += slope_table[i]; + DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); + } + } + else + { + for (i = 0; i < steps; i++) + { + t = pow (((double) i) / ((double) (steps - 1)), g); + slope_table[i] = vstart * (1 - t) + t * vend; + DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); + sum += slope_table[i]; + } + for (i = steps; i < 255; i++) + { + slope_table[i] = vend; + DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); + sum += slope_table[i]; + } + } + + DBG(DBG_proc, "%s: returns sum=%d, completed\n", __func__, sum); + + return sum; +} + +/* Generate slope table for motor movement */ +/* todo: check details */ +SANE_Int +sanei_genesys_create_slope_table (Genesys_Device * dev, + uint16_t * slope_table, int steps, + int step_type, int exposure_time, + SANE_Bool same_speed, double yres, + int power_mode) +{ + double t; + double start_speed; + double g; + uint32_t time_period; + int sum_time = 0; + int i, divider; + int same_step; + + if (dev->model->motor_type == MOTOR_5345 + || dev->model->motor_type == MOTOR_HP2300 + || dev->model->motor_type == MOTOR_HP2400) + return genesys_create_slope_table2 (dev, slope_table, steps, + step_type, exposure_time, + same_speed, yres, power_mode); + + DBG(DBG_proc, "%s: %d steps, step_type = %d, exposure_time = %d, same_speed =%d\n", __func__, + steps, step_type, exposure_time, same_speed); + DBG(DBG_proc, "%s: yres = %.2f\n", __func__, yres); + + g = 0.6; + start_speed = 0.01; + same_step = 4; + divider = 1 << step_type; + + time_period = + (uint32_t) (yres * exposure_time / dev->motor.base_ydpi /*MOTOR_GEAR */ ); + if ((time_period < 2000) && (same_speed)) + same_speed = SANE_FALSE; + + time_period = time_period / divider; + + if (same_speed) + { + for (i = 0; i < steps; i++) + { + slope_table[i] = (uint16_t) time_period; + sum_time += time_period; + + DBG (DBG_io, "slope_table[%d] = %d\n", i, time_period); + } + DBG(DBG_info, "%s: returns sum_time=%d, completed\n", __func__, sum_time); + return sum_time; + } + + if (time_period > MOTOR_SPEED_MAX * 5) + { + g = 1.0; + start_speed = 0.05; + same_step = 2; + } + else if (time_period > MOTOR_SPEED_MAX * 4) + { + g = 0.8; + start_speed = 0.04; + same_step = 2; + } + else if (time_period > MOTOR_SPEED_MAX * 3) + { + g = 0.7; + start_speed = 0.03; + same_step = 2; + } + else if (time_period > MOTOR_SPEED_MAX * 2) + { + g = 0.6; + start_speed = 0.02; + same_step = 3; + } + + if (dev->model->motor_type == MOTOR_ST24) + { + steps = 255; + switch ((int) yres) + { + case 2400: + g = 0.1672; + start_speed = 1.09; + break; + case 1200: + g = 1; + start_speed = 6.4; + break; + case 600: + g = 0.1672; + start_speed = 1.09; + break; + case 400: + g = 0.2005; + start_speed = 20.0 / 3.0 /*7.5 */ ; + break; + case 300: + g = 0.253; + start_speed = 2.182; + break; + case 150: + g = 0.253; + start_speed = 4.367; + break; + default: + g = 0.262; + start_speed = 7.29; + } + same_step = 1; + } + + if (steps <= same_step) + { + time_period = + (uint32_t) (yres * exposure_time / + dev->motor.base_ydpi /*MOTOR_GEAR */ ); + time_period = time_period / divider; + + if (time_period > 65535) + time_period = 65535; + + for (i = 0; i < same_step; i++) + { + slope_table[i] = (uint16_t) time_period; + sum_time += time_period; + + DBG (DBG_io, "slope_table[%d] = %d\n", i, time_period); + } + + DBG(DBG_proc, "%s: returns sum_time=%d, completed\n", __func__, sum_time); + return sum_time; + } + + for (i = 0; i < steps; i++) + { + double j = ((double) i) - same_step + 1; /* start from 1/16 speed */ + + if (j <= 0) + t = 0; + else + t = pow (j / (steps - same_step), g); + + time_period = /* time required for full steps */ + (uint32_t) (yres * exposure_time / + dev->motor.base_ydpi /*MOTOR_GEAR */ * + (start_speed + (1 - start_speed) * t)); + + time_period = time_period / divider; + if (time_period > 65535) + time_period = 65535; + + slope_table[i] = (uint16_t) time_period; + sum_time += time_period; + + DBG (DBG_io, "slope_table[%d] = %d\n", i, slope_table[i]); + } + + DBG(DBG_proc, "%s: returns sum_time=%d, completed\n", __func__, sum_time); + + return sum_time; +} + +/** @brief computes gamma table + * Generates a gamma table of the given length within 0 and the given + * maximum value + * @param gamma_table gamma table to fill + * @param size size of the table + * @param maximum value allowed for gamma + * @param gamma_max maximum gamma value + * @param gamma gamma to compute values + * @return a gamma table filled with the computed values + * */ +void +sanei_genesys_create_gamma_table (std::vector& gamma_table, int size, + float maximum, float gamma_max, float gamma) +{ + gamma_table.clear(); + gamma_table.resize(size, 0); + + int i; + float value; + + DBG(DBG_proc, "%s: size = %d, ""maximum = %g, gamma_max = %g, gamma = %g\n", __func__, size, + maximum, gamma_max, gamma); + for (i = 0; i < size; i++) + { + value = gamma_max * pow ((float) i / size, 1.0 / gamma); + if (value > maximum) + value = maximum; + gamma_table[i] = value; + } + DBG(DBG_proc, "%s: completed\n", __func__); +} + +void sanei_genesys_create_default_gamma_table(Genesys_Device* dev, + std::vector& gamma_table, float gamma) +{ + int size = 0; + int max = 0; + if (dev->model->asic_type == GENESYS_GL646) { + if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) { + size = 16384; + } else { + size = 4096; + } + max = size - 1; + } else { + size = 256; + max = 65535; + } + sanei_genesys_create_gamma_table(gamma_table, size, max, max, gamma); +} + +/* computes the exposure_time on the basis of the given vertical dpi, + the number of pixels the ccd needs to send, + the step_type and the corresponding maximum speed from the motor struct */ +/* + Currently considers maximum motor speed at given step_type, minimum + line exposure needed for conversion and led exposure time. + + TODO: Should also consider maximum transfer rate: ~6.5MB/s. + Note: The enhance option of the scanners does _not_ help. It only halves + the amount of pixels transfered. + */ +SANE_Int +sanei_genesys_exposure_time2 (Genesys_Device * dev, float ydpi, + int step_type, int endpixel, + int exposure_by_led, int power_mode) +{ + int exposure_by_ccd = endpixel + 32; + int exposure_by_motor = + (dev->motor.slopes[power_mode][step_type].maximum_speed + * dev->motor.base_ydpi) / ydpi; + + int exposure = exposure_by_ccd; + + if (exposure < exposure_by_motor) + exposure = exposure_by_motor; + + if (exposure < exposure_by_led && dev->model->is_cis) + exposure = exposure_by_led; + + DBG(DBG_info, "%s: ydpi=%d, step=%d, endpixel=%d led=%d, power=%d => exposure=%d\n", __func__, + (int)ydpi, step_type, endpixel, exposure_by_led, power_mode, exposure); + return exposure; +} + +/* computes the exposure_time on the basis of the given horizontal dpi */ +/* we will clean/simplify it by using constants from a future motor struct */ +SANE_Int +sanei_genesys_exposure_time (Genesys_Device * dev, Genesys_Register_Set * reg, + int xdpi) +{ + if (dev->model->motor_type == MOTOR_5345) + { + if (dev->model->cmd_set->get_filter_bit (reg)) + { + /* monochrome */ + switch (xdpi) + { + case 600: + return 8500; + case 500: + case 400: + case 300: + case 250: + case 200: + case 150: + return 5500; + case 100: + return 6500; + case 50: + return 12000; + default: + return 11000; + } + } + else + { + /* color scan */ + switch (xdpi) + { + case 300: + case 250: + case 200: + return 5500; + case 50: + return 12000; + default: + return 11000; + } + } + } + else if (dev->model->motor_type == MOTOR_HP2400) + { + if (dev->model->cmd_set->get_filter_bit (reg)) + { + /* monochrome */ + switch (xdpi) + { + case 200: + return 7210; + default: + return 11111; + } + } + else + { + /* color scan */ + switch (xdpi) + { + case 600: + return 8751; /*11902; 19200 */ + default: + return 11111; + } + } + } + else if (dev->model->motor_type == MOTOR_HP2300) + { + if (dev->model->cmd_set->get_filter_bit (reg)) + { + /* monochrome */ + switch (xdpi) + { + case 600: + return 8699; /* 3200; */ + case 300: + return 3200; /*10000;, 3200 -> too dark */ + case 150: + return 4480; /* 3200 ???, warmup needs 4480 */ + case 75: + return 5500; + default: + return 11111; + } + } + else + { + /* color scan */ + switch (xdpi) + { + case 600: + return 8699; + case 300: + return 4349; + case 150: + case 75: + return 4480; + default: + return 11111; + } + } + } + return 11000; +} + + + +/* Sends a block of shading information to the scanner. + The data is placed at address 0x0000 for color mode, gray mode and + unconditionally for the following CCD chips: HP2300, HP2400 and HP5345 + In the other cases (lineart, halftone on ccd chips not mentioned) the + addresses are 0x2a00 for dpihw==0, 0x5500 for dpihw==1 and 0xa800 for + dpihw==2. //Note: why this? + + The data needs to be of size "size", and in little endian byte order. + */ +static SANE_Status +genesys_send_offset_and_shading (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, + int size) +{ + int dpihw; + int start_address; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s: (size = %d)\n", __func__, size); + + /* ASIC higher than gl843 doesn't have register 2A/2B, so we route to + * a per ASIC shading data loading function if available. + * It is also used for scanners using SHDAREA */ + if(dev->model->cmd_set->send_shading_data!=NULL) + { + status=dev->model->cmd_set->send_shading_data(dev, sensor, data, size); + DBGCOMPLETED; + return status; + } + + /* gl646, gl84[123] case */ + dpihw = dev->reg.get8(0x05) >> 6; + + /* TODO invert the test so only the 2 models behaving like that are + * tested instead of adding all the others */ + /* many scanners send coefficient for lineart/gray like in color mode */ + if ((dev->settings.scan_mode == ScanColorMode::LINEART || + dev->settings.scan_mode == ScanColorMode::HALFTONE) + && dev->model->ccd_type != CCD_PLUSTEK3800 + && dev->model->ccd_type != CCD_KVSS080 + && dev->model->ccd_type != CCD_G4050 + && dev->model->ccd_type != CCD_CS4400F + && dev->model->ccd_type != CCD_CS8400F + && dev->model->ccd_type != CCD_CS8600F + && dev->model->ccd_type != CCD_DSMOBILE600 + && dev->model->ccd_type != CCD_XP300 + && dev->model->ccd_type != CCD_DP665 + && dev->model->ccd_type != CCD_DP685 + && dev->model->ccd_type != CIS_CANONLIDE80 + && dev->model->ccd_type != CCD_ROADWARRIOR + && dev->model->ccd_type != CCD_HP2300 + && dev->model->ccd_type != CCD_HP2400 + && dev->model->ccd_type != CCD_HP3670 + && dev->model->ccd_type != CCD_5345) /* lineart, halftone */ + { + if (dpihw == 0) /* 600 dpi */ + start_address = 0x02a00; + else if (dpihw == 1) /* 1200 dpi */ + start_address = 0x05500; + else if (dpihw == 2) /* 2400 dpi */ + start_address = 0x0a800; + else /* reserved */ + return SANE_STATUS_INVAL; + } + else /* color */ + start_address = 0x00; + + status = sanei_genesys_set_buffer_address (dev, start_address); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send shading table: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + + return SANE_STATUS_GOOD; +} + +/* ? */ +SANE_Status +sanei_genesys_init_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + int pixels_per_line) +{ + SANE_Status status = SANE_STATUS_GOOD; + int channels; + int i; + + /* these models don't need to init shading data due to the use of specific send shading data + function */ + if (dev->model->ccd_type==CCD_KVSS080 + || dev->model->ccd_type==CCD_G4050 + || dev->model->ccd_type==CCD_CS4400F + || dev->model->ccd_type==CCD_CS8400F + || dev->model->cmd_set->send_shading_data!=NULL) + return SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (pixels_per_line = %d)\n", __func__, pixels_per_line); + + // BUG: GRAY shouldn't probably be in the if condition below. Discovered when refactoring + if (dev->settings.scan_mode == ScanColorMode::GRAY || + dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + channels = 3; + } else { + channels = 1; + } + + // 16 bit black, 16 bit white + std::vector shading_data(pixels_per_line * 4 * channels, 0); + + uint8_t* shading_data_ptr = shading_data.data(); + + for (i = 0; i < pixels_per_line * channels; i++) + { + *shading_data_ptr++ = 0x00; /* dark lo */ + *shading_data_ptr++ = 0x00; /* dark hi */ + *shading_data_ptr++ = 0x00; /* white lo */ + *shading_data_ptr++ = 0x40; /* white hi -> 0x4000 */ + } + + status = genesys_send_offset_and_shading (dev, sensor, + shading_data.data(), + pixels_per_line * 4 * channels); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send shading data: %s\n", __func__, + sane_strstatus (status)); + } + + DBGCOMPLETED; + return status; +} + + +/* Find the position of the reference point: + takes gray level 8 bits data and find + first CCD usable pixel and top of scanning area */ +SANE_Status +sanei_genesys_search_reference_point (Genesys_Device * dev, Genesys_Sensor& sensor, + uint8_t * data, + int start_pixel, int dpi, int width, + int height) +{ + int x, y; + int current, left, top = 0; + int size, count; + int level = 80; /* edge threshold level */ + + /*sanity check */ + if ((width < 3) || (height < 3)) + return SANE_STATUS_INVAL; + + /* transformed image data */ + size = width * height; + std::vector image(size, 0); + + /* laplace filter to denoise picture */ + memcpy(image.data(), data, size); // to initialize unprocessed part of the image buffer + for (y = 1; y < height - 1; y++) + for (x = 1; x < width - 1; x++) + { + image[y * width + x] = + (data[(y - 1) * width + x + 1] + 2 * data[(y - 1) * width + x] + + data[(y - 1) * width + x - 1] + 2 * data[y * width + x + 1] + + 4 * data[y * width + x] + 2 * data[y * width + x - 1] + + data[(y + 1) * width + x + 1] + 2 * data[(y + 1) * width + x] + + data[(y + 1) * width + x - 1]) / 16; + } + + memcpy (data, image.data(), size); + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_laplace.pnm", image.data(), 8, 1, width, height); + + /* apply X direction sobel filter + -1 0 1 + -2 0 2 + -1 0 1 + and finds threshold level + */ + level = 0; + for (y = 2; y < height - 2; y++) + for (x = 2; x < width - 2; x++) + { + current = + data[(y - 1) * width + x + 1] - data[(y - 1) * width + x - 1] + + 2 * data[y * width + x + 1] - 2 * data[y * width + x - 1] + + data[(y + 1) * width + x + 1] - data[(y + 1) * width + x - 1]; + if (current < 0) + current = -current; + if (current > 255) + current = 255; + image[y * width + x] = current; + if (current > level) + level = current; + } + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_xsobel.pnm", image.data(), 8, 1, width, height); + + /* set up detection level */ + level = level / 3; + + /* find left black margin first + todo: search top before left + we average the result of N searches */ + left = 0; + count = 0; + for (y = 2; y < 11; y++) + { + x = 8; + while ((x < width / 2) && (image[y * width + x] < level)) + { + image[y * width + x] = 255; + x++; + } + count++; + left += x; + } + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_detected-xsobel.pnm", image.data(), 8, 1, width, height); + left = left / count; + + /* turn it in CCD pixel at full sensor optical resolution */ + sensor.CCD_start_xoffset = start_pixel + (left * sensor.optical_res) / dpi; + + /* find top edge by detecting black strip */ + /* apply Y direction sobel filter + -1 -2 -1 + 0 0 0 + 1 2 1 + */ + level = 0; + for (y = 2; y < height - 2; y++) + for (x = 2; x < width - 2; x++) + { + current = + -data[(y - 1) * width + x + 1] - 2 * data[(y - 1) * width + x] - + data[(y - 1) * width + x - 1] + data[(y + 1) * width + x + 1] + + 2 * data[(y + 1) * width + x] + data[(y + 1) * width + x - 1]; + if (current < 0) + current = -current; + if (current > 255) + current = 255; + image[y * width + x] = current; + if (current > level) + level = current; + } + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_ysobel.pnm", image.data(), 8, 1, width, height); + + /* set up detection level */ + level = level / 3; + + /* search top of horizontal black stripe : TODO yet another flag */ + if (dev->model->ccd_type == CCD_5345 + && dev->model->motor_type == MOTOR_5345) + { + top = 0; + count = 0; + for (x = width / 2; x < width - 1; x++) + { + y = 2; + while ((y < height) && (image[x + y * width] < level)) + { + image[y * width + x] = 255; + y++; + } + count++; + top += y; + } + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_detected-ysobel.pnm", image.data(), 8, 1, width, height); + top = top / count; + + /* bottom of black stripe is of fixed witdh, this hardcoded value + * will be moved into device struct if more such values are needed */ + top += 10; + dev->model->y_offset_calib = SANE_FIX ((top * MM_PER_INCH) / dpi); + DBG(DBG_info, "%s: black stripe y_offset = %f mm \n", __func__, + SANE_UNFIX (dev->model->y_offset_calib)); + } + + /* find white corner in dark area : TODO yet another flag */ + if ((dev->model->ccd_type == CCD_HP2300 + && dev->model->motor_type == MOTOR_HP2300) + || (dev->model->ccd_type == CCD_HP2400 + && dev->model->motor_type == MOTOR_HP2400) + || (dev->model->ccd_type == CCD_HP3670 + && dev->model->motor_type == MOTOR_HP3670)) + { + top = 0; + count = 0; + for (x = 10; x < 60; x++) + { + y = 2; + while ((y < height) && (image[x + y * width] < level)) + y++; + top += y; + count++; + } + top = top / count; + dev->model->y_offset_calib = SANE_FIX ((top * MM_PER_INCH) / dpi); + DBG(DBG_info, "%s: white corner y_offset = %f mm\n", __func__, + SANE_UNFIX (dev->model->y_offset_calib)); + } + + DBG(DBG_proc, "%s: CCD_start_xoffset = %d, left = %d, top = %d\n", __func__, + sensor.CCD_start_xoffset, left, top); + + return SANE_STATUS_GOOD; +} + + +void +sanei_genesys_calculate_zmode2 (SANE_Bool two_table, + uint32_t exposure_time, + uint16_t * slope_table, + int reg21, + int move, int reg22, uint32_t * z1, + uint32_t * z2) +{ + int i; + int sum; + DBG(DBG_info, "%s: two_table=%d\n", __func__, two_table); + + /* acceleration total time */ + sum = 0; + for (i = 0; i < reg21; i++) + sum += slope_table[i]; + + /* compute Z1MOD */ + /* c=sum(slope_table;reg21) + d=reg22*cruising speed + Z1MOD=(c+d) % exposure_time */ + *z1 = (sum + reg22 * slope_table[reg21 - 1]) % exposure_time; + + /* compute Z2MOD */ + /* a=sum(slope_table;reg21), b=move or 1 if 2 tables */ + /* Z2MOD=(a+b) % exposure_time */ + if (!two_table) + sum = sum + (move * slope_table[reg21 - 1]); + else + sum = sum + slope_table[reg21 - 1]; + *z2 = sum % exposure_time; +} + + +/* huh? */ +/* todo: double check */ +/* Z1 and Z2 seem to be a time to synchronize with clock or a phase correction */ +/* steps_sum is the result of create_slope_table */ +/* last_speed is the last entry of the slope_table */ +/* feedl is registers 3d,3e,3f */ +/* fastfed is register 02 bit 3 */ +/* scanfed is register 1f */ +/* fwdstep is register 22 */ +/* tgtime is register 6c bit 6+7 >> 6 */ + +void +sanei_genesys_calculate_zmode (uint32_t exposure_time, + uint32_t steps_sum, uint16_t last_speed, + uint32_t feedl, uint8_t fastfed, + uint8_t scanfed, uint8_t fwdstep, + uint8_t tgtime, uint32_t * z1, uint32_t * z2) +{ + uint8_t exposure_factor; + + exposure_factor = pow (2, tgtime); /* todo: originally, this is always 2^0 ! */ + + /* Z1 is for buffer-full backward forward moving */ + *z1 = + exposure_factor * ((steps_sum + fwdstep * last_speed) % exposure_time); + + /* Z2 is for acceleration before scan */ + if (fastfed) /* two curve mode */ + { + *z2 = + exposure_factor * ((steps_sum + scanfed * last_speed) % + exposure_time); + } + else /* one curve mode */ + { + *z2 = + exposure_factor * ((steps_sum + feedl * last_speed) % exposure_time); + } +} + + +static uint8_t genesys_adjust_gain(double* applied_multi, double multi, uint8_t gain) +{ + double voltage, original_voltage; + uint8_t new_gain = 0; + + DBG(DBG_proc, "%s: multi=%f, gain=%d\n", __func__, multi, gain); + + voltage = 0.5 + gain * 0.25; + original_voltage = voltage; + + voltage *= multi; + + new_gain = (uint8_t) ((voltage - 0.5) * 4); + if (new_gain > 0x0e) + new_gain = 0x0e; + + voltage = 0.5 + (new_gain) * 0.25; + + *applied_multi = voltage / original_voltage; + + DBG(DBG_proc, "%s: orig voltage=%.2f, new voltage=%.2f, *applied_multi=%f, new_gain=%d\n", + __func__, original_voltage, voltage, *applied_multi, new_gain); + + return new_gain; +} + + +/* todo: is return status necessary (unchecked?) */ +static SANE_Status +genesys_average_white (Genesys_Device * dev, Genesys_Sensor& sensor, int channels, int channel, + uint8_t * data, int size, int *max_average) +{ + int gain_white_ref, sum, range; + int average; + int i; + + DBG(DBG_proc, "%s: channels=%d, channel=%d, size=%d\n", __func__, channels, channel, size); + + range = size / 50; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) /* transparency mode */ + gain_white_ref = sensor.fau_gain_white_ref * 256; + else + gain_white_ref = sensor.gain_white_ref * 256; + + if (range < 1) + range = 1; + + size = size / (2 * range * channels); + + data += (channel * 2); + + *max_average = 0; + + while (size--) + { + sum = 0; + for (i = 0; i < range; i++) + { + sum += (*data); + sum += *(data + 1) * 256; + data += (2 * channels); /* byte based */ + } + + average = (sum / range); + if (average > *max_average) + *max_average = average; + } + + DBG(DBG_proc, "%s: max_average=%d, gain_white_ref = %d, finished\n", __func__, *max_average, + gain_white_ref); + + if (*max_average >= gain_white_ref) + return SANE_STATUS_INVAL; + + return SANE_STATUS_GOOD; +} + +/* todo: understand, values are too high */ +static int +genesys_average_black (Genesys_Device * dev, int channel, + uint8_t * data, int pixels) +{ + int i; + int sum; + int pixel_step; + + DBG(DBG_proc, "%s: channel=%d, pixels=%d\n", __func__, channel, pixels); + + sum = 0; + + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + data += (channel * 2); + pixel_step = 3 * 2; + } + else + { + pixel_step = 2; + } + + for (i = 0; i < pixels; i++) + { + sum += *data; + sum += *(data + 1) * 256; + + data += pixel_step; + } + + DBG(DBG_proc, "%s = %d\n", __func__, sum / pixels); + + return (int) (sum / pixels); +} + + +/* todo: check; it works but the lines 1, 2, and 3 are too dark even with the + same offset and gain settings? */ +static SANE_Status genesys_coarse_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) +{ + int size; + int black_pixels; + int white_average; + int channels; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t offset[4] = { 0xa0, 0x00, 0xa0, 0x40 }; /* first value isn't used */ + uint16_t white[12], dark[12]; + int i, j; + + DBG(DBG_info, "%s (scan_mode = %d)\n", __func__, static_cast(dev->settings.scan_mode)); + + black_pixels = sensor.black_pixels + * dev->settings.xres / sensor.optical_res; + + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + DBG(DBG_info, "channels %d y_size %d xres %d\n", channels, dev->model->y_size, + dev->settings.xres); + size = + channels * 2 * SANE_UNFIX (dev->model->y_size) * dev->settings.xres / + 25.4; + /* 1 1 mm 1/inch inch/mm */ + + std::vector calibration_data(size); + std::vector all_data(size * 4, 1); + + status = dev->model->cmd_set->set_fe(dev, sensor, AFE_INIT); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); + return status; + } + + dev->frontend.set_gain(0, 2); + dev->frontend.set_gain(1, 2); + dev->frontend.set_gain(2, 2); // TODO: ? was 2 + dev->frontend.set_offset(0, offset[0]); + dev->frontend.set_offset(1, offset[0]); + dev->frontend.set_offset(2, offset[0]); + + for (i = 0; i < 4; i++) /* read 4 lines */ + { + if (i < 3) /* first 3 lines */ + { + dev->frontend.set_offset(0, offset[i]); + dev->frontend.set_offset(1, offset[i]); + dev->frontend.set_offset(2, offset[i]); + } + + if (i == 1) /* second line */ + { + double applied_multi; + double gain_white_ref; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) /* Transparency */ + gain_white_ref = sensor.fau_gain_white_ref * 256; + else + gain_white_ref = sensor.gain_white_ref * 256; + /* white and black are defined downwards */ + + uint8_t gain0 = genesys_adjust_gain(&applied_multi, + gain_white_ref / (white[0] - dark[0]), + dev->frontend.get_gain(0)); + uint8_t gain1 = genesys_adjust_gain(&applied_multi, + gain_white_ref / (white[1] - dark[1]), + dev->frontend.get_gain(1)); + uint8_t gain2 = genesys_adjust_gain(&applied_multi, + gain_white_ref / (white[2] - dark[2]), + dev->frontend.get_gain(2)); + // FIXME: looks like overwritten data. Are the above calculations doing + // anything at all? + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain1); + dev->frontend.set_gain(2, gain2); + dev->frontend.set_gain(0, 2); + dev->frontend.set_gain(1, 2); + dev->frontend.set_gain(2, 2); + + status = + sanei_genesys_fe_write_data(dev, 0x28, dev->frontend.get_gain(0)); + if (status != SANE_STATUS_GOOD) /* todo: this was 0x28 + 3 ? */ + { + DBG(DBG_error, "%s: Failed to write gain[0]: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_fe_write_data(dev, 0x29, dev->frontend.get_gain(1)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to write gain[1]: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_fe_write_data(dev, 0x2a, dev->frontend.get_gain(2)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to write gain[2]: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + if (i == 3) /* last line */ + { + double x, y, rate; + + for (j = 0; j < 3; j++) + { + + x = + (double) (dark[(i - 2) * 3 + j] - + dark[(i - 1) * 3 + j]) * 254 / (offset[i - 1] / 2 - + offset[i - 2] / 2); + y = x - x * (offset[i - 1] / 2) / 254 - dark[(i - 1) * 3 + j]; + rate = (x - DARK_VALUE - y) * 254 / x + 0.5; + + uint8_t curr_offset = static_cast(rate); + + if (curr_offset > 0x7f) { + curr_offset = 0x7f; + } + curr_offset <<= 1; + dev->frontend.set_offset(j, curr_offset); + } + } + status = + sanei_genesys_fe_write_data(dev, 0x20, dev->frontend.get_offset(0)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to write offset[0]: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_fe_write_data(dev, 0x21, dev->frontend.get_offset(1)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to write offset[1]: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_fe_write_data(dev, 0x22, dev->frontend.get_offset(2)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to write offset[2]: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_info, + "%s: doing scan: gain: %d/%d/%d, offset: %d/%d/%d\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2), + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + + status = + dev->model->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_read_data_from_scanner (dev, calibration_data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + std::memcpy(all_data.data() + i * size, calibration_data.data(), size); + if (i == 3) /* last line */ + { + std::vector all_data_8(size * 4 / 2); + unsigned int count; + + for (count = 0; count < (unsigned int) (size * 4 / 2); count++) + all_data_8[count] = all_data[count * 2 + 1]; + status = + sanei_genesys_write_pnm_file("gl_coarse.pnm", all_data_8.data(), 8, channels, size / 6, 4); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + status = dev->model->cmd_set->end_scan(dev, &dev->calib_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + for (j = 0; j < 3; j++) + { + genesys_average_white (dev, sensor, 3, j, calibration_data.data(), size, + &white_average); + white[i * 3 + j] = white_average; + dark[i * 3 + j] = + genesys_average_black (dev, j, calibration_data.data(), + black_pixels); + DBG(DBG_info, "%s: white[%d]=%d, black[%d]=%d\n", __func__, + i * 3 + j, white[i * 3 + j], i * 3 + j, dark[i * 3 + j]); + } + } + else /* one color-component modes */ + { + genesys_average_white (dev, sensor, 1, 0, calibration_data.data(), size, + &white_average); + white[i * 3 + 0] = white[i * 3 + 1] = white[i * 3 + 2] = + white_average; + dark[i * 3 + 0] = dark[i * 3 + 1] = dark[i * 3 + 2] = + genesys_average_black (dev, 0, calibration_data.data(), black_pixels); + } + + if (i == 3) + { + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + /* todo: huh? */ + dev->dark[0] = + (uint16_t) (1.6925 * dark[i * 3 + 0] + 0.1895 * 256); + dev->dark[1] = + (uint16_t) (1.4013 * dark[i * 3 + 1] + 0.3147 * 256); + dev->dark[2] = + (uint16_t) (1.2931 * dark[i * 3 + 2] + 0.1558 * 256); + } + else /* one color-component modes */ + { + switch (dev->settings.color_filter) + { + case ColorFilter::RED: + default: + dev->dark[0] = + (uint16_t) (1.6925 * dark[i * 3 + 0] + + (1.1895 - 1.0) * 256); + dev->dark[1] = dev->dark[2] = dev->dark[0]; + break; + + case ColorFilter::GREEN: + dev->dark[1] = + (uint16_t) (1.4013 * dark[i * 3 + 1] + + (1.3147 - 1.0) * 256); + dev->dark[0] = dev->dark[2] = dev->dark[1]; + break; + + case ColorFilter::BLUE: + dev->dark[2] = + (uint16_t) (1.2931 * dark[i * 3 + 2] + + (1.1558 - 1.0) * 256); + dev->dark[0] = dev->dark[1] = dev->dark[2]; + break; + } + } + } + } /* for (i = 0; i < 4; i++) */ + + DBG(DBG_info, "%s: final: gain: %d/%d/%d, offset: %d/%d/%d\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2), + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + DBGCOMPLETED; + + return status; +} + +/* Averages image data. + average_data and calibration_data are little endian 16 bit words. + */ +static void +genesys_average_data (uint8_t * average_data, + uint8_t * calibration_data, + uint32_t lines, + uint32_t pixel_components_per_line) +{ + uint32_t x, y; + uint32_t sum; + + for (x = 0; x < pixel_components_per_line; x++) + { + sum = 0; + for (y = 0; y < lines; y++) + { + sum += calibration_data[(x + y * pixel_components_per_line) * 2]; + sum += + calibration_data[(x + y * pixel_components_per_line) * 2 + + 1] * 256; + } + sum /= lines; + *average_data++ = sum & 255; + *average_data++ = sum / 256; + } +} + +/** + * scans a white area with motor and lamp off to get the per CCD pixel offset + * that will be used to compute shading coefficient + * @param dev scanner's device + * @return SANE_STATUS_GOOD if OK, else an error + */ +static SANE_Status +genesys_dark_shading_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + size_t size; + uint32_t pixels_per_line; + uint8_t channels; + SANE_Bool motor; + + DBGSTART; + + /* end pixel - start pixel */ + pixels_per_line = dev->calib_pixels; + channels = dev->calib_channels; + + uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; + dev->average_size = channels * 2 * out_pixels_per_line; + + dev->dark_average_data.clear(); + dev->dark_average_data.resize(dev->average_size); + + // FIXME: the current calculation is likely incorrect on non-GENESYS_GL843 implementations, + // but this needs checking + if (dev->calib_total_bytes_to_read > 0) { + size = dev->calib_total_bytes_to_read; + } else if (dev->model->asic_type == GENESYS_GL843) { + size = channels * 2 * pixels_per_line * dev->calib_lines; + } else { + size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); + } + + std::vector calibration_data(size); + + motor=SANE_TRUE; + if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) + { + motor=SANE_FALSE; + } + + /* turn off motor and lamp power for flatbed scanners, but not for sheetfed scanners + * because they have a calibration sheet with a sufficient black strip */ + if (dev->model->is_sheetfed == SANE_FALSE) + { + sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, false); + sanei_genesys_set_motor_power(dev->calib_reg, motor); + } + else + { + sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true); + sanei_genesys_set_motor_power(dev->calib_reg, motor); + } + + status = + dev->model->cmd_set->bulk_write_register(dev, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + // wait some time to let lamp to get dark + sanei_genesys_sleep_ms(200); + + status = dev->model->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_read_data_from_scanner (dev, calibration_data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = dev->model->cmd_set->end_scan(dev, &dev->calib_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + std::fill(dev->dark_average_data.begin(), + dev->dark_average_data.begin() + dev->calib_pixels_offset * channels, + 0x00); + + genesys_average_data(dev->dark_average_data.data() + dev->calib_pixels_offset * channels, + calibration_data.data(), + dev->calib_lines, pixels_per_line * channels); + + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_pnm_file("gl_black_shading.pnm", calibration_data.data(), 16, + channels, pixels_per_line, dev->calib_lines); + sanei_genesys_write_pnm_file("gl_black_average.pnm", dev->dark_average_data.data(), 16, + channels, out_pixels_per_line, 1); + } + + DBGCOMPLETED; + + return SANE_STATUS_GOOD; +} + +/* + * this function builds dummy dark calibration data so that we can + * compute shading coefficient in a clean way + * todo: current values are hardcoded, we have to find if they + * can be computed from previous calibration data (when doing offset + * calibration ?) + */ +static SANE_Status +genesys_dummy_dark_shading (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + uint32_t pixels_per_line; + uint8_t channels; + uint32_t x, skip, xend; + int dummy1, dummy2, dummy3; /* dummy black average per channel */ + + DBGSTART; + + pixels_per_line = dev->calib_pixels; + channels = dev->calib_channels; + + uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; + + dev->average_size = channels * 2 * out_pixels_per_line; + dev->dark_average_data.clear(); + dev->dark_average_data.resize(dev->average_size, 0); + + /* we average values on 'the left' where CCD pixels are under casing and + give darkest values. We then use these as dummy dark calibration */ + if (dev->settings.xres <= sensor.optical_res / 2) + { + skip = 4; + xend = 36; + } + else + { + skip = 4; + xend = 68; + } + if (dev->model->ccd_type==CCD_G4050 + || dev->model->ccd_type==CCD_CS4400F + || dev->model->ccd_type==CCD_CS8400F + || dev->model->ccd_type==CCD_KVSS080) + { + skip = 2; + xend = sensor.black_pixels; + } + + /* average each channels on half left margin */ + dummy1 = 0; + dummy2 = 0; + dummy3 = 0; + + for (x = skip + 1; x <= xend; x++) + { + dummy1 += + dev->white_average_data[channels * 2 * x] + + 256 * dev->white_average_data[channels * 2 * x + 1]; + if (channels > 1) + { + dummy2 += + (dev->white_average_data[channels * 2 * x + 2] + + 256 * dev->white_average_data[channels * 2 * x + 3]); + dummy3 += + (dev->white_average_data[channels * 2 * x + 4] + + 256 * dev->white_average_data[channels * 2 * x + 5]); + } + } + + dummy1 /= (xend - skip); + if (channels > 1) + { + dummy2 /= (xend - skip); + dummy3 /= (xend - skip); + } + DBG(DBG_proc, "%s: dummy1=%d, dummy2=%d, dummy3=%d \n", __func__, dummy1, dummy2, dummy3); + + /* fill dark_average */ + for (x = 0; x < out_pixels_per_line; x++) + { + dev->dark_average_data[channels * 2 * x] = dummy1 & 0xff; + dev->dark_average_data[channels * 2 * x + 1] = dummy1 >> 8; + if (channels > 1) + { + dev->dark_average_data[channels * 2 * x + 2] = dummy2 & 0xff; + dev->dark_average_data[channels * 2 * x + 3] = dummy2 >> 8; + dev->dark_average_data[channels * 2 * x + 4] = dummy3 & 0xff; + dev->dark_average_data[channels * 2 * x + 5] = dummy3 >> 8; + } + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +static SANE_Status +genesys_white_shading_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + size_t size; + uint32_t pixels_per_line; + uint8_t channels; + SANE_Bool motor; + + DBG(DBG_proc, "%s (lines = %d)\n", __func__, (unsigned int)dev->calib_lines); + + pixels_per_line = dev->calib_pixels; + channels = dev->calib_channels; + + uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; + + dev->white_average_data.clear(); + dev->white_average_data.resize(channels * 2 * out_pixels_per_line); + + // FIXME: the current calculation is likely incorrect on non-GENESYS_GL843 implementations, + // but this needs checking + if (dev->calib_total_bytes_to_read > 0) { + size = dev->calib_total_bytes_to_read; + } else if (dev->model->asic_type == GENESYS_GL843) { + size = channels * 2 * pixels_per_line * dev->calib_lines; + } else { + size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); + } + + std::vector calibration_data(size); + + motor=SANE_TRUE; + if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) + { + motor=SANE_FALSE; + } + + // turn on motor and lamp power + sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true); + sanei_genesys_set_motor_power(dev->calib_reg, motor); + + /* if needed, go back before doing next scan */ + if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) + { + /* rewind keeps registers and slopes table intact from previous + scan but is not available on all supported chipsets (or may + cause scan artifacts, see #7) */ + status = (dev->model->cmd_set->rewind + ? dev->model->cmd_set->rewind (dev) + : dev->model->cmd_set->slow_back_home (dev, SANE_TRUE)); + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) + { + dev->model->cmd_set->move_to_ta(dev); + } + } + + status = + dev->model->cmd_set->bulk_write_register(dev, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) + sanei_genesys_sleep_ms(500); // make sure lamp is bright again + + status = dev->model->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_read_data_from_scanner (dev, calibration_data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = dev->model->cmd_set->end_scan(dev, &dev->calib_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_white_shading.pnm", calibration_data.data(), 16, + channels, pixels_per_line, dev->calib_lines); + + std::fill(dev->dark_average_data.begin(), + dev->dark_average_data.begin() + dev->calib_pixels_offset * channels, + 0x00); + + genesys_average_data (dev->white_average_data.data() + dev->calib_pixels_offset * channels, + calibration_data.data(), dev->calib_lines, + pixels_per_line * channels); + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_white_average.pnm", dev->white_average_data.data(), 16, + channels, out_pixels_per_line, 1); + + /* in case we haven't done dark calibration, build dummy data from white_average */ + if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) + { + status = genesys_dummy_dark_shading(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do dummy dark shading calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) + { + status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); + } + + DBGCOMPLETED; + + return status; +} + +/* This calibration uses a scan over the calibration target, comprising a + * black and a white strip. (So the motor must be on.) + */ +static SANE_Status +genesys_dark_white_shading_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + size_t size; + uint32_t pixels_per_line; + uint8_t *average_white, *average_dark; + uint8_t channels; + unsigned int x; + int y; + uint32_t dark, white, dark_sum, white_sum, dark_count, white_count, col, + dif; + SANE_Bool motor; + + + DBG(DBG_proc, "%s: (lines = %d)\n", __func__, (unsigned int)dev->calib_lines); + + pixels_per_line = dev->calib_pixels; + channels = dev->calib_channels; + + uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; + + dev->average_size = channels * 2 * out_pixels_per_line; + + dev->white_average_data.clear(); + dev->white_average_data.resize(dev->average_size); + + dev->dark_average_data.clear(); + dev->dark_average_data.resize(dev->average_size); + + if (dev->calib_total_bytes_to_read > 0) + size = dev->calib_total_bytes_to_read; + else + size = channels * 2 * pixels_per_line * dev->calib_lines; + + std::vector calibration_data(size); + + motor=SANE_TRUE; + if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) + { + motor=SANE_FALSE; + } + + // turn on motor and lamp power + sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true); + sanei_genesys_set_motor_power(dev->calib_reg, motor); + + status = + dev->model->cmd_set->bulk_write_register(dev, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = dev->model->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, SANE_FALSE); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_read_data_from_scanner (dev, calibration_data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = dev->model->cmd_set->end_scan(dev, &dev->calib_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (DBG_LEVEL >= DBG_data) + { + if (dev->model->is_cis) + { + sanei_genesys_write_pnm_file("gl_black_white_shading.pnm", calibration_data.data(), + 16, 1, pixels_per_line*channels, + dev->calib_lines); + } + else + { + sanei_genesys_write_pnm_file("gl_black_white_shading.pnm", calibration_data.data(), + 16, channels, pixels_per_line, + dev->calib_lines); + } + } + + + std::fill(dev->dark_average_data.begin(), + dev->dark_average_data.begin() + dev->calib_pixels_offset * channels, + 0x00); + std::fill(dev->white_average_data.begin(), + dev->white_average_data.begin() + dev->calib_pixels_offset * channels, + 0x00); + + average_white = dev->white_average_data.data() + dev->calib_pixels_offset * channels; + average_dark = dev->dark_average_data.data() + dev->calib_pixels_offset * channels; + + for (x = 0; x < pixels_per_line * channels; x++) + { + dark = 0xffff; + white = 0; + + for (y = 0; y < (int)dev->calib_lines; y++) + { + col = calibration_data[(x + y * pixels_per_line * channels) * 2]; + col |= + calibration_data[(x + y * pixels_per_line * channels) * 2 + + 1] << 8; + + if (col > white) + white = col; + if (col < dark) + dark = col; + } + + dif = white - dark; + + dark = dark + dif / 8; + white = white - dif / 8; + + dark_count = 0; + dark_sum = 0; + + white_count = 0; + white_sum = 0; + + for (y = 0; y < (int)dev->calib_lines; y++) + { + col = calibration_data[(x + y * pixels_per_line * channels) * 2]; + col |= + calibration_data[(x + y * pixels_per_line * channels) * 2 + + 1] << 8; + + if (col >= white) + { + white_sum += col; + white_count++; + } + if (col <= dark) + { + dark_sum += col; + dark_count++; + } + + } + + dark_sum /= dark_count; + white_sum /= white_count; + + *average_dark++ = dark_sum & 255; + *average_dark++ = dark_sum >> 8; + + *average_white++ = white_sum & 255; + *average_white++ = white_sum >> 8; + } + + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_pnm_file("gl_white_average.pnm", + dev->white_average_data.data(), 16, channels, + out_pixels_per_line, 1); + sanei_genesys_write_pnm_file("gl_dark_average.pnm", + dev->dark_average_data.data(), 16, channels, + out_pixels_per_line, 1); + } + + DBGCOMPLETED; + + return SANE_STATUS_GOOD; +} + +/* computes one coefficient given bright-dark value + * @param coeff factor giving 1.00 gain + * @param target desired target code + * @param value brght-dark value + * */ +static unsigned int +compute_coefficient (unsigned int coeff, unsigned int target, unsigned int value) +{ + int result; + + if (value > 0) + { + result = (coeff * target) / value; + if (result >= 65535) + { + result = 65535; + } + } + else + { + result = coeff; + } + return result; +} + +/** @brief compute shading coefficients for LiDE scanners + * The dark/white shading is actually performed _after_ reducing + * resolution via averaging. only dark/white shading data for what would be + * first pixel at full resolution is used. + * + * scanner raw input to output value calculation: + * o=(i-off)*(gain/coeff) + * + * from datasheet: + * off=dark_average + * gain=coeff*bright_target/(bright_average-dark_average) + * works for dark_target==0 + * + * what we want is these: + * bright_target=(bright_average-off)*(gain/coeff) + * dark_target=(dark_average-off)*(gain/coeff) + * leading to + * off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) + * gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff + * + * @param dev scanner's device + * @param shading_data memory area where to store the computed shading coefficients + * @param pixels_per_line number of pixels per line + * @param words_per_color memory words per color channel + * @param channels number of color channels (actually 1 or 3) + * @param o shading coefficients left offset + * @param coeff 4000h or 2000h depending on fast scan mode or not (GAIN4 bit) + * @param target_bright value of the white target code + * @param target_dark value of the black target code +*/ +static void +compute_averaged_planar (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * shading_data, + unsigned int pixels_per_line, + unsigned int words_per_color, + unsigned int channels, + unsigned int o, + unsigned int coeff, + unsigned int target_bright, + unsigned int target_dark) +{ + unsigned int x, i, j, br, dk, res, avgpixels, basepixels, val; + unsigned int fill,factor; + + DBG(DBG_info, "%s: pixels=%d, offset=%d\n", __func__, pixels_per_line, o); + + /* initialize result */ + memset (shading_data, 0xff, words_per_color * 3 * 2); + + /* + strangely i can write 0x20000 bytes beginning at 0x00000 without overwriting + slope tables - which begin at address 0x10000(for 1200dpi hw mode): + memory is organized in words(2 bytes) instead of single bytes. explains + quite some things + */ +/* + another one: the dark/white shading is actually performed _after_ reducing + resolution via averaging. only dark/white shading data for what would be + first pixel at full resolution is used. + */ +/* + scanner raw input to output value calculation: + o=(i-off)*(gain/coeff) + + from datasheet: + off=dark_average + gain=coeff*bright_target/(bright_average-dark_average) + works for dark_target==0 + + what we want is these: + bright_target=(bright_average-off)*(gain/coeff) + dark_target=(dark_average-off)*(gain/coeff) + leading to + off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) + gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff + */ + res = dev->settings.xres; + + if (sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres) > 1) + { + res *= 2; + } + + /* this should be evenly dividable */ + basepixels = sensor.optical_res / res; + + /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ + if (basepixels < 1) + avgpixels = 1; + else if (basepixels < 6) + avgpixels = basepixels; + else if (basepixels < 8) + avgpixels = 6; + else if (basepixels < 10) + avgpixels = 8; + else if (basepixels < 12) + avgpixels = 10; + else if (basepixels < 15) + avgpixels = 12; + else + avgpixels = 15; + + /* LiDE80 packs shading data */ + if(dev->model->ccd_type != CIS_CANONLIDE80) + { + factor=1; + fill=avgpixels; + } + else + { + factor=avgpixels; + fill=1; + } + + DBG(DBG_info, "%s: averaging over %d pixels\n", __func__, avgpixels); + DBG(DBG_info, "%s: packing factor is %d\n", __func__, factor); + DBG(DBG_info, "%s: fill length is %d\n", __func__, fill); + + for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) + { + if ((x + o) * 2 * 2 + 3 > words_per_color * 2) + break; + + for (j = 0; j < channels; j++) + { + + dk = 0; + br = 0; + for (i = 0; i < avgpixels; i++) + { + /* dark data */ + dk += + (dev->dark_average_data[(x + i + + pixels_per_line * j) * + 2] | + (dev->dark_average_data + [(x + i + pixels_per_line * j) * 2 + 1] << 8)); + + /* white data */ + br += + (dev->white_average_data[(x + i + + pixels_per_line * j) * + 2] | + (dev->white_average_data + [(x + i + pixels_per_line * j) * 2 + 1] << 8)); + } + + br /= avgpixels; + dk /= avgpixels; + + if (br * target_dark > dk * target_bright) + val = 0; + else if (dk * target_bright - br * target_dark > + 65535 * (target_bright - target_dark)) + val = 65535; + else + { + val = (dk * target_bright - br * target_dark) / (target_bright - target_dark); + } + + /*fill all pixels, even if only the last one is relevant*/ + for (i = 0; i < fill; i++) + { + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j] = val & 0xff; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = val >> 8; + } + + val = br - dk; + + if (65535 * val > (target_bright - target_dark) * coeff) + { + val = (coeff * (target_bright - target_dark)) / val; + } + else + { + val = 65535; + } + + /*fill all pixels, even if only the last one is relevant*/ + for (i = 0; i < fill; i++) + { + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = val & 0xff; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = val >> 8; + } + } + + /* fill remaining channels */ + for (j = channels; j < 3; j++) + { + for (i = 0; i < fill; i++) + { + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j ] = shading_data[(x/factor + o + i) * 2 * 2 ]; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = shading_data[(x/factor + o + i) * 2 * 2 + 1]; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = shading_data[(x/factor + o + i) * 2 * 2 + 2]; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = shading_data[(x/factor + o + i) * 2 * 2 + 3]; + } + } + } +} + +/** + * Computes shading coefficient using formula in data sheet. 16bit data values + * manipulated here are little endian. For now we assume deletion scanning type + * and that there is always 3 channels. + * @param dev scanner's device + * @param shading_data memory area where to store the computed shading coefficients + * @param pixels_per_line number of pixels per line + * @param channels number of color channels (actually 1 or 3) + * @param cmat color transposition matrix + * @param offset shading coefficients left offset + * @param coeff 4000h or 2000h depending on fast scan mode or not + * @param target value of the target code + */ +static void +compute_coefficients (Genesys_Device * dev, + uint8_t * shading_data, + unsigned int pixels_per_line, + unsigned int channels, + unsigned int cmat[3], + int offset, + unsigned int coeff, + unsigned int target) +{ + uint8_t *ptr; /* contain 16bit words in little endian */ + unsigned int x, c; + unsigned int val, br, dk; + unsigned int start, end; + + DBG(DBG_io, "%s: pixels_per_line=%d, coeff=0x%04x\n", __func__, pixels_per_line, coeff); + + /* compute start & end values depending of the offset */ + if (offset < 0) + { + start = -1 * offset; + end = pixels_per_line; + } + else + { + start = 0; + end = pixels_per_line - offset; + } + + for (c = 0; c < channels; c++) + { + for (x = start; x < end; x++) + { + /* TODO if channels=1 , use filter to know the base addr */ + ptr = shading_data + 4 * ((x + offset) * channels + cmat[c]); + + /* dark data */ + dk = dev->dark_average_data[x * 2 * channels + c * 2]; + dk += 256 * dev->dark_average_data[x * 2 * channels + c * 2 + 1]; + + /* white data */ + br = dev->white_average_data[x * 2 * channels + c * 2]; + br += 256 * dev->white_average_data[x * 2 * channels + c * 2 + 1]; + + /* compute coeff */ + val=compute_coefficient(coeff,target,br-dk); + + /* assign it */ + ptr[0] = dk & 255; + ptr[1] = dk / 256; + ptr[2] = val & 0xff; + ptr[3] = val / 256; + + } + } +} + +/** + * Computes shading coefficient using formula in data sheet. 16bit data values + * manipulated here are little endian. Data is in planar form, ie grouped by + * lines of the same color component. + * @param dev scanner's device + * @param shading_data memory area where to store the computed shading coefficients + * @param factor averaging factor when the calibration scan is done at a higher resolution + * than the final scan + * @param pixels_per_line number of pixels per line + * @param words_per_color total number of shading data words for one color element + * @param channels number of color channels (actually 1 or 3) + * @param cmat transcoding matrix for color channel order + * @param offset shading coefficients left offset + * @param coeff 4000h or 2000h depending on fast scan mode or not + * @param target white target value + */ +static void +compute_planar_coefficients (Genesys_Device * dev, + uint8_t * shading_data, + unsigned int factor, + unsigned int pixels_per_line, + unsigned int words_per_color, + unsigned int channels, + unsigned int cmat[3], + unsigned int offset, + unsigned int coeff, + unsigned int target) +{ + uint8_t *ptr; /* contains 16bit words in little endian */ + uint32_t x, c, i; + uint32_t val, dk, br; + + DBG(DBG_io, "%s: factor=%d, pixels_per_line=%d, words=0x%X, coeff=0x%04x\n", __func__, factor, + pixels_per_line, words_per_color, coeff); + for (c = 0; c < channels; c++) + { + /* shading data is larger than pixels_per_line so offset can be neglected */ + for (x = 0; x < pixels_per_line; x+=factor) + { + /* x2 because of 16 bit values, and x2 since one coeff for dark + * and another for white */ + ptr = shading_data + words_per_color * cmat[c] * 2 + (x + offset) * 4; + + dk = 0; + br = 0; + + /* average case */ + for(i=0;idark_average_data[((x+i) + pixels_per_line * c) * 2 + 1]; + dk += dev->dark_average_data[((x+i) + pixels_per_line * c) * 2]; + br += + 256 * dev->white_average_data[((x+i) + pixels_per_line * c) * 2 + 1]; + br += dev->white_average_data[((x+i) + pixels_per_line * c) * 2]; + } + dk /= factor; + br /= factor; + + val = compute_coefficient (coeff, target, br - dk); + + /* we duplicate the information to have calibration data at optical resolution */ + for (i = 0; i < factor; i++) + { + ptr[0 + 4 * i] = dk & 255; + ptr[1 + 4 * i] = dk / 256; + ptr[2 + 4 * i] = val & 0xff; + ptr[3 + 4 * i] = val / 256; + } + } + } + /* in case of gray level scan, we duplicate shading information on all + * three color channels */ + if(channels==1) + { + memcpy(shading_data+cmat[1]*2*words_per_color, + shading_data+cmat[0]*2*words_per_color, + words_per_color*2); + memcpy(shading_data+cmat[2]*2*words_per_color, + shading_data+cmat[0]*2*words_per_color, + words_per_color*2); + } +} + +static void +compute_shifted_coefficients (Genesys_Device * dev, + const Genesys_Sensor& sensor, + uint8_t * shading_data, + unsigned int pixels_per_line, + unsigned int channels, + unsigned int cmat[3], + int offset, + unsigned int coeff, + unsigned int target_dark, + unsigned int target_bright, + unsigned int patch_size) /* contigous extent */ +{ + unsigned int x, avgpixels, basepixels, i, j, val1, val2; + unsigned int br_tmp [3], dk_tmp [3]; + uint8_t *ptr = shading_data + offset * 3 * 4; /* contain 16bit words in little endian */ + unsigned int patch_cnt = offset * 3; /* at start, offset of first patch */ + + x = dev->settings.xres; + if (sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres) > 1) + x *= 2; /* scanner is using half-ccd mode */ + basepixels = sensor.optical_res / x; /*this should be evenly dividable */ + + /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ + if (basepixels < 1) + avgpixels = 1; + else if (basepixels < 6) + avgpixels = basepixels; + else if (basepixels < 8) + avgpixels = 6; + else if (basepixels < 10) + avgpixels = 8; + else if (basepixels < 12) + avgpixels = 10; + else if (basepixels < 15) + avgpixels = 12; + else + avgpixels = 15; + DBG(DBG_info, "%s: pixels_per_line=%d, coeff=0x%04x, averaging over %d pixels\n", __func__, + pixels_per_line, coeff, avgpixels); + + for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) { + memset (&br_tmp, 0, sizeof(br_tmp)); + memset (&dk_tmp, 0, sizeof(dk_tmp)); + + for (i = 0; i < avgpixels; i++) { + for (j = 0; j < channels; j++) { + br_tmp[j] += (dev->white_average_data[((x + i) * channels + j) * 2] | + (dev->white_average_data[((x + i) * channels + j) * 2 + 1] << 8)); + dk_tmp[i] += (dev->dark_average_data[((x + i) * channels + j) * 2] | + (dev->dark_average_data[((x + i) * channels + j) * 2 + 1] << 8)); + } + } + for (j = 0; j < channels; j++) { + br_tmp[j] /= avgpixels; + dk_tmp[j] /= avgpixels; + + if (br_tmp[j] * target_dark > dk_tmp[j] * target_bright) + val1 = 0; + else if (dk_tmp[j] * target_bright - br_tmp[j] * target_dark > 65535 * (target_bright - target_dark)) + val1 = 65535; + else + val1 = (dk_tmp[j] * target_bright - br_tmp[j] * target_dark) / (target_bright - target_dark); + + val2 = br_tmp[j] - dk_tmp[j]; + if (65535 * val2 > (target_bright - target_dark) * coeff) + val2 = (coeff * (target_bright - target_dark)) / val2; + else + val2 = 65535; + + br_tmp[j] = val1; + dk_tmp[j] = val2; + } + for (i = 0; i < avgpixels; i++) { + for (j = 0; j < channels; j++) { + * ptr++ = br_tmp[ cmat[j] ] & 0xff; + * ptr++ = br_tmp[ cmat[j] ] >> 8; + * ptr++ = dk_tmp[ cmat[j] ] & 0xff; + * ptr++ = dk_tmp[ cmat[j] ] >> 8; + patch_cnt++; + if (patch_cnt == patch_size) { + patch_cnt = 0; + val1 = cmat[2]; + cmat[2] = cmat[1]; + cmat[1] = cmat[0]; + cmat[0] = val1; + } + } + } + } +} + +static SANE_Status +genesys_send_shading_coefficient(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint32_t pixels_per_line; + uint8_t channels; + int o; + unsigned int length; /**> number of shading calibration data words */ + unsigned int factor; + unsigned int cmat[3]; /**> matrix of color channels */ + unsigned int coeff, target_code, words_per_color = 0; + + DBGSTART; + + pixels_per_line = dev->calib_pixels + dev->calib_pixels_offset; + channels = dev->calib_channels; + + /* we always build data for three channels, even for gray + * we make the shading data such that each color channel data line is contiguous + * to the next one, which allow to write the 3 channels in 1 write + * during genesys_send_shading_coefficient, some values are words, other bytes + * hence the x2 factor */ + switch (dev->reg.get8(0x05) >> 6) + { + /* 600 dpi */ + case 0: + words_per_color = 0x2a00; + break; + /* 1200 dpi */ + case 1: + words_per_color = 0x5500; + break; + /* 2400 dpi */ + case 2: + words_per_color = 0xa800; + break; + /* 4800 dpi */ + case 3: + words_per_color = 0x15000; + break; + } + + /* special case, memory is aligned on 0x5400, this has yet to be explained */ + /* could be 0xa800 because sensor is truly 2400 dpi, then halved because + * we only set 1200 dpi */ + if(dev->model->ccd_type==CIS_CANONLIDE80) + { + words_per_color = 0x5400; + } + + length = words_per_color * 3 * 2; + + /* allocate computed size */ + // contains 16bit words in little endian + std::vector shading_data(length, 0); + + /* TARGET/(Wn-Dn) = white gain -> ~1.xxx then it is multiplied by 0x2000 + or 0x4000 to give an integer + Wn = white average for column n + Dn = dark average for column n + */ + if (dev->model->cmd_set->get_gain4_bit(&dev->calib_reg)) + coeff = 0x4000; + else + coeff = 0x2000; + + /* compute avg factor */ + if(dev->settings.xres>sensor.optical_res) + { + factor=1; + } + else + { + factor=sensor.optical_res/dev->settings.xres; + } + + /* for GL646, shading data is planar if REG01_FASTMOD is set and + * chunky if not. For now we rely on the fact that we know that + * each sensor is used only in one mode. Currently only the CIS_XP200 + * sets REG01_FASTMOD. + */ + + /* TODO setup a struct in genesys_devices that + * will handle these settings instead of having this switch growing up */ + cmat[0] = 0; + cmat[1] = 1; + cmat[2] = 2; + switch (dev->model->ccd_type) + { + case CCD_XP300: + case CCD_ROADWARRIOR: + case CCD_DP665: + case CCD_DP685: + case CCD_DSMOBILE600: + target_code = 0xdc00; + o = 4; + compute_planar_coefficients (dev, + shading_data.data(), + factor, + pixels_per_line, + words_per_color, + channels, + cmat, + o, + coeff, + target_code); + break; + case CIS_XP200: + target_code = 0xdc00; + o = 2; + cmat[0] = 2; /* red is last */ + cmat[1] = 0; /* green is first */ + cmat[2] = 1; /* blue is second */ + compute_planar_coefficients (dev, + shading_data.data(), + 1, + pixels_per_line, + words_per_color, + channels, + cmat, + o, + coeff, + target_code); + break; + case CCD_HP2300: + target_code = 0xdc00; + o = 2; + if(dev->settings.xres<=sensor.optical_res/2) + { + o = o - sensor.dummy_pixel / 2; + } + compute_coefficients (dev, + shading_data.data(), + pixels_per_line, + 3, + cmat, + o, + coeff, + target_code); + break; + case CCD_5345: + target_code = 0xe000; + o = 4; + if(dev->settings.xres<=sensor.optical_res/2) + { + o = o - sensor.dummy_pixel; + } + compute_coefficients (dev, + shading_data.data(), + pixels_per_line, + 3, + cmat, + o, + coeff, + target_code); + break; + case CCD_HP3670: + case CCD_HP2400: + target_code = 0xe000; + /* offset is cksel dependent, but we can't use this in common code */ + if(dev->settings.xres<=300) + { + o = -10; /* OK for <=300 */ + } + else if(dev->settings.xres<=600) + { + o = -6; /* ok at 600 */ + } + else + { + o = +2; + } + compute_coefficients (dev, + shading_data.data(), + pixels_per_line, + 3, + cmat, + o, + coeff, + target_code); + break; + case CCD_KVSS080: + case CCD_PLUSTEK3800: + case CCD_G4050: + case CCD_CS4400F: + case CCD_CS8400F: + case CCD_CS8600F: + target_code = 0xe000; + o = 0; + compute_coefficients (dev, + shading_data.data(), + pixels_per_line, + 3, + cmat, + o, + coeff, + target_code); + break; + case CIS_CANONLIDE700: + case CIS_CANONLIDE100: + case CIS_CANONLIDE200: + case CIS_CANONLIDE110: + case CIS_CANONLIDE120: + case CIS_CANONLIDE210: + case CIS_CANONLIDE220: + /* TODO store this in a data struct so we avoid + * growing this switch */ + switch(dev->model->ccd_type) + { + case CIS_CANONLIDE110: + case CIS_CANONLIDE120: + case CIS_CANONLIDE210: + case CIS_CANONLIDE220: + target_code = 0xf000; + break; + case CIS_CANONLIDE700: + target_code = 0xc000; /* from experimentation */ + break; + default: + target_code = 0xdc00; + } + words_per_color=pixels_per_line*2; + length = words_per_color * 3 * 2; + shading_data.clear(); + shading_data.resize(length, 0); + compute_planar_coefficients (dev, + shading_data.data(), + 1, + pixels_per_line, + words_per_color, + channels, + cmat, + 0, + coeff, + target_code); + break; + case CCD_CANONLIDE35: + compute_averaged_planar (dev, sensor, + shading_data.data(), + pixels_per_line, + words_per_color, + channels, + 4, + coeff, + 0xe000, + 0x0a00); + break; + case CIS_CANONLIDE80: + compute_averaged_planar (dev, sensor, + shading_data.data(), + pixels_per_line, + words_per_color, + channels, + 0, + coeff, + 0xe000, + 0x0800); + break; + case CCD_PLUSTEK_3600: + compute_shifted_coefficients (dev, sensor, + shading_data.data(), + pixels_per_line, + channels, + cmat, + 12, /* offset */ + coeff, + 0x0001, /* target_dark */ + 0xf900, /* target_bright */ + 256); /* patch_size: contigous extent */ + break; + default: + DBG (DBG_error, "%s: sensor %d not supported\n", __func__, dev->model->ccd_type); + return SANE_STATUS_UNSUPPORTED; + break; + } + + /* do the actual write of shading calibration data to the scanner */ + status = genesys_send_offset_and_shading (dev, sensor, shading_data.data(), length); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to send shading data: %s\n", __func__, + sane_strstatus (status)); + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** + * search calibration cache list for an entry matching required scan. + * If one is found, set device calibration with it + * @param dev scanner's device + * @return false if no matching cache entry has been + * found, true if one has been found and used. + */ +static bool +genesys_restore_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) +{ + DBGSTART; + + /* if no cache or no function to evaluate cache entry ther can be no match */ + if (!dev->model->cmd_set->is_compatible_calibration + || dev->calibration_cache.empty()) + return false; + + /* we walk the link list of calibration cache in search for a + * matching one */ + for (auto& cache : dev->calibration_cache) + { + if (dev->model->cmd_set->is_compatible_calibration(dev, sensor, &cache, SANE_FALSE)) + { + dev->frontend = cache.frontend; + /* we don't restore the gamma fields */ + sensor.exposure = cache.sensor.exposure; + + dev->average_size = cache.average_size; + dev->calib_pixels = cache.calib_pixels; + dev->calib_channels = cache.calib_channels; + + dev->dark_average_data = cache.dark_average_data; + dev->white_average_data = cache.white_average_data; + + if(dev->model->cmd_set->send_shading_data==NULL) + { + TIE(genesys_send_shading_coefficient(dev, sensor)); + } + + DBG(DBG_proc, "%s: restored\n", __func__); + return true; + } + } + DBG(DBG_proc, "%s: completed(nothing found)\n", __func__); + return false; +} + + +static SANE_Status +genesys_save_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ +#ifdef HAVE_SYS_TIME_H + struct timeval time; +#endif + + DBGSTART; + + if (!dev->model->cmd_set->is_compatible_calibration) + return SANE_STATUS_UNSUPPORTED; + + auto found_cache_it = dev->calibration_cache.end(); + for (auto cache_it = dev->calibration_cache.begin(); cache_it != dev->calibration_cache.end(); + cache_it++) + { + if (dev->model->cmd_set->is_compatible_calibration(dev, sensor, &*cache_it, SANE_TRUE)) + { + found_cache_it = cache_it; + break; + } + } + + /* if we found on overridable cache, we reuse it */ + if (found_cache_it == dev->calibration_cache.end()) + { + /* create a new cache entry and insert it in the linked list */ + dev->calibration_cache.push_back(Genesys_Calibration_Cache()); + found_cache_it = std::prev(dev->calibration_cache.end()); + } + + found_cache_it->average_size = dev->average_size; + + found_cache_it->dark_average_data = dev->dark_average_data; + found_cache_it->white_average_data = dev->white_average_data; + + found_cache_it->used_setup = dev->current_setup; + found_cache_it->frontend = dev->frontend; + found_cache_it->sensor = sensor; + + found_cache_it->calib_pixels = dev->calib_pixels; + found_cache_it->calib_channels = dev->calib_channels; + +#ifdef HAVE_SYS_TIME_H + gettimeofday(&time,NULL); + found_cache_it->last_calibration = time.tv_sec; +#endif + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** + * does the calibration process for a flatbed scanner + * - offset calibration + * - gain calibration + * - shading calibration + * @param dev device to calibrate + * @return SANE_STATUS_GOOD if everything when all right, else the error code. + */ +static SANE_Status +genesys_flatbed_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint32_t pixels_per_line; + int yres; + + DBG(DBG_info, "%s\n", __func__); + + yres = sensor.optical_res; + if (dev->settings.yres <= sensor.optical_res / 2) + yres /= 2; + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + yres = 1200; + + /* do offset calibration if needed */ + if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) + { + status = dev->model->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: offset calibration failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* since all the registers are set up correctly, just use them */ + status = dev->model->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, yres); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: coarse gain calibration: %s\n", __func__, sane_strstatus(status)); + return status; + } + + } + else + /* since we have 2 gain calibration proc, skip second if first one was + used. */ + { + status = dev->model->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send calibration registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + status = genesys_coarse_calibration(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do coarse gain calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + } + + if (dev->model->is_cis) + { + /* the afe now sends valid data for doing led calibration */ + status = dev->model->cmd_set->led_calibration(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: led calibration failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* calibrate afe again to match new exposure */ + if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) + { + status = dev->model->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: offset calibration failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* since all the registers are set up correctly, just use them */ + + status = dev->model->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, yres); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: coarse gain calibration: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + else + /* since we have 2 gain calibration proc, skip second if first one was + used. */ + { + status = dev->model->cmd_set->init_regs_for_coarse_calibration(dev, sensor, + dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send calibration registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + status = genesys_coarse_calibration(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do static calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + } + + /* we always use sensor pixel number when the ASIC can't handle multi-segments sensor */ + if (!(dev->model->flags & GENESYS_FLAG_SIS_SENSOR)) + { + pixels_per_line = (SANE_UNFIX (dev->model->x_size) * dev->settings.xres) / MM_PER_INCH; + } + else + { + pixels_per_line = sensor.sensor_pixels; + } + + /* send default shading data */ + status = sanei_genesys_init_shading_data(dev, sensor, pixels_per_line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to init shading process: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { + RIE(dev->model->cmd_set->move_to_ta(dev)); + } + + /* shading calibration */ + status = dev->model->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send shading registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + if (dev->model->flags & GENESYS_FLAG_DARK_WHITE_CALIBRATION) + { + status = genesys_dark_white_shading_calibration (dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do dark+white shading calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + else + { + if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) + { + status = genesys_dark_shading_calibration(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do dark shading calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + status = genesys_white_shading_calibration (dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do white shading calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + if(dev->model->cmd_set->send_shading_data==NULL) + { + status = genesys_send_shading_coefficient(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send shading calibration coefficients: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + DBG(DBG_info, "%s: completed\n", __func__); + + return SANE_STATUS_GOOD; +} + +/** + * Does the calibration process for a sheetfed scanner + * - offset calibration + * - gain calibration + * - shading calibration + * During calibration a predefined calibration sheet with specific black and white + * areas is used. + * @param dev device to calibrate + * @return SANE_STATUS_GOOD if everything when all right, else the error code. + */ +static SANE_Status genesys_sheetfed_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Bool forward = SANE_TRUE; + int xres; + + DBGSTART; + if (dev->model->cmd_set->search_strip == NULL) + { + DBG(DBG_error, "%s: no strip searching function available\n", __func__); + return SANE_STATUS_UNSUPPORTED; + } + + /* first step, load document */ + status = dev->model->cmd_set->load_document (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to load document: %s\n", __func__, sane_strstatus(status)); + return status; + } + + + DBG(DBG_info, "%s\n", __func__); + + /* led, offset and gain calibration are influenced by scan + * settings. So we set it to sensor resolution */ + xres = sensor.optical_res; + dev->settings.xres = sensor.optical_res; + /* XP200 needs to calibrate a full and half sensor's resolution */ + if (dev->model->ccd_type == CIS_XP200 + && dev->settings.xres <= sensor.optical_res / 2) + dev->settings.xres /= 2; + + /* the afe needs to sends valid data even before calibration */ + + /* go to a white area */ + try { + status = dev->model->cmd_set->search_strip(dev, sensor, forward, SANE_FALSE); + if (status != SANE_STATUS_GOOD) { + DBG(DBG_error, "%s: failed to find white strip: %s\n", __func__, + sane_strstatus(status)); + dev->model->cmd_set->eject_document (dev); + return status; + } + } catch (...) { + dev->model->cmd_set->eject_document(dev); + throw; + } + + if (dev->model->is_cis) + { + status = dev->model->cmd_set->led_calibration(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: led calibration failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + /* calibrate afe */ + if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) + { + status = dev->model->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: offset calibration failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* since all the registers are set up correctly, just use them */ + + status = dev->model->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, xres); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: coarse gain calibration: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + else + /* since we have 2 gain calibration proc, skip second if first one was + used. */ + { + status = dev->model->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send calibration registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + status = genesys_coarse_calibration(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do static calibration: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + /* search for a full width black strip and then do a 16 bit scan to + * gather black shading data */ + if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) + { + /* seek black/white reverse/forward */ + try { + status = dev->model->cmd_set->search_strip(dev, sensor, forward, SANE_TRUE); + if (status != SANE_STATUS_GOOD) { + DBG(DBG_error, "%s: failed to find black strip: %s\n", __func__, + sane_strstatus(status)); + dev->model->cmd_set->eject_document(dev); + return status; + } + } catch (...) { + dev->model->cmd_set->eject_document(dev); + throw; + } + + status = dev->model->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do set up registers for shading calibration: %s\n", + __func__, sane_strstatus(status)); + return status; + } + try { + status = genesys_dark_shading_calibration(dev, sensor); + if (status != SANE_STATUS_GOOD) { + dev->model->cmd_set->eject_document(dev); + DBG(DBG_error, "%s: failed to do dark shading calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } catch (...) { + dev->model->cmd_set->eject_document(dev); + throw; + } + forward = SANE_FALSE; + } + + + /* go to a white area */ + try { + status = dev->model->cmd_set->search_strip(dev, sensor, forward, SANE_FALSE); + if (status != SANE_STATUS_GOOD) { + DBG(DBG_error, "%s: failed to find white strip: %s\n", __func__, + sane_strstatus(status)); + dev->model->cmd_set->eject_document (dev); + return status; + } + } catch (...) { + dev->model->cmd_set->eject_document (dev); + throw; + } + + status = dev->model->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do set up registers for shading calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + try { + status = genesys_white_shading_calibration(dev, sensor); + if (status != SANE_STATUS_GOOD) { + dev->model->cmd_set->eject_document(dev); + DBG(DBG_error, "%s: failed eject target: %s\n", __func__, sane_strstatus(status)); + return status; + } + } catch (...) { + dev->model->cmd_set->eject_document (dev); + throw; + } + + /* in case we haven't black shading data, build it from black pixels + * of white calibration */ + if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) + { + dev->dark_average_data.clear(); + dev->dark_average_data.resize(dev->average_size, 0x0f); + /* XXX STEF XXX + * with black point in white shading, build an average black + * pixel and use it to fill the dark_average + * dev->calib_pixels + (sensor.sensor_pixels * dev->settings.xres) / sensor.optical_res, + dev->calib_lines, + */ + } + + /* send the shading coefficient when doing whole line shading + * but not when using SHDAREA like GL124 */ + if(dev->model->cmd_set->send_shading_data==NULL) + { + status = genesys_send_shading_coefficient(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send shading calibration coefficients: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + /* save the calibration data */ + genesys_save_calibration (dev, sensor); + + /* and finally eject calibration sheet */ + status = dev->model->cmd_set->eject_document (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to eject document: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* resotre settings */ + dev->settings.xres = xres; + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** + * does the calibration process for a device + * @param dev device to calibrate + */ +static SANE_Status +genesys_scanner_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) +{ + if (dev->model->is_sheetfed == SANE_FALSE) + { + return genesys_flatbed_calibration (dev, sensor); + } + return genesys_sheetfed_calibration(dev, sensor); +} + +/* unused function kept in case it may be usefull in the futur */ +#if 0 +static SANE_Status +genesys_wait_not_moving (Genesys_Device * dev, int mseconds) +{ + uint8_t value; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s: waiting %d mseconds for motor to stop\n", __func__, mseconds); + while (mseconds > 0) + { + RIE (sanei_genesys_get_status (dev, &value)); + + if (dev->model->cmd_set->test_motor_flag_bit (value)) + { + sanei_genesys_sleep_ms(100); + mseconds -= 100; + DBG(DBG_io, "%s: motor is moving, %d mseconds to go\n", __func__, mseconds); + } + else + { + DBG(DBG_info, "%s: motor is not moving, exiting\n", __func__); + return SANE_STATUS_GOOD; + } + + } + DBG(DBG_error, "%s: motor is still moving, timeout exceeded\n", __func__); + return SANE_STATUS_DEVICE_BUSY; +} +#endif + + +/* ------------------------------------------------------------------------ */ +/* High level (exported) functions */ +/* ------------------------------------------------------------------------ */ + +/* + * wait lamp to be warm enough by scanning the same line until + * differences between two scans are below a threshold + */ +static SANE_Status +genesys_warmup_lamp (Genesys_Device * dev) +{ + int seconds = 0; + int pixel; + int channels, total_size; + double first_average = 0; + double second_average = 0; + int difference = 255; + int empty, lines = 3; + SANE_Status status = SANE_STATUS_IO_ERROR; + + DBGSTART; + + /* check if the current chipset implements warmup */ + if(dev->model->cmd_set->init_regs_for_warmup==NULL) + { + DBG(DBG_error,"%s: init_regs_for_warmup not implemented\n", __func__); + return status; + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + dev->model->cmd_set->init_regs_for_warmup(dev, sensor, &dev->reg, &channels, &total_size); + std::vector first_line(total_size); + std::vector second_line(total_size); + + do + { + DBG(DBG_info, "%s: one more loop\n", __func__); + RIE(dev->model->cmd_set->begin_scan(dev, sensor, &dev->reg, SANE_FALSE)); + do + { + sanei_genesys_test_buffer_empty (dev, &empty); + } + while (empty); + + try { + status = sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); + if (status != SANE_STATUS_GOOD) { + RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); + } + } catch (...) { + RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); + } + + RIE(dev->model->cmd_set->end_scan(dev, &dev->reg, SANE_TRUE)); + + sanei_genesys_sleep_ms(1000); + seconds++; + + RIE(dev->model->cmd_set->begin_scan(dev, sensor, &dev->reg, SANE_FALSE)); + do + { + sanei_genesys_test_buffer_empty (dev, &empty); + sanei_genesys_sleep_ms(100); + } + while (empty); + RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); + RIE(dev->model->cmd_set->end_scan(dev, &dev->reg, SANE_TRUE)); + + /* compute difference between the two scans */ + for (pixel = 0; pixel < total_size; pixel++) + { + /* 16 bit data */ + if (dev->model->cmd_set->get_bitset_bit(&dev->reg)) + { + first_average += (first_line[pixel] + first_line[pixel + 1] * 256); + second_average += (second_line[pixel] + second_line[pixel + 1] * 256); + pixel++; + } + else + { + first_average += first_line[pixel]; + second_average += second_line[pixel]; + } + } + if (dev->model->cmd_set->get_bitset_bit(&dev->reg)) + { + first_average /= pixel; + second_average /= pixel; + difference = fabs (first_average - second_average); + DBG(DBG_info, "%s: average = %.2f, diff = %.3f\n", __func__, + 100 * ((second_average) / (256 * 256)), + 100 * (difference / second_average)); + + if (second_average > (100 * 256) + && (difference / second_average) < 0.002) + break; + } + else + { + first_average /= pixel; + second_average /= pixel; + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_pnm_file("gl_warmup1.pnm", first_line.data(), 8, channels, + total_size / (lines * channels), lines); + sanei_genesys_write_pnm_file("gl_warmup2.pnm", second_line.data(), 8, channels, + total_size / (lines * channels), lines); + } + DBG(DBG_info, "%s: average 1 = %.2f, average 2 = %.2f\n", __func__, first_average, + second_average); + /* if delta below 15/255 ~= 5.8%, lamp is considred warm enough */ + if (fabs (first_average - second_average) < 15 + && second_average > 55) + break; + } + + /* sleep another second before next loop */ + sanei_genesys_sleep_ms(1000); + seconds++; + } + while (seconds < WARMUP_TIME); + + if (seconds >= WARMUP_TIME) + { + DBG(DBG_error, "%s: warmup timed out after %d seconds. Lamp defective?\n", __func__, seconds); + status = SANE_STATUS_IO_ERROR; + } + else + { + DBG(DBG_info, "%s: warmup succeeded after %d seconds\n", __func__, seconds); + } + + DBGCOMPLETED; + + return status; +} + + +/* High-level start of scanning */ +static SANE_Status +genesys_start_scan (Genesys_Device * dev, SANE_Bool lamp_off) +{ + SANE_Status status = SANE_STATUS_GOOD; + unsigned int steps, expected; + SANE_Bool empty; + + DBGSTART; + + /* since not all scanners are set ot wait for head to park + * we check we are not still parking before starting a new scan */ + if (dev->parking == SANE_TRUE) + { + status = sanei_genesys_wait_for_home (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to wait for head to park: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + /* disable power saving*/ + status = dev->model->cmd_set->save_power (dev, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to disable power saving mode: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* wait for lamp warmup : until a warmup for TRANSPARENCY is designed, skip + * it when scanning from XPA. */ + if (!(dev->model->flags & GENESYS_FLAG_SKIP_WARMUP) + && (dev->settings.scan_method == ScanMethod::FLATBED)) + { + RIE (genesys_warmup_lamp (dev)); + } + + /* set top left x and y values by scanning the internals if flatbed scanners */ + if (dev->model->is_sheetfed == SANE_FALSE) + { + /* do the geometry detection only once */ + if ((dev->model->flags & GENESYS_FLAG_SEARCH_START) + && (dev->model->y_offset_calib == 0)) + { + status = dev->model->cmd_set->search_start_position (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to search start position: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + dev->parking = SANE_FALSE; + status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to move scanhead to home position: %s\n", __func__, + sane_strstatus(status)); + return status; + } + dev->scanhead_position_in_steps = 0; + } + else + { + /* Go home */ + /* TODO: check we can drop this since we cannot have the + scanner's head wandering here */ + dev->parking = SANE_FALSE; + status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to move scanhead to home position: %s\n", __func__, + sane_strstatus(status)); + return status; + } + dev->scanhead_position_in_steps = 0; + } + } + + /* move to calibration area for transparency adapter */ + if ((dev->settings.scan_method == ScanMethod::TRANSPARENCY) + && dev->model->cmd_set->move_to_ta != NULL) + { + status=dev->model->cmd_set->move_to_ta(dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to move to start of transparency adapter: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + /* load document if needed (for sheetfed scanner for instance) */ + if (dev->model->is_sheetfed == SANE_TRUE + && dev->model->cmd_set->load_document != NULL) + { + status = dev->model->cmd_set->load_document (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to load document: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + auto& sensor = sanei_genesys_find_sensor_for_write(dev, dev->settings.xres, + dev->settings.scan_method); + + /* send gamma tables. They have been set to device or user value + * when setting option value */ + status = dev->model->cmd_set->send_gamma_table(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to init gamma table: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* try to use cached calibration first */ + if (!genesys_restore_calibration (dev, sensor)) + { + /* calibration : sheetfed scanners can't calibrate before each scan */ + /* and also those who have the NO_CALIBRATION flag */ + if (!(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) + &&dev->model->is_sheetfed == SANE_FALSE) + { + status = genesys_scanner_calibration(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do scanner calibration: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + genesys_save_calibration (dev, sensor); + } + else + { + DBG(DBG_warn, "%s: no calibration done\n", __func__); + } + } + + /* build look up table for dynamic lineart */ + if(dev->settings.dynamic_lineart==SANE_TRUE) + { + status = sanei_genesys_load_lut(dev->lineart_lut, 8, 8, 50, 205, + dev->settings.threshold_curve, + dev->settings.threshold-127); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to build lut\n", __func__); + return status; + } + } + + if (dev->model->cmd_set->wait_for_motor_stop) { + dev->model->cmd_set->wait_for_motor_stop(dev); + } + + if (dev->model->cmd_set->needs_home_before_init_regs_for_scan && + dev->model->cmd_set->needs_home_before_init_regs_for_scan(dev) && + dev->model->cmd_set->slow_back_home) + { + RIE(dev->model->cmd_set->slow_back_home(dev, SANE_TRUE)); + } + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { + RIE(dev->model->cmd_set->move_to_ta(dev)); + } + + status = dev->model->cmd_set->init_regs_for_scan(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do init registers for scan: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* no lamp during scan */ + if(lamp_off == SANE_TRUE) + { + sanei_genesys_set_lamp_power(dev, sensor, dev->reg, false); + } + + /* GL124 is using SHDAREA, so we have to wait for scan to be set up before + * sending shading data */ + if( (dev->model->cmd_set->send_shading_data!=NULL) + && !(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + status = genesys_send_shading_coefficient(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send shading calibration coefficients: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + /* now send registers for scan */ + status = + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers, status = %d\n", __func__, status); + return status; + } + + /* start effective scan */ + status = dev->model->cmd_set->begin_scan(dev, sensor, &dev->reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + /*do we really need this? the valid data check should be sufficent -- pierre*/ + /* waits for head to reach scanning position */ + expected = dev->reg.get8(0x3d) * 65536 + + dev->reg.get8(0x3e) * 256 + + dev->reg.get8(0x3f); + do + { + // wait some time between each test to avoid overloading USB and CPU + sanei_genesys_sleep_ms(100); + status = sanei_genesys_read_feed_steps (dev, &steps); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to read feed steps: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + while (steps < expected); + + /* wait for buffers to be filled */ + do + { + RIE (sanei_genesys_test_buffer_empty (dev, &empty)); + } + while (empty); + + /* when doing one or two-table movement, let the motor settle to scanning speed */ + /* and scanning start before reading data */ +/* the valid data check already waits until the scanner delivers data. this here leads to unnecessary buffer full conditions in the scanner. + if (dev->model->cmd_set->get_fast_feed_bit (dev->reg)) + sanei_genesys_sleep_ms(1000); + else + sanei_genesys_sleep_ms(500); +*/ + /* then we wait for at least one word of valid scan data + + this is also done in sanei_genesys_read_data_from_scanner -- pierre */ + if (dev->model->is_sheetfed == SANE_FALSE) + { + do + { + sanei_genesys_sleep_ms(100); + status = sanei_genesys_read_valid_words (dev, &steps); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read valid words: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + while (steps < 1); + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* this is _not_ a ringbuffer. + if we need a block which does not fit at the end of our available data, + we move the available data to the beginning. + */ + +void Genesys_Buffer::alloc(size_t size) +{ + buffer_.resize(size); + avail_ = 0; + pos_ = 0; +} + +void Genesys_Buffer::clear() +{ + buffer_.clear(); + avail_ = 0; + pos_ = 0; +} + +void Genesys_Buffer::reset() +{ + avail_ = 0; + pos_ = 0; +} + +uint8_t* Genesys_Buffer::get_write_pos(size_t size) +{ + if (avail_ + size > buffer_.size()) + return nullptr; + if (pos_ + avail_ + size > buffer_.size()) + { + std::memmove(buffer_.data(), buffer_.data() + pos_, avail_); + pos_ = 0; + } + return buffer_.data() + pos_ + avail_; +} + +uint8_t* Genesys_Buffer::get_read_pos() +{ + return buffer_.data() + pos_; +} + +void Genesys_Buffer::produce(size_t size) +{ + if (size > buffer_.size() - avail_) + throw std::runtime_error("buffer size exceeded"); + avail_ += size; +} + +void Genesys_Buffer::consume(size_t size) +{ + if (size > avail_) + throw std::runtime_error("no more data in buffer"); + avail_ -= size; + pos_ += size; +} + + +#include "genesys_conv.cc" + +static SANE_Status accurate_line_read(Genesys_Device * dev, + Genesys_Buffer& buffer) +{ + buffer.reset(); + + SANE_Status status = SANE_STATUS_GOOD; + status = dev->model->cmd_set->bulk_read_data(dev, 0x45, buffer.get_write_pos(buffer.size()), + buffer.size()); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, (u_long) buffer.size(), + sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + buffer.produce(buffer.size()); + return status; +} + +/** @brief fill buffer while reducing vertical resolution + * This function fills a read buffer with scanned data from a sensor + * which puts odd and even pixels in 2 different data segment. So a complete + * must be read and bytes interleaved to get usable by the other stages + * of the backend + */ +static SANE_Status +genesys_fill_line_interp_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, size_t size) +{ + size_t count; + SANE_Status status = SANE_STATUS_GOOD; + + /* fill buffer if needed */ + if (dev->oe_buffer.avail() == 0) + { + status = accurate_line_read(dev, dev->oe_buffer); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, + (u_long) dev->oe_buffer.size(), sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + } + + /* copy size bytes of data, copying from a line when line count matches */ + count = 0; + while (count < size) + { + /* line counter */ + /* dev->line_interp holds the number of lines scanned for one line of data sent */ + if(((dev->line_count/dev->current_setup.channels) % dev->line_interp)==0) + { + /* copy pixel when line matches */ + work_buffer_dst[count] = dev->oe_buffer.get_read_pos()[dev->cur]; + count++; + } + + /* always update pointer so we skip uncopied data */ + dev->cur++; + + /* go to next line if needed */ + if (dev->cur == dev->len) + { + dev->oe_buffer.set_pos(dev->oe_buffer.pos() + dev->bpl); + dev->cur = 0; + dev->line_count++; + } + + /* read a new buffer if needed */ + if (dev->oe_buffer.pos() >= dev->oe_buffer.avail()) + { + status = accurate_line_read(dev, dev->oe_buffer); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, + (u_long) dev->oe_buffer.size(), sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + } + } + + return SANE_STATUS_GOOD; +} + +/** @brief fill buffer for segmented sensors + * This function fills a read buffer with scanned data from a sensor segmented + * in several parts (multi-lines sensors). Data of the same valid area is read + * back to back and must be interleaved to get usable by the other stages + * of the backend + */ +static SANE_Status +genesys_fill_segmented_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, size_t size) +{ + size_t count; + SANE_Status status = SANE_STATUS_GOOD; + int depth,i,n,k; + + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART && dev->settings.dynamic_lineart==SANE_FALSE) + depth = 1; + + /* fill buffer if needed */ + if (dev->oe_buffer.avail() == 0) + { + status = accurate_line_read(dev, dev->oe_buffer); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, + (u_long) dev->oe_buffer.size(), sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + } + + /* copy size bytes of data, copying from a subwindow of each line + * when last line of buffer is exhausted, read another one */ + count = 0; + while (count < size) + { + if (depth==1) { + while (dev->cur < dev->len && count < size) { + for (n=0; nsegnb; n++) { + work_buffer_dst[count+n] = 0; + } + /* interleaving is at bit level */ + for (i=0;i<8;i++) { + k=count+(i*dev->segnb)/8; + for (n=0;nsegnb;n++) { + work_buffer_dst[k] = work_buffer_dst[k] << 1; + if ((dev->oe_buffer.get_read_pos()[dev->cur + dev->skip + dev->dist*dev->order[n]])&(128>>i)) { + work_buffer_dst[k] |= 1; + } + } + } + + /* update counter and pointer */ + count += dev->segnb; + dev->cur++; + } + } + if (depth==8) { + while (dev->cur < dev->len && count < size) { + for (n=0;nsegnb;n++) { + work_buffer_dst[count+n] = dev->oe_buffer.get_read_pos()[dev->cur + dev->skip + dev->dist*dev->order[n]]; + } + /* update counter and pointer */ + count += dev->segnb; + dev->cur++; + } + } + if (depth==16) { + while (dev->cur < dev->len && count < size) { + for (n=0;nsegnb;n++) { + work_buffer_dst[count+n*2] = dev->oe_buffer.get_read_pos()[dev->cur + dev->skip + dev->dist*dev->order[n]]; + work_buffer_dst[count+n*2+1] = dev->oe_buffer.get_read_pos()[dev->cur + dev->skip + dev->dist*dev->order[n] + 1]; + } + /* update counter and pointer */ + count += dev->segnb*2; + dev->cur+=2; + } + } + + /* go to next line if needed */ + if (dev->cur == dev->len) + { + dev->oe_buffer.set_pos(dev->oe_buffer.pos() + dev->bpl); + dev->cur = 0; + } + + /* read a new buffer if needed */ + if (dev->oe_buffer.pos() >= dev->oe_buffer.avail()) + { + status = accurate_line_read(dev, dev->oe_buffer); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, + (u_long) dev->oe_buffer.size(), sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + } + } + + return SANE_STATUS_GOOD; +} + +/** + * + */ +static SANE_Status +genesys_fill_read_buffer (Genesys_Device * dev) +{ + size_t size; + size_t space; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t *work_buffer_dst; + + DBGSTART; + + /* for sheetfed scanner, we must check is document is shorter than + * the requested scan */ + if (dev->model->is_sheetfed == SANE_TRUE) + { + status = dev->model->cmd_set->detect_document_end (dev); + if (status != SANE_STATUS_GOOD) + return status; + } + + space = dev->read_buffer.size() - dev->read_buffer.avail(); + + work_buffer_dst = dev->read_buffer.get_write_pos(space); + + size = space; + + /* never read an odd number. exception: last read + the chip internal counter does not count half words. */ + size &= ~1; + /* Some setups need the reads to be multiples of 256 bytes */ + size &= ~0xff; + + if (dev->read_bytes_left < size) + { + size = dev->read_bytes_left; + /*round up to a multiple of 256 bytes */ + size += (size & 0xff) ? 0x100 : 0x00; + size &= ~0xff; + } + + /* early out if our remaining buffer capacity is too low */ + if (size == 0) + return SANE_STATUS_GOOD; + + DBG(DBG_io, "%s: reading %lu bytes\n", __func__, (u_long) size); + + /* size is already maxed to our needs. for most models bulk_read_data + will read as much data as requested. */ + + /* due to sensors and motors, not all data can be directly used. It + * may have to be read from another intermediate buffer and then processed. + * There are currently 3 intermediate stages: + * - handling of odd/even sensors + * - handling of line interpolation for motors that can't have low + * enough dpi + * - handling of multi-segments sensors + * + * This is also the place where full duplex data will be handled. + */ + if (dev->line_interp>0) + { + /* line interpolation */ + status = genesys_fill_line_interp_buffer (dev, work_buffer_dst, size); + } + else if (dev->segnb>1) + { + /* multi-segment sensors processing */ + status = genesys_fill_segmented_buffer (dev, work_buffer_dst, size); + } + else /* regular case with no extra copy */ + { + status = dev->model->cmd_set->bulk_read_data (dev, 0x45, work_buffer_dst, size); + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, (u_long) size, + sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + if (size > dev->read_bytes_left) + size = dev->read_bytes_left; + + dev->read_bytes_left -= size; + + dev->read_buffer.produce(size); + + DBGCOMPLETED; + + return SANE_STATUS_GOOD; +} + +/* this function does the effective data read in a manner that suits + the scanner. It does data reordering and resizing if need. + It also manages EOF and I/O errors, and line distance correction. + */ +static SANE_Status +genesys_read_ordered_data (Genesys_Device * dev, SANE_Byte * destination, + size_t * len) +{ + SANE_Status status = SANE_STATUS_GOOD; + size_t bytes, extra; + unsigned int channels, depth, src_pixels; + unsigned int ccd_shift[12], shift_count; + uint8_t *work_buffer_src; + uint8_t *work_buffer_dst; + unsigned int dst_lines; + unsigned int step_1_mode; + unsigned int needs_reorder; + unsigned int needs_ccd; + unsigned int needs_shrink; + unsigned int needs_reverse; + Genesys_Buffer *src_buffer; + Genesys_Buffer *dst_buffer; + + DBGSTART; + if (dev->read_active != SANE_TRUE) + { + DBG(DBG_error, "%s: read not active!\n", __func__); + *len = 0; + return SANE_STATUS_INVAL; + } + + DBG(DBG_info, "%s: ", __func__); + debug_dump(DBG_info, dev->current_setup); + + /* prepare conversion */ + /* current settings */ + channels = dev->current_setup.channels; + depth = dev->current_setup.depth; + + src_pixels = dev->current_setup.pixels; + + needs_reorder = 1; + if (channels != 3 && depth != 16) + needs_reorder = 0; +#ifndef WORDS_BIGENDIAN + if (channels != 3 && depth == 16) + needs_reorder = 0; + if (channels == 3 && depth == 16 && !dev->model->is_cis && + dev->model->line_mode_color_order == COLOR_ORDER_RGB) + needs_reorder = 0; +#endif + if (channels == 3 && depth == 8 && !dev->model->is_cis && + dev->model->line_mode_color_order == COLOR_ORDER_RGB) + needs_reorder = 0; + + needs_ccd = dev->current_setup.max_shift > 0; + needs_shrink = dev->settings.pixels != src_pixels; + needs_reverse = depth == 1; + + DBG(DBG_info, "%s: using filters:%s%s%s%s\n", __func__, + needs_reorder ? " reorder" : "", + needs_ccd ? " ccd" : "", + needs_shrink ? " shrink" : "", + needs_reverse ? " reverse" : ""); + + DBG(DBG_info, "%s: frontend requested %lu bytes\n", __func__, (u_long) * len); + + DBG(DBG_info, "%s: bytes_to_read=%lu, total_bytes_read=%lu\n", __func__, + (u_long) dev->total_bytes_to_read, (u_long) dev->total_bytes_read); + /* is there data left to scan */ + if (dev->total_bytes_read >= dev->total_bytes_to_read) + { + DBG(DBG_proc, "%s: nothing more to scan: EOF\n", __func__); + *len = 0; + + /* issue park command immediatly in case scanner can handle it + * so we save time */ + if (dev->model->is_sheetfed == SANE_FALSE + && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) + && dev->parking == SANE_FALSE) + { + dev->model->cmd_set->slow_back_home (dev, SANE_FALSE); + dev->parking = SANE_TRUE; + } + return SANE_STATUS_EOF; + } + + DBG(DBG_info, "%s: %lu lines left by output\n", __func__, + ((dev->total_bytes_to_read - dev->total_bytes_read) * 8UL) / + (dev->settings.pixels * channels * depth)); + DBG(DBG_info, "%s: %lu lines left by input\n", __func__, + ((dev->read_bytes_left + dev->read_buffer.avail()) * 8UL) / + (src_pixels * channels * depth)); + + if (channels == 1) + { + ccd_shift[0] = 0; + ccd_shift[1] = dev->current_setup.stagger; + shift_count = 2; + } + else + { + ccd_shift[0] = + ((dev->ld_shift_r * dev->settings.yres) / + dev->motor.base_ydpi); + ccd_shift[1] = + ((dev->ld_shift_g * dev->settings.yres) / + dev->motor.base_ydpi); + ccd_shift[2] = + ((dev->ld_shift_b * dev->settings.yres) / + dev->motor.base_ydpi); + + ccd_shift[3] = ccd_shift[0] + dev->current_setup.stagger; + ccd_shift[4] = ccd_shift[1] + dev->current_setup.stagger; + ccd_shift[5] = ccd_shift[2] + dev->current_setup.stagger; + + shift_count = 6; + } + + +/* convert data */ +/* + 0. fill_read_buffer +-------------- read_buffer ---------------------- + 1a). (opt)uncis (assumes color components to be laid out + planar) + 1b). (opt)reverse_RGB (assumes pixels to be BGR or BBGGRR)) +-------------- lines_buffer ---------------------- + 2a). (opt)line_distance_correction (assumes RGB or RRGGBB) + 2b). (opt)unstagger (assumes pixels to be depth*channels/8 + bytes long, unshrinked) +------------- shrink_buffer --------------------- + 3. (opt)shrink_lines (assumes component separation in pixels) +-------------- out_buffer ----------------------- + 4. memcpy to destination (for lineart with bit reversal) +*/ +/*FIXME: for lineart we need sub byte addressing in buffers, or conversion to + bytes at 0. and back to bits at 4. +Problems with the first approach: + - its not clear how to check if we need to output an incomplete byte + because it is the last one. + */ +/*FIXME: add lineart support for gl646. in the meantime add logic to convert + from gray to lineart at the end? would suffer the above problem, + total_bytes_to_read and total_bytes_read help in that case. + */ + + status = genesys_fill_read_buffer (dev); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: genesys_fill_read_buffer failed\n", __func__); + return status; + } + + src_buffer = &(dev->read_buffer); + +/* maybe reorder components/bytes */ + if (needs_reorder) + { +/*not implemented for depth == 1.*/ + if (depth == 1) + { + DBG(DBG_error, "Can't reorder single bit data\n"); + return SANE_STATUS_INVAL; + } + + dst_buffer = &(dev->lines_buffer); + + work_buffer_src = src_buffer->get_read_pos(); + bytes = src_buffer->avail(); + +/*how many bytes can be processed here?*/ +/*we are greedy. we work as much as possible*/ + if (bytes > dst_buffer->size() - dst_buffer->avail()) + bytes = dst_buffer->size() - dst_buffer->avail(); + + dst_lines = (bytes * 8) / (src_pixels * channels * depth); + bytes = (dst_lines * src_pixels * channels * depth) / 8; + + work_buffer_dst = dst_buffer->get_write_pos(bytes); + + DBG(DBG_info, "%s: reordering %d lines\n", __func__, dst_lines); + + if (dst_lines != 0) + { + + if (channels == 3) + { + step_1_mode = 0; + + if (depth == 16) + step_1_mode |= 1; + + if (dev->model->is_cis) + step_1_mode |= 2; + + if (dev->model->line_mode_color_order == COLOR_ORDER_BGR) + step_1_mode |= 4; + + switch (step_1_mode) + { + case 1: /* RGB, chunky, 16 bit */ +#ifdef WORDS_BIGENDIAN + status = + genesys_reorder_components_endian_16 (work_buffer_src, + work_buffer_dst, + dst_lines, + src_pixels, 3); + break; +#endif /*WORDS_BIGENDIAN */ + case 0: /* RGB, chunky, 8 bit */ + status = SANE_STATUS_GOOD; + break; + case 2: /* RGB, cis, 8 bit */ + status = + genesys_reorder_components_cis_8 (work_buffer_src, + work_buffer_dst, + dst_lines, src_pixels); + break; + case 3: /* RGB, cis, 16 bit */ + status = + genesys_reorder_components_cis_16 (work_buffer_src, + work_buffer_dst, + dst_lines, src_pixels); + break; + case 4: /* BGR, chunky, 8 bit */ + status = + genesys_reorder_components_bgr_8 (work_buffer_src, + work_buffer_dst, + dst_lines, src_pixels); + break; + case 5: /* BGR, chunky, 16 bit */ + status = + genesys_reorder_components_bgr_16 (work_buffer_src, + work_buffer_dst, + dst_lines, src_pixels); + break; + case 6: /* BGR, cis, 8 bit */ + status = + genesys_reorder_components_cis_bgr_8 (work_buffer_src, + work_buffer_dst, + dst_lines, + src_pixels); + break; + case 7: /* BGR, cis, 16 bit */ + status = + genesys_reorder_components_cis_bgr_16 (work_buffer_src, + work_buffer_dst, + dst_lines, + src_pixels); + break; + } + } + else + { +#ifdef WORDS_BIGENDIAN + if (depth == 16) + { + status = + genesys_reorder_components_endian_16 (work_buffer_src, + work_buffer_dst, + dst_lines, + src_pixels, 1); + } + else + { + status = SANE_STATUS_GOOD; + } +#else /*!WORDS_BIGENDIAN */ + status = SANE_STATUS_GOOD; +#endif /*WORDS_BIGENDIAN */ + } + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to convert byte ordering(%s)\n", __func__, + sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + dst_buffer->produce(bytes); + src_buffer->consume(bytes); + } + src_buffer = dst_buffer; + } + +/* maybe reverse effects of ccd layout */ + if (needs_ccd) + { +/*should not happen with depth == 1.*/ + if (depth == 1) + { + DBG(DBG_error, "Can't reverse ccd for single bit data\n"); + return SANE_STATUS_INVAL; + } + + dst_buffer = &(dev->shrink_buffer); + + work_buffer_src = src_buffer->get_read_pos(); + bytes = src_buffer->avail(); + + extra = + (dev->current_setup.max_shift * src_pixels * channels * depth) / 8; + +/*extra bytes are reserved, and should not be consumed*/ + if (bytes < extra) + bytes = 0; + else + bytes -= extra; + +/*how many bytes can be processed here?*/ +/*we are greedy. we work as much as possible*/ + if (bytes > dst_buffer->size() - dst_buffer->avail()) + bytes = dst_buffer->size() - dst_buffer->avail(); + + dst_lines = (bytes * 8) / (src_pixels * channels * depth); + bytes = (dst_lines * src_pixels * channels * depth) / 8; + + work_buffer_dst = dst_buffer->get_write_pos(bytes); + + DBG(DBG_info, "%s: un-ccd-ing %d lines\n", __func__, dst_lines); + + if (dst_lines != 0) + { + + if (depth == 8) + status = genesys_reverse_ccd_8 (work_buffer_src, work_buffer_dst, + dst_lines, + src_pixels * channels, + ccd_shift, shift_count); + else + status = genesys_reverse_ccd_16 (work_buffer_src, work_buffer_dst, + dst_lines, + src_pixels * channels, + ccd_shift, shift_count); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to reverse ccd effects(%s)\n", __func__, + sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + dst_buffer->produce(bytes); + src_buffer->consume(bytes); + } + src_buffer = dst_buffer; + } + +/* maybe shrink(or enlarge) lines */ + if (needs_shrink) + { + + dst_buffer = &(dev->out_buffer); + + work_buffer_src = src_buffer->get_read_pos(); + bytes = src_buffer->avail(); + +/*lines in input*/ + dst_lines = (bytes * 8) / (src_pixels * channels * depth); + + /* how many lines can be processed here? */ + /* we are greedy. we work as much as possible */ + bytes = dst_buffer->size() - dst_buffer->avail(); + + if (dst_lines > (bytes * 8) / (dev->settings.pixels * channels * depth)) + dst_lines = (bytes * 8) / (dev->settings.pixels * channels * depth); + + bytes = (dst_lines * dev->settings.pixels * channels * depth) / 8; + + work_buffer_dst = dst_buffer->get_write_pos(bytes); + + DBG(DBG_info, "%s: shrinking %d lines\n", __func__, dst_lines); + + if (dst_lines != 0) + { + if (depth == 1) + status = genesys_shrink_lines_1 (work_buffer_src, + work_buffer_dst, + dst_lines, + src_pixels, + dev->settings.pixels, + channels); + else if (depth == 8) + status = genesys_shrink_lines_8 (work_buffer_src, + work_buffer_dst, + dst_lines, + src_pixels, + dev->settings.pixels, channels); + else + status = genesys_shrink_lines_16 (work_buffer_src, + work_buffer_dst, + dst_lines, + src_pixels, + dev->settings.pixels, channels); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to shrink lines(%s)\n", __func__, sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + /* we just consumed this many bytes*/ + bytes = (dst_lines * src_pixels * channels * depth) / 8; + src_buffer->consume(bytes); + + /* we just created this many bytes*/ + bytes = (dst_lines * dev->settings.pixels * channels * depth) / 8; + dst_buffer->produce(bytes); + } + src_buffer = dst_buffer; + } + + /* move data to destination */ + bytes = src_buffer->avail(); + if (bytes > *len) + bytes = *len; + work_buffer_src = src_buffer->get_read_pos(); + + if (needs_reverse) + { + status = genesys_reverse_bits (work_buffer_src, destination, bytes); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to reverse bits(%s)\n", __func__, sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + *len = bytes; + } + else + { + memcpy (destination, work_buffer_src, bytes); + *len = bytes; + } + + /* avoid signaling some extra data because we have treated a full block + * on the last block */ + if (dev->total_bytes_read + *len > dev->total_bytes_to_read) + *len = dev->total_bytes_to_read - dev->total_bytes_read; + + /* count bytes sent to frontend */ + dev->total_bytes_read += *len; + + src_buffer->consume(bytes); + + /* end scan if all needed data have been read */ + if(dev->total_bytes_read >= dev->total_bytes_to_read) + { + dev->model->cmd_set->end_scan(dev, &dev->reg, SANE_TRUE); + if (dev->model->is_sheetfed == SANE_TRUE) + { + dev->model->cmd_set->eject_document (dev); + } + } + + DBG(DBG_proc, "%s: completed, %lu bytes read\n", __func__, (u_long) bytes); + return SANE_STATUS_GOOD; +} + + + +/* ------------------------------------------------------------------------ */ +/* Start of higher level functions */ +/* ------------------------------------------------------------------------ */ + +static size_t +max_string_size (const SANE_String_Const strings[]) +{ + size_t size, max_size = 0; + SANE_Int i; + + for (i = 0; strings[i]; ++i) + { + size = strlen (strings[i]) + 1; + if (size > max_size) + max_size = size; + } + return max_size; +} + +static SANE_Status +calc_parameters (Genesys_Scanner * s) +{ + SANE_Status status = SANE_STATUS_GOOD; + double tl_x = 0, tl_y = 0, br_x = 0, br_y = 0; + + tl_x = SANE_UNFIX(s->pos_top_left_x); + tl_y = SANE_UNFIX(s->pos_top_left_y); + br_x = SANE_UNFIX(s->pos_bottom_right_x); + br_y = SANE_UNFIX(s->pos_bottom_right_y); + + s->params.last_frame = SANE_TRUE; /* only single pass scanning supported */ + + if (s->mode == SANE_VALUE_SCAN_MODE_GRAY || s->mode == SANE_VALUE_SCAN_MODE_LINEART) { + s->params.format = SANE_FRAME_GRAY; + } else { + s->params.format = SANE_FRAME_RGB; + } + + if (s->mode == SANE_VALUE_SCAN_MODE_LINEART) { + s->params.depth = 1; + } else { + s->params.depth = s->bit_depth; + } + + s->dev->settings.depth = s->bit_depth; + + /* interpolation */ + s->dev->settings.disable_interpolation = s->disable_interpolation; + + // FIXME: use correct sensor + const auto& sensor = sanei_genesys_find_sensor_any(s->dev); + + // hardware settings + if (s->resolution > sensor.optical_res && s->dev->settings.disable_interpolation) { + s->dev->settings.xres = sensor.optical_res; + } else { + s->dev->settings.xres = s->resolution; + } + s->dev->settings.yres = s->resolution; + + s->params.lines = ((br_y - tl_y) * s->dev->settings.yres) / MM_PER_INCH; + s->params.pixels_per_line = ((br_x - tl_x) * s->resolution) / MM_PER_INCH; + + /* we need an even pixels number + * TODO invert test logic or generalize behaviour across all ASICs */ + if ((s->dev->model->flags & GENESYS_FLAG_SIS_SENSOR) + || s->dev->model->asic_type == GENESYS_GL847 + || s->dev->model->asic_type == GENESYS_GL124 + || s->dev->model->asic_type == GENESYS_GL845 + || s->dev->model->asic_type == GENESYS_GL846 + || s->dev->model->asic_type == GENESYS_GL843) + { + if (s->dev->settings.xres <= 1200) + s->params.pixels_per_line = (s->params.pixels_per_line/4)*4; + else + s->params.pixels_per_line = (s->params.pixels_per_line/16)*16; + } + + /* corner case for true lineart for sensor with several segments + * or when xres is doubled to match yres */ + if (s->dev->settings.xres >= 1200 + && ( s->dev->model->asic_type == GENESYS_GL124 + || s->dev->model->asic_type == GENESYS_GL847 + || s->dev->current_setup.xres < s->dev->current_setup.yres + ) + ) + { + s->params.pixels_per_line = (s->params.pixels_per_line/16)*16; + } + + s->params.bytes_per_line = s->params.pixels_per_line; + if (s->params.depth > 8) + { + s->params.depth = 16; + s->params.bytes_per_line *= 2; + } + else if (s->params.depth == 1) + { + s->params.bytes_per_line /= 8; + /* round down pixel number + really? rounding down means loss of at most 7 pixels! -- pierre */ + s->params.pixels_per_line = 8 * s->params.bytes_per_line; + } + + if (s->params.format == SANE_FRAME_RGB) { + s->params.bytes_per_line *= 3; + } + + if (s->mode == SANE_VALUE_SCAN_MODE_COLOR) { + s->dev->settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + } else if (s->mode == SANE_VALUE_SCAN_MODE_GRAY) { + s->dev->settings.scan_mode = ScanColorMode::GRAY; + } else if (s->mode == SANE_TITLE_HALFTONE) { + s->dev->settings.scan_mode = ScanColorMode::HALFTONE; + } else { /* Lineart */ + s->dev->settings.scan_mode = ScanColorMode::LINEART; + } + + if (s->source == STR_FLATBED) { + s->dev->settings.scan_method = ScanMethod::FLATBED; + } else if (s->source == STR_TRANSPARENCY_ADAPTER) { + s->dev->settings.scan_method = ScanMethod::TRANSPARENCY; + } else if (s->source == STR_TRANSPARENCY_ADAPTER_INFRARED) { + s->dev->settings.scan_method = ScanMethod::TRANSPARENCY_INFRARED; + } + + s->dev->settings.lines = s->params.lines; + s->dev->settings.pixels = s->params.pixels_per_line; + s->dev->settings.tl_x = tl_x; + s->dev->settings.tl_y = tl_y; + + // threshold setting + s->dev->settings.threshold = 2.55 * (SANE_UNFIX(s->threshold)); + + // color filter + if (s->color_filter == "Red") { + s->dev->settings.color_filter = ColorFilter::RED; + } else if (s->color_filter == "Green") { + s->dev->settings.color_filter = ColorFilter::GREEN; + } else if (s->color_filter == "Blue") { + s->dev->settings.color_filter = ColorFilter::BLUE; + } else { + s->dev->settings.color_filter = ColorFilter::NONE; + } + + // true gray + if (s->color_filter == "None") { + s->dev->settings.true_gray = 1; + } else { + s->dev->settings.true_gray = 0; + } + + /* dynamic lineart */ + s->dev->settings.dynamic_lineart = SANE_FALSE; + s->dev->settings.threshold_curve=0; + if (!s->disable_dynamic_lineart && s->dev->settings.scan_mode == ScanColorMode::LINEART) { + s->dev->settings.dynamic_lineart = SANE_TRUE; + } + + /* hardware lineart works only when we don't have interleave data + * for GL847 scanners, ie up to 600 DPI, then we have to rely on + * dynamic_lineart */ + if(s->dev->settings.xres > 600 + && s->dev->model->asic_type==GENESYS_GL847 + && s->dev->settings.scan_mode == ScanColorMode::LINEART) + { + s->dev->settings.dynamic_lineart = SANE_TRUE; + } + + // threshold curve for dynamic rasterization + s->dev->settings.threshold_curve = s->threshold_curve; + + /* some digital processing requires the whole picture to be buffered */ + /* no digital processing takes place when doing preview, or when bit depth is + * higher than 8 bits */ + if ((s->swdespeck || s->swcrop || s->swdeskew || s->swderotate ||(SANE_UNFIX(s->swskip)>0)) + && (!s->preview) + && (s->bit_depth <= 8)) + { + s->dev->buffer_image=SANE_TRUE; + } + else + { + s->dev->buffer_image=SANE_FALSE; + } + + /* brigthness and contrast only for for 8 bit scans */ + if(s->bit_depth <= 8) + { + s->dev->settings.contrast = (s->contrast * 127) / 100; + s->dev->settings.brightness = (s->brightness * 127) / 100; + } + else + { + s->dev->settings.contrast=0; + s->dev->settings.brightness=0; + } + + /* cache expiration time */ + s->dev->settings.expiration_time = s->expiration_time; + + return status; +} + + +static SANE_Status +create_bpp_list (Genesys_Scanner * s, SANE_Int * bpp) +{ + int count; + + for (count = 0; bpp[count] != 0; count++) + ; + s->bpp_list[0] = count; + for (count = 0; bpp[count] != 0; count++) + { + s->bpp_list[s->bpp_list[0] - count] = bpp[count]; + } + return SANE_STATUS_GOOD; +} + +/** @brief this function initialize a gamma vector based on the ASIC: + * Set up a default gamma table vector based on device description + * gl646: 12 or 14 bits gamma table depending on GENESYS_FLAG_14BIT_GAMMA + * gl84x: 16 bits + * gl12x: 16 bits + * @param scanner pointer to scanner session to get options + * @param option option number of the gamma table to set + */ +static void +init_gamma_vector_option (Genesys_Scanner * scanner, int option) +{ + /* the option is inactive until the custom gamma control + * is enabled */ + scanner->opt[option].type = SANE_TYPE_INT; + scanner->opt[option].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED; + scanner->opt[option].unit = SANE_UNIT_NONE; + scanner->opt[option].constraint_type = SANE_CONSTRAINT_RANGE; + if (scanner->dev->model->asic_type == GENESYS_GL646) + { + if ((scanner->dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) != 0) + { + scanner->opt[option].size = 16384 * sizeof (SANE_Word); + scanner->opt[option].constraint.range = &u14_range; + } + else + { /* 12 bits gamma tables */ + scanner->opt[option].size = 4096 * sizeof (SANE_Word); + scanner->opt[option].constraint.range = &u12_range; + } + } + else + { /* other asics have 16 bits words gamma table */ + scanner->opt[option].size = 256 * sizeof (SANE_Word); + scanner->opt[option].constraint.range = &u16_range; + } +} + +/** + * allocate a geometry range + * @param size maximum size of the range + * @return a pointer to a valid range or NULL + */ +static SANE_Range *create_range(SANE_Fixed size) +{ +SANE_Range *range=NULL; + + range=(SANE_Range *)malloc(sizeof(SANE_Range)); + if(range!=NULL) + { + range->min = SANE_FIX (0.0); + range->max = size; + range->quant = SANE_FIX (0.0); + } + return range; +} + +/** @brief generate calibration cache file nam + * Generates the calibration cache file name to use. + * Tries to store the chache in $HOME/.sane or + * then fallbacks to $TMPDIR or TMP. The filename + * uses the model name if only one scanner is plugged + * else is uses the device name when several identical + * scanners are in use. + * @param currdev current scanner device + * @return an allocated string containing a file name + */ +static char *calibration_filename(Genesys_Device *currdev) +{ + char *tmpstr; + char *ptr; + char filename[80]; + unsigned int count; + unsigned int i; + + /* allocate space for result */ + tmpstr = (char*) malloc(PATH_MAX); + if(tmpstr==NULL) + { + return NULL; + } + + /* first compute the DIR where we can store cache: + * 1 - home dir + * 2 - $TMPDIR + * 3 - $TMP + * 4 - tmp dir + * 5 - temp dir + * 6 - then resort to current dir + */ + ptr = getenv ("HOME"); + if(ptr==NULL) + { + ptr = getenv ("USERPROFILE"); + } + if(ptr==NULL) + { + ptr = getenv ("TMPDIR"); + } + if(ptr==NULL) + { + ptr = getenv ("TMP"); + } + + /* now choose filename: + * 1 - if only one scanner, name of the model + * 2 - if several scanners of the same model, use device name, + * replacing special chars + */ + count=0; + /* count models of the same names if several scanners attached */ + if(s_devices->size() > 1) { + for (const auto& dev : *s_devices) { + if (dev.model->model_id == currdev->model->model_id) { + count++; + } + } + } + if(count>1) + { + snprintf(filename,sizeof(filename),"%s.cal",currdev->file_name); + for(i=0;imodel->name); + } + + /* build final final name : store dir + filename */ + if (NULL == ptr) + { + snprintf (tmpstr, PATH_MAX, "%s", filename); + } + else + { +#ifdef HAVE_MKDIR + /* make sure .sane directory exists in existing store dir */ + snprintf (tmpstr, PATH_MAX, "%s%c.sane", ptr, PATH_SEP); + mkdir(tmpstr,0700); +#endif + snprintf (tmpstr, PATH_MAX, "%s%c.sane%c%s", ptr, PATH_SEP, PATH_SEP, filename); + } + + DBG(DBG_info, "%s: calibration filename >%s<\n", __func__, tmpstr); + + return tmpstr; +} + + +static SANE_Status +init_options (Genesys_Scanner * s) +{ + SANE_Int option, count, min_dpi; + SANE_Status status = SANE_STATUS_GOOD; + SANE_Word *dpi_list; + Genesys_Model *model = s->dev->model; + SANE_Range *x_range, *y_range; + + DBGSTART; + + memset (s->opt, 0, sizeof (s->opt)); + + for (option = 0; option < NUM_OPTIONS; ++option) + { + s->opt[option].size = sizeof (SANE_Word); + s->opt[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } + s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; + s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; + + /* "Mode" group: */ + s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode"); + s->opt[OPT_MODE_GROUP].desc = ""; + s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_MODE_GROUP].size = 0; + s->opt[OPT_MODE_GROUP].cap = 0; + s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* scan mode */ + s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; + s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; + s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; + s->opt[OPT_MODE].type = SANE_TYPE_STRING; + s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->opt[OPT_MODE].size = max_string_size (mode_list); + s->opt[OPT_MODE].constraint.string_list = mode_list; + s->mode = SANE_VALUE_SCAN_MODE_GRAY; + + /* scan source */ + s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; + s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; + s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; + s->opt[OPT_SOURCE].type = SANE_TYPE_STRING; + s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->opt[OPT_SOURCE].size = max_string_size (source_list); + s->opt[OPT_SOURCE].constraint.string_list = source_list; + s->source = STR_FLATBED; + if (model->flags & GENESYS_FLAG_HAS_UTA) + { + ENABLE (OPT_SOURCE); + if (model->flags & GENESYS_FLAG_HAS_UTA_INFRARED) { + s->opt[OPT_SOURCE].size = max_string_size(source_list_infrared); + s->opt[OPT_SOURCE].constraint.string_list = source_list_infrared; + } + } + else + { + DISABLE (OPT_SOURCE); + } + + /* preview */ + s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; + s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; + s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; + s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; + s->opt[OPT_PREVIEW].unit = SANE_UNIT_NONE; + s->opt[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE; + s->preview = false; + + /* bit depth */ + s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; + s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; + s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; + s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT; + s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; + s->opt[OPT_BIT_DEPTH].size = sizeof (SANE_Word); + s->opt[OPT_BIT_DEPTH].constraint.word_list = 0; + s->opt[OPT_BIT_DEPTH].constraint.word_list = s->bpp_list; + create_bpp_list (s, model->bpp_gray_values); + s->bit_depth = 8; + if (s->opt[OPT_BIT_DEPTH].constraint.word_list[0] < 2) + DISABLE (OPT_BIT_DEPTH); + + /* resolution */ + min_dpi=200000; + for (count = 0; model->xdpi_values[count] != 0; count++) + { + if(model->xdpi_values[count]xdpi_values[count]; + } + } + dpi_list = (SANE_Word*) malloc((count + 1) * sizeof(SANE_Word)); + if (!dpi_list) + return SANE_STATUS_NO_MEM; + dpi_list[0] = count; + for (count = 0; model->xdpi_values[count] != 0; count++) + dpi_list[count + 1] = model->xdpi_values[count]; + s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; + s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; + s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; + s->opt[OPT_RESOLUTION].constraint.word_list = dpi_list; + s->resolution = min_dpi; + + /* "Geometry" group: */ + s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry"); + s->opt[OPT_GEOMETRY_GROUP].desc = ""; + s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_GEOMETRY_GROUP].size = 0; + s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + x_range=create_range(model->x_size); + if(x_range==NULL) + { + return SANE_STATUS_NO_MEM; + } + + y_range=create_range(model->y_size); + if(y_range==NULL) + { + return SANE_STATUS_NO_MEM; + } + + /* top-left x */ + s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; + s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; + s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; + s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; + s->opt[OPT_TL_X].unit = SANE_UNIT_MM; + s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_TL_X].constraint.range = x_range; + s->pos_top_left_x = 0; + + /* top-left y */ + s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; + s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; + s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; + s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; + s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; + s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_TL_Y].constraint.range = y_range; + s->pos_top_left_y = 0; + + /* bottom-right x */ + s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; + s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; + s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; + s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; + s->opt[OPT_BR_X].unit = SANE_UNIT_MM; + s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BR_X].constraint.range = x_range; + s->pos_bottom_right_x = x_range->max; + + /* bottom-right y */ + s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; + s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; + s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; + s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; + s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; + s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BR_Y].constraint.range = y_range; + s->pos_bottom_right_y = y_range->max; + + /* "Enhancement" group: */ + s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement"); + s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; + s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_ENHANCEMENT_GROUP].size = 0; + s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* custom-gamma table */ + s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA; + s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA; + s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA; + s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL; + s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_ADVANCED; + s->custom_gamma = false; + + /* grayscale gamma vector */ + s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; + s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; + s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR; + init_gamma_vector_option (s, OPT_GAMMA_VECTOR); + + /* red gamma vector */ + s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R; + s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R; + s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R; + init_gamma_vector_option (s, OPT_GAMMA_VECTOR_R); + + /* green gamma vector */ + s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G; + s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G; + s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G; + init_gamma_vector_option (s, OPT_GAMMA_VECTOR_G); + + /* blue gamma vector */ + s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B; + s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B; + s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B; + init_gamma_vector_option (s, OPT_GAMMA_VECTOR_B); + + /* currently, there are only gamma table options in this group, + * so if the scanner doesn't support gamma table, disable the + * whole group */ + if (!(model->flags & GENESYS_FLAG_CUSTOM_GAMMA)) + { + s->opt[OPT_ENHANCEMENT_GROUP].cap |= SANE_CAP_INACTIVE; + s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; + DBG(DBG_info, "%s: custom gamma disabled\n", __func__); + } + + /* software base image enhancements, these are consuming as many + * memory than used by the full scanned image and may fail at high + * resolution + */ + /* software deskew */ + s->opt[OPT_SWDESKEW].name = "swdeskew"; + s->opt[OPT_SWDESKEW].title = "Software deskew"; + s->opt[OPT_SWDESKEW].desc = "Request backend to rotate skewed pages digitally"; + s->opt[OPT_SWDESKEW].type = SANE_TYPE_BOOL; + s->opt[OPT_SWDESKEW].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->swdeskew = false; + + /* software deskew */ + s->opt[OPT_SWDESPECK].name = "swdespeck"; + s->opt[OPT_SWDESPECK].title = "Software despeck"; + s->opt[OPT_SWDESPECK].desc = "Request backend to remove lone dots digitally"; + s->opt[OPT_SWDESPECK].type = SANE_TYPE_BOOL; + s->opt[OPT_SWDESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->swdespeck = false; + + /* software despeckle radius */ + s->opt[OPT_DESPECK].name = "despeck"; + s->opt[OPT_DESPECK].title = "Software despeckle diameter"; + s->opt[OPT_DESPECK].desc = "Maximum diameter of lone dots to remove from scan"; + s->opt[OPT_DESPECK].type = SANE_TYPE_INT; + s->opt[OPT_DESPECK].unit = SANE_UNIT_NONE; + s->opt[OPT_DESPECK].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_DESPECK].constraint.range = &swdespeck_range; + s->opt[OPT_DESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED | SANE_CAP_INACTIVE; + s->despeck = 1; + + /* crop by software */ + s->opt[OPT_SWCROP].name = "swcrop"; + s->opt[OPT_SWCROP].title = SANE_I18N ("Software crop"); + s->opt[OPT_SWCROP].desc = SANE_I18N ("Request backend to remove border from pages digitally"); + s->opt[OPT_SWCROP].type = SANE_TYPE_BOOL; + s->opt[OPT_SWCROP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->opt[OPT_SWCROP].unit = SANE_UNIT_NONE; + s->swcrop = false; + + /* Software blank page skip */ + s->opt[OPT_SWSKIP].name = "swskip"; + s->opt[OPT_SWSKIP].title = SANE_I18N ("Software blank skip percentage"); + s->opt[OPT_SWSKIP].desc = SANE_I18N("Request driver to discard pages with low numbers of dark pixels"); + s->opt[OPT_SWSKIP].type = SANE_TYPE_FIXED; + s->opt[OPT_SWSKIP].unit = SANE_UNIT_PERCENT; + s->opt[OPT_SWSKIP].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_SWSKIP].constraint.range = &(percentage_range); + s->opt[OPT_SWSKIP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->swskip = 0; // disable by default + + /* Software Derotate */ + s->opt[OPT_SWDEROTATE].name = "swderotate"; + s->opt[OPT_SWDEROTATE].title = SANE_I18N ("Software derotate"); + s->opt[OPT_SWDEROTATE].desc = SANE_I18N("Request driver to detect and correct 90 degree image rotation"); + s->opt[OPT_SWDEROTATE].type = SANE_TYPE_BOOL; + s->opt[OPT_SWDEROTATE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->opt[OPT_SWDEROTATE].unit = SANE_UNIT_NONE; + s->swderotate = false; + + /* Software brightness */ + s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; + s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; + s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BRIGHTNESS].constraint.range = &(enhance_range); + s->opt[OPT_BRIGHTNESS].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->brightness = 0; // disable by default + + /* Sowftware contrast */ + s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; + s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; + s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; + s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; + s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; + s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_CONTRAST].constraint.range = &(enhance_range); + s->opt[OPT_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->contrast = 0; // disable by default + + /* "Extras" group: */ + s->opt[OPT_EXTRAS_GROUP].title = SANE_I18N ("Extras"); + s->opt[OPT_EXTRAS_GROUP].desc = ""; + s->opt[OPT_EXTRAS_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_EXTRAS_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_EXTRAS_GROUP].size = 0; + s->opt[OPT_EXTRAS_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* BW threshold */ + s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD; + s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; + s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; + s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED; + s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; + s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_THRESHOLD].constraint.range = &percentage_range; + s->threshold = SANE_FIX(50); + + /* BW threshold curve */ + s->opt[OPT_THRESHOLD_CURVE].name = "threshold-curve"; + s->opt[OPT_THRESHOLD_CURVE].title = SANE_I18N ("Threshold curve"); + s->opt[OPT_THRESHOLD_CURVE].desc = SANE_I18N ("Dynamic threshold curve, from light to dark, normally 50-65"); + s->opt[OPT_THRESHOLD_CURVE].type = SANE_TYPE_INT; + s->opt[OPT_THRESHOLD_CURVE].unit = SANE_UNIT_NONE; + s->opt[OPT_THRESHOLD_CURVE].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_THRESHOLD_CURVE].constraint.range = &threshold_curve_range; + s->threshold_curve = 50; + + /* dynamic linart */ + s->opt[OPT_DISABLE_DYNAMIC_LINEART].name = "disable-dynamic-lineart"; + s->opt[OPT_DISABLE_DYNAMIC_LINEART].title = SANE_I18N ("Disable dynamic lineart"); + s->opt[OPT_DISABLE_DYNAMIC_LINEART].desc = + SANE_I18N ("Disable use of a software adaptive algorithm to generate lineart relying instead on hardware lineart."); + s->opt[OPT_DISABLE_DYNAMIC_LINEART].type = SANE_TYPE_BOOL; + s->opt[OPT_DISABLE_DYNAMIC_LINEART].unit = SANE_UNIT_NONE; + s->opt[OPT_DISABLE_DYNAMIC_LINEART].constraint_type = SANE_CONSTRAINT_NONE; + s->disable_dynamic_lineart = false; + + /* fastmod is required for hw lineart to work */ + if ((s->dev->model->asic_type == GENESYS_GL646) + &&(s->dev->model->motor_type != MOTOR_XP200)) + { + s->opt[OPT_DISABLE_DYNAMIC_LINEART].cap = SANE_CAP_INACTIVE; + } + + /* disable_interpolation */ + s->opt[OPT_DISABLE_INTERPOLATION].name = "disable-interpolation"; + s->opt[OPT_DISABLE_INTERPOLATION].title = + SANE_I18N ("Disable interpolation"); + s->opt[OPT_DISABLE_INTERPOLATION].desc = + SANE_I18N + ("When using high resolutions where the horizontal resolution is smaller " + "than the vertical resolution this disables horizontal interpolation."); + s->opt[OPT_DISABLE_INTERPOLATION].type = SANE_TYPE_BOOL; + s->opt[OPT_DISABLE_INTERPOLATION].unit = SANE_UNIT_NONE; + s->opt[OPT_DISABLE_INTERPOLATION].constraint_type = SANE_CONSTRAINT_NONE; + s->disable_interpolation = false; + + /* color filter */ + s->opt[OPT_COLOR_FILTER].name = "color-filter"; + s->opt[OPT_COLOR_FILTER].title = SANE_I18N ("Color filter"); + s->opt[OPT_COLOR_FILTER].desc = + SANE_I18N + ("When using gray or lineart this option selects the used color."); + s->opt[OPT_COLOR_FILTER].type = SANE_TYPE_STRING; + s->opt[OPT_COLOR_FILTER].constraint_type = SANE_CONSTRAINT_STRING_LIST; + /* true gray not yet supported for GL847 and GL124 scanners */ + if(!model->is_cis || model->asic_type==GENESYS_GL847 || model->asic_type==GENESYS_GL124) + { + s->opt[OPT_COLOR_FILTER].size = max_string_size (color_filter_list); + s->opt[OPT_COLOR_FILTER].constraint.string_list = color_filter_list; + s->color_filter = s->opt[OPT_COLOR_FILTER].constraint.string_list[1]; + } + else + { + s->opt[OPT_COLOR_FILTER].size = max_string_size (cis_color_filter_list); + s->opt[OPT_COLOR_FILTER].constraint.string_list = cis_color_filter_list; + /* default to "None" ie true gray */ + s->color_filter = s->opt[OPT_COLOR_FILTER].constraint.string_list[3]; + } + + /* no support for color filter for cis+gl646 scanners */ + if (model->asic_type == GENESYS_GL646 && model->is_cis) + { + DISABLE (OPT_COLOR_FILTER); + } + + /* calibration store file name */ + s->opt[OPT_CALIBRATION_FILE].name = "calibration-file"; + s->opt[OPT_CALIBRATION_FILE].title = SANE_I18N ("Calibration file"); + s->opt[OPT_CALIBRATION_FILE].desc = SANE_I18N ("Specify the calibration file to use"); + s->opt[OPT_CALIBRATION_FILE].type = SANE_TYPE_STRING; + s->opt[OPT_CALIBRATION_FILE].unit = SANE_UNIT_NONE; + s->opt[OPT_CALIBRATION_FILE].size = PATH_MAX; + s->opt[OPT_CALIBRATION_FILE].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; + s->opt[OPT_CALIBRATION_FILE].constraint_type = SANE_CONSTRAINT_NONE; + s->calibration_file.clear(); + /* disable option if ran as root */ +#ifdef HAVE_GETUID + if(geteuid()==0) + { + DISABLE (OPT_CALIBRATION_FILE); + } +#endif + + /* expiration time for calibration cache entries */ + s->opt[OPT_EXPIRATION_TIME].name = "expiration-time"; + s->opt[OPT_EXPIRATION_TIME].title = SANE_I18N ("Calibration cache expiration time"); + s->opt[OPT_EXPIRATION_TIME].desc = SANE_I18N ("Time (in minutes) before a cached calibration expires. " + "A value of 0 means cache is not used. A negative value means cache never expires."); + s->opt[OPT_EXPIRATION_TIME].type = SANE_TYPE_INT; + s->opt[OPT_EXPIRATION_TIME].unit = SANE_UNIT_NONE; + s->opt[OPT_EXPIRATION_TIME].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_EXPIRATION_TIME].constraint.range = &expiration_range; + s->expiration_time = 60; // 60 minutes by default + + /* Powersave time (turn lamp off) */ + s->opt[OPT_LAMP_OFF_TIME].name = "lamp-off-time"; + s->opt[OPT_LAMP_OFF_TIME].title = SANE_I18N ("Lamp off time"); + s->opt[OPT_LAMP_OFF_TIME].desc = + SANE_I18N + ("The lamp will be turned off after the given time (in minutes). " + "A value of 0 means, that the lamp won't be turned off."); + s->opt[OPT_LAMP_OFF_TIME].type = SANE_TYPE_INT; + s->opt[OPT_LAMP_OFF_TIME].unit = SANE_UNIT_NONE; + s->opt[OPT_LAMP_OFF_TIME].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_LAMP_OFF_TIME].constraint.range = &time_range; + s->lamp_off_time = 15; // 15 minutes + + /* turn lamp off during scan */ + s->opt[OPT_LAMP_OFF].name = "lamp-off-scan"; + s->opt[OPT_LAMP_OFF].title = SANE_I18N ("Lamp off during scan"); + s->opt[OPT_LAMP_OFF].desc = SANE_I18N ("The lamp will be turned off during scan. "); + s->opt[OPT_LAMP_OFF].type = SANE_TYPE_BOOL; + s->opt[OPT_LAMP_OFF].unit = SANE_UNIT_NONE; + s->opt[OPT_LAMP_OFF].constraint_type = SANE_CONSTRAINT_NONE; + s->lamp_off = false; + + s->opt[OPT_SENSOR_GROUP].title = SANE_TITLE_SENSORS; + s->opt[OPT_SENSOR_GROUP].desc = SANE_DESC_SENSORS; + s->opt[OPT_SENSOR_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_SENSOR_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_SENSOR_GROUP].size = 0; + s->opt[OPT_SENSOR_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + s->opt[OPT_SCAN_SW].name = SANE_NAME_SCAN; + s->opt[OPT_SCAN_SW].title = SANE_TITLE_SCAN; + s->opt[OPT_SCAN_SW].desc = SANE_DESC_SCAN; + s->opt[OPT_SCAN_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_SCAN_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_SCAN_SW) + s->opt[OPT_SCAN_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_SCAN_SW].cap = SANE_CAP_INACTIVE; + + /* SANE_NAME_FILE is not for buttons */ + s->opt[OPT_FILE_SW].name = "file"; + s->opt[OPT_FILE_SW].title = SANE_I18N ("File button"); + s->opt[OPT_FILE_SW].desc = SANE_I18N ("File button"); + s->opt[OPT_FILE_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_FILE_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_FILE_SW) + s->opt[OPT_FILE_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_FILE_SW].cap = SANE_CAP_INACTIVE; + + s->opt[OPT_EMAIL_SW].name = SANE_NAME_EMAIL; + s->opt[OPT_EMAIL_SW].title = SANE_TITLE_EMAIL; + s->opt[OPT_EMAIL_SW].desc = SANE_DESC_EMAIL; + s->opt[OPT_EMAIL_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_EMAIL_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_EMAIL_SW) + s->opt[OPT_EMAIL_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_EMAIL_SW].cap = SANE_CAP_INACTIVE; + + s->opt[OPT_COPY_SW].name = SANE_NAME_COPY; + s->opt[OPT_COPY_SW].title = SANE_TITLE_COPY; + s->opt[OPT_COPY_SW].desc = SANE_DESC_COPY; + s->opt[OPT_COPY_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_COPY_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_COPY_SW) + s->opt[OPT_COPY_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_COPY_SW].cap = SANE_CAP_INACTIVE; + + s->opt[OPT_PAGE_LOADED_SW].name = SANE_NAME_PAGE_LOADED; + s->opt[OPT_PAGE_LOADED_SW].title = SANE_TITLE_PAGE_LOADED; + s->opt[OPT_PAGE_LOADED_SW].desc = SANE_DESC_PAGE_LOADED; + s->opt[OPT_PAGE_LOADED_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_PAGE_LOADED_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_PAGE_LOADED_SW) + s->opt[OPT_PAGE_LOADED_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_PAGE_LOADED_SW].cap = SANE_CAP_INACTIVE; + + /* OCR button */ + s->opt[OPT_OCR_SW].name = "ocr"; + s->opt[OPT_OCR_SW].title = SANE_I18N ("OCR button"); + s->opt[OPT_OCR_SW].desc = SANE_I18N ("OCR button"); + s->opt[OPT_OCR_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_OCR_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_OCR_SW) + s->opt[OPT_OCR_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_OCR_SW].cap = SANE_CAP_INACTIVE; + + /* power button */ + s->opt[OPT_POWER_SW].name = "power"; + s->opt[OPT_POWER_SW].title = SANE_I18N ("Power button"); + s->opt[OPT_POWER_SW].desc = SANE_I18N ("Power button"); + s->opt[OPT_POWER_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_POWER_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_POWER_SW) + s->opt[OPT_POWER_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_POWER_SW].cap = SANE_CAP_INACTIVE; + + /* extra button */ + s->opt[OPT_EXTRA_SW].name = "extra"; + s->opt[OPT_EXTRA_SW].title = SANE_I18N ("Extra button"); + s->opt[OPT_EXTRA_SW].desc = SANE_I18N ("Extra button"); + s->opt[OPT_EXTRA_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_EXTRA_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_EXTRA_SW) + s->opt[OPT_EXTRA_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_EXTRA_SW].cap = SANE_CAP_INACTIVE; + + /* calibration needed */ + s->opt[OPT_NEED_CALIBRATION_SW].name = "need-calibration"; + s->opt[OPT_NEED_CALIBRATION_SW].title = SANE_I18N ("Need calibration"); + s->opt[OPT_NEED_CALIBRATION_SW].desc = SANE_I18N ("The scanner needs calibration for the current settings"); + s->opt[OPT_NEED_CALIBRATION_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_NEED_CALIBRATION_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_CALIBRATE) + s->opt[OPT_NEED_CALIBRATION_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_NEED_CALIBRATION_SW].cap = SANE_CAP_INACTIVE; + + /* button group */ + s->opt[OPT_BUTTON_GROUP].title = SANE_I18N ("Buttons"); + s->opt[OPT_BUTTON_GROUP].desc = ""; + s->opt[OPT_BUTTON_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_BUTTON_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_BUTTON_GROUP].size = 0; + s->opt[OPT_BUTTON_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* calibrate button */ + s->opt[OPT_CALIBRATE].name = "calibrate"; + s->opt[OPT_CALIBRATE].title = SANE_I18N ("Calibrate"); + s->opt[OPT_CALIBRATE].desc = + SANE_I18N ("Start calibration using special sheet"); + s->opt[OPT_CALIBRATE].type = SANE_TYPE_BUTTON; + s->opt[OPT_CALIBRATE].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_CALIBRATE) + s->opt[OPT_CALIBRATE].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED | + SANE_CAP_AUTOMATIC; + else + s->opt[OPT_CALIBRATE].cap = SANE_CAP_INACTIVE; + + /* clear calibration cache button */ + s->opt[OPT_CLEAR_CALIBRATION].name = "clear-calibration"; + s->opt[OPT_CLEAR_CALIBRATION].title = SANE_I18N ("Clear calibration"); + s->opt[OPT_CLEAR_CALIBRATION].desc = SANE_I18N ("Clear calibration cache"); + s->opt[OPT_CLEAR_CALIBRATION].type = SANE_TYPE_BUTTON; + s->opt[OPT_CLEAR_CALIBRATION].unit = SANE_UNIT_NONE; + s->opt[OPT_CLEAR_CALIBRATION].size = 0; + s->opt[OPT_CLEAR_CALIBRATION].constraint_type = SANE_CONSTRAINT_NONE; + s->opt[OPT_CLEAR_CALIBRATION].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; + + /* force calibration cache button */ + s->opt[OPT_FORCE_CALIBRATION].name = "force-calibration"; + s->opt[OPT_FORCE_CALIBRATION].title = SANE_I18N("Force calibration"); + s->opt[OPT_FORCE_CALIBRATION].desc = SANE_I18N("Force calibration ignoring all and any calibration caches"); + s->opt[OPT_FORCE_CALIBRATION].type = SANE_TYPE_BUTTON; + s->opt[OPT_FORCE_CALIBRATION].unit = SANE_UNIT_NONE; + s->opt[OPT_FORCE_CALIBRATION].size = 0; + s->opt[OPT_FORCE_CALIBRATION].constraint_type = SANE_CONSTRAINT_NONE; + s->opt[OPT_FORCE_CALIBRATION].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; + + RIE (calc_parameters (s)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Bool present; + +// this function is passed to C API, it must not throw +static SANE_Status +check_present (SANE_String_Const devname) noexcept +{ + present=SANE_TRUE; + DBG(DBG_io, "%s: %s detected.\n", __func__, devname); + return SANE_STATUS_GOOD; +} + +static SANE_Status +attach (SANE_String_Const devname, Genesys_Device ** devp, SANE_Bool may_wait) +{ + DBG_HELPER(dbg); + + Genesys_Device *dev = 0; + unsigned int i; + + + DBG(DBG_proc, "%s: start: devp %s NULL, may_wait = %d\n", __func__, devp ? "!=" : "==", may_wait); + + if (devp) + *devp = 0; + + if (!devname) + { + DBG(DBG_error, "%s: devname == NULL\n", __func__); + return SANE_STATUS_INVAL; + } + + for (auto& dev : *s_devices) { + if (strcmp(dev.file_name, devname) == 0) { + if (devp) + *devp = &dev; + DBG(DBG_info, "%s: device `%s' was already in device list\n", __func__, devname); + return SANE_STATUS_GOOD; + } + } + + DBG(DBG_info, "%s: trying to open device `%s'\n", __func__, devname); + + UsbDevice usb_dev; + + usb_dev.open(devname); + DBG(DBG_info, "%s: device `%s' successfully opened\n", __func__, devname); + + int vendor, product; + usb_dev.get_vendor_product(vendor, product); + + /* KV-SS080 is an auxiliary device which requires a master device to be here */ + if(vendor == 0x04da && product == 0x100f) + { + present=SANE_FALSE; + sanei_usb_find_devices (vendor, 0x1006, check_present); + sanei_usb_find_devices (vendor, 0x1007, check_present); + sanei_usb_find_devices (vendor, 0x1010, check_present); + if (present == SANE_FALSE) { + throw SaneException("master device not present"); + } + } + + bool found_dev = false; + for (i = 0; i < MAX_SCANNERS && genesys_usb_device_list[i].model != 0; i++) + { + if (vendor == genesys_usb_device_list[i].vendor && + product == genesys_usb_device_list[i].product) + { + found_dev = true; + break; + } + } + + if (!found_dev) { + DBG(DBG_error, "%s: vendor 0x%xd product 0x%xd is not supported by this backend\n", __func__, + vendor, product); + return SANE_STATUS_INVAL; + } + + char* new_devname = strdup (devname); + if (!new_devname) { + return SANE_STATUS_NO_MEM; + } + + s_devices->emplace_back(); + dev = &s_devices->back(); + dev->file_name = new_devname; + + dev->model = genesys_usb_device_list[i].model; + dev->vendorId = genesys_usb_device_list[i].vendor; + dev->productId = genesys_usb_device_list[i].product; + dev->usb_mode = 0; /* i.e. unset */ + dev->already_initialized = SANE_FALSE; + + DBG(DBG_info, "%s: found %s flatbed scanner %s at %s\n", __func__, dev->model->vendor, + dev->model->model, dev->file_name); + + if (devp) { + *devp = dev; + } + + usb_dev.close(); + return SANE_STATUS_GOOD; +} + +static SANE_Status +attach_one_device_impl(SANE_String_Const devname) +{ + Genesys_Device *dev; + SANE_Status status = SANE_STATUS_GOOD; + + RIE (attach (devname, &dev, SANE_FALSE)); + + return SANE_STATUS_GOOD; +} + +static SANE_Status attach_one_device(SANE_String_Const devname) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return attach_one_device_impl(devname); + }); +} + +/* configuration framework functions */ + +// this function is passed to C API, it must not throw +static SANE_Status +config_attach_genesys(SANEI_Config __sane_unused__ *config, const char *devname) noexcept +{ + /* the devname has been processed and is ready to be used + * directly. Since the backend is an USB only one, we can + * call sanei_usb_attach_matching_devices straight */ + sanei_usb_attach_matching_devices (devname, attach_one_device); + + return SANE_STATUS_GOOD; +} + +/* probes for scanner to attach to the backend */ +static SANE_Status +probe_genesys_devices (void) +{ + SANEI_Config config; + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + /* set configuration options structure : no option for this backend */ + config.descriptors = NULL; + config.values = NULL; + config.count = 0; + + /* generic configure and attach function */ + status = sanei_configure_attach (GENESYS_CONFIG_FILE, &config, + config_attach_genesys); + + DBG(DBG_info, "%s: %d devices currently attached\n", __func__, (int) s_devices->size()); + + DBGCOMPLETED; + + return status; +} + +/** + * This should be changed if one of the substructures of + Genesys_Calibration_Cache change, but it must be changed if there are + changes that don't change size -- at least for now, as we store most + of Genesys_Calibration_Cache as is. +*/ +static const char* CALIBRATION_IDENT = "sane_genesys"; +static const int CALIBRATION_VERSION = 2; + +bool read_calibration(std::istream& str, Genesys_Device::Calibration& calibration, + const std::string& path) +{ + std::string ident; + serialize(str, ident); + + if (ident != CALIBRATION_IDENT) { + DBG(DBG_info, "%s: Incorrect calibration file '%s' header\n", __func__, path.c_str()); + return false; + } + + size_t version; + serialize(str, version); + + if (version != CALIBRATION_VERSION) { + DBG(DBG_info, "%s: Incorrect calibration file '%s' version\n", __func__, path.c_str()); + return false; + } + + calibration.clear(); + serialize(str, calibration); + return true; +} + +/** + * reads previously cached calibration data + * from file defined in dev->calib_file + */ +static bool sanei_genesys_read_calibration(Genesys_Device::Calibration& calibration, + const std::string& path) +{ + DBG_HELPER(dbg); + + std::ifstream str; + str.open(path); + if (!str.is_open()) { + DBG(DBG_info, "%s: Cannot open %s\n", __func__, path.c_str()); + return false; + } + + return read_calibration(str, calibration, path); +} + +void write_calibration(std::ostream& str, Genesys_Device::Calibration& calibration) +{ + std::string ident = CALIBRATION_IDENT; + serialize(str, ident); + size_t version = CALIBRATION_VERSION; + serialize(str, version); + serialize_newline(str); + serialize(str, calibration); +} + +static void write_calibration(Genesys_Device::Calibration& calibration, const std::string& path) +{ + DBG_HELPER(dbg); + + std::ofstream str; + str.open(path); + if (!str.is_open()) { + throw SaneException("Cannot open calibration for writing"); + } + write_calibration(str, calibration); +} + +/** @brief buffer scanned picture + * In order to allow digital processing, we must be able to put all the + * scanned picture in a buffer. + */ +static SANE_Status +genesys_buffer_image(Genesys_Scanner *s) +{ + SANE_Status status = SANE_STATUS_GOOD; + size_t maximum; /**> maximum bytes size of the scan */ + size_t len; /**> length of scanned data read */ + size_t total; /**> total of butes read */ + size_t size; /**> size of image buffer */ + size_t read_size; /**> size of reads */ + int lines; /** number of lines of the scan */ + Genesys_Device *dev = s->dev; + + /* compute maximum number of lines for the scan */ + if (s->params.lines > 0) + { + lines = s->params.lines; + } + else + { + lines = + (SANE_UNFIX (dev->model->y_size) * dev->settings.yres) / MM_PER_INCH; + } + DBG(DBG_info, "%s: buffering %d lines of %d bytes\n", __func__, lines, + s->params.bytes_per_line); + + /* maximum bytes to read */ + maximum = s->params.bytes_per_line * lines; + if(s->dev->settings.dynamic_lineart==SANE_TRUE) + { + maximum *= 8; + } + + /* initial size of the read buffer */ + size = + ((2048 * 2048) / s->params.bytes_per_line) * s->params.bytes_per_line; + + /* read size */ + read_size = size / 2; + + dev->img_buffer.resize(size); + + /* loop reading data until we reach maximum or EOF */ + total = 0; + while (total < maximum && status != SANE_STATUS_EOF) + { + len = size - maximum; + if (len > read_size) + { + len = read_size; + } + + status = genesys_read_ordered_data(dev, dev->img_buffer.data() + total, &len); + if (status != SANE_STATUS_EOF && status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: %s buffering failed\n", __func__, sane_strstatus(status)); + return status; + } + total += len; + + /* do we need to enlarge read buffer ? */ + if (total + read_size > size && status != SANE_STATUS_EOF) + { + size += read_size; + dev->img_buffer.resize(size); + } + } + + /* since digital processing is going to take place, + * issue head parking command so that the head move while + * computing so we can save time + */ + if (dev->model->is_sheetfed == SANE_FALSE && + dev->parking == SANE_FALSE) + { + dev->model->cmd_set->slow_back_home (dev, dev->model->flags & GENESYS_FLAG_MUST_WAIT); + dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); + } + + /* in case of dynamic lineart, we have buffered gray data which + * must be converted to lineart first */ + if(s->dev->settings.dynamic_lineart==SANE_TRUE) + { + total/=8; + std::vector lineart(total); + + genesys_gray_lineart (dev, + dev->img_buffer.data(), + lineart.data(), + dev->settings.pixels, + (total*8)/dev->settings.pixels, + dev->settings.threshold); + dev->img_buffer = lineart; + } + + /* update counters */ + dev->total_bytes_to_read = total; + dev->total_bytes_read = 0; + + /* update params */ + s->params.lines = total / s->params.bytes_per_line; + if (DBG_LEVEL >= DBG_io2) + { + sanei_genesys_write_pnm_file("gl_unprocessed.pnm", dev->img_buffer.data(), s->params.depth, + s->params.format==SANE_FRAME_RGB ? 3 : 1, + s->params.pixels_per_line, s->params.lines); + } + + return SANE_STATUS_GOOD; +} + +/* -------------------------- SANE API functions ------------------------- */ + +SANE_Status +sane_init_impl(SANE_Int * version_code, SANE_Auth_Callback authorize) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG_INIT (); + DBG(DBG_init, "SANE Genesys backend version %d.%d from %s\n", + SANE_CURRENT_MAJOR, V_MINOR, PACKAGE_STRING); +#ifdef HAVE_LIBUSB + DBG(DBG_init, "SANE Genesys backend built with libusb-1.0\n"); +#endif +#ifdef HAVE_LIBUSB_LEGACY + DBG(DBG_init, "SANE Genesys backend built with libusb\n"); +#endif + + if (version_code) + *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0); + + DBG(DBG_proc, "%s: authorize %s null\n", __func__, authorize ? "!=" : "=="); + + /* init usb use */ + sanei_usb_init (); + + /* init sanei_magic */ + sanei_magic_init(); + + s_scanners.init(); + s_devices.init(); + s_sane_devices.init(); + s_sane_devices_ptrs.init(); + genesys_init_sensor_tables(); + genesys_init_frontend_tables(); + + DBG(DBG_info, "%s: %s endian machine\n", __func__, +#ifdef WORDS_BIGENDIAN + "big" +#else + "little" +#endif + ); + + /* cold-plug case :detection of allready connected scanners */ + status = probe_genesys_devices (); + + DBGCOMPLETED; + + return status; +} + + +extern "C" SANE_Status sane_init(SANE_Int * version_code, SANE_Auth_Callback authorize) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_init_impl(version_code, authorize); + }); +} + +void +sane_exit_impl(void) +{ + DBGSTART; + + sanei_usb_exit(); + + run_functions_at_backend_exit(); + + DBGCOMPLETED; +} + +void sane_exit() +{ + catch_all_exceptions(__func__, [](){ sane_exit_impl(); }); +} + +SANE_Status +sane_get_devices_impl(const SANE_Device *** device_list, SANE_Bool local_only) +{ + DBG(DBG_proc, "%s: start: local_only = %s\n", __func__, + local_only == SANE_TRUE ? "true" : "false"); + + /* hot-plug case : detection of newly connected scanners */ + sanei_usb_scan_devices (); + probe_genesys_devices (); + + s_sane_devices->clear(); + s_sane_devices_ptrs->clear(); + s_sane_devices->reserve(s_devices->size()); + s_sane_devices_ptrs->reserve(s_devices->size() + 1); + + for (auto dev_it = s_devices->begin(); dev_it != s_devices->end();) { + present = SANE_FALSE; + sanei_usb_find_devices(dev_it->vendorId, dev_it->productId, check_present); + if (present) { + s_sane_devices->emplace_back(); + auto& sane_device = s_sane_devices->back(); + sane_device.name = dev_it->file_name; + sane_device.vendor = dev_it->model->vendor; + sane_device.model = dev_it->model->model; + sane_device.type = "flatbed scanner"; + s_sane_devices_ptrs->push_back(&sane_device); + dev_it++; + } else { + dev_it = s_devices->erase(dev_it); + } + } + s_sane_devices_ptrs->push_back(nullptr); + + *((SANE_Device ***)device_list) = s_sane_devices_ptrs->data(); + + DBGCOMPLETED; + + return SANE_STATUS_GOOD; +} + +SANE_Status sane_get_devices(const SANE_Device *** device_list, SANE_Bool local_only) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_get_devices_impl(device_list, local_only); + }); +} + +SANE_Status +sane_open_impl(SANE_String_Const devicename, SANE_Handle * handle) +{ + DBG_HELPER(dbg); + Genesys_Device *dev = nullptr; + SANE_Status status = SANE_STATUS_GOOD; + char *tmpstr; + + DBG(DBG_proc, "%s: devicename = `%s')\n", __func__, devicename); + + /* devicename="" or devicename="genesys" are default values that use + * first available device + */ + if (devicename[0] && strcmp ("genesys", devicename) != 0) + { + /* search for the given devicename in the device list */ + for (auto& d : *s_devices) { + if (strcmp(d.file_name, devicename) == 0) { + dev = &d; + break; + } + } + + if (!dev) + { + DBG(DBG_info, "%s: couldn't find `%s' in devlist, trying attach\n", __func__, devicename); + RIE (attach (devicename, &dev, SANE_TRUE)); + } + else + DBG(DBG_info, "%s: found `%s' in devlist\n", __func__, dev->model->name); + } + else + { + // empty devicename or "genesys" -> use first device + if (!s_devices->empty()) { + dev = &s_devices->front(); + devicename = dev->file_name; + DBG(DBG_info, "%s: empty devicename, trying `%s'\n", __func__, devicename); + } + } + + if (!dev) + return SANE_STATUS_INVAL; + + if (dev->model->flags & GENESYS_FLAG_UNTESTED) + { + DBG(DBG_error0, "WARNING: Your scanner is not fully supported or at least \n"); + DBG(DBG_error0, " had only limited testing. Please be careful and \n"); + DBG(DBG_error0, " report any failure/success to \n"); + DBG(DBG_error0, " sane-devel@alioth-lists.debian.net. Please provide as many\n"); + DBG(DBG_error0, " details as possible, e.g. the exact name of your\n"); + DBG(DBG_error0, " scanner and what does (not) work.\n"); + } + + dbg.vstatus("open device '%s'", dev->file_name); + dev->usb_dev.open(dev->file_name); + dbg.clear(); + + + s_scanners->push_back(Genesys_Scanner()); + auto* s = &s_scanners->back(); + + s->dev = dev; + s->scanning = SANE_FALSE; + s->dev->parking = SANE_FALSE; + s->dev->read_active = SANE_FALSE; + s->dev->force_calibration = 0; + s->dev->line_interp = 0; + s->dev->line_count = 0; + s->dev->segnb = 0; + s->dev->binary=NULL; + + *handle = s; + + if (!dev->already_initialized) + sanei_genesys_init_structs (dev); + + RIE (init_options (s)); + + if (sanei_genesys_init_cmd_set (s->dev) != SANE_STATUS_GOOD) + { + DBG(DBG_error0, "This device doesn't have a valid command set!!\n"); + return SANE_STATUS_IO_ERROR; + } + + // FIXME: we create sensor tables for the sensor, this should happen when we know which sensor + // we will select + RIE (dev->model->cmd_set->init(dev)); + + /* some hardware capabilities are detected through sensors */ + RIE (s->dev->model->cmd_set->update_hardware_sensors (s)); + + /* here is the place to fetch a stored calibration cache */ + if (s->dev->force_calibration == 0) + { + tmpstr=calibration_filename(s->dev); + s->calibration_file = tmpstr; + s->dev->calib_file = tmpstr; + DBG(DBG_info, "%s: Calibration filename set to:\n", __func__); + DBG(DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file.c_str()); + free(tmpstr); + + catch_all_exceptions(__func__, [&]() + { + sanei_genesys_read_calibration(s->dev->calibration_cache, s->dev->calib_file); + }); + } + + return SANE_STATUS_GOOD; +} + +SANE_Status sane_open(SANE_String_Const devicename, SANE_Handle* handle) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_open_impl(devicename, handle); + }); +} + +void +sane_close_impl(SANE_Handle handle) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + /* remove handle from list of open handles: */ + auto it = s_scanners->end(); + for (auto it2 = s_scanners->begin(); it2 != s_scanners->end(); it2++) + { + if (&*it2 == handle) { + it = it2; + break; + } + } + if (it == s_scanners->end()) + { + DBG(DBG_error, "%s: invalid handle %p\n", __func__, handle); + return; /* oops, not a handle we know about */ + } + + Genesys_Scanner* s = &*it; + + /* eject document for sheetfed scanners */ + if (s->dev->model->is_sheetfed == SANE_TRUE) + { + s->dev->model->cmd_set->eject_document (s->dev); + } + else + { + /* in case scanner is parking, wait for the head + * to reach home position */ + if(s->dev->parking==SANE_TRUE) + { + status = sanei_genesys_wait_for_home (s->dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to wait for head to park: %s\n", __func__, + sane_strstatus(status)); + } + } + } + + /* enable power saving before leaving */ + status = s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to enable power saving mode: %s\n", __func__, + sane_strstatus(status)); + } + + // here is the place to store calibration cache + if (s->dev->force_calibration == 0) { + catch_all_exceptions(__func__, [&](){ write_calibration(s->dev->calibration_cache, + s->dev->calib_file); }); + } + + s->dev->already_initialized = SANE_FALSE; + + /* for an handful of bytes .. */ + free ((void *)(size_t)s->opt[OPT_RESOLUTION].constraint.word_list); + free ((void *)(size_t)s->opt[OPT_TL_X].constraint.range); + free ((void *)(size_t)s->opt[OPT_TL_Y].constraint.range); + + s->dev->clear(); + + /* LAMP OFF : same register across all the ASICs */ + sanei_genesys_write_register (s->dev, 0x03, 0x00); + + catch_all_exceptions(__func__, [&](){ s->dev->usb_dev.clear_halt(); }); + + // we need this to avoid these ASIC getting stuck in bulk writes + catch_all_exceptions(__func__, [&](){ s->dev->usb_dev.reset(); }); + + // not freeing s->dev because it's in the dev list + catch_all_exceptions(__func__, [&](){ s->dev->usb_dev.close(); }); + + s_scanners->erase(it); + + DBGCOMPLETED; +} + +void sane_close(SANE_Handle handle) +{ + catch_all_exceptions(__func__, [=]() + { + sane_close_impl(handle); + }); +} + +const SANE_Option_Descriptor * +sane_get_option_descriptor_impl(SANE_Handle handle, SANE_Int option) +{ + Genesys_Scanner *s = (Genesys_Scanner*) handle; + + if ((unsigned) option >= NUM_OPTIONS) + return 0; + DBG(DBG_io2, "%s: option = %s (%d)\n", __func__, s->opt[option].name, option); + return s->opt + option; +} + + +const SANE_Option_Descriptor * +sane_get_option_descriptor(SANE_Handle handle, SANE_Int option) +{ + const SANE_Option_Descriptor* ret = NULL; + catch_all_exceptions(__func__, [&]() + { + ret = sane_get_option_descriptor_impl(handle, option); + }); + return ret; +} + +/* gets an option , called by sane_control_option */ +static SANE_Status +get_option_value (Genesys_Scanner * s, int option, void *val) +{ + unsigned int i; + SANE_Word* table = nullptr; + std::vector gamma_table; + unsigned option_size = 0; + SANE_Status status = SANE_STATUS_GOOD; + + // FIXME: we should pick correct sensor here + const Genesys_Sensor& sensor = sanei_genesys_find_sensor_any(s->dev); + + switch (option) + { + /* geometry */ + case OPT_TL_X: + *reinterpret_cast(val) = s->pos_top_left_x; + break; + case OPT_TL_Y: + *reinterpret_cast(val) = s->pos_top_left_y; + break; + case OPT_BR_X: + *reinterpret_cast(val) = s->pos_bottom_right_x; + break; + case OPT_BR_Y: + *reinterpret_cast(val) = s->pos_bottom_right_y; + break; + /* word options: */ + case OPT_NUM_OPTS: + *reinterpret_cast(val) = NUM_OPTIONS; + break; + case OPT_RESOLUTION: + *reinterpret_cast(val) = s->resolution; + break; + case OPT_BIT_DEPTH: + *reinterpret_cast(val) = s->bit_depth; + break; + case OPT_PREVIEW: + *reinterpret_cast(val) = s->preview; + break; + case OPT_THRESHOLD: + *reinterpret_cast(val) = s->threshold; + break; + case OPT_THRESHOLD_CURVE: + *reinterpret_cast(val) = s->threshold_curve; + break; + case OPT_DISABLE_DYNAMIC_LINEART: + *reinterpret_cast(val) = s->disable_dynamic_lineart; + break; + case OPT_DISABLE_INTERPOLATION: + *reinterpret_cast(val) = s->disable_interpolation; + break; + case OPT_LAMP_OFF: + *reinterpret_cast(val) = s->lamp_off; + break; + case OPT_LAMP_OFF_TIME: + *reinterpret_cast(val) = s->lamp_off_time; + break; + case OPT_SWDESKEW: + *reinterpret_cast(val) = s->swdeskew; + break; + case OPT_SWCROP: + *reinterpret_cast(val) = s->swcrop; + break; + case OPT_SWDESPECK: + *reinterpret_cast(val) = s->swdespeck; + break; + case OPT_SWDEROTATE: + *reinterpret_cast(val) = s->swderotate; + break; + case OPT_SWSKIP: + *reinterpret_cast(val) = s->swskip; + break; + case OPT_DESPECK: + *reinterpret_cast(val) = s->despeck; + break; + case OPT_CONTRAST: + *reinterpret_cast(val) = s->contrast; + break; + case OPT_BRIGHTNESS: + *reinterpret_cast(val) = s->brightness; + break; + case OPT_EXPIRATION_TIME: + *reinterpret_cast(val) = s->expiration_time; + break; + case OPT_CUSTOM_GAMMA: + *reinterpret_cast(val) = s->custom_gamma; + break; + + /* string options: */ + case OPT_MODE: + std::strcpy(reinterpret_cast(val), s->mode.c_str()); + break; + case OPT_COLOR_FILTER: + std::strcpy(reinterpret_cast(val), s->color_filter.c_str()); + break; + case OPT_CALIBRATION_FILE: + std::strcpy(reinterpret_cast(val), s->calibration_file.c_str()); + break; + case OPT_SOURCE: + std::strcpy(reinterpret_cast(val), s->source.c_str()); + break; + + /* word array options */ + case OPT_GAMMA_VECTOR: + table = (SANE_Word *) val; + if (s->color_filter == "Red") { + gamma_table = get_gamma_table(s->dev, sensor, GENESYS_RED); + } else if (s->color_filter == "Blue") { + gamma_table = get_gamma_table(s->dev, sensor, GENESYS_BLUE); + } else { + gamma_table = get_gamma_table(s->dev, sensor, GENESYS_GREEN); + } + option_size = s->opt[option].size / sizeof (SANE_Word); + if (gamma_table.size() != option_size) { + throw std::runtime_error("The size of the gamma tables does not match"); + } + for (i = 0; i < option_size; i++) { + table[i] = gamma_table[i]; + } + break; + case OPT_GAMMA_VECTOR_R: + table = (SANE_Word *) val; + gamma_table = get_gamma_table(s->dev, sensor, GENESYS_RED); + option_size = s->opt[option].size / sizeof (SANE_Word); + if (gamma_table.size() != option_size) { + throw std::runtime_error("The size of the gamma tables does not match"); + } + for (i = 0; i < option_size; i++) { + table[i] = gamma_table[i]; + } + break; + case OPT_GAMMA_VECTOR_G: + table = (SANE_Word *) val; + gamma_table = get_gamma_table(s->dev, sensor, GENESYS_GREEN); + option_size = s->opt[option].size / sizeof (SANE_Word); + if (gamma_table.size() != option_size) { + throw std::runtime_error("The size of the gamma tables does not match"); + } + for (i = 0; i < option_size; i++) { + table[i] = gamma_table[i]; + } + break; + case OPT_GAMMA_VECTOR_B: + table = (SANE_Word *) val; + gamma_table = get_gamma_table(s->dev, sensor, GENESYS_BLUE); + option_size = s->opt[option].size / sizeof (SANE_Word); + if (gamma_table.size() != option_size) { + throw std::runtime_error("The size of the gamma tables does not match"); + } + for (i = 0; i < option_size; i++) { + table[i] = gamma_table[i]; + } + break; + /* sensors */ + case OPT_SCAN_SW: + case OPT_FILE_SW: + case OPT_EMAIL_SW: + case OPT_COPY_SW: + case OPT_PAGE_LOADED_SW: + case OPT_OCR_SW: + case OPT_POWER_SW: + case OPT_EXTRA_SW: + RIE (s->dev->model->cmd_set->update_hardware_sensors (s)); + *(SANE_Bool *) val = s->buttons[genesys_option_to_button(option)].read(); + break; + case OPT_NEED_CALIBRATION_SW: + /* scanner needs calibration for current mode unless a matching + * calibration cache is found */ + *(SANE_Bool *) val = SANE_TRUE; + for (auto& cache : s->dev->calibration_cache) + { + if (s->dev->model->cmd_set->is_compatible_calibration(s->dev, sensor, &cache, SANE_FALSE)) + { + *(SANE_Bool *) val = SANE_FALSE; + } + } + break; + default: + DBG(DBG_warn, "%s: can't get unknown option %d\n", __func__, option); + } + return status; +} + +/** @brief set calibration file value + * Set calibration file value. Load new cache values from file if it exists, + * else creates the file*/ +static void set_calibration_value(Genesys_Scanner* s, const char* val) +{ + DBG_HELPER(dbg); + + std::string new_calib_path = val; + Genesys_Device::Calibration new_calibration; + + bool is_calib_success = false; + catch_all_exceptions(__func__, [&]() + { + is_calib_success = sanei_genesys_read_calibration(new_calibration, new_calib_path); + }); + + if (!is_calib_success) { + return; + } + + s->dev->calibration_cache = std::move(new_calibration); + s->dev->calib_file = new_calib_path; + s->calibration_file = new_calib_path; + DBG(DBG_info, "%s: Calibration filename set to '%s':\n", __func__, new_calib_path.c_str()); +} + +/* sets an option , called by sane_control_option */ +static SANE_Status +set_option_value (Genesys_Scanner * s, int option, void *val, + SANE_Int * myinfo) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Word *table; + unsigned int i; + SANE_Range *x_range, *y_range; + unsigned option_size = 0; + + // FIXME: we should modify device-specific sensor + auto& sensor = sanei_genesys_find_sensor_any_for_write(s->dev); + + switch (option) + { + case OPT_TL_X: + s->pos_top_left_x = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_TL_Y: + s->pos_top_left_y = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_BR_X: + s->pos_bottom_right_x = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_BR_Y: + s->pos_bottom_right_y = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_RESOLUTION: + s->resolution = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_THRESHOLD: + s->threshold = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_THRESHOLD_CURVE: + s->threshold_curve = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_DISABLE_DYNAMIC_LINEART: + s->disable_dynamic_lineart = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWCROP: + s->swcrop = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWDESKEW: + s->swdeskew = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_DESPECK: + s->despeck = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWDEROTATE: + s->swderotate = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWSKIP: + s->swskip = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_DISABLE_INTERPOLATION: + s->disable_interpolation = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_LAMP_OFF: + s->lamp_off = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_PREVIEW: + s->preview = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_BRIGHTNESS: + s->brightness = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_CONTRAST: + s->contrast = *reinterpret_cast(val); + RIE (calc_parameters(s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWDESPECK: + s->swdespeck = *reinterpret_cast(val); + if (s->swdespeck) { + ENABLE(OPT_DESPECK); + } else { + DISABLE(OPT_DESPECK); + } + RIE (calc_parameters (s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + /* software enhancement functions only apply to 8 or 1 bits data */ + case OPT_BIT_DEPTH: + s->bit_depth = *reinterpret_cast(val); + if(s->bit_depth>8) + { + DISABLE(OPT_SWDESKEW); + DISABLE(OPT_SWDESPECK); + DISABLE(OPT_SWCROP); + DISABLE(OPT_DESPECK); + DISABLE(OPT_SWDEROTATE); + DISABLE(OPT_SWSKIP); + DISABLE(OPT_CONTRAST); + DISABLE(OPT_BRIGHTNESS); + } + else + { + ENABLE(OPT_SWDESKEW); + ENABLE(OPT_SWDESPECK); + ENABLE(OPT_SWCROP); + ENABLE(OPT_DESPECK); + ENABLE(OPT_SWDEROTATE); + ENABLE(OPT_SWSKIP); + ENABLE(OPT_CONTRAST); + ENABLE(OPT_BRIGHTNESS); + } + RIE (calc_parameters (s)); + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + case OPT_SOURCE: + if (s->source != reinterpret_cast(val)) { + s->source = reinterpret_cast(val); + + // change geometry constraint to the new source value + if (s->source == STR_FLATBED) + { + x_range=create_range(s->dev->model->x_size); + y_range=create_range(s->dev->model->y_size); + } + else + { + x_range=create_range(s->dev->model->x_size_ta); + y_range=create_range(s->dev->model->y_size_ta); + } + if(x_range==NULL || y_range==NULL) + { + return SANE_STATUS_NO_MEM; + } + + /* assign new values */ + free((void *)(size_t)s->opt[OPT_TL_X].constraint.range); + free((void *)(size_t)s->opt[OPT_TL_Y].constraint.range); + s->opt[OPT_TL_X].constraint.range = x_range; + s->pos_top_left_x = 0; + s->opt[OPT_TL_Y].constraint.range = y_range; + s->pos_top_left_y = 0; + s->opt[OPT_BR_X].constraint.range = x_range; + s->pos_bottom_right_x = x_range->max; + s->opt[OPT_BR_Y].constraint.range = y_range; + s->pos_bottom_right_y = y_range->max; + + /* signals reload */ + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + } + break; + case OPT_MODE: + s->mode = reinterpret_cast(val); + + if (s->mode == SANE_VALUE_SCAN_MODE_LINEART) + { + ENABLE (OPT_THRESHOLD); + ENABLE (OPT_THRESHOLD_CURVE); + DISABLE (OPT_BIT_DEPTH); + if (s->dev->model->asic_type != GENESYS_GL646 || !s->dev->model->is_cis) + { + ENABLE (OPT_COLOR_FILTER); + } + ENABLE (OPT_DISABLE_DYNAMIC_LINEART); + } + else + { + DISABLE (OPT_THRESHOLD); + DISABLE (OPT_THRESHOLD_CURVE); + DISABLE (OPT_DISABLE_DYNAMIC_LINEART); + if (s->mode == SANE_VALUE_SCAN_MODE_GRAY) + { + if (s->dev->model->asic_type != GENESYS_GL646 || !s->dev->model->is_cis) + { + ENABLE (OPT_COLOR_FILTER); + } + create_bpp_list (s, s->dev->model->bpp_gray_values); + } + else + { + DISABLE (OPT_COLOR_FILTER); + create_bpp_list (s, s->dev->model->bpp_color_values); + } + if (s->bpp_list[0] < 2) + DISABLE (OPT_BIT_DEPTH); + else + ENABLE (OPT_BIT_DEPTH); + } + RIE (calc_parameters (s)); + + /* if custom gamma, toggle gamma table options according to the mode */ + if (s->custom_gamma) + { + if (s->mode == SANE_VALUE_SCAN_MODE_COLOR) + { + DISABLE (OPT_GAMMA_VECTOR); + ENABLE (OPT_GAMMA_VECTOR_R); + ENABLE (OPT_GAMMA_VECTOR_G); + ENABLE (OPT_GAMMA_VECTOR_B); + } + else + { + ENABLE (OPT_GAMMA_VECTOR); + DISABLE (OPT_GAMMA_VECTOR_R); + DISABLE (OPT_GAMMA_VECTOR_G); + DISABLE (OPT_GAMMA_VECTOR_B); + } + } + + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + case OPT_COLOR_FILTER: + s->color_filter = reinterpret_cast(val); + RIE (calc_parameters (s)); + break; + case OPT_CALIBRATION_FILE: + if (s->dev->force_calibration == 0) { + set_calibration_value(s, reinterpret_cast(val)); + } + break; + case OPT_LAMP_OFF_TIME: + if (*reinterpret_cast(val) != s->lamp_off_time) { + s->lamp_off_time = *reinterpret_cast(val); + RIE(s->dev->model->cmd_set->set_powersaving(s->dev, s->lamp_off_time)); + } + break; + case OPT_EXPIRATION_TIME: + if (*reinterpret_cast(val) != s->expiration_time) { + s->expiration_time = *reinterpret_cast(val); + // BUG: this is most likely not intended behavior, found out during refactor + RIE(s->dev->model->cmd_set->set_powersaving(s->dev, s->expiration_time)); + } + break; + + case OPT_CUSTOM_GAMMA: + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + s->custom_gamma = *reinterpret_cast(val); + + if (s->custom_gamma) { + if (s->mode == SANE_VALUE_SCAN_MODE_COLOR) + { + DISABLE (OPT_GAMMA_VECTOR); + ENABLE (OPT_GAMMA_VECTOR_R); + ENABLE (OPT_GAMMA_VECTOR_G); + ENABLE (OPT_GAMMA_VECTOR_B); + } + else + { + ENABLE (OPT_GAMMA_VECTOR); + DISABLE (OPT_GAMMA_VECTOR_R); + DISABLE (OPT_GAMMA_VECTOR_G); + DISABLE (OPT_GAMMA_VECTOR_B); + } + } + else + { + DISABLE (OPT_GAMMA_VECTOR); + DISABLE (OPT_GAMMA_VECTOR_R); + DISABLE (OPT_GAMMA_VECTOR_G); + DISABLE (OPT_GAMMA_VECTOR_B); + for (auto& table : s->dev->gamma_override_tables) { + table.clear(); + } + } + break; + + case OPT_GAMMA_VECTOR: + table = (SANE_Word *) val; + option_size = s->opt[option].size / sizeof (SANE_Word); + + s->dev->gamma_override_tables[GENESYS_RED].resize(option_size); + s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size); + s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size); + for (i = 0; i < option_size; i++) { + s->dev->gamma_override_tables[GENESYS_RED][i] = table[i]; + s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i]; + s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i]; + } + break; + case OPT_GAMMA_VECTOR_R: + table = (SANE_Word *) val; + option_size = s->opt[option].size / sizeof (SANE_Word); + s->dev->gamma_override_tables[GENESYS_RED].resize(option_size); + for (i = 0; i < option_size; i++) { + s->dev->gamma_override_tables[GENESYS_RED][i] = table[i]; + } + break; + case OPT_GAMMA_VECTOR_G: + table = (SANE_Word *) val; + option_size = s->opt[option].size / sizeof (SANE_Word); + s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size); + for (i = 0; i < option_size; i++) { + s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i]; + } + break; + case OPT_GAMMA_VECTOR_B: + table = (SANE_Word *) val; + option_size = s->opt[option].size / sizeof (SANE_Word); + s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size); + for (i = 0; i < option_size; i++) { + s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i]; + } + break; + case OPT_CALIBRATE: + status = s->dev->model->cmd_set->save_power (s->dev, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to disable power saving mode: %s\n", __func__, + sane_strstatus(status)); + } + else + status = genesys_scanner_calibration(s->dev, sensor); + /* not critical if this fails*/ + s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); + /* signals that sensors will have to be read again */ + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + case OPT_CLEAR_CALIBRATION: + s->dev->calibration_cache.clear(); + + /* remove file */ + unlink(s->dev->calib_file.c_str()); + /* signals that sensors will have to be read again */ + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + case OPT_FORCE_CALIBRATION: + s->dev->force_calibration = 1; + s->dev->calibration_cache.clear(); + s->dev->calib_file.clear(); + + /* signals that sensors will have to be read again */ + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + + default: + DBG(DBG_warn, "%s: can't set unknown option %d\n", __func__, option); + } + return status; +} + + +/* sets and gets scanner option values */ +SANE_Status +sane_control_option_impl(SANE_Handle handle, SANE_Int option, + SANE_Action action, void *val, SANE_Int * info) +{ + Genesys_Scanner *s = (Genesys_Scanner*) handle; + SANE_Status status = SANE_STATUS_GOOD; + SANE_Word cap; + SANE_Int myinfo = 0; + + DBG(DBG_io2, "%s: start: action = %s, option = %s (%d)\n", __func__, + (action == SANE_ACTION_GET_VALUE) ? "get" : (action == SANE_ACTION_SET_VALUE) ? + "set" : (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown", + s->opt[option].name, option); + + if (info) + *info = 0; + + if (s->scanning) + { + DBG(DBG_warn, "%s: don't call this function while scanning (option = %s (%d))\n", __func__, + s->opt[option].name, option); + + return SANE_STATUS_DEVICE_BUSY; + } + if (option >= NUM_OPTIONS || option < 0) + { + DBG(DBG_warn, "%s: option %d >= NUM_OPTIONS || option < 0\n", __func__, option); + return SANE_STATUS_INVAL; + } + + cap = s->opt[option].cap; + + if (!SANE_OPTION_IS_ACTIVE (cap)) + { + DBG(DBG_warn, "%s: option %d is inactive\n", __func__, option); + return SANE_STATUS_INVAL; + } + + switch (action) + { + case SANE_ACTION_GET_VALUE: + status = get_option_value (s, option, val); + break; + + case SANE_ACTION_SET_VALUE: + if (!SANE_OPTION_IS_SETTABLE (cap)) + { + DBG(DBG_warn, "%s: option %d is not settable\n", __func__, option); + return SANE_STATUS_INVAL; + } + + status = sanei_constrain_value (s->opt + option, val, &myinfo); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_warn, "%s: sanei_constrain_value returned %s\n", __func__, + sane_strstatus(status)); + return status; + } + + status = set_option_value (s, option, val, &myinfo); + break; + + case SANE_ACTION_SET_AUTO: + DBG(DBG_error, + "%s: SANE_ACTION_SET_AUTO unsupported since no option has SANE_CAP_AUTOMATIC\n", + __func__); + status = SANE_STATUS_INVAL; + break; + + default: + DBG(DBG_warn, "%s: unknown action %d for option %d\n", __func__, action, option); + status = SANE_STATUS_INVAL; + break; + } + + if (info) + *info = myinfo; + + DBG(DBG_io2, "%s: exit\n", __func__); + return status; +} + +SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, + SANE_Action action, void *val, SANE_Int * info) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_control_option_impl(handle, option, action, val, info); + }); +} + +SANE_Status sane_get_parameters_impl(SANE_Handle handle, SANE_Parameters* params) +{ + Genesys_Scanner *s = (Genesys_Scanner*) handle; + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + /* don't recompute parameters once data reading is active, ie during scan */ + if(s->dev->read_active == SANE_FALSE) + { + RIE (calc_parameters (s)); + } + if (params) + { + *params = s->params; + + /* in the case of a sheetfed scanner, when full height is specified + * we override the computed line number with -1 to signal that we + * don't know the real document height. + * We don't do that doing buffering image for digital processing + */ + if (s->dev->model->is_sheetfed == SANE_TRUE + && s->dev->buffer_image == SANE_FALSE + && s->pos_bottom_right_y == s->opt[OPT_BR_Y].constraint.range->max) + { + params->lines = -1; + } + } + + DBGCOMPLETED; + + return SANE_STATUS_GOOD; +} + +SANE_Status sane_get_parameters(SANE_Handle handle, SANE_Parameters* params) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_get_parameters_impl(handle, params); + }); +} + +SANE_Status sane_start_impl(SANE_Handle handle) +{ + Genesys_Scanner *s = (Genesys_Scanner*) handle; + SANE_Status status=SANE_STATUS_GOOD; + + DBGSTART; + + if (s->pos_top_left_x >= s->pos_bottom_right_x) + { + DBG(DBG_error0, "%s: top left x >= bottom right x --- exiting\n", __func__); + return SANE_STATUS_INVAL; + } + if (s->pos_top_left_y >= s->pos_bottom_right_y) + { + DBG(DBG_error0, "%s: top left y >= bottom right y --- exiting\n", __func__); + return SANE_STATUS_INVAL; + } + + /* First make sure we have a current parameter set. Some of the + parameters will be overwritten below, but that's OK. */ + + RIE (calc_parameters (s)); + RIE(genesys_start_scan(s->dev, s->lamp_off)); + + s->scanning = SANE_TRUE; + + /* allocate intermediate buffer when doing dynamic lineart */ + if(s->dev->settings.dynamic_lineart==SANE_TRUE) + { + s->dev->binarize_buffer.clear(); + s->dev->binarize_buffer.alloc(s->dev->settings.pixels); + s->dev->local_buffer.clear(); + s->dev->local_buffer.alloc(s->dev->binarize_buffer.size() * 8); + } + + /* if one of the software enhancement option is selected, + * we do the scan internally, process picture then put it an internal + * buffer. Since cropping may change scan parameters, we recompute them + * at the end */ + if (s->dev->buffer_image) + { + RIE(genesys_buffer_image(s)); + + /* check if we need to skip this page, sheetfed scanners + * can go to next doc while flatbed ones can't */ + if (s->swskip > 0 && IS_ACTIVE(OPT_SWSKIP)) { + status = sanei_magic_isBlank(&s->params, + s->dev->img_buffer.data(), + SANE_UNFIX(s->swskip)); + if(status == SANE_STATUS_NO_DOCS) + { + if (s->dev->model->is_sheetfed == SANE_TRUE) + { + DBG(DBG_info, "%s: blank page, recurse\n", __func__); + return sane_start(handle); + } + return status; + } + } + + if (s->swdeskew) { + const auto& sensor = sanei_genesys_find_sensor(s->dev, s->dev->settings.xres, + s->dev->settings.scan_method); + RIE(genesys_deskew(s, sensor)); + } + + if (s->swdespeck) { + RIE(genesys_despeck(s)); + } + + if(s->swcrop) { + RIE(genesys_crop(s)); + } + + if(s->swderotate) { + RIE(genesys_derotate(s)); + } + } + + DBGCOMPLETED; + return status; +} + +SANE_Status sane_start(SANE_Handle handle) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_start_impl(handle); + }); +} + +SANE_Status +sane_read_impl(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len) +{ + Genesys_Scanner *s = (Genesys_Scanner*) handle; + Genesys_Device *dev; + SANE_Status status=SANE_STATUS_GOOD; + size_t local_len; + + if (!s) + { + DBG(DBG_error, "%s: handle is null!\n", __func__); + return SANE_STATUS_INVAL; + } + + dev=s->dev; + if (!dev) + { + DBG(DBG_error, "%s: dev is null!\n", __func__); + return SANE_STATUS_INVAL; + } + + if (!buf) + { + DBG(DBG_error, "%s: buf is null!\n", __func__); + return SANE_STATUS_INVAL; + } + + if (!len) + { + DBG(DBG_error, "%s: len is null!\n", __func__); + return SANE_STATUS_INVAL; + } + + *len = 0; + + if (!s->scanning) + { + DBG(DBG_warn, "%s: scan was cancelled, is over or has not been initiated yet\n", __func__); + return SANE_STATUS_CANCELLED; + } + + DBG(DBG_proc, "%s: start, %d maximum bytes required\n", __func__, max_len); + DBG(DBG_io2, "%s: bytes_to_read=%lu, total_bytes_read=%lu\n", __func__, + (u_long) dev->total_bytes_to_read, (u_long) dev->total_bytes_read); + DBG(DBG_io2, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); + + if(dev->total_bytes_read>=dev->total_bytes_to_read) + { + DBG(DBG_proc, "%s: nothing more to scan: EOF\n", __func__); + + /* issue park command immediatly in case scanner can handle it + * so we save time */ + if (dev->model->is_sheetfed == SANE_FALSE + && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) + && dev->parking == SANE_FALSE) + { + dev->model->cmd_set->slow_back_home (dev, SANE_FALSE); + dev->parking = SANE_TRUE; + } + return SANE_STATUS_EOF; + } + + local_len = max_len; + + /* in case of image processing, all data has been stored in + * buffer_image. So read data from it if it exists, else from scanner */ + if(!dev->buffer_image) + { + /* dynamic lineart is another kind of digital processing that needs + * another layer of buffering on top of genesys_read_ordered_data */ + if(dev->settings.dynamic_lineart==SANE_TRUE) + { + /* if buffer is empty, fill it with genesys_read_ordered_data */ + if(dev->binarize_buffer.avail() == 0) + { + /* store gray data */ + local_len=dev->local_buffer.size(); + dev->local_buffer.reset(); + status = genesys_read_ordered_data (dev, dev->local_buffer.get_write_pos(local_len), + &local_len); + dev->local_buffer.produce(local_len); + + /* binarize data is read successful */ + if(status==SANE_STATUS_GOOD) + { + dev->binarize_buffer.reset(); + genesys_gray_lineart (dev, + dev->local_buffer.get_read_pos(), + dev->binarize_buffer.get_write_pos(local_len / 8), + dev->settings.pixels, + local_len/dev->settings.pixels, + dev->settings.threshold); + dev->binarize_buffer.produce(local_len / 8); + } + + } + + /* return data from lineart buffer if any, up to the available amount */ + local_len = max_len; + if((size_t)max_len>dev->binarize_buffer.avail()) + { + local_len=dev->binarize_buffer.avail(); + } + if(local_len) + { + memcpy(buf, dev->binarize_buffer.get_read_pos(), local_len); + dev->binarize_buffer.consume(local_len); + } + } + else + { + /* most usual case, direct read of data from scanner */ + status = genesys_read_ordered_data (dev, buf, &local_len); + } + } + else /* read data from buffer */ + { + if(dev->total_bytes_read+local_len>dev->total_bytes_to_read) + { + local_len=dev->total_bytes_to_read-dev->total_bytes_read; + } + memcpy(buf, dev->img_buffer.data() + dev->total_bytes_read, local_len); + dev->total_bytes_read+=local_len; + } + + *len = local_len; + if(local_len>(size_t)max_len) + { + fprintf (stderr, "[genesys] sane_read: returning incorrect length!!\n"); + } + DBG(DBG_proc, "%s: %d bytes returned\n", __func__, *len); + return status; +} + +SANE_Status sane_read(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_read_impl(handle, buf, max_len, len); + }); +} + +void sane_cancel_impl(SANE_Handle handle) +{ + Genesys_Scanner *s = (Genesys_Scanner*) handle; + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + /* end binary logging if needed */ + if (s->dev->binary!=NULL) + { + fclose(s->dev->binary); + s->dev->binary=NULL; + } + + s->scanning = SANE_FALSE; + s->dev->read_active = SANE_FALSE; + s->dev->img_buffer.clear(); + + /* no need to end scan if we are parking the head */ + if(s->dev->parking==SANE_FALSE) + { + status = s->dev->model->cmd_set->end_scan(s->dev, &s->dev->reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return; + } + } + + /* park head if flatbed scanner */ + if (s->dev->model->is_sheetfed == SANE_FALSE) + { + if(s->dev->parking==SANE_FALSE) + { + status = s->dev->model->cmd_set->slow_back_home (s->dev, s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to move scanhead to home position: %s\n", __func__, + sane_strstatus(status)); + return; + } + s->dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); + } + } + else + { /* in case of sheetfed scanners, we have to eject the document if still present */ + status = s->dev->model->cmd_set->eject_document (s->dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to eject document: %s\n", __func__, sane_strstatus(status)); + return; + } + } + + /* enable power saving mode unless we are parking .... */ + if(s->dev->parking==SANE_FALSE) + { + status = s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to enable power saving mode: %s\n", __func__, + sane_strstatus(status)); + return; + } + } + + DBGCOMPLETED; + return; +} + +void sane_cancel(SANE_Handle handle) +{ + catch_all_exceptions(__func__, [=]() { sane_cancel_impl(handle); }); +} + +SANE_Status +sane_set_io_mode_impl(SANE_Handle handle, SANE_Bool non_blocking) +{ + Genesys_Scanner *s = (Genesys_Scanner*) handle; + + DBG(DBG_proc, "%s: handle = %p, non_blocking = %s\n", __func__, handle, + non_blocking == SANE_TRUE ? "true" : "false"); + + if (!s->scanning) + { + DBG(DBG_error, "%s: not scanning\n", __func__); + return SANE_STATUS_INVAL; + } + if (non_blocking) + return SANE_STATUS_UNSUPPORTED; + return SANE_STATUS_GOOD; +} + +SANE_Status +sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_set_io_mode_impl(handle, non_blocking); + }); +} + +SANE_Status +sane_get_select_fd_impl(SANE_Handle handle, SANE_Int * fd) +{ + Genesys_Scanner *s = (Genesys_Scanner*) handle; + + DBG(DBG_proc, "%s: handle = %p, fd = %p\n", __func__, handle, (void *) fd); + + if (!s->scanning) + { + DBG(DBG_error, "%s: not scanning\n", __func__); + return SANE_STATUS_INVAL; + } + return SANE_STATUS_UNSUPPORTED; +} + +SANE_Status +sane_get_select_fd(SANE_Handle handle, SANE_Int * fd) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + return sane_get_select_fd_impl(handle, fd); + }); +} + +GenesysButtonName genesys_option_to_button(int option) +{ + switch (option) { + case OPT_SCAN_SW: return BUTTON_SCAN_SW; + case OPT_FILE_SW: return BUTTON_FILE_SW; + case OPT_EMAIL_SW: return BUTTON_EMAIL_SW; + case OPT_COPY_SW: return BUTTON_COPY_SW; + case OPT_PAGE_LOADED_SW: return BUTTON_PAGE_LOADED_SW; + case OPT_OCR_SW: return BUTTON_OCR_SW; + case OPT_POWER_SW: return BUTTON_POWER_SW; + case OPT_EXTRA_SW: return BUTTON_EXTRA_SW; + default: throw std::runtime_error("Unknown option to convert to button index"); + } +} diff --git a/backend/genesys.conf.in b/backend/genesys.conf.in index 5273d51..b1a0861 100644 --- a/backend/genesys.conf.in +++ b/backend/genesys.conf.in @@ -69,6 +69,9 @@ usb 0x04a9 0x190f # Canon 5600f usb 0x04a9 0x1906 +# Canon 8600F +usb 0x04a9 0x2229 + # Visioneer Strobe XP200 usb 0x04a7 0x0426 diff --git a/backend/genesys.h b/backend/genesys.h index eab92bb..47a684c 100644 --- a/backend/genesys.h +++ b/backend/genesys.h @@ -47,7 +47,12 @@ #ifndef GENESYS_H #define GENESYS_H +#ifndef BACKEND_NAME +# define BACKEND_NAME genesys +#endif + #include "genesys_low.h" +#include #ifndef PATH_MAX # define PATH_MAX 1024 @@ -69,8 +74,9 @@ /* Maximum time for lamp warm-up */ #define WARMUP_TIME 65 -#define FLATBED "Flatbed" -#define TRANSPARENCY_ADAPTER "Transparency Adapter" +#define STR_FLATBED "Flatbed" +#define STR_TRANSPARENCY_ADAPTER "Transparency Adapter" +#define STR_TRANSPARENCY_ADAPTER_INFRARED "Transparency Adapter Infrared" #ifndef SANE_I18N #define SANE_I18N(text) text @@ -135,31 +141,110 @@ enum Genesys_Option OPT_BUTTON_GROUP, OPT_CALIBRATE, OPT_CLEAR_CALIBRATION, + OPT_FORCE_CALIBRATION, /* must come last: */ NUM_OPTIONS }; +enum GenesysButtonName : unsigned { + BUTTON_SCAN_SW = 0, + BUTTON_FILE_SW, + BUTTON_EMAIL_SW, + BUTTON_COPY_SW, + BUTTON_PAGE_LOADED_SW, + BUTTON_OCR_SW, + BUTTON_POWER_SW, + BUTTON_EXTRA_SW, + NUM_BUTTONS +}; + +GenesysButtonName genesys_option_to_button(int option); + +class GenesysButton { +public: + void write(bool value) + { + if (value == value_) { + return; + } + values_to_read_.push(value); + value_ = value; + } + + bool read() + { + if (values_to_read_.empty()) { + return value_; + } + bool ret = values_to_read_.front(); + values_to_read_.pop(); + return ret; + } + +private: + bool value_ = false; + std::queue values_to_read_; +}; /** Scanner object. Should have better be called Session than Scanner */ -typedef struct Genesys_Scanner +struct Genesys_Scanner { - struct Genesys_Scanner *next; /**< Next scanner in list */ - Genesys_Device *dev; /**< Low-level device object */ - - /* SANE data */ - SANE_Bool scanning; /**< We are currently scanning */ - SANE_Option_Descriptor opt[NUM_OPTIONS]; /**< Option descriptors */ - Option_Value val[NUM_OPTIONS]; /**< Option values */ - Option_Value last_val[NUM_OPTIONS]; /**< Option values as read by the frontend. used for sensors. */ - SANE_Parameters params; /**< SANE Parameters */ - SANE_Int bpp_list[5]; /**< */ -} Genesys_Scanner; - -#ifdef UNIT_TESTING -SANE_Status genesys_dark_white_shading_calibration (Genesys_Device * dev); -char *calibration_filename(Genesys_Device *currdev); -void add_device(Genesys_Device *dev); -#endif + Genesys_Scanner() = default; + ~Genesys_Scanner() = default; + + // Next scanner in list + struct Genesys_Scanner *next; + + // Low-level device object + Genesys_Device* dev = nullptr; + + // SANE data + // We are currently scanning + SANE_Bool scanning; + // Option descriptors + SANE_Option_Descriptor opt[NUM_OPTIONS]; + + // Option values + SANE_Word bit_depth = 0; + SANE_Word resolution = 0; + bool preview = false; + SANE_Word threshold = 0; + SANE_Word threshold_curve = 0; + bool disable_dynamic_lineart = false; + bool disable_interpolation = false; + bool lamp_off = false; + SANE_Word lamp_off_time = 0; + bool swdeskew = false; + bool swcrop = false; + bool swdespeck = false; + bool swderotate = false; + SANE_Word swskip = 0; + SANE_Word despeck = 0; + SANE_Word contrast = 0; + SANE_Word brightness = 0; + SANE_Word expiration_time = 0; + bool custom_gamma = false; + + SANE_Word pos_top_left_y = 0; + SANE_Word pos_top_left_x = 0; + SANE_Word pos_bottom_right_y = 0; + SANE_Word pos_bottom_right_x = 0; + + std::string mode, source, color_filter; + + std::string calibration_file; + // Button states + GenesysButton buttons[NUM_BUTTONS]; + + // SANE Parameters + SANE_Parameters params = {}; + SANE_Int bpp_list[5] = {}; +}; + +void write_calibration(std::ostream& str, Genesys_Device::Calibration& cache); +bool read_calibration(std::istream& str, Genesys_Device::Calibration& cache, + const std::string& path); + #endif /* not GENESYS_H */ diff --git a/backend/genesys_conv.c b/backend/genesys_conv.c deleted file mode 100644 index 61f466e..0000000 --- a/backend/genesys_conv.c +++ /dev/null @@ -1,478 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2005, 2006 Pierre Willenbrock - Copyright (C) 2010-2013 Stéphane Voltz - - 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. -*/ - -/* - * Conversion filters for genesys backend - */ - - -/*8 bit*/ -#define SINGLE_BYTE -#define BYTES_PER_COMPONENT 1 -#define COMPONENT_TYPE uint8_t - -#define FUNC_NAME(f) f ## _8 - -#include "genesys_conv_hlp.c" - -#undef FUNC_NAME - -#undef COMPONENT_TYPE -#undef BYTES_PER_COMPONENT -#undef SINGLE_BYTE - -/*16 bit*/ -#define DOUBLE_BYTE -#define BYTES_PER_COMPONENT 2 -#define COMPONENT_TYPE uint16_t - -#define FUNC_NAME(f) f ## _16 - -#include "genesys_conv_hlp.c" - -#undef FUNC_NAME - -#undef COMPONENT_TYPE -#undef BYTES_PER_COMPONENT -#undef DOUBLE_BYTE - -static SANE_Status -genesys_reverse_bits( - uint8_t *src_data, - uint8_t *dst_data, - size_t bytes) -{ - size_t i; - for(i = 0; i < bytes; i++) { - *dst_data++ = ~ *src_data++; - } - return SANE_STATUS_GOOD; -} - -/** - * uses the threshold/threshold_curve to control software binarization - * This code was taken from the epjistsu backend by m. allan noah - * @param dev device set up for the scan - * @param src pointer to raw data - * @param dst pointer where to store result - * @param width width of the processed line - * */ -static SANE_Status -binarize_line(Genesys_Device * dev, uint8_t *src, uint8_t *dst, int width) -{ - int j, windowX, sum = 0; - int thresh; - int offset, addCol, dropCol; - unsigned char mask; - - int x; - uint8_t min, max; - - /* 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); - } - - /* ~1mm works best, but the window needs to have odd # of pixels */ - windowX = (6 * dev->settings.xres) / 150; - if (!(windowX % 2)) - windowX++; - - /* second, prefill the sliding sum */ - for (j = 0; j < windowX; j++) - sum += src[j]; - - /* third, walk the input buffer, update the sliding sum, */ - /* determine threshold, output bits */ - for (j = 0; j < width; j++) - { - /* output image location */ - offset = j % 8; - mask = 0x80 >> offset; - thresh = dev->settings.threshold; - - /* move sum/update threshold only if there is a curve */ - if (dev->settings.threshold_curve) - { - addCol = j + windowX / 2; - dropCol = addCol - windowX; - - if (dropCol >= 0 && addCol < width) - { - sum -= src[dropCol]; - sum += src[addCol]; - } - thresh = dev->lineart_lut[sum / windowX]; - } - - /* use average to lookup threshold */ - if (src[j] > thresh) - *dst &= ~mask; /* white */ - else - *dst |= mask; /* black */ - - if (offset == 7) - dst++; - } - - return SANE_STATUS_GOOD; -} - -/** - * software lineart using data from a 8 bit gray scan. We assume true gray - * or monochrome scan as input. - */ -static SANE_Status -genesys_gray_lineart( - Genesys_Device *dev, - uint8_t *src_data, - uint8_t *dst_data, - size_t pixels, - size_t lines, - uint8_t threshold) -{ - size_t y; - - DBG (DBG_io2, "genesys_gray_lineart: converting %lu lines of %lu pixels\n", - (unsigned long)lines, (unsigned long)pixels); - DBG (DBG_io2, "genesys_gray_lineart: threshold=%d\n",threshold); - - for (y = 0; y < lines; y++) - { - binarize_line (dev, src_data + y * pixels, dst_data, pixels); - dst_data += pixels / 8; - } - return SANE_STATUS_GOOD; -} - -/** @brief shrink or grow scanned data to fit the final scan size - * This function shrinks the scanned data it the required resolution is lower than the hardware one, - * or grows it in case it is the opposite like when motor resolution is higher than - * sensor's one. - */ -static SANE_Status -genesys_shrink_lines_1 ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int src_pixels, - unsigned int dst_pixels, - unsigned int channels) -{ - unsigned int dst_x, src_x, y, c, cnt; - unsigned int avg[3], val; - uint8_t *src = (uint8_t *) src_data; - uint8_t *dst = (uint8_t *) dst_data; - - /* choose between case where me must reduce or grow the scanned data */ - if (src_pixels > dst_pixels) - { - /* shrink data */ - /* TODO action must be taken at bit level, no bytes */ - src_pixels /= 8; - dst_pixels /= 8; - /*take first _byte_ */ - for (y = 0; y < lines; y++) - { - cnt = src_pixels / 2; - src_x = 0; - for (dst_x = 0; dst_x < dst_pixels; dst_x++) - { - while (cnt < src_pixels && src_x < src_pixels) - { - cnt += dst_pixels; - - for (c = 0; c < channels; c++) - avg[c] = *src++; - src_x++; - } - cnt -= src_pixels; - - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - } - } - } - else - { - /* common case where y res is double x res */ - for (y = 0; y < lines; y++) - { - if (2 * src_pixels == dst_pixels) - { - /* double and interleave on line */ - for (c = 0; c < src_pixels/8; c++) - { - /* first 4 bits */ - val = 0; - val |= (*src & 0x80) >> 0; /* X___ ____ --> X___ ____ */ - val |= (*src & 0x80) >> 1; /* X___ ____ --> _X__ ____ */ - val |= (*src & 0x40) >> 1; /* _X__ ____ --> __X_ ____ */ - val |= (*src & 0x40) >> 2; /* _X__ ____ --> ___X ____ */ - val |= (*src & 0x20) >> 2; /* __X_ ____ --> ____ X___ */ - val |= (*src & 0x20) >> 3; /* __X_ ____ --> ____ _X__ */ - val |= (*src & 0x10) >> 3; /* ___X ____ --> ____ __X_ */ - val |= (*src & 0x10) >> 4; /* ___X ____ --> ____ ___X */ - *dst = val; - dst++; - - /* last for bits */ - val = 0; - val |= (*src & 0x08) << 4; /* ____ X___ --> X___ ____ */ - val |= (*src & 0x08) << 3; /* ____ X___ --> _X__ ____ */ - val |= (*src & 0x04) << 3; /* ____ _X__ --> __X_ ____ */ - val |= (*src & 0x04) << 2; /* ____ _X__ --> ___X ____ */ - val |= (*src & 0x02) << 2; /* ____ __X_ --> ____ X___ */ - val |= (*src & 0x02) << 1; /* ____ __X_ --> ____ _X__ */ - val |= (*src & 0x01) << 1; /* ____ ___X --> ____ __X_ */ - val |= (*src & 0x01) << 0; /* ____ ___X --> ____ ___X */ - *dst = val; - dst++; - src++; - } - } - else - { - /* TODO: since depth is 1, we must interpolate bit within bytes */ - DBG (DBG_warn, "%s: inaccurate bit expansion!\n", __func__); - cnt = dst_pixels / 2; - dst_x = 0; - for (src_x = 0; src_x < src_pixels; src_x++) - { - for (c = 0; c < channels; c++) - avg[c] = *src++; - while (cnt < dst_pixels && dst_x < dst_pixels) - { - cnt += src_pixels; - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - dst_x++; - } - cnt -= dst_pixels; - } - } - } - } - - return SANE_STATUS_GOOD; -} - - -/** Look in image for likely left/right/bottom paper edges, then crop image. - * Since failing to crop isn't fatal, we always return SANE_STATUS_GOOD . - */ -static SANE_Status -genesys_crop(Genesys_Scanner *s) -{ - SANE_Status status; - Genesys_Device *dev = s->dev; - int top = 0; - int bottom = 0; - int left = 0; - int right = 0; - - DBG (DBG_proc, "%s: start\n", __func__); - - /* first find edges if any */ - status = sanei_magic_findEdges (&s->params, - dev->img_buffer, - dev->settings.xres, - dev->settings.yres, - &top, - &bottom, - &left, - &right); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_info, "%s: bad or no edges, bailing\n", __func__); - goto cleanup; - } - DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __func__, top, bottom, left, - right); - - /* now crop the image */ - status = - sanei_magic_crop (&(s->params), dev->img_buffer, top, bottom, left, right); - if (status) - { - DBG (DBG_warn, "%s: failed to crop\n", __func__); - goto cleanup; - } - - /* update counters to new image size */ - dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; - -cleanup: - DBG (DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} - -/** Look in image for likely upper and left paper edges, then rotate - * image so that upper left corner of paper is upper left of image. - * @return since failure doens't prevent scanning, we always return - * SANE_STATUS_GOOD - */ -static SANE_Status -genesys_deskew(Genesys_Scanner *s) -{ - SANE_Status status; - Genesys_Device *dev = s->dev; - - int x = 0, y = 0, bg; - double slope = 0; - - DBG (DBG_proc, "%s: start\n", __func__); - - bg=0; - if(s->params.format==SANE_FRAME_GRAY && s->params.depth == 1) - { - bg=0xff; - } - status = sanei_magic_findSkew (&s->params, - dev->img_buffer, - dev->sensor.optical_res, - dev->sensor.optical_res, - &x, - &y, - &slope); - if (status!=SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: bad findSkew, bailing\n", __func__); - return SANE_STATUS_GOOD; - } - DBG(DBG_info, "%s: slope=%f => %f\n",__func__,slope, (slope/M_PI_2)*90); - /* rotate image slope is in [-PI/2,PI/2] - * positive values rotate trigonometric direction wise */ - status = sanei_magic_rotate (&s->params, - dev->img_buffer, - x, - y, - slope, - bg); - if (status!=SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: rotate error: %s", __func__, sane_strstatus(status)); - } - - DBG (DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} - -/** remove lone dots - * @return since failure doens't prevent scanning, we always return - * SANE_STATUS_GOOD - */ -static SANE_Status -genesys_despeck(Genesys_Scanner *s) -{ - if(sanei_magic_despeck(&s->params, - s->dev->img_buffer, - s->val[OPT_DESPECK].w)!=SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: bad despeck, bailing\n",__func__); - } - - return SANE_STATUS_GOOD; -} - -/** Look if image needs rotation and apply it - * */ -static SANE_Status -genesys_derotate (Genesys_Scanner * s) -{ - SANE_Status status; - int angle = 0; - int resolution = s->val[OPT_RESOLUTION].w; - - DBGSTART; - status = sanei_magic_findTurn (&s->params, - s->dev->img_buffer, - resolution, - resolution, - &angle); - - if (status) - { - DBG (DBG_warn, "%s: failed : %d\n", __func__, status); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* apply rotation angle found */ - status = sanei_magic_turn (&s->params, s->dev->img_buffer, angle); - if (status) - { - DBG (DBG_warn, "%s: failed : %d\n", __func__, status); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* update counters to new image size */ - s->dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_conv.cc b/backend/genesys_conv.cc new file mode 100644 index 0000000..06fd4e0 --- /dev/null +++ b/backend/genesys_conv.cc @@ -0,0 +1,474 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2005, 2006 Pierre Willenbrock + Copyright (C) 2010-2013 Stéphane Voltz + + 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. +*/ + +/* + * Conversion filters for genesys backend + */ + + +/*8 bit*/ +#define SINGLE_BYTE +#define BYTES_PER_COMPONENT 1 +#define COMPONENT_TYPE uint8_t + +#define FUNC_NAME(f) f ## _8 + +#include "genesys_conv_hlp.cc" + +#undef FUNC_NAME + +#undef COMPONENT_TYPE +#undef BYTES_PER_COMPONENT +#undef SINGLE_BYTE + +/*16 bit*/ +#define DOUBLE_BYTE +#define BYTES_PER_COMPONENT 2 +#define COMPONENT_TYPE uint16_t + +#define FUNC_NAME(f) f ## _16 + +#include "genesys_conv_hlp.cc" + +#undef FUNC_NAME + +#undef COMPONENT_TYPE +#undef BYTES_PER_COMPONENT +#undef DOUBLE_BYTE + +static SANE_Status +genesys_reverse_bits( + uint8_t *src_data, + uint8_t *dst_data, + size_t bytes) +{ + size_t i; + for(i = 0; i < bytes; i++) { + *dst_data++ = ~ *src_data++; + } + return SANE_STATUS_GOOD; +} + +/** + * uses the threshold/threshold_curve to control software binarization + * This code was taken from the epjistsu backend by m. allan noah + * @param dev device set up for the scan + * @param src pointer to raw data + * @param dst pointer where to store result + * @param width width of the processed line + * */ +static SANE_Status +binarize_line(Genesys_Device * dev, uint8_t *src, uint8_t *dst, int width) +{ + int j, windowX, sum = 0; + int thresh; + int offset, addCol, dropCol; + unsigned char mask; + + int x; + uint8_t min, max; + + /* 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); + } + + /* ~1mm works best, but the window needs to have odd # of pixels */ + windowX = (6 * dev->settings.xres) / 150; + if (!(windowX % 2)) + windowX++; + + /* second, prefill the sliding sum */ + for (j = 0; j < windowX; j++) + sum += src[j]; + + /* third, walk the input buffer, update the sliding sum, */ + /* determine threshold, output bits */ + for (j = 0; j < width; j++) + { + /* output image location */ + offset = j % 8; + mask = 0x80 >> offset; + thresh = dev->settings.threshold; + + /* move sum/update threshold only if there is a curve */ + if (dev->settings.threshold_curve) + { + addCol = j + windowX / 2; + dropCol = addCol - windowX; + + if (dropCol >= 0 && addCol < width) + { + sum -= src[dropCol]; + sum += src[addCol]; + } + thresh = dev->lineart_lut[sum / windowX]; + } + + /* use average to lookup threshold */ + if (src[j] > thresh) + *dst &= ~mask; /* white */ + else + *dst |= mask; /* black */ + + if (offset == 7) + dst++; + } + + return SANE_STATUS_GOOD; +} + +/** + * software lineart using data from a 8 bit gray scan. We assume true gray + * or monochrome scan as input. + */ +static SANE_Status +genesys_gray_lineart( + Genesys_Device *dev, + uint8_t *src_data, + uint8_t *dst_data, + size_t pixels, + size_t lines, + uint8_t threshold) +{ + size_t y; + + DBG(DBG_io2, "%s: converting %lu lines of %lu pixels\n", __func__, (unsigned long)lines, + (unsigned long)pixels); + DBG(DBG_io2, "%s: threshold=%d\n", __func__, threshold); + + for (y = 0; y < lines; y++) + { + binarize_line (dev, src_data + y * pixels, dst_data, pixels); + dst_data += pixels / 8; + } + return SANE_STATUS_GOOD; +} + +/** @brief shrink or grow scanned data to fit the final scan size + * This function shrinks the scanned data it the required resolution is lower than the hardware one, + * or grows it in case it is the opposite like when motor resolution is higher than + * sensor's one. + */ +static SANE_Status +genesys_shrink_lines_1 ( + uint8_t *src_data, + uint8_t *dst_data, + unsigned int lines, + unsigned int src_pixels, + unsigned int dst_pixels, + unsigned int channels) +{ + unsigned int dst_x, src_x, y, c, cnt; + unsigned int avg[3], val; + uint8_t *src = (uint8_t *) src_data; + uint8_t *dst = (uint8_t *) dst_data; + + /* choose between case where me must reduce or grow the scanned data */ + if (src_pixels > dst_pixels) + { + /* shrink data */ + /* TODO action must be taken at bit level, no bytes */ + src_pixels /= 8; + dst_pixels /= 8; + /*take first _byte_ */ + for (y = 0; y < lines; y++) + { + cnt = src_pixels / 2; + src_x = 0; + for (dst_x = 0; dst_x < dst_pixels; dst_x++) + { + while (cnt < src_pixels && src_x < src_pixels) + { + cnt += dst_pixels; + + for (c = 0; c < channels; c++) + avg[c] = *src++; + src_x++; + } + cnt -= src_pixels; + + for (c = 0; c < channels; c++) + *dst++ = avg[c]; + } + } + } + else + { + /* common case where y res is double x res */ + for (y = 0; y < lines; y++) + { + if (2 * src_pixels == dst_pixels) + { + /* double and interleave on line */ + for (c = 0; c < src_pixels/8; c++) + { + /* first 4 bits */ + val = 0; + val |= (*src & 0x80) >> 0; /* X___ ____ --> X___ ____ */ + val |= (*src & 0x80) >> 1; /* X___ ____ --> _X__ ____ */ + val |= (*src & 0x40) >> 1; /* _X__ ____ --> __X_ ____ */ + val |= (*src & 0x40) >> 2; /* _X__ ____ --> ___X ____ */ + val |= (*src & 0x20) >> 2; /* __X_ ____ --> ____ X___ */ + val |= (*src & 0x20) >> 3; /* __X_ ____ --> ____ _X__ */ + val |= (*src & 0x10) >> 3; /* ___X ____ --> ____ __X_ */ + val |= (*src & 0x10) >> 4; /* ___X ____ --> ____ ___X */ + *dst = val; + dst++; + + /* last for bits */ + val = 0; + val |= (*src & 0x08) << 4; /* ____ X___ --> X___ ____ */ + val |= (*src & 0x08) << 3; /* ____ X___ --> _X__ ____ */ + val |= (*src & 0x04) << 3; /* ____ _X__ --> __X_ ____ */ + val |= (*src & 0x04) << 2; /* ____ _X__ --> ___X ____ */ + val |= (*src & 0x02) << 2; /* ____ __X_ --> ____ X___ */ + val |= (*src & 0x02) << 1; /* ____ __X_ --> ____ _X__ */ + val |= (*src & 0x01) << 1; /* ____ ___X --> ____ __X_ */ + val |= (*src & 0x01) << 0; /* ____ ___X --> ____ ___X */ + *dst = val; + dst++; + src++; + } + } + else + { + /* TODO: since depth is 1, we must interpolate bit within bytes */ + DBG (DBG_warn, "%s: inaccurate bit expansion!\n", __func__); + cnt = dst_pixels / 2; + dst_x = 0; + for (src_x = 0; src_x < src_pixels; src_x++) + { + for (c = 0; c < channels; c++) + avg[c] = *src++; + while (cnt < dst_pixels && dst_x < dst_pixels) + { + cnt += src_pixels; + for (c = 0; c < channels; c++) + *dst++ = avg[c]; + dst_x++; + } + cnt -= dst_pixels; + } + } + } + } + + return SANE_STATUS_GOOD; +} + + +/** Look in image for likely left/right/bottom paper edges, then crop image. + * Since failing to crop isn't fatal, we always return SANE_STATUS_GOOD . + */ +static SANE_Status +genesys_crop(Genesys_Scanner *s) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Device *dev = s->dev; + int top = 0; + int bottom = 0; + int left = 0; + int right = 0; + + DBG (DBG_proc, "%s: start\n", __func__); + + /* first find edges if any */ + status = sanei_magic_findEdges (&s->params, + dev->img_buffer.data(), + dev->settings.xres, + dev->settings.yres, + &top, + &bottom, + &left, + &right); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_info, "%s: bad or no edges, bailing\n", __func__); + return SANE_STATUS_GOOD; + } + DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __func__, top, bottom, left, + right); + + /* now crop the image */ + status = + sanei_magic_crop (&(s->params), dev->img_buffer.data(), top, bottom, left, right); + if (status) + { + DBG (DBG_warn, "%s: failed to crop\n", __func__); + return SANE_STATUS_GOOD; + } + + /* update counters to new image size */ + dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; + + DBG (DBG_proc, "%s: completed\n", __func__); + return SANE_STATUS_GOOD; +} + +/** Look in image for likely upper and left paper edges, then rotate + * image so that upper left corner of paper is upper left of image. + * @return since failure doens't prevent scanning, we always return + * SANE_STATUS_GOOD + */ +static SANE_Status +genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Device *dev = s->dev; + + int x = 0, y = 0, bg; + double slope = 0; + + DBG (DBG_proc, "%s: start\n", __func__); + + bg=0; + if(s->params.format==SANE_FRAME_GRAY && s->params.depth == 1) + { + bg=0xff; + } + status = sanei_magic_findSkew (&s->params, + dev->img_buffer.data(), + sensor.optical_res, + sensor.optical_res, + &x, + &y, + &slope); + if (status!=SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: bad findSkew, bailing\n", __func__); + return SANE_STATUS_GOOD; + } + DBG(DBG_info, "%s: slope=%f => %f\n",__func__,slope, (slope/M_PI_2)*90); + /* rotate image slope is in [-PI/2,PI/2] + * positive values rotate trigonometric direction wise */ + status = sanei_magic_rotate (&s->params, + dev->img_buffer.data(), + x, + y, + slope, + bg); + if (status!=SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: rotate error: %s", __func__, sane_strstatus(status)); + } + + DBG (DBG_proc, "%s: completed\n", __func__); + return SANE_STATUS_GOOD; +} + +/** remove lone dots + * @return since failure doens't prevent scanning, we always return + * SANE_STATUS_GOOD + */ +static SANE_Status +genesys_despeck(Genesys_Scanner *s) +{ + if(sanei_magic_despeck(&s->params, + s->dev->img_buffer.data(), + s->despeck)!=SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: bad despeck, bailing\n",__func__); + } + + return SANE_STATUS_GOOD; +} + +/** Look if image needs rotation and apply it + * */ +static SANE_Status +genesys_derotate (Genesys_Scanner * s) +{ + SANE_Status status = SANE_STATUS_GOOD; + int angle = 0; + + DBGSTART; + status = sanei_magic_findTurn (&s->params, + s->dev->img_buffer.data(), + s->resolution, + s->resolution, + &angle); + + if (status) + { + DBG (DBG_warn, "%s: failed : %d\n", __func__, status); + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + /* apply rotation angle found */ + status = sanei_magic_turn (&s->params, s->dev->img_buffer.data(), angle); + if (status) + { + DBG (DBG_warn, "%s: failed : %d\n", __func__, status); + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + /* update counters to new image size */ + s->dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} diff --git a/backend/genesys_conv_hlp.c b/backend/genesys_conv_hlp.c deleted file mode 100644 index 7663a87..0000000 --- a/backend/genesys_conv_hlp.c +++ /dev/null @@ -1,345 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2005 Pierre Willenbrock - - 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. -*/ - -/* - * Conversion filters for genesys backend - */ - -static SANE_Status -FUNC_NAME(genesys_reorder_components_cis) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int pixels) -{ - unsigned int x, y; - uint8_t *src[3]; - uint8_t *dst = dst_data; - unsigned int rest = pixels * 2 * BYTES_PER_COMPONENT; - - src[0] = src_data + pixels * BYTES_PER_COMPONENT * 0; - src[1] = src_data + pixels * BYTES_PER_COMPONENT * 1; - src[2] = src_data + pixels * BYTES_PER_COMPONENT * 2; - - for(y = 0; y < lines; y++) { - for(x = 0; x < pixels; x++) { - -#ifndef DOUBLE_BYTE - *dst++ = *src[0]++; - *dst++ = *src[1]++; - *dst++ = *src[2]++; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = *src[0]++; - *dst++ = *src[0]++; - *dst++ = *src[1]++; - *dst++ = *src[1]++; - *dst++ = *src[2]++; - *dst++ = *src[2]++; -# else - *dst++ = src[0][1]; - *dst++ = src[0][0]; - *dst++ = src[1][1]; - *dst++ = src[1][0]; - *dst++ = src[2][1]; - *dst++ = src[2][0]; - src[0] += 2; - src[1] += 2; - src[2] += 2; -# endif -#endif - } - - src[0] += rest; - src[1] += rest; - src[2] += rest; - } - return SANE_STATUS_GOOD; -} - -static SANE_Status -FUNC_NAME(genesys_reorder_components_cis_bgr) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int pixels) -{ - unsigned int x, y; - uint8_t *src[3]; - uint8_t *dst = dst_data; - unsigned int rest = pixels * 2 * BYTES_PER_COMPONENT; - - src[0] = src_data + pixels * BYTES_PER_COMPONENT * 0; - src[1] = src_data + pixels * BYTES_PER_COMPONENT * 1; - src[2] = src_data + pixels * BYTES_PER_COMPONENT * 2; - - for(y = 0; y < lines; y++) { - for(x = 0; x < pixels; x++) { -#ifndef DOUBLE_BYTE - *dst++ = *src[2]++; - *dst++ = *src[1]++; - *dst++ = *src[0]++; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = *src[2]++; - *dst++ = *src[2]++; - *dst++ = *src[1]++; - *dst++ = *src[1]++; - *dst++ = *src[0]++; - *dst++ = *src[0]++; -# else - *dst++ = src[2][1]; - *dst++ = src[2][0]; - *dst++ = src[1][1]; - *dst++ = src[1][0]; - *dst++ = src[0][1]; - *dst++ = src[0][0]; - src[0] += 2; - src[1] += 2; - src[2] += 2; -# endif -#endif - } - - src[0] += rest; - src[1] += rest; - src[2] += rest; - } - return SANE_STATUS_GOOD; -} - -static SANE_Status -FUNC_NAME(genesys_reorder_components_bgr) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int pixels) -{ - unsigned int c; - uint8_t *src = src_data; - uint8_t *dst = dst_data; - - for(c = 0; c < lines * pixels; c++) { - -#ifndef DOUBLE_BYTE - *dst++ = src[2]; - *dst++ = src[1]; - *dst++ = src[0]; - src += 3; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = src[2 * 2 + 0]; - *dst++ = src[2 * 2 + 1]; - *dst++ = src[1 * 2 + 0]; - *dst++ = src[1 * 2 + 1]; - *dst++ = src[0 * 2 + 0]; - *dst++ = src[0 * 2 + 1]; -# else - *dst++ = src[2 * 2 + 1]; - *dst++ = src[2 * 2 + 0]; - *dst++ = src[1 * 2 + 1]; - *dst++ = src[1 * 2 + 0]; - *dst++ = src[0 * 2 + 1]; - *dst++ = src[0 * 2 + 0]; -# endif - src += 3 * 2; -#endif - - } - return SANE_STATUS_GOOD; -} - -#if defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN) -static SANE_Status -FUNC_NAME(genesys_reorder_components_endian) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int pixels, - unsigned int channels) -{ - unsigned int c; - uint8_t *src = src_data; - uint8_t *dst = dst_data; - - for(c = 0; c < lines * pixels * channels; c++) { - *dst++ = src[1]; - *dst++ = src[0]; - src += 2; - } -return SANE_STATUS_GOOD; -} -#endif /*defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN)*/ - - -static SANE_Status -FUNC_NAME(genesys_reverse_ccd) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int components_per_line, - unsigned int *ccd_shift, - unsigned int component_count) -{ - unsigned int x, y, c; - COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; - COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; - COMPONENT_TYPE *srcp; - COMPONENT_TYPE *dstp; - unsigned int pitch = components_per_line; - unsigned int ccd_shift_pitch[12]; - unsigned int *csp; - - for (c = 0; c < component_count; c++) - ccd_shift_pitch[c] = ccd_shift[c] * pitch; - -/* - * cache efficiency: - we are processing a single line component_count times, so it should fit - into the cpu cache for maximum efficiency. our lines take - maximum 252kb(3 channels, 16bit, 2400dpi, full gl841 shading range) - * instruction efficiency: - the innermost loop runs long and consists of 3 adds, one compare, - 2 derefences. - */ -/* - for (y = 0; y < lines; y++) { - csp = ccd_shift_pitch; - for (c = 0; c < component_count; c++) { - srcp = src + c + *csp++; - dstp = dst + c; - for (x = 0; x < pitch; x += component_count) { - *dstp = *srcp; - srcp += component_count; - dstp += component_count; - } - } - dst += pitch; - src += pitch; - } - */ -/* - * cache efficency: - here only line_dist_pitch needs to stay in cache. 12*4 = 48 bytes - * instruction efficiency: - we have a short running inner loop, consisting of 4 incs, 2 compare, 1 add, - 2 dereference and 1 indexed dereference. - the enclosing loop is long running, consisting of 1 add, 1 compare. - */ - srcp = src; - dstp = dst; - for (y = 0; y < lines; y++) { - for (x = 0; x < pitch; x += component_count) { - csp = ccd_shift_pitch; - for (c = 0; c < component_count && c + x < pitch; c++) { - *dstp = srcp[*csp++]; - dstp++; - srcp++; - } - } - } - return SANE_STATUS_GOOD; -} - -static SANE_Status -FUNC_NAME(genesys_shrink_lines) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int src_pixels, - unsigned int dst_pixels, - unsigned int channels) -{ - unsigned int dst_x, src_x, y, c, cnt; - unsigned int avg[3]; - unsigned int count; - COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; - COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; - - if (src_pixels > dst_pixels) { -/*average*/ - for (c = 0; c < channels; c++) - avg[c] = 0; - for(y = 0; y < lines; y++) { - cnt = src_pixels / 2; - src_x = 0; - for (dst_x = 0; dst_x < dst_pixels; dst_x++) { - count = 0; - while (cnt < src_pixels && src_x < src_pixels) { - cnt += dst_pixels; - - for (c = 0; c < channels; c++) - avg[c] += *src++; - src_x++; - count++; - } - cnt -= src_pixels; - - for (c = 0; c < channels; c++) { - *dst++ = avg[c] / count; - avg[c] = 0; - } - } - } - } else { -/*interpolate. copy pixels*/ - for(y = 0; y < lines; y++) { - cnt = dst_pixels / 2; - dst_x = 0; - for (src_x = 0; src_x < src_pixels; src_x++) { - for (c = 0; c < channels; c++) - avg[c] = *src++; - while ((cnt < dst_pixels || src_x + 1 == src_pixels) && - dst_x < dst_pixels) { - cnt += src_pixels; - - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - dst_x++; - } - cnt -= dst_pixels; - } - } - } - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_conv_hlp.cc b/backend/genesys_conv_hlp.cc new file mode 100644 index 0000000..7663a87 --- /dev/null +++ b/backend/genesys_conv_hlp.cc @@ -0,0 +1,345 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2005 Pierre Willenbrock + + 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. +*/ + +/* + * Conversion filters for genesys backend + */ + +static SANE_Status +FUNC_NAME(genesys_reorder_components_cis) ( + uint8_t *src_data, + uint8_t *dst_data, + unsigned int lines, + unsigned int pixels) +{ + unsigned int x, y; + uint8_t *src[3]; + uint8_t *dst = dst_data; + unsigned int rest = pixels * 2 * BYTES_PER_COMPONENT; + + src[0] = src_data + pixels * BYTES_PER_COMPONENT * 0; + src[1] = src_data + pixels * BYTES_PER_COMPONENT * 1; + src[2] = src_data + pixels * BYTES_PER_COMPONENT * 2; + + for(y = 0; y < lines; y++) { + for(x = 0; x < pixels; x++) { + +#ifndef DOUBLE_BYTE + *dst++ = *src[0]++; + *dst++ = *src[1]++; + *dst++ = *src[2]++; +#else +# ifndef WORDS_BIGENDIAN + *dst++ = *src[0]++; + *dst++ = *src[0]++; + *dst++ = *src[1]++; + *dst++ = *src[1]++; + *dst++ = *src[2]++; + *dst++ = *src[2]++; +# else + *dst++ = src[0][1]; + *dst++ = src[0][0]; + *dst++ = src[1][1]; + *dst++ = src[1][0]; + *dst++ = src[2][1]; + *dst++ = src[2][0]; + src[0] += 2; + src[1] += 2; + src[2] += 2; +# endif +#endif + } + + src[0] += rest; + src[1] += rest; + src[2] += rest; + } + return SANE_STATUS_GOOD; +} + +static SANE_Status +FUNC_NAME(genesys_reorder_components_cis_bgr) ( + uint8_t *src_data, + uint8_t *dst_data, + unsigned int lines, + unsigned int pixels) +{ + unsigned int x, y; + uint8_t *src[3]; + uint8_t *dst = dst_data; + unsigned int rest = pixels * 2 * BYTES_PER_COMPONENT; + + src[0] = src_data + pixels * BYTES_PER_COMPONENT * 0; + src[1] = src_data + pixels * BYTES_PER_COMPONENT * 1; + src[2] = src_data + pixels * BYTES_PER_COMPONENT * 2; + + for(y = 0; y < lines; y++) { + for(x = 0; x < pixels; x++) { +#ifndef DOUBLE_BYTE + *dst++ = *src[2]++; + *dst++ = *src[1]++; + *dst++ = *src[0]++; +#else +# ifndef WORDS_BIGENDIAN + *dst++ = *src[2]++; + *dst++ = *src[2]++; + *dst++ = *src[1]++; + *dst++ = *src[1]++; + *dst++ = *src[0]++; + *dst++ = *src[0]++; +# else + *dst++ = src[2][1]; + *dst++ = src[2][0]; + *dst++ = src[1][1]; + *dst++ = src[1][0]; + *dst++ = src[0][1]; + *dst++ = src[0][0]; + src[0] += 2; + src[1] += 2; + src[2] += 2; +# endif +#endif + } + + src[0] += rest; + src[1] += rest; + src[2] += rest; + } + return SANE_STATUS_GOOD; +} + +static SANE_Status +FUNC_NAME(genesys_reorder_components_bgr) ( + uint8_t *src_data, + uint8_t *dst_data, + unsigned int lines, + unsigned int pixels) +{ + unsigned int c; + uint8_t *src = src_data; + uint8_t *dst = dst_data; + + for(c = 0; c < lines * pixels; c++) { + +#ifndef DOUBLE_BYTE + *dst++ = src[2]; + *dst++ = src[1]; + *dst++ = src[0]; + src += 3; +#else +# ifndef WORDS_BIGENDIAN + *dst++ = src[2 * 2 + 0]; + *dst++ = src[2 * 2 + 1]; + *dst++ = src[1 * 2 + 0]; + *dst++ = src[1 * 2 + 1]; + *dst++ = src[0 * 2 + 0]; + *dst++ = src[0 * 2 + 1]; +# else + *dst++ = src[2 * 2 + 1]; + *dst++ = src[2 * 2 + 0]; + *dst++ = src[1 * 2 + 1]; + *dst++ = src[1 * 2 + 0]; + *dst++ = src[0 * 2 + 1]; + *dst++ = src[0 * 2 + 0]; +# endif + src += 3 * 2; +#endif + + } + return SANE_STATUS_GOOD; +} + +#if defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN) +static SANE_Status +FUNC_NAME(genesys_reorder_components_endian) ( + uint8_t *src_data, + uint8_t *dst_data, + unsigned int lines, + unsigned int pixels, + unsigned int channels) +{ + unsigned int c; + uint8_t *src = src_data; + uint8_t *dst = dst_data; + + for(c = 0; c < lines * pixels * channels; c++) { + *dst++ = src[1]; + *dst++ = src[0]; + src += 2; + } +return SANE_STATUS_GOOD; +} +#endif /*defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN)*/ + + +static SANE_Status +FUNC_NAME(genesys_reverse_ccd) ( + uint8_t *src_data, + uint8_t *dst_data, + unsigned int lines, + unsigned int components_per_line, + unsigned int *ccd_shift, + unsigned int component_count) +{ + unsigned int x, y, c; + COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; + COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; + COMPONENT_TYPE *srcp; + COMPONENT_TYPE *dstp; + unsigned int pitch = components_per_line; + unsigned int ccd_shift_pitch[12]; + unsigned int *csp; + + for (c = 0; c < component_count; c++) + ccd_shift_pitch[c] = ccd_shift[c] * pitch; + +/* + * cache efficiency: + we are processing a single line component_count times, so it should fit + into the cpu cache for maximum efficiency. our lines take + maximum 252kb(3 channels, 16bit, 2400dpi, full gl841 shading range) + * instruction efficiency: + the innermost loop runs long and consists of 3 adds, one compare, + 2 derefences. + */ +/* + for (y = 0; y < lines; y++) { + csp = ccd_shift_pitch; + for (c = 0; c < component_count; c++) { + srcp = src + c + *csp++; + dstp = dst + c; + for (x = 0; x < pitch; x += component_count) { + *dstp = *srcp; + srcp += component_count; + dstp += component_count; + } + } + dst += pitch; + src += pitch; + } + */ +/* + * cache efficency: + here only line_dist_pitch needs to stay in cache. 12*4 = 48 bytes + * instruction efficiency: + we have a short running inner loop, consisting of 4 incs, 2 compare, 1 add, + 2 dereference and 1 indexed dereference. + the enclosing loop is long running, consisting of 1 add, 1 compare. + */ + srcp = src; + dstp = dst; + for (y = 0; y < lines; y++) { + for (x = 0; x < pitch; x += component_count) { + csp = ccd_shift_pitch; + for (c = 0; c < component_count && c + x < pitch; c++) { + *dstp = srcp[*csp++]; + dstp++; + srcp++; + } + } + } + return SANE_STATUS_GOOD; +} + +static SANE_Status +FUNC_NAME(genesys_shrink_lines) ( + uint8_t *src_data, + uint8_t *dst_data, + unsigned int lines, + unsigned int src_pixels, + unsigned int dst_pixels, + unsigned int channels) +{ + unsigned int dst_x, src_x, y, c, cnt; + unsigned int avg[3]; + unsigned int count; + COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; + COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; + + if (src_pixels > dst_pixels) { +/*average*/ + for (c = 0; c < channels; c++) + avg[c] = 0; + for(y = 0; y < lines; y++) { + cnt = src_pixels / 2; + src_x = 0; + for (dst_x = 0; dst_x < dst_pixels; dst_x++) { + count = 0; + while (cnt < src_pixels && src_x < src_pixels) { + cnt += dst_pixels; + + for (c = 0; c < channels; c++) + avg[c] += *src++; + src_x++; + count++; + } + cnt -= src_pixels; + + for (c = 0; c < channels; c++) { + *dst++ = avg[c] / count; + avg[c] = 0; + } + } + } + } else { +/*interpolate. copy pixels*/ + for(y = 0; y < lines; y++) { + cnt = dst_pixels / 2; + dst_x = 0; + for (src_x = 0; src_x < src_pixels; src_x++) { + for (c = 0; c < channels; c++) + avg[c] = *src++; + while ((cnt < dst_pixels || src_x + 1 == src_pixels) && + dst_x < dst_pixels) { + cnt += src_pixels; + + for (c = 0; c < channels; c++) + *dst++ = avg[c]; + dst_x++; + } + cnt -= dst_pixels; + } + } + } + return SANE_STATUS_GOOD; +} diff --git a/backend/genesys_devices.c b/backend/genesys_devices.c deleted file mode 100644 index 11f2579..0000000 --- a/backend/genesys_devices.c +++ /dev/null @@ -1,3706 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003 Oliver Rauch - Copyright (C) 2003-2005 Henning Meier-Geinitz - Copyright (C) 2004, 2005 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2007 Luke - Copyright (C) 2010 Jack McGill - Copyright (C) 2010 Andrey Loginov , - xerox travelscan device entry - Copyright (C) 2010 Chris Berry and Michael Rickmann - for Plustek Opticbook 3600 support - - 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. -*/ - -/* ------------------------------------------------------------------------ */ -/* Some setup DAC and CCD tables */ -/* ------------------------------------------------------------------------ */ - -/** Setup table for various scanners using a Wolfson DAC - */ -static Genesys_Frontend Wolfson[] = { - { DAC_WOLFSON_UMAX, {0x00, 0x03, 0x05, 0x11} - , {0x00, 0x00, 0x00} - , {0x80, 0x80, 0x80} - , {0x02, 0x02, 0x02} - , {0x00, 0x00, 0x00} - } - , /* 0: UMAX */ - {DAC_WOLFSON_ST12, {0x00, 0x03, 0x05, 0x03} - , {0x00, 0x00, 0x00} - , {0xc8, 0xc8, 0xc8} - , {0x04, 0x04, 0x04} - , {0x00, 0x00, 0x00} - } - , /* 1: ST12 */ - {DAC_WOLFSON_ST24,{0x00, 0x03, 0x05, 0x21} - , {0x00, 0x00, 0x00} - , {0xc8, 0xc8, 0xc8} - , {0x06, 0x06, 0x06} - , {0x00, 0x00, 0x00} - } - , /* 2: ST24 */ - {DAC_WOLFSON_5345,{0x00, 0x03, 0x05, 0x12} - , {0x00, 0x00, 0x00} - , {0xb8, 0xb8, 0xb8} - , {0x04, 0x04, 0x04} - , {0x00, 0x00, 0x00} - } - , /* 3: MD6228/MD6471 */ - {DAC_WOLFSON_HP2400, - /* reg0 reg1 reg2 reg3 */ - {0x00, 0x03, 0x05, 0x02} /* reg3=0x02 for 50-600 dpi, 0x32 (0x12 also works well) at 1200 */ - , {0x00, 0x00, 0x00} - , {0xb4, 0xb6, 0xbc} - , {0x06, 0x09, 0x08} - , {0x00, 0x00, 0x00} - } - , /* 4: HP2400c */ - {DAC_WOLFSON_HP2300, - {0x00, 0x03, 0x04, 0x02} - , {0x00, 0x00, 0x00} - , {0xbe, 0xbe, 0xbe} - , {0x04, 0x04, 0x04} - , {0x00, 0x00, 0x00} - } - , /* 5: HP2300c */ - {DAC_CANONLIDE35,{0x00, 0x3d, 0x08, 0x00} - , {0x00, 0x00, 0x00} - , {0xe1, 0xe1, 0xe1} - , {0x93, 0x93, 0x93} - , {0x00, 0x19, 0x06} - } - , /* 6: CANONLIDE35 */ - {DAC_AD_XP200, - {0x58, 0x80, 0x00, 0x00} /* reg1=0x80 ? */ - , {0x00, 0x00, 0x00} - , {0x09, 0x09, 0x09} - , {0x09, 0x09, 0x09} - , {0x00, 0x00, 0x00} - } - , - {DAC_WOLFSON_XP300,{0x00, 0x35, 0x20, 0x14} /* 7: XP300 */ - , {0x00, 0x00, 0x00} - , {0xe1, 0xe1, 0xe1} - , {0x93, 0x93, 0x93} - , {0x07, 0x00, 0x00} - } - , /* 8: HP3670 */ - {DAC_WOLFSON_HP3670, - /* reg0 reg1 reg2 reg3 */ - {0x00, 0x03, 0x05, 0x32} /* reg3=0x32 for 100-300 dpi, 0x12 at 1200 */ - , {0x00, 0x00, 0x00} /* sign */ - , {0xba, 0xb8, 0xb8} /* offset */ - , {0x06, 0x05, 0x04} /* gain 4,3,2 at 1200 ?*/ - , {0x00, 0x00, 0x00} - } - , - {DAC_WOLFSON_DSM600,{0x00, 0x35, 0x20, 0x14} /* 9: DSMOBILE600 */ - , {0x00, 0x00, 0x00} - , {0x85, 0x85, 0x85} - , {0xa0, 0xa0, 0xa0} - , {0x07, 0x00, 0x00} - } - , - {DAC_CANONLIDE200, - {0x9d, 0x91, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x3f, 0x00} /* 0x00 0x3f 0x00 : offset/brigthness ? */ - , {0x32, 0x04, 0x00} - , {0x00, 0x00, 0x00} - } - , - {DAC_CANONLIDE700, - {0x9d, 0x9e, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x3f, 0x00} /* 0x00 0x3f 0x00 : offset/brigthness ? */ - , {0x2f, 0x04, 0x00} - , {0x00, 0x00, 0x00} - } - , /* KV-SS080 */ - {DAC_KVSS080, - {0x00, 0x23, 0x24, 0x0f} - , {0x00, 0x00, 0x00} - , {0x80, 0x80, 0x80} - , {0x4b, 0x4b, 0x4b} - , {0x00,0x00,0x00} - } - , - {DAC_G4050, - {0x00, 0x23, 0x24, 0x1f} - , {0x00, 0x00, 0x00} - , {0x45, 0x45, 0x45} /* 0x20, 0x21, 0x22 */ - , {0x4b, 0x4b, 0x4b} /* 0x28, 0x29, 0x2a */ - , {0x00,0x00,0x00} - } - , - {DAC_CANONLIDE110, - {0x80, 0x8a, 0x23, 0x4c} - , {0x00, 0xca, 0x94} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} - } - , - /** @brief GL124 special case - * for GL124 based scanners, this struct is "abused" - * in fact the fields are map like below to AFE registers - * (from Texas Instrument or alike ?) - */ - {DAC_CANONLIDE120, - {0x80, - /* 0001 0002 0003 */ - 0xa3, 0x2b, 0x4c} - /* 0005 0006 0007 */ - , {0x00, 0xca, 0x95} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} - } - , - {DAC_PLUSTEK_3600, - {0x70, 0x80, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x3f, 0x3d, 0x3d} - , {0x00, 0x00, 0x00} - } - , - {DAC_CS8400F, - {0x00, 0x23, 0x24, 0x0f} - , {0x00, 0x00, 0x00} - , {0x60, 0x5c, 0x6c} /* 0x20, 0x21, 0x22 */ - , {0x8a, 0x9f, 0xc2} /* 0x28, 0x29, 0x2a */ - , {0x00, 0x00, 0x00} - } - , - {DAC_IMG101, - {0x78, 0xf0, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} /* 0x20, 0x21, 0x22 */ - , {0x00, 0x00, 0x00} /* 0x28, 0x29, 0x2a */ - , {0x00, 0x00, 0x00} - } - , - {DAC_PLUSTEK3800, - {0x78, 0xf0, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} /* 0x20, 0x21, 0x22 */ - , {0x00, 0x00, 0x00} /* 0x28, 0x29, 0x2a */ - , {0x00, 0x00, 0x00} - }, - {DAC_CANONLIDE80, - /* reg0: control 74 data, 70 no data - * reg3: offset - * reg6: gain - * reg0 , reg3, reg6 */ - {0x70, 0x16, 0x60, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} - , {0x00, 0x00, 0x00} - } -}; - - -/** for setting up the sensor-specific settings: - * Optical Resolution, number of black pixels, number of dummy pixels, - * CCD_start_xoffset, and overall number of sensor pixels - * registers 0x08-0x0b, 0x10-0x1d and 0x52-0x5e - */ -static Genesys_Sensor Sensor[] = { - /* 0: UMAX */ - {CCD_UMAX, - 1200, 48, 64, 0, 10800, 210, 230, - {0x01, 0x03, 0x05, 0x07} - , - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x05, 0x31, 0x2a, 0x00, 0x00, - 0x00, 0x02} - , - {0x13, 0x17, 0x03, 0x07, 0x0b, 0x0f, 0x23, 0x00, 0xc1, 0x00, 0x00, 0x00, - 0x00} - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL}} - , - /* 1: Plustek OpticPro S12/ST12 */ - {CCD_ST12, - 600, 48, 85, 152, 5416, 210, 230, - {0x02, 0x00, 0x06, 0x04} , - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2b, 0x08, 0x20, 0x2a, 0x00, 0x00, 0x0c, 0x03} , - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00} , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* 2: Plustek OpticPro S24/ST24 */ - {CCD_ST24, - 1200, - 48, 64, 0, 10800, 210, 230, - {0x0e, 0x0c, 0x00, 0x0c} , - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x08, 0x31, 0x2a, 0x00, 0x00, 0x00, 0x02} , - {0x17, 0x03, 0x07, 0x0b, 0x0f, 0x13, 0x03, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00} , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* 3: MD6471 */ - {CCD_5345, - 1200, - 48, - 16, 0, 10872, - 190, 190, - {0x0d, 0x0f, 0x11, 0x13} , - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0a, 0x30, 0x2a, 0x00, 0x00, 0x00, 0x03} , - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x23, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00} , - {2.38, 2.35, 2.34}, - {NULL, NULL, NULL} - } - , - /* 4: HP2400c */ - {CCD_HP2400, - 1200, - 48, - 15, 0, 10872, 210, 200, - {0x14, 0x15, 0x00, 0x00} /* registers 0x08-0x0b */ , - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xbf, 0x08, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x02} , - {0x0b, 0x0f, 0x13, 0x17, 0x03, 0x07, 0x63, 0x00, 0xc1, 0x00, 0x0e, 0x00, 0x00} , - {2.1, 2.1, 2.1}, - {NULL, NULL, NULL} - } - , - /* 5: HP2300c */ - {CCD_HP2300, - 600, - 48, - 20, 0, 5368, 180, 180, /* 5376 */ - {0x16, 0x00, 0x01, 0x03} , - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb7, 0x0a, 0x20, 0x2a, 0x6a, 0x8a, 0x00, 0x05} , - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83, 0x00, 0xc1, 0x06, 0x0b, 0x10, 0x16} , - {2.1, 2.1, 2.1}, - {NULL, NULL, NULL} - } - , - /* CANOLIDE35 */ - {CCD_CANONLIDE35, - 1200, - 87, /* (black) */ - 87, /* (dummy) */ - 0, /* (startxoffset) */ - 10400, /* sensor_pixels */ - 0, - 0, - {0x00, 0x00, 0x00, 0x00}, - {0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x00, 0x02, 0x00, 0x50, - 0x00, 0x00, 0x00, 0x02 /* TODO(these do no harm, but may be neccessery for CCD) */ - }, - {0x05, 0x07, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ - 0x3a, 0x03, - 0x40, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x00 /*TODO (these do no harm, but may be neccessery for CCD) */ - } - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* 7: Strobe XP200 */ - {CIS_XP200, 600, - 5, - 38, 0, 5200, 200, 200, /* 5125 */ - {0x16, 0x00, 0x01, 0x03} , - {0x14, 0x50, 0x0c, 0x80, 0x0a, 0x28, 0xb7, 0x0a, 0x20, 0x2a, 0x6a, 0x8a, 0x00, 0x05} , - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83, 0x00, 0xc1, 0x06, 0x0b, 0x10, 0x16} , - {2.1, 2.1, 2.1}, - {NULL, NULL, NULL} - } - , - /* HP3670 */ - {CCD_HP3670,1200, - 48, - 16, 0, 10872, - 210, 200, - {0x00, 0x0a, 0x0b, 0x0d} , - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x07, 0x20, 0x2a, 0x00, 0x00, 0xc0, 0x43} , - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83, 0x00, 0x15, 0x05, 0x0a, 0x0f, 0x00}, - {1.00, 1.00, 1.00}, - {NULL, NULL, NULL} - } - , - /* Syscan DP 665 */ - {CCD_DP665, 600, - 27, /*(black) */ - 27, /* (dummy) */ - 0, /* (startxoffset) */ - 2496, /*sensor_pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - {0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x00, 0x02, 0x04, 0x50, - 0x10, 0x00, 0x20, 0x02 - }, - {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ - 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ - } - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* Visioneer Roadwarrior */ - {CCD_ROADWARRIOR, 600, - 27, /*(black) */ - 27, /* (dummy) */ - 0, /* (startxoffset) */ - 5200, /*sensor_pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - {0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x00, 0x02, 0x04, 0x50, - 0x10, 0x00, 0x20, 0x02 - }, - {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ - 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ - } - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } -, - /* Pentax DS Mobile 600 */ - {CCD_DSMOBILE600, 600, - 28, /*(black) */ - 28, /* (dummy) */ - 0, /* (startxoffset) */ - 5200, /*sensor_pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - {0x15, 0x44, 0x15, 0x44, 0x15, 0x44, 0x00, 0x02, 0x04, 0x50, - 0x10, 0x00, 0x20, 0x02 - }, - {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ - 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ - } - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* 13: Strobe XP300 */ - {CCD_XP300, 600, - 27, /*(black) */ - 27, /* (dummy) */ - 0, /* (startxoffset) */ - 10240, /*sensor_pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - {0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x00, 0x02, 0x04, 0x50, - 0x10, 0x00, 0x20, 0x02 - }, - {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ - 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ - } - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* 13: Strobe XP300 */ - {CCD_DP685, 600, - 27, /*(black) */ - 27, /* (dummy) */ - 0, /* (startxoffset) */ - 5020, /*sensor_pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - {0x11, 0x00, 0x11, 0x00, 0x11, 0x00, 0x00, 0x02, 0x04, 0x50, - 0x10, 0x00, 0x20, 0x02 - }, - {0x04, 0x05, - 0x00, 0x00, 0x00, 0x00, /*[GB](HI|LOW) not needed for cis */ - 0x54, 0x03, - 0x00, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x01 /*TODO (these do no harm, but may be neccessery for CCD) */ - } - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* CANONLIDE200 */ - {CIS_CANONLIDE200, - 4800, /* optical resolution */ - 87*4, /* black pixels */ - 16*4, /* dummy pixels */ - 320*8, /* CCD_startx_offset 323 */ - 5136*8, - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - /* reg 0x10 - 0x1d */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* EXPR/EXPG/EXPB */ - 0x10, 0x08, 0x00, 0xff, 0x34, 0x00, 0x02, 0x04 }, - /* reg 0x52 - 0x5e */ - {0x03, 0x07, - 0x00, 0x00, 0x00, 0x00, - 0x2a, 0xe1, - 0x55, - 0x00, 0x00, 0x00, - 0x41 - } - , - {1.7, 1.7, 1.7}, - {NULL, NULL, NULL} - } - , - /* CANONLIDE700 */ - {CIS_CANONLIDE700, - 4800, /* optical resolution */ - 73*8, /* black pixels 73 at 600 dpi */ - 16*8, /* dummy pixels */ - 384*8, /* CCD_startx_offset 384 at 600 dpi */ - 5188*8, /* 8x5570 segments , 5187+1 for rounding */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - /* reg 0x10 - 0x1d */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* EXPR/EXPG/EXPB */ - 0x10, 0x08, 0x00, 0xff, 0x34, 0x00, 0x02, 0x04 }, - /* reg 0x52 - 0x5e */ - {0x07, 0x03, - 0x00, 0x00, 0x00, 0x00, - 0x2a, 0xe1, - 0x55, - 0x00, 0x00, 0x00, - 0x41 - } - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* CANONLIDE100 */ - {CIS_CANONLIDE100, - 2400, /* optical resolution */ - 87*4, /* black pixels */ - 16*4, /* dummy pixels 16 */ - 320*4, /* 323 */ - 5136*4, /* 10272 */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - /* reg 0x10 - 0x15 */ - {0x01, 0xc1, 0x01, 0x26, 0x00, 0xe5, /* EXPR/EXPG/EXPB */ - /* reg 0x16 - 0x1d 0x19=0x50*/ - 0x10, 0x08, 0x00, 0x50, 0x34, 0x00, 0x02, 0x04 }, - /* reg 0x52 - 0x5e */ - {0x03, 0x07, - 0x00, 0x00, 0x00, 0x00, - 0x2a, 0xe1, - 0x55, - 0x00, 0x00, 0x00, - 0x41 - } - , - {1.7, 1.7, 1.7}, - {NULL, NULL, NULL} - } - , - {CCD_KVSS080, - 600, - 38, /* black pixels on left */ - 38, /* 36 dummy pixels */ - 152, - 5376, /* 5100-> 5200 */ - 160, /* TAU white ref */ - 160, /* gain white ref */ - /* 08 09 0a 0b */ - {0x00, 0x00, 0x00, 0x6a} , - /* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x1c, 0x00, 0x2a, 0x2c, 0x00, 0x20, 0x04} , /* 18=00 at 600 dpi */ - /* 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e */ - {0x0c, 0x0f, 0x00, 0x03, 0x06, 0x09, 0x6b, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x23} , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - {CCD_G4050, - 4800, - 50*8, /* black_pixels */ - 58, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ - 152, - 5360*8, /* 5360 max at 600 dpi */ - 160, - 160, - /* 08 09 0a 0b */ - {0x00, 0x00, 0x18, 0x69} , - /* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d */ - {0x2c, 0x09, 0x22, 0xb8, 0x10, 0xf0, 0x33, 0x0c, 0x00, 0x2a, 0x30, 0x00, 0x00, 0x08} , - /* 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e */ - {0x0b, 0x0e, 0x11, 0x02, 0x05, 0x08, 0x63, 0x00, 0x40, 0x00, 0x00, 0x00, 0x6f} , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - {CCD_CS4400F, - 4800, - 50*8, /* black_pixels */ - 20, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ - 152, - 5360*8, /* 5360 max at 600 dpi */ - 160, - 160, - /* 08 09 0a 0b */ - {0x00, 0x00, 0x18, 0x69} , - /* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d */ - {0x9c, 0x40, 0x9c, 0x40, 0x9c, 0x40, 0x13, 0x0a, 0x10, 0x2a, 0x30, 0x00, 0x00, 0x6b}, - /* 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e */ - {0x0a, 0x0d, 0x00, 0x03, 0x06, 0x08, 0x5b, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f}, - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - {CCD_CS8400F, - 4800, - 50*8, /* black_pixels */ - 20, /* 31 at 600 dpi dummy_pixels 58 at 1200 */ - 152, - 5360*8, /* 5360 max at 600 dpi */ - 160, - 160, - /* 08 09 0a 0b */ - {0x00, 0x00, 0x18, 0x69} , - /* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d */ - {0x9c, 0x40, 0x9c, 0x40, 0x9c, 0x40, 0x13, 0x0a, 0x10, 0x2a, 0x30, 0x00, 0x00, 0x6b}, - /* 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e */ - {0x0a, 0x0d, 0x00, 0x03, 0x06, 0x08, 0x5b, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f}, - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - /* HP N6310 */ - {CCD_HP_N6310, - 2400, - 96, - 26, - 128, - 42720, - 210, - 230, - /* 08 09 0a 0b */ - {0x00, 0x10, 0x10, 0x0c} , - /* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x0c, 0x02, 0x2a, 0x30, 0x00, 0x00, 0x08} , - /* 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e */ - {0x0b, 0x0e, 0x11, 0x02, 0x05, 0x08, 0x63, 0x00, 0x40, 0x00, 0x00, 0x06, 0x6f} , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL} - } - , - - /* CANONLIDE110 */ - {CIS_CANONLIDE110, - 2400, /* optical resolution */ - 87, /* black pixels */ - 16, /* dummy pixels 16 */ - 303, /* 303 */ - 5168*4, /* total pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - /* reg 0x10 - 0x15 : EXPR, EXPG and EXPB */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* reg 0x16 - 0x1d */ - 0x10, 0x04, 0x00, 0x01, 0x30, 0x00, 0x02, 0x01 }, - /* reg 0x52 - 0x5e */ - { - 0x00, 0x02, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, - 0x1a, 0x00, 0xc0, 0x00, 0x00 - } - , - {2.1, 2.1, 2.1}, - {NULL, NULL, NULL}} - , - - /* CANONLIDE120 */ - {CIS_CANONLIDE120, - 2400, /* optical resolution */ - 87, /* black pixels */ - 16, /* dummy pixels 16 */ - 303, - /* SEGCNT at 600 DPI by number of segments */ - 5104*4, /* total pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - /* reg 0x10 - 0x15 : EXPR, EXPG and EXPB */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* reg 0x16 - 0x1d */ - 0x15, 0x04, 0x00, 0x01, 0x30, 0x00, 0x02, 0x01 }, - /* reg 0x52 - 0x5e */ - { - /* 52 53 54 55 56 57 58 59 */ - 0x04, 0x06, 0x00, 0x02, 0x04, 0x04, 0x04, 0x04, - /* 5a 5b 5c 5d 5e */ - 0x3a, 0x00, 0x00, 0x00, 0x1f - } - , - {2.1, 2.1, 2.1}, - {NULL, NULL, NULL}} - , - /* CANON LIDE 210 sensor */ - {CIS_CANONLIDE210, - 2400, /* optical resolution */ - 87, /* black pixels */ - 16, /* dummy pixels 16 */ - 303, /* 303 */ - 5168*4, /* total pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - /* reg 0x10 - 0x15 : EXPR, EXPG and EXPB */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* reg 0x16 - 0x1d */ - 0x10, 0x04, 0x00, 0x01, 0x30, 0x00, 0x02, 0x01 }, - /* reg 0x52 - 0x5e */ - { - 0x00, 0x02, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, - 0x1a, 0x00, 0xc0, 0x00, 0x00 - } - , - {2.1, 2.1, 2.1}, - {NULL, NULL, NULL}} - , - /* CANON LIDE 220 sensor */ - {CIS_CANONLIDE220, - 2400, /* optical resolution */ - 87, /* black pixels */ - 16, /* dummy pixels 16 */ - 303, /* 303 */ - 5168*4, /* total pixels */ - 210, - 200, - {0x00, 0x00, 0x00, 0x00}, - /* reg 0x10 - 0x15 : EXPR, EXPG and EXPB */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - /* reg 0x16 - 0x1d */ - 0x10, 0x04, 0x00, 0x01, 0x30, 0x00, 0x02, 0x01 }, - /* reg 0x52 - 0x5e */ - { - 0x00, 0x02, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, - 0x1a, 0x00, 0xc0, 0x00, 0x00 - } - , - {2.1, 2.1, 2.1}, - {NULL, NULL, NULL}} - , - {CCD_PLUSTEK_3600, - 1200, - 87, /*(black) */ - 87, /* (dummy) */ - 0, /* (startxoffset) */ - 10100, /*sensor_pixels */ - 210, - 230, - {0x00, 0x00, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x0b, 0x11, 0x2a, - 0x00, 0x00, 0x00, 0xc4 /* TODO(these do no harm, but may be neccessery for CCD) */ - }, - {0x07, 0x0a, - 0x0c, 0x00, 0x02, 0x06, /*[GB](HI|LOW) not needed for cis */ - 0x22, 0x69, - 0x40, /*TODO: bit7 */ - 0x00, 0x00, 0x00, 0x02 /*TODO (these do no harm, but may be neccessery for CCD) */ - } - , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL}} - , - /* Canon Image formula 101 */ - {CCD_IMG101, - 1200, /* optical resolution */ - 31, - 31, - 0, - 10800, - 210, - 200, - {0x60, 0x00, 0x00, 0x8b}, - /* reg 0x10 - 0x15 */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* EXPR/EXPG/EXPB */ - /* reg 0x16 - 0x1d 0x19=0x50*/ - 0xbb, 0x13, 0x10, 0x2a, 0x34, 0x00, 0x20, 0x06 }, - /* reg 0x52 - 0x5e */ - {0x02, 0x04, - 0x06, 0x08, 0x0a, 0x00, - 0x59, 0x31, - 0x40, - 0x00, 0x00, 0x00, - 0x1f - } - , - {1.7, 1.7, 1.7}, - {NULL, NULL, NULL} - } - , - /* Plustek OpticBook 3800 */ - {CCD_PLUSTEK3800, - 1200, /* optical resolution */ - 31, - 31, - 0, - 10200, - 210, - 200, - {0x60, 0x00, 0x00, 0x8b}, - /* reg 0x10 - 0x15 */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* EXPR/EXPG/EXPB */ - /* reg 0x16 - 0x1d 0x19=0x50*/ - 0xbb, 0x13, 0x10, 0x2a, 0x34, 0x00, 0x20, 0x06 }, - /* reg 0x52 - 0x5e */ - {0x02, 0x04, - 0x06, 0x08, 0x0a, 0x00, - 0x59, 0x31, - 0x40, - 0x00, 0x00, 0x00, - 0x1f - } - , - {1.7, 1.7, 1.7}, - {NULL, NULL, NULL} - }, - /* CANOLIDE80 */ - {CIS_CANONLIDE80, - 1200, /* real hardware limit is 2400 */ - 20, /* black pixels */ - 6, /* expdummy 6 */ - /* tuned to give 3*8 multiple startx coordinate during shading calibration */ - 34, /* CCD_start_xoffset 14=>3, 20=>2 */ - 10240, /* 10400, too wide=>10288 in shading data 10240~, 10208 too short for shading, max shading data = 10240 pixels, endpix-startpix=10208 */ - 150, - 150, - {0x00, 0x05, 0x07, 0x09}, /* in fact ,maps to 0x70-0x73 for GL841 */ - /* [0x10-0x15] values are initial led exposure values */ - /* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d*/ - {0x10, 0x00, 0x10, 0x00, 0x05, 0x00, 0x00, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x04}, - {0x03, 0x07, 0x00, 0x00, 0x00, 0x00, 0x29, 0x69, 0x55, 0x00, 0x00, 0x20, 0x41} , - {1.0, 1.0, 1.0}, - {NULL, NULL, NULL}} -}; - -/** for General Purpose Output specific settings: - * initial GPO value (registers 0x66-0x67/0x6c-0x6d) - * GPO enable mask (registers 0x68-0x69/0x6e-0x6f) - * The first register is for GPIO9-GPIO16, the second for GPIO1-GPIO8 - */ -static Genesys_Gpo Gpo[] = { - /* UMAX */ - {GPO_UMAX, - {0x11, 0x00} - , - {0x51, 0x20} - , - } - , - /* Plustek OpticPro S12/ST12 */ - {GPO_ST12, - {0x11, 0x00} - , - {0x51, 0x20} - , - } - , - /* Plustek OpticPro S24/ST24 */ - {GPO_ST24, - {0x00, 0x00} - , - {0x51, 0x20} - , - } - , - /* MD5345/MD6471 */ - {GPO_5345, - {0x30, 0x18} - , /* bits 11-12 are for bipolar V-ref input voltage */ - {0xa0, 0x18} - , - } - , - /* HP2400C */ - {GPO_HP2400, - {0x30, 0x00} - , - {0x31, 0x00} - , - } - , - /* HP2300C */ - {GPO_HP2300, - {0x00, 0x00} - , - {0x00, 0x00} - , - } - , - /* CANONLIDE35 */ - {GPO_CANONLIDE35, - {0x02, 0x80} - , - {0xef, 0x80} - , - } - , - /* 7: XP200 */ - {GPO_XP200, - {0x30, 0x00} - , - {0xb0, 0x00} - , - }, - /* HP3670 */ - {GPO_HP3670, - {0x00, 0x00} - , - {0x00, 0x00} - } - , - /* 8: XP300 */ - {GPO_XP300, - {0x09, 0xc6}, - {0xbb, 0x00}, - } - , - /* Syscan DP 665 */ - { - GPO_DP665, - {0x18, 0x00},/*0x19,0x00*/ - {0xbb, 0x00}, - } - , - /* Syscan DP 685 */ - { - GPO_DP685, - {0x3f, 0x46}, /* 6c, 6d */ - {0xfb, 0x00}, /* 6e, 6f */ - }, - /* CANONLIDE200 */ - {GPO_CANONLIDE200, - {0xfb, 0x20}, /* 0xfb when idle , 0xf9/0xe9 (1200) when scanning */ - {0xff, 0x00}, - }, - /* CANONLIDE700 */ - {GPO_CANONLIDE700, - {0xdb, 0xff}, - {0xff, 0x80}, - }, - {GPO_KVSS080, - {0xf5, 0x20}, - {0x7e, 0xa1}, - } - , - {GPO_G4050, - {0x20, 0x00}, - {0xfc, 0x00}, - } - , - /* HP N6310 */ - {GPO_HP_N6310, - {0xa3, 0x00}, - {0x7f, 0x00}, - } - , - /* CANONLIDE110 */ - {GPO_CANONLIDE110, - {0xfb, 0x20}, - {0xff, 0x00}, - } - , - /* CANONLIDE120 */ - {GPO_CANONLIDE120, - {0xfb, 0x20}, - {0xff, 0x00}, - } - , - /* CANONLIDE210 */ - {GPO_CANONLIDE210, - {0xfb, 0x20}, - {0xff, 0x00}, - } - , - /* Plustek 3600 */ - {GPO_PLUSTEK_3600, - {0x02, 0x00}, - {0x1e, 0x80}, - } - /* CanoScan 4400f */ - , - {GPO_CS4400F, - {0x01, 0x7f}, - {0xff, 0x00}, - } - /* CanoScan 8400f */ - , - {GPO_CS8400F, - {0x9a, 0xdf}, - {0xfe, 0x60}, - } - /* Canon Image formula 101 */ - , - {GPO_IMG101, - {0x41, 0xa4}, - {0x13, 0xa7} - } - /* Plustek OpticBook 3800 */ - , - {GPO_PLUSTEK3800, - {0x41, 0xa4}, - {0x13, 0xa7} - }, - /* Canon LiDE 80 */ - { - GPO_CANONLIDE80, - {0x28, 0x90}, /* 6c, 6d */ - {0x75, 0x80}, /* 6e, 6f */ - } -}; - -static Genesys_Motor Motor[] = { - /* UMAX */ - {MOTOR_UMAX, - 1200, /* motor base steps */ - 2400, /* maximum motor resolution */ - 1, /* maximum step mode */ - 1, /* number of power modes*/ - {{{ - 11000, /* maximum start speed */ - 3000, /* maximum end speed */ - 128, /* step count */ - 1.0, /* nonlinearity */ - }, - { - 11000, - 3000, - 128, - 1.0, - },},}, - }, - {MOTOR_5345, /* MD5345/6228/6471 */ - 1200, - 2400, - 1, - 1, - {{{ - 2000, - 1375, - 128, - 0.5, - }, - { - 2000, - 1375, - 128, - 0.5, - },},}, - }, - {MOTOR_ST24, /* ST24 */ - 2400, - 2400, - 1, - 1, - {{{ - 2289, - 2100, - 128, - 0.3, - }, - { - 2289, - 2100, - 128, - 0.3, - },},}, - }, - {MOTOR_HP3670, /* HP 3670 */ - 1200, - 2400, - 1, - 1, - {{{ - 11000, /* start speed */ - 3000, /* max speed */ - 128, /* min steps */ - 0.25, - }, - { - 11000, - 3000, - 128, - 0.5, - },},}, - }, - {MOTOR_HP2400, /* HP 2400c */ - 1200, - 1200, - 1, - 1, - {{{ - 11000, /* start speed */ - 3000, /* max speed */ - 128, /* min steps */ - 0.25, - }, - { - 11000, - 3000, - 128, - 0.5, - },},}, - }, - {MOTOR_HP2300, /* HP 2300c */ - 600, /* 600/1200 */ - 1200, - 1, - 1, - {{{ - 3200, - 1200, - 128, - 0.5, - }, - { - 3200, - 1200, - 128, - 0.5, - },},}, - }, - {MOTOR_CANONLIDE35, /* Canon LiDE 35 */ - 1200, - 2400, - 1, - 1, - {{{ 3500, 1300, 60, 0.8, }, - { 3500, 1400, 60, 0.8, },},}, - }, - {MOTOR_XP200, /* Strobe XP200 */ - 600, - 600, - 1, - 1, - {{{ - 3500, - 1300, - 60, - 0.25, - }, - { - 3500, - 1400, - 60, - 0.5, - },},}, - }, - {MOTOR_XP300, /* 7: Visioneer Strobe XP300 */ - 300, - 600, - 1, - 1, - {{{ /* works best with GPIO10, GPIO14 off */ - 3700, - 3700, - 2, - 0.8, - }, - { - 11000, - 11000, - 2, - 0.8, - },},}, - }, - {MOTOR_DP665, /* Syscan DP 665 */ - 750, - 1500, - 1, - 1, - {{{ - 3000, - 2500, - 10, - 0.8, - }, - { - 11000, - 11000, - 2, - 0.8, - },},}, - }, - {MOTOR_ROADWARRIOR, /* Visioneer Roadwarrior */ - 750, - 1500, - 1, - 1, - {{{ - 3000, - 2600, - 10, - 0.8, - }, - { - 11000, - 11000, - 2, - 0.8, - },},}, - }, - {MOTOR_DSMOBILE_600, /* Pentax DSmobile 600 */ - 750, - 1500, - 2, - 1, - {{{ - 6666, - 3700, - 8, - 0.8, - }, - { - 6666, - 3700, - 8, - 0.8, - },},}, - }, - {MOTOR_CANONLIDE100, /* Canon LiDE 100 */ - 1200, - 6400, - 2, /* maximum step type count */ - 1, /* maximum power modes count */ - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ - }, - }, - }, - {MOTOR_CANONLIDE200, /* Canon LiDE 200 */ - 1200, - 6400, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ - }, - }, - }, - {MOTOR_CANONLIDE700, /* Canon LiDE 700 */ - 1200, - 6400, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ - }, - }, - }, - {MOTOR_KVSS080, - 1200, - 1200, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 22222, 500, 246, 0.5 }, /* max speed / dpi * base dpi => exposure */ - { 22222, 500, 246, 0.5 }, - { 22222, 500, 246, 0.5 }, - }, - }, - }, - {MOTOR_G4050, - 2400, - 9600, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3961, 240, 246, 0.8 }, /* full step */ - { 3961, 240, 246, 0.8 }, /* half step */ - { 3961, 240, 246, 0.8 }, /* quarter step */ - }, - }, - }, - {MOTOR_CS8400F, - 2400, - 9600, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3961, 240, 246, 0.8 }, /* full step */ - { 3961, 240, 246, 0.8 }, /* half step */ - { 3961, 240, 246, 0.8 }, /* quarter step */ - }, - }, - }, - {MOTOR_CANONLIDE110, /* Canon LiDE 110 */ - 4800, - 9600, - 1, /* maximum step type count */ - 1, /* maximum power modes count */ - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 256, 0.50}, /* full step */ - }, - }, - }, - {MOTOR_CANONLIDE120, /* Canon LiDE 120 */ - 4800, - 9600, - 1, /* maximum step type count */ - 1, /* maximum power modes count */ - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 256, 0.50}, /* full step */ - }, - }, - }, - {MOTOR_CANONLIDE210, /* Canon LiDE 210 */ - 4800, - 9600, - 1, /* maximum step type count */ - 1, /* maximum power modes count */ - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 256, 0.50}, /* full step */ - }, - }, - }, - {MOTOR_PLUSTEK_3600, /* PLUSTEK 3600 */ - 1200, - 2400, - 1, - 1, - { - { - { 3500, 1300, 60, 0.8 }, - { 3500, 3250, 60, 0.8 }, - }, - },}, - {MOTOR_IMG101, /* Canon Image Formula 101 */ - 600, - 1200, - 1, - 1, - { - { - { 3500, 1300, 60, 0.8 }, - { 3500, 3250, 60, 0.8 }, - }, - },}, - {MOTOR_PLUSTEK3800, /* Plustek OpticBook 3800 */ - 600, - 1200, - 1, - 1, - { - { - { 3500, 1300, 60, 0.8 }, - { 3500, 3250, 60, 0.8 }, - }, - },}, - {MOTOR_CANONLIDE80, - 2400, /* 2400 ???? */ - 4800, /* 9600 ???? */ - 1, /* max step type */ - 1, /* power mode count */ - { - { /* start speed, max end speed, step number */ - /* maximum speed (second field) is used to compute exposure as seen by motor */ - /* exposure=max speed/ slope dpi * base dpi */ - /* 5144 = max pixels at 600 dpi */ - /* 1288=(5144+8)*ydpi(=300)/base_dpi(=1200) , where 5152 is exposure */ - /* 6440=9660/(1932/1288) */ - { 9560, 1912, 31, 0.8 }, - }, - },}, -}; - -/* here we have the various device settings... - */ -static Genesys_Model umax_astra_4500_model = { - "umax-astra-4500", /* Name */ - "UMAX", /* Device vendor string */ - "Astra 4500", /* Device model name */ - GENESYS_GL646, - NULL, - - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_UMAX, - DAC_WOLFSON_UMAX, - GPO_UMAX, - MOTOR_UMAX, - GENESYS_FLAG_UNTESTED, /* Which flags are needed for this scanner? */ - /* untested, values set by hmg */ - GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ - 20, - 200 -}; - -static Genesys_Model canon_lide_50_model = { - "canon-lide-50", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 35/40/50", /* Device model name */ - GENESYS_GL841, - NULL, - - { 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.42), /* Start of scan area in mm (x) */ - SANE_FIX (7.9), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (6.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_CANONLIDE35, - DAC_CANONLIDE35, - GPO_CANONLIDE35, - MOTOR_CANONLIDE35, - GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_DARK_WHITE_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA | - GENESYS_FLAG_HALF_CCD_MODE, - GENESYS_HAS_SCAN_SW | - GENESYS_HAS_FILE_SW | - GENESYS_HAS_EMAIL_SW | - GENESYS_HAS_COPY_SW, - 280, - 400 -}; - -static Genesys_Model panasonic_kvss080_model = { - "panasonic-kv-ss080", /* Name */ - "Panasonic", /* Device vendor string */ - "KV-SS080", /* Device model name */ - GENESYS_GL843, - NULL, - - { 600, /* 500, 400,*/ 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - { 1200, 600, /* 500, 400, */ 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_KVSS080, - DAC_KVSS080, - GPO_KVSS080, - MOTOR_KVSS080, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW , - 100, - 100 -}; - -static Genesys_Model hp4850c_model = { - "hewlett-packard-scanjet-4850c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 4850C", /* Device model name */ - GENESYS_GL843, - NULL, - - {2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (7.9), /* Start of scan area in mm (x) */ - SANE_FIX (5.9), /* Start of scan area in mm (y) */ - SANE_FIX (219.6), /* Size of scan area in mm (x) */ - SANE_FIX (314.5), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_G4050, - DAC_G4050, - GPO_G4050, - MOTOR_G4050, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 100 -}; - -static Genesys_Model hpg4010_model = { - "hewlett-packard-scanjet-g4010", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet G4010", /* Device model name */ - GENESYS_GL843, - NULL, - - { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (8.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_G4050, - DAC_G4050, - GPO_G4050, - MOTOR_G4050, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 100 -}; - -static Genesys_Model hpg4050_model = { - "hewlett-packard-scanjet-g4050", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet G4050", /* Device model name */ - GENESYS_GL843, - NULL, - - { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (8.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_G4050, - DAC_G4050, - GPO_G4050, - MOTOR_G4050, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 100 -}; - - -static Genesys_Model canon_4400f_model = { - "canon-canoscan-4400f", /* Name */ - "Canon", /* Device vendor string */ - "Canoscan 4400f", /* Device model name */ - GENESYS_GL843, - NULL, - - { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (6.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_CS4400F, - DAC_G4050, - GPO_CS4400F, - MOTOR_G4050, - GENESYS_FLAG_NO_CALIBRATION | - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_FULL_HWDPI_MODE | - GENESYS_FLAG_HALF_CCD_MODE | /* actually quarter CCD mode ... */ - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 100 -}; - - -static Genesys_Model canon_8400f_model = { - "canon-canoscan-8400f", /* Name */ - "Canon", /* Device vendor string */ - "Canoscan 8400f", /* Device model name */ - GENESYS_GL843, - NULL, - - { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (4.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_CS8400F, - DAC_CS8400F, - GPO_CS8400F, - MOTOR_CS8400F, - GENESYS_FLAG_NO_CALIBRATION | - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_FULL_HWDPI_MODE | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 100 -}; - - - -static Genesys_Model canon_lide_100_model = { - "canon-lide-100", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 100", /* Device model name */ - GENESYS_GL847, - NULL, - - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE100, - DAC_CANONLIDE200, - GPO_CANONLIDE200, - MOTOR_CANONLIDE100, - /* Which flags are needed for this scanner? */ - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_SIS_SENSOR - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 400 -}; - -static Genesys_Model canon_lide_110_model = { - "canon-lide-110", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 110", /* Device model name */ - GENESYS_GL124, - NULL, - - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (9.0), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE110, - DAC_CANONLIDE110, - GPO_CANONLIDE110, - MOTOR_CANONLIDE110, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_HALF_CCD_MODE - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 400 -}; - -static Genesys_Model canon_lide_120_model = { - "canon-lide-120", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 120", /* Device model name */ - GENESYS_GL124, - NULL, - - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (8.0), /* Start of scan area in mm (y) */ - SANE_FIX (216.0), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE120, - DAC_CANONLIDE120, - GPO_CANONLIDE120, - MOTOR_CANONLIDE120, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_HALF_CCD_MODE - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 400 -}; - - -static Genesys_Model canon_lide_210_model = { - "canon-lide-210", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 210", /* Device model name */ - GENESYS_GL124, - NULL, - - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (8.7), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (297.5), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE210, - DAC_CANONLIDE110, - GPO_CANONLIDE210, - MOTOR_CANONLIDE210, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_HALF_CCD_MODE - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_EXTRA_SW, - 60, - 400 -}; - -static Genesys_Model canon_lide_220_model = { - "canon-lide-220", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 220", /* Device model name */ - GENESYS_GL124, /* or a compatible one */ - NULL, - - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (8.7), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (297.5), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE220, - DAC_CANONLIDE110, - GPO_CANONLIDE210, - MOTOR_CANONLIDE210, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_HALF_CCD_MODE - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_EXTRA_SW, - 60, - 400 -}; - -static Genesys_Model canon_5600f_model = { - "canon-5600f", /* Name */ - "Canon", /* Device vendor string */ - "5600F", /* Device model name */ - GENESYS_GL847, - NULL, - - {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE200, - DAC_CANONLIDE200, - GPO_CANONLIDE200, - MOTOR_CANONLIDE200, - GENESYS_FLAG_UNTESTED /* not working yet */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_SIS_SENSOR - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 400 -}; - -static Genesys_Model canon_lide_700f_model = { - "canon-lide-700f", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 700F", /* Device model name */ - GENESYS_GL847, - NULL, - - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (3.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.1), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (297.0), /* Size of scan area in mm (y) */ - - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE700, - DAC_CANONLIDE700, - GPO_CANONLIDE700, - MOTOR_CANONLIDE700, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_SIS_SENSOR - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 70, - 400 -}; - - - -static Genesys_Model canon_lide_200_model = { - "canon-lide-200", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 200", /* Device model name */ - GENESYS_GL847, - NULL, - - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE200, - DAC_CANONLIDE200, - GPO_CANONLIDE200, - MOTOR_CANONLIDE200, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_SIS_SENSOR - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 400 -}; - - -static Genesys_Model canon_lide_60_model = { - "canon-lide-60", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 60", /* Device model name */ - GENESYS_GL841, - NULL, - - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.42), /* Start of scan area in mm (x) */ - SANE_FIX (7.9), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (6.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_CANONLIDE35, - DAC_CANONLIDE35, - GPO_CANONLIDE35, - MOTOR_CANONLIDE35, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_WHITE_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_HALF_CCD_MODE, - - GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ - 300, - 400 -}; /* this is completely untested -- hmg */ - -static Genesys_Model canon_lide_80_model = { - "canon-lide-80", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 80", /* Device model name */ - GENESYS_GL841, - NULL, - - { 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.42), /* Start of scan area in mm (x) 0.42 */ - SANE_FIX (7.90), /* Start of scan area in mm (y) 7.90 */ - SANE_FIX (216.07), /* Size of scan area in mm (x) 218.00 */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (4.5), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE80, - DAC_CANONLIDE80, - GPO_CANONLIDE80, - MOTOR_CANONLIDE80, - GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_DARK_WHITE_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA | - GENESYS_FLAG_HALF_CCD_MODE, - GENESYS_HAS_SCAN_SW | - GENESYS_HAS_FILE_SW | - GENESYS_HAS_EMAIL_SW | - GENESYS_HAS_COPY_SW, - 160, /* 280 @2400 */ - 400 -}; - - -static Genesys_Model hp2300c_model = { - "hewlett-packard-scanjet-2300c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 2300c", /* Device model name */ - GENESYS_GL646, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions, motor can go up to 1200 dpi */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (2.0), /* Start of scan area in mm (x_offset) */ - SANE_FIX (7.5), /* Start of scan area in mm (y_offset) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (295.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 16, 8, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_HP2300, - DAC_WOLFSON_HP2300, - GPO_HP2300, - MOTOR_HP2300, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_HALF_CCD_MODE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW, - 40, - 132 -}; - -static -Genesys_Model hp2400c_model = { - "hewlett-packard-scanjet-2400c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 2400c", /* Device model name */ - GENESYS_GL646, - NULL, - - {1200, 600, 300, 150, 100, 50, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (6.5), /* Start of scan area in mm (x) */ - SANE_FIX (2.5), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (297.2), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_HP2400, - DAC_WOLFSON_HP2400, - GPO_HP2400, - MOTOR_HP2400, - GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW, - 20, - 132 -}; - -static -Genesys_Model visioneer_xp200_model = { - "visioneer-strobe-xp200", /* Name */ - "Visioneer", /* Device vendor string */ - "Strobe XP200", /* Device model name */ - GENESYS_GL646, - NULL, - - {600, 300, 200, 100, 75, 0}, /* possible x-resolutions */ - {600, 300, 200, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.5), /* Start of scan area in mm (x) */ - SANE_FIX (16.0), /* Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (297.2), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CIS_XP200, - DAC_AD_XP200, /* Analog Device frontend */ - GPO_XP200, - MOTOR_XP200, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 120, - 132 -}; - -static Genesys_Model hp3670c_model = { - "hewlett-packard-scanjet-3670c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 3670c", /* Device model name */ - GENESYS_GL646, - NULL, - - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (8.5), /* Start of scan area in mm (x) */ - SANE_FIX (11.0), /* Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (104.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (55.6), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (25.6), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (78.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (76.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_HP3670, - DAC_WOLFSON_HP3670, - GPO_HP3670, - MOTOR_HP3670, - GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_XPA - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW, - 20, - 200 -}; - -static Genesys_Model plustek_st12_model = { - "plustek-opticpro-st12", /* Name */ - "Plustek", /* Device vendor string */ - "OpticPro ST12", /* Device model name */ - GENESYS_GL646, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_ST12, - DAC_WOLFSON_ST12, - GPO_ST12, - MOTOR_UMAX, - GENESYS_FLAG_UNTESTED | GENESYS_FLAG_14BIT_GAMMA, /* Which flags are needed for this scanner? */ - GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ - 20, - 200 -}; - -static Genesys_Model plustek_st24_model = { - "plustek-opticpro-st24", /* Name */ - "Plustek", /* Device vendor string */ - "OpticPro ST24", /* Device model name */ - GENESYS_GL646, - NULL, - - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_ST24, - DAC_WOLFSON_ST24, - GPO_ST24, - MOTOR_ST24, - GENESYS_FLAG_UNTESTED - | GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_OFFSET_CALIBRATION, - GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ - 20, - 200 -}; - -static Genesys_Model medion_md5345_model = { - "medion-md5345-model", /* Name */ - "Medion", /* Device vendor string */ - "MD5345/MD6228/MD6471", /* Device model name */ - GENESYS_GL646, - NULL, - - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX ( 0.30), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ - - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_5345, - DAC_WOLFSON_5345, - GPO_5345, - MOTOR_5345, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_HALF_CCD_MODE - | GENESYS_FLAG_SHADING_NO_MOVE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, - 40, - 200 -}; - -static Genesys_Model visioneer_xp300_model = { - "visioneer-strobe-xp300", /* Name */ - "Visioneer", /* Device vendor string */ - "Strobe XP300", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (26.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - /* this is larger than needed -- accounts for second sensor head, which is a - calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_XP300, - DAC_WOLFSON_XP300, - GPO_XP300, - MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model syscan_docketport_665_model = { - "syscan-docketport-665", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 665", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (108.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (17.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_DP665, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_DP665, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model visioneer_roadwarrior_model = { - "visioneer-roadwarrior", /* Name */ - "Visioneer", /* Device vendor string */ - "Readwarrior", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_ROADWARRIOR, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model syscan_docketport_465_model = { - "syscan-docketport-465", /* Name */ - "Syscan", /* Device vendor string */ - "DocketPORT 465", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_ROADWARRIOR, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_NO_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_UNTESTED, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW, - 300, - 400 -}; - -static Genesys_Model visioneer_xp100_r3_model = { - "visioneer-xp100-revision3", /* Name */ - "Visioneer", /* Device vendor string */ - "XP100 Revision 3", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_ROADWARRIOR, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model pentax_dsmobile_600_model = { - "pentax-dsmobile-600", /* Name */ - "Pentax", /* Device vendor string */ - "DSmobile 600", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_DSMOBILE600, - DAC_WOLFSON_DSM600, - GPO_DP665, - MOTOR_DSMOBILE_600, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model syscan_docketport_467_model = { - "syscan-docketport-467", /* Name */ - "Syscan", /* Device vendor string */ - "DocketPORT 467", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_DSMOBILE600, - DAC_WOLFSON_DSM600, - GPO_DP665, - MOTOR_DSMOBILE_600, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model syscan_docketport_685_model = { - "syscan-docketport-685", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 685", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (212.0), /* Size of scan area in mm (x) */ - SANE_FIX (500), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (26.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - /* this is larger than needed -- accounts for second sensor head, which is a - calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_DP685, - DAC_WOLFSON_DSM600, - GPO_DP685, - MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model syscan_docketport_485_model = { - "syscan-docketport-485", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 485", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (26.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - /* this is larger than needed -- accounts for second sensor head, which is a - calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_XP300, - DAC_WOLFSON_XP300, - GPO_XP300, - MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model dct_docketport_487_model = { - "dct-docketport-487", /* Name */ - "DCT", /* Device vendor string */ - "DocketPORT 487", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (26.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - /* this is larger than needed -- accounts for second sensor head, which is a - calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_XP300, - DAC_WOLFSON_XP300, - GPO_XP300, - MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_UNTESTED, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model visioneer_7100_model = { - "visioneer-7100-model", /* Name */ - "Visioneer", /* Device vendor string */ - "OneTouch 7100", /* Device model name */ - GENESYS_GL646, - NULL, - - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ - - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ -/* 48, 24, 0, */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_5345, - DAC_WOLFSON_5345, - GPO_5345, - MOTOR_5345, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_HALF_CCD_MODE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, - 40, - 200 -}; - -static Genesys_Model xerox_2400_model = { - "xerox-2400-model", /* Name */ - "Xerox", /* Device vendor string */ - "OneTouch 2400", /* Device model name */ - GENESYS_GL646, - NULL, - - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ - - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ -/* 48, 24, 0, */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_5345, - DAC_WOLFSON_5345, - GPO_5345, - MOTOR_5345, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_HALF_CCD_MODE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, - 40, - 200 -}; - - -static Genesys_Model xerox_travelscanner_model = { - "xerox-travelscanner", /* Name */ - "Xerox", /* Device vendor string */ - "Travelscanner 100", /* Device model name */ - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (4.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_ROADWARRIOR, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 400 -}; - -static Genesys_Model plustek_3600_model = { - "plustek-opticbook-3600", /* Name */ - "PLUSTEK", /* Device vendor string */ - "OpticBook 3600", /* Device model name */ - GENESYS_GL841, - NULL, - {/*1200,*/ 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {/*2400,*/ 1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.42),/*SANE_FIX (0.42), Start of scan area in mm (x) */ - SANE_FIX (6.75),/*SANE_FIX (7.9), Start of scan area in mm (y) */ - SANE_FIX (216.0),/*SANE_FIX (216.0), Size of scan area in mm (x) */ - SANE_FIX (297.0),/*SANE_FIX (297.0), Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_PLUSTEK_3600, - DAC_PLUSTEK_3600, - GPO_PLUSTEK_3600, - MOTOR_PLUSTEK_3600, - GENESYS_FLAG_UNTESTED /* not fully working yet */ - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_HALF_CCD_MODE,/* - | GENESYS_FLAG_NO_CALIBRATION,*/ - GENESYS_HAS_NO_BUTTONS, - 7, - 200 -}; - -static Genesys_Model hpn6310_model = { - "hewlett-packard-scanjet-N6310", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet N6310", /* Device model name */ - GENESYS_GL847, - NULL, - - { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 0}, - { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 0}, - - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (6), /* Start of scan area in mm (x) */ - SANE_FIX (2), /* Start of scan area in mm (y) */ - SANE_FIX (216), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_HP_N6310, - DAC_CANONLIDE200, /*Not defined yet for N6310 */ - GPO_HP_N6310, - MOTOR_CANONLIDE200, /*Not defined yet for N6310 */ - GENESYS_FLAG_UNTESTED /* not fully working yet */ - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_NO_CALIBRATION, -/* | GENESYS_FLAG_HALF_CCD_MODE,*/ - - GENESYS_HAS_NO_BUTTONS, - 100, - 100 -}; - - -static Genesys_Model plustek_3800_model = { - "plustek-opticbook-3800", /* Name */ - "PLUSTEK", /* Device vendor string */ - "OpticBook 3800", /* Device model name */ - GENESYS_GL845, - NULL, - - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_PLUSTEK3800, - DAC_PLUSTEK3800, - GPO_PLUSTEK3800, - MOTOR_PLUSTEK3800, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_NO_BUTTONS, /* TODO there are 4 buttons to support */ - 100, - 100 -}; - - -static Genesys_Model canon_formula101_model = { - "canon-image-formula-101", /* Name */ - "Canon", /* Device vendor string */ - "Image Formula 101", /* Device model name */ - GENESYS_GL846, - NULL, - - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_IMG101, - DAC_IMG101, - GPO_IMG101, - MOTOR_IMG101, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_NO_BUTTONS , - 100, - 100 -}; - - -static Genesys_USB_Device_Entry genesys_usb_device_list[] = { - /* GL646 devices */ - {0x03f0, 0x0901, &hp2300c_model}, - {0x03f0, 0x0a01, &hp2400c_model}, - {0x03f0, 0x1405, &hp3670c_model}, - {0x0461, 0x0377, &medion_md5345_model}, - {0x04a7, 0x0229, &visioneer_7100_model}, - {0x0461, 0x038b, &xerox_2400_model}, - {0x04a7, 0x0426, &visioneer_xp200_model}, - {0x0638, 0x0a10, &umax_astra_4500_model}, - {0x07b3, 0x0600, &plustek_st12_model}, - {0x07b3, 0x0601, &plustek_st24_model}, - /* GL841 devices */ - {0x04a7, 0x0474, &visioneer_xp300_model}, - {0x04a7, 0x0494, &visioneer_roadwarrior_model}, - {0x04a7, 0x049b, &visioneer_xp100_r3_model}, - {0x04a7, 0x04ac, &xerox_travelscanner_model}, - {0x04a9, 0x2213, &canon_lide_50_model}, - {0x04a9, 0x221c, &canon_lide_60_model}, - {0x04a9, 0x2214, &canon_lide_80_model}, - {0x07b3, 0x0900, &plustek_3600_model}, - {0x0a17, 0x3210, &pentax_dsmobile_600_model}, - {0x04f9, 0x2038, &pentax_dsmobile_600_model}, /* clone, only usb id is different */ - {0x0a82, 0x4800, &syscan_docketport_485_model}, - {0x0a82, 0x4802, &syscan_docketport_465_model}, - {0x0a82, 0x4803, &syscan_docketport_665_model}, - {0x0a82, 0x480c, &syscan_docketport_685_model}, - {0x1dcc, 0x4810, &dct_docketport_487_model}, - {0x1dcc, 0x4812, &syscan_docketport_467_model}, - /* GL843 devices */ - {0x04da, 0x100f, &panasonic_kvss080_model}, - {0x03f0, 0x1b05, &hp4850c_model}, - {0x03f0, 0x4505, &hpg4010_model}, - {0x03f0, 0x4605, &hpg4050_model}, - {0x04a9, 0x2228, &canon_4400f_model}, - {0x04a9, 0x221e, &canon_8400f_model}, - /* GL845 devices */ - {0x07b3, 0x1300, &plustek_3800_model}, - /* GL846 devices */ - {0x1083, 0x162e, &canon_formula101_model}, - /* GL847 devices */ - {0x04a9, 0x1904, &canon_lide_100_model}, - {0x04a9, 0x1905, &canon_lide_200_model}, - {0x04a9, 0x1906, &canon_5600f_model}, - {0x04a9, 0x1907, &canon_lide_700f_model}, - {0x03f0, 0x4705, &hpn6310_model}, - /* GL124 devices */ - {0x04a9, 0x1909, &canon_lide_110_model}, - {0x04a9, 0x190e, &canon_lide_120_model}, - {0x04a9, 0x190a, &canon_lide_210_model}, - {0x04a9, 0x190f, &canon_lide_220_model}, - {0, 0, NULL} -}; - -#define MAX_SCANNERS (sizeof(genesys_usb_device_list) / \ - sizeof(genesys_usb_device_list[0])) diff --git a/backend/genesys_devices.cc b/backend/genesys_devices.cc new file mode 100644 index 0000000..b4ae5ca --- /dev/null +++ b/backend/genesys_devices.cc @@ -0,0 +1,5165 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003 Oliver Rauch + Copyright (C) 2003-2005 Henning Meier-Geinitz + Copyright (C) 2004, 2005 Gerhard Jaeger + Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2007 Luke + Copyright (C) 2010 Jack McGill + Copyright (C) 2010 Andrey Loginov , + xerox travelscan device entry + Copyright (C) 2010 Chris Berry and Michael Rickmann + for Plustek Opticbook 3600 support + + 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. +*/ + +/* ------------------------------------------------------------------------ */ +/* Some setup DAC and CCD tables */ +/* ------------------------------------------------------------------------ */ + +#include "genesys_low.h" + +StaticInit> s_frontends; + +void genesys_init_frontend_tables() +{ + s_frontends.init(); + + GenesysFrontendLayout wolfson_layout; + wolfson_layout.offset_addr = { 0x20, 0x21, 0x22 }; + wolfson_layout.gain_addr = { 0x28, 0x29, 0x2a }; + + Genesys_Frontend fe; + fe.fe_id = DAC_WOLFSON_UMAX; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x11 }, + { 0x20, 0x80 }, + { 0x21, 0x80 }, + { 0x22, 0x80 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x02 }, + { 0x29, 0x02 }, + { 0x2a, 0x02 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_WOLFSON_ST12; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x03 }, + { 0x20, 0xc8 }, + { 0x21, 0xc8 }, + { 0x22, 0xc8 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x04 }, + { 0x29, 0x04 }, + { 0x2a, 0x04 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_WOLFSON_ST24; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x21 }, + { 0x20, 0xc8 }, + { 0x21, 0xc8 }, + { 0x22, 0xc8 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x06 }, + { 0x29, 0x06 }, + { 0x2a, 0x06 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_WOLFSON_5345; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x12 }, + { 0x20, 0xb8 }, + { 0x21, 0xb8 }, + { 0x22, 0xb8 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x04 }, + { 0x29, 0x04 }, + { 0x2a, 0x04 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + // reg3=0x02 for 50-600 dpi, 0x32 (0x12 also works well) at 1200 + fe = Genesys_Frontend(); + fe.fe_id = DAC_WOLFSON_HP2400; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x02 }, + { 0x20, 0xb4 }, + { 0x21, 0xb6 }, + { 0x22, 0xbc }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x06 }, + { 0x29, 0x09 }, + { 0x2a, 0x08 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_WOLFSON_HP2300; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x04 }, + { 0x03, 0x02 }, + { 0x20, 0xbe }, + { 0x21, 0xbe }, + { 0x22, 0xbe }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x04 }, + { 0x29, 0x04 }, + { 0x2a, 0x04 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_CANONLIDE35; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x3d }, + { 0x02, 0x08 }, + { 0x03, 0x00 }, + { 0x20, 0xe1 }, + { 0x21, 0xe1 }, + { 0x22, 0xe1 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x93 }, + { 0x29, 0x93 }, + { 0x2a, 0x93 }, + }; + fe.reg2 = {0x00, 0x19, 0x06}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_AD_XP200; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x58 }, + { 0x01, 0x80 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x09 }, + { 0x21, 0x09 }, + { 0x22, 0x09 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x09 }, + { 0x29, 0x09 }, + { 0x2a, 0x09 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_WOLFSON_XP300; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x35 }, + { 0x02, 0x20 }, + { 0x03, 0x14 }, + { 0x20, 0xe1 }, + { 0x21, 0xe1 }, + { 0x22, 0xe1 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x93 }, + { 0x29, 0x93 }, + { 0x2a, 0x93 }, + }; + fe.reg2 = {0x07, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_WOLFSON_HP3670; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x32 }, + { 0x20, 0xba }, + { 0x21, 0xb8 }, + { 0x22, 0xb8 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x06 }, + { 0x29, 0x05 }, + { 0x2a, 0x04 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_WOLFSON_DSM600; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x35 }, + { 0x02, 0x20 }, + { 0x03, 0x14 }, + { 0x20, 0x85 }, + { 0x21, 0x85 }, + { 0x22, 0x85 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0xa0 }, + { 0x29, 0xa0 }, + { 0x2a, 0xa0 }, + }; + fe.reg2 = {0x07, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_CANONLIDE200; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x9d }, + { 0x01, 0x91 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x3f }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x32 }, + { 0x29, 0x04 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_CANONLIDE700; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x9d }, + { 0x01, 0x9e }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x3f }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x2f }, + { 0x29, 0x04 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_KVSS080; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x0f }, + { 0x20, 0x80 }, + { 0x21, 0x80 }, + { 0x22, 0x80 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x4b }, + { 0x29, 0x4b }, + { 0x2a, 0x4b }, + }; + fe.reg2 = {0x00,0x00,0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_G4050; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x1f }, + { 0x20, 0x45 }, + { 0x21, 0x45 }, + { 0x22, 0x45 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x4b }, + { 0x29, 0x4b }, + { 0x2a, 0x4b }, + }; + fe.reg2 = {0x00,0x00,0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_CANONLIDE110; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x80 }, + { 0x01, 0x8a }, + { 0x02, 0x23 }, + { 0x03, 0x4c }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0xca }, + { 0x26, 0x94 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + /** @brief GL124 special case + * for GL124 based scanners, this struct is "abused" + * in fact the fields are map like below to AFE registers + * (from Texas Instrument or alike ?) + */ + fe = Genesys_Frontend(); + fe.fe_id = DAC_CANONLIDE120; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x80 }, + { 0x01, 0xa3 }, + { 0x02, 0x2b }, + { 0x03, 0x4c }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, // actual address 0x05 + { 0x25, 0xca }, // actual address 0x06 + { 0x26, 0x95 }, // actual address 0x07 + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_PLUSTEK_3600; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x70 }, + { 0x01, 0x80 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x3f }, + { 0x29, 0x3d }, + { 0x2a, 0x3d }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_CS8400F; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x0f }, + { 0x20, 0x60 }, + { 0x21, 0x5c }, + { 0x22, 0x6c }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x8a }, + { 0x29, 0x9f }, + { 0x2a, 0xc2 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_CS8600F; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x2f }, + { 0x20, 0x67 }, + { 0x21, 0x69 }, + { 0x22, 0x68 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0xdb }, + { 0x29, 0xda }, + { 0x2a, 0xd7 }, + }; + fe.reg2 = { 0x00, 0x00, 0x00 }; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_IMG101; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x78 }, + { 0x01, 0xf0 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.fe_id = DAC_PLUSTEK3800; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x78 }, + { 0x01, 0xf0 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + /* reg0: control 74 data, 70 no data + * reg3: offset + * reg6: gain + * reg0 , reg3, reg6 */ + fe = Genesys_Frontend(); + fe.fe_id = DAC_CANONLIDE80; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x70 }, + { 0x01, 0x16 }, + { 0x02, 0x60 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); +} + + +/** for setting up the sensor-specific settings: + * Optical Resolution, number of black pixels, number of dummy pixels, + * CCD_start_xoffset, and overall number of sensor pixels + * registers 0x08-0x0b, 0x10-0x1d and 0x52-0x5e + */ +StaticInit> s_sensors; + +void genesys_init_sensor_tables() +{ + s_sensors.init(); + + Genesys_Sensor sensor; + sensor.sensor_id = CCD_UMAX; + sensor.optical_res = 1200; + sensor.black_pixels = 48; + sensor.dummy_pixel = 64; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10800; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x01 }, + { 0x09, 0x03 }, + { 0x0a, 0x05 }, + { 0x0b, 0x07 }, + { 0x16, 0x33 }, + { 0x17, 0x05 }, + { 0x18, 0x31 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x13 }, + { 0x53, 0x17 }, + { 0x54, 0x03 }, + { 0x55, 0x07 }, + { 0x56, 0x0b }, + { 0x57, 0x0f }, + { 0x58, 0x23 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_ST12; + sensor.optical_res = 600; + sensor.black_pixels = 48; + sensor.dummy_pixel = 85; + sensor.CCD_start_xoffset = 152; + sensor.sensor_pixels = 5416; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x02 }, + { 0x09, 0x00 }, + { 0x0a, 0x06 }, + { 0x0b, 0x04 }, + { 0x16, 0x2b }, + { 0x17, 0x08 }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x0c }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_ST24; + sensor.optical_res = 1200; + sensor.black_pixels = 48; + sensor.dummy_pixel = 64; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10800; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x0e }, + { 0x09, 0x0c }, + { 0x0a, 0x00 }, + { 0x0b, 0x0c }, + { 0x16, 0x33 }, + { 0x17, 0x08 }, + { 0x18, 0x31 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x17 }, + { 0x53, 0x03 }, + { 0x54, 0x07 }, + { 0x55, 0x0b }, + { 0x56, 0x0f }, + { 0x57, 0x13 }, + { 0x58, 0x03 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_5345; + sensor.optical_res = 1200; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 48; + sensor.dummy_pixel = 16; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10872; + sensor.fau_gain_white_ref = 190; + sensor.gain_white_ref = 190; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x0d }, + { 0x09, 0x0f }, + { 0x0a, 0x11 }, + { 0x0b, 0x13 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x30 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x23 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {2.38, 2.35, 2.34}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_HP2400; + sensor.optical_res = 1200, + sensor.black_pixels = 48; + sensor.dummy_pixel = 15; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10872; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x14 }, + { 0x09, 0x15 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0xbf }, + { 0x17, 0x08 }, + { 0x18, 0x3f }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x0b }, + { 0x53, 0x0f }, + { 0x54, 0x13 }, + { 0x55, 0x17 }, + { 0x56, 0x03 }, + { 0x57, 0x07 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x0e }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {2.1, 2.1, 2.1}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_HP2300; + sensor.optical_res = 600; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 48; + sensor.dummy_pixel = 20; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 5368; + sensor.fau_gain_white_ref = 180; + sensor.gain_white_ref = 180; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x16 }, + { 0x09, 0x00 }, + { 0x0a, 0x01 }, + { 0x0b, 0x03 }, + { 0x16, 0xb7 }, + { 0x17, 0x0a }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x6a }, + { 0x1b, 0x8a }, + { 0x1c, 0x00 }, + { 0x1d, 0x05 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x06 }, + { 0x5c, 0x0b }, + { 0x5d, 0x10 }, + { 0x5e, 0x16 }, + }; + sensor.gamma = {2.1, 2.1, 2.1}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_CANONLIDE35; + sensor.optical_res = 1200; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 87; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10400; + sensor.fau_gain_white_ref = 0; + sensor.gain_white_ref = 0; + sensor.exposure = { 0x0400, 0x0400, 0x0400 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x00 }, + { 0x19, 0x50 }, + { 0x1a, 0x00 }, // TODO: 1a-1d: these do no harm, but may be neccessery for CCD + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x05 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x07 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x3a }, + { 0x59, 0x03 }, + { 0x5a, 0x40 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_XP200; + sensor.optical_res = 600; + sensor.black_pixels = 5; + sensor.dummy_pixel = 38; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 5200; + sensor.fau_gain_white_ref = 200; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1450, 0x0c80, 0x0a28 }; + sensor.custom_regs = { + { 0x08, 0x16 }, + { 0x09, 0x00 }, + { 0x0a, 0x01 }, + { 0x0b, 0x03 }, + { 0x16, 0xb7 }, + { 0x17, 0x0a }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x6a }, + { 0x1b, 0x8a }, + { 0x1c, 0x00 }, + { 0x1d, 0x05 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x06 }, + { 0x5c, 0x0b }, + { 0x5d, 0x10 }, + { 0x5e, 0x16 }, + }; + sensor.gamma = {2.1, 2.1, 2.1}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_HP3670; + sensor.optical_res = 1200; + sensor.black_pixels = 48; + sensor.dummy_pixel = 16; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10872; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x0a }, + { 0x0a, 0x0b }, + { 0x0b, 0x0d }, + { 0x16, 0x33 }, + { 0x17, 0x07 }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0x15 }, + { 0x5b, 0x05 }, + { 0x5c, 0x0a }, + { 0x5d, 0x0f }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_DP665; + sensor.optical_res = 600; + sensor.black_pixels = 27; + sensor.dummy_pixel = 27; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 2496; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1100, 0x1100, 0x1100 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_ROADWARRIOR; + sensor.optical_res = 600; + sensor.black_pixels = 27; + sensor.dummy_pixel = 27; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 5200; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1100, 0x1100, 0x1100 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_DSMOBILE600; + sensor.optical_res = 600; + sensor.black_pixels = 28; + sensor.dummy_pixel = 28; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 5200; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1544, 0x1544, 0x1544 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_XP300; + sensor.optical_res = 600; + sensor.black_pixels = 27; + sensor.dummy_pixel = 27; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10240; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1100, 0x1100, 0x1100 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_DP685; + sensor.optical_res = 600; + sensor.black_pixels = 27; + sensor.dummy_pixel = 27; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 5020; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1100, 0x1100, 0x1100 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_CANONLIDE200; + sensor.optical_res = 4800; + sensor.black_pixels = 87*4; + sensor.dummy_pixel = 16*4; + sensor.CCD_start_xoffset = 320*8; + sensor.sensor_pixels = 5136*8; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x10 }, + { 0x17, 0x08 }, + { 0x18, 0x00 }, + { 0x19, 0xff }, + { 0x1a, 0x34 }, + { 0x1b, 0x00 }, + { 0x1c, 0x02 }, + { 0x1d, 0x04 }, + { 0x52, 0x03 }, + { 0x53, 0x07 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x2a }, + { 0x59, 0xe1 }, + { 0x5a, 0x55 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x41 }, + }; + sensor.gamma = {1.7, 1.7, 1.7}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_CANONLIDE700; + sensor.optical_res = 4800; + sensor.black_pixels = 73*8; // black pixels 73 at 600 dpi + sensor.dummy_pixel = 16*8; + // 384 at 600 dpi + sensor.CCD_start_xoffset = 384*8; + // 8x5570 segments, 5187+1 for rounding + sensor.sensor_pixels = 5188*8; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x10 }, + { 0x17, 0x08 }, + { 0x18, 0x00 }, + { 0x19, 0xff }, + { 0x1a, 0x34 }, + { 0x1b, 0x00 }, + { 0x1c, 0x02 }, + { 0x1d, 0x04 }, + { 0x52, 0x07 }, + { 0x53, 0x03 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x2a }, + { 0x59, 0xe1 }, + { 0x5a, 0x55 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x41 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_CANONLIDE100; + sensor.optical_res = 2400; + sensor.black_pixels = 87*4, /* black pixels */ + sensor.dummy_pixel = 16*4; + sensor.CCD_start_xoffset = 320*4; + sensor.sensor_pixels = 5136*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x01c1, 0x0126, 0x00e5 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x10 }, + { 0x17, 0x08 }, + { 0x18, 0x00 }, + { 0x19, 0x50 }, + { 0x1a, 0x34 }, + { 0x1b, 0x00 }, + { 0x1c, 0x02 }, + { 0x1d, 0x04 }, + { 0x52, 0x03 }, + { 0x53, 0x07 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x2a }, + { 0x59, 0xe1 }, + { 0x5a, 0x55 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x41 }, + }; + sensor.gamma = {1.7, 1.7, 1.7}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_KVSS080; + sensor.optical_res = 600; + sensor.black_pixels = 38; + sensor.dummy_pixel = 38; + sensor.CCD_start_xoffset = 152; + sensor.sensor_pixels = 5376; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.exposure_lperiod = 8000; + sensor.custom_regs = { + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, + { 0x0c, 0x00 }, + { 0x70, 0x01 }, + { 0x71, 0x03 }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x1c }, + { 0x18, 0x00 }, + { 0x19, 0x2a }, + { 0x1a, 0x2c }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x04 }, + { 0x52, 0x0c }, + { 0x53, 0x0f }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x09 }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0xc0 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_G4050; + sensor.optical_res = 4800; + sensor.black_pixels = 50*8; + // 31 at 600 dpi dummy_pixels 58 at 1200 + sensor.dummy_pixel = 58; + sensor.CCD_start_xoffset = 152; + sensor.sensor_pixels = 5360*8; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x2c09, 0x22b8, 0x10f0 }; + sensor.custom_regs = {}; + sensor.gamma = {1.0, 1.0, 1.0}; + + { + struct CustomSensorSettings { + int min_resolution; + int max_resolution; + int exposure_lperiod; + ScanMethod method; + GenesysRegisterSettingSet extra_custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { -1, 600, 8016, ScanMethod::FLATBED, { + { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff }, + { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, + { 0x0c, 0x00 }, + { 0x70, 0x00 }, + { 0x71, 0x02 }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x00 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x08 }, + { 0x52, 0x0b }, + { 0x53, 0x0e }, + { 0x54, 0x11 }, + { 0x55, 0x02 }, + { 0x56, 0x05 }, + { 0x57, 0x08 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + } + }, + { 1200, 1200, 56064, ScanMethod::FLATBED, { + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x01 }, { 0x79, 0xff }, + { 0x7a, 0x00 }, { 0x7b, 0x01 }, { 0x7c, 0xff }, + { 0x0c, 0x20 }, + { 0x70, 0x08 }, + { 0x71, 0x0c }, + { 0x9e, 0xc0 }, + { 0xaa, 0x05 }, + { 0x16, 0x3b }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x38 }, + { 0x1b, 0x10 }, + { 0x1c, 0x00 }, + { 0x1d, 0x08 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0e }, + { 0x57, 0x11 }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + } + }, + { 2400, 2400, 56064, ScanMethod::FLATBED, { + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + { 0x0c, 0x20 }, + { 0x70, 0x08 }, + { 0x71, 0x0a }, + { 0x9e, 0xc0 }, + { 0xaa, 0x05 }, + { 0x16, 0x3b }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x38 }, + { 0x1b, 0x10 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x08 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0e }, + { 0x57, 0x11 }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + } + }, + { 4800, 4800, 42752, ScanMethod::FLATBED, { + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + { 0x0c, 0x21 }, + { 0x70, 0x08 }, + { 0x71, 0x0a }, + { 0x9e, 0xc0 }, + { 0xaa, 0x07 }, + { 0x16, 0x3b }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x38 }, + { 0x1b, 0x10 }, + { 0x1c, 0xc1 }, + { 0x1d, 0x08 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0e }, + { 0x57, 0x11 }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + } + }, + { -1, -1, 15624, ScanMethod::TRANSPARENCY, { + { 0x74, 0x00 }, { 0x75, 0x1c }, { 0x76, 0x7f }, + { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, + { 0x0c, 0x00 }, + { 0x70, 0x00 }, + { 0x71, 0x02 }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x4c }, + { 0x18, 0x01 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x08 }, + { 0x52, 0x0e }, + { 0x53, 0x11 }, + { 0x54, 0x02 }, + { 0x55, 0x05 }, + { 0x56, 0x08 }, + { 0x57, 0x0b }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0xc0 }, + } + } + }; + + auto base_custom_regs = sensor.custom_regs; + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.min_resolution = setting.min_resolution; + sensor.max_resolution = setting.max_resolution; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.method = setting.method; + sensor.custom_regs = base_custom_regs; + sensor.custom_regs.merge(setting.extra_custom_regs); + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_CS4400F; + sensor.optical_res = 4800; + sensor.ccd_size_divisor = 4; + sensor.black_pixels = 50*8; + // 31 at 600 dpi, 58 at 1200 dpi + sensor.dummy_pixel = 20; + sensor.CCD_start_xoffset = 152; + // 5360 max at 600 dpi + sensor.sensor_pixels = 5360*8; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; + sensor.exposure_lperiod = 11640; + sensor.custom_regs = { + { 0x74, 0x00 }, { 0x75, 0xf8 }, { 0x76, 0x38 }, + { 0x77, 0x00 }, { 0x78, 0xfc }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0xa4 }, + { 0x0c, 0x00 }, + { 0x70, 0x00 }, + { 0x71, 0x02 }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + { 0x16, 0x13 }, + { 0x17, 0x0a }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x6b }, + { 0x52, 0x0a }, + { 0x53, 0x0d }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x08 }, + { 0x58, 0x5b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_CS8400F; + sensor.optical_res = 4800; + sensor.black_pixels = 50*8; + // 31 at 600 dpi, 58 at 1200 dpi + sensor.dummy_pixel = 20; + sensor.CCD_start_xoffset = 152; + // 5360 max at 600 dpi + sensor.sensor_pixels = 5360*8; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; + sensor.exposure_lperiod = 7200; + sensor.custom_regs = { + { 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x01 }, { 0x7b, 0xb6 }, { 0x7c, 0xdb }, + { 0x0c, 0x00 }, + { 0x70, 0x01 }, + { 0x71, 0x02 }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x13 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x84 }, + { 0x52, 0x0d }, + { 0x53, 0x10 }, + { 0x54, 0x01 }, + { 0x55, 0x04 }, + { 0x56, 0x07 }, + { 0x57, 0x0a }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_CS8600F; + sensor.optical_res = 4800; + sensor.ccd_size_divisor = 4; + sensor.black_pixels = 31; + sensor.dummy_pixel = 20; + sensor.CCD_start_xoffset = 0; // not used at the moment + // 11372 pixels at 1200 dpi + sensor.sensor_pixels = 11372*4; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; + sensor.custom_regs = {}; + sensor.gamma = {1.0, 1.0, 1.0}; + + { + struct CustomSensorSettings { + int min_resolution; + int max_resolution; + int exposure_lperiod; + ScanMethod method; + GenesysRegisterSettingSet extra_custom_regs; + GenesysRegisterSettingSet custom_fe_regs; + }; + + CustomSensorSettings custom_settings[] = { + { -1, 1200, 24000, ScanMethod::FLATBED, { + { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 }, + { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, + { 0x0c, 0x00 }, + { 0x70, 0x00 }, + { 0x71, 0x02 }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + { 0x16, 0x13 }, + { 0x17, 0x0a }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x6b }, + { 0x52, 0x0c }, + { 0x53, 0x0f }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x09 }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + }, + {}, + }, + { -1, 1200, 24000, ScanMethod::TRANSPARENCY, { + { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 }, + { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, + { 0x0c, 0x00 }, + { 0x70, 0x00 }, + { 0x71, 0x02 }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + { 0x16, 0x13 }, + { 0x17, 0x0a }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x6b }, + { 0x52, 0x0c }, + { 0x53, 0x0f }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x09 }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + }, + {}, + }, + { 2400, 2400, 24000, ScanMethod::TRANSPARENCY, { + { 0x74, 0x03 }, { 0x75, 0xfe }, { 0x76, 0x00 }, + { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, + { 0x0c, 0x00 }, + { 0x70, 0x00 }, + { 0x71, 0x02 }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + { 0x16, 0x13 }, + { 0x17, 0x15 }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x01 }, + { 0x1d, 0x75 }, + { 0x52, 0x0c }, + { 0x53, 0x0f }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x09 }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + }, + {}, + }, + { 4800, 4800, 24000, ScanMethod::TRANSPARENCY, { + { 0x74, 0x03 }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, + { 0x0c, 0x00 }, + { 0x70, 0x0a }, + { 0x71, 0x0c }, + { 0x72, 0x0c }, + { 0x73, 0x0e }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + { 0x16, 0x13 }, + { 0x17, 0x15 }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x61 }, + { 0x1d, 0x75 }, + { 0x52, 0x03 }, + { 0x53, 0x06 }, + { 0x54, 0x09 }, + { 0x55, 0x0c }, + { 0x56, 0x0f }, + { 0x57, 0x00 }, + { 0x58, 0x23 }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + }, + { { 0x03, 0x1f }, + }, + }, + }; + + auto base_custom_regs = sensor.custom_regs; + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.min_resolution = setting.min_resolution; + sensor.max_resolution = setting.max_resolution; + sensor.method = setting.method; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.custom_regs = base_custom_regs; + sensor.custom_regs.merge(setting.extra_custom_regs); + sensor.custom_fe_regs = setting.custom_fe_regs; + s_sensors->push_back(sensor); + } + } + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_HP_N6310; + sensor.optical_res = 2400; + // sensor.ccd_size_divisor = 2; Possibly half CCD, needs checking + sensor.black_pixels = 96; + sensor.dummy_pixel = 26; + sensor.CCD_start_xoffset = 128; + sensor.sensor_pixels = 42720; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x10 }, + { 0x0a, 0x10 }, + { 0x0b, 0x0c }, + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x02 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x08 }, + { 0x52, 0x0b }, + { 0x53, 0x0e }, + { 0x54, 0x11 }, + { 0x55, 0x02 }, + { 0x56, 0x05 }, + { 0x57, 0x08 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x06 }, + { 0x5e, 0x6f }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_CANONLIDE110; + sensor.optical_res = 2400; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 16; + sensor.CCD_start_xoffset = 303; + sensor.sensor_pixels = 5168*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x10 }, + { 0x17, 0x04 }, + { 0x18, 0x00 }, + { 0x19, 0x01 }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x02 }, + { 0x1d, 0x01 }, + { 0x52, 0x00 }, + { 0x53, 0x02 }, + { 0x54, 0x04 }, + { 0x55, 0x06 }, + { 0x56, 0x04 }, + { 0x57, 0x04 }, + { 0x58, 0x04 }, + { 0x59, 0x04 }, + { 0x5a, 0x1a }, + { 0x5b, 0x00 }, + { 0x5c, 0xc0 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {2.1, 2.1, 2.1}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_CANONLIDE120; + sensor.optical_res = 2400; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 16; + sensor.CCD_start_xoffset = 303; + // SEGCNT at 600 DPI by number of segments + sensor.sensor_pixels = 5104*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x15 }, + { 0x17, 0x04 }, + { 0x18, 0x00 }, + { 0x19, 0x01 }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x02 }, + { 0x1d, 0x01 }, + { 0x52, 0x04 }, + { 0x53, 0x06 }, + { 0x54, 0x00 }, + { 0x55, 0x02 }, + { 0x56, 0x04 }, + { 0x57, 0x04 }, + { 0x58, 0x04 }, + { 0x59, 0x04 }, + { 0x5a, 0x3a }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x1f }, + }; + sensor.gamma = {2.1, 2.1, 2.1}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_CANONLIDE210; + sensor.optical_res = 2400; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 16; + sensor.CCD_start_xoffset = 303; + sensor.sensor_pixels = 5168*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x10 }, + { 0x17, 0x04 }, + { 0x18, 0x00 }, + { 0x19, 0x01 }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x02 }, + { 0x1d, 0x01 }, + { 0x52, 0x00 }, + { 0x53, 0x02 }, + { 0x54, 0x04 }, + { 0x55, 0x06 }, + { 0x56, 0x04 }, + { 0x57, 0x04 }, + { 0x58, 0x04 }, + { 0x59, 0x04 }, + { 0x5a, 0x1a }, + { 0x5b, 0x00 }, + { 0x5c, 0xc0 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {2.1, 2.1, 2.1}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_CANONLIDE220; + sensor.optical_res = 2400; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 16; + sensor.CCD_start_xoffset = 303; + sensor.sensor_pixels = 5168*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x10 }, + { 0x17, 0x04 }, + { 0x18, 0x00 }, + { 0x19, 0x01 }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x02 }, + { 0x1d, 0x01 }, + { 0x52, 0x00 }, + { 0x53, 0x02 }, + { 0x54, 0x04 }, + { 0x55, 0x06 }, + { 0x56, 0x04 }, + { 0x57, 0x04 }, + { 0x58, 0x04 }, + { 0x59, 0x04 }, + { 0x5a, 0x1a }, + { 0x5b, 0x00 }, + { 0x5c, 0xc0 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = {2.1, 2.1, 2.1}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_PLUSTEK_3600; + sensor.optical_res = 1200; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 87; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10100; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x0b }, + { 0x18, 0x11 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0xc4 }, + { 0x52, 0x07 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x0a }, + { 0x54, 0x0c }, + { 0x55, 0x00 }, + { 0x56, 0x02 }, + { 0x57, 0x06 }, + { 0x58, 0x22 }, + { 0x59, 0x69 }, + { 0x5a, 0x40 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x02 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_IMG101; + sensor.optical_res = 1200; + sensor.black_pixels = 31; + sensor.dummy_pixel = 31; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10800; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x60 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x8b }, + { 0x16, 0xbb }, + { 0x17, 0x13 }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x34 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x06 }, + { 0x52, 0x02 }, + { 0x53, 0x04 }, + { 0x54, 0x06 }, + { 0x55, 0x08 }, + { 0x56, 0x0a }, + { 0x57, 0x00 }, + { 0x58, 0x59 }, + { 0x59, 0x31 }, + { 0x5a, 0x40 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x1f }, + }; + sensor.gamma = {1.7, 1.7, 1.7}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CCD_PLUSTEK3800; + sensor.optical_res = 1200; + sensor.black_pixels = 31; + sensor.dummy_pixel = 31; + sensor.CCD_start_xoffset = 0; + sensor.sensor_pixels = 10200; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x60 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x8b }, + { 0x16, 0xbb }, + { 0x17, 0x13 }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x34 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x06 }, + { 0x52, 0x02 }, + { 0x53, 0x04 }, + { 0x54, 0x06 }, + { 0x55, 0x08 }, + { 0x56, 0x0a }, + { 0x57, 0x00 }, + { 0x58, 0x59 }, + { 0x59, 0x31 }, + { 0x5a, 0x40 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x1f }, + }; + sensor.gamma = {1.7, 1.7, 1.7}; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = CIS_CANONLIDE80, + sensor.optical_res = 1200; // real hardware limit is 2400 + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 20; + sensor.dummy_pixel = 6; + // tuned to give 3*8 multiple startx coordinate during shading calibration + sensor.CCD_start_xoffset = 34; // 14=>3, 20=>2 + // 10400, too wide=>10288 in shading data 10240~ + // 10208 too short for shading, max shading data = 10240 pixels, endpix-startpix=10208 + sensor.sensor_pixels = 10240; + sensor.fau_gain_white_ref = 150; + sensor.gain_white_ref = 150; + // maps to 0x70-0x73 for GL841 + sensor.exposure = { 0x1000, 0x1000, 0x0500 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x07 }, + { 0x0b, 0x09 }, + { 0x16, 0x00 }, + { 0x17, 0x01 }, + { 0x18, 0x00 }, + { 0x19, 0x06 }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x04 }, + { 0x52, 0x03 }, + { 0x53, 0x07 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x29 }, + { 0x59, 0x69 }, + { 0x5a, 0x55 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x20 }, + { 0x5e, 0x41 }, + }; + sensor.gamma = {1.0, 1.0, 1.0}; + s_sensors->push_back(sensor); +} + +/** for General Purpose Output specific settings: + * initial GPO value (registers 0x66-0x67/0x6c-0x6d) + * GPO enable mask (registers 0x68-0x69/0x6e-0x6f) + * The first register is for GPIO9-GPIO16, the second for GPIO1-GPIO8 + */ +static Genesys_Gpo Gpo[] = { + /* UMAX */ + {GPO_UMAX, + {0x11, 0x00} + , + {0x51, 0x20} + , + } + , + /* Plustek OpticPro S12/ST12 */ + {GPO_ST12, + {0x11, 0x00} + , + {0x51, 0x20} + , + } + , + /* Plustek OpticPro S24/ST24 */ + {GPO_ST24, + {0x00, 0x00} + , + {0x51, 0x20} + , + } + , + /* MD5345/MD6471 */ + {GPO_5345, + {0x30, 0x18} + , /* bits 11-12 are for bipolar V-ref input voltage */ + {0xa0, 0x18} + , + } + , + /* HP2400C */ + {GPO_HP2400, + {0x30, 0x00} + , + {0x31, 0x00} + , + } + , + /* HP2300C */ + {GPO_HP2300, + {0x00, 0x00} + , + {0x00, 0x00} + , + } + , + /* CANONLIDE35 */ + {GPO_CANONLIDE35, + {0x02, 0x80} + , + {0xef, 0x80} + , + } + , + /* 7: XP200 */ + {GPO_XP200, + {0x30, 0x00} + , + {0xb0, 0x00} + , + }, + /* HP3670 */ + {GPO_HP3670, + {0x00, 0x00} + , + {0x00, 0x00} + } + , + /* 8: XP300 */ + {GPO_XP300, + {0x09, 0xc6}, + {0xbb, 0x00}, + } + , + /* Syscan DP 665 */ + { + GPO_DP665, + {0x18, 0x00},/*0x19,0x00*/ + {0xbb, 0x00}, + } + , + /* Syscan DP 685 */ + { + GPO_DP685, + {0x3f, 0x46}, /* 6c, 6d */ + {0xfb, 0x00}, /* 6e, 6f */ + }, + /* CANONLIDE200 */ + {GPO_CANONLIDE200, + {0xfb, 0x20}, /* 0xfb when idle , 0xf9/0xe9 (1200) when scanning */ + {0xff, 0x00}, + }, + /* CANONLIDE700 */ + {GPO_CANONLIDE700, + {0xdb, 0xff}, + {0xff, 0x80}, + }, + {GPO_KVSS080, + {0xf5, 0x20}, + {0x7e, 0xa1}, + } + , + {GPO_G4050, + {0x20, 0x00}, + {0xfc, 0x00}, + } + , + /* HP N6310 */ + {GPO_HP_N6310, + {0xa3, 0x00}, + {0x7f, 0x00}, + } + , + /* CANONLIDE110 */ + {GPO_CANONLIDE110, + {0xfb, 0x20}, + {0xff, 0x00}, + } + , + /* CANONLIDE120 */ + {GPO_CANONLIDE120, + {0xfb, 0x20}, + {0xff, 0x00}, + } + , + /* CANONLIDE210 */ + {GPO_CANONLIDE210, + {0xfb, 0x20}, + {0xff, 0x00}, + } + , + /* Plustek 3600 */ + {GPO_PLUSTEK_3600, + {0x02, 0x00}, + {0x1e, 0x80}, + } + /* CanoScan 4400f */ + , + {GPO_CS4400F, + {0x01, 0x7f}, + {0xff, 0x00}, + } + /* CanoScan 8400f */ + , + {GPO_CS8400F, + {0x9a, 0xdf}, + {0xfe, 0x60}, + } + /* CanoScan 8600F */ + , + { GPO_CS8600F, + { 0x20, 0x7c }, + { 0xff, 0x00 }, + } + /* Canon Image formula 101 */ + , + {GPO_IMG101, + {0x41, 0xa4}, + {0x13, 0xa7} + } + /* Plustek OpticBook 3800 */ + , + {GPO_PLUSTEK3800, + {0x41, 0xa4}, + {0x13, 0xa7} + }, + /* Canon LiDE 80 */ + { + GPO_CANONLIDE80, + {0x28, 0x90}, + {0x75, 0x80}, + } +}; + +static Genesys_Motor Motor[] = { + /* UMAX */ + {MOTOR_UMAX, + 1200, /* motor base steps */ + 2400, /* maximum motor resolution */ + 1, /* maximum step mode */ + 1, /* number of power modes*/ + {{{ + 11000, /* maximum start speed */ + 3000, /* maximum end speed */ + 128, /* step count */ + 1.0, /* nonlinearity */ + }, + { + 11000, + 3000, + 128, + 1.0, + },},}, + }, + {MOTOR_5345, /* MD5345/6228/6471 */ + 1200, + 2400, + 1, + 1, + {{{ + 2000, + 1375, + 128, + 0.5, + }, + { + 2000, + 1375, + 128, + 0.5, + },},}, + }, + {MOTOR_ST24, /* ST24 */ + 2400, + 2400, + 1, + 1, + {{{ + 2289, + 2100, + 128, + 0.3, + }, + { + 2289, + 2100, + 128, + 0.3, + },},}, + }, + {MOTOR_HP3670, /* HP 3670 */ + 1200, + 2400, + 1, + 1, + {{{ + 11000, /* start speed */ + 3000, /* max speed */ + 128, /* min steps */ + 0.25, + }, + { + 11000, + 3000, + 128, + 0.5, + },},}, + }, + {MOTOR_HP2400, /* HP 2400c */ + 1200, + 1200, + 1, + 1, + {{{ + 11000, /* start speed */ + 3000, /* max speed */ + 128, /* min steps */ + 0.25, + }, + { + 11000, + 3000, + 128, + 0.5, + },},}, + }, + {MOTOR_HP2300, /* HP 2300c */ + 600, /* 600/1200 */ + 1200, + 1, + 1, + {{{ + 3200, + 1200, + 128, + 0.5, + }, + { + 3200, + 1200, + 128, + 0.5, + },},}, + }, + {MOTOR_CANONLIDE35, /* Canon LiDE 35 */ + 1200, + 2400, + 1, + 1, + {{{ 3500, 1300, 60, 0.8, }, + { 3500, 1400, 60, 0.8, },},}, + }, + {MOTOR_XP200, /* Strobe XP200 */ + 600, + 600, + 1, + 1, + {{{ + 3500, + 1300, + 60, + 0.25, + }, + { + 3500, + 1400, + 60, + 0.5, + },},}, + }, + {MOTOR_XP300, /* 7: Visioneer Strobe XP300 */ + 300, + 600, + 1, + 1, + {{{ /* works best with GPIO10, GPIO14 off */ + 3700, + 3700, + 2, + 0.8, + }, + { + 11000, + 11000, + 2, + 0.8, + },},}, + }, + {MOTOR_DP665, /* Syscan DP 665 */ + 750, + 1500, + 1, + 1, + {{{ + 3000, + 2500, + 10, + 0.8, + }, + { + 11000, + 11000, + 2, + 0.8, + },},}, + }, + {MOTOR_ROADWARRIOR, /* Visioneer Roadwarrior */ + 750, + 1500, + 1, + 1, + {{{ + 3000, + 2600, + 10, + 0.8, + }, + { + 11000, + 11000, + 2, + 0.8, + },},}, + }, + {MOTOR_DSMOBILE_600, /* Pentax DSmobile 600 */ + 750, + 1500, + 2, + 1, + {{{ + 6666, + 3700, + 8, + 0.8, + }, + { + 6666, + 3700, + 8, + 0.8, + },},}, + }, + {MOTOR_CANONLIDE100, /* Canon LiDE 100 */ + 1200, + 6400, + 2, /* maximum step type count */ + 1, /* maximum power modes count */ + { /* motor slopes */ + { /* power mode 0 */ + { 3000, 1000, 127, 0.50}, /* full step */ + { 3000, 1500, 127, 0.50}, /* half step */ + { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ + }, + }, + }, + {MOTOR_CANONLIDE200, /* Canon LiDE 200 */ + 1200, + 6400, + 2, + 1, + { /* motor slopes */ + { /* power mode 0 */ + { 3000, 1000, 127, 0.50}, /* full step */ + { 3000, 1500, 127, 0.50}, /* half step */ + { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ + }, + }, + }, + {MOTOR_CANONLIDE700, /* Canon LiDE 700 */ + 1200, + 6400, + 2, + 1, + { /* motor slopes */ + { /* power mode 0 */ + { 3000, 1000, 127, 0.50}, /* full step */ + { 3000, 1500, 127, 0.50}, /* half step */ + { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ + }, + }, + }, + {MOTOR_KVSS080, + 1200, + 1200, + 2, + 1, + { /* motor slopes */ + { /* power mode 0 */ + { 22222, 500, 246, 0.5 }, /* max speed / dpi * base dpi => exposure */ + { 22222, 500, 246, 0.5 }, + { 22222, 500, 246, 0.5 }, + }, + }, + }, + {MOTOR_G4050, + 2400, + 9600, + 2, + 1, + { /* motor slopes */ + { /* power mode 0 */ + { 3961, 240, 246, 0.8 }, /* full step */ + { 3961, 240, 246, 0.8 }, /* half step */ + { 3961, 240, 246, 0.8 }, /* quarter step */ + }, + }, + }, + {MOTOR_CS8400F, + 2400, + 9600, + 2, + 1, + { /* motor slopes */ + { /* power mode 0 */ + { 3961, 240, 246, 0.8 }, /* full step */ + { 3961, 240, 246, 0.8 }, /* half step */ + { 3961, 240, 246, 0.8 }, /* quarter step */ + }, + }, + }, + { + MOTOR_CS8600F, + 2400, + 9600, + 2, + 1, + { /* motor slopes */ + { /* power mode 0 */ + { 3961, 240, 246, 0.8 }, /* full step */ + { 3961, 240, 246, 0.8 }, /* half step */ + { 3961, 240, 246, 0.8 }, /* quarter step */ + }, + }, + }, + {MOTOR_CANONLIDE110, /* Canon LiDE 110 */ + 4800, + 9600, + 1, /* maximum step type count */ + 1, /* maximum power modes count */ + { /* motor slopes */ + { /* power mode 0 */ + { 3000, 1000, 256, 0.50}, /* full step */ + }, + }, + }, + {MOTOR_CANONLIDE120, /* Canon LiDE 120 */ + 4800, + 9600, + 1, /* maximum step type count */ + 1, /* maximum power modes count */ + { /* motor slopes */ + { /* power mode 0 */ + { 3000, 1000, 256, 0.50}, /* full step */ + }, + }, + }, + {MOTOR_CANONLIDE210, /* Canon LiDE 210 */ + 4800, + 9600, + 1, /* maximum step type count */ + 1, /* maximum power modes count */ + { /* motor slopes */ + { /* power mode 0 */ + { 3000, 1000, 256, 0.50}, /* full step */ + }, + }, + }, + {MOTOR_PLUSTEK_3600, /* PLUSTEK 3600 */ + 1200, + 2400, + 1, + 1, + { + { + { 3500, 1300, 60, 0.8 }, + { 3500, 3250, 60, 0.8 }, + }, + },}, + {MOTOR_IMG101, /* Canon Image Formula 101 */ + 600, + 1200, + 1, + 1, + { + { + { 3500, 1300, 60, 0.8 }, + { 3500, 3250, 60, 0.8 }, + }, + },}, + {MOTOR_PLUSTEK3800, /* Plustek OpticBook 3800 */ + 600, + 1200, + 1, + 1, + { + { + { 3500, 1300, 60, 0.8 }, + { 3500, 3250, 60, 0.8 }, + }, + },}, + {MOTOR_CANONLIDE80, + 2400, /* 2400 ???? */ + 4800, /* 9600 ???? */ + 1, /* max step type */ + 1, /* power mode count */ + { + { /* start speed, max end speed, step number */ + /* maximum speed (second field) is used to compute exposure as seen by motor */ + /* exposure=max speed/ slope dpi * base dpi */ + /* 5144 = max pixels at 600 dpi */ + /* 1288=(5144+8)*ydpi(=300)/base_dpi(=1200) , where 5152 is exposure */ + /* 6440=9660/(1932/1288) */ + { 9560, 1912, 31, 0.8 }, + }, + },}, +}; + +/* here we have the various device settings... + */ +static Genesys_Model umax_astra_4500_model = { + "umax-astra-4500", /* Name */ + "UMAX", /* Device vendor string */ + "Astra 4500", /* Device model name */ + MODEL_UMAX_ASTRA_4500, + GENESYS_GL646, + NULL, + + {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (3.5), /* Start of scan area in mm (x) */ + SANE_FIX (7.5), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_UMAX, + DAC_WOLFSON_UMAX, + GPO_UMAX, + MOTOR_UMAX, + GENESYS_FLAG_UNTESTED, /* Which flags are needed for this scanner? */ + /* untested, values set by hmg */ + GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ + 20, + 0, // shading_ta_lines + 200 +}; + +static Genesys_Model canon_lide_50_model = { + "canon-lide-50", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 35/40/50", /* Device model name */ + MODEL_CANON_LIDE_50, + GENESYS_GL841, + NULL, + + { 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.42), /* Start of scan area in mm (x) */ + SANE_FIX (7.9), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (6.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_CANONLIDE35, + DAC_CANONLIDE35, + GPO_CANONLIDE35, + MOTOR_CANONLIDE35, + GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_WHITE_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | + GENESYS_HAS_FILE_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_COPY_SW, + 280, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model panasonic_kvss080_model = { + "panasonic-kv-ss080", /* Name */ + "Panasonic", /* Device vendor string */ + "KV-SS080", /* Device model name */ + MODEL_PANASONIC_KV_SS080, + GENESYS_GL843, + NULL, + + { 600, /* 500, 400,*/ 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + { 1200, 600, /* 500, 400, */ 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (7.2), /* Start of scan area in mm (x) */ + SANE_FIX (14.7), /* Start of scan area in mm (y) */ + SANE_FIX (217.7), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ + + SANE_FIX (9.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_KVSS080, + DAC_KVSS080, + GPO_KVSS080, + MOTOR_KVSS080, + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW , + 100, + 0, // shading_ta_lines + 100 +}; + +static Genesys_Model hp4850c_model = { + "hewlett-packard-scanjet-4850c", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet 4850C", /* Device model name */ + MODEL_HP_SCANJET_4850C, + GENESYS_GL843, + NULL, + + {2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + {2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (7.9), /* Start of scan area in mm (x) */ + SANE_FIX (5.9), /* Start of scan area in mm (y) */ + SANE_FIX (219.6), /* Size of scan area in mm (x) */ + SANE_FIX (314.5), /* Size of scan area in mm (y) */ + + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_G4050, + DAC_G4050, + GPO_G4050, + MOTOR_G4050, + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_STAGGERED_LINE | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, + 100, + 0, // shading_ta_lines + 100 +}; + +static Genesys_Model hpg4010_model = { + "hewlett-packard-scanjet-g4010", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet G4010", /* Device model name */ + MODEL_HP_SCANJET_G4010, + GENESYS_GL843, + NULL, + + { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (8.0), /* Start of scan area in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (315.0), /* Size of scan area in mm (y) */ + + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_G4050, + DAC_G4050, + GPO_G4050, + MOTOR_G4050, + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_STAGGERED_LINE | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, + 100, + 0, // shading_ta_lines + 100 +}; + +static Genesys_Model hpg4050_model = { + "hewlett-packard-scanjet-g4050", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet G4050", /* Device model name */ + MODEL_HP_SCANJET_G4050, + GENESYS_GL843, + NULL, + + { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (8.0), /* Start of scan area in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (315.0), /* Size of scan area in mm (y) */ + + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_G4050, + DAC_G4050, + GPO_G4050, + MOTOR_G4050, + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_STAGGERED_LINE | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, + 100, + 0, // shading_ta_lines + 100 +}; + + +static Genesys_Model canon_4400f_model = { + "canon-canoscan-4400f", /* Name */ + "Canon", /* Device vendor string */ + "Canoscan 4400f", /* Device model name */ + MODEL_CANON_CANOSCAN_4400F, + GENESYS_GL843, + NULL, + + { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (6.0), /* Start of scan area in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (315.0), /* Size of scan area in mm (y) */ + + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_CS4400F, + DAC_G4050, + GPO_CS4400F, + MOTOR_G4050, + GENESYS_FLAG_NO_CALIBRATION | + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_STAGGERED_LINE | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_FULL_HWDPI_MODE | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, + 100, + 0, // shading_ta_lines + 100 +}; + + +static Genesys_Model canon_8400f_model = { + "canon-canoscan-8400f", /* Name */ + "Canon", /* Device vendor string */ + "Canoscan 8400f", /* Device model name */ + MODEL_CANON_CANOSCAN_8400F, + GENESYS_GL843, + NULL, + + { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (4.0), /* Start of scan area in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (315.0), /* Size of scan area in mm (y) */ + + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in line number */ + /* 0 38 76 OK 1200/2400 */ + /* 0 24 48 OK [100,600] dpi */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_CS8400F, + DAC_CS8400F, + GPO_CS8400F, + MOTOR_CS8400F, + GENESYS_FLAG_NO_CALIBRATION | + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_STAGGERED_LINE | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_FULL_HWDPI_MODE | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, + 100, + 0, // shading_ta_lines + 100 +}; + + +static Genesys_Model canon_8600f_model = { + "canon-canoscan-8600f", // name + "Canon", // Device vendor string + "Canoscan 8600f", // Device model name + MODEL_CANON_CANOSCAN_8600F, + GENESYS_GL843, // ASIC type + NULL, + + { 4800, 2400, 1200, 600, 400, 300, 0}, // TODO: resolutions for non-XPA mode + { 4800, 2400, 1200, 600, 400, 300, 0}, // TODO: resolutions for non-XPA mode + { 16, 8, 0 }, // possible depths in gray mode + { 16, 8, 0 }, // possible depths in color mode + + SANE_FIX(24.0), // Start of scan area in mm (x) + SANE_FIX(10.0), // Start of scan area in mm (y) + SANE_FIX(216.0), // Size of scan area in mm (x) + SANE_FIX(297.0), // Size of scan area in mm (y) + + SANE_FIX(0.0), // Start of white strip in mm (y) + SANE_FIX(8.0), // Start of black mark in mm (x) + + SANE_FIX(95.0), // x_offset_ta + SANE_FIX(26.0), // y_offset_ta + SANE_FIX(70.0), // x_size_ta + SANE_FIX(230.0), // y_size_ta + + SANE_FIX(12.5), // y_offset_calib + + SANE_FIX(0.0), // Size of scan area after paper sensor stops + // sensing document in mm + SANE_FIX(0.0), // Amount of feeding needed to eject document + // after finishing scanning in mm + + 0, 48, 96, // RGB CCD Line-distance correction in line number + + COLOR_ORDER_RGB, // Order of the CCD/CIS colors + + SANE_FALSE, // Is this a CIS scanner? + SANE_FALSE, // Is this a sheetfed scanner? + CCD_CS8600F, + DAC_CS8600F, + GPO_CS8600F, + MOTOR_CS8600F, + GENESYS_FLAG_HAS_UTA | + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_STAGGERED_LINE | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_FULL_HWDPI_MODE | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SHADING_REPARK, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, + 50, // shading_lines + 50, // shading_ta_lines + 100 +}; + + +static Genesys_Model canon_lide_100_model = { + "canon-lide-100", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 100", /* Device model name */ + MODEL_CANON_LIDE_100, + GENESYS_GL847, + NULL, + + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (1.1), /* Start of scan area in mm (x) */ + SANE_FIX (8.3), /* Start of scan area in mm (y) */ + SANE_FIX (216.07), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (1.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE100, + DAC_CANONLIDE200, + GPO_CANONLIDE200, + MOTOR_CANONLIDE100, + /* Which flags are needed for this scanner? */ + GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_SIS_SENSOR + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_SHADING_REPARK + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, + 50, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model canon_lide_110_model = { + "canon-lide-110", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 110", /* Device model name */ + MODEL_CANON_LIDE_110, + GENESYS_GL124, + NULL, + + {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (2.2), /* Start of scan area in mm (x) */ + SANE_FIX (9.0), /* Start of scan area in mm (y) */ + SANE_FIX (216.70), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ + + SANE_FIX (1.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE110, + DAC_CANONLIDE110, + GPO_CANONLIDE110, + MOTOR_CANONLIDE110, + GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_SHADING_REPARK + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, + 50, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model canon_lide_120_model = { + "canon-lide-120", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 120", /* Device model name */ + MODEL_CANON_LIDE_120, + GENESYS_GL124, + NULL, + + {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (8.0), /* Start of scan area in mm (y) */ + SANE_FIX (216.0), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ + + SANE_FIX (1.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE120, + DAC_CANONLIDE120, + GPO_CANONLIDE120, + MOTOR_CANONLIDE120, + GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_SHADING_REPARK + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, + 50, + 0, // shading_ta_lines + 400 +}; + + +static Genesys_Model canon_lide_210_model = { + "canon-lide-210", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 210", /* Device model name */ + MODEL_CANON_LIDE_210, + GENESYS_GL124, + NULL, + + {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (2.2), /* Start of scan area in mm (x) */ + SANE_FIX (8.7), /* Start of scan area in mm (y) */ + SANE_FIX (216.70), /* Size of scan area in mm (x) */ + SANE_FIX (297.5), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE210, + DAC_CANONLIDE110, + GPO_CANONLIDE210, + MOTOR_CANONLIDE210, + GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_SHADING_REPARK + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_EXTRA_SW, + 60, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model canon_lide_220_model = { + "canon-lide-220", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 220", /* Device model name */ + MODEL_CANON_LIDE_220, + GENESYS_GL124, /* or a compatible one */ + NULL, + + {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (2.2), /* Start of scan area in mm (x) */ + SANE_FIX (8.7), /* Start of scan area in mm (y) */ + SANE_FIX (216.70), /* Size of scan area in mm (x) */ + SANE_FIX (297.5), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE220, + DAC_CANONLIDE110, + GPO_CANONLIDE210, + MOTOR_CANONLIDE210, + GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_SHADING_REPARK + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_EXTRA_SW, + 60, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model canon_5600f_model = { + "canon-5600f", /* Name */ + "Canon", /* Device vendor string */ + "5600F", /* Device model name */ + MODEL_CANON_CANOSCAN_5600F, + GENESYS_GL847, + NULL, + + {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (1.1), /* Start of scan area in mm (x) */ + SANE_FIX (8.3), /* Start of scan area in mm (y) */ + SANE_FIX (216.07), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE200, + DAC_CANONLIDE200, + GPO_CANONLIDE200, + MOTOR_CANONLIDE200, + GENESYS_FLAG_UNTESTED /* not working yet */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_SIS_SENSOR + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, + 50, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model canon_lide_700f_model = { + "canon-lide-700f", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 700F", /* Device model name */ + MODEL_CANON_LIDE_700F, + GENESYS_GL847, + NULL, + + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (3.1), /* Start of scan area in mm (x) */ + SANE_FIX (8.1), /* Start of scan area in mm (y) */ + SANE_FIX (216.07), /* Size of scan area in mm (x) */ + SANE_FIX (297.0), /* Size of scan area in mm (y) */ + + SANE_FIX (1.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE700, + DAC_CANONLIDE700, + GPO_CANONLIDE700, + MOTOR_CANONLIDE700, + GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_SIS_SENSOR + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_SHADING_REPARK + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, + 70, + 0, // shading_ta_lines + 400 +}; + + + +static Genesys_Model canon_lide_200_model = { + "canon-lide-200", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 200", /* Device model name */ + MODEL_CANON_LIDE_200, + GENESYS_GL847, + NULL, + + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (1.1), /* Start of scan area in mm (x) */ + SANE_FIX (8.3), /* Start of scan area in mm (y) */ + SANE_FIX (216.07), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE200, + DAC_CANONLIDE200, + GPO_CANONLIDE200, + MOTOR_CANONLIDE200, + GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_SIS_SENSOR + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_SHADING_REPARK + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, + 50, + 0, // shading_ta_lines + 400 +}; + + +static Genesys_Model canon_lide_60_model = { + "canon-lide-60", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 60", /* Device model name */ + MODEL_CANON_LIDE_60, + GENESYS_GL841, + NULL, + + {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.42), /* Start of scan area in mm (x) */ + SANE_FIX (7.9), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (6.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_CANONLIDE35, + DAC_CANONLIDE35, + GPO_CANONLIDE35, + MOTOR_CANONLIDE35, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_WHITE_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA, + + GENESYS_HAS_COPY_SW /* Has four buttons: COPY, SCAN, PDF, EMAIL */ + | GENESYS_HAS_SCAN_SW + | GENESYS_HAS_FILE_SW + | GENESYS_HAS_EMAIL_SW, + 300, + 0, // shading_ta_lines + 400 +}; /* this is completely untested -- hmg */ + +static Genesys_Model canon_lide_80_model = { + "canon-lide-80", /* Name */ + "Canon", /* Device vendor string */ + "LiDE 80", /* Device model name */ + MODEL_CANON_LIDE_80, + GENESYS_GL841, + NULL, + + { 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + SANE_FIX (0.42), /* Start of scan area in mm (x) 0.42 */ + SANE_FIX (7.90), /* Start of scan area in mm (y) 7.90 */ + SANE_FIX (216.07), /* Size of scan area in mm (x) 218.00 */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (4.5), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CIS_CANONLIDE80, + DAC_CANONLIDE80, + GPO_CANONLIDE80, + MOTOR_CANONLIDE80, + GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_WHITE_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | + GENESYS_HAS_FILE_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_COPY_SW, + 160, /* 280 @2400 */ + 0, // shading_ta_lines + 400 +}; + + +static Genesys_Model hp2300c_model = { + "hewlett-packard-scanjet-2300c", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet 2300c", /* Device model name */ + MODEL_HP_SCANJET_2300C, + GENESYS_GL646, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions, motor can go up to 1200 dpi */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (2.0), /* Start of scan area in mm (x_offset) */ + SANE_FIX (7.5), /* Start of scan area in mm (y_offset) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (295.0), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 16, 8, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_HP2300, + DAC_WOLFSON_HP2300, + GPO_HP2300, + MOTOR_HP2300, + GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_SEARCH_START + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW, + 40, + 0, // shading_ta_lines + 132 +}; + +static +Genesys_Model hp2400c_model = { + "hewlett-packard-scanjet-2400c", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet 2400c", /* Device model name */ + MODEL_HP_SCANJET_2400C, + GENESYS_GL646, + NULL, + + {1200, 600, 300, 150, 100, 50, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 100, 50, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (6.5), /* Start of scan area in mm (x) */ + SANE_FIX (2.5), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (297.2), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_HP2400, + DAC_WOLFSON_HP2400, + GPO_HP2400, + MOTOR_HP2400, + GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_STAGGERED_LINE + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW, + 20, + 0, // shading_ta_lines + 132 +}; + +static +Genesys_Model visioneer_xp200_model = { + "visioneer-strobe-xp200", /* Name */ + "Visioneer", /* Device vendor string */ + "Strobe XP200", /* Device model name */ + MODEL_VISIONEER_STROBE_XP200, + GENESYS_GL646, + NULL, + + {600, 300, 200, 100, 75, 0}, /* possible x-resolutions */ + {600, 300, 200, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.5), /* Start of scan area in mm (x) */ + SANE_FIX (16.0), /* Start of scan area in mm (y) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (297.2), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CIS_XP200, + DAC_AD_XP200, /* Analog Device frontend */ + GPO_XP200, + MOTOR_XP200, + GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 120, + 0, // shading_ta_lines + 132 +}; + +static Genesys_Model hp3670c_model = { + "hewlett-packard-scanjet-3670c", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet 3670c", /* Device model name */ + MODEL_HP_SCANJET_3670C, + GENESYS_GL646, + NULL, + + {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (8.5), /* Start of scan area in mm (x) */ + SANE_FIX (11.0), /* Start of scan area in mm (y) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ + + SANE_FIX (104.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (55.6), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (25.6), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (78.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (76.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_HP3670, + DAC_WOLFSON_HP3670, + GPO_HP3670, + MOTOR_HP3670, + GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_XPA + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_STAGGERED_LINE + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW, + 20, + 0, // shading_ta_lines + 200 +}; + +static Genesys_Model plustek_st12_model = { + "plustek-opticpro-st12", /* Name */ + "Plustek", /* Device vendor string */ + "OpticPro ST12", /* Device model name */ + MODEL_PLUSTEK_OPTICPRO_ST12, + GENESYS_GL646, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (3.5), /* Start of scan area in mm (x) */ + SANE_FIX (7.5), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_ST12, + DAC_WOLFSON_ST12, + GPO_ST12, + MOTOR_UMAX, + GENESYS_FLAG_UNTESTED | GENESYS_FLAG_14BIT_GAMMA, /* Which flags are needed for this scanner? */ + GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ + 20, + 0, // shading_ta_lines + 200 +}; + +static Genesys_Model plustek_st24_model = { + "plustek-opticpro-st24", /* Name */ + "Plustek", /* Device vendor string */ + "OpticPro ST24", /* Device model name */ + MODEL_PLUSTEK_OPTICPRO_ST24, + GENESYS_GL646, + NULL, + + {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (3.5), /* Start of scan area in mm (x) */ + SANE_FIX (7.5), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (299.0), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (1.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_ST24, + DAC_WOLFSON_ST24, + GPO_ST24, + MOTOR_ST24, + GENESYS_FLAG_UNTESTED + | GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_SEARCH_START + | GENESYS_FLAG_OFFSET_CALIBRATION, + GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ + 20, + 0, // shading_ta_lines + 200 +}; + +static Genesys_Model medion_md5345_model = { + "medion-md5345-model", /* Name */ + "Medion", /* Device vendor string */ + "MD5345/MD6228/MD6471", /* Device model name */ + MODEL_MEDION_MD5345, + GENESYS_GL646, + NULL, + + {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX ( 0.30), /* Start of scan area in mm (x) */ + SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (296.4), /* Size of scan area in mm (y) */ + + SANE_FIX (0.00), /* Start of white strip in mm (y) */ + SANE_FIX (0.00), /* Start of black mark in mm (x) */ + + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_5345, + DAC_WOLFSON_5345, + GPO_5345, + MOTOR_5345, + GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_SEARCH_START + | GENESYS_FLAG_STAGGERED_LINE + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_SHADING_NO_MOVE + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, + 40, + 0, // shading_ta_lines + 200 +}; + +static Genesys_Model visioneer_xp300_model = { + "visioneer-strobe-xp300", /* Name */ + "Visioneer", /* Device vendor string */ + "Strobe XP300", /* Device model name */ + MODEL_VISIONEER_STROBE_XP300, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (1.0), /* Start of scan area in mm (y) */ + SANE_FIX (435.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (26.5), /* Size of scan area after paper sensor stops + sensing document in mm */ + /* this is larger than needed -- accounts for second sensor head, which is a + calibration item */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_XP300, + DAC_WOLFSON_XP300, + GPO_XP300, + MOTOR_XP300, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model syscan_docketport_665_model = { + "syscan-docketport-665", /* Name */ + "Syscan/Ambir", /* Device vendor string */ + "DocketPORT 665", /* Device model name */ + MODEL_SYSCAN_DOCKETPORT_665, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (108.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (17.5), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_DP665, + DAC_WOLFSON_XP300, + GPO_DP665, + MOTOR_DP665, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model visioneer_roadwarrior_model = { + "visioneer-roadwarrior", /* Name */ + "Visioneer", /* Device vendor string */ + "Readwarrior", /* Device model name */ + MODEL_VISIONEER_ROADWARRIOR, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (16.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_ROADWARRIOR, + DAC_WOLFSON_XP300, + GPO_DP665, + MOTOR_ROADWARRIOR, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model syscan_docketport_465_model = { + "syscan-docketport-465", /* Name */ + "Syscan", /* Device vendor string */ + "DocketPORT 465", /* Device model name */ + MODEL_SYSCAN_DOCKETPORT_465, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (16.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_ROADWARRIOR, + DAC_WOLFSON_XP300, + GPO_DP665, + MOTOR_ROADWARRIOR, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_NO_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_UNTESTED, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW, + 300, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model visioneer_xp100_r3_model = { + "visioneer-xp100-revision3", /* Name */ + "Visioneer", /* Device vendor string */ + "XP100 Revision 3", /* Device model name */ + MODEL_VISIONEER_STROBE_XP100_REVISION3, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (16.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_ROADWARRIOR, + DAC_WOLFSON_XP300, + GPO_DP665, + MOTOR_ROADWARRIOR, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model pentax_dsmobile_600_model = { + "pentax-dsmobile-600", /* Name */ + "Pentax", /* Device vendor string */ + "DSmobile 600", /* Device model name */ + MODEL_PENTAX_DSMOBILE_600, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (16.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_DSMOBILE600, + DAC_WOLFSON_DSM600, + GPO_DP665, + MOTOR_DSMOBILE_600, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model syscan_docketport_467_model = { + "syscan-docketport-467", /* Name */ + "Syscan", /* Device vendor string */ + "DocketPORT 467", /* Device model name */ + MODEL_SYSCAN_DOCKETPORT_467, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (16.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_DSMOBILE600, + DAC_WOLFSON_DSM600, + GPO_DP665, + MOTOR_DSMOBILE_600, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model syscan_docketport_685_model = { + "syscan-docketport-685", /* Name */ + "Syscan/Ambir", /* Device vendor string */ + "DocketPORT 685", /* Device model name */ + MODEL_SYSCAN_DOCKETPORT_685, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (1.0), /* Start of scan area in mm (y) */ + SANE_FIX (212.0), /* Size of scan area in mm (x) */ + SANE_FIX (500), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (26.5), /* Size of scan area after paper sensor stops + sensing document in mm */ + /* this is larger than needed -- accounts for second sensor head, which is a + calibration item */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_DP685, + DAC_WOLFSON_DSM600, + GPO_DP685, + MOTOR_XP300, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model syscan_docketport_485_model = { + "syscan-docketport-485", /* Name */ + "Syscan/Ambir", /* Device vendor string */ + "DocketPORT 485", /* Device model name */ + MODEL_SYSCAN_DOCKETPORT_485, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (1.0), /* Start of scan area in mm (y) */ + SANE_FIX (435.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (26.5), /* Size of scan area after paper sensor stops + sensing document in mm */ + /* this is larger than needed -- accounts for second sensor head, which is a + calibration item */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_XP300, + DAC_WOLFSON_XP300, + GPO_XP300, + MOTOR_XP300, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model dct_docketport_487_model = { + "dct-docketport-487", /* Name */ + "DCT", /* Device vendor string */ + "DocketPORT 487", /* Device model name */ + MODEL_DCT_DOCKETPORT_487, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.0), /* Start of scan area in mm (x) */ + SANE_FIX (1.0), /* Start of scan area in mm (y) */ + SANE_FIX (435.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (26.5), /* Size of scan area after paper sensor stops + sensing document in mm */ + /* this is larger than needed -- accounts for second sensor head, which is a + calibration item */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_XP300, + DAC_WOLFSON_XP300, + GPO_XP300, + MOTOR_XP300, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_UNTESTED, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model visioneer_7100_model = { + "visioneer-7100-model", /* Name */ + "Visioneer", /* Device vendor string */ + "OneTouch 7100", /* Device model name */ + MODEL_VISIONEER_7100, + GENESYS_GL646, + NULL, + + {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ + SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (296.4), /* Size of scan area in mm (y) */ + + SANE_FIX (0.00), /* Start of white strip in mm (y) */ + SANE_FIX (0.00), /* Start of black mark in mm (x) */ + + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ +/* 48, 24, 0, */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_5345, + DAC_WOLFSON_5345, + GPO_5345, + MOTOR_5345, + GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_SEARCH_START + | GENESYS_FLAG_STAGGERED_LINE + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, + 40, + 0, // shading_ta_lines + 200 +}; + +static Genesys_Model xerox_2400_model = { + "xerox-2400-model", /* Name */ + "Xerox", /* Device vendor string */ + "OneTouch 2400", /* Device model name */ + MODEL_XEROX_2400, + GENESYS_GL646, + NULL, + + {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ + {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ + SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ + SANE_FIX (215.9), /* Size of scan area in mm (x) */ + SANE_FIX (296.4), /* Size of scan area in mm (y) */ + + SANE_FIX (0.00), /* Start of white strip in mm (y) */ + SANE_FIX (0.00), /* Start of black mark in mm (x) */ + + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ +/* 48, 24, 0, */ + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_5345, + DAC_WOLFSON_5345, + GPO_5345, + MOTOR_5345, + GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_SEARCH_START + | GENESYS_FLAG_STAGGERED_LINE + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, + 40, + 0, // shading_ta_lines + 200 +}; + + +static Genesys_Model xerox_travelscanner_model = { + "xerox-travelscanner", /* Name */ + "Xerox", /* Device vendor string */ + "Travelscanner 100", /* Device model name */ + MODEL_XEROX_TRAVELSCANNER_100, + GENESYS_GL841, + NULL, + + {600, 300, 150, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (4.0), /* Start of scan area in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in mm (y) */ + SANE_FIX (220.0), /* Size of scan area in mm (x) */ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (16.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_TRUE, /* Is this a CIS scanner? */ + SANE_TRUE, /* Is this a sheetfed scanner? */ + CCD_ROADWARRIOR, + DAC_WOLFSON_XP300, + GPO_DP665, + MOTOR_ROADWARRIOR, + GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION, + GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, + 100, + 0, // shading_ta_lines + 400 +}; + +static Genesys_Model plustek_3600_model = { + "plustek-opticbook-3600", /* Name */ + "PLUSTEK", /* Device vendor string */ + "OpticBook 3600", /* Device model name */ + MODEL_PLUSTEK_OPTICPRO_3600, + GENESYS_GL841, + NULL, + {/*1200,*/ 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ + {/*2400,*/ 1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (0.42),/*SANE_FIX (0.42), Start of scan area in mm (x) */ + SANE_FIX (6.75),/*SANE_FIX (7.9), Start of scan area in mm (y) */ + SANE_FIX (216.0),/*SANE_FIX (216.0), Size of scan area in mm (x) */ + SANE_FIX (297.0),/*SANE_FIX (297.0), Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_PLUSTEK_3600, + DAC_PLUSTEK_3600, + GPO_PLUSTEK_3600, + MOTOR_PLUSTEK_3600, + GENESYS_FLAG_UNTESTED /* not fully working yet */ + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_LAZY_INIT,/* + | GENESYS_FLAG_NO_CALIBRATION,*/ + GENESYS_HAS_NO_BUTTONS, + 7, + 0, // shading_ta_lines + 200 +}; + +static Genesys_Model hpn6310_model = { + "hewlett-packard-scanjet-N6310", /* Name */ + "Hewlett Packard", /* Device vendor string */ + "ScanJet N6310", /* Device model name */ + MODEL_HP_SCANJET_N6310, + GENESYS_GL847, + NULL, + + { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 0}, + { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 0}, + + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (6), /* Start of scan area in mm (x) */ + SANE_FIX (2), /* Start of scan area in mm (y) */ + SANE_FIX (216), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ + SANE_FIX (511), /* Size of scan area in mm (y) */ + + SANE_FIX (3.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_HP_N6310, + DAC_CANONLIDE200, /*Not defined yet for N6310 */ + GPO_HP_N6310, + MOTOR_CANONLIDE200, /*Not defined yet for N6310 */ + GENESYS_FLAG_UNTESTED /* not fully working yet */ + | GENESYS_FLAG_LAZY_INIT + | GENESYS_FLAG_14BIT_GAMMA + | GENESYS_FLAG_DARK_CALIBRATION + | GENESYS_FLAG_OFFSET_CALIBRATION + | GENESYS_FLAG_CUSTOM_GAMMA + | GENESYS_FLAG_SKIP_WARMUP + | GENESYS_FLAG_NO_CALIBRATION, + + GENESYS_HAS_NO_BUTTONS, + 100, + 0, // shading_ta_lines + 100 +}; + + +static Genesys_Model plustek_3800_model = { + "plustek-opticbook-3800", /* Name */ + "PLUSTEK", /* Device vendor string */ + "OpticBook 3800", /* Device model name */ + MODEL_PLUSTEK_OPTICBOOK_3800, + GENESYS_GL845, + NULL, + + {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (7.2), /* Start of scan area in mm (x) */ + SANE_FIX (14.7), /* Start of scan area in mm (y) */ + SANE_FIX (217.7), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ + + SANE_FIX (9.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_PLUSTEK3800, + DAC_PLUSTEK3800, + GPO_PLUSTEK3800, + MOTOR_PLUSTEK3800, + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_NO_BUTTONS, /* TODO there are 4 buttons to support */ + 100, + 0, // shading_ta_lines + 100 +}; + + +static Genesys_Model canon_formula101_model = { + "canon-image-formula-101", /* Name */ + "Canon", /* Device vendor string */ + "Image Formula 101", /* Device model name */ + MODEL_CANON_IMAGE_FORMULA_101, + GENESYS_GL846, + NULL, + + {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (7.2), /* Start of scan area in mm (x) */ + SANE_FIX (14.7), /* Start of scan area in mm (y) */ + SANE_FIX (217.7), /* Size of scan area in mm (x) */ + SANE_FIX (300.0), /* Size of scan area in mm (y) */ + + SANE_FIX (9.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Size of scan area after paper sensor stops + sensing document in mm */ + SANE_FIX (0.0), /* Amount of feeding needed to eject document + after finishing scanning in mm */ + + 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + + SANE_FALSE, /* Is this a CIS scanner? */ + SANE_FALSE, /* Is this a sheetfed scanner? */ + CCD_IMG101, + DAC_IMG101, + GPO_IMG101, + MOTOR_IMG101, + GENESYS_FLAG_LAZY_INIT | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA, + GENESYS_HAS_NO_BUTTONS , + 100, + 0, // shading_ta_lines + 100 +}; + + +static Genesys_USB_Device_Entry genesys_usb_device_list[] = { + /* GL646 devices */ + {0x03f0, 0x0901, &hp2300c_model}, + {0x03f0, 0x0a01, &hp2400c_model}, + {0x03f0, 0x1405, &hp3670c_model}, + {0x0461, 0x0377, &medion_md5345_model}, + {0x04a7, 0x0229, &visioneer_7100_model}, + {0x0461, 0x038b, &xerox_2400_model}, + {0x04a7, 0x0426, &visioneer_xp200_model}, + {0x0638, 0x0a10, &umax_astra_4500_model}, + {0x07b3, 0x0600, &plustek_st12_model}, + {0x07b3, 0x0601, &plustek_st24_model}, + /* GL841 devices */ + {0x04a7, 0x0474, &visioneer_xp300_model}, + {0x04a7, 0x0494, &visioneer_roadwarrior_model}, + {0x04a7, 0x049b, &visioneer_xp100_r3_model}, + {0x04a7, 0x04ac, &xerox_travelscanner_model}, + {0x04a9, 0x2213, &canon_lide_50_model}, + {0x04a9, 0x221c, &canon_lide_60_model}, + {0x04a9, 0x2214, &canon_lide_80_model}, + {0x07b3, 0x0900, &plustek_3600_model}, + {0x0a17, 0x3210, &pentax_dsmobile_600_model}, + {0x04f9, 0x2038, &pentax_dsmobile_600_model}, /* clone, only usb id is different */ + {0x0a82, 0x4800, &syscan_docketport_485_model}, + {0x0a82, 0x4802, &syscan_docketport_465_model}, + {0x0a82, 0x4803, &syscan_docketport_665_model}, + {0x0a82, 0x480c, &syscan_docketport_685_model}, + {0x1dcc, 0x4810, &dct_docketport_487_model}, + {0x1dcc, 0x4812, &syscan_docketport_467_model}, + /* GL843 devices */ + {0x04da, 0x100f, &panasonic_kvss080_model}, + {0x03f0, 0x1b05, &hp4850c_model}, + {0x03f0, 0x4505, &hpg4010_model}, + {0x03f0, 0x4605, &hpg4050_model}, + {0x04a9, 0x2228, &canon_4400f_model}, + {0x04a9, 0x221e, &canon_8400f_model}, + {0x04a9, 0x2229, &canon_8600f_model}, + /* GL845 devices */ + {0x07b3, 0x1300, &plustek_3800_model}, + /* GL846 devices */ + {0x1083, 0x162e, &canon_formula101_model}, + /* GL847 devices */ + {0x04a9, 0x1904, &canon_lide_100_model}, + {0x04a9, 0x1905, &canon_lide_200_model}, + {0x04a9, 0x1906, &canon_5600f_model}, + {0x04a9, 0x1907, &canon_lide_700f_model}, + {0x03f0, 0x4705, &hpn6310_model}, + /* GL124 devices */ + {0x04a9, 0x1909, &canon_lide_110_model}, + {0x04a9, 0x190e, &canon_lide_120_model}, + {0x04a9, 0x190a, &canon_lide_210_model}, + {0x04a9, 0x190f, &canon_lide_220_model}, + {0, 0, NULL} +}; + +#define MAX_SCANNERS (sizeof(genesys_usb_device_list) / \ + sizeof(genesys_usb_device_list[0])) diff --git a/backend/genesys_error.cc b/backend/genesys_error.cc new file mode 100644 index 0000000..c98a490 --- /dev/null +++ b/backend/genesys_error.cc @@ -0,0 +1,115 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_error.h" +#include +#include + +extern "C" void sanei_debug_msg(int level, int max_level, const char *be, const char *fmt, + va_list ap); + +#if (defined(__GNUC__) || defined(__CLANG__)) && (defined(__linux__) || defined(__APPLE__)) +extern "C" char* __cxa_get_globals(); +#endif + +static unsigned num_uncaught_exceptions() +{ +#if __cplusplus >= 201703L + int count = std::uncaught_exceptions(); + return count >= 0 ? count : 0; +#elif (defined(__GNUC__) || defined(__CLANG__)) && (defined(__linux__) || defined(__APPLE__)) + // the format of the __cxa_eh_globals struct is enshrined into the Itanium C++ ABI and it's + // very unlikely we'll get issues referencing it directly + char* cxa_eh_globals_ptr = __cxa_get_globals(); + return *reinterpret_cast(cxa_eh_globals_ptr + sizeof(void*)); +#else + return std::uncaught_exception() ? 1 : 0; +#endif +} + +DebugMessageHelper::DebugMessageHelper(const char* func) +{ + func_ = func; + num_exceptions_on_enter_ = num_uncaught_exceptions(); + msg_[0] = '\0'; + DBG(DBG_proc, "%s: start\n", func_); +} + +DebugMessageHelper::DebugMessageHelper(const char* func, const char* format, ...) +{ + func_ = func; + num_exceptions_on_enter_ = num_uncaught_exceptions(); + msg_[0] = '\0'; + DBG(DBG_proc, "%s: start\n", func_); + DBG(DBG_proc, "%s: ", func_); + + std::va_list args; + va_start(args, format); + sanei_debug_msg(DBG_proc, DBG_LEVEL, STRINGIFY(BACKEND_NAME), format, args); + va_end(args); + DBG(DBG_proc, "\n"); +} + + +DebugMessageHelper::~DebugMessageHelper() +{ + if (num_exceptions_on_enter_ < num_uncaught_exceptions()) { + if (msg_[0] != '\0') { + DBG(DBG_error, "%s: failed during %s\n", func_, msg_); + } else { + DBG(DBG_error, "%s: failed\n", func_); + } + } else { + DBG(DBG_proc, "%s: completed\n", func_); + } +} + +void DebugMessageHelper::vstatus(const char* format, ...) +{ + std::va_list args; + va_start(args, format); + std::vsnprintf(msg_, MAX_BUF_SIZE, format, args); + va_end(args); +} diff --git a/backend/genesys_error.h b/backend/genesys_error.h new file mode 100644 index 0000000..d456581 --- /dev/null +++ b/backend/genesys_error.h @@ -0,0 +1,202 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_ERROR_H +#define BACKEND_GENESYS_ERROR_H + +#include "../include/sane/config.h" +#include "../include/sane/sane.h" +#include "../include/sane/sanei_backend.h" + +#include +#include +#include + +#define DBG_error0 0 /* errors/warnings printed even with devuglevel 0 */ +#define DBG_error 1 /* fatal errors */ +#define DBG_init 2 /* initialization and scanning time messages */ +#define DBG_warn 3 /* warnings and non-fatal errors */ +#define DBG_info 4 /* informational messages */ +#define DBG_proc 5 /* starting/finishing functions */ +#define DBG_io 6 /* io functions */ +#define DBG_io2 7 /* io functions that are called very often */ +#define DBG_data 8 /* log image data */ + +class SaneException : std::exception { +public: + SaneException(SANE_Status status) : status_(status) + { + set_msg(nullptr); + } + + SaneException(SANE_Status status, const char* msg) : status_(status) + { + set_msg(msg); + } + + SaneException(const char* msg) : SaneException(SANE_STATUS_INVAL, msg) {} + + SANE_Status status() const { return status_; } + virtual const char* what() const noexcept override { return msg_.c_str(); } + +private: + + void set_msg(const char* msg) + { + const char* status_msg = sane_strstatus(status_); + std::size_t status_msg_len = std::strlen(status_msg); + + if (msg) { + std::size_t msg_len = std::strlen(msg); + msg_.reserve(msg_len + status_msg_len + 3); + msg_ = msg; + msg_ += " : "; + msg_ += status_msg; + return; + } + + msg_.reserve(status_msg_len); + msg_ = status_msg; + } + + std::string msg_; + SANE_Status status_; +}; + +/** + * call a function and return on error + */ +#define RIE(function) \ + do { status = function; \ + if (status != SANE_STATUS_GOOD) \ + { \ + DBG(DBG_error, "%s: %s\n", __func__, sane_strstatus (status)); \ + return status; \ + } \ + } while (SANE_FALSE) + +// call a function and throw an exception on error +#define TIE(function) \ + do { \ + SANE_Status tmp_status = function; \ + if (tmp_status != SANE_STATUS_GOOD) { \ + throw SaneException(tmp_status); \ + } \ + } while (false) + +#define DBGSTART DBG (DBG_proc, "%s start\n", __func__); +#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __func__); + +class DebugMessageHelper { +public: + static constexpr unsigned MAX_BUF_SIZE = 120; + + DebugMessageHelper(const char* func); + DebugMessageHelper(const char* func, const char* format, ...) + #ifdef __GNUC__ + __attribute__((format(printf, 3, 4))) + #endif + ; + + ~DebugMessageHelper(); + + void status(const char* msg) { vstatus("%s", msg); } + void vstatus(const char* format, ...) + #ifdef __GNUC__ + __attribute__((format(printf, 2, 3))) + #endif + ; + + void clear() { msg_[0] = '\n'; } + +private: + const char* func_ = nullptr; + char msg_[MAX_BUF_SIZE]; + unsigned num_exceptions_on_enter_ = 0; +}; + +#define DBG_HELPER(var) DebugMessageHelper var(__func__) +#define DBG_HELPER_ARGS(var, ...) DebugMessageHelper var(__func__, __VA_ARGS__) + +template +SANE_Status wrap_exceptions_to_status_code(const char* func, F&& function) +{ + try { + return function(); + } catch (const SaneException& exc) { + return exc.status(); + } catch (const std::bad_alloc& exc) { + return SANE_STATUS_NO_MEM; + } catch (const std::exception& exc) { + DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what()); + return SANE_STATUS_INVAL; + } catch (...) { + DBG(DBG_error, "%s: got unknown uncaught exception\n", func); + return SANE_STATUS_INVAL; + } +} + +template +void catch_all_exceptions(const char* func, F&& function) +{ + try { + function(); + } catch (const SaneException& exc) { + DBG(DBG_error, "%s: got exception: %s\n", func, exc.what()); + } catch (const std::bad_alloc& exc) { + DBG(DBG_error, "%s: got exception: could not allocate memory: %s\n", func, exc.what()); + } catch (const std::exception& exc) { + DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what()); + } catch (...) { + DBG(DBG_error, "%s: got unknown uncaught exception\n", func); + } +} + +inline void wrap_status_code_to_exception(SANE_Status status) +{ + if (status == SANE_STATUS_GOOD) + return; + throw SaneException(status); +} + +#endif // BACKEND_GENESYS_ERROR_H diff --git a/backend/genesys_gl124.c b/backend/genesys_gl124.c deleted file mode 100644 index a98d3d4..0000000 --- a/backend/genesys_gl124.c +++ /dev/null @@ -1,3997 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2016 Stéphane Voltz - - - 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. -*/ - -#undef BACKEND_NAME -#define BACKEND_NAME genesys_gl124 - -#include "genesys_gl124.h" - -/**************************************************************************** - Low level function - ****************************************************************************/ - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - - -/** @brief read scanned data - * Read in 0xeff0 maximum sized blocks. This read is done in 2 - * parts if not multple of 512. First read is rounded to a multiple of 512 bytes, last read fetches the - * remainder. Read addr is always 0x10000000 with the memory layout setup. - * @param dev device to read data from - * @param addr address within ASIC emory space - * @param data pointer where to store the read data - * @param len size to read - */ -static SANE_Status -gl124_bulk_read_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size, target, read, done; - uint8_t outdata[8], *buffer; - - DBG (DBG_io, "gl124_bulk_read_data: requesting %lu bytes (unused addr=0x%02x)\n", (u_long) len,addr); - - if (len == 0) - return SANE_STATUS_GOOD; - - target = len; - buffer = data; - - /* loop until computed data size is read */ - while (target) - { - if (target > 0xeff0) - { - size = 0xeff0; - } - else - { - size = target; - } - - /* hard coded 0x10000000 addr */ - outdata[0] = 0; - outdata[1] = 0; - outdata[2] = 0; - outdata[3] = 0x10; - - /* data size to transfer */ - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, 0x00, sizeof (outdata), - outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s failed while writing command: %s\n", - __func__, sane_strstatus (status)); - return status; - } - - /* blocks must be multiple of 512 but not last block */ - read = size; - read /= 512; - read *= 512; - - if(read>0) - { - DBG (DBG_io2, - "gl124_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) read); - status = sanei_usb_read_bulk (dev->dn, data, &read); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* read less than 512 bytes remainder */ - if (read < size) - { - done = read; - read = size - read; - DBG (DBG_io2, - "gl124_bulk_read_data: trying to read remaining %lu bytes of data\n", - (u_long) read); - status = sanei_usb_read_bulk (dev->dn, data+done, &read); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - } - - DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __func__, - (u_long) size, (u_long) (target - size)); - - target -= size; - data += size; - } - - if (DBG_LEVEL >= DBG_data && dev->binary!=NULL) - { - fwrite(buffer, len, 1, dev->binary); - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl124_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl124_get_filter_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl124_get_lineart_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl124_get_bitset_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl124_get_gain4_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl124_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl124_test_motor_flag_bit (SANE_Byte val) -{ - if (val & MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** @brief sensor profile - * search for the database of motor profiles and get the best one. Each - * profile is at a specific dpihw. Use LiDE 110 table by default. - * @param sensor_type sensor id - * @param dpi hardware dpi for the scan - * @param half_ccd flag to signal half ccd mode - * @return a pointer to a Sensor_Profile struct - */ -static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi, int half_ccd) -{ - unsigned int i; - int idx; - - i=0; - idx=-1; - while(i=dpi - && sensors[i].dpiflags & GENESYS_FLAG_HALF_CCD_MODE)) - { - return SANE_TRUE; - } - return SANE_FALSE; -} - -/** @brief set all registers to default values . - * This function is called only once at the beginning and - * fills register startup values for registers reused across scans. - * Those that are rarely modified or not modified are written - * individually. - * @param dev device structure holding register set to initialize - */ -static void -gl124_init_registers (Genesys_Device * dev) -{ - DBGSTART; - - memset (dev->reg, 0, GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* default to LiDE 110 */ - SETREG (0x01,0xa2); /* + REG01_SHDAREA */ - SETREG (0x02,0x90); - SETREG (0x03,0x50); - SETREG (0x04,0x03); - SETREG (0x05,0x00); - if(dev->model->ccd_type==CIS_CANONLIDE120) - { - SETREG (0x06,0x50); - SETREG (0x07,0x00); - } - else - { - SETREG (0x03,0x50 & ~REG03_AVEENB); - SETREG (0x06,0x50 | REG06_GAIN4); - } - SETREG (0x09,0x00); - SETREG (0x0a,0xc0); - SETREG (0x0b,0x2a); - SETREG (0x0c,0x12); - SETREG (0x11,0x00); - SETREG (0x12,0x00); - SETREG (0x13,0x0f); - SETREG (0x14,0x00); - SETREG (0x15,0x80); - SETREG (0x16,0x10); - SETREG (0x17,0x04); - SETREG (0x18,0x00); - SETREG (0x19,0x01); - SETREG (0x1a,0x30); - SETREG (0x1b,0x00); - SETREG (0x1c,0x00); - SETREG (0x1d,0x01); - SETREG (0x1e,0x10); - SETREG (0x1f,0x00); - SETREG (0x20,0x15); - SETREG (0x21,0x00); - if(dev->model->ccd_type!=CIS_CANONLIDE120) - { - SETREG (0x22,0x02); - } - else - { - SETREG (0x22,0x14); - } - SETREG (0x23,0x00); - SETREG (0x24,0x00); - SETREG (0x25,0x00); - SETREG (0x26,0x0d); - SETREG (0x27,0x48); - SETREG (0x28,0x00); - SETREG (0x29,0x56); - SETREG (0x2a,0x5e); - SETREG (0x2b,0x02); - SETREG (0x2c,0x02); - SETREG (0x2d,0x58); - SETREG (0x3b,0x00); - SETREG (0x3c,0x00); - SETREG (0x3d,0x00); - SETREG (0x3e,0x00); - SETREG (0x3f,0x02); - SETREG (0x40,0x00); - SETREG (0x41,0x00); - SETREG (0x42,0x00); - SETREG (0x43,0x00); - SETREG (0x44,0x00); - SETREG (0x45,0x00); - SETREG (0x46,0x00); - SETREG (0x47,0x00); - SETREG (0x48,0x00); - SETREG (0x49,0x00); - SETREG (0x4f,0x00); - SETREG (0x52,0x00); - SETREG (0x53,0x02); - SETREG (0x54,0x04); - SETREG (0x55,0x06); - SETREG (0x56,0x04); - SETREG (0x57,0x04); - SETREG (0x58,0x04); - SETREG (0x59,0x04); - SETREG (0x5a,0x1a); - SETREG (0x5b,0x00); - SETREG (0x5c,0xc0); - SETREG (0x5f,0x00); - SETREG (0x60,0x02); - SETREG (0x61,0x00); - SETREG (0x62,0x00); - SETREG (0x63,0x00); - SETREG (0x64,0x00); - SETREG (0x65,0x00); - SETREG (0x66,0x00); - SETREG (0x67,0x00); - SETREG (0x68,0x00); - SETREG (0x69,0x00); - SETREG (0x6a,0x00); - SETREG (0x6b,0x00); - SETREG (0x6c,0x00); - SETREG (0x6e,0x00); - SETREG (0x6f,0x00); - if(dev->model->ccd_type!=CIS_CANONLIDE120) - { - SETREG (0x6d,0xd0); - SETREG (0x71,0x08); - } - else - { - SETREG (0x6d,0x00); - SETREG (0x71,0x1f); - } - SETREG (0x70,0x00); - SETREG (0x72,0x08); - SETREG (0x73,0x0a); - - /* CKxMAP */ - SETREG (0x74,0x00); - SETREG (0x75,0x00); - SETREG (0x76,0x3c); - SETREG (0x77,0x00); - SETREG (0x78,0x00); - SETREG (0x79,0x9f); - SETREG (0x7a,0x00); - SETREG (0x7b,0x00); - SETREG (0x7c,0x55); - - SETREG (0x7d,0x00); - SETREG (0x7e,0x08); - SETREG (0x7f,0x58); - if(dev->model->ccd_type!=CIS_CANONLIDE120) - { - SETREG (0x80,0x00); - SETREG (0x81,0x14); - } - else - { - SETREG (0x80,0x00); - SETREG (0x81,0x10); - } - - /* STRPIXEL */ - SETREG (0x82,0x00); - SETREG (0x83,0x00); - SETREG (0x84,0x00); - /* ENDPIXEL */ - SETREG (0x85,0x00); - SETREG (0x86,0x00); - SETREG (0x87,0x00); - - SETREG (0x88,0x00); - SETREG (0x89,0x65); - SETREG (0x8a,0x00); - SETREG (0x8b,0x00); - SETREG (0x8c,0x00); - SETREG (0x8d,0x00); - SETREG (0x8e,0x00); - SETREG (0x8f,0x00); - SETREG (0x90,0x00); - SETREG (0x91,0x00); - SETREG (0x92,0x00); - SETREG (0x93,0x00); - SETREG (0x94,0x14); - SETREG (0x95,0x30); - SETREG (0x96,0x00); - SETREG (0x97,0x90); - SETREG (0x98,0x01); - SETREG (0x99,0x1f); - SETREG (0x9a,0x00); - SETREG (0x9b,0x80); - SETREG (0x9c,0x80); - SETREG (0x9d,0x3f); - SETREG (0x9e,0x00); - SETREG (0x9f,0x00); - SETREG (0xa0,0x20); - SETREG (0xa1,0x30); - SETREG (0xa2,0x00); - SETREG (0xa3,0x20); - SETREG (0xa4,0x01); - SETREG (0xa5,0x00); - SETREG (0xa6,0x00); - SETREG (0xa7,0x08); - SETREG (0xa8,0x00); - SETREG (0xa9,0x08); - SETREG (0xaa,0x01); - SETREG (0xab,0x00); - SETREG (0xac,0x00); - SETREG (0xad,0x40); - SETREG (0xae,0x01); - SETREG (0xaf,0x00); - SETREG (0xb0,0x00); - SETREG (0xb1,0x40); - SETREG (0xb2,0x00); - SETREG (0xb3,0x09); - SETREG (0xb4,0x5b); - SETREG (0xb5,0x00); - SETREG (0xb6,0x10); - SETREG (0xb7,0x3f); - SETREG (0xb8,0x00); - SETREG (0xbb,0x00); - SETREG (0xbc,0xff); - SETREG (0xbd,0x00); - SETREG (0xbe,0x07); - SETREG (0xc3,0x00); - SETREG (0xc4,0x00); - - /* gamma - SETREG (0xc5,0x00); - SETREG (0xc6,0x00); - SETREG (0xc7,0x00); - SETREG (0xc8,0x00); - SETREG (0xc9,0x00); - SETREG (0xca,0x00); - SETREG (0xcb,0x00); - SETREG (0xcc,0x00); - SETREG (0xcd,0x00); - SETREG (0xce,0x00); - */ - if(dev->model->ccd_type==CIS_CANONLIDE120) - { - SETREG (0xc5,0x20); - SETREG (0xc6,0xeb); - SETREG (0xc7,0x20); - SETREG (0xc8,0xeb); - SETREG (0xc9,0x20); - SETREG (0xca,0xeb); - } - - /* memory layout - SETREG (0xd0,0x0a); - SETREG (0xd1,0x1f); - SETREG (0xd2,0x34); */ - SETREG (0xd3,0x00); - SETREG (0xd4,0x00); - SETREG (0xd5,0x00); - SETREG (0xd6,0x00); - SETREG (0xd7,0x00); - SETREG (0xd8,0x00); - SETREG (0xd9,0x00); - - /* memory layout - SETREG (0xe0,0x00); - SETREG (0xe1,0x48); - SETREG (0xe2,0x15); - SETREG (0xe3,0x90); - SETREG (0xe4,0x15); - SETREG (0xe5,0x91); - SETREG (0xe6,0x2a); - SETREG (0xe7,0xd9); - SETREG (0xe8,0x2a); - SETREG (0xe9,0xad); - SETREG (0xea,0x40); - SETREG (0xeb,0x22); - SETREG (0xec,0x40); - SETREG (0xed,0x23); - SETREG (0xee,0x55); - SETREG (0xef,0x6b); - SETREG (0xf0,0x55); - SETREG (0xf1,0x6c); - SETREG (0xf2,0x6a); - SETREG (0xf3,0xb4); - SETREG (0xf4,0x6a); - SETREG (0xf5,0xb5); - SETREG (0xf6,0x7f); - SETREG (0xf7,0xfd);*/ - - SETREG (0xf8,0x01); /* other value is 0x05 */ - SETREG (0xf9,0x00); - SETREG (0xfa,0x00); - SETREG (0xfb,0x00); - SETREG (0xfc,0x00); - SETREG (0xff,0x00); - - /* fine tune upon device description */ - dev->reg[reg_0x05].value &= ~REG05_DPIHW; - switch (dev->sensor.optical_res) - { - case 600: - dev->reg[reg_0x05].value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg[reg_0x05].value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg[reg_0x05].value |= REG05_DPIHW_2400; - break; - case 4800: - dev->reg[reg_0x05].value |= REG05_DPIHW_4800; - break; - } - - /* initalize calibration reg */ - memcpy (dev->calib_reg, dev->reg, - GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - - DBGCOMPLETED; -} - -/**@brief send slope table for motor movement - * Send slope_table in machine byte order - * @param dev device to send slope table - * @param table_nr index of the slope table in ASIC memory - * Must be in the [0-4] range. - * @param slope_table pointer to 16 bit values array of the slope table - * @param steps number of elemnts in the slope table - */ -GENESYS_STATIC SANE_Status -gl124_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - SANE_Status status; - uint8_t *table; - int i; - char msg[10000]; - - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, - table_nr, steps); - - /* sanity check */ - if(table_nr<0 || table_nr>4) - { - DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); - return SANE_STATUS_INVAL; - } - - table = (uint8_t *) malloc (steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), ",%d", slope_table[i]); - } - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - /* slope table addresses are fixed */ - status = - sanei_genesys_write_ahb (dev->dn, dev->usb_mode, 0x10000000 + 0x4000 * table_nr, steps * 2, table); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: write to AHB failed writing slope table %d (%s)\n", - __func__, table_nr, sane_strstatus (status)); - } - - free (table); - DBGCOMPLETED; - return status; -} - -/** @brief * Set register values of 'special' ti type frontend - * Registers value are taken from the frontend register data - * set. - * @param dev device owning the AFE - * @param set flag AFE_INIT to specify the AFE must be reset before writing data - * */ -static SANE_Status -gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - uint16_t val; - - DBGSTART; - if (set == AFE_INIT) - { - DBG (DBG_proc, "%s: setting DAC %u\n", __func__, dev->model->dac_type); - - /* sets to default values */ - sanei_genesys_init_fe (dev); - } - - /* start writing to DAC */ - status = sanei_genesys_fe_write_data (dev, 0x00, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* write values to analog frontend */ - for (i = 1; i < 4; i++) - { - val = dev->frontend.reg[i]; - status = sanei_genesys_fe_write_data (dev, i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write reg %d: %s\n", __func__, i, - sane_strstatus (status)); - return status; - } - } - - status = sanei_genesys_fe_write_data (dev, 0x04, 0x00); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg4: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* these are not really sign for this AFE */ - for (i = 0; i < 3; i++) - { - val = dev->frontend.sign[i]; - status = sanei_genesys_fe_write_data (dev, 0x05 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write reg %d: %s\n", __func__, i+5, - sane_strstatus (status)); - return status; - } - } - - /* close writing to DAC */ - if(dev->model->dac_type == DAC_CANONLIDE120) - { - status = sanei_genesys_fe_write_data (dev, 0x00, 0x01); - } - else - { - status = sanei_genesys_fe_write_data (dev, 0x00, 0x11); - } - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - - return status; -} - - -/* Set values of analog frontend */ -static SANE_Status -gl124_set_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status; - uint8_t val; - - DBG (DBG_proc, "gl124_set_fe (%s)\n", - set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?"); - - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl124_set_fe(): setting DAC %u\n", - dev->model->dac_type); - sanei_genesys_init_fe (dev); - } - - RIE (sanei_genesys_read_register (dev, REG0A, &val)); - - if(dev->usb_mode<0) - { - val=3<>REG0AS_SIFSEL) - { - case 3: - status=gl124_set_ti_fe (dev, set); - break; - case 0: - case 1: - case 2: - default: - DBG (DBG_error, "%s: unsupported analog FE 0x%02x\n",__func__,val); - status=SANE_STATUS_INVAL; - break; - } - - DBGCOMPLETED; - return status; -} - - -/**@brief compute exposure to use - * compute the sensor exposure based on target resolution - * @param dev pointer to device description - * @param xres sensor's required resolution - * @param half_ccd flag for half ccd mode - */ -static int gl124_compute_exposure(Genesys_Device *dev, int xres, int half_ccd) -{ - Sensor_Profile *sensor; - - sensor=get_sensor_profile(dev->model->ccd_type, xres, half_ccd); - return sensor->exposure; -} - - -static SANE_Status -gl124_init_motor_regs_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - int scan_mode, - unsigned int flags) -{ - SANE_Status status; - int use_fast_fed; - unsigned int lincnt, fast_dpi; - uint16_t scan_table[SLOPE_TABLE_SIZE]; - uint16_t fast_table[SLOPE_TABLE_SIZE]; - int scan_steps,fast_steps,factor; - unsigned int feedl,dist; - Genesys_Register_Set *r; - uint32_t z1, z2; - float yres; - int min_speed; - unsigned int linesel; - - DBGSTART; - DBG (DBG_info, "gl124_init_motor_regs_scan : scan_exposure_time=%d, " - "scan_yres=%g, scan_step_type=%d, scan_lines=%d, scan_dummy=%d, " - "feed_steps=%d, scan_mode=%d, flags=%x\n", - scan_exposure_time, - scan_yres, - scan_step_type, - scan_lines, scan_dummy, feed_steps, scan_mode, flags); - - /* we never use fast fed since we do manual feed for the scans */ - use_fast_fed=0; - factor=1; - - /* enforce motor minimal scan speed - * @TODO extend motor struct for this value */ - if (scan_mode == SCAN_MODE_COLOR) - { - min_speed = 900; - } - else - { - switch(dev->model->motor_type) - { - case MOTOR_CANONLIDE110: - min_speed = 600; - break; - case MOTOR_CANONLIDE120: - min_speed = 900; - break; - default: - min_speed = 900; - break; - } - } - - /* compute min_speed and linesel */ - if(scan_yres 0 */ - if(linesel==0) - { - linesel=1; - yres=scan_yres*2; - } - } - else - { - yres=scan_yres; - linesel=0; - } - - DBG (DBG_io2, "%s: final yres=%f, linesel=%d\n", __func__, yres, linesel); - - lincnt=scan_lines*(linesel+1); - sanei_genesys_set_triple(reg,REG_LINCNT,lincnt); - DBG (DBG_io, "%s: lincnt=%d\n", __func__, lincnt); - - /* compute register 02 value */ - r = sanei_genesys_get_address (reg, REG02); - r->value = REG02_NOTHOME; - r->value |= REG02_MTRPWR; - - if (use_fast_fed) - r->value |= REG02_FASTFED; - else - r->value &= ~REG02_FASTFED; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= REG02_AGOHOME; - - if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - ||(yres>=dev->sensor.optical_res)) - r->value |= REG02_ACDCDIS; - - /* SCANFED */ - sanei_genesys_set_double(reg,REG_SCANFED,4); - - /* scan and backtracking slope table */ - sanei_genesys_slope_table(scan_table, - &scan_steps, - yres, - scan_exposure_time, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - motors); - RIE(gl124_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps)); - RIE(gl124_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps)); - - /* STEPNO */ - sanei_genesys_set_double(reg,REG_STEPNO,scan_steps); - - /* fast table */ - fast_dpi=yres; - - /* - if (scan_mode != SCAN_MODE_COLOR) - { - fast_dpi*=3; - } - */ - sanei_genesys_slope_table(fast_table, - &fast_steps, - fast_dpi, - scan_exposure_time, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - motors); - RIE(gl124_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps)); - RIE(gl124_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps)); - - /* FASTNO */ - sanei_genesys_set_double(reg,REG_FASTNO,fast_steps); - - /* FSHDEC */ - sanei_genesys_set_double(reg,REG_FSHDEC,fast_steps); - - /* FMOVNO */ - sanei_genesys_set_double(reg,REG_FMOVNO,fast_steps); - - /* substract acceleration distance from feedl */ - feedl=feed_steps; - feedl<<=scan_step_type; - - dist = scan_steps; - if (flags & MOTOR_FLAG_FEED) - dist *=2; - if (use_fast_fed) - { - dist += fast_steps*2; - } - DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); - - /* get sure we don't use insane value */ - if(distvalue = (r->value & ~REG1D_LINESEL) | linesel; - - r = sanei_genesys_get_address (reg, REGA0); - r->value = (scan_step_type << REGA0S_STEPSEL) | (scan_step_type << REGA0S_FSTPSEL); - - /* FMOVDEC */ - sanei_genesys_set_double(reg,REG_FMOVDEC,fast_steps); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** @brief copy sensor specific settings - * Set up register set for the given sensor resolution. Values are from the device table - * in genesys_devices.c for registers: - * [0x16 ... 0x1d] - * [0x52 ... 0x5e] - * Other come from the specific device sensor table in genesys_gl124.h: - * 0x18, 0x20, 0x61, 0x98 and - * @param dev device to set up - * @param regs register set to modify - * @param dpi resolution of the sensor during scan - * @param half_ccd flag for half ccd mode - * */ -static void -gl124_setup_sensor (Genesys_Device * dev, Genesys_Register_Set * regs, int dpi, int half_ccd) -{ - Genesys_Register_Set *r; - int i; - Sensor_Profile *sensor; - int dpihw; - uint32_t exp; - - DBGSTART; - - /* we start at 6, 0-5 is a 16 bits cache for exposure */ - for (i = 0x06; i < 0x0e; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - if (r) - { - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - } - - /* skip writing 5d,5e which is AFE address because - * they are not deifned in register set */ - for (i = 0; i < 11; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - if (r) - { - r->value = dev->sensor.regs_0x52_0x5e[i]; - } - } - - /* set EXPDUMMY and CKxMAP */ - dpihw=sanei_genesys_compute_dpihw(dev,dpi); - sensor=get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); - - r = sanei_genesys_get_address (regs, 0x18); - if (r) - { - r->value = sensor->reg18; - } - r = sanei_genesys_get_address (regs, 0x20); - if (r) - { - r->value = sensor->reg20; - } - r = sanei_genesys_get_address (regs, 0x61); - if (r) - { - r->value = sensor->reg61; - } - r = sanei_genesys_get_address (regs, 0x98); - if (r) - { - r->value = sensor->reg98; - } - - if(sensor->reg16!=0) - { - r = sanei_genesys_get_address (regs, 0x16); - if (r) - { - r->value = sensor->reg16; - } - } - if(sensor->reg70!=0) - { - r = sanei_genesys_get_address (regs, 0x70); - if (r) - { - r->value = sensor->reg70; - } - } - - sanei_genesys_set_triple(regs,REG_SEGCNT,sensor->segcnt); - sanei_genesys_set_double(regs,REG_TG0CNT,sensor->tg0cnt); - sanei_genesys_set_double(regs,REG_EXPDMY,sensor->expdummy); - - /* if no calibration has been done, set default values for exposures */ - exp=dev->sensor.regs_0x10_0x1d[0]*256+dev->sensor.regs_0x10_0x1d[1]; - if(exp==0) - { - exp=sensor->expr; - } - sanei_genesys_set_triple(regs,REG_EXPR,exp); - - exp=dev->sensor.regs_0x10_0x1d[2]*256+dev->sensor.regs_0x10_0x1d[3]; - if(exp==0) - { - exp=sensor->expg; - } - sanei_genesys_set_triple(regs,REG_EXPG,exp); - - exp=dev->sensor.regs_0x10_0x1d[4]*256+dev->sensor.regs_0x10_0x1d[5]; - if(exp==0) - { - exp=sensor->expb; - } - sanei_genesys_set_triple(regs,REG_EXPB,exp); - - sanei_genesys_set_triple(regs,REG_CK1MAP,sensor->ck1map); - sanei_genesys_set_triple(regs,REG_CK3MAP,sensor->ck3map); - sanei_genesys_set_triple(regs,REG_CK4MAP,sensor->ck4map); - - /* order of the sub-segments */ - dev->order=sensor->order; - - DBGCOMPLETED; -} - -/** @brief setup optical related registers - * start and pixels are expressed in optical sensor resolution coordinate - * space. - * @param dev scanner device to use - * @param reg registers to set up - * @param exposure_time exposure time to use - * @param used_res scanning resolution used, may differ from - * scan's one - * @param start logical start pixel coordinate - * @param pixels logical number of pixels to use - * @param channels number of color channels (currently 1 or 3) - * @param depth bit depth of the scan (1, 8 or 16) - * @param half_ccd SANE_TRUE if sensor's timings are such that x coordinates - * must be halved - * @param color_filter color channel to use as gray data - * @param flags optical flags (@see ) - * @return SANE_STATUS_GOOD if OK - */ -static SANE_Status -gl124_init_optical_regs_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int exposure_time, - int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, - int color_filter, - int flags) -{ - unsigned int words_per_line, segcnt; - unsigned int startx, endx, used_pixels, segnb; - unsigned int dpiset, cksel, dpihw, factor; - unsigned int bytes; - Genesys_Register_Set *r; - SANE_Status status; - uint32_t expmax, exp; - - DBG (DBG_proc, "%s : exposure_time=%d, " - "used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", __func__, exposure_time, - used_res, start, pixels, channels, depth, half_ccd, flags); - - /* resolution is divided according to CKSEL */ - r = sanei_genesys_get_address (reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); - - /* to manage high resolution device while keeping good - * low resolution scanning speed, we make hardware dpi vary */ - dpihw=sanei_genesys_compute_dpihw(dev, used_res * cksel); - factor=dev->sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); - - /* sensor parameters */ - gl124_setup_sensor (dev, reg, dpihw, half_ccd); - dpiset = used_res * cksel; - - /* start and end coordinate in optical dpi coordinates */ - /* startx = start/cksel + dev->sensor.dummy_pixel; XXX STEF XXX */ - startx = start/cksel; - used_pixels=pixels/cksel; - endx = startx + used_pixels; - - /* pixel coordinate factor correction when used dpihw is not maximal one */ - startx/=factor; - endx/=factor; - used_pixels=endx-startx; - - status = gl124_set_fe (dev, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, REG01); - r->value &= ~REG01_SCAN; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - r->value &= ~REG01_DVDSET; - } - else - { - r->value |= REG01_DVDSET; - } - r->value &= ~REG01_SCAN; - - r = sanei_genesys_get_address (reg, REG03); - if((dev->model->ccd_type!=CIS_CANONLIDE120)&&(used_res>=600)) - { - r->value &= ~REG03_AVEENB; - DBG (DBG_io, "%s: disabling AVEENB\n", __func__); - } - else - { - r->value |= ~REG03_AVEENB; - DBG (DBG_io, "%s: enabling AVEENB\n", __func__); - } - - if (flags & OPTICAL_FLAG_DISABLE_LAMP) - r->value &= ~REG03_LAMPPWR; - else - r->value |= REG03_LAMPPWR; - - /* BW threshold */ - RIE (sanei_genesys_write_register (dev, REG114, dev->settings.threshold)); - RIE (sanei_genesys_write_register (dev, REG115, dev->settings.threshold)); - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, REG04); - switch (depth) - { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - r->value &= ~REG04_FILTER; - if (channels == 1) - { - switch (color_filter) - { - case 0: - r->value |= 0x10; /* red filter */ - break; - case 2: - r->value |= 0x30; /* blue filter */ - break; - default: - r->value |= 0x20; /* green filter */ - break; - } - } - - /* register 05 */ - r = sanei_genesys_get_address (reg, REG05); - - /* set up dpihw */ - r->value &= ~REG05_DPIHW; - switch(dpihw) - { - case 600: - r->value |= REG05_DPIHW_600; - break; - case 1200: - r->value |= REG05_DPIHW_1200; - break; - case 2400: - r->value |= REG05_DPIHW_2400; - break; - case 4800: - r->value |= REG05_DPIHW_4800; - break; - } - - /* enable gamma tables */ - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - if(half_ccd) - { - sanei_genesys_set_double(reg,REG_DPISET,dpiset*2); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset*2); - } - else - { - sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); - } - - r = sanei_genesys_get_address (reg, REG06); - r->value |= REG06_GAIN4; - - /* CIS scanners can do true gray by setting LEDADD */ - /* we set up LEDADD only when asked */ - if (dev->model->is_cis == SANE_TRUE) - { - r = sanei_genesys_get_address (reg, REG60); - r->value &= ~REG60_LEDADD; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG60_LEDADD; - sanei_genesys_get_triple(reg,REG_EXPR,&expmax); - sanei_genesys_get_triple(reg,REG_EXPG,&exp); - if(exp>expmax) - { - expmax=exp; - } - sanei_genesys_get_triple(reg,REG_EXPB,&exp); - if(exp>expmax) - { - expmax=exp; - } - sanei_genesys_set_triple(dev->reg,REG_EXPR,expmax); - sanei_genesys_set_triple(dev->reg,REG_EXPG,expmax); - sanei_genesys_set_triple(dev->reg,REG_EXPB,expmax); - } - /* RGB weighting, REG_TRUER,G and B are to be set */ - r = sanei_genesys_get_address (reg, 0x01); - r->value &= ~REG01_TRUEGRAY; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG01_TRUEGRAY; - sanei_genesys_write_register (dev, REG_TRUER, 0x80); - sanei_genesys_write_register (dev, REG_TRUEG, 0x80); - sanei_genesys_write_register (dev, REG_TRUEB, 0x80); - } - } - - /* segment number */ - r = sanei_genesys_get_address (reg, 0x98); - segnb = r->value & 0x0f; - - sanei_genesys_set_triple(reg,REG_STRPIXEL,startx/segnb); - DBG (DBG_io2, "%s: strpixel used=%d\n", __func__, startx/segnb); - sanei_genesys_get_triple(reg,REG_SEGCNT,&segcnt); - if(endx/segnb==segcnt) - { - endx=0; - } - sanei_genesys_set_triple(reg,REG_ENDPIXEL,endx/segnb); - DBG (DBG_io2, "%s: endpixel used=%d\n", __func__, endx/segnb); - - /* words(16bit) before gamma, conversion to 8 bit or lineart */ - words_per_line = (used_pixels * dpiset) / dpihw; - bytes = depth / 8; - if (depth == 1) - { - words_per_line = (words_per_line >> 3) + ((words_per_line & 7) ? 1 : 0); - } - else - { - words_per_line *= bytes; - } - - dev->bpl = words_per_line; - dev->cur = 0; - dev->skip = 0; - dev->len = dev->bpl/segnb; - dev->dist = dev->bpl/segnb; - dev->segnb = segnb; - dev->line_count = 0; - dev->line_interp = 0; - - DBG (DBG_io2, "%s: used_pixels =%d\n", __func__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->line_interp=%lu\n", __func__, (unsigned long)dev->line_interp); - - words_per_line *= channels; - dev->wpl = words_per_line; - - /* allocate buffer for odd/even pixels handling */ - if(dev->oe_buffer.buffer!=NULL) - { - sanei_genesys_buffer_free (&(dev->oe_buffer)); - } - RIE (sanei_genesys_buffer_alloc (&(dev->oe_buffer), dev->wpl)); - - /* MAXWD is expressed in 2 words unit */ - sanei_genesys_set_triple(reg,REG_MAXWD,(words_per_line)); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); - - sanei_genesys_set_triple(reg,REG_LPERIOD,exposure_time); - DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); - - sanei_genesys_set_double(reg,REG_DUMMY,dev->sensor.dummy_pixel); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -GENESYS_STATIC -SANE_Status -gl124_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - __sane_unused__ int scan_method, - int scan_mode, - int color_filter, - unsigned int flags) -{ - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; - unsigned int oflags, mflags; /**> optical and motor flags */ - int exposure_time; - int stagger; - - int dummy = 0; - int slope_dpi = 0; - int scan_step_type = 1; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - SANE_Status status; - - DBG (DBG_info, - "gl124_init_scan_regs settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g/%g\n" - "Depth/Channels: %u/%u\n" - "Flags : %x\n\n", - xres, yres, lines, pixels, startx, starty, depth, channels, flags); - - half_ccd=compute_half_ccd(dev->model, xres); - - /* optical_res */ - optical_res = dev->sensor.optical_res; - if (half_ccd) - optical_res /= 2; - DBG (DBG_info, "%s: optical_res=%d\n", __func__, optical_res); - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "gl124_init_scan_regs : stagger=%d lines\n", stagger); - - /** @brief compute used resolution */ - if (flags & SCAN_FLAG_USE_OPTICAL_RES) - { - used_res = optical_res; - } - else - { - /* resolution is choosen from a fixed list and can be used directly, - * unless we have ydpi higher than sensor's maximum one */ - if(xres>optical_res) - used_res=optical_res; - else - used_res = xres; - } - - /* compute scan parameters values */ - /* pixels are allways given at full optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - /* add x coordinates */ - start = startx; - - if (stagger > 0) - start |= 1; - - /* compute correct pixels number */ - used_pixels = (pixels * optical_res) / xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); - - /* round up pixels number if needed */ - if (used_pixels * xres < pixels * optical_res) - used_pixels++; - - /* we want even number of pixels here */ - if(used_pixels & 1) - used_pixels++; - - /* slope_dpi */ - /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = yres * channels; - else - slope_dpi = yres; - - /* scan_step_type */ - if(flags & SCAN_FLAG_FEEDING) - { - scan_step_type=0; - exposure_time=MOVE_EXPOSURE; - } - else - { - exposure_time = gl124_compute_exposure (dev, used_res, half_ccd); - scan_step_type = sanei_genesys_compute_step_type(motors, dev->model->motor_type, exposure_time); - } - - DBG (DBG_info, "gl124_init_scan_regs : exposure_time=%d pixels\n", exposure_time); - DBG (DBG_info, "gl124_init_scan_regs : scan_step_type=%d\n", scan_step_type); - - /*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if ((flags & SCAN_FLAG_DYNAMIC_LINEART) && (scan_mode == SCAN_MODE_LINEART)) - { - depth = 8; - } - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - oflags = 0; - if (flags & SCAN_FLAG_DISABLE_SHADING) - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - if (flags & SCAN_FLAG_DISABLE_GAMMA) - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - if (flags & SCAN_FLAG_DISABLE_LAMP) - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - if (flags & SCAN_FLAG_CALIBRATION) - oflags |= OPTICAL_FLAG_DISABLE_DOUBLE; - - if (dev->model->is_cis && dev->settings.true_gray) - { - oflags |= OPTICAL_FLAG_ENABLE_LEDADD; - } - - /* now _LOGICAL_ optical values used are known, setup registers */ - status = gl124_init_optical_regs_scan (dev, - reg, - exposure_time, - used_res, - start, - used_pixels, - channels, - depth, - half_ccd, - color_filter, - oflags); - if (status != SANE_STATUS_GOOD) - return status; - - /*** motor parameters ***/ - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,flags); - - /* lines to scan */ - lincnt = lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = starty; - DBG (DBG_info, "gl124_init_scan_regs: move=%d steps\n", move); - - mflags=0; - if(flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) - mflags|=MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; - if(flags & SCAN_FLAG_FEEDING) - mflags|=MOTOR_FLAG_FEED; - - status = gl124_init_motor_regs_scan (dev, - reg, - exposure_time, - slope_dpi, - scan_step_type, - dev->model->is_cis ? lincnt * channels : lincnt, - dummy, - move, - scan_mode, - mflags); - if (status != SANE_STATUS_GOOD) - return status; - - /*** prepares data reordering ***/ - - /* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * channels * depth) / 8; - - /* since we don't have sheetfed scanners to handle, - * use huge read buffer */ - /* TODO find the best size according to settings */ - requested_buffer_size = 16 * bytes_per_line; - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * channels * depth) / 8; - - RIE (sanei_genesys_buffer_free (&(dev->read_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->read_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->lines_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->lines_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->shrink_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->shrink_buffer), - requested_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->out_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->out_buffer), - (8 * dev->settings.pixels * channels * - depth) / 8)); - - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG (DBG_info, - "gl124_init_scan_regs: physical bytes to read = %lu\n", - (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - dev->total_bytes_read = 0; - if (depth == 1) - dev->total_bytes_to_read = - ((dev->settings.pixels * dev->settings.lines) / 8 + - (((dev->settings.pixels * dev->settings.lines) % 8) ? 1 : 0)) * - channels; - else - dev->total_bytes_to_read = - dev->settings.pixels * dev->settings.lines * channels * (depth / 8); - - DBG (DBG_info, "gl124_init_scan_regs: total bytes to send = %lu\n", - (u_long) dev->total_bytes_to_read); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl124_calculate_current_setup (Genesys_Device * dev) -{ - int channels; - int depth; - int start; - - float xres; /*dpi */ - float yres; /*dpi */ - float startx; /*optical_res, from dummy_pixel+1 */ - float pixels; - float lines; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure_time; - int stagger; - SANE_Bool half_ccd; - - int max_shift, dpihw; - Sensor_Profile *sensor; - - int optical_res; - - DBG (DBG_info, - "gl124_calculate_current_setup settings:\n" - "Resolution: %ux%uDPI\n" - "Lines : %u\n" - "PPL : %u\n" - "Startpos : %.3f/%.3f\n" - "Scan mode : %d\n\n", - dev->settings.xres, - dev->settings.yres, dev->settings.lines, dev->settings.pixels, - dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); - - /* channels */ - if (dev->settings.scan_mode == 4) /* single pass color */ - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == 0) - depth = 1; - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - - xres = dev->settings.xres; - yres = dev->settings.yres; - startx = start; - pixels = dev->settings.pixels; - lines = dev->settings.lines; - - half_ccd=compute_half_ccd(dev->model, xres); - - DBG (DBG_info, - "gl124_calculate_current_setup settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g\n" - "Half ccd : %d\n" - "Depth/Channels: %u/%u\n\n", - xres, yres, lines, pixels, startx, depth, half_ccd, channels); - - /* optical_res */ - optical_res = dev->sensor.optical_res; - - if(xres<=optical_res) - used_res = xres; - else - used_res=optical_res; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - - /* compute correct pixels number */ - used_pixels = (pixels * optical_res) / xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); - - /* exposure */ - exposure_time = gl124_compute_exposure (dev, xres, half_ccd); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); - - /* compute hw dpi for sensor */ - dpihw=sanei_genesys_compute_dpihw(dev,used_res); - - sensor=get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); - dev->segnb=sensor->reg98 & 0x0f; - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "%s: stagger=%d lines\n", __func__, stagger); - - /* lincnt */ - lincnt = lines + max_shift + stagger; - - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static void -gl124_set_motor_power (Genesys_Register_Set * regs, SANE_Bool set) -{ - - DBG (DBG_proc, "gl124_set_motor_power\n"); - - if (set) - { - sanei_genesys_set_reg_from_set (regs, REG02, - sanei_genesys_read_reg_from_set (regs, - REG02) - | REG02_MTRPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, REG02, - sanei_genesys_read_reg_from_set (regs, - REG02) - & ~REG02_MTRPWR); - } -} - -static void -gl124_set_lamp_power (Genesys_Device * dev, - Genesys_Register_Set * regs, SANE_Bool set) -{ - if (dev == NULL || regs==NULL) - return; - - if (set) - { - sanei_genesys_set_reg_from_set (regs, 0x03, - sanei_genesys_read_reg_from_set (regs, - 0x03) - | REG03_LAMPPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, 0x03, - sanei_genesys_read_reg_from_set (regs, - 0x03) - & ~REG03_LAMPPWR); - } -} - -/** - * for fast power saving methods only, like disabling certain amplifiers - * @param dev device to use - * @param enable true to set inot powersaving - * */ -static SANE_Status -gl124_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - DBG (DBG_proc, "gl124_save_power: enable = %d\n", enable); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl124_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - Genesys_Register_Set *r; - - DBG (DBG_proc, "gl124_set_powersaving (delay = %d)\n", delay); - - r = sanei_genesys_get_address (dev->reg, REG03); - r->value &= ~0xf0; - if(delay<15) - { - r->value |= delay; - } - else - { - r->value |= 0x0f; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl124_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl124_stop_action (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val40, val; - unsigned int loop; - - DBGSTART; - - /* post scan gpio : without that HOMSNR is unreliable */ - gl124_homsnr_gpio(dev); - - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - status = sanei_genesys_read_register (dev, REG100, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read reg100: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG100_DATAENB) && !(val40 & REG100_MOTMFLG)) - { - DBG (DBG_info, "%s: already stopped\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* ends scan */ - val = sanei_genesys_read_reg_from_set (dev->reg, REG01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set (dev->reg, REG01, val); - status = sanei_genesys_write_register (dev, REG01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write register 01: %s\n", __func__, - sane_strstatus (status)); - return status; - } - usleep (100 * 1000); - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - status = sanei_genesys_read_register (dev, REG100, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG100_DATAENB) && !(val40 & REG100_MOTMFLG) - && !(val & MOTORENB)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - usleep (100 * 1000); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - - -/** @brief setup GPIOs for scan - * Setup GPIO values to drive motor (or light) needed for the - * target resolution - * @param *dev device to set up - * @param resolution dpi of the target scan - * @return SANE_STATUS_GOOD unless REG32 cannot be read - */ -static SANE_Status -gl124_setup_scan_gpio(Genesys_Device *dev, int resolution) -{ -SANE_Status status; -uint8_t val; - - DBGSTART; - RIE (sanei_genesys_read_register (dev, REG32, &val)); - - /* LiDE 110, 210 and 220 cases */ - if(dev->model->gpo_type != GPO_CANONLIDE120) - { - if(resolution>=dev->motor.base_ydpi/2) - { - val &= 0xf7; - } - else if(resolution>=dev->motor.base_ydpi/4) - { - val &= 0xef; - } - else - { - val |= 0x10; - } - } - /* 120 : <=300 => 0x53 */ - else - { /* base_ydpi is 4800 */ - if(resolution<=300) - { - val &= 0xf7; - } - else if(resolution<=600) - { - val |= 0x08; - } - else if(resolution<=1200) - { - val &= 0xef; - val |= 0x08; - } - else - { - val &= 0xf7; - } - } - val |= 0x02; - RIE (sanei_genesys_write_register (dev, REG32, val)); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Send the low-level scan command */ -/* todo : is this that useful ? */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl124_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - SANE_Status status; - uint8_t val; - - DBGSTART; - if (reg == NULL) - return SANE_STATUS_INVAL; - - /* set up GPIO for scan */ - RIE(gl124_setup_scan_gpio(dev,dev->settings.yres)); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* enable scan and motor */ - RIE (sanei_genesys_read_register (dev, REG01, &val)); - val |= REG01_SCAN; - RIE (sanei_genesys_write_register (dev, REG01, val)); - - if (start_motor) - { - RIE (sanei_genesys_write_register (dev, REG0F, 1)); - } - else - { - RIE (sanei_genesys_write_register (dev, REG0F, 0)); - } - - DBGCOMPLETED; - return status; -} - - -/* Send the stop scan command */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl124_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - SANE_Status status; - - DBG (DBG_proc, "gl124_end_scan (check_stop = %d)\n", check_stop); - if (reg == NULL) - return SANE_STATUS_INVAL; - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl124_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_end_scan: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - - -/** rewind scan - * Move back by the same amount of distance than previous scan. - * @param dev device to rewind - * @returns SANE_STATUS_GOOD on success - */ -GENESYS_STATIC -SANE_Status gl124_rewind(Genesys_Device * dev) -{ - SANE_Status status; - uint8_t byte; - - DBGSTART; - - /* set motor reverse */ - RIE (sanei_genesys_read_register (dev, 0x02, &byte)); - byte |= 0x04; - RIE (sanei_genesys_write_register(dev, 0x02, byte)); - - /* and start scan, then wait completion */ - RIE (gl124_begin_scan (dev, dev->reg, SANE_TRUE)); - do - { - usleep(100*1000); - RIE (sanei_genesys_read_register (dev, REG100, &byte)); - } - while(byte & REG100_MOTMFLG); - RIE (gl124_end_scan (dev, dev->reg, SANE_TRUE)); - - /* restore direction */ - RIE (sanei_genesys_read_register (dev, 0x02, &byte)); - byte &= 0xfb; - RIE (sanei_genesys_write_register(dev, 0x02, byte)); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** Park head - * Moves the slider to the home (top) position slowly - * @param dev device to park - * @param wait_until_home true to make the function waiting for head - * to be home before returning, if fals returne immediately - * @returns SANE_STATUS_GOO on success */ -GENESYS_STATIC -SANE_Status -gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg[GENESYS_GL124_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - uint8_t val; - float resolution; - int loop = 0; - - DBG (DBG_proc, "gl124_slow_back_home (wait_until_home = %d)\n", - wait_until_home); - - if(dev->usb_mode<0) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* post scan gpio : without that HOMSNR is unreliable */ - gl124_homsnr_gpio(dev); - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - usleep (100000); /* sleep 100 ms */ - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - /* is sensor at home? */ - if (val & HOMESNR) - { - DBG (DBG_info, "%s: already at home, completed\n", __func__); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* feed a little first */ - if (strcmp (dev->model->name, "canon-lide-210") == 0) - { - status = gl124_feed (dev, 20, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to do initial feed: %s\n", __func__, sane_strstatus (status)); - return status; - } - } - - memcpy (local_reg, dev->reg, GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - resolution=sanei_genesys_get_lowest_dpi(dev); - - status = gl124_init_scan_regs (dev, - local_reg, - resolution, - resolution, - 100, - 30000, - 100, - 100, - 8, - 1, - dev->settings.scan_method, - SCAN_MODE_GRAY, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_slow_back_home: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse and no scan */ - r = sanei_genesys_get_address (local_reg, REG02); - r->value |= REG02_MTRREV; - - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL124_MAX_REGS)); - - RIE(gl124_setup_scan_gpio(dev,resolution)); - - status = gl124_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_slow_back_home: failed to start motor: %s\n", - sane_strstatus (status)); - gl124_stop_action (dev); - /* restore original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL124_MAX_REGS); - return status; - } - - /* post scan gpio : without that HOMSNR is unreliable */ - gl124_homsnr_gpio(dev); - - if (wait_until_home) - { - - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - - if (val & HOMESNR) /* home sensor */ - { - DBG (DBG_info, "gl124_slow_back_home: reached home position\n"); - DBGCOMPLETED; - dev->scanhead_position_in_steps = 0; - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl124_stop_action (dev); - DBG (DBG_error, - "gl124_slow_back_home: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; - } - - DBG (DBG_info, "gl124_slow_back_home: scanhead is still moving\n"); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move - * @param reverse true is moving backward - * */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse) -{ - Genesys_Register_Set local_reg[GENESYS_GL124_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - float resolution; - uint8_t val; - - DBGSTART; - DBG (DBG_io, "%s: steps=%d\n", __func__, steps); - - /* prepare local registers */ - memcpy (local_reg, dev->reg, GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - - resolution=sanei_genesys_get_lowest_ydpi(dev); - status = gl124_init_scan_regs (dev, - local_reg, - resolution, - resolution, - 0, - steps, - 100, - 3, - 8, - 3, - dev->settings.scan_method, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_FEEDING | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* set exposure to zero */ - sanei_genesys_set_triple(local_reg,REG_EXPR,0); - sanei_genesys_set_triple(local_reg,REG_EXPG,0); - sanei_genesys_set_triple(local_reg,REG_EXPB,0); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); - - /* set up for no scan */ - r = sanei_genesys_get_address (local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* set up for reverse if needed */ - if(reverse) - { - r = sanei_genesys_get_address (local_reg, REG02); - r->value |= REG02_MTRREV; - } - - /* send registers */ - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL124_MAX_REGS)); - - status = gl124_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); - gl124_stop_action (dev); - - /* restore original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL124_MAX_REGS); - return status; - } - - /* wait until feed count reaches the required value, but do not - * exceed 30s */ - do - { - status = sanei_genesys_get_status (dev, &val); - } - while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); - - /* then stop scanning */ - RIE(gl124_stop_action (dev)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl124_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status; - uint8_t *data; - Genesys_Register_Set local_reg[GENESYS_GL124_MAX_REGS]; - int steps; - - int pixels = 600; - int dpi = 300; - - DBGSTART; - - memcpy (local_reg, dev->reg, - GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - status = gl124_init_scan_regs (dev, - local_reg, - dpi, - dpi, - 0, - 0, /*we should give a small offset here~60 steps */ - 600, - dev->model->search_lines, - 8, - 1, - dev->settings.scan_method, - SCAN_MODE_GRAY, - 1, /*green */ - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE); - if (status!=SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to init scan registers: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* send to scanner */ - status = dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL124_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_search_start_position: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - size = pixels * dev->model->search_lines; - - data = malloc (size); - if (!data) - { - DBG (DBG_error, - "gl124_search_start_position: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - status = gl124_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl124_search_start_position: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl124_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("search_position.pnm", data, 8, 1, pixels, - dev->model->search_lines); - - status = gl124_end_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl124_search_start_position: failed to end scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* update regs to copy ASIC internal state */ - memcpy (dev->reg, local_reg, - GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - - status = - sanei_genesys_search_reference_point (dev, data, 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl124_search_start_position: failed to set search reference point: %s\n", - sane_strstatus (status)); - return status; - } - - free (data); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl124_init_regs_for_coarse_calibration (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t channels; - uint8_t cksel; - - DBGSTART; - cksel = (dev->calib_reg[reg_0x18].value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - status = gl124_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - dev->sensor.optical_res / cksel, - 20, - 16, - channels, - dev->settings.scan_method, - dev->settings.scan_mode, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_FEEDING | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_init_register_for_coarse_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - gl124_set_motor_power (dev->calib_reg, SANE_FALSE); - - DBG (DBG_info, - "gl124_init_register_for_coarse_calibration: optical sensor res: %d dpi, actual res: %d\n", - dev->sensor.optical_res / cksel, dev->settings.xres); - - status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_init_register_for_coarse_calibration: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -/* shading calibration is done at dpihw */ -static SANE_Status -gl124_init_regs_for_shading (Genesys_Device * dev) -{ - SANE_Status status; - int move, resolution, dpihw, factor; - - DBGSTART; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - - dev->calib_channels = 3; - dev->calib_lines = dev->model->shading_lines; - dpihw=sanei_genesys_compute_dpihw(dev,dev->settings.xres); - if(dpihw>=2400) - { - dev->calib_lines *= 2; - } - resolution=dpihw; - - /* if half CCD mode, use half resolution */ - if(compute_half_ccd(dev->model, dev->settings.xres)==SANE_TRUE) - { - resolution /= 2; - dev->calib_lines /= 2; - } - dev->calib_resolution = resolution; - factor=dev->sensor.optical_res/resolution; - dev->calib_pixels = dev->sensor.sensor_pixels/factor; - - /* distance to move to reach white target at high resolution */ - move=0; - if(dev->settings.yres>=1200) - { - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; - } - DBG (DBG_io, "%s: move=%d steps\n", __func__, move); - - status = gl124_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - move, - dev->calib_pixels, - dev->calib_lines, - 16, - dev->calib_channels, - dev->settings.scan_method, - SCAN_MODE_COLOR, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - gl124_set_motor_power (dev->calib_reg, SANE_FALSE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - dev->scanhead_position_in_steps += dev->calib_lines + move; - - status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to bulk write registers: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief set up registers for the actual scan - */ -static SANE_Status -gl124_init_regs_for_scan (Genesys_Device * dev) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - uint8_t val40,val; - - SANE_Status status; - - DBG (DBG_info, - "gl124_init_regs_for_scan settings:\nResolution: %ux%uDPI\n" - "Lines : %u\npixels : %u\nStartpos : %.3f/%.3f\nScan mode : %d\n\n", - dev->settings.xres, - dev->settings.yres, - dev->settings.lines, - dev->settings.pixels, - dev->settings.tl_x, - dev->settings.tl_y, - dev->settings.scan_mode); - - /* wait for motor to stop first */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - status = sanei_genesys_read_register (dev, REG100, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to read reg100: %s\n", __func__, sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - if((val & MOTORENB) || (val40 & REG100_MOTMFLG)) - { - do - { - usleep(10000); - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - status = sanei_genesys_read_register (dev, REG100, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to read reg100: %s\n", __func__, sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - } while ((val & MOTORENB) || (val40 & REG100_MOTMFLG)); - usleep(50000); - } - - /* ensure head is parked in case of calibration */ - RIE (gl124_slow_back_home (dev, SANE_TRUE)); - - /* channels */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == SCAN_MODE_LINEART) - depth = 1; - - /* y (motor) distance to move to reach scanned area */ - move_dpi = dev->motor.base_ydpi/4; - move = SANE_UNFIX (dev->model->y_offset); - move += dev->settings.tl_y; - move = (move * move_dpi) / MM_PER_INCH; - DBG (DBG_info, "%s: move=%f steps\n", __func__, move); - - if(channels*dev->settings.yres>=600 && move>700) - { - status = gl124_feed (dev, move-500, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to move to scan area\n",__func__); - return status; - } - move=500; - } - DBG (DBG_info, "gl124_init_regs_for_scan: move=%f steps\n", move); - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - if(compute_half_ccd(dev->model, dev->settings.xres)==SANE_TRUE) - { - start /=2; - } - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - flags = 0; - - /* enable emulated lineart from gray data */ - if(dev->settings.scan_mode == SCAN_MODE_LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - status = gl124_init_scan_regs (dev, - dev->reg, - dev->settings.xres, - dev->settings.yres, - start, - move, - dev->settings.pixels, - dev->settings.lines, - depth, - channels, - dev->settings.scan_method, - dev->settings.scan_mode, - dev->settings.color_filter, - flags); - - if (status != SANE_STATUS_GOOD) - return status; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl124_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t addr, length, strpixel ,endpixel, x, factor, segcnt, pixels, i; - uint32_t lines, channels; - uint16_t dpiset,dpihw; - uint8_t val,*buffer,*ptr,*src; - - DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); - - /* logical size of a color as seen by generic code of the frontend */ - length = (uint32_t) (size / 3); - sanei_genesys_get_triple(dev->reg,REG_STRPIXEL,&strpixel); - sanei_genesys_get_triple(dev->reg,REG_ENDPIXEL,&endpixel); - sanei_genesys_get_triple(dev->reg,REG_SEGCNT,&segcnt); - if(endpixel==0) - { - endpixel=segcnt; - } - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, SEGCNT=%d\n",__func__,strpixel,endpixel,endpixel-strpixel,segcnt); - - /* compute deletion factor */ - sanei_genesys_get_double(dev->reg,REG_DPISET,&dpiset); - dpihw=sanei_genesys_compute_dpihw(dev,dpiset); - factor=dpihw/dpiset; - DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); - - /* binary data logging */ - if(DBG_LEVEL>=DBG_data) - { - dev->binary=fopen("binary.pnm","wb"); - sanei_genesys_get_triple(dev->reg, REG_LINCNT, &lines); - channels=dev->current_setup.channels; - if(dev->binary!=NULL) - { - fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels*dev->segnb,lines/channels,255); - } - } - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; /* 2 words of 2 bytes */ - endpixel*=2*2; - segcnt*=2*2; - pixels=endpixel-strpixel; - - DBG( DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__func__,length, length/4); - buffer=(uint8_t *)malloc(pixels*dev->segnb); - memset(buffer,0,pixels*dev->segnb); - - /* write actual red data */ - for(i=0;i<3;i++) - { - /* copy data to work buffer and process it */ - /* coefficent destination */ - ptr=buffer; - - /* iterate on both sensor segment */ - for(x=0;xsegnb) - { - case 1: - ptr[0+pixels*0]=src[0+segcnt*0]; - ptr[1+pixels*0]=src[1+segcnt*0]; - ptr[2+pixels*0]=src[2+segcnt*0]; - ptr[3+pixels*0]=src[3+segcnt*0]; - break; - case 2: - ptr[0+pixels*0]=src[0+segcnt*0]; - ptr[1+pixels*0]=src[1+segcnt*0]; - ptr[2+pixels*0]=src[2+segcnt*0]; - ptr[3+pixels*0]=src[3+segcnt*0]; - ptr[0+pixels*1]=src[0+segcnt*1]; - ptr[1+pixels*1]=src[1+segcnt*1]; - ptr[2+pixels*1]=src[2+segcnt*1]; - ptr[3+pixels*1]=src[3+segcnt*1]; - break; - case 4: - ptr[0+pixels*0]=src[0+segcnt*0]; - ptr[1+pixels*0]=src[1+segcnt*0]; - ptr[2+pixels*0]=src[2+segcnt*0]; - ptr[3+pixels*0]=src[3+segcnt*0]; - ptr[0+pixels*1]=src[0+segcnt*2]; - ptr[1+pixels*1]=src[1+segcnt*2]; - ptr[2+pixels*1]=src[2+segcnt*2]; - ptr[3+pixels*1]=src[3+segcnt*2]; - ptr[0+pixels*2]=src[0+segcnt*1]; - ptr[1+pixels*2]=src[1+segcnt*1]; - ptr[2+pixels*2]=src[2+segcnt*1]; - ptr[3+pixels*2]=src[3+segcnt*1]; - ptr[0+pixels*3]=src[0+segcnt*3]; - ptr[1+pixels*3]=src[1+segcnt*3]; - ptr[2+pixels*3]=src[2+segcnt*3]; - ptr[3+pixels*3]=src[3+segcnt*3]; - break; - } - - /* next shading coefficient */ - ptr+=4; - } - RIE (sanei_genesys_read_register (dev, 0xd0+i, &val)); - addr = val * 8192 + 0x10000000; - status = sanei_genesys_write_ahb (dev->dn, dev->usb_mode, addr, pixels*dev->segnb, buffer); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl124_send_shading_data; write to AHB failed (%s)\n", - sane_strstatus (status)); - return status; - } - } - - free(buffer); - DBGCOMPLETED; - - return status; -} - - -/** @brief move to calibration area - * This functions moves scanning head to calibration area - * by doing a 600 dpi scan - * @param dev scanner device - * @return SANE_STATUS_GOOD on success, else the error code - */ -static SANE_Status -move_to_calibration_area (Genesys_Device * dev) -{ - int pixels; - int size; - uint8_t *line; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - pixels = (dev->sensor.sensor_pixels*600)/dev->sensor.optical_res; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* set up for the calibration scan */ - status = gl124_init_scan_regs (dev, - dev->calib_reg, - 600, - 600, - 0, - 0, - pixels, - 1, - 8, - 3, - dev->settings.scan_method, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - size = pixels * 3; - line = malloc (size); - if (!line) - return SANE_STATUS_NO_MEM; - - /* write registers and scan data */ - RIEF (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS), line); - - DBG (DBG_info, "%s: starting line reading\n", __func__); - RIEF (gl124_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, size), line); - - /* stop scanning */ - RIE (gl124_stop_action (dev)); - - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file ("movetocalarea.pnm", line, 8, 3, pixels, 1); - } - - /* cleanup before return */ - free (line); - - DBGCOMPLETED; - return status; -} - -/* this function does the led calibration by scanning one line of the calibration - area below scanner's top on white strip. - --needs working coarse/gain -*/ -static SANE_Status -gl124_led_calibration (Genesys_Device * dev) -{ - int num_pixels; - int total_size; - int resolution; - int dpihw; - uint8_t *line; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels, depth; - int avg[3]; - int turn; - char fn[20]; - uint16_t exp[3],target; - Sensor_Profile *sensor; - SANE_Bool acceptable; - SANE_Bool half_ccd; - - DBGSTART; - - /* move to calibration area */ - move_to_calibration_area(dev); - - /* offset calibration is always done in 16 bit depth color mode */ - channels = 3; - depth=16; - dpihw=sanei_genesys_compute_dpihw(dev, dev->settings.xres); - half_ccd=compute_half_ccd(dev->model, dev->settings.xres); - if(half_ccd==SANE_TRUE) - { - resolution = dpihw/2; - } - else - { - resolution = dpihw; - } - sensor=get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); - num_pixels = (dev->sensor.sensor_pixels*resolution)/dev->sensor.optical_res; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL124_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* set up for the calibration scan */ - status = gl124_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - num_pixels, - 1, - depth, - channels, - dev->settings.scan_method, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - - /* initial loop values and boundaries */ - exp[0]=sensor->expr; - exp[1]=sensor->expg; - exp[2]=sensor->expb; - target=dev->sensor.gain_white_ref*256; - - turn = 0; - - /* no move during led calibration */ - gl124_set_motor_power (dev->calib_reg, SANE_FALSE); - do - { - /* set up exposure */ - sanei_genesys_set_triple(dev->calib_reg,REG_EXPR,exp[0]); - sanei_genesys_set_triple(dev->calib_reg,REG_EXPG,exp[1]); - sanei_genesys_set_triple(dev->calib_reg,REG_EXPB,exp[2]); - - /* write registers and scan data */ - RIEF (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS), line); - - DBG (DBG_info, "gl124_led_calibration: starting line reading\n"); - RIEF (gl124_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, total_size), line); - - /* stop scanning */ - RIEF (gl124_stop_action (dev), line); - - if (DBG_LEVEL >= DBG_data) - { - snprintf (fn, 20, "led_%02d.pnm", turn); - sanei_genesys_write_pnm_file (fn, line, depth, channels, num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG (DBG_info, "gl124_led_calibration: average: %d,%d,%d\n", avg[0], avg[1], avg[2]); - - /* check if exposure gives average within the boundaries */ - acceptable = SANE_TRUE; - for(i=0;i<3;i++) - { - /* we accept +- 2% delta from target */ - if(abs(avg[i]-target)>target/50) - { - exp[i]=(exp[i]*target)/avg[i]; - acceptable = SANE_FALSE; - } - } - - turn++; - } - while (!acceptable && turn < 100); - - DBG (DBG_info, "gl124_led_calibration: acceptable exposure: %d,%d,%d\n", exp[0], exp[1], exp[2]); - - /* set these values as final ones for scan */ - sanei_genesys_set_triple(dev->reg,REG_EXPR,exp[0]); - sanei_genesys_set_triple(dev->reg,REG_EXPG,exp[1]); - sanei_genesys_set_triple(dev->reg,REG_EXPB,exp[2]); - - /* store in this struct since it is the one used by cache calibration */ - dev->sensor.regs_0x10_0x1d[0] = (exp[0] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[1] = exp[0] & 0xff; - dev->sensor.regs_0x10_0x1d[2] = (exp[1] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[3] = exp[1] & 0xff; - dev->sensor.regs_0x10_0x1d[4] = (exp[2] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[5] = exp[2] & 0xff; - - /* cleanup before return */ - free (line); - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a 8 bits scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black) -{ - unsigned int i, j, k, average, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average value on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG (DBG_info, "dark_average: avg[%d] = %d\n", k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG (DBG_info, "dark_average: average = %d\n", average); - return average; -} - - -static SANE_Status -gl124_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *first_line, *second_line, reg0a; - unsigned int channels, bpp; - char title[32]; - int pass = 0, avg, total_size; - int topavg, bottomavg, resolution, lines; - int top, bottom, black_pixels, pixels; - - DBGSTART; - - /* no gain nor offset for TI AFE */ - RIE (sanei_genesys_read_register (dev, REG0A, ®0a)); - if(((reg0a & REG0A_SIFSEL)>>REG0AS_SIFSEL)==3) - { - DBGCOMPLETED; - return status; - } - - /* offset calibration is always done in color mode */ - channels = 3; - resolution=dev->sensor.optical_res; - dev->calib_pixels = dev->sensor.sensor_pixels; - lines=1; - bpp=8; - pixels= (dev->sensor.sensor_pixels*resolution) / dev->sensor.optical_res; - black_pixels = (dev->sensor.black_pixels * resolution) / dev->sensor.optical_res; - DBG (DBG_io2, "gl124_offset_calibration: black_pixels=%d\n", black_pixels); - - status = gl124_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - pixels, - lines, - bpp, - channels, - dev->settings.scan_method, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_offset_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - gl124_set_motor_power (dev->calib_reg, SANE_FALSE); - - /* allocate memory for scans */ - total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ - - first_line = malloc (total_size); - if (!first_line) - return SANE_STATUS_NO_MEM; - - second_line = malloc (total_size); - if (!second_line) - { - free (first_line); - return SANE_STATUS_NO_MEM; - } - - /* init gain */ - dev->frontend.gain[0] = 0; - dev->frontend.gain[1] = 0; - dev->frontend.gain[2] = 0; - - /* scan with no move */ - bottom = 10; - dev->frontend.offset[0] = bottom; - dev->frontend.offset[1] = bottom; - dev->frontend.offset[2] = bottom; - - RIEF2 (gl124_set_fe(dev, AFE_SET), first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl124_offset_calibration: starting first line reading\n"); - RIEF2 (gl124_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, first_line, total_size), first_line, second_line); - if (DBG_LEVEL >= DBG_data) - { - snprintf(title,20,"offset%03d.pnm",bottom); - sanei_genesys_write_pnm_file (title, first_line, bpp, channels, pixels, lines); - } - - bottomavg = dark_average (first_line, pixels, lines, channels, black_pixels); - DBG (DBG_io2, "gl124_offset_calibration: bottom avg=%d\n", bottomavg); - - /* now top value */ - top = 255; - dev->frontend.offset[0] = top; - dev->frontend.offset[1] = top; - dev->frontend.offset[2] = top; - RIEF2 (gl124_set_fe(dev, AFE_SET), first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl124_offset_calibration: starting second line reading\n"); - RIEF2 (gl124_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); - - topavg = dark_average (second_line, pixels, lines, channels, black_pixels); - DBG (DBG_io2, "gl124_offset_calibration: top avg=%d\n", topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.offset[0] = (top + bottom) / 2; - dev->frontend.offset[1] = (top + bottom) / 2; - dev->frontend.offset[2] = (top + bottom) / 2; - - /* scan with no move */ - RIEF2 (gl124_set_fe(dev, AFE_SET), first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl124_offset_calibration: starting second line reading\n"); - RIEF2 (gl124_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", dev->frontend.offset[1]); - sanei_genesys_write_pnm_file (title, second_line, bpp, channels, pixels, lines); - } - - avg = dark_average (second_line, pixels, lines, channels, black_pixels); - DBG (DBG_info, "gl124_offset_calibration: avg=%d offset=%d\n", avg, - dev->frontend.offset[1]); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.offset[1]; - } - else - { - bottomavg = avg; - bottom = dev->frontend.offset[1]; - } - } - DBG (DBG_info, "gl124_offset_calibration: offset=(%d,%d,%d)\n", dev->frontend.offset[0], dev->frontend.offset[1], dev->frontend.offset[2]); - - /* cleanup before return */ - free (first_line); - free (second_line); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* alternative coarse gain calibration - this on uses the settings from offset_calibration and - uses only one scanline - */ -/* - with offset and coarse calibration we only want to get our input range into - a reasonable shape. the fine calibration of the upper and lower bounds will - be done with shading. - */ -static SANE_Status -gl124_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - int pixels; - int total_size; - uint8_t *line, reg0a; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3],coeff; - int val, code, lines; - int resolution; - int bpp; - - DBG (DBG_proc, "gl124_coarse_gain_calibration: dpi = %d\n", dpi); - - /* no gain nor offset for TI AFE */ - RIE (sanei_genesys_read_register (dev, REG0A, ®0a)); - if(((reg0a & REG0A_SIFSEL)>>REG0AS_SIFSEL)==3) - { - DBGCOMPLETED; - return status; - } - - /* coarse gain calibration is always done in color mode */ - channels = 3; - - /* follow CKSEL */ - if(dev->settings.xressensor.optical_res) - { - coeff=0.9; - /*resolution=dev->sensor.optical_res/2;*/ - resolution=dev->sensor.optical_res; - } - else - { - resolution=dev->sensor.optical_res; - coeff=1.0; - } - lines=10; - bpp=8; - pixels = (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - - status = gl124_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - pixels, - lines, - bpp, - channels, - dev->settings.scan_method, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - gl124_set_motor_power (dev->calib_reg, SANE_FALSE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_coarse_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - RIE (dev->model->cmd_set->bulk_write_register - (dev, dev->calib_reg, GENESYS_GL124_MAX_REGS)); - - total_size = pixels * channels * (16/bpp) * lines; - - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - - RIEF (gl124_set_fe(dev, AFE_SET), line); - RIEF (gl124_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, total_size), line); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("coarse.pnm", line, bpp, channels, pixels, lines); - - /* average value on each channel */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = pixels/4; i < (pixels*3/4); i++) - { - if(bpp==16) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * pixels + 1] * 256 + - line[i * 2 + j * 2 * pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - } - else - { - if (dev->model->is_cis) - val = line[i + j * pixels]; - else - val = line[i * channels + j]; - } - - max[j] += val; - } - max[j] = max[j] / (pixels/2); - - gain[j] = ((float) dev->sensor.gain_white_ref*coeff) / max[j]; - - /* turn logical gain value into gain code, checking for overflow */ - code = 283 - 208 / gain[j]; - if (code > 255) - code = 255; - else if (code < 0) - code = 0; - dev->frontend.gain[j] = code; - - DBG (DBG_proc, - "gl124_coarse_gain_calibration: channel %d, max=%d, gain = %f, setting:%d\n", - j, max[j], gain[j], dev->frontend.gain[j]); - } - - if (dev->model->is_cis) - { - if (dev->frontend.gain[0] > dev->frontend.gain[1]) - dev->frontend.gain[0] = dev->frontend.gain[1]; - if (dev->frontend.gain[0] > dev->frontend.gain[2]) - dev->frontend.gain[0] = dev->frontend.gain[2]; - dev->frontend.gain[2] = dev->frontend.gain[1] = dev->frontend.gain[0]; - } - - if (channels == 1) - { - dev->frontend.gain[0] = dev->frontend.gain[1]; - dev->frontend.gain[2] = dev->frontend.gain[1]; - } - - free (line); - - RIE (gl124_stop_action (dev)); - - status = gl124_slow_back_home (dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - -/* - * wait for lamp warmup by scanning the same line until difference - * between 2 scans is below a threshold - */ -static SANE_Status -gl124_init_regs_for_warmup (Genesys_Device * dev, - Genesys_Register_Set * reg, - int *channels, int *total_size) -{ - int num_pixels; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - if (dev == NULL || reg == NULL || channels == NULL || total_size == NULL) - return SANE_STATUS_INVAL; - - *channels=3; - - memcpy (reg, dev->reg, (GENESYS_GL124_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - status = gl124_init_scan_regs (dev, - reg, - dev->sensor.optical_res, - dev->motor.base_ydpi, - dev->sensor.sensor_pixels/4, - 0, - dev->sensor.sensor_pixels/2, - 1, - 8, - *channels, - dev->settings.scan_method, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl124_init_regs_for_warmup: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - num_pixels = dev->current_setup.pixels; - - *total_size = num_pixels * 3 * 1; /* colors * bytes_per_color * scan lines */ - - gl124_set_motor_power (reg, SANE_FALSE); - RIE (dev->model->cmd_set->bulk_write_register (dev, reg, GENESYS_GL124_MAX_REGS)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief default GPIO values - * set up GPIO/GPOE for idle state - * @param dev device to set up - * @return SANE_STATUS_GOOD unless a GPIO register cannot be written - */ -static SANE_Status -gl124_init_gpio (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx; - - DBGSTART; - - /* per model GPIO layout */ - if (strcmp (dev->model->name, "canon-lide-110") == 0) - { - idx = 0; - } - else if (strcmp (dev->model->name, "canon-lide-110") == 0) - { - idx = 2; - } - else - { /* canon LiDE 210 and 220 case */ - idx = 1; - } - - RIE (sanei_genesys_write_register (dev, REG31, gpios[idx].r31)); - RIE (sanei_genesys_write_register (dev, REG32, gpios[idx].r32)); - RIE (sanei_genesys_write_register (dev, REG33, gpios[idx].r33)); - RIE (sanei_genesys_write_register (dev, REG34, gpios[idx].r34)); - RIE (sanei_genesys_write_register (dev, REG35, gpios[idx].r35)); - RIE (sanei_genesys_write_register (dev, REG36, gpios[idx].r36)); - RIE (sanei_genesys_write_register (dev, REG38, gpios[idx].r38)); - - DBGCOMPLETED; - return status; -} - -/** - * set memory layout by filling values in dedicated registers - */ -static SANE_Status -gl124_init_memory_layout (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx = 0; - - DBGSTART; - - /* point to per model memory layout */ - if ((strcmp (dev->model->name, "canon-lide-110") == 0) - ||(strcmp (dev->model->name, "canon-lide-120") == 0)) - { - idx = 0; - } - else - { /* canon LiDE 210 and 220 case */ - idx = 1; - } - - /* setup base address for shading data. */ - /* values must be multiplied by 8192=0x4000 to give address on AHB */ - /* R-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd0, layouts[idx].rd0); - /* G-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd1, layouts[idx].rd1); - /* B-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd2, layouts[idx].rd2); - - /* setup base address for scanned data. */ - /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ - /* R-Channel ODD image buffer 0x0124->0x92000 */ - /* size for each buffer is 0x16d*1k word */ - sanei_genesys_write_register (dev, 0xe0, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xe1, layouts[idx].re1); - /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ - sanei_genesys_write_register (dev, 0xe2, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xe3, layouts[idx].re3); - - /* R-Channel EVEN image buffer 0x0292 */ - sanei_genesys_write_register (dev, 0xe4, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xe5, layouts[idx].re5); - /* R-Channel EVEN image buffer end-address 0x03ff*/ - sanei_genesys_write_register (dev, 0xe6, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xe7, layouts[idx].re7); - - /* same for green, since CIS, same addresses */ - sanei_genesys_write_register (dev, 0xe8, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xe9, layouts[idx].re1); - sanei_genesys_write_register (dev, 0xea, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xeb, layouts[idx].re3); - sanei_genesys_write_register (dev, 0xec, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xed, layouts[idx].re5); - sanei_genesys_write_register (dev, 0xee, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xef, layouts[idx].re7); - -/* same for blue, since CIS, same addresses */ - sanei_genesys_write_register (dev, 0xf0, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xf1, layouts[idx].re1); - sanei_genesys_write_register (dev, 0xf2, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xf3, layouts[idx].re3); - sanei_genesys_write_register (dev, 0xf4, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xf5, layouts[idx].re5); - sanei_genesys_write_register (dev, 0xf6, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xf7, layouts[idx].re7); - - DBGCOMPLETED; - return status; -} - -/** - * initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl124_init (Genesys_Device * dev) -{ - SANE_Status status; - - DBG_INIT (); - DBGSTART; - - status=sanei_genesys_asic_init(dev, GENESYS_GL124_MAX_REGS); - - DBGCOMPLETED; - return status; -} - - -/* * - * initialize ASIC from power on condition - */ -static SANE_Status -gl124_boot (Genesys_Device * dev, SANE_Bool cold) -{ - SANE_Status status; - uint8_t val; - - DBGSTART; - - /* reset ASIC in case of cold boot */ - if(cold) - { - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - } - - /* enable GPOE 17 */ - RIE (sanei_genesys_write_register (dev, 0x36, 0x01)); - - /* set GPIO 17 */ - RIE (sanei_genesys_read_register (dev, 0x33, &val)); - val |= 0x01; - RIE (sanei_genesys_write_register (dev, 0x33, val)); - - /* test CHKVER */ - RIE (sanei_genesys_read_register (dev, REG100, &val)); - if (val & REG100_CHKVER) - { - RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG (DBG_info, - "gl124_cold_boot: reported version for genesys chip is 0x%02x\n", - val); - } - - /* Set default values for registers */ - gl124_init_registers (dev); - - /* Write initial registers */ - RIE (dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL124_MAX_REGS)); - - /* tune reg 0B */ - val = REG0B_30MHZ | REG0B_ENBDRAM | REG0B_64M; - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg[reg_0x0b].address = 0x00; - - /* set up end access */ - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0b)); - RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); - - /* CIS_LINE */ - SETREG (0x08, REG08_CIS_LINE); - RIE (sanei_genesys_write_register (dev, 0x08, dev->reg[reg_0x08].value)); - - /* setup gpio */ - RIE (gl124_init_gpio (dev)); - - /* setup internal memory layout */ - RIE (gl124_init_memory_layout (dev)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl124_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not loose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val=0; - - RIE (sanei_genesys_read_register (s->dev, REG31, &val)); - - /* TODO : for the next scanner special case, - * add another per scanner button profile struct to avoid growing - * hard-coded button mapping here. - */ - if((s->dev->model->gpo_type == GPO_CANONLIDE110) - ||(s->dev->model->gpo_type == GPO_CANONLIDE120)) - { - if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) - s->val[OPT_SCAN_SW].b = (val & 0x01) == 0; - if (s->val[OPT_FILE_SW].b == s->last_val[OPT_FILE_SW].b) - s->val[OPT_FILE_SW].b = (val & 0x08) == 0; - if (s->val[OPT_EMAIL_SW].b == s->last_val[OPT_EMAIL_SW].b) - s->val[OPT_EMAIL_SW].b = (val & 0x04) == 0; - if (s->val[OPT_COPY_SW].b == s->last_val[OPT_COPY_SW].b) - s->val[OPT_COPY_SW].b = (val & 0x02) == 0; - } - else - { /* LiDE 210 case */ - if (s->val[OPT_EXTRA_SW].b == s->last_val[OPT_EXTRA_SW].b) - s->val[OPT_EXTRA_SW].b = (val & 0x01) == 0; - if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) - s->val[OPT_SCAN_SW].b = (val & 0x02) == 0; - if (s->val[OPT_COPY_SW].b == s->last_val[OPT_COPY_SW].b) - s->val[OPT_COPY_SW].b = (val & 0x04) == 0; - if (s->val[OPT_EMAIL_SW].b == s->last_val[OPT_EMAIL_SW].b) - s->val[OPT_EMAIL_SW].b = (val & 0x08) == 0; - if (s->val[OPT_FILE_SW].b == s->last_val[OPT_FILE_SW].b) - s->val[OPT_FILE_SW].b = (val & 0x10) == 0; - } - return status; -} - - -/** the gl124 command set */ -static Genesys_Command_Set gl124_cmd_set = { - "gl124-generic", /* the name of this set */ - - gl124_init, - gl124_init_regs_for_warmup, - gl124_init_regs_for_coarse_calibration, - gl124_init_regs_for_shading, - gl124_init_regs_for_scan, - - gl124_get_filter_bit, - gl124_get_lineart_bit, - gl124_get_bitset_bit, - gl124_get_gain4_bit, - gl124_get_fast_feed_bit, - gl124_test_buffer_empty_bit, - gl124_test_motor_flag_bit, - - gl124_bulk_full_size, - - gl124_set_fe, - gl124_set_powersaving, - gl124_save_power, - - gl124_set_motor_power, - gl124_set_lamp_power, - - gl124_begin_scan, - gl124_end_scan, - - sanei_genesys_send_gamma_table, - - gl124_search_start_position, - - gl124_offset_calibration, - gl124_coarse_gain_calibration, - gl124_led_calibration, - - gl124_slow_back_home, - gl124_rewind, - - sanei_genesys_bulk_write_register, - NULL, - gl124_bulk_read_data, - - gl124_update_hardware_sensors, - - /* no sheetfed support for now */ - NULL, - NULL, - NULL, - NULL, - - sanei_genesys_is_compatible_calibration, - NULL, - gl124_send_shading_data, - gl124_calculate_current_setup, - gl124_boot, - gl124_init_scan_regs -}; - -SANE_Status -sanei_gl124_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl124_cmd_set; - return SANE_STATUS_GOOD; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl124.cc b/backend/genesys_gl124.cc new file mode 100644 index 0000000..a535d58 --- /dev/null +++ b/backend/genesys_gl124.cc @@ -0,0 +1,3592 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2016 Stéphane Voltz + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_gl124.h" + +#include + +/**************************************************************************** + Mid level functions + ****************************************************************************/ + +static SANE_Bool gl124_get_fast_feed_bit(Genesys_Register_Set* regs) +{ + return (bool)(regs->get8(REG02) & REG02_FASTFED); +} + +static SANE_Bool gl124_get_filter_bit(Genesys_Register_Set* regs) +{ + return (bool)(regs->get8(REG04) & REG04_FILTER); +} + +static SANE_Bool gl124_get_lineart_bit(Genesys_Register_Set* regs) +{ + return (bool)(regs->get8(REG04) & REG04_LINEART); +} + +static SANE_Bool gl124_get_bitset_bit(Genesys_Register_Set* regs) +{ + return (bool)(regs->get8(REG04) & REG04_BITSET); +} + +static SANE_Bool gl124_get_gain4_bit (Genesys_Register_Set * regs) +{ + return (bool)(regs->get8(REG06) & REG06_GAIN4); +} + +static SANE_Bool +gl124_test_buffer_empty_bit (SANE_Byte val) +{ + if (val & BUFEMPTY) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl124_test_motor_flag_bit (SANE_Byte val) +{ + if (val & MOTORENB) + return SANE_TRUE; + return SANE_FALSE; +} + +/** @brief sensor profile + * search for the database of motor profiles and get the best one. Each + * profile is at a specific dpihw. Use LiDE 110 table by default. + * @param sensor_type sensor id + * @param dpi hardware dpi for the scan + * @param half_ccd flag to signal half ccd mode + * @return a pointer to a Sensor_Profile struct + */ +static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi, int half_ccd) +{ + unsigned int i; + int idx; + + i=0; + idx=-1; + while(i=dpi + && sensors[i].dpi 1) + { + return SANE_TRUE; + } + return SANE_FALSE; +} + +/** @brief set all registers to default values . + * This function is called only once at the beginning and + * fills register startup values for registers reused across scans. + * Those that are rarely modified or not modified are written + * individually. + * @param dev device structure holding register set to initialize + */ +static void +gl124_init_registers (Genesys_Device * dev) +{ + DBGSTART; + + dev->reg.clear(); + + /* default to LiDE 110 */ + SETREG (0x01,0xa2); /* + REG01_SHDAREA */ + SETREG (0x02,0x90); + SETREG (0x03,0x50); + SETREG (0x04,0x03); + SETREG (0x05,0x00); + if(dev->model->ccd_type==CIS_CANONLIDE120) + { + SETREG (0x06,0x50); + SETREG (0x07,0x00); + } + else + { + SETREG (0x03,0x50 & ~REG03_AVEENB); + SETREG (0x06,0x50 | REG06_GAIN4); + } + SETREG (0x09,0x00); + SETREG (0x0a,0xc0); + SETREG (0x0b,0x2a); + SETREG (0x0c,0x12); + SETREG (0x11,0x00); + SETREG (0x12,0x00); + SETREG (0x13,0x0f); + SETREG (0x14,0x00); + SETREG (0x15,0x80); + SETREG (0x16,0x10); + SETREG (0x17,0x04); + SETREG (0x18,0x00); + SETREG (0x19,0x01); + SETREG (0x1a,0x30); + SETREG (0x1b,0x00); + SETREG (0x1c,0x00); + SETREG (0x1d,0x01); + SETREG (0x1e,0x10); + SETREG (0x1f,0x00); + SETREG (0x20,0x15); + SETREG (0x21,0x00); + if(dev->model->ccd_type!=CIS_CANONLIDE120) + { + SETREG (0x22,0x02); + } + else + { + SETREG (0x22,0x14); + } + SETREG (0x23,0x00); + SETREG (0x24,0x00); + SETREG (0x25,0x00); + SETREG (0x26,0x0d); + SETREG (0x27,0x48); + SETREG (0x28,0x00); + SETREG (0x29,0x56); + SETREG (0x2a,0x5e); + SETREG (0x2b,0x02); + SETREG (0x2c,0x02); + SETREG (0x2d,0x58); + SETREG (0x3b,0x00); + SETREG (0x3c,0x00); + SETREG (0x3d,0x00); + SETREG (0x3e,0x00); + SETREG (0x3f,0x02); + SETREG (0x40,0x00); + SETREG (0x41,0x00); + SETREG (0x42,0x00); + SETREG (0x43,0x00); + SETREG (0x44,0x00); + SETREG (0x45,0x00); + SETREG (0x46,0x00); + SETREG (0x47,0x00); + SETREG (0x48,0x00); + SETREG (0x49,0x00); + SETREG (0x4f,0x00); + SETREG (0x52,0x00); + SETREG (0x53,0x02); + SETREG (0x54,0x04); + SETREG (0x55,0x06); + SETREG (0x56,0x04); + SETREG (0x57,0x04); + SETREG (0x58,0x04); + SETREG (0x59,0x04); + SETREG (0x5a,0x1a); + SETREG (0x5b,0x00); + SETREG (0x5c,0xc0); + SETREG (0x5f,0x00); + SETREG (0x60,0x02); + SETREG (0x61,0x00); + SETREG (0x62,0x00); + SETREG (0x63,0x00); + SETREG (0x64,0x00); + SETREG (0x65,0x00); + SETREG (0x66,0x00); + SETREG (0x67,0x00); + SETREG (0x68,0x00); + SETREG (0x69,0x00); + SETREG (0x6a,0x00); + SETREG (0x6b,0x00); + SETREG (0x6c,0x00); + SETREG (0x6e,0x00); + SETREG (0x6f,0x00); + if(dev->model->ccd_type!=CIS_CANONLIDE120) + { + SETREG (0x6d,0xd0); + SETREG (0x71,0x08); + } + else + { + SETREG (0x6d,0x00); + SETREG (0x71,0x1f); + } + SETREG (0x70,0x00); + SETREG (0x72,0x08); + SETREG (0x73,0x0a); + + /* CKxMAP */ + SETREG (0x74,0x00); + SETREG (0x75,0x00); + SETREG (0x76,0x3c); + SETREG (0x77,0x00); + SETREG (0x78,0x00); + SETREG (0x79,0x9f); + SETREG (0x7a,0x00); + SETREG (0x7b,0x00); + SETREG (0x7c,0x55); + + SETREG (0x7d,0x00); + SETREG (0x7e,0x08); + SETREG (0x7f,0x58); + if(dev->model->ccd_type!=CIS_CANONLIDE120) + { + SETREG (0x80,0x00); + SETREG (0x81,0x14); + } + else + { + SETREG (0x80,0x00); + SETREG (0x81,0x10); + } + + /* STRPIXEL */ + SETREG (0x82,0x00); + SETREG (0x83,0x00); + SETREG (0x84,0x00); + /* ENDPIXEL */ + SETREG (0x85,0x00); + SETREG (0x86,0x00); + SETREG (0x87,0x00); + + SETREG (0x88,0x00); + SETREG (0x89,0x65); + SETREG (0x8a,0x00); + SETREG (0x8b,0x00); + SETREG (0x8c,0x00); + SETREG (0x8d,0x00); + SETREG (0x8e,0x00); + SETREG (0x8f,0x00); + SETREG (0x90,0x00); + SETREG (0x91,0x00); + SETREG (0x92,0x00); + SETREG (0x93,0x00); + SETREG (0x94,0x14); + SETREG (0x95,0x30); + SETREG (0x96,0x00); + SETREG (0x97,0x90); + SETREG (0x98,0x01); + SETREG (0x99,0x1f); + SETREG (0x9a,0x00); + SETREG (0x9b,0x80); + SETREG (0x9c,0x80); + SETREG (0x9d,0x3f); + SETREG (0x9e,0x00); + SETREG (0x9f,0x00); + SETREG (0xa0,0x20); + SETREG (0xa1,0x30); + SETREG (0xa2,0x00); + SETREG (0xa3,0x20); + SETREG (0xa4,0x01); + SETREG (0xa5,0x00); + SETREG (0xa6,0x00); + SETREG (0xa7,0x08); + SETREG (0xa8,0x00); + SETREG (0xa9,0x08); + SETREG (0xaa,0x01); + SETREG (0xab,0x00); + SETREG (0xac,0x00); + SETREG (0xad,0x40); + SETREG (0xae,0x01); + SETREG (0xaf,0x00); + SETREG (0xb0,0x00); + SETREG (0xb1,0x40); + SETREG (0xb2,0x00); + SETREG (0xb3,0x09); + SETREG (0xb4,0x5b); + SETREG (0xb5,0x00); + SETREG (0xb6,0x10); + SETREG (0xb7,0x3f); + SETREG (0xb8,0x00); + SETREG (0xbb,0x00); + SETREG (0xbc,0xff); + SETREG (0xbd,0x00); + SETREG (0xbe,0x07); + SETREG (0xc3,0x00); + SETREG (0xc4,0x00); + + /* gamma + SETREG (0xc5,0x00); + SETREG (0xc6,0x00); + SETREG (0xc7,0x00); + SETREG (0xc8,0x00); + SETREG (0xc9,0x00); + SETREG (0xca,0x00); + SETREG (0xcb,0x00); + SETREG (0xcc,0x00); + SETREG (0xcd,0x00); + SETREG (0xce,0x00); + */ + if(dev->model->ccd_type==CIS_CANONLIDE120) + { + SETREG (0xc5,0x20); + SETREG (0xc6,0xeb); + SETREG (0xc7,0x20); + SETREG (0xc8,0xeb); + SETREG (0xc9,0x20); + SETREG (0xca,0xeb); + } + + /* memory layout + SETREG (0xd0,0x0a); + SETREG (0xd1,0x1f); + SETREG (0xd2,0x34); */ + SETREG (0xd3,0x00); + SETREG (0xd4,0x00); + SETREG (0xd5,0x00); + SETREG (0xd6,0x00); + SETREG (0xd7,0x00); + SETREG (0xd8,0x00); + SETREG (0xd9,0x00); + + /* memory layout + SETREG (0xe0,0x00); + SETREG (0xe1,0x48); + SETREG (0xe2,0x15); + SETREG (0xe3,0x90); + SETREG (0xe4,0x15); + SETREG (0xe5,0x91); + SETREG (0xe6,0x2a); + SETREG (0xe7,0xd9); + SETREG (0xe8,0x2a); + SETREG (0xe9,0xad); + SETREG (0xea,0x40); + SETREG (0xeb,0x22); + SETREG (0xec,0x40); + SETREG (0xed,0x23); + SETREG (0xee,0x55); + SETREG (0xef,0x6b); + SETREG (0xf0,0x55); + SETREG (0xf1,0x6c); + SETREG (0xf2,0x6a); + SETREG (0xf3,0xb4); + SETREG (0xf4,0x6a); + SETREG (0xf5,0xb5); + SETREG (0xf6,0x7f); + SETREG (0xf7,0xfd);*/ + + SETREG (0xf8,0x01); /* other value is 0x05 */ + SETREG (0xf9,0x00); + SETREG (0xfa,0x00); + SETREG (0xfb,0x00); + SETREG (0xfc,0x00); + SETREG (0xff,0x00); + + /* fine tune upon device description */ + dev->reg.find_reg(0x05).value &= ~REG05_DPIHW; + switch (sanei_genesys_find_sensor_any(dev).optical_res) + { + case 600: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; + break; + case 1200: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; + break; + case 2400: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; + break; + case 4800: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_4800; + break; + } + + dev->calib_reg = dev->reg; + + DBGCOMPLETED; +} + +/**@brief send slope table for motor movement + * Send slope_table in machine byte order + * @param dev device to send slope table + * @param table_nr index of the slope table in ASIC memory + * Must be in the [0-4] range. + * @param slope_table pointer to 16 bit values array of the slope table + * @param steps number of elemnts in the slope table + */ +static SANE_Status +gl124_send_slope_table (Genesys_Device * dev, int table_nr, + uint16_t * slope_table, int steps) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + char msg[10000]; + + DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, + table_nr, steps); + + /* sanity check */ + if(table_nr<0 || table_nr>4) + { + DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); + return SANE_STATUS_INVAL; + } + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + sprintf (msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) + { + sprintf (msg+strlen(msg), ",%d", slope_table[i]); + } + DBG (DBG_io, "%s: %s\n", __func__, msg); + } + + /* slope table addresses are fixed */ + status = sanei_genesys_write_ahb(dev, 0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: write to AHB failed writing slope table %d (%s)\n", + __func__, table_nr, sane_strstatus (status)); + } + + DBGCOMPLETED; + return status; +} + +/** @brief * Set register values of 'special' ti type frontend + * Registers value are taken from the frontend register data + * set. + * @param dev device owning the AFE + * @param set flag AFE_INIT to specify the AFE must be reset before writing data + * */ +static SANE_Status +gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + + DBGSTART; + if (set == AFE_INIT) + { + DBG (DBG_proc, "%s: setting DAC %u\n", __func__, dev->model->dac_type); + + dev->frontend = dev->frontend_initial; + } + + /* start writing to DAC */ + status = sanei_genesys_fe_write_data (dev, 0x00, 0x80); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, + sane_strstatus (status)); + return status; + } + + /* write values to analog frontend */ + for (uint16_t addr = 0x01; addr < 0x04; addr++) + { + status = sanei_genesys_fe_write_data(dev, addr, dev->frontend.regs.get_value(addr)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write reg %d: %s\n", __func__, addr, + sane_strstatus(status)); + return status; + } + } + + status = sanei_genesys_fe_write_data (dev, 0x04, 0x00); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to write reg4: %s\n", __func__, + sane_strstatus (status)); + return status; + } + + /* these are not really sign for this AFE */ + for (i = 0; i < 3; i++) + { + status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.regs.get_value(0x24 + i)); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to write reg %d: %s\n", __func__, i+5, + sane_strstatus (status)); + return status; + } + } + + /* close writing to DAC */ + if(dev->model->dac_type == DAC_CANONLIDE120) + { + status = sanei_genesys_fe_write_data (dev, 0x00, 0x01); + } + else + { + status = sanei_genesys_fe_write_data (dev, 0x00, 0x11); + } + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, + sane_strstatus (status)); + return status; + } + + DBGCOMPLETED; + + return status; +} + + +/* Set values of analog frontend */ +static SANE_Status +gl124_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) +{ + (void) sensor; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + DBG(DBG_proc, "%s (%s)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == + AFE_POWER_SAVE ? "powersave" : "huh?"); + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + dev->frontend = dev->frontend_initial; + } + + RIE (sanei_genesys_read_register (dev, REG0A, &val)); + + /* route to correct analog FE */ + switch ((val & REG0A_SIFSEL)>>REG0AS_SIFSEL) + { + case 3: + status=gl124_set_ti_fe (dev, set); + break; + case 0: + case 1: + case 2: + default: + DBG(DBG_error, "%s: unsupported analog FE 0x%02x\n", __func__, val); + status=SANE_STATUS_INVAL; + break; + } + + DBGCOMPLETED; + return status; +} + + +/**@brief compute exposure to use + * compute the sensor exposure based on target resolution + * @param dev pointer to device description + * @param xres sensor's required resolution + * @param half_ccd flag for half ccd mode + */ +static int gl124_compute_exposure(Genesys_Device *dev, int xres, int half_ccd) +{ + Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, xres, half_ccd); + return sensor_profile->exposure; +} + + +static SANE_Status +gl124_init_motor_regs_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int scan_exposure_time, + float scan_yres, + int scan_step_type, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + ScanColorMode scan_mode, + unsigned int flags) +{ + SANE_Status status = SANE_STATUS_GOOD; + int use_fast_fed; + unsigned int lincnt, fast_dpi; + uint16_t scan_table[SLOPE_TABLE_SIZE]; + uint16_t fast_table[SLOPE_TABLE_SIZE]; + int scan_steps,fast_steps,factor; + unsigned int feedl,dist; + uint32_t z1, z2; + float yres; + int min_speed; + unsigned int linesel; + + DBGSTART; + DBG(DBG_info, "%s : scan_exposure_time=%d, scan_yres=%g, scan_step_type=%d, scan_lines=%d, " + "scan_dummy=%d, feed_steps=%d, scan_mode=%d, flags=%x\n", __func__, scan_exposure_time, + scan_yres, scan_step_type, scan_lines, scan_dummy, feed_steps, + static_cast(scan_mode), flags); + + /* we never use fast fed since we do manual feed for the scans */ + use_fast_fed=0; + factor=1; + + /* enforce motor minimal scan speed + * @TODO extend motor struct for this value */ + if (scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + min_speed = 900; + } + else + { + switch(dev->model->motor_type) + { + case MOTOR_CANONLIDE110: + min_speed = 600; + break; + case MOTOR_CANONLIDE120: + min_speed = 900; + break; + default: + min_speed = 900; + break; + } + } + + /* compute min_speed and linesel */ + if(scan_yres 0 */ + if(linesel==0) + { + linesel=1; + yres=scan_yres*2; + } + } + else + { + yres=scan_yres; + linesel=0; + } + + DBG (DBG_io2, "%s: final yres=%f, linesel=%d\n", __func__, yres, linesel); + + lincnt=scan_lines*(linesel+1); + sanei_genesys_set_triple(reg,REG_LINCNT,lincnt); + DBG (DBG_io, "%s: lincnt=%d\n", __func__, lincnt); + + /* compute register 02 value */ + uint8_t r02 = REG02_NOTHOME; + + if (use_fast_fed) { + r02 |= REG02_FASTFED; + } else { + r02 &= ~REG02_FASTFED; + } + + if (flags & MOTOR_FLAG_AUTO_GO_HOME) + r02 |= REG02_AGOHOME; + + if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) + ||(yres>=sensor.optical_res)) + { + r02 |= REG02_ACDCDIS; + } + + reg->set8(REG02, r02); + sanei_genesys_set_motor_power(*reg, true); + + /* SCANFED */ + sanei_genesys_set_double(reg,REG_SCANFED,4); + + /* scan and backtracking slope table */ + sanei_genesys_slope_table(scan_table, + &scan_steps, + yres, + scan_exposure_time, + dev->motor.base_ydpi, + scan_step_type, + factor, + dev->model->motor_type, + motors); + RIE(gl124_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps)); + RIE(gl124_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps)); + + /* STEPNO */ + sanei_genesys_set_double(reg,REG_STEPNO,scan_steps); + + /* fast table */ + fast_dpi=yres; + + /* + if (scan_mode != ScanColorMode::COLOR_SINGLE_PASS) + { + fast_dpi*=3; + } + */ + sanei_genesys_slope_table(fast_table, + &fast_steps, + fast_dpi, + scan_exposure_time, + dev->motor.base_ydpi, + scan_step_type, + factor, + dev->model->motor_type, + motors); + RIE(gl124_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps)); + RIE(gl124_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps)); + + /* FASTNO */ + sanei_genesys_set_double(reg,REG_FASTNO,fast_steps); + + /* FSHDEC */ + sanei_genesys_set_double(reg,REG_FSHDEC,fast_steps); + + /* FMOVNO */ + sanei_genesys_set_double(reg,REG_FMOVNO,fast_steps); + + /* substract acceleration distance from feedl */ + feedl=feed_steps; + feedl<<=scan_step_type; + + dist = scan_steps; + if (flags & MOTOR_FLAG_FEED) + dist *=2; + if (use_fast_fed) + { + dist += fast_steps*2; + } + DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + /* get sure we don't use insane value */ + if(distset8_mask(REG1D, linesel, REG1D_LINESEL); + reg->set8(REGA0, (scan_step_type << REGA0S_STEPSEL) | (scan_step_type << REGA0S_FSTPSEL)); + + /* FMOVDEC */ + sanei_genesys_set_double(reg,REG_FMOVDEC,fast_steps); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** @brief copy sensor specific settings + * Set up register set for the given sensor resolution. Values are from the device table + * in genesys_devices.c for registers: + * [0x16 ... 0x1d] + * [0x52 ... 0x5e] + * Other come from the specific device sensor table in genesys_gl124.h: + * 0x18, 0x20, 0x61, 0x98 and + * @param dev device to set up + * @param regs register set to modify + * @param dpi resolution of the sensor during scan + * @param half_ccd flag for half ccd mode + * */ +static void gl124_setup_sensor(Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * regs, int dpi, int half_ccd) +{ + int dpihw; + uint32_t exp; + + DBGSTART; + + // we start at 6, 0-5 is a 16 bits cache for exposure + for (uint16_t addr = 0x16; addr < 0x1e; addr++) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + // skip writing 5d,5e which is AFE address because + // they are not defined in register set */ + for (uint16_t addr = 0x52; addr < 0x52 + 11; addr++) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + /* set EXPDUMMY and CKxMAP */ + dpihw = sanei_genesys_compute_dpihw(dev, sensor, dpi); + Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); + + regs->set8(0x18, sensor_profile->reg18); + regs->set8(0x20, sensor_profile->reg20); + regs->set8(0x61, sensor_profile->reg61); + regs->set8(0x98, sensor_profile->reg98); + if (sensor_profile->reg16 != 0) { + regs->set8(0x16, sensor_profile->reg16); + } + if (sensor_profile->reg70 != 0) { + regs->set8(0x70, sensor_profile->reg70); + } + + + sanei_genesys_set_triple(regs,REG_SEGCNT,sensor_profile->segcnt); + sanei_genesys_set_double(regs,REG_TG0CNT,sensor_profile->tg0cnt); + sanei_genesys_set_double(regs,REG_EXPDMY,sensor_profile->expdummy); + + /* if no calibration has been done, set default values for exposures */ + exp = sensor.exposure.red; + if(exp==0) + { + exp=sensor_profile->expr; + } + sanei_genesys_set_triple(regs,REG_EXPR,exp); + + exp =sensor.exposure.green; + if(exp==0) + { + exp=sensor_profile->expg; + } + sanei_genesys_set_triple(regs,REG_EXPG,exp); + + exp = sensor.exposure.blue; + if(exp==0) + { + exp=sensor_profile->expb; + } + sanei_genesys_set_triple(regs,REG_EXPB,exp); + + sanei_genesys_set_triple(regs,REG_CK1MAP,sensor_profile->ck1map); + sanei_genesys_set_triple(regs,REG_CK3MAP,sensor_profile->ck3map); + sanei_genesys_set_triple(regs,REG_CK4MAP,sensor_profile->ck4map); + + /* order of the sub-segments */ + dev->order=sensor_profile->order; + + DBGCOMPLETED; +} + +/** @brief setup optical related registers + * start and pixels are expressed in optical sensor resolution coordinate + * space. + * @param dev scanner device to use + * @param reg registers to set up + * @param exposure_time exposure time to use + * @param used_res scanning resolution used, may differ from + * scan's one + * @param start logical start pixel coordinate + * @param pixels logical number of pixels to use + * @param channels number of color channels (currently 1 or 3) + * @param depth bit depth of the scan (1, 8 or 16) + * @param half_ccd SANE_TRUE if sensor's timings are such that x coordinates + * must be halved + * @param color_filter color channel to use as gray data + * @param flags optical flags (@see ) + * @return SANE_STATUS_GOOD if OK + */ +static SANE_Status +gl124_init_optical_regs_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int exposure_time, + int used_res, + unsigned int start, + unsigned int pixels, + int channels, + int depth, + SANE_Bool half_ccd, + ColorFilter color_filter, + int flags) +{ + unsigned int words_per_line, segcnt; + unsigned int startx, endx, used_pixels, segnb; + unsigned int dpiset, cksel, dpihw, factor; + unsigned int bytes; + GenesysRegister *r; + SANE_Status status = SANE_STATUS_GOOD; + uint32_t expmax, exp; + + DBG(DBG_proc, "%s : exposure_time=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " + "half_ccd=%d, flags=%x\n", __func__, exposure_time, used_res, start, pixels, channels, depth, + half_ccd, flags); + + /* resolution is divided according to CKSEL */ + r = sanei_genesys_get_address (reg, REG18); + cksel= (r->value & REG18_CKSEL)+1; + DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); + + /* to manage high resolution device while keeping good + * low resolution scanning speed, we make hardware dpi vary */ + dpihw=sanei_genesys_compute_dpihw(dev, sensor, used_res * cksel); + factor=sensor.optical_res/dpihw; + DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); + + /* sensor parameters */ + gl124_setup_sensor(dev, sensor, reg, dpihw, half_ccd); + dpiset = used_res * cksel; + + /* start and end coordinate in optical dpi coordinates */ + /* startx = start/cksel + sensor.dummy_pixel; XXX STEF XXX */ + startx = start/cksel; + used_pixels=pixels/cksel; + endx = startx + used_pixels; + + /* pixel coordinate factor correction when used dpihw is not maximal one */ + startx/=factor; + endx/=factor; + used_pixels=endx-startx; + + status = gl124_set_fe(dev, sensor, AFE_SET); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, + sane_strstatus (status)); + return status; + } + + /* enable shading */ + r = sanei_genesys_get_address (reg, REG01); + r->value &= ~REG01_SCAN; + if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + r->value &= ~REG01_DVDSET; + } + else + { + r->value |= REG01_DVDSET; + } + r->value &= ~REG01_SCAN; + + r = sanei_genesys_get_address (reg, REG03); + if((dev->model->ccd_type!=CIS_CANONLIDE120)&&(used_res>=600)) + { + r->value &= ~REG03_AVEENB; + DBG (DBG_io, "%s: disabling AVEENB\n", __func__); + } + else + { + r->value |= ~REG03_AVEENB; + DBG (DBG_io, "%s: enabling AVEENB\n", __func__); + } + + sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); + + /* BW threshold */ + RIE (sanei_genesys_write_register (dev, REG114, dev->settings.threshold)); + RIE (sanei_genesys_write_register (dev, REG115, dev->settings.threshold)); + + /* monochrome / color scan */ + r = sanei_genesys_get_address (reg, REG04); + switch (depth) + { + case 1: + r->value &= ~REG04_BITSET; + r->value |= REG04_LINEART; + break; + case 8: + r->value &= ~(REG04_LINEART | REG04_BITSET); + break; + case 16: + r->value &= ~REG04_LINEART; + r->value |= REG04_BITSET; + break; + } + + r->value &= ~REG04_FILTER; + if (channels == 1) + { + switch (color_filter) + { + case ColorFilter::RED: + r->value |= 0x10; + break; + case ColorFilter::BLUE: + r->value |= 0x30; + break; + case ColorFilter::GREEN: + r->value |= 0x20; + break; + default: + break; // should not happen + } + } + + /* register 05 */ + r = sanei_genesys_get_address (reg, REG05); + + /* set up dpihw */ + r->value &= ~REG05_DPIHW; + switch(dpihw) + { + case 600: + r->value |= REG05_DPIHW_600; + break; + case 1200: + r->value |= REG05_DPIHW_1200; + break; + case 2400: + r->value |= REG05_DPIHW_2400; + break; + case 4800: + r->value |= REG05_DPIHW_4800; + break; + } + + /* enable gamma tables */ + if (flags & OPTICAL_FLAG_DISABLE_GAMMA) + r->value &= ~REG05_GMMENB; + else + r->value |= REG05_GMMENB; + + if(half_ccd) + { + sanei_genesys_set_double(reg,REG_DPISET,dpiset*2); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset*2); + } + else + { + sanei_genesys_set_double(reg,REG_DPISET,dpiset); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); + } + + r = sanei_genesys_get_address (reg, REG06); + r->value |= REG06_GAIN4; + + /* CIS scanners can do true gray by setting LEDADD */ + /* we set up LEDADD only when asked */ + if (dev->model->is_cis == SANE_TRUE) + { + r = sanei_genesys_get_address (reg, REG60); + r->value &= ~REG60_LEDADD; + if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) + { + r->value |= REG60_LEDADD; + sanei_genesys_get_triple(reg,REG_EXPR,&expmax); + sanei_genesys_get_triple(reg,REG_EXPG,&exp); + if(exp>expmax) + { + expmax=exp; + } + sanei_genesys_get_triple(reg,REG_EXPB,&exp); + if(exp>expmax) + { + expmax=exp; + } + sanei_genesys_set_triple(&dev->reg,REG_EXPR,expmax); + sanei_genesys_set_triple(&dev->reg,REG_EXPG,expmax); + sanei_genesys_set_triple(&dev->reg,REG_EXPB,expmax); + } + /* RGB weighting, REG_TRUER,G and B are to be set */ + r = sanei_genesys_get_address (reg, 0x01); + r->value &= ~REG01_TRUEGRAY; + if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) + { + r->value |= REG01_TRUEGRAY; + sanei_genesys_write_register (dev, REG_TRUER, 0x80); + sanei_genesys_write_register (dev, REG_TRUEG, 0x80); + sanei_genesys_write_register (dev, REG_TRUEB, 0x80); + } + } + + /* segment number */ + r = sanei_genesys_get_address (reg, 0x98); + segnb = r->value & 0x0f; + + sanei_genesys_set_triple(reg,REG_STRPIXEL,startx/segnb); + DBG (DBG_io2, "%s: strpixel used=%d\n", __func__, startx/segnb); + sanei_genesys_get_triple(reg,REG_SEGCNT,&segcnt); + if(endx/segnb==segcnt) + { + endx=0; + } + sanei_genesys_set_triple(reg,REG_ENDPIXEL,endx/segnb); + DBG (DBG_io2, "%s: endpixel used=%d\n", __func__, endx/segnb); + + /* words(16bit) before gamma, conversion to 8 bit or lineart */ + words_per_line = (used_pixels * dpiset) / dpihw; + bytes = depth / 8; + if (depth == 1) + { + words_per_line = (words_per_line >> 3) + ((words_per_line & 7) ? 1 : 0); + } + else + { + words_per_line *= bytes; + } + + dev->bpl = words_per_line; + dev->cur = 0; + dev->skip = 0; + dev->len = dev->bpl/segnb; + dev->dist = dev->bpl/segnb; + dev->segnb = segnb; + dev->line_count = 0; + dev->line_interp = 0; + + DBG (DBG_io2, "%s: used_pixels =%d\n", __func__, used_pixels); + DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); + DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); + DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); + DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); + DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); + DBG (DBG_io2, "%s: dev->line_interp=%lu\n", __func__, (unsigned long)dev->line_interp); + + words_per_line *= channels; + dev->wpl = words_per_line; + + /* allocate buffer for odd/even pixels handling */ + dev->oe_buffer.clear(); + dev->oe_buffer.alloc(dev->wpl); + + /* MAXWD is expressed in 2 words unit */ + sanei_genesys_set_triple(reg,REG_MAXWD,(words_per_line)); + DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); + + sanei_genesys_set_triple(reg,REG_LPERIOD,exposure_time); + DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); + + sanei_genesys_set_double(reg,REG_DUMMY,sensor.dummy_pixel); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** set up registers for an actual scan + * + * this function sets up the scanner to scan in normal or single line mode + */ +static SANE_Status +gl124_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set* reg, + SetupParams& params) +{ + params.assert_valid(); + + int used_res; + int start, used_pixels; + int bytes_per_line; + int move; + unsigned int lincnt; + unsigned int oflags, mflags; /**> optical and motor flags */ + int exposure_time; + int stagger; + + int dummy = 0; + int slope_dpi = 0; + int scan_step_type = 1; + int max_shift; + size_t requested_buffer_size, read_buffer_size; + + SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ + unsigned optical_res; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + + half_ccd=compute_half_ccd(sensor, params.xres); + + /* optical_res */ + optical_res = sensor.optical_res; + if (half_ccd) + optical_res /= 2; + DBG (DBG_info, "%s: optical_res=%d\n", __func__, optical_res); + + /* stagger */ + if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG (DBG_info, "gl124_init_scan_regs : stagger=%d lines\n", stagger); + + /** @brief compute used resolution */ + if (params.flags & SCAN_FLAG_USE_OPTICAL_RES) + { + used_res = optical_res; + } + else + { + /* resolution is choosen from a fixed list and can be used directly, + * unless we have ydpi higher than sensor's maximum one */ + if(params.xres>optical_res) + used_res=optical_res; + else + used_res = params.xres; + } + + /* compute scan parameters values */ + /* pixels are allways given at full optical resolution */ + /* use detected left margin and fixed value */ + /* start */ + /* add x coordinates */ + start = params.startx; + + if (stagger > 0) + start |= 1; + + /* compute correct pixels number */ + used_pixels = (params.pixels * optical_res) / params.xres; + DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); + + /* round up pixels number if needed */ + if (used_pixels * params.xres < params.pixels * optical_res) + used_pixels++; + + /* we want even number of pixels here */ + if(used_pixels & 1) + used_pixels++; + + /* slope_dpi */ + /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ + if (dev->model->is_cis) + slope_dpi = params.yres * params.channels; + else + slope_dpi = params.yres; + + /* scan_step_type */ + if(params.flags & SCAN_FLAG_FEEDING) + { + scan_step_type=0; + exposure_time=MOVE_EXPOSURE; + } + else + { + exposure_time = gl124_compute_exposure (dev, used_res, half_ccd); + scan_step_type = sanei_genesys_compute_step_type(motors, dev->model->motor_type, exposure_time); + } + + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); + + /*** optical parameters ***/ + /* in case of dynamic lineart, we use an internal 8 bit gray scan + * to generate 1 lineart data */ + if (params.flags & SCAN_FLAG_DYNAMIC_LINEART) { + params.depth = 8; + } + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + oflags = 0; + if (params.flags & SCAN_FLAG_DISABLE_SHADING) + oflags |= OPTICAL_FLAG_DISABLE_SHADING; + if (params.flags & SCAN_FLAG_DISABLE_GAMMA) + oflags |= OPTICAL_FLAG_DISABLE_GAMMA; + if (params.flags & SCAN_FLAG_DISABLE_LAMP) + oflags |= OPTICAL_FLAG_DISABLE_LAMP; + if (params.flags & SCAN_FLAG_CALIBRATION) + oflags |= OPTICAL_FLAG_DISABLE_DOUBLE; + + if (dev->model->is_cis && dev->settings.true_gray) + { + oflags |= OPTICAL_FLAG_ENABLE_LEDADD; + } + + /* now _LOGICAL_ optical values used are known, setup registers */ + status = gl124_init_optical_regs_scan (dev, + sensor, + reg, + exposure_time, + used_res, + start, + used_pixels, + params.channels, + params.depth, + half_ccd, + params.color_filter, + oflags); + if (status != SANE_STATUS_GOOD) + return status; + + /*** motor parameters ***/ + + /* max_shift */ + max_shift=sanei_genesys_compute_max_shift(dev,params.channels,params.yres,params.flags); + + /* lines to scan */ + lincnt = params.lines + max_shift + stagger; + + /* add tl_y to base movement */ + move = params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + mflags=0; + if(params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) + mflags|=MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; + if(params.flags & SCAN_FLAG_FEEDING) + mflags|=MOTOR_FLAG_FEED; + + status = gl124_init_motor_regs_scan (dev, sensor, + reg, + exposure_time, + slope_dpi, + scan_step_type, + dev->model->is_cis ? lincnt * params.channels : lincnt, + dummy, + move, + params.scan_mode, + mflags); + if (status != SANE_STATUS_GOOD) + return status; + + /*** prepares data reordering ***/ + + /* words_per_line */ + bytes_per_line = (used_pixels * used_res) / optical_res; + bytes_per_line = (bytes_per_line * params.channels * params.depth) / 8; + + /* since we don't have sheetfed scanners to handle, + * use huge read buffer */ + /* TODO find the best size according to settings */ + requested_buffer_size = 16 * bytes_per_line; + + read_buffer_size = + 2 * requested_buffer_size + + ((max_shift + stagger) * used_pixels * params.channels * params.depth) / 8; + + dev->read_buffer.clear(); + dev->read_buffer.alloc(read_buffer_size); + + dev->lines_buffer.clear(); + dev->lines_buffer.alloc(read_buffer_size); + + dev->shrink_buffer.clear(); + dev->shrink_buffer.alloc(requested_buffer_size); + + dev->out_buffer.clear(); + dev->out_buffer.alloc((8 * dev->settings.pixels * params.channels * params.depth) / 8); + + dev->read_bytes_left = bytes_per_line * lincnt; + + DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); + dev->read_active = SANE_TRUE; + + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res) / optical_res; + DBG(DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure_time; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + + dev->total_bytes_read = 0; + if (params.depth == 1) + dev->total_bytes_to_read = + ((dev->settings.pixels * dev->settings.lines) / 8 + + (((dev->settings.pixels * dev->settings.lines) % 8) ? 1 : 0)) * + params.channels; + else + dev->total_bytes_to_read = + dev->settings.pixels * dev->settings.lines * params.channels * (params.depth / 8); + + DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static void +gl124_calculate_current_setup (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int depth; + int start; + + int used_res; + int used_pixels; + unsigned int lincnt; + int exposure_time; + int stagger; + SANE_Bool half_ccd; + + int max_shift, dpihw; + + int optical_res; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + /* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + /* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + /* start */ + start = SANE_UNFIX (dev->model->x_offset); + start += dev->settings.tl_x; + start = (start * sensor.optical_res) / MM_PER_INCH; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; + params.starty = 0; // not used + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = 0; + + half_ccd=compute_half_ccd(sensor, params.xres); + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + + /* optical_res */ + optical_res = sensor.optical_res; + + if (params.xres <= (unsigned) optical_res) + used_res = params.xres; + else + used_res=optical_res; + + /* compute scan parameters values */ + /* pixels are allways given at half or full CCD optical resolution */ + /* use detected left margin and fixed value */ + + /* compute correct pixels number */ + used_pixels = (params.pixels * optical_res) / params.xres; + DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); + + /* exposure */ + exposure_time = gl124_compute_exposure (dev, params.xres, half_ccd); + DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + + /* max_shift */ + max_shift=sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); + + /* compute hw dpi for sensor */ + dpihw=sanei_genesys_compute_dpihw(dev, sensor,used_res); + + Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); + dev->segnb=sensor_profile->reg98 & 0x0f; + + /* stagger */ + if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG (DBG_info, "%s: stagger=%d lines\n", __func__, stagger); + + /* lincnt */ + lincnt = params.lines + max_shift + stagger; + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res) / optical_res; + DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure_time; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + + DBGCOMPLETED; +} + +/** + * for fast power saving methods only, like disabling certain amplifiers + * @param dev device to use + * @param enable true to set inot powersaving + * */ +static SANE_Status +gl124_save_power (Genesys_Device * dev, SANE_Bool enable) +{ + DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); + if (dev == NULL) + return SANE_STATUS_INVAL; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl124_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) +{ + GenesysRegister *r; + + DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); + + r = sanei_genesys_get_address (&dev->reg, REG03); + r->value &= ~0xf0; + if(delay<15) + { + r->value |= delay; + } + else + { + r->value |= 0x0f; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl124_start_action (Genesys_Device * dev) +{ + return sanei_genesys_write_register (dev, 0x0f, 0x01); +} + +static SANE_Status +gl124_stop_action (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val40, val; + unsigned int loop; + + DBGSTART; + + /* post scan gpio : without that HOMSNR is unreliable */ + gl124_homsnr_gpio(dev); + + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + status = sanei_genesys_read_register (dev, REG100, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read reg100: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* only stop action if needed */ + if (!(val40 & REG100_DATAENB) && !(val40 & REG100_MOTMFLG)) + { + DBG (DBG_info, "%s: already stopped\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + /* ends scan */ + val = dev->reg.get8(REG01); + val &= ~REG01_SCAN; + dev->reg.set8(REG01, val); + status = sanei_genesys_write_register (dev, REG01, val); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to write register 01: %s\n", __func__, + sane_strstatus (status)); + return status; + } + sanei_genesys_sleep_ms(100); + + loop = 10; + while (loop > 0) + { + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + status = sanei_genesys_read_register (dev, REG100, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus (status)); + DBGCOMPLETED; + return status; + } + + /* if scanner is in command mode, we are done */ + if (!(val40 & REG100_DATAENB) && !(val40 & REG100_MOTMFLG) + && !(val & MOTORENB)) + { + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + sanei_genesys_sleep_ms(100); + loop--; + } + + DBGCOMPLETED; + return SANE_STATUS_IO_ERROR; +} + + +/** @brief setup GPIOs for scan + * Setup GPIO values to drive motor (or light) needed for the + * target resolution + * @param *dev device to set up + * @param resolution dpi of the target scan + * @return SANE_STATUS_GOOD unless REG32 cannot be read + */ +static SANE_Status +gl124_setup_scan_gpio(Genesys_Device *dev, int resolution) +{ +SANE_Status status = SANE_STATUS_GOOD; +uint8_t val; + + DBGSTART; + RIE (sanei_genesys_read_register (dev, REG32, &val)); + + /* LiDE 110, 210 and 220 cases */ + if(dev->model->gpo_type != GPO_CANONLIDE120) + { + if(resolution>=dev->motor.base_ydpi/2) + { + val &= 0xf7; + } + else if(resolution>=dev->motor.base_ydpi/4) + { + val &= 0xef; + } + else + { + val |= 0x10; + } + } + /* 120 : <=300 => 0x53 */ + else + { /* base_ydpi is 4800 */ + if(resolution<=300) + { + val &= 0xf7; + } + else if(resolution<=600) + { + val |= 0x08; + } + else if(resolution<=1200) + { + val &= 0xef; + val |= 0x08; + } + else + { + val &= 0xf7; + } + } + val |= 0x02; + RIE (sanei_genesys_write_register (dev, REG32, val)); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* Send the low-level scan command */ +/* todo : is this that useful ? */ +static SANE_Status +gl124_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SANE_Bool start_motor) +{ + (void) sensor; + + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + DBGSTART; + if (reg == NULL) + return SANE_STATUS_INVAL; + + /* set up GPIO for scan */ + RIE(gl124_setup_scan_gpio(dev,dev->settings.yres)); + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); + + /* enable scan and motor */ + RIE (sanei_genesys_read_register (dev, REG01, &val)); + val |= REG01_SCAN; + RIE (sanei_genesys_write_register (dev, REG01, val)); + + if (start_motor) + { + RIE (sanei_genesys_write_register (dev, REG0F, 1)); + } + else + { + RIE (sanei_genesys_write_register (dev, REG0F, 0)); + } + + DBGCOMPLETED; + return status; +} + + +/* Send the stop scan command */ +static SANE_Status +gl124_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, + SANE_Bool check_stop) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); + if (reg == NULL) + return SANE_STATUS_INVAL; + + if (dev->model->is_sheetfed == SANE_TRUE) + { + status = SANE_STATUS_GOOD; + } + else /* flat bed scanners */ + { + status = gl124_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + DBGCOMPLETED; + return status; +} + + +/** rewind scan + * Move back by the same amount of distance than previous scan. + * @param dev device to rewind + * @returns SANE_STATUS_GOOD on success + */ +static +SANE_Status gl124_rewind(Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t byte; + + DBGSTART; + + /* set motor reverse */ + RIE (sanei_genesys_read_register (dev, 0x02, &byte)); + byte |= 0x04; + RIE (sanei_genesys_write_register(dev, 0x02, byte)); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + /* and start scan, then wait completion */ + RIE (gl124_begin_scan (dev, sensor, &dev->reg, SANE_TRUE)); + do + { + sanei_genesys_sleep_ms(100); + RIE (sanei_genesys_read_register (dev, REG100, &byte)); + } + while(byte & REG100_MOTMFLG); + RIE (gl124_end_scan (dev, &dev->reg, SANE_TRUE)); + + /* restore direction */ + RIE (sanei_genesys_read_register (dev, 0x02, &byte)); + byte &= 0xfb; + RIE (sanei_genesys_write_register(dev, 0x02, byte)); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** Park head + * Moves the slider to the home (top) position slowly + * @param dev device to park + * @param wait_until_home true to make the function waiting for head + * to be home before returning, if fals returne immediately + * @returns SANE_STATUS_GOO on success */ +static +SANE_Status +gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + uint8_t val; + float resolution; + int loop = 0; + + DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); + + /* post scan gpio : without that HOMSNR is unreliable */ + gl124_homsnr_gpio(dev); + + /* first read gives HOME_SENSOR true */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + sanei_genesys_sleep_ms(100); + + /* second is reliable */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + /* is sensor at home? */ + if (val & HOMESNR) + { + DBG (DBG_info, "%s: already at home, completed\n", __func__); + dev->scanhead_position_in_steps = 0; + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + /* feed a little first */ + if (dev->model->model_id == MODEL_CANON_LIDE_210) + { + status = gl124_feed (dev, 20, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to do initial feed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + local_reg = dev->reg; + resolution=sanei_genesys_get_lowest_dpi(dev); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 100; + params.starty = 30000; + params.pixels = 100; + params.lines = 100; + params.depth = 8; + params.channels = 1; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::RED; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl124_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); + + /* set up for reverse and no scan */ + r = sanei_genesys_get_address(&local_reg, REG02); + r->value |= REG02_MTRREV; + + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + + RIE(gl124_setup_scan_gpio(dev,resolution)); + + try { + status = gl124_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl124_stop_action (dev); + } catch (...) {} + try { + // restore original registers + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + if (status != SANE_STATUS_GOOD) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl124_stop_action (dev); + } catch (...) {} + /* restore original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + /* post scan gpio : without that HOMSNR is unreliable */ + gl124_homsnr_gpio(dev); + + if (wait_until_home) + { + + while (loop < 300) /* do not wait longer then 30 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + if (val & HOMESNR) /* home sensor */ + { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBGCOMPLETED; + dev->scanhead_position_in_steps = 0; + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + ++loop; + } + + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl124_stop_action (dev); + DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + DBG(DBG_info, "%s: scanhead is still moving\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief moves the slider to steps at motor base dpi + * @param dev device to work on + * @param steps number of steps to move + * @param reverse true is moving backward + * */ +static SANE_Status +gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + float resolution; + uint8_t val; + + DBGSTART; + DBG (DBG_io, "%s: steps=%d\n", __func__, steps); + + /* prepare local registers */ + local_reg = dev->reg; + + resolution=sanei_genesys_get_lowest_ydpi(dev); + const auto& sensor = sanei_genesys_find_sensor(dev, resolution); + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 0; + params.starty = steps; + params.pixels = 100; + params.lines = 3; + params.depth = 8; + params.channels = 3; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_FEEDING | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl124_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus (status)); + DBGCOMPLETED; + return status; + } + + /* set exposure to zero */ + sanei_genesys_set_triple(&local_reg,REG_EXPR,0); + sanei_genesys_set_triple(&local_reg,REG_EXPG,0); + sanei_genesys_set_triple(&local_reg,REG_EXPB,0); + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); + + /* set up for no scan */ + r = sanei_genesys_get_address (&local_reg, REG01); + r->value &= ~REG01_SCAN; + + /* set up for reverse if needed */ + if(reverse) + { + r = sanei_genesys_get_address (&local_reg, REG02); + r->value |= REG02_MTRREV; + } + + /* send registers */ + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + + status = gl124_start_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); + gl124_stop_action (dev); + + /* restore original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + /* wait until feed count reaches the required value, but do not + * exceed 30s */ + do + { + status = sanei_genesys_get_status (dev, &val); + } + while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); + + /* then stop scanning */ + RIE(gl124_stop_action (dev)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels + area at 600 dpi from very top of scanner */ +static SANE_Status +gl124_search_start_position (Genesys_Device * dev) +{ + int size; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg = dev->reg; + int steps; + + int pixels = 600; + int dpi = 300; + + DBGSTART; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); + + SetupParams params; + params.xres = dpi; + params.yres = dpi; + params.startx = 0; + params.starty = 0; /*we should give a small offset here~60 steps */ + params.pixels = 600; + params.lines = dev->model->search_lines; + params.depth = 8; + params.channels = 1; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::GREEN; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; + + status = gl124_init_scan_regs(dev, sensor, &local_reg, params); + + if (status!=SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to init scan registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* send to scanner */ + status = dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + size = pixels * dev->model->search_lines; + + std::vector data(size); + + status = gl124_begin_scan (dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner (dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl124_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + + status = gl124_end_scan (dev, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + + status = + sanei_genesys_search_reference_point (dev, sensor, data.data(), 0, dpi, pixels, + dev->model->search_lines); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* + * sets up register for coarse gain calibration + * todo: check it for scanners using it */ +static SANE_Status +gl124_init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t channels; + uint8_t cksel; + + DBGSTART; + cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ + + /* set line size */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) { + channels = 3; + } else { + channels = 1; + } + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = 0; + params.starty = 0; + params.pixels = sensor.optical_res / cksel; + params.lines = 20; + params.depth = 16; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_FEEDING | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl124_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_set_motor_power(regs, false); + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / cksel, dev->settings.xres); + + status = dev->model->cmd_set->bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/* init registers for shading calibration */ +/* shading calibration is done at dpihw */ +static SANE_Status +gl124_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + int move, resolution, dpihw, factor; + + DBGSTART; + + /* initial calibration reg values */ + regs = dev->reg; + + dev->calib_channels = 3; + dev->calib_lines = dev->model->shading_lines; + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); + if(dpihw>=2400) + { + dev->calib_lines *= 2; + } + resolution=dpihw; + + /* if half CCD mode, use half resolution */ + if(compute_half_ccd(sensor, dev->settings.xres)==SANE_TRUE) + { + resolution /= 2; + dev->calib_lines /= 2; + } + dev->calib_resolution = resolution; + dev->calib_total_bytes_to_read = 0; + factor=sensor.optical_res/resolution; + dev->calib_pixels = sensor.sensor_pixels/factor; + + /* distance to move to reach white target at high resolution */ + move=0; + if(dev->settings.yres>=1200) + { + move = SANE_UNFIX (dev->model->y_offset_calib); + move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; + } + DBG (DBG_io, "%s: move=%d steps\n", __func__, move); + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 0; + params.starty = move; + params.pixels = dev->calib_pixels; + params.lines = dev->calib_lines; + params.depth = 16; + params.channels = dev->calib_channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = ColorFilter::RED; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl124_init_scan_regs(dev, sensor, ®s, params); + + sanei_genesys_set_motor_power(regs, false); + + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, + sane_strstatus (status)); + return status; + } + + dev->scanhead_position_in_steps += dev->calib_lines + move; + + status = dev->model->cmd_set->bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to bulk write registers: %s\n", __func__, + sane_strstatus (status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static void gl124_wait_for_motor_stop(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + uint8_t val40, val; + + TIE(sanei_genesys_get_status(dev, &val)); + TIE(sanei_genesys_read_register(dev, REG100, &val40)); + + if ((val & MOTORENB) == 0 && (val40 & REG100_MOTMFLG) == 0) + return; + + do { + sanei_genesys_sleep_ms(10); + TIE(sanei_genesys_get_status(dev, &val)); + TIE(sanei_genesys_read_register(dev, REG100, &val40)); + } while ((val & MOTORENB) ||(val40 & REG100_MOTMFLG)); + sanei_genesys_sleep_ms(50); +} + +/** @brief set up registers for the actual scan + */ +static SANE_Status +gl124_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int flags; + int depth; + float move; + int move_dpi; + float start; + + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + /* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + /* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + /* y (motor) distance to move to reach scanned area */ + move_dpi = dev->motor.base_ydpi/4; + move = SANE_UNFIX (dev->model->y_offset); + move += dev->settings.tl_y; + move = (move * move_dpi) / MM_PER_INCH; + DBG (DBG_info, "%s: move=%f steps\n", __func__, move); + + if(channels*dev->settings.yres>=600 && move>700) + { + status = gl124_feed (dev, move-500, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to move to scan area\n",__func__); + return status; + } + move=500; + } + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* start */ + start = SANE_UNFIX (dev->model->x_offset); + start += dev->settings.tl_x; + if(compute_half_ccd(sensor, dev->settings.xres)==SANE_TRUE) + { + start /=2; + } + start = (start * sensor.optical_res) / MM_PER_INCH; + + flags = 0; + + /* enable emulated lineart from gray data */ + if(dev->settings.scan_mode == ScanColorMode::LINEART + && dev->settings.dynamic_lineart) + { + flags |= SCAN_FLAG_DYNAMIC_LINEART; + } + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; + params.starty = move; + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = flags; + + status = gl124_init_scan_regs(dev, sensor, &dev->reg, params); + + if (status != SANE_STATUS_GOOD) + return status; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +static SANE_Status +gl124_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, int size) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint32_t addr, length, strpixel ,endpixel, x, factor, segcnt, pixels, i; + uint32_t lines, channels; + uint16_t dpiset,dpihw; + uint8_t val,*ptr,*src; + + DBGSTART; + DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); + + /* logical size of a color as seen by generic code of the frontend */ + length = (uint32_t) (size / 3); + sanei_genesys_get_triple(&dev->reg,REG_STRPIXEL,&strpixel); + sanei_genesys_get_triple(&dev->reg,REG_ENDPIXEL,&endpixel); + sanei_genesys_get_triple(&dev->reg,REG_SEGCNT,&segcnt); + if(endpixel==0) + { + endpixel=segcnt; + } + DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, SEGCNT=%d\n",__func__,strpixel,endpixel,endpixel-strpixel,segcnt); + + /* compute deletion factor */ + sanei_genesys_get_double(&dev->reg,REG_DPISET,&dpiset); + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpiset); + factor=dpihw/dpiset; + DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); + + /* binary data logging */ + if(DBG_LEVEL>=DBG_data) + { + dev->binary=fopen("binary.pnm","wb"); + sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &lines); + channels=dev->current_setup.channels; + if(dev->binary!=NULL) + { + fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels*dev->segnb,lines/channels,255); + } + } + + /* turn pixel value into bytes 2x16 bits words */ + strpixel*=2*2; /* 2 words of 2 bytes */ + endpixel*=2*2; + segcnt*=2*2; + pixels=endpixel-strpixel; + + DBG( DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__func__,length, length/4); + std::vector buffer(pixels * dev->segnb, 0); + + /* write actual red data */ + for(i=0;i<3;i++) + { + /* copy data to work buffer and process it */ + /* coefficent destination */ + ptr = buffer.data(); + + /* iterate on both sensor segment */ + for(x=0;xsegnb) + { + case 1: + ptr[0+pixels*0]=src[0+segcnt*0]; + ptr[1+pixels*0]=src[1+segcnt*0]; + ptr[2+pixels*0]=src[2+segcnt*0]; + ptr[3+pixels*0]=src[3+segcnt*0]; + break; + case 2: + ptr[0+pixels*0]=src[0+segcnt*0]; + ptr[1+pixels*0]=src[1+segcnt*0]; + ptr[2+pixels*0]=src[2+segcnt*0]; + ptr[3+pixels*0]=src[3+segcnt*0]; + ptr[0+pixels*1]=src[0+segcnt*1]; + ptr[1+pixels*1]=src[1+segcnt*1]; + ptr[2+pixels*1]=src[2+segcnt*1]; + ptr[3+pixels*1]=src[3+segcnt*1]; + break; + case 4: + ptr[0+pixels*0]=src[0+segcnt*0]; + ptr[1+pixels*0]=src[1+segcnt*0]; + ptr[2+pixels*0]=src[2+segcnt*0]; + ptr[3+pixels*0]=src[3+segcnt*0]; + ptr[0+pixels*1]=src[0+segcnt*2]; + ptr[1+pixels*1]=src[1+segcnt*2]; + ptr[2+pixels*1]=src[2+segcnt*2]; + ptr[3+pixels*1]=src[3+segcnt*2]; + ptr[0+pixels*2]=src[0+segcnt*1]; + ptr[1+pixels*2]=src[1+segcnt*1]; + ptr[2+pixels*2]=src[2+segcnt*1]; + ptr[3+pixels*2]=src[3+segcnt*1]; + ptr[0+pixels*3]=src[0+segcnt*3]; + ptr[1+pixels*3]=src[1+segcnt*3]; + ptr[2+pixels*3]=src[2+segcnt*3]; + ptr[3+pixels*3]=src[3+segcnt*3]; + break; + } + + /* next shading coefficient */ + ptr+=4; + } + RIE (sanei_genesys_read_register (dev, 0xd0+i, &val)); + addr = val * 8192 + 0x10000000; + status = sanei_genesys_write_ahb(dev, addr, pixels*dev->segnb, buffer.data()); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s; write to AHB failed (%s)\n", __func__, sane_strstatus(status)); + return status; + } + } + + DBGCOMPLETED; + + return status; +} + + +/** @brief move to calibration area + * This functions moves scanning head to calibration area + * by doing a 600 dpi scan + * @param dev scanner device + * @return SANE_STATUS_GOOD on success, else the error code + */ +static SANE_Status +move_to_calibration_area (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + int pixels; + int size; + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + pixels = (sensor.sensor_pixels*600)/sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + SetupParams params; + params.xres = 600; + params.yres = 600; + params.startx = 0; + params.starty = 0; + params.pixels = pixels; + params.lines = 1; + params.depth = 8; + params.channels = 3; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl124_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); + return status; + } + + size = pixels * 3; + std::vector line(size); + + /* write registers and scan data */ + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + + DBG (DBG_info, "%s: starting line reading\n", __func__); + RIE(gl124_begin_scan (dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), size)); + + /* stop scanning */ + RIE(gl124_stop_action (dev)); + + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_pnm_file("gl124_movetocalarea.pnm", line.data(), 8, 3, pixels, 1); + } + + DBGCOMPLETED; + return status; +} + +/* this function does the led calibration by scanning one line of the calibration + area below scanner's top on white strip. + +-needs working coarse/gain +*/ +static SANE_Status +gl124_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs) +{ + int num_pixels; + int total_size; + int resolution; + int dpihw; + int i, j; + SANE_Status status = SANE_STATUS_GOOD; + int val; + int channels, depth; + int avg[3]; + int turn; + uint16_t exp[3],target; + SANE_Bool acceptable; + SANE_Bool half_ccd; + + DBGSTART; + + /* move to calibration area */ + move_to_calibration_area(dev, sensor, regs); + + /* offset calibration is always done in 16 bit depth color mode */ + channels = 3; + depth=16; + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); + half_ccd=compute_half_ccd(sensor, dev->settings.xres); + if(half_ccd==SANE_TRUE) + { + resolution = dpihw/2; + } + else + { + resolution = dpihw; + } + Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); + num_pixels = (sensor.sensor_pixels*resolution)/sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 0; + params.starty = 0; + params.pixels = num_pixels; + params.lines = 1; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl124_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); + return status; + } + + total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ + std::vector line(total_size); + + /* initial loop values and boundaries */ + exp[0]=sensor_profile->expr; + exp[1]=sensor_profile->expg; + exp[2]=sensor_profile->expb; + target=sensor.gain_white_ref*256; + + turn = 0; + + /* no move during led calibration */ + sanei_genesys_set_motor_power(regs, false); + do + { + /* set up exposure */ + sanei_genesys_set_triple(®s,REG_EXPR,exp[0]); + sanei_genesys_set_triple(®s,REG_EXPG,exp[1]); + sanei_genesys_set_triple(®s,REG_EXPB,exp[2]); + + /* write registers and scan data */ + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + + DBG(DBG_info, "%s: starting line reading\n", __func__); + RIE(gl124_begin_scan (dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, line.data(), total_size)); + + /* stop scanning */ + RIE(gl124_stop_action (dev)); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl124_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), depth, channels, num_pixels, 1); + } + + /* compute average */ + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + /* check if exposure gives average within the boundaries */ + acceptable = SANE_TRUE; + for(i=0;i<3;i++) + { + /* we accept +- 2% delta from target */ + if(abs(avg[i]-target)>target/50) + { + exp[i]=(exp[i]*target)/avg[i]; + acceptable = SANE_FALSE; + } + } + + turn++; + } + while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); + + /* set these values as final ones for scan */ + sanei_genesys_set_triple(&dev->reg,REG_EXPR,exp[0]); + sanei_genesys_set_triple(&dev->reg,REG_EXPG,exp[1]); + sanei_genesys_set_triple(&dev->reg,REG_EXPB,exp[2]); + + /* store in this struct since it is the one used by cache calibration */ + sensor.exposure.red = exp[0]; + sensor.exposure.green = exp[1]; + sensor.exposure.blue = exp[2]; + + DBGCOMPLETED; + return status; +} + +/** + * average dark pixels of a 8 bits scan + */ +static int +dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black) +{ + unsigned int i, j, k, average, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average value on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + for (i = 0; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + average = 0; + for (i = 0; i < channels; i++) + average += avg[i]; + average /= channels; + DBG(DBG_info, "%s: average = %d\n", __func__, average); + return average; +} + + +static SANE_Status +gl124_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t reg0a; + unsigned int channels, bpp; + int pass = 0, avg, total_size; + int topavg, bottomavg, resolution, lines; + int top, bottom, black_pixels, pixels; + + DBGSTART; + + /* no gain nor offset for TI AFE */ + RIE (sanei_genesys_read_register (dev, REG0A, ®0a)); + if(((reg0a & REG0A_SIFSEL)>>REG0AS_SIFSEL)==3) + { + DBGCOMPLETED; + return status; + } + + /* offset calibration is always done in color mode */ + channels = 3; + resolution=sensor.optical_res; + dev->calib_pixels = sensor.sensor_pixels; + lines=1; + bpp=8; + pixels= (sensor.sensor_pixels*resolution) / sensor.optical_res; + black_pixels = (sensor.black_pixels * resolution) / sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 0; + params.starty = 0; + params.pixels = pixels; + params.lines = lines; + params.depth = bpp; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl124_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_set_motor_power(regs, false); + + /* allocate memory for scans */ + total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* init gain */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* scan with no move */ + bottom = 10; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + + RIE(gl124_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting first line reading\n", __func__); + RIE(gl124_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + snprintf(title, 30, "gl124_offset%03d.pnm", bottom); + sanei_genesys_write_pnm_file(title, first_line.data(), bpp, channels, pixels, lines); + } + + bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); + + /* now top value */ + top = 255; + dev->frontend.set_offset(0, top); + dev->frontend.set_offset(1, top); + dev->frontend.set_offset(2, top); + RIE(gl124_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(gl124_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); + + topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); + + /* loop until acceptable level */ + while ((pass < 32) && (top - bottom > 1)) + { + pass++; + + /* settings for new scan */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + /* scan with no move */ + RIE(gl124_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(gl124_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + snprintf(title, 30, "gl124_offset%03d.pnm", dev->frontend.get_offset(1)); + sanei_genesys_write_pnm_file(title, second_line.data(), bpp, channels, pixels, lines); + } + + avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); + + /* compute new boundaries */ + if (topavg == avg) + { + topavg = avg; + top = dev->frontend.get_offset(1); + } + else + { + bottomavg = avg; + bottom = dev->frontend.get_offset(1); + } + } + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/* alternative coarse gain calibration + this on uses the settings from offset_calibration and + uses only one scanline + */ +/* + with offset and coarse calibration we only want to get our input range into + a reasonable shape. the fine calibration of the upper and lower bounds will + be done with shading. + */ +static SANE_Status +gl124_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) +{ + int pixels; + int total_size; + uint8_t reg0a; + int i, j, channels; + SANE_Status status = SANE_STATUS_GOOD; + int max[3]; + float gain[3],coeff; + int val, code, lines; + int resolution; + int bpp; + + DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); + + /* no gain nor offset for TI AFE */ + RIE (sanei_genesys_read_register (dev, REG0A, ®0a)); + if(((reg0a & REG0A_SIFSEL)>>REG0AS_SIFSEL)==3) + { + DBGCOMPLETED; + return status; + } + + /* coarse gain calibration is always done in color mode */ + channels = 3; + + /* follow CKSEL */ + if(dev->settings.xressettings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + try { + status = gl124_init_scan_regs(dev, sensor, ®s, params); + } catch (...) { + try { + sanei_genesys_set_motor_power(regs, false); + } catch (...) {} + throw; + } + + sanei_genesys_set_motor_power(regs, false); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + RIE (dev->model->cmd_set->bulk_write_register(dev, regs)); + + total_size = pixels * channels * (16/bpp) * lines; + + std::vector line(total_size); + + RIE(gl124_set_fe(dev, sensor, AFE_SET)); + RIE(gl124_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl124_gain.pnm", line.data(), bpp, channels, pixels, lines); + + /* average value on each channel */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + for (i = pixels/4; i < (pixels*3/4); i++) + { + if(bpp==16) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * pixels + 1] * 256 + + line[i * 2 + j * 2 * pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + } + else + { + if (dev->model->is_cis) + val = line[i + j * pixels]; + else + val = line[i * channels + j]; + } + + max[j] += val; + } + max[j] = max[j] / (pixels/2); + + gain[j] = ((float) sensor.gain_white_ref*coeff) / max[j]; + + /* turn logical gain value into gain code, checking for overflow */ + code = 283 - 208 / gain[j]; + if (code > 255) + code = 255; + else if (code < 0) + code = 0; + dev->frontend.set_gain(j, code); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], + gain[j], dev->frontend.get_gain(j)); + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + if (channels == 1) { + dev->frontend.set_gain(0, dev->frontend.get_gain(1)); + dev->frontend.set_gain(2, dev->frontend.get_gain(1)); + } + + RIE (gl124_stop_action (dev)); + + status = gl124_slow_back_home (dev, SANE_TRUE); + + DBGCOMPLETED; + return status; +} + +/* + * wait for lamp warmup by scanning the same line until difference + * between 2 scans is below a threshold + */ +static SANE_Status +gl124_init_regs_for_warmup (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + int *channels, int *total_size) +{ + int num_pixels; + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + if (dev == NULL || reg == NULL || channels == NULL || total_size == NULL) + return SANE_STATUS_INVAL; + + *channels=3; + + *reg = dev->reg; + + SetupParams params; + params.xres = sensor.optical_res; + params.yres = dev->motor.base_ydpi; + params.startx = sensor.sensor_pixels / 4; + params.starty = 0; + params.pixels = sensor.sensor_pixels / 2; + params.lines = 1; + params.depth = 8; + params.channels = *channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl124_init_scan_regs(dev, sensor, reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + num_pixels = dev->current_setup.pixels; + + *total_size = num_pixels * 3 * 1; /* colors * bytes_per_color * scan lines */ + + sanei_genesys_set_motor_power(*reg, false); + RIE (dev->model->cmd_set->bulk_write_register(dev, *reg)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief default GPIO values + * set up GPIO/GPOE for idle state + * @param dev device to set up + * @return SANE_STATUS_GOOD unless a GPIO register cannot be written + */ +static SANE_Status +gl124_init_gpio (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + int idx; + + DBGSTART; + + /* per model GPIO layout */ + if (dev->model->model_id == MODEL_CANON_LIDE_110) + { + idx = 0; + } + else if (dev->model->model_id == MODEL_CANON_LIDE_120) + { + idx = 2; + } + else + { /* canon LiDE 210 and 220 case */ + idx = 1; + } + + RIE (sanei_genesys_write_register (dev, REG31, gpios[idx].r31)); + RIE (sanei_genesys_write_register (dev, REG32, gpios[idx].r32)); + RIE (sanei_genesys_write_register (dev, REG33, gpios[idx].r33)); + RIE (sanei_genesys_write_register (dev, REG34, gpios[idx].r34)); + RIE (sanei_genesys_write_register (dev, REG35, gpios[idx].r35)); + RIE (sanei_genesys_write_register (dev, REG36, gpios[idx].r36)); + RIE (sanei_genesys_write_register (dev, REG38, gpios[idx].r38)); + + DBGCOMPLETED; + return status; +} + +/** + * set memory layout by filling values in dedicated registers + */ +static SANE_Status +gl124_init_memory_layout (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + int idx = 0; + + DBGSTART; + + /* point to per model memory layout */ + if (dev->model->model_id == MODEL_CANON_LIDE_110 ||dev->model->model_id == MODEL_CANON_LIDE_120) + { + idx = 0; + } + else + { /* canon LiDE 210 and 220 case */ + idx = 1; + } + + /* setup base address for shading data. */ + /* values must be multiplied by 8192=0x4000 to give address on AHB */ + /* R-Channel shading bank0 address setting for CIS */ + sanei_genesys_write_register (dev, 0xd0, layouts[idx].rd0); + /* G-Channel shading bank0 address setting for CIS */ + sanei_genesys_write_register (dev, 0xd1, layouts[idx].rd1); + /* B-Channel shading bank0 address setting for CIS */ + sanei_genesys_write_register (dev, 0xd2, layouts[idx].rd2); + + /* setup base address for scanned data. */ + /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ + /* R-Channel ODD image buffer 0x0124->0x92000 */ + /* size for each buffer is 0x16d*1k word */ + sanei_genesys_write_register (dev, 0xe0, layouts[idx].re0); + sanei_genesys_write_register (dev, 0xe1, layouts[idx].re1); + /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ + sanei_genesys_write_register (dev, 0xe2, layouts[idx].re2); + sanei_genesys_write_register (dev, 0xe3, layouts[idx].re3); + + /* R-Channel EVEN image buffer 0x0292 */ + sanei_genesys_write_register (dev, 0xe4, layouts[idx].re4); + sanei_genesys_write_register (dev, 0xe5, layouts[idx].re5); + /* R-Channel EVEN image buffer end-address 0x03ff*/ + sanei_genesys_write_register (dev, 0xe6, layouts[idx].re6); + sanei_genesys_write_register (dev, 0xe7, layouts[idx].re7); + + /* same for green, since CIS, same addresses */ + sanei_genesys_write_register (dev, 0xe8, layouts[idx].re0); + sanei_genesys_write_register (dev, 0xe9, layouts[idx].re1); + sanei_genesys_write_register (dev, 0xea, layouts[idx].re2); + sanei_genesys_write_register (dev, 0xeb, layouts[idx].re3); + sanei_genesys_write_register (dev, 0xec, layouts[idx].re4); + sanei_genesys_write_register (dev, 0xed, layouts[idx].re5); + sanei_genesys_write_register (dev, 0xee, layouts[idx].re6); + sanei_genesys_write_register (dev, 0xef, layouts[idx].re7); + +/* same for blue, since CIS, same addresses */ + sanei_genesys_write_register (dev, 0xf0, layouts[idx].re0); + sanei_genesys_write_register (dev, 0xf1, layouts[idx].re1); + sanei_genesys_write_register (dev, 0xf2, layouts[idx].re2); + sanei_genesys_write_register (dev, 0xf3, layouts[idx].re3); + sanei_genesys_write_register (dev, 0xf4, layouts[idx].re4); + sanei_genesys_write_register (dev, 0xf5, layouts[idx].re5); + sanei_genesys_write_register (dev, 0xf6, layouts[idx].re6); + sanei_genesys_write_register (dev, 0xf7, layouts[idx].re7); + + DBGCOMPLETED; + return status; +} + +/** + * initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +static SANE_Status +gl124_init(Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG_INIT (); + DBGSTART; + + status=sanei_genesys_asic_init(dev, 0); + + DBGCOMPLETED; + return status; +} + + +/* * + * initialize ASIC from power on condition + */ +static SANE_Status +gl124_boot (Genesys_Device * dev, SANE_Bool cold) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + DBGSTART; + + /* reset ASIC in case of cold boot */ + if(cold) + { + RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); + RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); + } + + /* enable GPOE 17 */ + RIE (sanei_genesys_write_register (dev, 0x36, 0x01)); + + /* set GPIO 17 */ + RIE (sanei_genesys_read_register (dev, 0x33, &val)); + val |= 0x01; + RIE (sanei_genesys_write_register (dev, 0x33, val)); + + /* test CHKVER */ + RIE (sanei_genesys_read_register (dev, REG100, &val)); + if (val & REG100_CHKVER) + { + RIE (sanei_genesys_read_register (dev, 0x00, &val)); + DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); + } + + /* Set default values for registers */ + gl124_init_registers (dev); + + /* Write initial registers */ + RIE (dev->model->cmd_set->bulk_write_register(dev, dev->reg)); + + /* tune reg 0B */ + val = REG0B_30MHZ | REG0B_ENBDRAM | REG0B_64M; + RIE (sanei_genesys_write_register (dev, REG0B, val)); + dev->reg.remove_reg(0x0b); + + /* set up end access */ + RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0b)); + RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); + + /* CIS_LINE */ + SETREG (0x08, REG08_CIS_LINE); + RIE (sanei_genesys_write_register (dev, 0x08, dev->reg.find_reg(0x08).value)); + + /* setup gpio */ + RIE (gl124_init_gpio (dev)); + + /* setup internal memory layout */ + RIE (gl124_init_memory_layout (dev)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +static SANE_Status +gl124_update_hardware_sensors (Genesys_Scanner * s) +{ + /* do what is needed to get a new set of events, but try to not loose + any of them. + */ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val=0; + + RIE (sanei_genesys_read_register (s->dev, REG31, &val)); + + /* TODO : for the next scanner special case, + * add another per scanner button profile struct to avoid growing + * hard-coded button mapping here. + */ + if((s->dev->model->gpo_type == GPO_CANONLIDE110) + ||(s->dev->model->gpo_type == GPO_CANONLIDE120)) + { + s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_FILE_SW].write((val & 0x08) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); + s->buttons[BUTTON_COPY_SW].write((val & 0x02) == 0); + } + else + { /* LiDE 210 case */ + s->buttons[BUTTON_EXTRA_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_SCAN_SW].write((val & 0x02) == 0); + s->buttons[BUTTON_COPY_SW].write((val & 0x04) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & 0x08) == 0); + s->buttons[BUTTON_FILE_SW].write((val & 0x10) == 0); + } + return status; +} + + +/** the gl124 command set */ +static Genesys_Command_Set gl124_cmd_set = { + "gl124-generic", /* the name of this set */ + + [](Genesys_Device* dev) -> bool { (void) dev; return true; }, + + gl124_init, + gl124_init_regs_for_warmup, + gl124_init_regs_for_coarse_calibration, + gl124_init_regs_for_shading, + gl124_init_regs_for_scan, + + gl124_get_filter_bit, + gl124_get_lineart_bit, + gl124_get_bitset_bit, + gl124_get_gain4_bit, + gl124_get_fast_feed_bit, + gl124_test_buffer_empty_bit, + gl124_test_motor_flag_bit, + + gl124_set_fe, + gl124_set_powersaving, + gl124_save_power, + + gl124_begin_scan, + gl124_end_scan, + + sanei_genesys_send_gamma_table, + + gl124_search_start_position, + + gl124_offset_calibration, + gl124_coarse_gain_calibration, + gl124_led_calibration, + + gl124_wait_for_motor_stop, + gl124_slow_back_home, + gl124_rewind, + + sanei_genesys_bulk_write_register, + NULL, + sanei_genesys_bulk_read_data, + + gl124_update_hardware_sensors, + + /* no sheetfed support for now */ + NULL, + NULL, + NULL, + NULL, + + sanei_genesys_is_compatible_calibration, + NULL, + gl124_send_shading_data, + gl124_calculate_current_setup, + gl124_boot +}; + +SANE_Status +sanei_gl124_init_cmd_set (Genesys_Device * dev) +{ + dev->model->cmd_set = &gl124_cmd_set; + return SANE_STATUS_GOOD; +} diff --git a/backend/genesys_gl124.h b/backend/genesys_gl124.h index 9ca6afd..751321d 100644 --- a/backend/genesys_gl124.h +++ b/backend/genesys_gl124.h @@ -301,228 +301,7 @@ #define REG_TRUEG 0x111 #define REG_TRUEB 0x112 -/** - * writable scanner registers */ -enum -{ - reg_0x01 = 0, - reg_0x02, - reg_0x03, - reg_0x04, - reg_0x05, - reg_0x06, - reg_0x07, - reg_0x08, - reg_0x09, - reg_0x0a, - reg_0x0b, - reg_0x0c, - reg_0x11, - reg_0x12, - reg_0x13, - reg_0x14, - reg_0x15, - reg_0x16, - reg_0x17, - reg_0x18, - reg_0x19, - reg_0x1a, - reg_0x1b, - reg_0x1c, - reg_0x1d, - reg_0x1e, - reg_0x1f, - reg_0x20, - reg_0x21, - reg_0x22, - reg_0x23, - reg_0x24, - reg_0x25, - reg_0x26, - reg_0x27, - reg_0x28, - reg_0x29, - reg_0x2a, - reg_0x2b, - reg_0x2c, - reg_0x2d, - reg_0x3b, - reg_0x3c, - reg_0x3d, - reg_0x3e, - reg_0x3f, - reg_0x40, - reg_0x41, - reg_0x42, - reg_0x43, - reg_0x44, - reg_0x45, - reg_0x46, - reg_0x47, - reg_0x48, - reg_0x49, - reg_0x4f, - reg_0x52, - reg_0x53, - reg_0x54, - reg_0x55, - reg_0x56, - reg_0x57, - reg_0x58, - reg_0x59, - reg_0x5a, - reg_0x5b, - reg_0x5c, - reg_0x5f, - reg_0x60, - reg_0x61, - reg_0x62, - reg_0x63, - reg_0x64, - reg_0x65, - reg_0x66, - reg_0x67, - reg_0x68, - reg_0x69, - reg_0x6a, - reg_0x6b, - reg_0x6c, - reg_0x6d, - reg_0x6e, - reg_0x6f, - reg_0x70, - reg_0x71, - reg_0x72, - reg_0x73, - reg_0x74, - reg_0x75, - reg_0x76, - reg_0x77, - reg_0x78, - reg_0x79, - reg_0x7a, - reg_0x7b, - reg_0x7c, - reg_0x7d, - reg_0x7e, - reg_0x7f, - reg_0x80, - reg_0x81, - reg_0x82, - reg_0x83, - reg_0x84, - reg_0x85, - reg_0x86, - reg_0x87, - reg_0x88, - reg_0x89, - reg_0x8a, - reg_0x8b, - reg_0x8c, - reg_0x8d, - reg_0x8e, - reg_0x8f, - reg_0x90, - reg_0x91, - reg_0x92, - reg_0x93, - reg_0x94, - reg_0x95, - reg_0x96, - reg_0x97, - reg_0x98, - reg_0x99, - reg_0x9a, - reg_0x9b, - reg_0x9c, - reg_0x9d, - reg_0x9e, - reg_0x9f, - reg_0xa0, - reg_0xa1, - reg_0xa2, - reg_0xa3, - reg_0xa4, - reg_0xa5, - reg_0xa6, - reg_0xa7, - reg_0xa8, - reg_0xa9, - reg_0xaa, - reg_0xab, - reg_0xac, - reg_0xad, - reg_0xae, - reg_0xaf, - reg_0xb0, - reg_0xb1, - reg_0xb2, - reg_0xb3, - reg_0xb4, - reg_0xb5, - reg_0xb6, - reg_0xb7, - reg_0xb8, - reg_0xbb, - reg_0xbc, - reg_0xbd, - reg_0xbe, - reg_0xc3, - reg_0xc4, - reg_0xc5, - reg_0xc6, - reg_0xc7, - reg_0xc8, - reg_0xc9, - reg_0xca, - reg_0xcb, - reg_0xcc, - reg_0xcd, - reg_0xce, - reg_0xd0, - reg_0xd1, - reg_0xd2, - reg_0xd3, - reg_0xd4, - reg_0xd5, - reg_0xd6, - reg_0xd7, - reg_0xd8, - reg_0xd9, - reg_0xe0, - reg_0xe1, - reg_0xe2, - reg_0xe3, - reg_0xe4, - reg_0xe5, - reg_0xe6, - reg_0xe7, - reg_0xe8, - reg_0xe9, - reg_0xea, - reg_0xeb, - reg_0xec, - reg_0xed, - reg_0xee, - reg_0xef, - reg_0xf0, - reg_0xf1, - reg_0xf2, - reg_0xf3, - reg_0xf4, - reg_0xf5, - reg_0xf6, - reg_0xf7, - reg_0xf8, - reg_0xf9, - reg_0xfa, - reg_0xfb, - reg_0xfc, - reg_0xff, - GENESYS_GL124_MAX_REGS -}; - -#define SETREG(adr,val) {dev->reg[reg_##adr].address=adr;dev->reg[reg_##adr].value=val;} +#define SETREG(adr,val) { dev->reg.init_reg(adr, val); } typedef struct { @@ -616,8 +395,6 @@ typedef struct { static size_t order_01[]={0,1}; static size_t order_0213[]={0,2,1,3}; -/* *INDENT-OFF* */ - /** @brief database of sensor profiles * database of sensor profiles giving for each sensor and a given resolution, the period, and timings * to setup the sensor for the scan. @@ -684,63 +461,29 @@ static Motor_Profile motors[]={ {MOTOR_CANONLIDE210, 20864, 2, lide210_max}, {0, 0, 0, NULL}, }; -/* *INDENT-ON* */ -GENESYS_STATIC -SANE_Status gl124_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int scan_method, - int scan_mode, - int color_filter, - unsigned int flags); - -#ifndef UNIT_TESTING -static -#endif - SANE_Status gl124_start_action (Genesys_Device * dev); -#ifndef UNIT_TESTING + static -#endif - SANE_Status -gl124_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, +SANE_Status gl124_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, SetupParams& params); + +static SANE_Status gl124_start_action (Genesys_Device * dev); +static SANE_Status +gl124_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, SANE_Bool start_motor); -#ifndef UNIT_TESTING -static -#endif - SANE_Status +static SANE_Status gl124_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool check_stop); -#ifndef UNIT_TESTING -static -#endif - SANE_Status +static SANE_Status gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl124_init (Genesys_Device * dev); -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl124_send_shading_data (Genesys_Device * dev, uint8_t * data, int size); +static SANE_Status gl124_init(Genesys_Device * dev); +static SANE_Status gl124_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, int size); -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse); +static SANE_Status gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse); -GENESYS_STATIC SANE_Status +static SANE_Status gl124_stop_action (Genesys_Device * dev); -GENESYS_STATIC SANE_Status +static SANE_Status gl124_send_slope_table (Genesys_Device * dev, int table_nr, uint16_t * slope_table, int steps); - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl646.c b/backend/genesys_gl646.c deleted file mode 100644 index 58952fb..0000000 --- a/backend/genesys_gl646.c +++ /dev/null @@ -1,5799 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003 Oliver Rauch - Copyright (C) 2003, 2004 Henning Meier-Geinitz - Copyright (C) 2004 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2007 Luke - Copyright (C) 2011 Alexey Osipov for HP2400 description - and tuning - - 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. -*/ - -#undef BACKEND_NAME -#define BACKEND_NAME genesys_gl646 - -#include "genesys_gl646.h" - -/** - * returns the value hold by a 3 word register - * @param regs register set from which reading the value - * @param regnum number of the register to read - * @return 24 bit value of the register - */ -static uint32_t -gl646_get_triple_reg (Genesys_Register_Set * regs, int regnum) -{ - Genesys_Register_Set *r = NULL; - uint32_t ret = 0; - - r = sanei_genesys_get_address (regs, regnum); - ret = r->value; - r = sanei_genesys_get_address (regs, regnum + 1); - ret = (ret << 8) + r->value; - r = sanei_genesys_get_address (regs, regnum + 2); - ret = (ret << 8) + r->value; - - return ret; -} - -/** - * returns the value hold by a 2 word register - * @param regs register set from which reading the value - * @param regnum number of the register to read - * @return 16 bit value of the register - */ -static uint32_t -gl646_get_double_reg (Genesys_Register_Set * regs, int regnum) -{ - Genesys_Register_Set *r = NULL; - uint32_t ret = 0; - - r = sanei_genesys_get_address (regs, regnum); - ret = r->value; - r = sanei_genesys_get_address (regs, regnum + 1); - ret = (ret << 8) + r->value; - - return ret; -} - -/* Write to many registers */ -static SANE_Status -gl646_bulk_write_register (Genesys_Device * dev, - Genesys_Register_Set * reg, size_t elems) -{ - SANE_Status status; - uint8_t outdata[8]; - uint8_t buffer[GENESYS_MAX_REGS * 2]; - size_t size; - unsigned int i; - - /* handle differently sized register sets, reg[0x00] may be the last one */ - i = 0; - while ((i < elems) && (reg[i].address != 0)) - i++; - elems = i; - size = i * 2; - - DBG (DBG_io, "gl646_bulk_write_register (elems= %lu, size = %lu)\n", - (u_long) elems, (u_long) size); - - - outdata[0] = BULK_OUT; - outdata[1] = BULK_REGISTER; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_register: failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - /* copy registers and values in data buffer */ - for (i = 0; i < size; i += 2) - { - buffer[i] = reg[i / 2].address; - buffer[i + 1] = reg[i / 2].value; - } - - status = sanei_usb_write_bulk (dev->dn, buffer, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_register: failed while writing bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_io2) - { - for (i = 0; i < size; i += 2) - { - DBG (DBG_io2, "reg[0x%02x] = 0x%02x\n", buffer[i], buffer[i + 1]); - } - /* when full size, decode register content */ - if (elems > 60) - { - DBG (DBG_io2, "DPISET =%d\n", - gl646_get_double_reg (reg, REG_DPISET)); - DBG (DBG_io2, "DUMMY =%d\n", - sanei_genesys_get_address (reg, REG_DUMMY)->value); - DBG (DBG_io2, "STRPIXEL =%d\n", - gl646_get_double_reg (reg, REG_STRPIXEL)); - DBG (DBG_io2, "ENDPIXEL =%d\n", - gl646_get_double_reg (reg, REG_ENDPIXEL)); - DBG (DBG_io2, "LINCNT =%d\n", - gl646_get_triple_reg (reg, REG_LINCNT)); - DBG (DBG_io2, "MAXWD =%d\n", - gl646_get_triple_reg (reg, REG_MAXWD)); - DBG (DBG_io2, "LPERIOD =%d\n", - gl646_get_double_reg (reg, REG_LPERIOD)); - DBG (DBG_io2, "FEEDL =%d\n", - gl646_get_triple_reg (reg, REG_FEEDL)); - } - } - - DBG (DBG_io, "gl646_bulk_write_register: wrote %lu bytes, %lu registers\n", - (u_long) size, (u_long) elems); - return status; -} - -/* Write bulk data (e.g. shading, gamma) */ -static SANE_Status -gl646_bulk_write_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size; - uint8_t outdata[8]; - - DBG (DBG_io, "gl646_bulk_write_data writing %lu bytes\n", (u_long) len); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_data failed while setting register: %s\n", - sane_strstatus (status)); - return status; - } - - while (len) - { - if (len > BULKOUT_MAXSIZE) - size = BULKOUT_MAXSIZE; - else - size = len; - - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), - outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_data failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_usb_write_bulk (dev->dn, data, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_write_data failed while writing bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "gl646_bulk_write_data wrote %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (len - size)); - - len -= size; - data += size; - } - - DBG (DBG_io, "gl646_bulk_write_data: end\n"); - - return status; -} - -/** - * reads value from gpio endpoint - */ -static SANE_Status -gl646_gpio_read (SANE_Int dn, uint8_t * value) -{ - return sanei_usb_control_msg (dn, REQUEST_TYPE_IN, - REQUEST_REGISTER, GPIO_READ, INDEX, 1, value); -} - -/** - * writes the given value to gpio endpoint - */ -static SANE_Status -gl646_gpio_write (SANE_Int dn, uint8_t value) -{ - DBG (DBG_proc, "gl646_gpio_write(0x%02x)\n", value); - return sanei_usb_control_msg (dn, REQUEST_TYPE_OUT, - REQUEST_REGISTER, GPIO_WRITE, - INDEX, 1, &value); -} - -/** - * writes the given value to gpio output enable endpoint - */ -static SANE_Status -gl646_gpio_output_enable (SANE_Int dn, uint8_t value) -{ - DBG (DBG_proc, "gl646_gpio_output_enable(0x%02x)\n", value); - return sanei_usb_control_msg (dn, REQUEST_TYPE_OUT, - REQUEST_REGISTER, GPIO_OUTPUT_ENABLE, - INDEX, 1, &value); -} - -/* Read bulk data (e.g. scanned data) */ -static SANE_Status -gl646_bulk_read_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size; - uint8_t outdata[8]; - - DBG (DBG_io, "gl646_bulk_read_data: requesting %lu bytes\n", (u_long) len); - - /* write requested size */ - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_read_data failed while setting register: %s\n", - sane_strstatus (status)); - return status; - } - - outdata[0] = BULK_IN; - outdata[1] = BULK_RAM; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (len & 0xff); - outdata[5] = ((len >> 8) & 0xff); - outdata[6] = ((len >> 16) & 0xff); - outdata[7] = ((len >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_read_data failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - while (len) - { - if (len > GL646_BULKIN_MAXSIZE) - size = GL646_BULKIN_MAXSIZE; - else - size = len; - - DBG (DBG_io2, - "gl646_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) size); - status = sanei_usb_read_bulk (dev->dn, data, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "gl646_bulk_read_data read %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (len - size)); - - len -= size; - data += size; - } - - if (dev->model->is_sheetfed == SANE_TRUE) - { - gl646_detect_document_end (dev); - } - - DBG (DBG_io, "gl646_bulk_read_data: end\n"); - - return status; -} - -#if 0 -static SANE_Status -read_triple_reg (Genesys_Device * dev, int index, unsigned int *words) -{ - SANE_Status status; - uint8_t value; - - DBG (DBG_proc, "read_triple_reg\n"); - - RIE (sanei_genesys_read_register (dev, index + 2, &value)); - *words = value; - RIE (sanei_genesys_read_register (dev, index + 1, &value)); - *words += (value * 256); - RIE (sanei_genesys_read_register (dev, index, &value)); - if (dev->model->asic_type == GENESYS_GL646) - *words += ((value & 0x03) * 256 * 256); - else - *words += ((value & 0x0f) * 256 * 256); - - DBG (DBG_proc, "read_triple_reg: value=%d\n", *words); - return status; -} -#endif - - -static SANE_Bool -gl646_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_filter_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_lineart_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_bitset_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_gain4_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTMFLG) - return SANE_TRUE; - return SANE_FALSE; -} - -static void -gl646_set_triple_reg (Genesys_Register_Set * regs, int regnum, uint32_t value) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, regnum); - r->value = LOBYTE (HIWORD (value)); - r = sanei_genesys_get_address (regs, regnum + 1); - r->value = HIBYTE (LOWORD (value)); - r = sanei_genesys_get_address (regs, regnum + 2); - r->value = LOBYTE (LOWORD (value)); -} - -static void -gl646_set_double_reg (Genesys_Register_Set * regs, int regnum, uint16_t value) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, regnum); - r->value = HIBYTE (LOWORD (value)); - r = sanei_genesys_get_address (regs, regnum + 1); - r->value = LOBYTE (LOWORD (value)); -} - -/** - * decodes and prints content of status (0x41) register - * @param val value read from reg41 - */ -static void -print_status (uint8_t val) -{ - char msg[80]; - - sprintf (msg, "%s%s%s%s%s%s%s%s", - val & REG41_PWRBIT ? "PWRBIT " : "", - val & REG41_BUFEMPTY ? "BUFEMPTY " : "", - val & REG41_FEEDFSH ? "FEEDFSH " : "", - val & REG41_SCANFSH ? "SCANFSH " : "", - val & REG41_HOMESNR ? "HOMESNR " : "", - val & REG41_LAMPSTS ? "LAMPSTS " : "", - val & REG41_FEBUSY ? "FEBUSY " : "", - val & REG41_MOTMFLG ? "MOTMFLG" : ""); - DBG (DBG_info, "status=%s\n", msg); -} - -/** - * start scanner's motor - * @param dev scanner's device - */ -static SANE_Status -gl646_start_motor (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - - -/** - * stop scanner's motor - * @param dev scanner's device - */ -static SANE_Status -gl646_stop_motor (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x00); -} - - -/** - * find the lowest resolution for the sensor in the given mode. - * @param sensor id of the sensor - * @param color true is color mode - * @return the closest resolution for the sensor and mode - */ -static int -get_lowest_resolution (int sensor, SANE_Bool color) -{ - int i, nb; - int dpi; - - i = 0; - dpi = 9600; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* computes distance and keep mode if it is closer than previous */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].color == color) - { - if (sensor_master[i].dpi < dpi) - { - dpi = sensor_master[i].dpi; - } - } - i++; - } - DBG (DBG_info, "get_lowest_resolution: %d\n", dpi); - return dpi; -} - -/** - * find the closest match in mode tables for the given resolution and scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return the closest resolution for the sensor and mode - */ -static int -get_closest_resolution (int sensor, int required, SANE_Bool color) -{ - int i, nb; - int dist, dpi; - - i = 0; - dpi = 0; - dist = 9600; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].color == color) - { - DBG (DBG_info, "get_closest_resolution: match found for %d\n", - required); - return required; - } - /* computes distance and keep mode if it is closer than previous */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].color == color) - { - if (abs (sensor_master[i].dpi - required) < dist) - { - dpi = sensor_master[i].dpi; - dist = abs (sensor_master[i].dpi - required); - } - } - i++; - } - DBG (DBG_info, "get_closest_resolution: closest match for %d is %d\n", - required, dpi); - return dpi; -} - -/** - * Computes if sensor will be set up for half ccd pixels for the given - * scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return SANE_TRUE if half ccd is used - */ -static SANE_Bool -is_half_ccd (int sensor, int required, SANE_Bool color) -{ - int i, nb; - - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].color == color) - { - DBG (DBG_io, "is_half_ccd: match found for %d (half_ccd=%d)\n", - required, sensor_master[i].half_ccd); - return sensor_master[i].half_ccd; - } - i++; - } - DBG (DBG_info, "is_half_ccd: failed to find match for %d dpi\n", required); - return SANE_FALSE; -} - -/** - * Returns the cksel values used by the required scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return cksel value for mode - */ -static int -get_cksel (int sensor, int required, SANE_Bool color) -{ - int i, nb; - - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].color == color) - { - DBG (DBG_io, "get_cksel: match found for %d (cksel=%d)\n", - required, sensor_master[i].cksel); - return sensor_master[i].cksel; - } - i++; - } - DBG (DBG_error, "get_cksel: failed to find match for %d dpi\n", required); - /* fail safe fallback */ - return 1; -} - -/** - * Setup register and motor tables for a scan at the - * given resolution and color mode. TODO try to not use any filed from - * the device. - * @param dev pointer to a struct describing the device - * @param regs register set to fill - * @param scan_settings scan's settings - * @param slope_table1 first motor table to fill - * @param slope_table2 second motor table to fill - * @param resolution dpi of the scan - * @param move distance to move (at scan's dpi) before scan - * @param linecnt number of lines to scan at scan's dpi - * @param startx start of scan area on CCD at CCD's optical resolution - * @param endx end of scan area on CCD at CCD's optical resolution - * @param color SANE_TRUE is color scan - * @param depth 1, 8 or 16 bits data sample - * @return SANE_STATUS_GOOD if registers could be set, SANE_STATUS_INVAL if - * conditions can't be met. - * @note No harcoded SENSOR or MOTOR 'names' should be present and - * registers are set from settings tables and flags related - * to the hardware capabilities. - * */ -static SANE_Status -gl646_setup_registers (Genesys_Device * dev, - Genesys_Register_Set * regs, - Genesys_Settings scan_settings, - uint16_t * slope_table1, - uint16_t * slope_table2, - SANE_Int resolution, - uint32_t move, - uint32_t linecnt, - uint16_t startx, - uint16_t endx, SANE_Bool color, - SANE_Int depth) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i, nb; - Sensor_Master *sensor = NULL; - Motor_Master *motor = NULL; - Sensor_Settings *settings = NULL; - Genesys_Register_Set *r; - unsigned int used1, used2, vfinal; - unsigned int bpp; /**> bytes per pixel */ - uint32_t z1, z2; - uint16_t ex, sx; - int channels = 1, stagger, words_per_line, max_shift; - size_t requested_buffer_size; - size_t read_buffer_size; - SANE_Bool half_ccd = SANE_FALSE; - SANE_Int xresolution; - int feedl; - - DBG (DBG_proc, "gl646_setup_registers: start\n"); - DBG (DBG_info, "gl646_setup_registers: startx=%d, endx=%d, linecnt=%d\n", - startx, endx, linecnt); - - /* x resolution is capped by sensor's capability */ - if (resolution > dev->sensor.optical_res) - { - xresolution = dev->sensor.optical_res; - } - else - { - xresolution = resolution; - } - - /* for the given resolution, search for master - * sensor mode setting */ - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - if (dev->model->ccd_type == sensor_master[i].sensor - && sensor_master[i].dpi == xresolution - && sensor_master[i].color == color) - { - sensor = &sensor_master[i]; - } - i++; - } - if (sensor == NULL) - { - DBG (DBG_error, - "gl646_setup_registers: unable to find settings for sensor %d at %d dpi color=%d\n", - dev->model->ccd_type, xresolution, color); - return SANE_STATUS_INVAL; - } - - /* for the given resolution, search for master - * motor mode setting */ - i = 0; - nb = sizeof (motor_master) / sizeof (Motor_Master); - while (i < nb) - { - if (dev->model->motor_type == motor_master[i].motor - && motor_master[i].dpi == resolution - && motor_master[i].color == color) - { - motor = &motor_master[i]; - } - i++; - } - if (motor == NULL) - { - DBG (DBG_error, - "gl646_setup_registers: unable to find settings for motor %d at %d dpi, color=%d\n", - dev->model->motor_type, resolution, color); - return SANE_STATUS_INVAL; - } - - /* now we can search for the specific sensor settings */ - i = 0; - nb = sizeof (sensor_settings) / sizeof (Sensor_Settings); - while (i < nb) - { - if (sensor->sensor == sensor_settings[i].sensor - && sensor->cksel == sensor_settings[i].cksel) - { - settings = &sensor_settings[i]; - } - i++; - } - if (settings == NULL) - { - DBG (DBG_error, - "gl646_setup_registers: unable to find settings for sensor %d with '%d' ccd timing\n", - sensor->sensor, sensor->cksel); - return SANE_STATUS_INVAL; - } - - /* half_ccd if manual clock programming or dpi is half dpiset */ - half_ccd = sensor->half_ccd; - - /* now apply values from settings to registers */ - if (sensor->regs_0x10_0x15 != NULL) - { - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = sensor->regs_0x10_0x15[i]; - } - } - else - { - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = 0; - } - } - - for (i = 0; i < 4; i++) - { - r = sanei_genesys_get_address (regs, 0x08 + i); - if (half_ccd == SANE_TRUE) - r->value = settings->manual_0x08_0x0b[i]; - else - r->value = settings->regs_0x08_0x0b[i]; - } - - for (i = 0; i < 8; i++) - { - r = sanei_genesys_get_address (regs, 0x16 + i); - r->value = settings->regs_0x16_0x1d[i]; - } - - for (i = 0; i < 13; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - r->value = settings->regs_0x52_0x5e[i]; - } - if (half_ccd == SANE_TRUE) - { - for (i = 0; i < 7; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - r->value = settings->manual_0x52_0x58[i]; - } - } - - /* now generate slope tables : we are not using generate_slope_table3 yet */ - sanei_genesys_generate_slope_table (slope_table1, motor->steps1, - motor->steps1 + 1, motor->vend1, - motor->vstart1, motor->vend1, - motor->steps1, motor->g1, &used1, - &vfinal); - sanei_genesys_generate_slope_table (slope_table2, motor->steps2, - motor->steps2 + 1, motor->vend2, - motor->vstart2, motor->vend2, - motor->steps2, motor->g2, &used2, - &vfinal); - - if (color == SANE_TRUE) - channels = 3; - else - channels = 1; - - /* R01 */ - /* now setup other registers for final scan (ie with shading enabled) */ - /* watch dog + shading + scan enable */ - regs[reg_0x01].value |= REG01_DOGENB | REG01_DVDSET | REG01_SCAN; - if (dev->model->is_cis == SANE_TRUE) - regs[reg_0x01].value |= REG01_CISSET; - else - regs[reg_0x01].value &= ~REG01_CISSET; - - /* if device has no calibration, don't enable shading correction */ - if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) - { - regs[reg_0x01].value &= ~REG01_DVDSET; - } - - regs[reg_0x01].value &= ~REG01_FASTMOD; - if (motor->fastmod) - regs[reg_0x01].value |= REG01_FASTMOD; - - /* R02 */ - /* allow moving when buffer full by default */ - if (dev->model->is_sheetfed == SANE_FALSE) - dev->reg[reg_0x02].value &= ~REG02_ACDCDIS; - else - dev->reg[reg_0x02].value |= REG02_ACDCDIS; - - /* setup motor power and direction */ - regs[reg_0x02].value |= REG02_MTRPWR; - regs[reg_0x02].value &= ~REG02_MTRREV; - - /* fastfed enabled (2 motor slope tables) */ - if (motor->fastfed) - regs[reg_0x02].value |= REG02_FASTFED; - else - regs[reg_0x02].value &= ~REG02_FASTFED; - - /* step type */ - regs[reg_0x02].value &= ~REG02_STEPSEL; - switch (motor->steptype) - { - case FULL_STEP: - break; - case HALF_STEP: - regs[reg_0x02].value |= 1; - break; - case QUATER_STEP: - regs[reg_0x02].value |= 2; - break; - default: - regs[reg_0x02].value |= 3; - break; - } - - /* if sheetfed, no AGOHOME */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - regs[reg_0x02].value &= ~REG02_AGOHOME; - } - else - { - regs[reg_0x02].value |= REG02_AGOHOME; - } - - /* R03 */ - regs[reg_0x03].value &= ~REG03_AVEENB; - /* regs[reg_0x03].value |= REG03_AVEENB; */ - regs[reg_0x03].value &= ~REG03_LAMPDOG; - - /* select XPA */ - regs[reg_0x03].value &= ~REG03_XPASEL; - if (scan_settings.scan_method == SCAN_METHOD_TRANSPARENCY) - { - regs[reg_0x03].value |= REG03_XPASEL; - } - - /* R04 */ - /* monochrome / color scan */ - switch (depth) - { - case 1: - regs[reg_0x04].value &= ~REG04_BITSET; - regs[reg_0x04].value |= REG04_LINEART; - break; - case 8: - regs[reg_0x04].value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - regs[reg_0x04].value &= ~REG04_LINEART; - regs[reg_0x04].value |= REG04_BITSET; - break; - } - - /* R05 */ - regs[reg_0x05].value &= ~REG05_DPIHW; - switch (dev->sensor.optical_res) - { - case 600: - regs[reg_0x05].value |= REG05_DPIHW_600; - break; - case 1200: - regs[reg_0x05].value |= REG05_DPIHW_1200; - break; - case 2400: - regs[reg_0x05].value |= REG05_DPIHW_2400; - break; - default: - regs[reg_0x05].value |= REG05_DPIHW; - } - - /* gamma enable for scans */ - if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) - regs[reg_0x05].value |= REG05_GMM14BIT; - - regs[reg_0x05].value &= ~REG05_GMMENB; - - /* true CIS gray if needed */ - if (dev->model->is_cis == SANE_TRUE && color == SANE_FALSE - && dev->settings.true_gray) - { - regs[reg_0x05].value |= REG05_LEDADD; - } - else - { - regs[reg_0x05].value &= ~REG05_LEDADD; - } - - /* cktoggle, ckdelay and cksel at once, cktdelay=2 => half_ccd for md5345 */ - regs[reg_0x18].value = sensor->r18; - - /* manual CCD/2 clock programming => half_ccd for hp2300 */ - regs[reg_0x1d].value = sensor->r1d; - - /* HP2400 1200dpi mode tuning */ - - if (dev->model->ccd_type == CCD_HP2400) - { - /* reset count of dummy lines to zero */ - regs[reg_0x1e].value &= ~REG1E_LINESEL; - if (scan_settings.xres >= 1200) - { - /* there must be one dummy line */ - regs[reg_0x1e].value |= 1 & REG1E_LINESEL; - - /* GPO12 need to be set to zero */ - regs[reg_0x66].value &= ~0x20; - } - else - { - /* set GPO12 back to one */ - regs[reg_0x66].value |= 0x20; - } - } - - /* motor steps used */ - regs[reg_0x21].value = motor->steps1; - regs[reg_0x22].value = motor->fwdbwd; - regs[reg_0x23].value = motor->fwdbwd; - regs[reg_0x24].value = motor->steps1; - - /* scanned area height must be enlarged by max color shift needed */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,scan_settings.yres,0); - - /* we adjust linecnt according to real motor dpi */ - linecnt = (linecnt * motor->ydpi) / scan_settings.yres + max_shift; - - /* at QUATER_STEP lines are 'staggered' and need correction */ - stagger = 0; - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - { - /* for HP3670, stagger happens only at >=1200 dpi */ - if ((dev->model->motor_type != MOTOR_HP3670 - && dev->model->motor_type != MOTOR_HP2400) - || scan_settings.yres >= dev->sensor.optical_res) - { - stagger = (4 * scan_settings.yres) / dev->motor.base_ydpi; - } - } - linecnt += stagger; - - DBG (DBG_info, "gl646_setup_registers : max_shift=%d, stagger=%d lines\n", - max_shift, stagger); - - /* CIS scanners read one line per color channel - * since gray mode use 'add' we also read 3 channels even not in - * color mode */ - if (dev->model->is_cis == SANE_TRUE) - { - gl646_set_triple_reg (regs, REG_LINCNT, linecnt * 3); - linecnt *= channels; - } - else - { - gl646_set_triple_reg (regs, REG_LINCNT, linecnt); - } - - /* scanner's x coordinates are expressed in physical DPI but they must be divided by cksel */ - sx = startx / sensor->cksel; - ex = endx / sensor->cksel; - if (half_ccd == SANE_TRUE) - { - sx /= 2; - ex /= 2; - } - gl646_set_double_reg (regs, REG_STRPIXEL, sx); - gl646_set_double_reg (regs, REG_ENDPIXEL, ex); - DBG (DBG_info, "gl646_setup_registers: startx=%d, endx=%d, half_ccd=%d\n", - sx, ex, half_ccd); - - /* words_per_line must be computed according to the scan's resolution */ - /* in fact, words_per_line _gives_ the actual scan resolution */ - words_per_line = (((endx - startx) * sensor->xdpi) / dev->sensor.optical_res); - bpp=depth/8; - if (depth == 1) - { - words_per_line = (words_per_line+7)/8 ; - bpp=1; - } - else - { - words_per_line *= bpp; - } - dev->bpl = words_per_line; - words_per_line *= channels; - dev->wpl = words_per_line; - - DBG (DBG_info, "gl646_setup_registers: wpl=%d\n", words_per_line); - gl646_set_triple_reg (regs, REG_MAXWD, words_per_line); - - gl646_set_double_reg (regs, REG_DPISET, sensor->dpiset); - gl646_set_double_reg (regs, REG_LPERIOD, sensor->exposure); - - /* move distance must be adjusted to take into account the extra lines - * read to reorder data */ - feedl = move; - if (stagger + max_shift > 0 && feedl != 0) - { - if (feedl > - ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi) - feedl = - feedl - - ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi; - } - - /* we assume all scans are done with 2 tables */ - /* - feedl = feed_steps - fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type); */ - /* but head has moved due to shading calibration => dev->scanhead_position_in_steps */ - if (feedl > 0) - { - /* take into account the distance moved during calibration */ - /* feedl -= dev->scanhead_position_in_steps; */ - DBG (DBG_info, "gl646_setup_registers: initial move=%d\n", feedl); - DBG (DBG_info, "gl646_setup_registers: scanhead_position_in_steps=%d\n", - dev->scanhead_position_in_steps); - - /* TODO clean up this when I'll fully understand. - * for now, special casing each motor */ - switch (dev->model->motor_type) - { - case MOTOR_5345: - switch (motor->ydpi) - { - case 200: - feedl -= 70; - break; - case 300: - feedl -= 70; - break; - case 400: - feedl += 130; - break; - case 600: - feedl += 160; - break; - case 1200: - feedl += 160; - break; - case 2400: - feedl += 180; - break; - default: - break; - } - break; - case MOTOR_HP2300: - switch (motor->ydpi) - { - case 75: - feedl -= 180; - break; - case 150: - feedl += 0; - break; - case 300: - feedl += 30; - break; - case 600: - feedl += 35; - break; - case 1200: - feedl += 45; - break; - default: - break; - } - break; - case MOTOR_HP2400: - switch (motor->ydpi) - { - case 150: - feedl += 150; - break; - case 300: - feedl += 220; - break; - case 600: - feedl += 260; - break; - case 1200: - feedl += 280; /* 300 */ - break; - case 50: - feedl += 0; - break; - case 100: - feedl += 100; - break; - default: - break; - } - break; - - /* theorical value */ - default: - if (motor->fastfed) - { - feedl = - feedl - 2 * motor->steps2 - - (motor->steps1 >> motor->steptype); - } - else - { - feedl = feedl - (motor->steps1 >> motor->steptype); - } - break; - } - /* security */ - if (feedl < 0) - feedl = 0; - } - - DBG (DBG_info, "gl646_setup_registers: final move=%d\n", feedl); - gl646_set_triple_reg (regs, REG_FEEDL, feedl); - - regs[reg_0x65].value = motor->mtrpwm; - - sanei_genesys_calculate_zmode2 (regs[reg_0x02].value & REG02_FASTFED, - sensor->exposure, - slope_table1, - motor->steps1, - move, motor->fwdbwd, &z1, &z2); - - /* no z1/z2 for sheetfed scanners */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - z1 = 0; - z2 = 0; - } - gl646_set_double_reg (regs, REG_Z1MOD, z1); - gl646_set_double_reg (regs, REG_Z2MOD, z2); - regs[reg_0x6b].value = motor->steps2; - regs[reg_0x6c].value = - (regs[reg_0x6c].value & REG6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16) - & 0x07); - - RIE (write_control (dev, xresolution)); - - /* setup analog frontend */ - RIE (gl646_set_fe (dev, AFE_SET, xresolution)); - - /* now we're done with registers setup values used by data transfer */ - /* we setup values needed for the data transfer */ - - /* we must use a round number of words_per_line */ - requested_buffer_size = 8 * words_per_line; - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * scan_settings.pixels * channels * depth) / 8; - - RIE (sanei_genesys_buffer_free (&(dev->read_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->read_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->lines_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->lines_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->shrink_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->shrink_buffer), - requested_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->out_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->out_buffer), - 8 * scan_settings.pixels * channels * bpp)); - - /* scan bytes to read */ - dev->read_bytes_left = words_per_line * linecnt; - - DBG (DBG_info, - "gl646_setup_registers: physical bytes to read = %lu\n", - (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - dev->current_setup.pixels = - ((endx - startx) * sensor->xdpi) / dev->sensor.optical_res; - dev->current_setup.lines = linecnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = sensor->exposure; - dev->current_setup.xres = sensor->xdpi; - dev->current_setup.yres = motor->ydpi; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - /* total_bytes_to_read is the number of byte to send to frontend - * total_bytes_read is the number of bytes sent to frontend - * read_bytes_left is the number of bytes to read from the scanner - */ - dev->total_bytes_read = 0; - if (depth == 1) - dev->total_bytes_to_read = - ((scan_settings.pixels * scan_settings.lines) / 8 + - (((scan_settings.pixels * scan_settings.lines) % 8) ? 1 : 0)) * - channels; - else - dev->total_bytes_to_read = - scan_settings.pixels * scan_settings.lines * channels * bpp; - - DBG (DBG_proc, "gl646_setup_registers: end\n"); - return SANE_STATUS_GOOD; -} - - -/** copy sensor specific settings */ -/* *dev : device infos - *regs : regiters to be set - extended : do extended set up - half_ccd: set up for half ccd resolution - all registers 08-0B, 10-1D, 52-5E are set up. They shouldn't - appear anywhere else but in register init -*/ -static void -gl646_setup_sensor (Genesys_Device * dev, Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r; - int i; - - DBG (DBG_proc, "gl646_setup_sensor: start\n"); - for (i = 0; i < 4; i++) - { - r = sanei_genesys_get_address (regs, 0x08 + i); - r->value = dev->sensor.regs_0x08_0x0b[i]; - } - - for (i = 0; i < 14; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - - for (i = 0; i < 13; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - r->value = dev->sensor.regs_0x52_0x5e[i]; - } - DBG (DBG_proc, "gl646_setup_sensor: end\n"); - -} - -/** Test if the ASIC works - */ -static SANE_Status -gl646_asic_test (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val; - uint8_t *data; - uint8_t *verify_data; - size_t size, verify_size; - unsigned int i; - - DBG (DBG_proc, "gl646_asic_test: start\n"); - - /* set and read exposure time, compare if it's the same */ - status = sanei_genesys_write_register (dev, 0x38, 0xde); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to write register: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_write_register (dev, 0x39, 0xad); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to write register: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_read_register (dev, 0x4e, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val != 0xde) /* value of register 0x38 */ - { - DBG (DBG_error, "gl646_asic_test: register contains invalid value\n"); - return SANE_STATUS_IO_ERROR; - } - - status = sanei_genesys_read_register (dev, 0x4f, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val != 0xad) /* value of register 0x39 */ - { - DBG (DBG_error, "gl646_asic_test: register contains invalid value\n"); - return SANE_STATUS_IO_ERROR; - } - - /* ram test: */ - size = 0x40000; - verify_size = size + 0x80; - /* todo: looks like the read size must be a multiple of 128? - otherwise the read doesn't succeed the second time after the scanner has - been plugged in. Very strange. */ - - data = (uint8_t *) malloc (size); - if (!data) - { - DBG (DBG_error, "gl646_asic_test: could not allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - verify_data = (uint8_t *) malloc (verify_size); - if (!verify_data) - { - free (data); - DBG (DBG_error, "gl646_asic_test: could not allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - for (i = 0; i < (size - 1); i += 2) - { - data[i] = i / 512; - data[i + 1] = (i / 2) % 256; - } - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to set buffer address: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - status = gl646_bulk_write_data (dev, 0x3c, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to bulk write data: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to set buffer address: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - status = - gl646_bulk_read_data (dev, 0x45, (uint8_t *) verify_data, verify_size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_asic_test: failed to bulk read data: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - /* i + 2 is needed as the changed address goes into effect only after one - data word is sent. */ - for (i = 0; i < size; i++) - { - if (verify_data[i + 2] != data[i]) - { - DBG (DBG_error, "gl646_asic_test: data verification error\n"); - free (data); - free (verify_data); - return SANE_STATUS_IO_ERROR; - } - } - - free (data); - free (verify_data); - - DBG (DBG_info, "gl646_asic_test: end\n"); - - return SANE_STATUS_GOOD; -} - -/* returns the max register bulk size */ -static int -gl646_bulk_full_size (void) -{ - return GENESYS_GL646_MAX_REGS; -} - -/** - * Set all registers to default values after init - * @param dev scannerr's device to set - */ -static void -gl646_init_regs (Genesys_Device * dev) -{ - int nr, addr; - - DBG (DBG_proc, "gl646_init_regs\n"); - - nr = 0; - memset (dev->reg, 0, GENESYS_MAX_REGS * sizeof (Genesys_Register_Set)); - - for (addr = 1; addr <= 0x0b; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x10; addr <= 0x29; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x2c; addr <= 0x39; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x3d; addr <= 0x3f; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x52; addr <= 0x5e; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x60; addr <= 0x6d; addr++) - dev->reg[nr++].address = addr; - - dev->reg[reg_0x01].value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */ - dev->reg[reg_0x02].value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ - if (dev->model->motor_type == MOTOR_5345) - dev->reg[reg_0x02].value |= 0x01; /* half-step */ - switch (dev->model->motor_type) - { - case MOTOR_5345: - dev->reg[reg_0x02].value |= 0x01; /* half-step */ - break; - case MOTOR_XP200: - /* for this sheetfed scanner, no AGOHOME, nor backtracking */ - dev->reg[reg_0x02].value = 0x50; - break; - default: - break; - } - dev->reg[reg_0x03].value = 0x1f /*0x17 */ ; /* lamp on */ - dev->reg[reg_0x04].value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */ - switch (dev->model->dac_type) - { - case DAC_AD_XP200: - dev->reg[reg_0x04].value = 0x12; - break; - default: - /* Wolfson frontend */ - dev->reg[reg_0x04].value = 0x13; - break; - } - - dev->reg[reg_0x05].value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */ - switch (dev->sensor.optical_res) - { - case 600: - dev->reg[reg_0x05].value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg[reg_0x05].value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg[reg_0x05].value |= REG05_DPIHW_2400; - break; - default: - dev->reg[reg_0x05].value |= REG05_DPIHW; - break; - } - if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) - dev->reg[reg_0x05].value |= REG05_GMM14BIT; - if (dev->model->dac_type == DAC_AD_XP200) - dev->reg[reg_0x05].value |= 0x01; /* 12 clocks/pixel */ - - if (dev->model->ccd_type == CCD_HP2300) - dev->reg[reg_0x06].value = 0x00; /* PWRBIT off, shading gain=4, normal AFE image capture */ - else - dev->reg[reg_0x06].value = 0x18; /* PWRBIT on, shading gain=8, normal AFE image capture */ - - - gl646_setup_sensor (dev, dev->reg); - - dev->reg[reg_0x1e].value = 0xf0; /* watch-dog time */ - - switch (dev->model->ccd_type) - { - case CCD_HP2300: - dev->reg[reg_0x1e].value = 0xf0; - dev->reg[reg_0x1f].value = 0x10; - dev->reg[reg_0x20].value = 0x20; - break; - case CCD_HP2400: - dev->reg[reg_0x1e].value = 0x80; - dev->reg[reg_0x1f].value = 0x10; - dev->reg[reg_0x20].value = 0x20; - break; - case CCD_HP3670: - dev->reg[reg_0x19].value = 0x2a; - dev->reg[reg_0x1e].value = 0x80; - dev->reg[reg_0x1f].value = 0x10; - dev->reg[reg_0x20].value = 0x20; - break; - case CIS_XP200: - dev->reg[reg_0x1e].value = 0x10; - dev->reg[reg_0x1f].value = 0x01; - dev->reg[reg_0x20].value = 0x50; - break; - default: - dev->reg[reg_0x1f].value = 0x01; - dev->reg[reg_0x20].value = 0x50; - break; - } - - dev->reg[reg_0x21].value = 0x08 /*0x20 */ ; /* table one steps number for forward slope curve of the acc/dec */ - dev->reg[reg_0x22].value = 0x10 /*0x08 */ ; /* steps number of the forward steps for start/stop */ - dev->reg[reg_0x23].value = 0x10 /*0x08 */ ; /* steps number of the backward steps for start/stop */ - dev->reg[reg_0x24].value = 0x08 /*0x20 */ ; /* table one steps number backward slope curve of the acc/dec */ - dev->reg[reg_0x25].value = 0x00; /* scan line numbers (7000) */ - dev->reg[reg_0x26].value = 0x00 /*0x1b */ ; - dev->reg[reg_0x27].value = 0xd4 /*0x58 */ ; - dev->reg[reg_0x28].value = 0x01; /* PWM duty for lamp control */ - dev->reg[reg_0x29].value = 0xff; - - dev->reg[reg_0x2c].value = 0x02; /* set resolution (600 DPI) */ - dev->reg[reg_0x2d].value = 0x58; - dev->reg[reg_0x2e].value = 0x78; /* set black&white threshold high level */ - dev->reg[reg_0x2f].value = 0x7f; /* set black&white threshold low level */ - - dev->reg[reg_0x30].value = 0x00; /* begin pixel position (16) */ - dev->reg[reg_0x31].value = dev->sensor.dummy_pixel /*0x10 */ ; /* TGW + 2*TG_SHLD + x */ - dev->reg[reg_0x32].value = 0x2a /*0x15 */ ; /* end pixel position (5390) */ - dev->reg[reg_0x33].value = 0xf8 /*0x0e */ ; /* TGW + 2*TG_SHLD + y */ - dev->reg[reg_0x34].value = dev->sensor.dummy_pixel; - dev->reg[reg_0x35].value = 0x01 /*0x00 */ ; /* set maximum word size per line, for buffer full control (10800) */ - dev->reg[reg_0x36].value = 0x00 /*0x2a */ ; - dev->reg[reg_0x37].value = 0x00 /*0x30 */ ; - dev->reg[reg_0x38].value = HIBYTE (dev->settings.exposure_time) /*0x2a */ ; /* line period (exposure time = 11000 pixels) */ - dev->reg[reg_0x39].value = LOBYTE (dev->settings.exposure_time) /*0xf8 */ ; - dev->reg[reg_0x3d].value = 0x00; /* set feed steps number of motor move */ - dev->reg[reg_0x3e].value = 0x00; - dev->reg[reg_0x3f].value = 0x01 /*0x00 */ ; - - dev->reg[reg_0x60].value = 0x00; /* Z1MOD, 60h:61h:(6D b5:b3), remainder for start/stop */ - dev->reg[reg_0x61].value = 0x00; /* (21h+22h)/LPeriod */ - dev->reg[reg_0x62].value = 0x00; /* Z2MODE, 62h:63h:(6D b2:b0), remainder for start scan */ - dev->reg[reg_0x63].value = 0x00; /* (3Dh+3Eh+3Fh)/LPeriod for one-table mode,(21h+1Fh)/LPeriod */ - dev->reg[reg_0x64].value = 0x00; /* motor PWM frequency */ - dev->reg[reg_0x65].value = 0x00; /* PWM duty cycle for table one motor phase (63 = max) */ - if (dev->model->motor_type == MOTOR_5345) - dev->reg[reg_0x65].value = 0x02; /* PWM duty cycle for table one motor phase (63 = max) */ - dev->reg[reg_0x66].value = dev->gpo.value[0]; - dev->reg[reg_0x67].value = dev->gpo.value[1]; - dev->reg[reg_0x68].value = dev->gpo.enable[0]; - dev->reg[reg_0x69].value = dev->gpo.enable[1]; - - switch (dev->model->motor_type) - { - case MOTOR_HP2300: - case MOTOR_HP2400: - dev->reg[reg_0x6a].value = 0x7f; /* table two steps number for acc/dec */ - dev->reg[reg_0x6b].value = 0x78; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x7f; - break; - case MOTOR_5345: - dev->reg[reg_0x6a].value = 0x42; /* table two fast moving step type, PWM duty for table two */ - dev->reg[reg_0x6b].value = 0xff; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x41; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - case MOTOR_XP200: - dev->reg[reg_0x6a].value = 0x7f; /* table two fast moving step type, PWM duty for table two */ - dev->reg[reg_0x6b].value = 0x08; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - case MOTOR_HP3670: - dev->reg[reg_0x6a].value = 0x41; /* table two steps number for acc/dec */ - dev->reg[reg_0x6b].value = 0xc8; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x7f; - break; - default: - dev->reg[reg_0x6a].value = 0x40; /* table two fast moving step type, PWM duty for table two */ - dev->reg[reg_0x6b].value = 0xff; /* table two steps number for acc/dec */ - dev->reg[reg_0x6d].value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - } - dev->reg[reg_0x6c].value = 0x00; /* peroid times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE (one period time) */ -} - - -/* Send slope table for motor movement - slope_table in machine byte order -*/ -static SANE_Status -gl646_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - int dpihw; - int start_address; - SANE_Status status; - uint8_t *table; -#ifdef WORDS_BIGENDIAN - int i; -#endif - - DBG (DBG_proc, - "gl646_send_slope_table (table_nr = %d, steps = %d)=%d .. %d\n", - table_nr, steps, slope_table[0], slope_table[steps - 1]); - - dpihw = dev->reg[reg_0x05].value >> 6; - - if (dpihw == 0) /* 600 dpi */ - start_address = 0x08000; - else if (dpihw == 1) /* 1200 dpi */ - start_address = 0x10000; - else if (dpihw == 2) /* 2400 dpi */ - start_address = 0x1f800; - else /* reserved */ - return SANE_STATUS_INVAL; - -#ifdef WORDS_BIGENDIAN - table = (uint8_t *) malloc (steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } -#else - table = (uint8_t *) slope_table; -#endif - - status = - sanei_genesys_set_buffer_address (dev, start_address + table_nr * 0x100); - if (status != SANE_STATUS_GOOD) - { -#ifdef WORDS_BIGENDIAN - free (table); -#endif - DBG (DBG_error, - "gl646_send_slope_table: failed to set buffer address: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl646_bulk_write_data (dev, 0x3c, (uint8_t *) table, steps * 2); - if (status != SANE_STATUS_GOOD) - { -#ifdef WORDS_BIGENDIAN - free (table); -#endif - DBG (DBG_error, - "gl646_send_slope_table: failed to send slope table: %s\n", - sane_strstatus (status)); - return status; - } - -#ifdef WORDS_BIGENDIAN - free (table); -#endif - DBG (DBG_proc, "gl646_send_slope_table: end\n"); - return status; -} - -/* Set values of Analog Device type frontend */ -static SANE_Status -gl646_set_ad_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - uint16_t val; - - DBG (DBG_proc, "gl646_set_ad_fe(): start\n"); - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl646_set_ad_fe(): setting DAC %u\n", - dev->model->dac_type); - - /* sets to default values */ - sanei_genesys_init_fe (dev); - - /* write them to analog frontend */ - val = dev->frontend.reg[0]; - status = sanei_genesys_fe_write_data (dev, 0x00, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_ad_fe: failed to write reg0: %s\n", - sane_strstatus (status)); - return status; - } - val = dev->frontend.reg[1]; - status = sanei_genesys_fe_write_data (dev, 0x01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_ad_fe: failed to write reg1: %s\n", - sane_strstatus (status)); - return status; - } - } - if (set == AFE_SET) - { - for (i = 0; i < 3; i++) - { - val = dev->frontend.gain[i]; - status = sanei_genesys_fe_write_data (dev, 0x02 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_ad_fe: failed to write gain %d: %s\n", i, - sane_strstatus (status)); - return status; - } - } - for (i = 0; i < 3; i++) - { - val = dev->frontend.offset[i]; - status = sanei_genesys_fe_write_data (dev, 0x05 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_ad_fe: failed to write offset %d: %s\n", i, - sane_strstatus (status)); - return status; - } - } - } - /* - if (set == AFE_POWER_SAVE) - { - status = - sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0] | 0x04); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_ad_fe: failed to write reg0: %s\n", - sane_strstatus (status)); - return status; - } - } */ - DBG (DBG_proc, "gl646_set_ad_fe(): end\n"); - - return status; -} - -/** set up analog frontend - * set up analog frontend - * @param dev device to set up - * @param set action from AFE_SET, AFE_INIT and AFE_POWERSAVE - * @param dpi resolution of the scan since it affects settings - * @return SANE_STATUS_GOOD if evrithing OK - */ -static SANE_Status -gl646_wm_hp3670 (Genesys_Device * dev, uint8_t set, int dpi) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - - DBGSTART; - switch (set) - { - case AFE_INIT: - status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: reset failed: %s\n", - sane_strstatus (status)); - return status; - } - usleep (200000UL); - RIE (sanei_genesys_write_register (dev, 0x50, 0x00)); - sanei_genesys_init_fe (dev); - status = sanei_genesys_fe_write_data (dev, 0x01, dev->frontend.reg[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg1 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x02, dev->frontend.reg[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg2 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = gl646_gpio_output_enable (dev->dn, 0x07); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: failed to enable GPIO: %s\n", - sane_strstatus (status)); - return status; - } - break; - case AFE_POWER_SAVE: - status = sanei_genesys_fe_write_data (dev, 0x01, 0x06); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg1 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x06, 0x0f); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg6 failed: %s\n", - sane_strstatus (status)); - return status; - } - return status; - break; - default: /* AFE_SET */ - /* mode setup */ - i = dev->frontend.reg[3]; - if (dpi > dev->sensor.optical_res / 2) - { - /* fe_reg_0x03 must be 0x12 for 1200 dpi in DAC_WOLFSON_HP3670. - * DAC_WOLFSON_HP2400 in 1200 dpi mode works well with - * fe_reg_0x03 set to 0x32 or 0x12 but not to 0x02 */ - i = 0x12; - } - status = sanei_genesys_fe_write_data (dev, 0x03, i); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing reg3 failed: %s\n", - sane_strstatus (status)); - return status; - } - /* offset and sign (or msb/lsb ?) */ - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x20 + i, - dev->frontend.offset[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_wm_hp3670: writing offset%d failed: %s\n", i, - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x24 + i, dev->frontend.sign[i]); /* MSB/LSB ? */ - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing sign%d failed: %s\n", - i, sane_strstatus (status)); - return status; - } - } - - /* gain */ - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x28 + i, - dev->frontend.gain[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_wm_hp3670: writing gain%d failed: %s\n", - i, sane_strstatus (status)); - return status; - } - } - } - - DBGCOMPLETED; - return status; -} - -/** Set values of analog frontend - * @param dev device to set - * @param set action to execute - * @param dpi dpi to setup the AFE - * @return error or SANE_STATUS_GOOD */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl646_set_fe (Genesys_Device * dev, uint8_t set, int dpi) -{ - SANE_Status status; - int i; - uint8_t val; - - DBG (DBG_proc, "gl646_set_fe (%s,%d)\n", - set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?", dpi); - - /* Analog Device type frontend */ - if ((dev->reg[reg_0x04].value & REG04_FESET) == 0x02) - return gl646_set_ad_fe (dev, set); - - /* Wolfson type frontend */ - if ((dev->reg[reg_0x04].value & REG04_FESET) != 0x03) - { - DBG (DBG_proc, "gl646_set_fe(): unsupported frontend type %d\n", - dev->reg[reg_0x04].value & REG04_FESET); - return SANE_STATUS_UNSUPPORTED; - } - - /* per frontend function to keep code clean */ - switch (dev->model->dac_type) - { - case DAC_WOLFSON_HP3670: - case DAC_WOLFSON_HP2400: - return gl646_wm_hp3670 (dev, set, dpi); - break; - default: - DBG (DBG_proc, "gl646_set_fe(): using old method\n"); - break; - } - - /* initialize analog frontend */ - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl646_set_fe(): setting DAC %u\n", - dev->model->dac_type); - sanei_genesys_init_fe (dev); - - /* reset only done on init */ - status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: init fe failed: %s\n", - sane_strstatus (status)); - return status; - } - - /* enable GPIO for some models */ - if (dev->model->ccd_type == CCD_HP2300) - { - val = 0x07; - status = gl646_gpio_output_enable (dev->dn, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_fe: failed to enable GPIO: %s\n", - sane_strstatus (status)); - return status; - } - } - return status; - } - - /* set fontend to power saving mode */ - if (set == AFE_POWER_SAVE) - { - status = sanei_genesys_fe_write_data (dev, 0x01, 0x02); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing data failed: %s\n", - sane_strstatus (status)); - } - return status; - } - - /* here starts AFE_SET */ - /* TODO : base this test on cfg reg3 or a CCD family flag to be created */ - /* if (dev->model->ccd_type != CCD_HP2300 - && dev->model->ccd_type != CCD_HP3670 - && dev->model->ccd_type != CCD_HP2400) */ - { - status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing reg0 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x02, dev->frontend.reg[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing reg2 failed: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* start with reg3 */ - status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.reg[3]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing reg3 failed: %s\n", - sane_strstatus (status)); - return status; - } - - switch (dev->model->ccd_type) - { - default: - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x24 + i, - dev->frontend.sign[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing sign[%d] failed: %s\n", - i, sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x28 + i, - dev->frontend.gain[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing gain[%d] failed: %s\n", - i, sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x20 + i, - dev->frontend.offset[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_fe: writing offset[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - } - break; - /* just can't have it to work .... - case CCD_HP2300: - case CCD_HP2400: - case CCD_HP3670: - - status = - sanei_genesys_fe_write_data (dev, 0x23, dev->frontend.offset[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_set_fe: writing offset[1] failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x28, dev->frontend.gain[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing gain[1] failed: %s\n", - sane_strstatus (status)); - return status; - } - break; */ - } - - /* end with reg1 */ - status = sanei_genesys_fe_write_data (dev, 0x01, dev->frontend.reg[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_set_fe: writing reg1 failed: %s\n", - sane_strstatus (status)); - return status; - } - - - DBG (DBG_proc, "gl646_set_fe: end\n"); - - return SANE_STATUS_GOOD; -} - -/** Set values of analog frontend - * this this the public interface, the gl646 as to use one more - * parameter to work effectively, hence the redirection - * @param dev device to set - * @param set action to execute - * @return error or SANE_STATUS_GOOD */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl646_public_set_fe (Genesys_Device * dev, uint8_t set) -{ - return gl646_set_fe (dev, set, dev->settings.yres); -} - -static void -gl646_set_motor_power (Genesys_Register_Set * regs, SANE_Bool set) -{ - if (set) - { - sanei_genesys_set_reg_from_set (regs, 0x02, - sanei_genesys_read_reg_from_set (regs, - 0x02) | - REG02_MTRPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, 0x02, - sanei_genesys_read_reg_from_set (regs, - 0x02) & - ~REG02_MTRPWR); - } -} - -static void -gl646_set_lamp_power (Genesys_Device * dev, - Genesys_Register_Set * regs, SANE_Bool set) -{ - if (dev) - { - if (set) - { - sanei_genesys_set_reg_from_set (regs, 0x03, - sanei_genesys_read_reg_from_set - (regs, 0x03) | REG03_LAMPPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, 0x03, - sanei_genesys_read_reg_from_set - (regs, 0x03) & ~REG03_LAMPPWR); - } - } -} - -/** - * enters or leaves power saving mode - * limited to AFE for now. - * @param dev scanner's device - * @param enable SANE_TRUE to enable power saving, SANE_FALSE to leave it - * @return allways SANE_STATUS_GOOD - */ -GENESYS_STATIC -SANE_Status -gl646_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - - DBGSTART; - DBG (DBG_info, "gl646_save_power: enable = %d\n", enable); - - if (enable) - { - /* gl646_set_fe (dev, AFE_POWER_SAVE); */ - } - else - { - gl646_set_fe (dev, AFE_INIT, 0); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl646_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg[6]; - int rate, exposure_time, tgtime, time; - - DBG (DBG_proc, "gl646_set_powersaving (delay = %d)\n", delay); - - local_reg[0].address = 0x01; - local_reg[0].value = sanei_genesys_read_reg_from_set (dev->reg, 0x01); /* disable fastmode */ - - local_reg[1].address = 0x03; - local_reg[1].value = sanei_genesys_read_reg_from_set (dev->reg, 0x03); /* Lamp power control */ - - local_reg[2].address = 0x05; - local_reg[2].value = sanei_genesys_read_reg_from_set (dev->reg, 0x05) & ~REG05_BASESEL; /* 24 clocks/pixel */ - - local_reg[3].address = 0x38; /* line period low */ - local_reg[3].value = 0x00; - - local_reg[4].address = 0x39; /* line period high */ - local_reg[4].value = 0x00; - - local_reg[5].address = 0x6c; /* period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE */ - local_reg[5].value = 0x00; - - if (!delay) - local_reg[1].value = local_reg[1].value & 0xf0; /* disable lampdog and set lamptime = 0 */ - else if (delay < 20) - local_reg[1].value = (local_reg[1].value & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ - else - local_reg[1].value = (local_reg[1].value & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ - - time = delay * 1000 * 60; /* -> msec */ - exposure_time = - (uint32_t) (time * 32000.0 / - (24.0 * 64.0 * (local_reg[1].value & REG03_LAMPTIM) * - 1024.0) + 0.5); - /* 32000 = system clock, 24 = clocks per pixel */ - rate = (exposure_time + 65536) / 65536; - if (rate > 4) - { - rate = 8; - tgtime = 3; - } - else if (rate > 2) - { - rate = 4; - tgtime = 2; - } - else if (rate > 1) - { - rate = 2; - tgtime = 1; - } - else - { - rate = 1; - tgtime = 0; - } - - local_reg[5].value |= tgtime << 6; - exposure_time /= rate; - - if (exposure_time > 65535) - exposure_time = 65535; - - local_reg[3].value = exposure_time / 256; /* highbyte */ - local_reg[4].value = exposure_time & 255; /* lowbyte */ - - status = gl646_bulk_write_register (dev, local_reg, - sizeof (local_reg) / - sizeof (local_reg[0])); - if (status != SANE_STATUS_GOOD) - DBG (DBG_error, - "gl646_set_powersaving: Failed to bulk write registers: %s\n", - sane_strstatus (status)); - - DBG (DBG_proc, "gl646_set_powersaving: end\n"); - return status; -} - - -/** - * loads document into scanner - * currently only used by XP200 - * bit2 (0x04) of gpio is paper event (document in/out) on XP200 - * HOMESNR is set if no document in front of sensor, the sequence of events is - * paper event -> document is in the sheet feeder - * HOMESNR becomes 0 -> document reach sensor - * HOMESNR becomes 1 ->document left sensor - * paper event -> document is out - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl646_load_document (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set regs[11]; - unsigned int used, vfinal, count; - uint16_t slope_table[255]; - uint8_t val; - - DBG (DBG_proc, "gl646_load_document: start\n"); - - /* no need to load document is flatbed scanner */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - DBG (DBG_proc, "gl646_load_document: nothing to load\n"); - DBG (DBG_proc, "gl646_load_document: end\n"); - return SANE_STATUS_GOOD; - } - - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - - /* HOMSNR is set if a document is inserted */ - if ((val & REG41_HOMESNR)) - { - /* if no document, waits for a paper event to start loading */ - /* with a 60 seconde minutes timeout */ - count = 0; - do - { - status = gl646_gpio_read (dev->dn, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to read paper sensor %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_info, "gl646_load_document: GPIO=0x%02x\n", val); - if ((val & 0x04) != 0x04) - { - DBG (DBG_warn, "gl646_load_document: no paper detected\n"); - } - usleep (200000UL); /* sleep 200 ms */ - count++; - } - while (((val & 0x04) != 0x04) && (count < 300)); /* 1 min time out */ - if (count == 300) - { - DBG (DBG_error, - "gl646_load_document: timeout waiting for document\n"); - return SANE_STATUS_NO_DOCS; - } - } - - /* set up to fast move before scan then move until document is detected */ - regs[0].address = 0x01; - regs[0].value = 0x90; - - /* AGOME, 2 slopes motor moving */ - regs[1].address = 0x02; - regs[1].value = 0x79; - - /* motor feeding steps to 0 */ - regs[2].address = 0x3d; - regs[2].value = 0; - regs[3].address = 0x3e; - regs[3].value = 0; - regs[4].address = 0x3f; - regs[4].value = 0; - - /* 50 fast moving steps */ - regs[5].address = 0x6b; - regs[5].value = 50; - - /* set GPO */ - regs[6].address = 0x66; - regs[6].value = 0x30; - - /* stesp NO */ - regs[7].address = 0x21; - regs[7].value = 4; - regs[8].address = 0x22; - regs[8].value = 1; - regs[9].address = 0x23; - regs[9].value = 1; - regs[10].address = 0x24; - regs[10].value = 4; - - /* generate slope table 2 */ - sanei_genesys_generate_slope_table (slope_table, - 50, - 51, - 2400, - 6000, 2400, 50, 0.25, &used, &vfinal); -/* document loading: - * send regs - * start motor - * wait e1 status to become e0 - */ - status = gl646_send_slope_table (dev, 1, slope_table, 50); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to send slope table 1: %s\n", - sane_strstatus (status)); - return status; - } - status = - gl646_bulk_write_register (dev, regs, sizeof (regs) / sizeof (regs[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl646_start_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to start motor: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - count = 0; - do - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - usleep (200000UL); /* sleep 200 ms */ - count++; - } - while ((val & REG41_MOTMFLG) && (count < 300)); - if (count == 300) - { - DBG (DBG_error, "gl646_load_document: can't load document\n"); - return SANE_STATUS_JAMMED; - } - - /* when loading OK, document is here */ - dev->document = SANE_TRUE; - - /* set up to idle */ - regs[1].value = 0x71; - regs[4].value = 1; - regs[5].value = 8; - status = - gl646_bulk_write_register (dev, regs, sizeof (regs) / sizeof (regs[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_load_document: failed to bulk write idle registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "gl646_load_document: end\n"); - - return status; -} - -/** - * detects end of document and adjust current scan - * to take it into account - * used by sheetfed scanners - */ -static SANE_Status -gl646_detect_document_end (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val, gpio; - unsigned int bytes_left, lines; - - DBG (DBG_proc, "gl646_detect_document_end: start\n"); - - /* test for document presence */ - RIE (sanei_genesys_get_status (dev, &val)); - if (DBG_LEVEL > DBG_info) - { - print_status (val); - } - status = gl646_gpio_read (dev->dn, &gpio); - DBG (DBG_info, "gl646_detect_document_end: GPIO=0x%02x\n", gpio); - - /* detect document event. There one event when the document go in, - * then another when it leaves */ - if ((dev->document == SANE_TRUE) && (gpio & 0x04) - && (dev->total_bytes_read > 0)) - { - DBG (DBG_info, "gl646_detect_document_end: no more document\n"); - dev->document = SANE_FALSE; - - /* adjust number of bytes to read: - * total_bytes_to_read is the number of byte to send to frontend - * total_bytes_read is the number of bytes sent to frontend - * read_bytes_left is the number of bytes to read from the scanner - */ - DBG (DBG_io, "gl646_detect_document_end: total_bytes_to_read=%lu\n", - (u_long) dev->total_bytes_to_read); - DBG (DBG_io, "gl646_detect_document_end: total_bytes_read =%lu\n", - (u_long) dev->total_bytes_read); - DBG (DBG_io, "gl646_detect_document_end: read_bytes_left =%lu\n", - (u_long) dev->read_bytes_left); - - /* amount of data available from scanner is what to scan */ - status = sanei_genesys_read_valid_words (dev, &bytes_left); - - /* we add the number of lines needed to read the last part of the document in */ - lines = - (SANE_UNFIX (dev->model->y_offset) * dev->current_setup.yres) / - MM_PER_INCH; - DBG (DBG_io, "gl646_detect_document_end: adding %d line to flush\n", - lines); - bytes_left += lines * dev->wpl; - if (dev->current_setup.depth > 8) - { - bytes_left = 2 * bytes_left; - } - if (dev->current_setup.channels > 1) - { - bytes_left = 3 * bytes_left; - } - if (bytes_left < dev->read_bytes_left) - { - dev->total_bytes_to_read = dev->total_bytes_read + bytes_left; - dev->read_bytes_left = bytes_left; - } - DBG (DBG_io, "gl646_detect_document_end: total_bytes_to_read=%lu\n", - (u_long) dev->total_bytes_to_read); - DBG (DBG_io, "gl646_detect_document_end: total_bytes_read =%lu\n", - (u_long) dev->total_bytes_read); - DBG (DBG_io, "gl646_detect_document_end: read_bytes_left =%lu\n", - (u_long) dev->read_bytes_left); - } - DBG (DBG_proc, "gl646_detect_document_end: end\n"); - - return status; -} - -/** - * eject document from the feeder - * currently only used by XP200 - * TODO we currently rely on AGOHOME not being set for sheetfed scanners, - * maybe check this flag in eject to let the document being eject automaticaly - */ -static SANE_Status -gl646_eject_document (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set regs[11]; - unsigned int used, vfinal, count; - uint16_t slope_table[255]; - uint8_t gpio, state; - - DBG (DBG_proc, "gl646_eject_document: start\n"); - - /* at the end there will be noe more document */ - dev->document = SANE_FALSE; - - /* first check for document event */ - status = gl646_gpio_read (dev->dn, &gpio); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read paper sensor %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_info, "gl646_eject_document: GPIO=0x%02x\n", gpio); - - /* test status : paper event + HOMESNR -> no more doc ? */ - status = sanei_genesys_get_status (dev, &state); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_info, "gl646_eject_document: state=0x%02x\n", state); - if (DBG_LEVEL > DBG_info) - { - print_status (state); - } - - /* HOMSNR=0 if no document inserted */ - if ((state & REG41_HOMESNR) != 0) - { - dev->document = SANE_FALSE; - DBG (DBG_info, "gl646_eject_document: no more document to eject\n"); - DBG (DBG_proc, "gl646_eject_document: end\n"); - return status; - } - - /* there is a document inserted, eject it */ - status = sanei_genesys_write_register (dev, 0x01, 0xb0); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to write register: %s\n", - sane_strstatus (status)); - return status; - } - - /* wait for motor to stop */ - do - { - usleep (200000UL); - status = sanei_genesys_get_status (dev, &state); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - } - while (state & REG41_MOTMFLG); - - /* set up to fast move before scan then move until document is detected */ - regs[0].address = 0x01; - regs[0].value = 0xb0; - - /* AGOME, 2 slopes motor moving , eject 'backward' */ - regs[1].address = 0x02; - regs[1].value = 0x5d; - - /* motor feeding steps to 119880 */ - regs[2].address = 0x3d; - regs[2].value = 1; - regs[3].address = 0x3e; - regs[3].value = 0xd4; - regs[4].address = 0x3f; - regs[4].value = 0x48; - - /* 60 fast moving steps */ - regs[5].address = 0x6b; - regs[5].value = 60; - - /* set GPO */ - regs[6].address = 0x66; - regs[6].value = 0x30; - - /* stesp NO */ - regs[7].address = 0x21; - regs[7].value = 4; - regs[8].address = 0x22; - regs[8].value = 1; - regs[9].address = 0x23; - regs[9].value = 1; - regs[10].address = 0x24; - regs[10].value = 4; - - /* generate slope table 2 */ - sanei_genesys_generate_slope_table (slope_table, - 60, - 61, - 1600, - 10000, 1600, 60, 0.25, &used, &vfinal); -/* document eject: - * send regs - * start motor - * wait c1 status to become c8 : HOMESNR and ~MOTFLAG - */ - status = gl646_send_slope_table (dev, 1, slope_table, 60); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to send slope table 1: %s\n", - sane_strstatus (status)); - return status; - } - status = - gl646_bulk_write_register (dev, regs, sizeof (regs) / sizeof (regs[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl646_start_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to start motor: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - /* loop until paper sensor tells paper is out, and till motor is running */ - /* use a 30 timeout */ - count = 0; - do - { - status = sanei_genesys_get_status (dev, &state); - print_status (state); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read status: %s\n", - sane_strstatus (status)); - return status; - } - usleep (200000UL); /* sleep 200 ms */ - count++; - } - while (((state & REG41_HOMESNR) == 0) && (count < 150)); - - /* read GPIO on exit */ - status = gl646_gpio_read (dev->dn, &gpio); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_eject_document: failed to read paper sensor %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_info, "gl646_eject_document: GPIO=0x%02x\n", gpio); - - DBG (DBG_proc, "gl646_eject_document: end\n"); - return status; -} - -/* Send the low-level scan command */ -static SANE_Status -gl646_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - SANE_Status status; - Genesys_Register_Set local_reg[3]; - - DBG (DBG_proc, "gl646_begin_scan\n"); - - local_reg[0].address = 0x03; - local_reg[0].value = sanei_genesys_read_reg_from_set (reg, 0x03); - - local_reg[1].address = 0x01; - local_reg[1].value = sanei_genesys_read_reg_from_set (reg, 0x01) | REG01_SCAN; /* set scan bit */ - - local_reg[2].address = 0x0f; - if (start_motor) - local_reg[2].value = 0x01; - else - local_reg[2].value = 0x00; /* do not start motor yet */ - - status = gl646_bulk_write_register (dev, local_reg, - sizeof (local_reg) / - sizeof (local_reg[0])); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_begin_scan: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "gl646_begin_scan: end\n"); - - return status; -} - - -/* Send the stop scan command */ -static SANE_Status -end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop, SANE_Bool eject) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i = 0; - uint8_t val, scanfsh = 0; - - DBG (DBG_proc, "end_scan (check_stop = %d, eject = %d)\n", check_stop, - eject); - - /* we need to compute scanfsh before cancelling scan */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "end_scan: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io2) - { - print_status (val); - } - } - - /* ends scan */ - val = sanei_genesys_read_reg_from_set (reg, 0x01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set (reg, 0x01, val); - status = sanei_genesys_write_register (dev, 0x01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "end_scan: failed to write register 01: %s\n", - sane_strstatus (status)); - return status; - } - - /* for sheetfed scanners, we may have to eject document */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - if (eject == SANE_TRUE && dev->document == SANE_TRUE) - { - status = gl646_eject_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "end_scan: failed to eject document\n"); - return status; - } - } - if (check_stop) - { - for (i = 0; i < 30; i++) /* do not wait longer than wait 3 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "end_scan: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io2) - { - print_status (val); - } - - if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh) - { - DBG (DBG_proc, "end_scan: scanfeed finished\n"); - break; /* leave for loop */ - } - - usleep (10000UL); /* sleep 100 ms */ - } - } - } - else /* flat bed scanners */ - { - if (check_stop) - { - for (i = 0; i < 300; i++) /* do not wait longer than wait 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "end_scan: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io) - { - print_status (val); - } - - if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh) - { - DBG (DBG_proc, "end_scan: scanfeed finished\n"); - break; /* leave while loop */ - } - - if ((!(val & REG41_MOTMFLG)) && (val & REG41_HOMESNR)) - { - DBG (DBG_proc, "end_scan: head at home\n"); - break; /* leave while loop */ - } - - usleep (10000UL); /* sleep 100 ms */ - } - } - } - - DBG (DBG_proc, "end_scan: end (i=%u)\n", i); - - return status; -} - -/* Send the stop scan command */ -static SANE_Status -gl646_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - return end_scan (dev, reg, check_stop, SANE_FALSE); -} - -/** - * parks head - * @param dev scanner's device - * @param wait_until_home true if the function waits until head parked - */ -GENESYS_STATIC -SANE_Status -gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - SANE_Status status; - Genesys_Settings settings; - uint8_t val; - int i; - int loop = 0; - - DBG (DBG_proc, "gl646_slow_back_home: start , wait_until_home = %d\n", - wait_until_home); - - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL > DBG_io) - { - print_status (val); - } - - dev->scanhead_position_in_steps = 0; - - if (val & REG41_HOMESNR) /* is sensor at home? */ - { - DBG (DBG_info, "gl646_slow_back_home: end since already at home\n"); - return SANE_STATUS_GOOD; - } - - /* stop motor if needed */ - if (val & REG41_MOTMFLG) - { - status = gl646_stop_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_slow_back_home: failed to stop motor: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - usleep (200000UL); - } - - /* when scanhead is moving then wait until scanhead stops or timeout */ - DBG (DBG_info, "gl646_slow_back_home: ensuring that motor is off\n"); - val = REG41_MOTMFLG; - for (i = 400; i > 0 && (val & REG41_MOTMFLG); i--) /* do not wait longer than 40 seconds, count down to get i = 0 when busy */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_slow_back_home: Failed to read home sensor & motor status: %s\n", - sane_strstatus (status)); - return status; - } - if (((val & (REG41_MOTMFLG | REG41_HOMESNR)) == REG41_HOMESNR)) /* at home and motor is off */ - { - DBG (DBG_info, - "gl646_slow_back_home: already at home and not moving\n"); - return SANE_STATUS_GOOD; - } - usleep (100 * 1000); /* sleep 100 ms (todo: fixed to really sleep 100 ms) */ - } - - if (!i) /* the loop counted down to 0, scanner still is busy */ - { - DBG (DBG_error, - "gl646_slow_back_home: motor is still on: device busy\n"); - return SANE_STATUS_DEVICE_BUSY; - } - - /* setup for a backward scan of 65535 steps, with no actual data reading */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = get_lowest_resolution (dev->model->ccd_type, SANE_FALSE); - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = 600; - settings.lines = 1; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - status = setup_for_scan (dev, dev->reg, settings, SANE_TRUE, SANE_TRUE, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to setup for scan: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* backward , no actual data scanned TODO more setup flags to avoid this register manipulations ? */ - dev->reg[reg_0x02].value |= REG02_MTRREV; - dev->reg[reg_0x01].value &= ~REG01_SCAN; - gl646_set_triple_reg (dev->reg, REG_FEEDL, 65535); - - /* sets frontend */ - status = gl646_set_fe (dev, AFE_SET, settings.xres); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to set frontend: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* write scan registers */ - status = gl646_bulk_write_register (dev, dev->reg, - sizeof (dev->reg) / - sizeof (dev->reg[0])); - if (status != SANE_STATUS_GOOD) - DBG (DBG_error, - "gl646_slow_back_home: failed to bulk write registers: %s\n", - sane_strstatus (status)); - - /* registers are restored to an iddl state, give up if no head to park */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - DBG (DBG_proc, "gl646_slow_back_home: end \n"); - return SANE_STATUS_GOOD; - } - - /* starts scan */ - status = gl646_begin_scan (dev, dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_slow_back_home: failed to begin scan: \n"); - return status; - } - - /* loop until head parked */ - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_slow_back_home: Failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - - if (val & 0x08) /* home sensor */ - { - DBG (DBG_info, "gl646_slow_back_home: reached home position\n"); - DBG (DBG_proc, "gl646_slow_back_home: end\n"); - usleep (500000); /* sleep 500 ms before returning */ - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl646_stop_motor (dev); - end_scan (dev, dev->reg, SANE_TRUE, SANE_FALSE); - DBG (DBG_error, - "gl646_slow_back_home: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; - } - - - DBG (DBG_info, "gl646_slow_back_home: scanhead is still moving\n"); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * Automatically set top-left edge of the scan area by scanning an - * area at 300 dpi from very top of scanner - * @param dev device stucture describing the scanner - * @return SANE_STATUS_GOOD in cas of success, else failure code - */ -static SANE_Status -gl646_search_start_position (Genesys_Device * dev) -{ - SANE_Status status; - unsigned char *data = NULL; - Genesys_Settings settings; - unsigned int resolution, x, y; - - DBG (DBG_proc, "gl646_search_start_position: start\n"); - - /* we scan at 300 dpi */ - resolution = get_closest_resolution (dev->model->ccd_type, 300, SANE_FALSE); - - /* fill settings for a gray level scan */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_GRAY; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = 600; - settings.lines = dev->model->search_lines; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan the desired area */ - status = - simple_scan (dev, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, &data); - - /* process data if scan is OK */ - if (status == SANE_STATUS_GOOD) - { - /* handle stagger case : reorder gray data and thus loose some lines */ - if (dev->current_setup.stagger > 0) - { - DBG (DBG_proc, "gl646_search_start_position: 'un-staggering'\n"); - for (y = 0; y < settings.lines - dev->current_setup.stagger; y++) - { - /* one point out of 2 is 'unaligned' */ - for (x = 0; x < settings.pixels; x += 2) - { - data[y * settings.pixels + x] = - data[(y + dev->current_setup.stagger) * settings.pixels + - x]; - } - } - /* correct line number */ - settings.lines -= dev->current_setup.stagger; - } - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file ("search_position.pnm", - data, - settings.depth, - 1, settings.pixels, settings.lines); - } - } - else - { - DBG (DBG_error, "gl646_search_start_position: simple_scan failed\n"); - free (data); - DBGCOMPLETED; - return status; - } - - /* now search reference points on the data */ - status = - sanei_genesys_search_reference_point (dev, data, - dev->sensor.CCD_start_xoffset, - resolution, settings.pixels, - settings.lines); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_search_start_position: failed to set search reference point: %s\n", - sane_strstatus (status)); - } - - free (data); - DBGCOMPLETED; - return status; -} - -/** - * internally overriden during effective calibration - * sets up register for coarse gain calibration - */ -static SANE_Status -gl646_init_regs_for_coarse_calibration (Genesys_Device * dev) -{ - DBG (DBG_proc, "gl646_init_regs_for_coarse_calibration\n"); - DBG (DBG_proc, "gl646_init_register_for_coarse_calibration: end\n"); - - /* to make compilers happy ... */ - if (!dev) - { - return SANE_STATUS_INVAL; - } - - return SANE_STATUS_GOOD; -} - - -/** - * init registers for shading calibration - * we assume that scanner's head is on an area suiting shading calibration. - * We scan a full scan width area by the shading line number for the device - * at either at full sensor's resolution or half depending upon half_ccd - * @param dev scanner's device - * @return SANE_STATUS_GOOD if success, else error code - */ -static SANE_Status -gl646_init_regs_for_shading (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - /* 1: no half_ccd, 2: use half number of pixels */ - int half_ccd = 1; - int cksel = 1; - - DBG (DBG_proc, "gl646_init_register_for_shading: start\n"); - - /* when shading all (full width) line, we must adapt to half_ccd case */ - if (dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE) - { - /* walk the master mode list to find if half_ccd */ - if (is_half_ccd (dev->model->ccd_type, dev->settings.xres, SANE_TRUE) == - SANE_TRUE) - { - half_ccd = 2; - } - } - - /* fill settings for scan : always a color scan */ - settings.scan_method = dev->settings.scan_method; - settings.scan_mode = dev->settings.scan_mode; - if (dev->model->is_cis == SANE_FALSE) - { - settings.scan_mode = SCAN_MODE_COLOR; - } - settings.xres = dev->sensor.optical_res / half_ccd; - cksel = get_cksel (dev->model->ccd_type, dev->settings.xres, SANE_TRUE); - settings.xres = settings.xres / cksel; - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * settings.xres) / dev->sensor.optical_res; - dev->calib_lines = dev->model->shading_lines; - settings.lines = dev->calib_lines * (3 - half_ccd); - settings.depth = 16; - settings.color_filter = dev->settings.color_filter; - - settings.disable_interpolation = dev->settings.disable_interpolation; - settings.threshold = dev->settings.threshold; - settings.exposure_time = dev->settings.exposure_time; - settings.dynamic_lineart = SANE_FALSE; - - /* keep account of the movement for final scan move */ - dev->scanhead_position_in_steps += settings.lines; - - /* we don't want top offset, but we need right margin to be the same - * than the one for the final scan */ - status = setup_for_scan (dev, dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE); - - /* used when sending shading calibration data */ - dev->calib_pixels = settings.pixels; - dev->calib_channels = dev->current_setup.channels; - if (dev->model->is_cis == SANE_FALSE) - { - dev->calib_channels = 3; - } - - /* no shading */ - dev->reg[reg_0x01].value &= ~REG01_DVDSET; - dev->reg[reg_0x02].value |= REG02_ACDCDIS; /* ease backtracking */ - dev->reg[reg_0x02].value &= ~(REG02_FASTFED | REG02_AGOHOME); - dev->reg[reg_0x05].value &= ~REG05_GMMENB; - gl646_set_motor_power (dev->reg, SANE_FALSE); - - /* TODO another flag to setup regs ? */ - /* enforce needed LINCNT, getting rid of extra lines for color reordering */ - if (dev->model->is_cis == SANE_FALSE) - { - gl646_set_triple_reg (dev->reg, REG_LINCNT, dev->calib_lines); - } - else - { - gl646_set_triple_reg (dev->reg, REG_LINCNT, dev->calib_lines * 3); - } - - /* copy reg to calib_reg */ - memcpy (dev->calib_reg, dev->reg, - GENESYS_GL646_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* this is an hack to make calibration cache working .... */ - /* if we don't do this, cache will be identified at the shading calibration - * dpi which is different from calibration one */ - dev->current_setup.xres = dev->settings.xres; - DBG (DBG_info, - "gl646_init_register_for_shading:\n\tdev->settings.xres=%d\n\tdev->settings.yres=%d\n", - dev->settings.xres, dev->settings.yres); - - DBG (DBG_proc, "gl646_init_register_for_shading: end\n"); - return status; -} - - -/** - * set up registers for the actual scan. The scan's parameters are given - * through the device settings. It allocates the scan buffers. - */ -static SANE_Status -gl646_init_regs_for_scan (Genesys_Device * dev) -{ - SANE_Status status; - - DBGSTART; - - /* park head after calibration if needed */ - if (dev->scanhead_position_in_steps > 0 - && dev->settings.scan_method == SCAN_METHOD_FLATBED) - { - RIE(gl646_slow_back_home (dev, SANE_TRUE)); - dev->scanhead_position_in_steps = 0; - } - - RIE(setup_for_scan (dev, dev->reg, dev->settings, SANE_FALSE, SANE_TRUE, SANE_TRUE)); - - /* gamma is only enabled at final scan time */ - if (dev->settings.depth < 16) - dev->reg[reg_0x05].value |= REG05_GMMENB; - - DBGCOMPLETED; - return status; -} - -/** - * set up registers for the actual scan. The scan's parameters are given - * through the device settings. It allocates the scan buffers. - * @param dev scanner's device - * @param regs registers to set up - * @param settings settings of scan - * @param split SANE_TRUE if move to scan area is split from scan, SANE_FALSE is - * scan first moves to area - * @param xcorrection take x geometry correction into account (fixed and detected offsets) - * @param ycorrection take y geometry correction into account - */ -GENESYS_STATIC SANE_Status -setup_for_scan (Genesys_Device * dev, - Genesys_Register_Set *regs, - Genesys_Settings settings, - SANE_Bool split, - SANE_Bool xcorrection, - SANE_Bool ycorrection) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool color; - SANE_Int depth; - int channels; - uint16_t startx = 0, endx, pixels; - int move = 0; - - DBGSTART; - DBG (DBG_info, - "%s settings:\nResolution: %ux%uDPI\n" - "Lines : %u\nPixels : %u\nStartpos : %.3f/%.3f\nScan mode : %d\nScan method: %s\n\n", - __func__, - settings.xres, settings.yres, settings.lines, settings.pixels, - settings.tl_x, settings.tl_y, settings.scan_mode, - settings.scan_method == SCAN_METHOD_FLATBED ? "flatbed" : "XPA"); - - if (settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - { - channels = 3; - color = SANE_TRUE; - } - else - { - channels = 1; - color = SANE_FALSE; - } - - depth=settings.depth; - if (settings.scan_mode == SCAN_MODE_LINEART) - { - if (settings.dynamic_lineart == SANE_TRUE) - { - depth = 8; - } - else - { - /* XXX STEF XXX : why does the common layer never send depth=1 ? */ - depth = 1; - } - } - - /* compute distance to move */ - move = 0; - /* XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */ - if (split == SANE_FALSE) - { - if (dev->model->is_sheetfed == SANE_FALSE) - { - if (ycorrection == SANE_TRUE) - { - move = - (SANE_UNFIX (dev->model->y_offset) * - dev->motor.optical_ydpi) / MM_PER_INCH; - } - - /* add tl_y to base movement */ - move += (settings.tl_y * dev->motor.optical_ydpi) / MM_PER_INCH; - - } - else - { - move += (settings.tl_y * dev->motor.optical_ydpi) / MM_PER_INCH; - } - - DBG (DBG_info, "%s: move=%d steps\n", __func__, move); - - /* security check */ - if (move < 0) - { - DBG (DBG_error, "%s: overriding negative move value %d\n", __func__, move); - move = 0; - } - } - DBG (DBG_info, "%s: move=%d steps\n", __func__, move); - - /* pixels are allways given at full CCD optical resolution */ - /* use detected left margin and fixed value */ - if (xcorrection == SANE_TRUE) - { - if (dev->sensor.CCD_start_xoffset > 0) - startx = dev->sensor.CCD_start_xoffset; - else - startx = dev->sensor.dummy_pixel; - if (settings.scan_method == SCAN_METHOD_FLATBED) - { - startx += - ((SANE_UNFIX (dev->model->x_offset) * dev->sensor.optical_res) / - MM_PER_INCH); - } - else - { - startx += - ((SANE_UNFIX (dev->model->x_offset_ta) * - dev->sensor.optical_res) / MM_PER_INCH); - } - } - else - { - /* startx cannot be below dummy pixel value */ - startx = dev->sensor.dummy_pixel; - } - - /* add x coordinates : expressed in sensor max dpi */ - startx += (settings.tl_x * dev->sensor.optical_res) / MM_PER_INCH; - - /* stagger works with odd start cordinates */ - if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) - startx |= 1; - - pixels = (settings.pixels * dev->sensor.optical_res) / settings.xres; - /* special requirement for 400 dpi on 1200 dpi sensors */ - if (settings.xres == 400) - { - pixels = (pixels / 6) * 6; - } - endx = startx + pixels; - - /* TODO check for pixel width overflow */ - - /* set up correct values for scan (gamma and shading enabled) */ - status = gl646_setup_registers (dev, - regs, - settings, - dev->slope_table0, - dev->slope_table1, - settings.xres, - move, - settings.lines, - startx, endx, color, - depth); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed setup registers: %s\n", __func__, sane_strstatus (status)); - return status; - } - - /* now post-process values for register and options fine tuning */ - - /* select color filter based on settings */ - regs[reg_0x04].value &= ~REG04_FILTER; - if (channels == 1) - { - switch (settings.color_filter) - { - /* red */ - case 0: - regs[reg_0x04].value |= 0x04; - break; - /* green */ - case 1: - regs[reg_0x04].value |= 0x08; - break; - /* blue */ - case 2: - regs[reg_0x04].value |= 0x0c; - break; - default: - break; - } - } - - /* send computed slope tables */ - status = - gl646_send_slope_table (dev, 0, dev->slope_table0, - sanei_genesys_read_reg_from_set (regs, 0x21)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send slope table 0: %s\n", __func__, sane_strstatus (status)); - return status; - } - - status = - gl646_send_slope_table (dev, 1, dev->slope_table1, - sanei_genesys_read_reg_from_set (regs, 0x6b)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return status; -} - -/** - * this function sen gamm table to ASIC - */ -static SANE_Status -gl646_send_gamma_table (Genesys_Device * dev) -{ - int size; - int address; - SANE_Status status; - uint8_t *gamma; - int bits; - - DBGSTART; - - /* gamma table size */ - if (dev->reg[reg_0x05].value & REG05_GMMTYPE) - { - size = 16384; - bits = 14; - } - else - { - size = 4096; - bits = 12; - } - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - gamma = (uint8_t *) malloc (size * 2 * 3); - if (gamma==NULL) - { - return SANE_STATUS_NO_MEM; - } - - RIE(sanei_genesys_generate_gamma_buffer(dev, bits, size-1, size, gamma)); - - /* table address */ - switch (dev->reg[reg_0x05].value >> 6) - { - case 0: /* 600 dpi */ - address = 0x09000; - break; - case 1: /* 1200 dpi */ - address = 0x11000; - break; - case 2: /* 2400 dpi */ - address = 0x20000; - break; - default: - free (gamma); - return SANE_STATUS_INVAL; - } - - /* send address */ - status = sanei_genesys_set_buffer_address (dev, address); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "gl646_send_gamma_table: failed to set buffer address: %s\n", - sane_strstatus (status)); - return status; - } - - /* send data */ - status = gl646_bulk_write_data (dev, 0x3c, (uint8_t *) gamma, size * 2 * 3); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "gl646_send_gamma_table: failed to send gamma table: %s\n", - sane_strstatus (status)); - return status; - } - free (gamma); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief this function does the led calibration. - * this function does the led calibration by scanning one line of the calibration - * area below scanner's top on white strip. The scope of this function is - * currently limited to the XP200 - */ -static SANE_Status -gl646_led_calibration (Genesys_Device * dev) -{ - int total_size; - uint8_t *line; - unsigned int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - unsigned int channels; - int avg[3], avga, avge; - int turn; - char fn[20]; - uint16_t expr, expg, expb; - Genesys_Settings settings; - SANE_Int resolution; - - SANE_Bool acceptable = SANE_FALSE; - - DBG (DBG_proc, "gl646_led_calibration\n"); - if (!dev->model->is_cis) - { - DBG (DBG_proc, - "gl646_led_calibration: not a cis scanner, nothing to do...\n"); - return SANE_STATUS_GOOD; - } - - /* get led calibration resolution */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, - SANE_TRUE); - settings.scan_mode = SCAN_MODE_COLOR; - channels = 3; - } - else - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, - SANE_FALSE); - settings.scan_mode = SCAN_MODE_GRAY; - channels = 1; - } - - /* offset calibration is always done in color mode */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = 1; - settings.depth = 16; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* colors * bytes_per_color * scan lines */ - total_size = settings.pixels * channels * 2 * 1; - - line = malloc (total_size); - if (!line) - { - DBG (DBG_error, "gl646_led_calibration: failed to allocate %d bytes\n", - total_size); - return SANE_STATUS_NO_MEM; - } - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - - Sensor_Master uint8_t regs_0x10_0x15[6]; - */ - - expr = (dev->sensor.regs_0x10_0x1d[0] << 8) | dev->sensor.regs_0x10_0x1d[1]; - expg = (dev->sensor.regs_0x10_0x1d[2] << 8) | dev->sensor.regs_0x10_0x1d[3]; - expb = (dev->sensor.regs_0x10_0x1d[4] << 8) | dev->sensor.regs_0x10_0x1d[5]; - - turn = 0; - - do - { - - dev->sensor.regs_0x10_0x1d[0] = (expr >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[1] = expr & 0xff; - dev->sensor.regs_0x10_0x1d[2] = (expg >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[3] = expg & 0xff; - dev->sensor.regs_0x10_0x1d[4] = (expb >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[5] = expb & 0xff; - - DBG (DBG_info, "gl646_led_calibration: starting first line reading\n"); - - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, &line); - if (status != SANE_STATUS_GOOD) - { - free(line); - DBG (DBG_error, - "gl646_led_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - snprintf (fn, 20, "led_%02d.pnm", turn); - sanei_genesys_write_pnm_file (fn, - line, - 16, channels, settings.pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < settings.pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * settings.pixels + 1] * 256 + - line[i * 2 + j * 2 * settings.pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= settings.pixels; - } - - DBG (DBG_info, "gl646_led_calibration: average: " - "%d,%d,%d\n", avg[0], avg[1], avg[2]); - - acceptable = SANE_TRUE; - - if (!acceptable) - { - avga = (avg[0] + avg[1] + avg[2]) / 3; - expr = (expr * avga) / avg[0]; - expg = (expg * avga) / avg[1]; - expb = (expb * avga) / avg[2]; - - /* keep exposure time in a working window */ - avge = (expr + expg + expb) / 3; - if (avge > 0x2000) - { - expr = (expr * 0x2000) / avge; - expg = (expg * 0x2000) / avge; - expb = (expb * 0x2000) / avge; - } - if (avge < 0x400) - { - expr = (expr * 0x400) / avge; - expg = (expg * 0x400) / avge; - expb = (expb * 0x400) / avge; - } - } - - turn++; - - } - while (!acceptable && turn < 100); - - DBG (DBG_info, - "gl646_led_calibration: acceptable exposure: 0x%04x,0x%04x,0x%04x\n", - expr, expg, expb); - - /* cleanup before return */ - free (line); - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black) -{ - unsigned int i, j, k, average, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average value on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG (DBG_info, "dark_average: avg[%d] = %d\n", k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG (DBG_info, "dark_average: average = %d\n", average); - return average; -} - - -/** @brief calibration for AD frontend devices - * we do simple scan until all black_pixels are higher than 0, - * raising offset at each turn. - */ -static SANE_Status -ad_fe_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *line; - unsigned int channels; - char title[32]; - int pass = 0; - SANE_Int resolution; - Genesys_Settings settings; - unsigned int x, y, adr, min; - unsigned int bottom, black_pixels; - - DBG (DBG_proc, "ad_fe_offset_calibration: start\n"); - resolution = - get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, - SANE_TRUE); - channels = 3; - black_pixels = - (dev->sensor.black_pixels * resolution) / dev->sensor.optical_res; - DBG (DBG_io2, "ad_fe_offset_calibration: black_pixels=%d\n", black_pixels); - - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan first line of data with no gain */ - dev->frontend.gain[0] = 0; - dev->frontend.gain[1] = 0; - dev->frontend.gain[2] = 0; - - /* scan with no move */ - bottom = 1; - do - { - pass++; - dev->frontend.offset[0] = bottom; - dev->frontend.offset[1] = bottom; - dev->frontend.offset[2] = bottom; - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, &line); - if (status != SANE_STATUS_GOOD) - { - free(line); - DBG (DBG_error, - "ad_fe_offset_calibration: failed to scan first line\n"); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", (int)bottom); - sanei_genesys_write_pnm_file (title, line, 8, channels, - settings.pixels, settings.lines); - } - - min = 0; - for (y = 0; y < settings.lines; y++) - { - for (x = 0; x < black_pixels; x++) - { - adr = (x + y * settings.pixels) * channels; - if (line[adr] > min) - min = line[adr]; - if (line[adr + 1] > min) - min = line[adr + 1]; - if (line[adr + 2] > min) - min = line[adr + 2]; - } - } - - free (line); - DBG (DBG_io2, "ad_fe_offset_calibration: pass=%d, min=%d\n", pass, min); - bottom++; - } - while (pass < 128 && min == 0); - if (pass == 128) - { - DBG (DBG_error, - "ad_fe_offset_calibration: failed to find correct offset\n"); - return SANE_STATUS_INVAL; - } - - DBG (DBG_info, "ad_fe_offset_calibration: offset=(%d,%d,%d)\n", - dev->frontend.offset[0], dev->frontend.offset[1], - dev->frontend.offset[2]); - DBG (DBG_proc, "ad_fe_offset_calibration: end\n"); - return status; -} - -#define DARK_TARGET 8 -/** - * This function does the offset calibration by scanning one line of the calibration - * area below scanner's top. There is a black margin and the remaining is white. - * genesys_search_start() must have been called so that the offsets and margins - * are already known. - * @param dev scanner's device - * @return SANE_STATUS_GOOD if success, else error code is failure -*/ -static SANE_Status -gl646_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *first_line, *second_line; - unsigned int channels; - char title[32]; - int pass = 0, avg; - SANE_Int resolution; - Genesys_Settings settings; - int topavg, bottomavg; - int top, bottom, black_pixels; - - /* Analog Device fronted have a different calibration */ - if (dev->model->dac_type == DAC_AD_XP200) - { - return ad_fe_offset_calibration (dev); - } - - DBG (DBG_proc, "gl646_offset_calibration: start\n"); - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - if (dev->settings.xres > dev->sensor.optical_res) - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->sensor.optical_res, - SANE_TRUE); - } - else - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->settings.xres, - SANE_TRUE); - } - channels = 3; - black_pixels = - (dev->sensor.black_pixels * resolution) / dev->sensor.optical_res; - DBG (DBG_io2, "gl646_offset_calibration: black_pixels=%d\n", black_pixels); - - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan first line of data with no gain, but with offset from - * last calibration */ - dev->frontend.gain[0] = 0; - dev->frontend.gain[1] = 0; - dev->frontend.gain[2] = 0; - - /* scan with no move */ - bottom = 90; - dev->frontend.offset[0] = bottom; - dev->frontend.offset[1] = bottom; - dev->frontend.offset[2] = bottom; - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, - &first_line); - if (status != SANE_STATUS_GOOD) - { - free(first_line); - DBG (DBG_error, - "gl646_offset_calibration: failed to scan first line\n"); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", bottom); - sanei_genesys_write_pnm_file (title, first_line, 8, channels, - settings.pixels, settings.lines); - } - bottomavg = - dark_average (first_line, settings.pixels, settings.lines, channels, - black_pixels); - free (first_line); - DBG (DBG_io2, "gl646_offset_calibration: bottom avg=%d\n", bottomavg); - - /* now top value */ - top = 231; - dev->frontend.offset[0] = top; - dev->frontend.offset[1] = top; - dev->frontend.offset[2] = top; - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, - &second_line); - if (status != SANE_STATUS_GOOD) - { - free(second_line); - DBG (DBG_error, - "gl646_offset_calibration: failed to scan first line\n"); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", top); - sanei_genesys_write_pnm_file (title, second_line, 8, channels, - settings.pixels, settings.lines); - } - topavg = - dark_average (second_line, settings.pixels, settings.lines, channels, - black_pixels); - free (second_line); - DBG (DBG_io2, "gl646_offset_calibration: top avg=%d\n", topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.offset[0] = (top + bottom) / 2; - dev->frontend.offset[1] = (top + bottom) / 2; - dev->frontend.offset[2] = (top + bottom) / 2; - - /* scan with no move */ - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, - &second_line); - if (status != SANE_STATUS_GOOD) - { - free(second_line); - DBG (DBG_error, - "gl646_offset_calibration: failed to scan first line\n"); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", dev->frontend.offset[1]); - sanei_genesys_write_pnm_file (title, second_line, 8, channels, - settings.pixels, settings.lines); - } - - avg = - dark_average (second_line, settings.pixels, settings.lines, channels, - black_pixels); - DBG (DBG_info, "gl646_offset_calibration: avg=%d offset=%d\n", avg, - dev->frontend.offset[1]); - free (second_line); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.offset[1]; - } - else - { - bottomavg = avg; - bottom = dev->frontend.offset[1]; - } - } - - /* in case of debug do a final scan to get result */ - if (DBG_LEVEL >= DBG_data) - { - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, - &second_line); - if (status != SANE_STATUS_GOOD) - { - free(second_line); - DBG (DBG_error, - "gl646_offset_calibration: failed to scan final line\n"); - return status; - } - sanei_genesys_write_pnm_file ("offset-final.pnm", second_line, 8, - channels, settings.pixels, - settings.lines); - free (second_line); - } - - DBG (DBG_info, "gl646_offset_calibration: offset=(%d,%d,%d)\n", - dev->frontend.offset[0], dev->frontend.offset[1], - dev->frontend.offset[2]); - DBG (DBG_proc, "gl646_offset_calibration: end\n"); - return status; -} - -/** @brief gain calibration for Analog Device frontends - * Alternative coarse gain calibration - */ -static SANE_Status -ad_fe_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - uint8_t *line; - unsigned int i, channels, val; - unsigned int size, count, resolution, pass; - SANE_Status status = SANE_STATUS_GOOD; - float average; - Genesys_Settings settings; - char title[32]; - - DBGSTART; - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - resolution = get_closest_resolution (dev->model->ccd_type, dpi, SANE_TRUE); - channels = 3; - settings.scan_mode = SCAN_MODE_COLOR; - - settings.scan_method = SCAN_METHOD_FLATBED; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - size = channels * settings.pixels * settings.lines; - - /* start gain value */ - dev->frontend.gain[0] = 1; - dev->frontend.gain[1] = 1; - dev->frontend.gain[2] = 1; - - average = 0; - pass = 0; - - /* loop until each channel raises to acceptable level */ - while ((average < dev->sensor.gain_white_ref) && (pass < 30)) - { - /* scan with no move */ - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, &line); - if (status != SANE_STATUS_GOOD) - { - free(line); - DBG (DBG_error, - "ad_fe_coarse_gain_calibration: failed to scan first line\n"); - return status; - } - - /* log scanning data */ - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "alternative_coarse%02d.pnm", (int)pass); - sanei_genesys_write_pnm_file (title, line, 8, - channels, settings.pixels, - settings.lines); - } - pass++; - - /* computes white average */ - average = 0; - count = 0; - for (i = 0; i < size; i++) - { - val = line[i]; - average += val; - count++; - } - average = average / count; - - /* adjusts gain for the channel */ - if (average < dev->sensor.gain_white_ref) - dev->frontend.gain[0]++; - dev->frontend.gain[1] = dev->frontend.gain[0]; - dev->frontend.gain[2] = dev->frontend.gain[0]; - - DBG (DBG_proc, - "ad_fe_coarse_gain_calibration: average = %.2f, gain = %d\n", - average, dev->frontend.gain[0]); - free (line); - } - - DBG (DBG_info, "ad_fe_coarse_gain_calibration: gains=(%d,%d,%d)\n", - dev->frontend.gain[0], dev->frontend.gain[1], dev->frontend.gain[2]); - DBGCOMPLETED; - return status; -} - -/** - * Alternative coarse gain calibration - * this on uses the settings from offset_calibration. First scan moves so - * we can go to calibration area for XPA. - * @param dev device for scan - * @param dpi resolutnio to calibrate at - */ -static SANE_Status -gl646_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - uint8_t *line; - unsigned int i, j, k, channels, val, maximum, idx; - unsigned int count, resolution, pass; - SANE_Status status = SANE_STATUS_GOOD; - float average[3]; - Genesys_Settings settings; - char title[32]; - - if (dev->model->ccd_type == CIS_XP200) - { - return ad_fe_coarse_gain_calibration (dev, dev->sensor.optical_res); - } - DBGSTART; - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - channels = 3; - - /* we are searching a sensor resolution */ - if (dpi > dev->sensor.optical_res) - { - resolution = dev->sensor.optical_res; - } - else - { - resolution = - get_closest_resolution (dev->model->ccd_type, dev->settings.xres, - SANE_TRUE); - } - - settings.scan_method = dev->settings.scan_method; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_y = 0; - if (settings.scan_method == SCAN_METHOD_FLATBED) - { - settings.tl_x = 0; - settings.pixels = (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - } - else - { - settings.tl_x = SANE_UNFIX (dev->model->x_offset_ta); - settings.pixels = (SANE_UNFIX (dev->model->x_size_ta) * resolution) / MM_PER_INCH; - } - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* start gain value */ - dev->frontend.gain[0] = 1; - dev->frontend.gain[1] = 1; - dev->frontend.gain[2] = 1; - - if (channels > 1) - { - average[0] = 0; - average[1] = 0; - average[2] = 0; - idx = 0; - } - else - { - average[0] = 255; - average[1] = 255; - average[2] = 255; - idx = dev->settings.color_filter; - average[idx] = 0; - } - pass = 0; - - /* loop until each channel raises to acceptable level */ - while (((average[0] < dev->sensor.gain_white_ref) - || (average[1] < dev->sensor.gain_white_ref) - || (average[2] < dev->sensor.gain_white_ref)) && (pass < 30)) - { - /* scan with no move */ - status = - simple_scan (dev, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, &line); - if (status != SANE_STATUS_GOOD) - { - free(line); - DBG (DBG_error, "%s: failed to scan first line\n", __func__); - return status; - } - - /* log scanning data */ - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "coarse_gain%02d.pnm", (int)pass); - sanei_genesys_write_pnm_file (title, line, 8, - channels, settings.pixels, - settings.lines); - } - pass++; - - /* average high level for each channel and compute gain - to reach the target code - we only use the central half of the CCD data */ - for (k = idx; k < idx + channels; k++) - { - /* we find the maximum white value, so we can deduce a threshold - to average white values */ - maximum = 0; - for (i = 0; i < settings.lines; i++) - { - for (j = 0; j < settings.pixels; j++) - { - val = line[i * channels * settings.pixels + j + k]; - if (val > maximum) - maximum = val; - } - } - - /* threshold */ - maximum *= 0.9; - - /* computes white average */ - average[k] = 0; - count = 0; - for (i = 0; i < settings.lines; i++) - { - for (j = 0; j < settings.pixels; j++) - { - /* averaging only white points allow us not to care about dark margins */ - val = line[i * channels * settings.pixels + j + k]; - if (val > maximum) - { - average[k] += val; - count++; - } - } - } - average[k] = average[k] / count; - - /* adjusts gain for the channel */ - if (average[k] < dev->sensor.gain_white_ref) - dev->frontend.gain[k]++; - - DBG (DBG_proc, - "%s: channel %d, average = %.2f, gain = %d\n", __func__, - k, average[k], dev->frontend.gain[k]); - } - free (line); - } - - if (channels < 3) - { - dev->frontend.gain[1] = dev->frontend.gain[0]; - dev->frontend.gain[2] = dev->frontend.gain[0]; - } - - DBG (DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, - dev->frontend.gain[0], dev->frontend.gain[1], dev->frontend.gain[2]); - DBGCOMPLETED; - return status; -} - -/** - * sets up the scanner's register for warming up. We scan 2 lines without moving. - * - */ -static SANE_Status -gl646_init_regs_for_warmup (Genesys_Device * dev, - Genesys_Register_Set * local_reg, - int *channels, int *total_size) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - int resolution, lines; - - DBG (DBG_proc, "gl646_init_regs_for_warmup: start\n"); - - sanei_genesys_init_fe (dev); - - resolution = get_closest_resolution (dev->model->ccd_type, 300, SANE_FALSE); - - /* set up for a half width 2 lines gray scan without moving */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_GRAY; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - settings.lines = 2; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* setup for scan */ - status = setup_for_scan (dev, dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_init_regs_for_warmup: setup_for_scan failed (%s)\n", - sane_strstatus (status)); - return status; - } - - /* we are not going to move, so clear these bits */ - dev->reg[reg_0x02].value &= ~(REG02_FASTFED | REG02_AGOHOME); - - /* don't enable any correction for this scan */ - dev->reg[reg_0x01].value &= ~REG01_DVDSET; - - /* copy to local_reg */ - memcpy (local_reg, dev->reg, (GENESYS_GL646_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - - /* turn off motor during this scan */ - gl646_set_motor_power (local_reg, SANE_FALSE); - - /* returned value to higher level warmup function */ - *channels = 1; - lines = gl646_get_triple_reg (local_reg, REG_LINCNT) + 1; - *total_size = lines * settings.pixels; - - /* now registers are ok, write them to scanner */ - RIE (gl646_set_fe (dev, AFE_SET, settings.xres)); - RIE (gl646_bulk_write_register (dev, local_reg, GENESYS_GL646_MAX_REGS)); - - DBGCOMPLETED; - return status; -} - - -/* - * this function moves head without scanning, forward, then backward - * so that the head goes to park position. - * as a by-product, also check for lock - */ -static SANE_Status -gl646_repark_head (Genesys_Device * dev) -{ - SANE_Status status; - Genesys_Settings settings; - unsigned int expected, steps; - - DBG (DBG_proc, "gl646_repark_head: start\n"); - - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = - get_closest_resolution (dev->model->ccd_type, 75, SANE_FALSE); - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 5; - settings.pixels = 600; - settings.lines = 4; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - status = setup_for_scan (dev, dev->reg, settings, SANE_FALSE, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_repark_head: failed to setup for scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* TODO seems wrong ... no effective scan */ - dev->reg[reg_0x01].value &= ~REG01_SCAN; - - status = gl646_bulk_write_register (dev, dev->reg, GENESYS_GL646_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_repark_head: failed to send registers: %s\n", - sane_strstatus (status)); - return status; - } - - /* start scan */ - status = gl646_begin_scan (dev, dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_repark_head: failed to begin scan: \n"); - return status; - } - - expected = gl646_get_triple_reg (dev->reg, REG_FEEDL); - do - { - usleep (100 * 1000); - status = sanei_genesys_read_feed_steps (dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_repark_head: failed to read feed steps: %s\n", - sane_strstatus (status)); - return status; - } - } - while (steps < expected); - - /* toggle motor flag, put an huge step number and redo move backward */ - status = gl646_slow_back_home (dev, 1); - DBG (DBG_proc, "gl646_repark_head: end\n"); - return status; -} - -/* * - * initialize ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - * @param dev device description of the scanner to initailize - * @return SANE_STATUS_GOOD if success, error code if failure - */ -static SANE_Status -gl646_init (Genesys_Device * dev) -{ - SANE_Status status; - struct timeval tv; - uint8_t cold = 0, val = 0; - uint32_t addr = 0xdead; - int size, i; - size_t len; - - DBG_INIT (); - DBG (DBG_proc, "gl646_init: start\n"); - - /* to detect real power up condition, we write to REG41 - * with pwrbit set, then read it back. When scanner is cold (just replugged) - * PWRBIT will be set in the returned value - */ - RIE (sanei_genesys_get_status (dev, &cold)); - DBG (DBG_info, "gl646_init: status=0x%02x\n", cold); - cold = !(cold & REG41_PWRBIT); - if (cold) - { - DBG (DBG_info, "gl646_init: device is cold\n"); - } - else - { - DBG (DBG_info, "gl646_init: device is hot\n"); - } - - /* if scanning session hasn't been initialized, set it up */ - if (!dev->already_initialized) - { - dev->dark_average_data = NULL; - dev->white_average_data = NULL; - - dev->settings.color_filter = 1; /* green filter by default */ - gettimeofday (&tv, NULL); - dev->init_date = tv.tv_sec; - - switch (dev->model->motor_type) - { - /* set to 11111 to spot bugs, sanei_genesys_exposure_time should - have obsoleted this field */ - case MOTOR_5345: - dev->settings.exposure_time = 11111; - break; - - case MOTOR_ST24: - dev->settings.exposure_time = 11000; - break; - default: - dev->settings.exposure_time = 11000; - break; - } - - /* Set default values for registers */ - gl646_init_regs (dev); - - /* build default gamma tables */ - if (dev->reg[reg_0x05].value & REG05_GMMTYPE) - size = 16384; - else - size = 4096; - - for(i=0;i<3;i++) - { - if (dev->sensor.gamma_table[i] == NULL) - { - dev->sensor.gamma_table[i] = (uint16_t *) malloc (2 * size); - if (dev->sensor.gamma_table[i] == NULL) - { - DBG (DBG_error, "gl646_init: could not allocate memory for gamma table %d\n",i); - return SANE_STATUS_NO_MEM; - } - sanei_genesys_create_gamma_table (dev->sensor.gamma_table[i], - size, - size - 1, - size - 1, - dev->sensor.gamma[i]); - } - } - - /* Init shading data */ - RIE (sanei_genesys_init_shading_data (dev, dev->sensor.sensor_pixels)); - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, - (GENESYS_GL646_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - } - - /* execute physical unit init only if cold */ - if (cold) - { - DBG (DBG_info, "gl646_init: device is cold\n"); - val = 0x04; - RIE (sanei_usb_control_msg - (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_INIT, - INDEX, 1, &val)); - - /* ASIC reset */ - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - usleep (100000UL); /* sleep 100 ms */ - - /* Write initial registers */ - RIE (gl646_bulk_write_register (dev, dev->reg, GENESYS_GL646_MAX_REGS)); - - /* Test ASIC and RAM */ - if (!(dev->model->flags & GENESYS_FLAG_LAZY_INIT)) - { - RIE (gl646_asic_test (dev)); - } - - /* send gamma tables if needed */ - status = gl646_send_gamma_table (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_init: failed to send generic gamma tables: %s\n", - sane_strstatus (status)); - return status; - } - - /* Set powersaving (default = 15 minutes) */ - RIE (gl646_set_powersaving (dev, 15)); - } /* end if cold */ - - /* Set analog frontend */ - RIE (gl646_set_fe (dev, AFE_INIT, 0)); - - /* GPO enabling for XP200 */ - if (dev->model->ccd_type == CIS_XP200) - { - sanei_genesys_write_register (dev, 0x68, dev->gpo.enable[0]); - sanei_genesys_write_register (dev, 0x69, dev->gpo.enable[1]); - - /* enable GPIO */ - val = 6; - status = gl646_gpio_output_enable (dev->dn, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_init: GPO enable failed ... %s\n", - sane_strstatus (status)); - } - val = 0; - - /* writes 0 to GPIO */ - status = gl646_gpio_write (dev->dn, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_init: GPO write failed ... %s\n", - sane_strstatus (status)); - } - - /* clear GPIO enable */ - status = gl646_gpio_output_enable (dev->dn, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_init: GPO disable failed ... %s\n", - sane_strstatus (status)); - } - sanei_genesys_write_register (dev, 0x66, 0x10); - sanei_genesys_write_register (dev, 0x66, 0x00); - sanei_genesys_write_register (dev, 0x66, 0x10); - } - - /* MD6471/G2410 and XP200 read/write data from an undocumented memory area which - * is after the second slope table */ - if (dev->model->gpo_type != GPO_HP3670 - && dev->model->gpo_type != GPO_HP2400) - { - switch (dev->sensor.optical_res) - { - case 600: - addr = 0x08200; - break; - case 1200: - addr = 0x10200; - break; - case 2400: - addr = 0x1fa00; - break; - } - status = sanei_genesys_set_buffer_address (dev, addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_init: failed to set up control address\n"); - return SANE_STATUS_INVAL; - } - sanei_usb_set_timeout (2 * 1000); - len = 6; - status = gl646_bulk_read_data (dev, 0x45, dev->control, len); - /* for some reason, read fails here for MD6471, HP2300 and XP200 - * one time out of 2 scanimage launches - */ - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_warn, "gl646_init: failed to read control\n"); - status = gl646_bulk_read_data (dev, 0x45, dev->control, len); - } - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_warn, "gl646_init: failed to read control\n"); - return SANE_STATUS_INVAL; - } - else - { - DBG (DBG_info, - "gl646_init: control read=0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", - dev->control[0], dev->control[1], dev->control[2], - dev->control[3], dev->control[4], dev->control[5]); - } - sanei_usb_set_timeout (30 * 1000); - } - else - /* HP2400 and HP3670 case */ - { - dev->control[0] = 0x00; - dev->control[1] = 0x00; - dev->control[2] = 0x01; - dev->control[3] = 0x00; - dev->control[4] = 0x00; - dev->control[5] = 0x00; - } - - /* ensure head is correctly parked, and check lock */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - if (dev->model->flags & GENESYS_FLAG_REPARK) - { - status = gl646_repark_head (dev); - if (status != SANE_STATUS_GOOD) - { - if (status == SANE_STATUS_INVAL) - { - DBG (DBG_error0, - "Your scanner is locked. Please move the lock switch " - "to the unlocked position\n"); -#ifdef SANE_STATUS_HW_LOCKED - return SANE_STATUS_HW_LOCKED; -#else - return SANE_STATUS_JAMMED; -#endif - } - else - DBG (DBG_error, - "gl646_init: gl646_repark_head failed: %s\n", - sane_strstatus (status)); - return status; - } - } - else - { - RIE (gl646_slow_back_home (dev, SANE_TRUE)); - } - } - - /* here session and device are initialized */ - dev->already_initialized = SANE_TRUE; - - DBG (DBG_proc, "gl646_init: end\n"); - return SANE_STATUS_GOOD; -} - -GENESYS_STATIC -SANE_Status -gl646_move_to_ta (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - if (simple_move (dev, SANE_UNFIX (dev->model->y_offset_calib_ta)) != - SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_move_to_ta: failed to move to calibration area\n"); - return status; - } - DBGCOMPLETED; - return status; -} - - -/** - * Does a simple scan: ie no line reordering and avanced data buffering and - * shading correction. Memory for data is allocated in this function - * and must be freed by caller. - * @param dev device of the scanner - * @param settings parameters of the scan - * @param move SANE_TRUE if moving during scan - * @param forward SANE_TRUE if moving forward during scan - * @param shading SANE_TRUE to enable shading correction - * @param data pointer for the data - */ -GENESYS_STATIC SANE_Status -simple_scan (Genesys_Device * dev, Genesys_Settings settings, SANE_Bool move, - SANE_Bool forward, SANE_Bool shading, unsigned char **data) -{ - SANE_Status status = SANE_STATUS_INVAL; - unsigned int size, lines, x, y, bpp; - SANE_Bool empty, split; - unsigned char *buffer; - int count; - uint8_t val; - - DBG (DBG_proc, "simple_scan: starting\n"); - DBG (DBG_io, "simple_scan: move=%d, forward=%d, shading=%d\n", move, - forward, shading); - - /* round up to multiple of 3 in case of CIS scanner */ - if (dev->model->is_cis == SANE_TRUE) - { - settings.lines = ((settings.lines + 2) / 3) * 3; - } - - /* setup for move then scan */ - if (move == SANE_TRUE && settings.tl_y > 0) - { - split = SANE_FALSE; - } - else - { - split = SANE_TRUE; - } - status = setup_for_scan (dev, dev->reg, settings, split, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "simple_scan: setup_for_scan failed (%s)\n", - sane_strstatus (status)); - return status; - } - - /* allocate memory fo scan : LINCNT may have been adjusted for CCD reordering */ - if (dev->model->is_cis == SANE_TRUE) - { - lines = gl646_get_triple_reg (dev->reg, REG_LINCNT) / 3; - } - else - { - lines = gl646_get_triple_reg (dev->reg, REG_LINCNT) + 1; - } - size = lines * settings.pixels; - if (settings.depth == 16) - bpp = 2; - else - bpp = 1; - size *= bpp; - if (settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - size *= 3; - *data = malloc (size); - if (!*data) - { - DBG (DBG_error, - "simple_scan: failed to allocate %d bytes of memory\n", size); - return SANE_STATUS_NO_MEM; - } - DBG (DBG_io, "simple_scan: allocated %d bytes of memory for %d lines\n", - size, lines); - - /* put back real line number in settings */ - settings.lines = lines; - - /* initialize frontend */ - status = gl646_set_fe (dev, AFE_SET, settings.xres); - if (status != SANE_STATUS_GOOD) - { - free (*data); - DBG (DBG_error, - "simple_scan: failed to set frontend: %s\n", - sane_strstatus (status)); - return status; - } - - /* no shading correction and not watch dog for simple scan */ - dev->reg[reg_0x01].value &= ~(REG01_DVDSET | REG01_DOGENB); - if (shading == SANE_TRUE) - { - dev->reg[reg_0x01].value |= REG01_DVDSET; - } - - /* enable gamma table for the scan */ - dev->reg[reg_0x05].value |= REG05_GMMENB; - - /* one table movement for simple scan */ - dev->reg[reg_0x02].value &= ~REG02_FASTFED; - - if (move == SANE_FALSE) - { - /* clear motor power flag if no move */ - dev->reg[reg_0x02].value &= ~REG02_MTRPWR; - - /* no automatic go home if no movement */ - dev->reg[reg_0x02].value &= ~REG02_AGOHOME; - } - if (forward == SANE_FALSE) - { - dev->reg[reg_0x02].value |= REG02_MTRREV; - } - else - { - dev->reg[reg_0x02].value &= ~REG02_MTRREV; - } - - /* no automatic go home when using XPA */ - if (settings.scan_method == SCAN_METHOD_TRANSPARENCY) - { - dev->reg[reg_0x02].value &= ~REG02_AGOHOME; - } - - /* write scan registers */ - status = gl646_bulk_write_register (dev, dev->reg, - sizeof (dev->reg) / - sizeof (dev->reg[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "simple_scan: failed to bulk write registers: %s\n", - sane_strstatus (status)); - free (*data); - return status; - } - - /* starts scan */ - status = gl646_begin_scan (dev, dev->reg, move); - if (status != SANE_STATUS_GOOD) - { - free (*data); - DBG (DBG_error, "simple_scan: failed to begin scan: \n"); - return status; - } - - /* wait for buffers to be filled */ - count = 0; - do - { - usleep (10000UL); - RIE (sanei_genesys_get_status (dev, &val)); - if (DBG_LEVEL > DBG_info) - { - print_status (val); - } - RIE (sanei_genesys_test_buffer_empty (dev, &empty)); - count++; - } - while (empty && count < 1000); - if (count == 1000) - { - free (*data); - DBG (DBG_error, "simple_scan: failed toread data\n"); - return SANE_STATUS_IO_ERROR; - } - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, *data, size); - if (status != SANE_STATUS_GOOD) - { - free (*data); - DBG (DBG_error, - "simple_scan: failed to read data: %s\n", sane_strstatus (status)); - return status; - } - - /* in case of CIS scanner, we must reorder data */ - if (dev->model->is_cis == SANE_TRUE - && settings.scan_mode == SCAN_MODE_COLOR) - { - /* alloc one line sized working buffer */ - buffer = (unsigned char *) malloc (settings.pixels * 3 * bpp); - if (buffer == NULL) - { - DBG (DBG_error, - "simple_scan: failed to allocate %d bytes of memory\n", - settings.pixels * 3); - return SANE_STATUS_NO_MEM; - } - - /* reorder one line of data and put it back to buffer */ - if (bpp == 1) - { - for (y = 0; y < lines; y++) - { - /* reorder line */ - for (x = 0; x < settings.pixels; x++) - { - buffer[x * 3] = (*data)[y * settings.pixels * 3 + x]; - buffer[x * 3 + 1] = - (*data)[y * settings.pixels * 3 + settings.pixels + x]; - buffer[x * 3 + 2] = - (*data)[y * settings.pixels * 3 + 2 * settings.pixels + - x]; - } - /* copy line back */ - memcpy ((*data) + settings.pixels * 3 * y, buffer, - settings.pixels * 3); - } - } - else - { - for (y = 0; y < lines; y++) - { - /* reorder line */ - for (x = 0; x < settings.pixels; x++) - { - buffer[x * 6] = (*data)[y * settings.pixels * 6 + x * 2]; - buffer[x * 6 + 1] = - (*data)[y * settings.pixels * 6 + x * 2 + 1]; - buffer[x * 6 + 2] = - (*data)[y * settings.pixels * 6 + 2 * settings.pixels + - x * 2]; - buffer[x * 6 + 3] = - (*data)[y * settings.pixels * 6 + 2 * settings.pixels + - x * 2 + 1]; - buffer[x * 6 + 4] = - (*data)[y * settings.pixels * 6 + 4 * settings.pixels + - x * 2]; - buffer[x * 6 + 5] = - (*data)[y * settings.pixels * 6 + 4 * settings.pixels + - x * 2 + 1]; - } - /* copy line back */ - memcpy ((*data) + settings.pixels * 6 * y, buffer, - settings.pixels * 6); - } - } - free (buffer); - } - - /* end scan , waiting the motor to stop if needed (if moving), but without ejecting doc */ - status = end_scan (dev, dev->reg, SANE_TRUE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - free (*data); - DBG (DBG_error, - "simple_scan: failed to end scan: %s\n", sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "simple_scan: end\n"); - return status; -} - -/** - * Does a simple move of the given distance by doing a scan at lowest resolution - * shading correction. Memory for data is allocated in this function - * and must be freed by caller. - * @param dev device of the scanner - * @param distance distance to move in MM - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -simple_move (Genesys_Device * dev, SANE_Int distance) -{ - SANE_Status status; - unsigned char *data = NULL; - Genesys_Settings settings; - - DBG (DBG_proc, "simple_move: %d mm\n", distance); - - /* TODO give a no AGOHOME flag */ - settings.scan_method = SCAN_METHOD_TRANSPARENCY; - settings.scan_mode = SCAN_MODE_COLOR; - settings.xres = get_lowest_resolution (dev->model->ccd_type, SANE_TRUE); - settings.yres = settings.xres; - settings.tl_y = 0; - settings.tl_x = 0; - settings.pixels = - (dev->sensor.sensor_pixels * settings.xres) / dev->sensor.optical_res; - settings.lines = (distance * settings.xres) / MM_PER_INCH; - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - status = simple_scan (dev, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, &data); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "simple_move: simple_scan failed\n"); - } - - free (data); - DBGCOMPLETED - return status; -} - -/** - * update the status of the required sensor in the scanner session - * the last_val fileds are used to make events 'sticky' - */ -static SANE_Status -gl646_update_hardware_sensors (Genesys_Scanner * session) -{ - Genesys_Device *dev = session->dev; - uint8_t value; - SANE_Status status; - - /* do what is needed to get a new set of events, but try to not loose - any of them. - */ - status = gl646_gpio_read (dev->dn, &value); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl646_update_hardware_sensors: failed to read GPIO %s\n", - sane_strstatus (status)); - return status; - } - DBG (DBG_io, "gl646_update_hardware_sensors: GPIO=0x%02x\n", value); - - /* scan button */ - if ((dev->model->buttons & GENESYS_HAS_SCAN_SW) - && session->val[OPT_SCAN_SW].b == session->last_val[OPT_SCAN_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_XP200: - session->val[OPT_SCAN_SW].b = ((value & 0x02) != 0); - break; - case GPO_5345: - session->val[OPT_SCAN_SW].b = (value == 0x16); - break; - case GPO_HP2300: - session->val[OPT_SCAN_SW].b = (value == 0x6c); - break; - case GPO_HP3670: - case GPO_HP2400: - session->val[OPT_SCAN_SW].b = ((value & 0x20) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* email button */ - if ((dev->model->buttons & GENESYS_HAS_EMAIL_SW) - && session->val[OPT_EMAIL_SW].b == session->last_val[OPT_EMAIL_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_5345: - session->val[OPT_EMAIL_SW].b = (value == 0x12); - break; - case GPO_HP3670: - case GPO_HP2400: - session->val[OPT_EMAIL_SW].b = ((value & 0x08) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* copy button */ - if ((dev->model->buttons & GENESYS_HAS_COPY_SW) - && session->val[OPT_COPY_SW].b == session->last_val[OPT_COPY_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_5345: - session->val[OPT_COPY_SW].b = (value == 0x11); - break; - case GPO_HP2300: - session->val[OPT_COPY_SW].b = (value == 0x5c); - break; - case GPO_HP3670: - case GPO_HP2400: - session->val[OPT_COPY_SW].b = ((value & 0x10) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* power button */ - if ((dev->model->buttons & GENESYS_HAS_POWER_SW) - && session->val[OPT_POWER_SW].b == session->last_val[OPT_POWER_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_5345: - session->val[OPT_POWER_SW].b = (value == 0x14); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* ocr button */ - if ((dev->model->buttons & GENESYS_HAS_OCR_SW) - && session->val[OPT_OCR_SW].b == session->last_val[OPT_OCR_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_5345: - session->val[OPT_OCR_SW].b = (value == 0x13); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* document detection */ - if ((dev->model->buttons & GENESYS_HAS_PAGE_LOADED_SW) - && session->val[OPT_PAGE_LOADED_SW].b == - session->last_val[OPT_PAGE_LOADED_SW].b) - { - switch (dev->model->gpo_type) - { - case GPO_XP200: - session->val[OPT_PAGE_LOADED_SW].b = ((value & 0x04) != 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* XPA detection */ - if (dev->model->flags & GENESYS_FLAG_XPA) - { - switch (dev->model->gpo_type) - { - case GPO_HP3670: - case GPO_HP2400: - /* test if XPA is plugged-in */ - if ((value & 0x40) == 0) - { - DBG (DBG_io, "gl646_update_hardware_sensors: enabling XPA\n"); - session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE; - } - else - { - DBG (DBG_io, "gl646_update_hardware_sensors: disabling XPA\n"); - session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; - } - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - return status; -} - - -static SANE_Status -write_control (Genesys_Device * dev, int resolution) -{ - SANE_Status status; - uint8_t control[4]; - uint32_t addr = 0xdead; - - /* 2300 does not write to 'control' */ - if (dev->model->motor_type == MOTOR_HP2300) - return SANE_STATUS_GOOD; - - /* MD6471/G2410/HP2300 and XP200 read/write data from an undocumented memory area which - * is after the second slope table */ - switch (dev->sensor.optical_res) - { - case 600: - addr = 0x08200; - break; - case 1200: - addr = 0x10200; - break; - case 2400: - addr = 0x1fa00; - break; - default: - DBG (DBG_error, "write_control: failed to compute control address\n"); - return SANE_STATUS_INVAL; - } - - /* XP200 sets dpi, what other scanner put is unknown yet */ - switch (dev->model->motor_type) - { - case MOTOR_XP200: - /* we put scan's dpi, not motor one */ - control[0] = LOBYTE (resolution); - control[1] = HIBYTE (resolution); - control[2] = dev->control[4]; - control[3] = dev->control[5]; - break; - case MOTOR_HP3670: - case MOTOR_HP2400: - case MOTOR_5345: - default: - control[0] = dev->control[2]; - control[1] = dev->control[3]; - control[2] = dev->control[4]; - control[3] = dev->control[5]; - break; - } - - DBG (DBG_info, - "write_control: control write=0x%02x 0x%02x 0x%02x 0x%02x\n", - control[0], control[1], control[2], control[3]); - status = sanei_genesys_set_buffer_address (dev, addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "write_control: failed to set up control address\n"); - return SANE_STATUS_INVAL; - } - status = gl646_bulk_write_data (dev, 0x3c, control, 4); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "write_control: failed to set up control\n"); - return SANE_STATUS_INVAL; - } - return status; -} - -/** - * check if a stored calibration is compatible with requested scan. - * @return SANE_STATUS_GOOD if compatible, SANE_STATUS_UNSUPPORTED if not. - * Whenever an error is met, it is returned. - * @param dev scanner device - * @param cache cache entry to test - * @param for_overwrite reserved for future use ... - */ -static SANE_Status -gl646_is_compatible_calibration (Genesys_Device * dev, - Genesys_Calibration_Cache * cache, - int for_overwrite) -{ -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - int compatible = 1; - - DBG (DBG_proc, - "gl646_is_compatible_calibration: start (for_overwrite=%d)\n", - for_overwrite); - - if (cache == NULL) - return SANE_STATUS_UNSUPPORTED; - - /* build minimal current_setup for calibration cache use only, it will be better - * computed when during setup for scan - */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) - { - dev->current_setup.channels = 3; - } - else - { - dev->current_setup.channels = 1; - } - dev->current_setup.xres = dev->settings.xres; - dev->current_setup.scan_method = dev->settings.scan_method; - - DBG (DBG_io, - "gl646_is_compatible_calibration: requested=(%d,%f), tested=(%d,%f)\n", - dev->current_setup.channels, dev->current_setup.xres, - cache->used_setup.channels, cache->used_setup.xres); - - /* a calibration cache is compatible if color mode and x dpi match the user - * requested scan. In the case of CIS scanners, dpi isn't a criteria */ - if (dev->model->is_cis == SANE_FALSE) - { - compatible = - ((dev->current_setup.channels == cache->used_setup.channels) - && (((int) dev->current_setup.xres) == - ((int) cache->used_setup.xres))); - } - else - { - compatible = - (dev->current_setup.channels == cache->used_setup.channels); - } - if (dev->current_setup.scan_method != cache->used_setup.scan_method) - { - DBG (DBG_io, - "gl646_is_compatible_calibration: current method=%d, used=%d\n", - dev->current_setup.scan_method, cache->used_setup.scan_method); - compatible = 0; - } - if (!compatible) - { - DBG (DBG_proc, - "gl646_is_compatible_calibration: completed, non compatible cache\n"); - return SANE_STATUS_UNSUPPORTED; - } - - /* a cache entry expires after 30 minutes for non sheetfed scanners */ - /* this is not taken into account when overwriting cache entries */ -#ifdef HAVE_SYS_TIME_H - if(for_overwrite == SANE_FALSE) - { - gettimeofday (&time, NULL); - if ((time.tv_sec - cache->last_calibration > 30 * 60) - && (dev->model->is_sheetfed == SANE_FALSE)) - { - DBG (DBG_proc, - "gl646_is_compatible_calibration: expired entry, non compatible cache\n"); - return SANE_STATUS_UNSUPPORTED; - } - } -#endif - - DBG (DBG_proc, - "gl646_is_compatible_calibration: completed, cache compatible\n"); - return SANE_STATUS_GOOD; -} - -/** - * search for a full width black or white strip. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl646_search_strip (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool half_ccd = SANE_FALSE; - Genesys_Settings settings; - int res = get_closest_resolution (dev->model->ccd_type, 75, SANE_FALSE); - unsigned char *data = NULL; - unsigned int pass, count, found, x, y; - char title[80]; - - DBG (DBG_proc, "gl646_search_strip: start\n"); - /* adapt to half_ccd case */ - if (dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE) - { - /* walk the master mode list to find if half_ccd */ - if (is_half_ccd (dev->model->ccd_type, res, SANE_TRUE) == SANE_TRUE) - { - half_ccd = SANE_TRUE; - } - } - - /* we set up for a lowest available resolution color grey scan, full width */ - settings.scan_method = SCAN_METHOD_FLATBED; - settings.scan_mode = SCAN_MODE_GRAY; - settings.xres = res; - settings.yres = res; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = (SANE_UNFIX (dev->model->x_size) * res) / MM_PER_INCH; - if (half_ccd == SANE_TRUE) - { - settings.pixels /= 2; - } - - /* 15 mm at at time */ - settings.lines = (15 * settings.yres) / MM_PER_INCH; /* may become a parameter from genesys_devices.c */ - settings.depth = 8; - settings.color_filter = 0; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.exposure_time = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* signals if a strip of the given color has been found */ - found = 0; - - /* detection pass done */ - pass = 0; - - /* loop until strip is found or maximum pass number done */ - while (pass < 20 && !found) - { - /* scan a full width strip */ - status = - simple_scan (dev, settings, SANE_TRUE, forward, SANE_FALSE, &data); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl646_search_strip: simple_scan failed\n"); - free (data); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s%02d.pnm", forward ? "fwd" : "bwd", - (int)pass); - sanei_genesys_write_pnm_file (title, data, settings.depth, 1, - settings.pixels, settings.lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < settings.lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < settings.pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * settings.pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * settings.pixels + x] < 60) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / settings.pixels < 3) - { - found = 1; - DBG (DBG_data, - "gl646_search_strip: strip found forward during pass %d at line %d\n", - pass, y); - } - else - { - DBG (DBG_data, "gl646_search_strip: pixels=%d, count=%d\n", - settings.pixels, count); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < settings.lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < settings.pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * settings.pixels + x] > 60) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * settings.pixels + x] < 60) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (settings.pixels * settings.lines) < 3) - { - found = 1; - DBG (DBG_data, - "gl646_search_strip: strip found backward during pass %d \n", - pass); - } - else - { - DBG (DBG_data, "gl646_search_strip: pixels=%d, count=%d\n", - settings.pixels, count); - } - } - pass++; - } - free (data); - if (found) - { - status = SANE_STATUS_GOOD; - DBG (DBG_info, "gl646_search_strip: strip found\n"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG (DBG_info, "gl646_search_strip: strip not found\n"); - } - return status; -} - -/** the gl646 command set */ -static Genesys_Command_Set gl646_cmd_set = { - "gl646-generic", /* the name of this set */ - - gl646_init, - gl646_init_regs_for_warmup, - gl646_init_regs_for_coarse_calibration, - gl646_init_regs_for_shading, - gl646_init_regs_for_scan, - - gl646_get_filter_bit, - gl646_get_lineart_bit, - gl646_get_bitset_bit, - gl646_get_gain4_bit, - gl646_get_fast_feed_bit, - gl646_test_buffer_empty_bit, - gl646_test_motor_flag_bit, - - gl646_bulk_full_size, - - gl646_public_set_fe, - gl646_set_powersaving, - gl646_save_power, - gl646_set_motor_power, - gl646_set_lamp_power, - - gl646_begin_scan, - gl646_end_scan, - - gl646_send_gamma_table, - - gl646_search_start_position, - - gl646_offset_calibration, - gl646_coarse_gain_calibration, - gl646_led_calibration, - - gl646_slow_back_home, - NULL, - - gl646_bulk_write_register, - gl646_bulk_write_data, - gl646_bulk_read_data, - - gl646_update_hardware_sensors, - - /* sheetfed related functions */ - gl646_load_document, - gl646_detect_document_end, - gl646_eject_document, - gl646_search_strip, - - gl646_is_compatible_calibration, - gl646_move_to_ta, - NULL, - NULL, - NULL, - NULL -}; - -SANE_Status -sanei_gl646_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl646_cmd_set; - return SANE_STATUS_GOOD; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl646.cc b/backend/genesys_gl646.cc new file mode 100644 index 0000000..b2b9f62 --- /dev/null +++ b/backend/genesys_gl646.cc @@ -0,0 +1,4911 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003 Oliver Rauch + Copyright (C) 2003, 2004 Henning Meier-Geinitz + Copyright (C) 2004 Gerhard Jaeger + Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2007 Luke + Copyright (C) 2011 Alexey Osipov for HP2400 description + and tuning + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_gl646.h" + +#include + +/** + * reads value from gpio endpoint + */ +static void gl646_gpio_read(UsbDevice& usb_dev, uint8_t* value) +{ + DBG_HELPER(dbg); + usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, GPIO_READ, INDEX, 1, value); +} + +/** + * writes the given value to gpio endpoint + */ +static void gl646_gpio_write(UsbDevice& usb_dev, uint8_t value) +{ + DBG_HELPER_ARGS(dbg, "(0x%02x)", value); + usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_WRITE, INDEX, 1, &value); +} + +/** + * writes the given value to gpio output enable endpoint + */ +static void gl646_gpio_output_enable(UsbDevice& usb_dev, uint8_t value) +{ + DBG_HELPER_ARGS(dbg, "(0x%02x)", value); + usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_OUTPUT_ENABLE, INDEX, 1, &value); +} + +/* Read bulk data (e.g. scanned data) */ +static SANE_Status +gl646_bulk_read_data (Genesys_Device * dev, uint8_t addr, + uint8_t * data, size_t len) +{ + SANE_Status status = sanei_genesys_bulk_read_data(dev, addr, data, len); + if (status != SANE_STATUS_GOOD) { + return status; + } + if (dev->model->is_sheetfed == SANE_TRUE) { + gl646_detect_document_end (dev); + } + return status; +} + +static SANE_Bool +gl646_get_fast_feed_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x02); + if (r && (r->value & REG02_FASTFED)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl646_get_filter_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x04); + if (r && (r->value & REG04_FILTER)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl646_get_lineart_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x04); + if (r && (r->value & REG04_LINEART)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl646_get_bitset_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x04); + if (r && (r->value & REG04_BITSET)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl646_get_gain4_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x06); + if (r && (r->value & REG06_GAIN4)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl646_test_buffer_empty_bit (SANE_Byte val) +{ + if (val & REG41_BUFEMPTY) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl646_test_motor_flag_bit (SANE_Byte val) +{ + if (val & REG41_MOTMFLG) + return SANE_TRUE; + return SANE_FALSE; +} + +/** + * decodes and prints content of status (0x41) register + * @param val value read from reg41 + */ +static void +print_status (uint8_t val) +{ + char msg[80]; + + sprintf (msg, "%s%s%s%s%s%s%s%s", + val & REG41_PWRBIT ? "PWRBIT " : "", + val & REG41_BUFEMPTY ? "BUFEMPTY " : "", + val & REG41_FEEDFSH ? "FEEDFSH " : "", + val & REG41_SCANFSH ? "SCANFSH " : "", + val & REG41_HOMESNR ? "HOMESNR " : "", + val & REG41_LAMPSTS ? "LAMPSTS " : "", + val & REG41_FEBUSY ? "FEBUSY " : "", + val & REG41_MOTMFLG ? "MOTMFLG" : ""); + DBG(DBG_info, "status=%s\n", msg); +} + +/** + * start scanner's motor + * @param dev scanner's device + */ +static SANE_Status +gl646_start_motor (Genesys_Device * dev) +{ + return sanei_genesys_write_register (dev, 0x0f, 0x01); +} + + +/** + * stop scanner's motor + * @param dev scanner's device + */ +static SANE_Status +gl646_stop_motor (Genesys_Device * dev) +{ + return sanei_genesys_write_register (dev, 0x0f, 0x00); +} + + +/** + * find the lowest resolution for the sensor in the given mode. + * @param sensor id of the sensor + * @param color true is color mode + * @return the closest resolution for the sensor and mode + */ +static int +get_lowest_resolution(int sensor_id, unsigned channels) +{ + int i, nb; + int dpi; + + i = 0; + dpi = 9600; + nb = sizeof (sensor_master) / sizeof (Sensor_Master); + while (i < nb) + { + /* computes distance and keep mode if it is closer than previous */ + if (sensor_id == sensor_master[i].sensor + && sensor_master[i].channels == channels) + { + if (sensor_master[i].dpi < dpi) + { + dpi = sensor_master[i].dpi; + } + } + i++; + } + DBG(DBG_info, "%s: %d\n", __func__, dpi); + return dpi; +} + +/** + * find the closest match in mode tables for the given resolution and scan mode. + * @param sensor id of the sensor + * @param required required resolution + * @param color true is color mode + * @return the closest resolution for the sensor and mode + */ +static int +get_closest_resolution(int sensor_id, int required, unsigned channels) +{ + int i, nb; + int dist, dpi; + + i = 0; + dpi = 0; + dist = 9600; + nb = sizeof (sensor_master) / sizeof (Sensor_Master); + while (i < nb) + { + /* exit on perfect match */ + if (sensor_id == sensor_master[i].sensor + && sensor_master[i].dpi == required + && sensor_master[i].channels == channels) + { + DBG(DBG_info, "%s: match found for %d\n", __func__, required); + return required; + } + /* computes distance and keep mode if it is closer than previous */ + if (sensor_id == sensor_master[i].sensor + && sensor_master[i].channels == channels) + { + if (abs (sensor_master[i].dpi - required) < dist) + { + dpi = sensor_master[i].dpi; + dist = abs (sensor_master[i].dpi - required); + } + } + i++; + } + DBG(DBG_info, "%s: closest match for %d is %d\n", __func__, required, dpi); + return dpi; +} + +/** + * Computes if sensor will be set up for half ccd pixels for the given + * scan mode. + * @param sensor id of the sensor + * @param required required resolution + * @param color true is color mode + * @return SANE_TRUE if half ccd is used + */ +static SANE_Bool is_half_ccd(int sensor_id, int required, unsigned channels) +{ + int i, nb; + + i = 0; + nb = sizeof (sensor_master) / sizeof (Sensor_Master); + while (i < nb) + { + /* exit on perfect match */ + if (sensor_id == sensor_master[i].sensor + && sensor_master[i].dpi == required + && sensor_master[i].channels == channels) + { + DBG(DBG_io, "%s: match found for %d (half_ccd=%d)\n", __func__, required, + sensor_master[i].half_ccd); + return sensor_master[i].half_ccd; + } + i++; + } + DBG(DBG_info, "%s: failed to find match for %d dpi\n", __func__, required); + return SANE_FALSE; +} + +/** + * Returns the cksel values used by the required scan mode. + * @param sensor id of the sensor + * @param required required resolution + * @param color true is color mode + * @return cksel value for mode + */ +static int get_cksel(int sensor_id, int required, unsigned channels) +{ + int i, nb; + + i = 0; + nb = sizeof (sensor_master) / sizeof (Sensor_Master); + while (i < nb) + { + /* exit on perfect match */ + if (sensor_id == sensor_master[i].sensor + && sensor_master[i].dpi == required + && sensor_master[i].channels == channels) + { + DBG(DBG_io, "%s: match found for %d (cksel=%d)\n", __func__, required, + sensor_master[i].cksel); + return sensor_master[i].cksel; + } + i++; + } + DBG(DBG_error, "%s: failed to find match for %d dpi\n", __func__, required); + /* fail safe fallback */ + return 1; +} + +/** + * Setup register and motor tables for a scan at the + * given resolution and color mode. TODO try to not use any filed from + * the device. + * @param dev pointer to a struct describing the device + * @param regs register set to fill + * @param slope_table1 first motor table to fill + * @param slope_table2 second motor table to fill + * @return SANE_STATUS_GOOD if registers could be set, SANE_STATUS_INVAL if + * conditions can't be met. + * @note No harcoded SENSOR or MOTOR 'names' should be present and + * registers are set from settings tables and flags related + * to the hardware capabilities. + * */ +static SANE_Status +gl646_setup_registers (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * regs, + SetupParams& params, + uint16_t * slope_table1, + uint16_t * slope_table2, + bool xcorrection) +{ + int resolution = params.xres; + uint32_t move = params.starty; + uint32_t linecnt = params.lines; + + uint32_t startx = 0; + /* pixels are allways given at full CCD optical resolution */ + /* use detected left margin and fixed value */ + if (xcorrection == SANE_TRUE) { + if (sensor.CCD_start_xoffset > 0) { + startx = sensor.CCD_start_xoffset; + } else { + startx = sensor.dummy_pixel; + } + } else { + // startx cannot be below dummy pixel value + startx = sensor.dummy_pixel; + } + + /* add x coordinates : expressed in sensor max dpi */ + startx += params.startx; + + /* stagger works with odd start cordinates */ + if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) { + startx |= 1; + } + + uint32_t pixels = (params.pixels * sensor.optical_res) / params.xres; + /* special requirement for 400 dpi on 1200 dpi sensors */ + if (params.xres == 400) + { + pixels = (pixels / 6) * 6; + } + /* TODO check for pixel width overflow */ + uint32_t endx = startx + pixels; + + SANE_Status status = SANE_STATUS_GOOD; + int i, nb; + Sensor_Master *sensor_mst = NULL; + Motor_Master *motor = NULL; + Sensor_Settings *settings = NULL; + GenesysRegister *r; + unsigned int used1, used2, vfinal; + unsigned int bpp; /**> bytes per pixel */ + uint32_t z1, z2; + uint16_t ex, sx; + int stagger, words_per_line, max_shift; + size_t requested_buffer_size; + size_t read_buffer_size; + SANE_Bool half_ccd = SANE_FALSE; + SANE_Int xresolution; + int feedl; + + DBG(DBG_proc, "%s: start\n", __func__); + DBG(DBG_info, "%s: startx=%d, endx=%d, linecnt=%d\n", __func__, startx, endx, linecnt); + + /* x resolution is capped by sensor's capability */ + if (resolution > sensor.optical_res) + { + xresolution = sensor.optical_res; + } + else + { + xresolution = resolution; + } + + /* for the given resolution, search for master + * sensor mode setting */ + i = 0; + nb = sizeof (sensor_master) / sizeof (Sensor_Master); + while (i < nb) + { + if (dev->model->ccd_type == sensor_master[i].sensor + && sensor_master[i].dpi == xresolution + && sensor_master[i].channels == params.channels) + { + sensor_mst = &sensor_master[i]; + } + i++; + } + if (sensor_mst == NULL) + { + DBG(DBG_error, "%s: unable to find settings for sensor %d at %d dpi channels=%d\n", __func__, + dev->model->ccd_type, xresolution, params.channels); + return SANE_STATUS_INVAL; + } + + /* for the given resolution, search for master + * motor mode setting */ + i = 0; + nb = sizeof (motor_master) / sizeof (Motor_Master); + while (i < nb) + { + if (dev->model->motor_type == motor_master[i].motor + && motor_master[i].dpi == resolution + && motor_master[i].channels == params.channels) + { + motor = &motor_master[i]; + } + i++; + } + if (motor == NULL) + { + DBG(DBG_error, "%s: unable to find settings for motor %d at %d dpi, color=%d\n", __func__, + dev->model->motor_type, resolution, params.channels); + return SANE_STATUS_INVAL; + } + + /* now we can search for the specific sensor settings */ + i = 0; + nb = sizeof (sensor_settings) / sizeof (Sensor_Settings); + while (i < nb) + { + if (sensor_mst->sensor == sensor_settings[i].sensor + && sensor_mst->cksel == sensor_settings[i].cksel) + { + settings = &sensor_settings[i]; + } + i++; + } + if (settings == NULL) + { + DBG(DBG_error, "%s: unable to find settings for sensor %d with '%d' ccd timing\n", __func__, + sensor_mst->sensor, sensor_mst->cksel); + return SANE_STATUS_INVAL; + } + + /* half_ccd if manual clock programming or dpi is half dpiset */ + half_ccd = sensor_mst->half_ccd; + + /* now apply values from settings to registers */ + if (sensor_mst->regs_0x10_0x15 != NULL) + { + for (i = 0; i < 6; i++) + { + r = sanei_genesys_get_address (regs, 0x10 + i); + r->value = sensor_mst->regs_0x10_0x15[i]; + } + } + else + { + for (i = 0; i < 6; i++) + { + r = sanei_genesys_get_address (regs, 0x10 + i); + r->value = 0; + } + } + + for (i = 0; i < 4; i++) + { + r = sanei_genesys_get_address (regs, 0x08 + i); + if (half_ccd == SANE_TRUE) + r->value = settings->manual_0x08_0x0b[i]; + else + r->value = settings->regs_0x08_0x0b[i]; + } + + for (i = 0; i < 8; i++) + { + r = sanei_genesys_get_address (regs, 0x16 + i); + r->value = settings->regs_0x16_0x1d[i]; + } + + for (i = 0; i < 13; i++) + { + r = sanei_genesys_get_address (regs, 0x52 + i); + r->value = settings->regs_0x52_0x5e[i]; + } + if (half_ccd == SANE_TRUE) + { + for (i = 0; i < 7; i++) + { + r = sanei_genesys_get_address (regs, 0x52 + i); + r->value = settings->manual_0x52_0x58[i]; + } + } + + /* now generate slope tables : we are not using generate_slope_table3 yet */ + sanei_genesys_generate_slope_table (slope_table1, motor->steps1, + motor->steps1 + 1, motor->vend1, + motor->vstart1, motor->vend1, + motor->steps1, motor->g1, &used1, + &vfinal); + sanei_genesys_generate_slope_table (slope_table2, motor->steps2, + motor->steps2 + 1, motor->vend2, + motor->vstart2, motor->vend2, + motor->steps2, motor->g2, &used2, + &vfinal); + + /* R01 */ + /* now setup other registers for final scan (ie with shading enabled) */ + /* watch dog + shading + scan enable */ + regs->find_reg(0x01).value |= REG01_DOGENB | REG01_DVDSET | REG01_SCAN; + if (dev->model->is_cis == SANE_TRUE) + regs->find_reg(0x01).value |= REG01_CISSET; + else + regs->find_reg(0x01).value &= ~REG01_CISSET; + + /* if device has no calibration, don't enable shading correction */ + if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) + { + regs->find_reg(0x01).value &= ~REG01_DVDSET; + } + + regs->find_reg(0x01).value &= ~REG01_FASTMOD; + if (motor->fastmod) + regs->find_reg(0x01).value |= REG01_FASTMOD; + + /* R02 */ + /* allow moving when buffer full by default */ + if (dev->model->is_sheetfed == SANE_FALSE) + dev->reg.find_reg(0x02).value &= ~REG02_ACDCDIS; + else + dev->reg.find_reg(0x02).value |= REG02_ACDCDIS; + + /* setup motor power and direction */ + sanei_genesys_set_motor_power(*regs, true); + regs->find_reg(0x02).value &= ~REG02_MTRREV; + + /* fastfed enabled (2 motor slope tables) */ + if (motor->fastfed) + regs->find_reg(0x02).value |= REG02_FASTFED; + else + regs->find_reg(0x02).value &= ~REG02_FASTFED; + + /* step type */ + regs->find_reg(0x02).value &= ~REG02_STEPSEL; + switch (motor->steptype) + { + case FULL_STEP: + break; + case HALF_STEP: + regs->find_reg(0x02).value |= 1; + break; + case QUATER_STEP: + regs->find_reg(0x02).value |= 2; + break; + default: + regs->find_reg(0x02).value |= 3; + break; + } + + /* if sheetfed, no AGOHOME */ + if (dev->model->is_sheetfed == SANE_TRUE) + { + regs->find_reg(0x02).value &= ~REG02_AGOHOME; + } + else + { + regs->find_reg(0x02).value |= REG02_AGOHOME; + } + + /* R03 */ + regs->find_reg(0x03).value &= ~REG03_AVEENB; + /* regs->find_reg(0x03).value |= REG03_AVEENB; */ + regs->find_reg(0x03).value &= ~REG03_LAMPDOG; + + /* select XPA */ + regs->find_reg(0x03).value &= ~REG03_XPASEL; + if (params.flags & SCAN_FLAG_USE_XPA) { + regs->find_reg(0x03).value |= REG03_XPASEL; + } + regs->state.is_xpa_on = params.flags & SCAN_FLAG_USE_XPA; + + /* R04 */ + /* monochrome / color scan */ + switch (params.depth) + { + case 1: + regs->find_reg(0x04).value &= ~REG04_BITSET; + regs->find_reg(0x04).value |= REG04_LINEART; + break; + case 8: + regs->find_reg(0x04).value &= ~(REG04_LINEART | REG04_BITSET); + break; + case 16: + regs->find_reg(0x04).value &= ~REG04_LINEART; + regs->find_reg(0x04).value |= REG04_BITSET; + break; + } + + /* R05 */ + regs->find_reg(0x05).value &= ~REG05_DPIHW; + switch (sensor.optical_res) + { + case 600: + regs->find_reg(0x05).value |= REG05_DPIHW_600; + break; + case 1200: + regs->find_reg(0x05).value |= REG05_DPIHW_1200; + break; + case 2400: + regs->find_reg(0x05).value |= REG05_DPIHW_2400; + break; + default: + regs->find_reg(0x05).value |= REG05_DPIHW; + } + + /* gamma enable for scans */ + if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) + regs->find_reg(0x05).value |= REG05_GMM14BIT; + + regs->find_reg(0x05).value &= ~REG05_GMMENB; + + /* true CIS gray if needed */ + if (dev->model->is_cis == SANE_TRUE && params.channels == 1 + && dev->settings.true_gray) + { + regs->find_reg(0x05).value |= REG05_LEDADD; + } + else + { + regs->find_reg(0x05).value &= ~REG05_LEDADD; + } + + /* cktoggle, ckdelay and cksel at once, cktdelay=2 => half_ccd for md5345 */ + regs->find_reg(0x18).value = sensor_mst->r18; + + /* manual CCD/2 clock programming => half_ccd for hp2300 */ + regs->find_reg(0x1d).value = sensor_mst->r1d; + + /* HP2400 1200dpi mode tuning */ + + if (dev->model->ccd_type == CCD_HP2400) + { + /* reset count of dummy lines to zero */ + regs->find_reg(0x1e).value &= ~REG1E_LINESEL; + if (params.xres >= 1200) + { + /* there must be one dummy line */ + regs->find_reg(0x1e).value |= 1 & REG1E_LINESEL; + + /* GPO12 need to be set to zero */ + regs->find_reg(0x66).value &= ~0x20; + } + else + { + /* set GPO12 back to one */ + regs->find_reg(0x66).value |= 0x20; + } + } + + /* motor steps used */ + regs->find_reg(0x21).value = motor->steps1; + regs->find_reg(0x22).value = motor->fwdbwd; + regs->find_reg(0x23).value = motor->fwdbwd; + regs->find_reg(0x24).value = motor->steps1; + + /* scanned area height must be enlarged by max color shift needed */ + max_shift=sanei_genesys_compute_max_shift(dev,params.channels, params.yres, 0); + + /* we adjust linecnt according to real motor dpi */ + linecnt = (linecnt * motor->ydpi) / params.yres + max_shift; + + /* at QUATER_STEP lines are 'staggered' and need correction */ + stagger = 0; + if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + { + /* for HP3670, stagger happens only at >=1200 dpi */ + if ((dev->model->motor_type != MOTOR_HP3670 && dev->model->motor_type != MOTOR_HP2400) + || params.yres >= (unsigned) sensor.optical_res) + { + stagger = (4 * params.yres) / dev->motor.base_ydpi; + } + } + linecnt += stagger; + + DBG(DBG_info, "%s : max_shift=%d, stagger=%d lines\n", __func__, max_shift, stagger); + + /* CIS scanners read one line per color channel + * since gray mode use 'add' we also read 3 channels even not in + * color mode */ + if (dev->model->is_cis == SANE_TRUE) + { + sanei_genesys_set_triple(regs, REG_LINCNT, linecnt * 3); + linecnt *= params.channels; + } + else + { + sanei_genesys_set_triple(regs, REG_LINCNT, linecnt); + } + + /* scanner's x coordinates are expressed in physical DPI but they must be divided by cksel */ + sx = startx / sensor_mst->cksel; + ex = endx / sensor_mst->cksel; + if (half_ccd == SANE_TRUE) + { + sx /= 2; + ex /= 2; + } + sanei_genesys_set_double(regs, REG_STRPIXEL, sx); + sanei_genesys_set_double(regs, REG_ENDPIXEL, ex); + DBG(DBG_info, "%s: startx=%d, endx=%d, half_ccd=%d\n", __func__, sx, ex, half_ccd); + + /* words_per_line must be computed according to the scan's resolution */ + /* in fact, words_per_line _gives_ the actual scan resolution */ + words_per_line = (((endx - startx) * sensor_mst->xdpi) / sensor.optical_res); + bpp=params.depth/8; + if (params.depth == 1) + { + words_per_line = (words_per_line+7)/8 ; + bpp=1; + } + else + { + words_per_line *= bpp; + } + dev->bpl = words_per_line; + words_per_line *= params.channels; + dev->wpl = words_per_line; + + DBG(DBG_info, "%s: wpl=%d\n", __func__, words_per_line); + sanei_genesys_set_triple(regs, REG_MAXWD, words_per_line); + + sanei_genesys_set_double(regs, REG_DPISET, sensor_mst->dpiset); + sanei_genesys_set_double(regs, REG_LPERIOD, sensor_mst->exposure); + + /* move distance must be adjusted to take into account the extra lines + * read to reorder data */ + feedl = move; + if (stagger + max_shift > 0 && feedl != 0) + { + if (feedl > + ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi) + feedl = + feedl - + ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi; + } + + /* we assume all scans are done with 2 tables */ + /* + feedl = feed_steps - fast_slope_steps*2 - + (slow_slope_steps >> scan_step_type); */ + /* but head has moved due to shading calibration => dev->scanhead_position_in_steps */ + if (feedl > 0) + { + /* take into account the distance moved during calibration */ + /* feedl -= dev->scanhead_position_in_steps; */ + DBG(DBG_info, "%s: initial move=%d\n", __func__, feedl); + DBG(DBG_info, "%s: scanhead_position_in_steps=%d\n", __func__, + dev->scanhead_position_in_steps); + + /* TODO clean up this when I'll fully understand. + * for now, special casing each motor */ + switch (dev->model->motor_type) + { + case MOTOR_5345: + switch (motor->ydpi) + { + case 200: + feedl -= 70; + break; + case 300: + feedl -= 70; + break; + case 400: + feedl += 130; + break; + case 600: + feedl += 160; + break; + case 1200: + feedl += 160; + break; + case 2400: + feedl += 180; + break; + default: + break; + } + break; + case MOTOR_HP2300: + switch (motor->ydpi) + { + case 75: + feedl -= 180; + break; + case 150: + feedl += 0; + break; + case 300: + feedl += 30; + break; + case 600: + feedl += 35; + break; + case 1200: + feedl += 45; + break; + default: + break; + } + break; + case MOTOR_HP2400: + switch (motor->ydpi) + { + case 150: + feedl += 150; + break; + case 300: + feedl += 220; + break; + case 600: + feedl += 260; + break; + case 1200: + feedl += 280; /* 300 */ + break; + case 50: + feedl += 0; + break; + case 100: + feedl += 100; + break; + default: + break; + } + break; + + /* theorical value */ + default: + if (motor->fastfed) + { + feedl = + feedl - 2 * motor->steps2 - + (motor->steps1 >> motor->steptype); + } + else + { + feedl = feedl - (motor->steps1 >> motor->steptype); + } + break; + } + /* security */ + if (feedl < 0) + feedl = 0; + } + + DBG(DBG_info, "%s: final move=%d\n", __func__, feedl); + sanei_genesys_set_triple(regs, REG_FEEDL, feedl); + + regs->find_reg(0x65).value = motor->mtrpwm; + + sanei_genesys_calculate_zmode2 (regs->find_reg(0x02).value & REG02_FASTFED, + sensor_mst->exposure, + slope_table1, + motor->steps1, + move, motor->fwdbwd, &z1, &z2); + + /* no z1/z2 for sheetfed scanners */ + if (dev->model->is_sheetfed == SANE_TRUE) + { + z1 = 0; + z2 = 0; + } + sanei_genesys_set_double(regs, REG_Z1MOD, z1); + sanei_genesys_set_double(regs, REG_Z2MOD, z2); + regs->find_reg(0x6b).value = motor->steps2; + regs->find_reg(0x6c).value = + (regs->find_reg(0x6c).value & REG6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16) + & 0x07); + + RIE (write_control (dev, sensor, xresolution)); + + /* setup analog frontend */ + RIE (gl646_set_fe(dev, sensor, AFE_SET, xresolution)); + + /* now we're done with registers setup values used by data transfer */ + /* we setup values needed for the data transfer */ + + /* we must use a round number of words_per_line */ + requested_buffer_size = 8 * words_per_line; + read_buffer_size = + 2 * requested_buffer_size + + ((max_shift + stagger) * params.pixels * params.channels * params.depth) / 8; + + dev->read_buffer.clear(); + dev->read_buffer.alloc(read_buffer_size); + + dev->lines_buffer.clear(); + dev->lines_buffer.alloc(read_buffer_size); + + dev->shrink_buffer.clear(); + dev->shrink_buffer.alloc(requested_buffer_size); + + dev->out_buffer.clear(); + dev->out_buffer.alloc(8 * params.pixels * params.channels * bpp); + + /* scan bytes to read */ + dev->read_bytes_left = words_per_line * linecnt; + + DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); + dev->read_active = SANE_TRUE; + + dev->current_setup.params = params; + dev->current_setup.pixels = + ((endx - startx) * sensor_mst->xdpi) / sensor.optical_res; + dev->current_setup.lines = linecnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = sensor_mst->exposure; + dev->current_setup.xres = sensor_mst->xdpi; + dev->current_setup.yres = motor->ydpi; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + + /* total_bytes_to_read is the number of byte to send to frontend + * total_bytes_read is the number of bytes sent to frontend + * read_bytes_left is the number of bytes to read from the scanner + */ + dev->total_bytes_read = 0; + if (params.depth == 1) { + dev->total_bytes_to_read = ((params.pixels * params.lines) / 8 + + (((params.pixels * params.lines) % 8) ? 1 : 0)) * params.channels; + } else { + dev->total_bytes_to_read = params.pixels * params.lines * params.channels * bpp; + } + + /* select color filter based on settings */ + regs->find_reg(0x04).value &= ~REG04_FILTER; + if (params.channels == 1) { + switch (params.color_filter) { + case ColorFilter::RED: + regs->find_reg(0x04).value |= 0x04; + break; + case ColorFilter::GREEN: + regs->find_reg(0x04).value |= 0x08; + break; + case ColorFilter::BLUE: + regs->find_reg(0x04).value |= 0x0c; + break; + default: + break; + } + } + + DBG(DBG_proc, "%s: end\n", __func__); + return SANE_STATUS_GOOD; +} + + +/** copy sensor specific settings */ +/* *dev : device infos + *regs : regiters to be set + extended : do extended set up + half_ccd: set up for half ccd resolution + all registers 08-0B, 10-1D, 52-5E are set up. They shouldn't + appear anywhere else but in register init +*/ +static void +gl646_setup_sensor (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * regs) +{ + (void) dev; + DBG(DBG_proc, "%s: start\n", __func__); + + for (const auto& reg_setting : sensor.custom_regs) { + regs->set8(reg_setting.address, reg_setting.value); + } + // FIXME: all other drivers don't set exposure here + sanei_genesys_set_exposure(*regs, sensor.exposure); + + DBG(DBG_proc, "%s: end\n", __func__); +} + +/** Test if the ASIC works + */ +static SANE_Status +gl646_asic_test (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + size_t size, verify_size; + unsigned int i; + + DBG(DBG_proc, "%s: start\n", __func__); + + /* set and read exposure time, compare if it's the same */ + status = sanei_genesys_write_register (dev, 0x38, 0xde); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_write_register (dev, 0x39, 0xad); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_read_register (dev, 0x4e, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (val != 0xde) /* value of register 0x38 */ + { + DBG(DBG_error, "%s: register contains invalid value\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + status = sanei_genesys_read_register (dev, 0x4f, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (val != 0xad) /* value of register 0x39 */ + { + DBG(DBG_error, "%s: register contains invalid value\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + /* ram test: */ + size = 0x40000; + verify_size = size + 0x80; + /* todo: looks like the read size must be a multiple of 128? + otherwise the read doesn't succeed the second time after the scanner has + been plugged in. Very strange. */ + + std::vector data(size); + std::vector verify_data(verify_size); + + for (i = 0; i < (size - 1); i += 2) + { + data[i] = i / 512; + data[i + 1] = (i / 2) % 256; + } + + status = sanei_genesys_set_buffer_address (dev, 0x0000); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_bulk_write_data(dev, 0x3c, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_set_buffer_address (dev, 0x0000); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = + gl646_bulk_read_data (dev, 0x45, verify_data.data(), verify_size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* i + 2 is needed as the changed address goes into effect only after one + data word is sent. */ + for (i = 0; i < size; i++) + { + if (verify_data[i + 2] != data[i]) + { + DBG(DBG_error, "%s: data verification error\n", __func__); + return SANE_STATUS_IO_ERROR; + } + } + + DBG(DBG_info, "%s: end\n", __func__); + + return SANE_STATUS_GOOD; +} + +/** + * Set all registers to default values after init + * @param dev scannerr's device to set + */ +static void +gl646_init_regs (Genesys_Device * dev) +{ + int addr; + + DBG(DBG_proc, "%s\n", __func__); + + dev->reg.clear(); + + for (addr = 1; addr <= 0x0b; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x10; addr <= 0x29; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x2c; addr <= 0x39; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x3d; addr <= 0x3f; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x52; addr <= 0x5e; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x60; addr <= 0x6d; addr++) + dev->reg.init_reg(addr, 0); + + dev->reg.find_reg(0x01).value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */ + dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ + if (dev->model->motor_type == MOTOR_5345) + dev->reg.find_reg(0x02).value |= 0x01; /* half-step */ + switch (dev->model->motor_type) + { + case MOTOR_5345: + dev->reg.find_reg(0x02).value |= 0x01; /* half-step */ + break; + case MOTOR_XP200: + /* for this sheetfed scanner, no AGOHOME, nor backtracking */ + dev->reg.find_reg(0x02).value = 0x50; + break; + default: + break; + } + dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */ + dev->reg.find_reg(0x04).value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */ + switch (dev->model->dac_type) + { + case DAC_AD_XP200: + dev->reg.find_reg(0x04).value = 0x12; + break; + default: + /* Wolfson frontend */ + dev->reg.find_reg(0x04).value = 0x13; + break; + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + dev->reg.find_reg(0x05).value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */ + switch (sensor.optical_res) + { + case 600: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; + break; + case 1200: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; + break; + case 2400: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; + break; + default: + dev->reg.find_reg(0x05).value |= REG05_DPIHW; + break; + } + if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) + dev->reg.find_reg(0x05).value |= REG05_GMM14BIT; + if (dev->model->dac_type == DAC_AD_XP200) + dev->reg.find_reg(0x05).value |= 0x01; /* 12 clocks/pixel */ + + if (dev->model->ccd_type == CCD_HP2300) + dev->reg.find_reg(0x06).value = 0x00; /* PWRBIT off, shading gain=4, normal AFE image capture */ + else + dev->reg.find_reg(0x06).value = 0x18; /* PWRBIT on, shading gain=8, normal AFE image capture */ + + + gl646_setup_sensor(dev, sensor, &dev->reg); + + dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */ + + switch (dev->model->ccd_type) + { + case CCD_HP2300: + dev->reg.find_reg(0x1e).value = 0xf0; + dev->reg.find_reg(0x1f).value = 0x10; + dev->reg.find_reg(0x20).value = 0x20; + break; + case CCD_HP2400: + dev->reg.find_reg(0x1e).value = 0x80; + dev->reg.find_reg(0x1f).value = 0x10; + dev->reg.find_reg(0x20).value = 0x20; + break; + case CCD_HP3670: + dev->reg.find_reg(0x19).value = 0x2a; + dev->reg.find_reg(0x1e).value = 0x80; + dev->reg.find_reg(0x1f).value = 0x10; + dev->reg.find_reg(0x20).value = 0x20; + break; + case CIS_XP200: + dev->reg.find_reg(0x1e).value = 0x10; + dev->reg.find_reg(0x1f).value = 0x01; + dev->reg.find_reg(0x20).value = 0x50; + break; + default: + dev->reg.find_reg(0x1f).value = 0x01; + dev->reg.find_reg(0x20).value = 0x50; + break; + } + + dev->reg.find_reg(0x21).value = 0x08 /*0x20 */ ; /* table one steps number for forward slope curve of the acc/dec */ + dev->reg.find_reg(0x22).value = 0x10 /*0x08 */ ; /* steps number of the forward steps for start/stop */ + dev->reg.find_reg(0x23).value = 0x10 /*0x08 */ ; /* steps number of the backward steps for start/stop */ + dev->reg.find_reg(0x24).value = 0x08 /*0x20 */ ; /* table one steps number backward slope curve of the acc/dec */ + dev->reg.find_reg(0x25).value = 0x00; /* scan line numbers (7000) */ + dev->reg.find_reg(0x26).value = 0x00 /*0x1b */ ; + dev->reg.find_reg(0x27).value = 0xd4 /*0x58 */ ; + dev->reg.find_reg(0x28).value = 0x01; /* PWM duty for lamp control */ + dev->reg.find_reg(0x29).value = 0xff; + + dev->reg.find_reg(0x2c).value = 0x02; /* set resolution (600 DPI) */ + dev->reg.find_reg(0x2d).value = 0x58; + dev->reg.find_reg(0x2e).value = 0x78; /* set black&white threshold high level */ + dev->reg.find_reg(0x2f).value = 0x7f; /* set black&white threshold low level */ + + dev->reg.find_reg(0x30).value = 0x00; /* begin pixel position (16) */ + dev->reg.find_reg(0x31).value = sensor.dummy_pixel /*0x10 */ ; /* TGW + 2*TG_SHLD + x */ + dev->reg.find_reg(0x32).value = 0x2a /*0x15 */ ; /* end pixel position (5390) */ + dev->reg.find_reg(0x33).value = 0xf8 /*0x0e */ ; /* TGW + 2*TG_SHLD + y */ + dev->reg.find_reg(0x34).value = sensor.dummy_pixel; + dev->reg.find_reg(0x35).value = 0x01 /*0x00 */ ; /* set maximum word size per line, for buffer full control (10800) */ + dev->reg.find_reg(0x36).value = 0x00 /*0x2a */ ; + dev->reg.find_reg(0x37).value = 0x00 /*0x30 */ ; + dev->reg.find_reg(0x38).value = 0x2a; // line period (exposure time = 11000 pixels) */ + dev->reg.find_reg(0x39).value = 0xf8; + dev->reg.find_reg(0x3d).value = 0x00; /* set feed steps number of motor move */ + dev->reg.find_reg(0x3e).value = 0x00; + dev->reg.find_reg(0x3f).value = 0x01 /*0x00 */ ; + + dev->reg.find_reg(0x60).value = 0x00; /* Z1MOD, 60h:61h:(6D b5:b3), remainder for start/stop */ + dev->reg.find_reg(0x61).value = 0x00; /* (21h+22h)/LPeriod */ + dev->reg.find_reg(0x62).value = 0x00; /* Z2MODE, 62h:63h:(6D b2:b0), remainder for start scan */ + dev->reg.find_reg(0x63).value = 0x00; /* (3Dh+3Eh+3Fh)/LPeriod for one-table mode,(21h+1Fh)/LPeriod */ + dev->reg.find_reg(0x64).value = 0x00; /* motor PWM frequency */ + dev->reg.find_reg(0x65).value = 0x00; /* PWM duty cycle for table one motor phase (63 = max) */ + if (dev->model->motor_type == MOTOR_5345) + dev->reg.find_reg(0x65).value = 0x02; /* PWM duty cycle for table one motor phase (63 = max) */ + dev->reg.find_reg(0x66).value = dev->gpo.value[0]; + dev->reg.find_reg(0x67).value = dev->gpo.value[1]; + dev->reg.find_reg(0x68).value = dev->gpo.enable[0]; + dev->reg.find_reg(0x69).value = dev->gpo.enable[1]; + + switch (dev->model->motor_type) + { + case MOTOR_HP2300: + case MOTOR_HP2400: + dev->reg.find_reg(0x6a).value = 0x7f; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6b).value = 0x78; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x7f; + break; + case MOTOR_5345: + dev->reg.find_reg(0x6a).value = 0x42; /* table two fast moving step type, PWM duty for table two */ + dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x41; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ + break; + case MOTOR_XP200: + dev->reg.find_reg(0x6a).value = 0x7f; /* table two fast moving step type, PWM duty for table two */ + dev->reg.find_reg(0x6b).value = 0x08; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ + break; + case MOTOR_HP3670: + dev->reg.find_reg(0x6a).value = 0x41; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6b).value = 0xc8; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x7f; + break; + default: + dev->reg.find_reg(0x6a).value = 0x40; /* table two fast moving step type, PWM duty for table two */ + dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ + break; + } + dev->reg.find_reg(0x6c).value = 0x00; /* peroid times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE (one period time) */ +} + + +/* Send slope table for motor movement + slope_table in machine byte order +*/ +static SANE_Status +gl646_send_slope_table (Genesys_Device * dev, int table_nr, + uint16_t * slope_table, int steps) +{ + int dpihw; + int start_address; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (table_nr = %d, steps = %d)=%d .. %d\n", __func__, table_nr, steps, + slope_table[0], slope_table[steps - 1]); + + dpihw = dev->reg.find_reg(0x05).value >> 6; + + if (dpihw == 0) /* 600 dpi */ + start_address = 0x08000; + else if (dpihw == 1) /* 1200 dpi */ + start_address = 0x10000; + else if (dpihw == 2) /* 2400 dpi */ + start_address = 0x1f800; + else /* reserved */ + return SANE_STATUS_INVAL; + + std::vector table(steps * 2); + for (int i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + status = + sanei_genesys_set_buffer_address (dev, start_address + table_nr * 0x100); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_bulk_write_data(dev, 0x3c, table.data(), steps * 2); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send slope table: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: end\n", __func__); + return status; +} + +/* Set values of Analog Device type frontend */ +static SANE_Status +gl646_set_ad_fe (Genesys_Device * dev, uint8_t set) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + + DBG(DBG_proc, "%s(): start\n", __func__); + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + + dev->frontend = dev->frontend_initial; + + /* write them to analog frontend */ + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write reg1: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + if (set == AFE_SET) + { + for (i = 0; i < 3; i++) + { + status = sanei_genesys_fe_write_data(dev, 0x02 + i, dev->frontend.get_gain(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write gain %d: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + for (i = 0; i < 3; i++) + { + status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.get_offset(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write offset %d: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + } + /* + if (set == AFE_POWER_SAVE) + { + status = + sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0] | 0x04); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status)); + return status; + } + } */ + DBG(DBG_proc, "%s(): end\n", __func__); + + return status; +} + +/** set up analog frontend + * set up analog frontend + * @param dev device to set up + * @param set action from AFE_SET, AFE_INIT and AFE_POWERSAVE + * @param dpi resolution of the scan since it affects settings + * @return SANE_STATUS_GOOD if evrithing OK + */ +static SANE_Status +gl646_wm_hp3670(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set, int dpi) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + + DBGSTART; + switch (set) + { + case AFE_INIT: + status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: reset failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_sleep_ms(200); + RIE (sanei_genesys_write_register (dev, 0x50, 0x00)); + dev->frontend = dev->frontend_initial; + status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.regs.get_value(0x02)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg2 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + gl646_gpio_output_enable(dev->usb_dev, 0x07); + break; + case AFE_POWER_SAVE: + status = sanei_genesys_fe_write_data (dev, 0x01, 0x06); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data (dev, 0x06, 0x0f); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg6 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + return status; + break; + default: /* AFE_SET */ + /* mode setup */ + i = dev->frontend.regs.get_value(0x03); + if (dpi > sensor.optical_res / 2) + { + /* fe_reg_0x03 must be 0x12 for 1200 dpi in DAC_WOLFSON_HP3670. + * DAC_WOLFSON_HP2400 in 1200 dpi mode works well with + * fe_reg_0x03 set to 0x32 or 0x12 but not to 0x02 */ + i = 0x12; + } + status = sanei_genesys_fe_write_data (dev, 0x03, i); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg3 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + /* offset and sign (or msb/lsb ?) */ + for (i = 0; i < 3; i++) + { + status = + sanei_genesys_fe_write_data(dev, 0x20 + i, dev->frontend.get_offset(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing offset%d failed: %s\n", __func__, i, + sane_strstatus (status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x24 + i, + dev->frontend.regs.get_value(0x24 + i)); /* MSB/LSB ? */ + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing sign%d failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + + /* gain */ + for (i = 0; i < 3; i++) + { + status = + sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing gain%d failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + } + + DBGCOMPLETED; + return status; +} + +/** Set values of analog frontend + * @param dev device to set + * @param set action to execute + * @param dpi dpi to setup the AFE + * @return error or SANE_STATUS_GOOD */ +static SANE_Status +gl646_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set, int dpi) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + uint8_t val; + + DBG(DBG_proc, "%s (%s,%d)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == + AFE_POWER_SAVE ? "powersave" : "huh?", dpi); + + /* Analog Device type frontend */ + if ((dev->reg.find_reg(0x04).value & REG04_FESET) == 0x02) + return gl646_set_ad_fe (dev, set); + + /* Wolfson type frontend */ + if ((dev->reg.find_reg(0x04).value & REG04_FESET) != 0x03) + { + DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, + dev->reg.find_reg(0x04).value & REG04_FESET); + return SANE_STATUS_UNSUPPORTED; + } + + /* per frontend function to keep code clean */ + switch (dev->model->dac_type) + { + case DAC_WOLFSON_HP3670: + case DAC_WOLFSON_HP2400: + return gl646_wm_hp3670(dev, sensor, set, dpi); + break; + default: + DBG(DBG_proc, "%s(): using old method\n", __func__); + break; + } + + /* initialize analog frontend */ + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + dev->frontend = dev->frontend_initial; + + /* reset only done on init */ + status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: init fe failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* enable GPIO for some models */ + if (dev->model->ccd_type == CCD_HP2300) + { + val = 0x07; + gl646_gpio_output_enable(dev->usb_dev, val); + } + return status; + } + + /* set fontend to power saving mode */ + if (set == AFE_POWER_SAVE) + { + status = sanei_genesys_fe_write_data (dev, 0x01, 0x02); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing data failed: %s\n", __func__, sane_strstatus(status)); + } + return status; + } + + /* here starts AFE_SET */ + /* TODO : base this test on cfg reg3 or a CCD family flag to be created */ + /* if (dev->model->ccd_type != CCD_HP2300 + && dev->model->ccd_type != CCD_HP3670 + && dev->model->ccd_type != CCD_HP2400) */ + { + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg0 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.regs.get_value(0x02)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg2 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + /* start with reg3 */ + status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x03)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg3 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + switch (dev->model->ccd_type) + { + default: + for (i = 0; i < 3; i++) + { + status = + sanei_genesys_fe_write_data(dev, 0x24 + i, + dev->frontend.regs.get_value(0x24 + i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing gain[%d] failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_fe_write_data(dev, 0x20 + i, dev->frontend.get_offset(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing offset[%d] failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + break; + /* just can't have it to work .... + case CCD_HP2300: + case CCD_HP2400: + case CCD_HP3670: + + status = + sanei_genesys_fe_write_data(dev, 0x23, dev->frontend.get_offset(1)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing offset[1] failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x28, dev->frontend.get_gain(1)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing gain[1] failed: %s\n", __func__, sane_strstatus (status)); + return status; + } + break; */ + } + + /* end with reg1 */ + status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + + DBG(DBG_proc, "%s: end\n", __func__); + + return SANE_STATUS_GOOD; +} + +/** Set values of analog frontend + * this this the public interface, the gl646 as to use one more + * parameter to work effectively, hence the redirection + * @param dev device to set + * @param set action to execute + * @return error or SANE_STATUS_GOOD */ +static SANE_Status +gl646_public_set_fe (Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) +{ + return gl646_set_fe(dev, sensor, set, dev->settings.yres); +} + +/** + * enters or leaves power saving mode + * limited to AFE for now. + * @param dev scanner's device + * @param enable SANE_TRUE to enable power saving, SANE_FALSE to leave it + * @return allways SANE_STATUS_GOOD + */ +static +SANE_Status +gl646_save_power (Genesys_Device * dev, SANE_Bool enable) +{ + + DBGSTART; + DBG(DBG_info, "%s: enable = %d\n", __func__, enable); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + if (enable) + { + /* gl646_set_fe(dev, sensor, AFE_POWER_SAVE); */ + } + else + { + gl646_set_fe(dev, sensor, AFE_INIT, 0); + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl646_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); + int rate, exposure_time, tgtime, time; + + DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); + + local_reg.init_reg(0x01, dev->reg.get8(0x01)); // disable fastmode + local_reg.init_reg(0x03, dev->reg.get8(0x03)); // Lamp power control + local_reg.init_reg(0x05, dev->reg.get8(0x05) & ~REG05_BASESEL); // 24 clocks/pixel + local_reg.init_reg(0x38, 0x00); // line period low + local_reg.init_reg(0x39, 0x00); //line period high + local_reg.init_reg(0x6c, 0x00); // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE + + if (!delay) + local_reg.find_reg(0x03).value &= 0xf0; /* disable lampdog and set lamptime = 0 */ + else if (delay < 20) + local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ + else + local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ + + time = delay * 1000 * 60; /* -> msec */ + exposure_time = + (uint32_t) (time * 32000.0 / + (24.0 * 64.0 * (local_reg.get8(0x03) & REG03_LAMPTIM) * + 1024.0) + 0.5); + /* 32000 = system clock, 24 = clocks per pixel */ + rate = (exposure_time + 65536) / 65536; + if (rate > 4) + { + rate = 8; + tgtime = 3; + } + else if (rate > 2) + { + rate = 4; + tgtime = 2; + } + else if (rate > 1) + { + rate = 2; + tgtime = 1; + } + else + { + rate = 1; + tgtime = 0; + } + + local_reg.find_reg(0x6c).value |= tgtime << 6; + exposure_time /= rate; + + if (exposure_time > 65535) + exposure_time = 65535; + + local_reg.find_reg(0x38).value = exposure_time / 256; + local_reg.find_reg(0x39).value = exposure_time & 255; + + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) { + DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: end\n", __func__); + return status; +} + + +/** + * loads document into scanner + * currently only used by XP200 + * bit2 (0x04) of gpio is paper event (document in/out) on XP200 + * HOMESNR is set if no document in front of sensor, the sequence of events is + * paper event -> document is in the sheet feeder + * HOMESNR becomes 0 -> document reach sensor + * HOMESNR becomes 1 ->document left sensor + * paper event -> document is out + */ +static SANE_Status +gl646_load_document (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + + // FIXME: sequential not really needed in this case + Genesys_Register_Set regs(Genesys_Register_Set::SEQUENTIAL); + unsigned int used, vfinal, count; + uint16_t slope_table[255]; + uint8_t val; + + DBG(DBG_proc, "%s: start\n", __func__); + + /* no need to load document is flatbed scanner */ + if (dev->model->is_sheetfed == SANE_FALSE) + { + DBG(DBG_proc, "%s: nothing to load\n", __func__); + DBG(DBG_proc, "%s: end\n", __func__); + return SANE_STATUS_GOOD; + } + + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* HOMSNR is set if a document is inserted */ + if ((val & REG41_HOMESNR)) + { + /* if no document, waits for a paper event to start loading */ + /* with a 60 seconde minutes timeout */ + count = 0; + do + { + gl646_gpio_read(dev->usb_dev, &val); + + DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, val); + if ((val & 0x04) != 0x04) + { + DBG(DBG_warn, "%s: no paper detected\n", __func__); + } + sanei_genesys_sleep_ms(200); + count++; + } + while (((val & 0x04) != 0x04) && (count < 300)); /* 1 min time out */ + if (count == 300) + { + DBG(DBG_error, "%s: timeout waiting for document\n", __func__); + return SANE_STATUS_NO_DOCS; + } + } + + /* set up to fast move before scan then move until document is detected */ + regs.init_reg(0x01, 0x90); + + /* AGOME, 2 slopes motor moving */ + regs.init_reg(0x02, 0x79); + + /* motor feeding steps to 0 */ + regs.init_reg(0x3d, 0); + regs.init_reg(0x3e, 0); + regs.init_reg(0x3f, 0); + + /* 50 fast moving steps */ + regs.init_reg(0x6b, 50); + + /* set GPO */ + regs.init_reg(0x66, 0x30); + + /* stesp NO */ + regs.init_reg(0x21, 4); + regs.init_reg(0x22, 1); + regs.init_reg(0x23, 1); + regs.init_reg(0x24, 4); + + /* generate slope table 2 */ + sanei_genesys_generate_slope_table (slope_table, + 50, + 51, + 2400, + 6000, 2400, 50, 0.25, &used, &vfinal); +/* document loading: + * send regs + * start motor + * wait e1 status to become e0 + */ + status = gl646_send_slope_table (dev, 1, slope_table, 50); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl646_start_motor (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + count = 0; + do + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_sleep_ms(200); + count++; + } + while ((val & REG41_MOTMFLG) && (count < 300)); + if (count == 300) + { + DBG(DBG_error, "%s: can't load document\n", __func__); + return SANE_STATUS_JAMMED; + } + + /* when loading OK, document is here */ + dev->document = SANE_TRUE; + + /* set up to idle */ + regs.set8(0x02, 0x71); + regs.set8(0x3f, 1); + regs.set8(0x6b, 8); + status = sanei_genesys_bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write idle registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: end\n", __func__); + + return status; +} + +/** + * detects end of document and adjust current scan + * to take it into account + * used by sheetfed scanners + */ +static SANE_Status +gl646_detect_document_end (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val, gpio; + unsigned int bytes_left, lines; + + DBG(DBG_proc, "%s: start\n", __func__); + + /* test for document presence */ + RIE (sanei_genesys_get_status (dev, &val)); + if (DBG_LEVEL > DBG_info) + { + print_status (val); + } + gl646_gpio_read(dev->usb_dev, &gpio); + DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); + + /* detect document event. There one event when the document go in, + * then another when it leaves */ + if ((dev->document == SANE_TRUE) && (gpio & 0x04) + && (dev->total_bytes_read > 0)) + { + DBG(DBG_info, "%s: no more document\n", __func__); + dev->document = SANE_FALSE; + + /* adjust number of bytes to read: + * total_bytes_to_read is the number of byte to send to frontend + * total_bytes_read is the number of bytes sent to frontend + * read_bytes_left is the number of bytes to read from the scanner + */ + DBG(DBG_io, "%s: total_bytes_to_read=%lu\n", __func__, (u_long) dev->total_bytes_to_read); + DBG(DBG_io, "%s: total_bytes_read =%lu\n", __func__, (u_long) dev->total_bytes_read); + DBG(DBG_io, "%s: read_bytes_left =%lu\n", __func__, (u_long) dev->read_bytes_left); + + /* amount of data available from scanner is what to scan */ + status = sanei_genesys_read_valid_words (dev, &bytes_left); + + /* we add the number of lines needed to read the last part of the document in */ + lines = + (SANE_UNFIX (dev->model->y_offset) * dev->current_setup.yres) / + MM_PER_INCH; + DBG(DBG_io, "%s: adding %d line to flush\n", __func__, lines); + bytes_left += lines * dev->wpl; + if (dev->current_setup.depth > 8) + { + bytes_left = 2 * bytes_left; + } + if (dev->current_setup.channels > 1) + { + bytes_left = 3 * bytes_left; + } + if (bytes_left < dev->read_bytes_left) + { + dev->total_bytes_to_read = dev->total_bytes_read + bytes_left; + dev->read_bytes_left = bytes_left; + } + DBG(DBG_io, "%s: total_bytes_to_read=%lu\n", __func__, (u_long) dev->total_bytes_to_read); + DBG(DBG_io, "%s: total_bytes_read =%lu\n", __func__, (u_long) dev->total_bytes_read); + DBG(DBG_io, "%s: read_bytes_left =%lu\n", __func__, (u_long) dev->read_bytes_left); + } + DBG(DBG_proc, "%s: end\n", __func__); + + return status; +} + +/** + * eject document from the feeder + * currently only used by XP200 + * TODO we currently rely on AGOHOME not being set for sheetfed scanners, + * maybe check this flag in eject to let the document being eject automaticaly + */ +static SANE_Status +gl646_eject_document (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set regs((Genesys_Register_Set::SEQUENTIAL)); + unsigned int used, vfinal, count; + uint16_t slope_table[255]; + uint8_t gpio, state; + + DBG(DBG_proc, "%s: start\n", __func__); + + /* at the end there will be noe more document */ + dev->document = SANE_FALSE; + + // first check for document event + gl646_gpio_read(dev->usb_dev, &gpio); + + DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); + + /* test status : paper event + HOMESNR -> no more doc ? */ + status = sanei_genesys_get_status (dev, &state); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); + return status; + } + DBG(DBG_info, "%s: state=0x%02x\n", __func__, state); + if (DBG_LEVEL > DBG_info) + { + print_status (state); + } + + /* HOMSNR=0 if no document inserted */ + if ((state & REG41_HOMESNR) != 0) + { + dev->document = SANE_FALSE; + DBG(DBG_info, "%s: no more document to eject\n", __func__); + DBG(DBG_proc, "%s: end\n", __func__); + return status; + } + + /* there is a document inserted, eject it */ + status = sanei_genesys_write_register (dev, 0x01, 0xb0); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* wait for motor to stop */ + do + { + sanei_genesys_sleep_ms(200); + status = sanei_genesys_get_status (dev, &state); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + while (state & REG41_MOTMFLG); + + /* set up to fast move before scan then move until document is detected */ + regs.init_reg(0x01, 0xb0); + + /* AGOME, 2 slopes motor moving , eject 'backward' */ + regs.init_reg(0x02, 0x5d); + + /* motor feeding steps to 119880 */ + regs.init_reg(0x3d, 1); + regs.init_reg(0x3e, 0xd4); + regs.init_reg(0x3f, 0x48); + + /* 60 fast moving steps */ + regs.init_reg(0x6b, 60); + + /* set GPO */ + regs.init_reg(0x66, 0x30); + + /* stesp NO */ + regs.init_reg(0x21, 4); + regs.init_reg(0x22, 1); + regs.init_reg(0x23, 1); + regs.init_reg(0x24, 4); + + /* generate slope table 2 */ + sanei_genesys_generate_slope_table (slope_table, + 60, + 61, + 1600, + 10000, 1600, 60, 0.25, &used, &vfinal); +/* document eject: + * send regs + * start motor + * wait c1 status to become c8 : HOMESNR and ~MOTFLAG + */ + status = gl646_send_slope_table (dev, 1, slope_table, 60); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl646_start_motor (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); + return SANE_STATUS_IO_ERROR; + } + + /* loop until paper sensor tells paper is out, and till motor is running */ + /* use a 30 timeout */ + count = 0; + do + { + status = sanei_genesys_get_status (dev, &state); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); + return status; + } + print_status (state); + sanei_genesys_sleep_ms(200); + count++; + } + while (((state & REG41_HOMESNR) == 0) && (count < 150)); + + // read GPIO on exit + gl646_gpio_read(dev->usb_dev, &gpio); + + DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); + + DBG(DBG_proc, "%s: end\n", __func__); + return status; +} + +/* Send the low-level scan command */ +static SANE_Status +gl646_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SANE_Bool start_motor) +{ + (void) sensor; + SANE_Status status = SANE_STATUS_GOOD; + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); + + DBG(DBG_proc, "%s\n", __func__); + + local_reg.init_reg(0x03, sanei_genesys_read_reg_from_set(reg, 0x03)); + local_reg.init_reg(0x01, sanei_genesys_read_reg_from_set(reg, 0x01) | REG01_SCAN); /* set scan bit */ + + if (start_motor) { + local_reg.init_reg(0x0f, 0x01); + } else { + local_reg.init_reg(0x0f, 0x00); // do not start motor yet + } + + status = sanei_genesys_bulk_write_register(dev, local_reg); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: end\n", __func__); + + return status; +} + + +/* Send the stop scan command */ +static SANE_Status +end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, + SANE_Bool check_stop, SANE_Bool eject) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i = 0; + uint8_t val, scanfsh = 0; + + DBG(DBG_proc, "%s (check_stop = %d, eject = %d)\n", __func__, check_stop, eject); + + /* we need to compute scanfsh before cancelling scan */ + if (dev->model->is_sheetfed == SANE_TRUE) + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (val & REG41_SCANFSH) + scanfsh = 1; + if (DBG_LEVEL > DBG_io2) + { + print_status (val); + } + } + + /* ends scan */ + val = sanei_genesys_read_reg_from_set (reg, 0x01); + val &= ~REG01_SCAN; + sanei_genesys_set_reg_from_set (reg, 0x01, val); + status = sanei_genesys_write_register (dev, 0x01, val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* for sheetfed scanners, we may have to eject document */ + if (dev->model->is_sheetfed == SANE_TRUE) + { + if (eject == SANE_TRUE && dev->document == SANE_TRUE) + { + status = gl646_eject_document (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to eject document\n", __func__); + return status; + } + } + if (check_stop) + { + for (i = 0; i < 30; i++) /* do not wait longer than wait 3 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read register: %s\n", __func__, + sane_strstatus(status)); + return status; + } + if (val & REG41_SCANFSH) + scanfsh = 1; + if (DBG_LEVEL > DBG_io2) + { + print_status (val); + } + + if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh) + { + DBG(DBG_proc, "%s: scanfeed finished\n", __func__); + break; /* leave for loop */ + } + + sanei_genesys_sleep_ms(100); + } + } + } + else /* flat bed scanners */ + { + if (check_stop) + { + for (i = 0; i < 300; i++) /* do not wait longer than wait 30 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read register: %s\n", __func__, + sane_strstatus(status)); + return status; + } + if (val & REG41_SCANFSH) + scanfsh = 1; + if (DBG_LEVEL > DBG_io) + { + print_status (val); + } + + if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh) + { + DBG(DBG_proc, "%s: scanfeed finished\n", __func__); + break; /* leave while loop */ + } + + if ((!(val & REG41_MOTMFLG)) && (val & REG41_HOMESNR)) + { + DBG(DBG_proc, "%s: head at home\n", __func__); + break; /* leave while loop */ + } + + sanei_genesys_sleep_ms(100); + } + } + } + + DBG(DBG_proc, "%s: end (i=%u)\n", __func__, i); + + return status; +} + +/* Send the stop scan command */ +static SANE_Status +gl646_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, + SANE_Bool check_stop) +{ + return end_scan (dev, reg, check_stop, SANE_FALSE); +} + +/** + * parks head + * @param dev scanner's device + * @param wait_until_home true if the function waits until head parked + */ +static +SANE_Status +gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Settings settings; + uint8_t val; + int i; + int loop = 0; + + DBG(DBG_proc, "%s: start , wait_until_home = %d\n", __func__, wait_until_home); + + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL > DBG_io) + { + print_status (val); + } + + dev->scanhead_position_in_steps = 0; + + if (val & REG41_HOMESNR) /* is sensor at home? */ + { + DBG(DBG_info, "%s: end since already at home\n", __func__); + return SANE_STATUS_GOOD; + } + + /* stop motor if needed */ + if (val & REG41_MOTMFLG) + { + status = gl646_stop_motor (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + sanei_genesys_sleep_ms(200); + } + + /* when scanhead is moving then wait until scanhead stops or timeout */ + DBG(DBG_info, "%s: ensuring that motor is off\n", __func__); + val = REG41_MOTMFLG; + for (i = 400; i > 0 && (val & REG41_MOTMFLG); i--) /* do not wait longer than 40 seconds, count down to get i = 0 when busy */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to read home sensor & motor status: %s\n", __func__, + sane_strstatus(status)); + return status; + } + if (((val & (REG41_MOTMFLG | REG41_HOMESNR)) == REG41_HOMESNR)) /* at home and motor is off */ + { + DBG(DBG_info, "%s: already at home and not moving\n", __func__); + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + } + + if (!i) /* the loop counted down to 0, scanner still is busy */ + { + DBG(DBG_error, "%s: motor is still on: device busy\n", __func__); + return SANE_STATUS_DEVICE_BUSY; + } + + /* setup for a backward scan of 65535 steps, with no actual data reading */ + settings.scan_method = ScanMethod::FLATBED; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = get_lowest_resolution(dev->model->ccd_type, 1); + settings.yres = settings.xres; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = 600; + settings.lines = 1; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres); + + status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_TRUE, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* backward , no actual data scanned TODO more setup flags to avoid this register manipulations ? */ + dev->reg.find_reg(0x02).value |= REG02_MTRREV; + dev->reg.find_reg(0x01).value &= ~REG01_SCAN; + sanei_genesys_set_triple(&dev->reg, REG_FEEDL, 65535); + + /* sets frontend */ + status = gl646_set_fe(dev, sensor, AFE_SET, settings.xres); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* write scan registers */ + try { + status = sanei_genesys_bulk_write_register(dev, dev->reg); + } catch (...) { + DBG(DBG_error, "%s: failed to bulk write registers\n", __func__); + } + if (status != SANE_STATUS_GOOD) + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + + /* registers are restored to an iddl state, give up if no head to park */ + if (dev->model->is_sheetfed == SANE_TRUE) + { + DBG(DBG_proc, "%s: end \n", __func__); + return SANE_STATUS_GOOD; + } + + /* starts scan */ + status = gl646_begin_scan(dev, sensor, &dev->reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: \n", __func__); + return status; + } + + /* loop until head parked */ + if (wait_until_home) + { + while (loop < 300) /* do not wait longer then 30 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to read home sensor: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + if (val & 0x08) /* home sensor */ + { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBG(DBG_proc, "%s: end\n", __func__); + sanei_genesys_sleep_ms(500); + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + ++loop; + } + + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl646_stop_motor (dev); + end_scan(dev, &dev->reg, SANE_TRUE, SANE_FALSE); + DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + + DBG(DBG_info, "%s: scanhead is still moving\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** + * Automatically set top-left edge of the scan area by scanning an + * area at 300 dpi from very top of scanner + * @param dev device stucture describing the scanner + * @return SANE_STATUS_GOOD in cas of success, else failure code + */ +static SANE_Status +gl646_search_start_position (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Settings settings; + unsigned int resolution, x, y; + + DBG(DBG_proc, "%s: start\n", __func__); + + /* we scan at 300 dpi */ + resolution = get_closest_resolution(dev->model->ccd_type, 300, 1); + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + auto& sensor = sanei_genesys_find_sensor_for_write(dev, resolution); + + /* fill settings for a gray level scan */ + settings.scan_method = ScanMethod::FLATBED; + settings.scan_mode = ScanColorMode::GRAY; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = 600; + settings.lines = dev->model->search_lines; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + /* scan the desired area */ + std::vector data; + status = simple_scan(dev, sensor, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, data); + + /* process data if scan is OK */ + if (status != SANE_STATUS_GOOD) { + DBG(DBG_error, "%s: simple_scan failed\n", __func__); + DBGCOMPLETED; + return status; + } + + + /* handle stagger case : reorder gray data and thus loose some lines */ + if (dev->current_setup.stagger > 0) + { + DBG(DBG_proc, "%s: 'un-staggering'\n", __func__); + for (y = 0; y < settings.lines - dev->current_setup.stagger; y++) + { + /* one point out of 2 is 'unaligned' */ + for (x = 0; x < settings.pixels; x += 2) + { + data[y * settings.pixels + x] = + data[(y + dev->current_setup.stagger) * settings.pixels + + x]; + } + } + /* correct line number */ + settings.lines -= dev->current_setup.stagger; + } + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_pnm_file("gl646_search_position.pnm", data.data(), settings.depth, 1, + settings.pixels, settings.lines); + } + + /* now search reference points on the data */ + status = + sanei_genesys_search_reference_point (dev, sensor, data.data(), + sensor.CCD_start_xoffset, + resolution, settings.pixels, + settings.lines); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, + sane_strstatus(status)); + } + + DBGCOMPLETED; + return status; +} + +/** + * internally overriden during effective calibration + * sets up register for coarse gain calibration + */ +static SANE_Status +gl646_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + (void) sensor; + (void) regs; + + DBG(DBG_proc, "%s\n", __func__); + DBG(DBG_proc, "%s: end\n", __func__); + + /* to make compilers happy ... */ + if (!dev) + { + return SANE_STATUS_INVAL; + } + + return SANE_STATUS_GOOD; +} + + +/** + * init registers for shading calibration + * we assume that scanner's head is on an area suiting shading calibration. + * We scan a full scan width area by the shading line number for the device + * at either at full sensor's resolution or half depending upon half_ccd + * @param dev scanner's device + * @return SANE_STATUS_GOOD if success, else error code + */ +static SANE_Status +gl646_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + (void) regs; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Settings settings; + /* 1: no half_ccd, 2: use half number of pixels */ + int half_ccd = 1; + int cksel = 1; + + DBG(DBG_proc, "%s: start\n", __func__); + + /* fill settings for scan : always a color scan */ + int channels = 3; + + if (sensor.ccd_size_divisor > 1) + { + // when shading all (full width) line, we must adapt to half_ccd case + if (is_half_ccd(dev->model->ccd_type, dev->settings.xres, channels) == SANE_TRUE) + { + half_ccd = 2; + } + } + + settings.scan_method = dev->settings.scan_method; + settings.scan_mode = dev->settings.scan_mode; + if (dev->model->is_cis == SANE_FALSE) + { + // FIXME: always a color scan, but why don't we set scan_mode to COLOR_SINGLE_PASS always? + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + } + settings.xres = sensor.optical_res / half_ccd; + cksel = get_cksel(dev->model->ccd_type, dev->settings.xres, channels); + settings.xres = settings.xres / cksel; + settings.yres = settings.xres; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = + (sensor.sensor_pixels * settings.xres) / sensor.optical_res; + dev->calib_lines = dev->model->shading_lines; + settings.lines = dev->calib_lines * (3 - half_ccd); + settings.depth = 16; + settings.color_filter = dev->settings.color_filter; + + settings.disable_interpolation = dev->settings.disable_interpolation; + settings.threshold = dev->settings.threshold; + settings.dynamic_lineart = SANE_FALSE; + + /* keep account of the movement for final scan move */ + dev->scanhead_position_in_steps += settings.lines; + + /* we don't want top offset, but we need right margin to be the same + * than the one for the final scan */ + status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE); + + /* used when sending shading calibration data */ + dev->calib_pixels = settings.pixels; + dev->calib_channels = dev->current_setup.channels; + if (dev->model->is_cis == SANE_FALSE) + { + dev->calib_channels = 3; + } + + /* no shading */ + dev->reg.find_reg(0x01).value &= ~REG01_DVDSET; + dev->reg.find_reg(0x02).value |= REG02_ACDCDIS; /* ease backtracking */ + dev->reg.find_reg(0x02).value &= ~(REG02_FASTFED | REG02_AGOHOME); + dev->reg.find_reg(0x05).value &= ~REG05_GMMENB; + sanei_genesys_set_motor_power(dev->reg, false); + + /* TODO another flag to setup regs ? */ + /* enforce needed LINCNT, getting rid of extra lines for color reordering */ + if (dev->model->is_cis == SANE_FALSE) + { + sanei_genesys_set_triple(&dev->reg, REG_LINCNT, dev->calib_lines); + } + else + { + sanei_genesys_set_triple(&dev->reg, REG_LINCNT, dev->calib_lines * 3); + } + + /* copy reg to calib_reg */ + dev->calib_reg = dev->reg; + + /* this is an hack to make calibration cache working .... */ + /* if we don't do this, cache will be identified at the shading calibration + * dpi which is different from calibration one */ + dev->current_setup.xres = dev->settings.xres; + DBG(DBG_info, "%s:\n\tdev->settings.xres=%d\n\tdev->settings.yres=%d\n", __func__, + dev->settings.xres, dev->settings.yres); + + DBG(DBG_proc, "%s: end\n", __func__); + return status; +} + +static bool gl646_needs_home_before_init_regs_for_scan(Genesys_Device* dev) +{ + return (dev->scanhead_position_in_steps > 0 && + dev->settings.scan_method == ScanMethod::FLATBED); +} + +/** + * set up registers for the actual scan. The scan's parameters are given + * through the device settings. It allocates the scan buffers. + */ +static SANE_Status +gl646_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + RIE(setup_for_scan(dev, sensor, &dev->reg, dev->settings, SANE_FALSE, SANE_TRUE, SANE_TRUE)); + + /* gamma is only enabled at final scan time */ + if (dev->settings.depth < 16) + dev->reg.find_reg(0x05).value |= REG05_GMMENB; + + DBGCOMPLETED; + return status; +} + +/** + * set up registers for the actual scan. The scan's parameters are given + * through the device settings. It allocates the scan buffers. + * @param dev scanner's device + * @param regs registers to set up + * @param settings settings of scan + * @param split SANE_TRUE if move to scan area is split from scan, SANE_FALSE is + * scan first moves to area + * @param xcorrection take x geometry correction into account (fixed and detected offsets) + * @param ycorrection take y geometry correction into account + */ +static SANE_Status +setup_for_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set *regs, + Genesys_Settings settings, + SANE_Bool split, + SANE_Bool xcorrection, + SANE_Bool ycorrection) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Int depth; + int channels; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + if (settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + channels = 3; + } + else + { + channels = 1; + } + + depth=settings.depth; + if (settings.scan_mode == ScanColorMode::LINEART) + { + if (settings.dynamic_lineart == SANE_TRUE) + { + depth = 8; + } + else + { + /* XXX STEF XXX : why does the common layer never send depth=1 ? */ + depth = 1; + } + } + + // compute distance to move + float move = 0; + // XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */ + if (split == SANE_FALSE) { + if (dev->model->is_sheetfed == SANE_FALSE) { + if (ycorrection == SANE_TRUE) { + move = SANE_UNFIX(dev->model->y_offset); + } + + // add tl_y to base movement + } + move += settings.tl_y; + + if (move < 0) { + DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move); + move = 0; + } + } + move = (move * dev->motor.optical_ydpi) / MM_PER_INCH; + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + float start = settings.tl_x; + if (xcorrection) { + if (settings.scan_method == ScanMethod::FLATBED) { + start += SANE_UNFIX(dev->model->x_offset); + } else { + start += SANE_UNFIX(dev->model->x_offset_ta); + } + } + start = (start * sensor.optical_res) / MM_PER_INCH; + + SetupParams params; + params.xres = settings.xres; + params.yres = settings.yres; + params.startx = start; + params.starty = move; + params.pixels = settings.pixels; + params.lines = settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = settings.scan_mode; + params.color_filter = settings.color_filter; + params.flags = 0; + if (settings.scan_method == ScanMethod::TRANSPARENCY) { + params.flags |= SCAN_FLAG_USE_XPA; + } + + uint16_t slope_table0[256] = {}; + uint16_t slope_table1[256] = {}; + + /* set up correct values for scan (gamma and shading enabled) */ + status = gl646_setup_registers(dev, sensor, regs, params, slope_table0, slope_table1, + xcorrection); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed setup registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* send computed slope tables */ + status = + gl646_send_slope_table (dev, 0, slope_table0, + sanei_genesys_read_reg_from_set (regs, 0x21)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send slope table 0: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = + gl646_send_slope_table (dev, 1, slope_table1, + sanei_genesys_read_reg_from_set (regs, 0x6b)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return status; +} + +/** + * this function sen gamm table to ASIC + */ +static SANE_Status +gl646_send_gamma_table (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int size; + int address; + SANE_Status status = SANE_STATUS_GOOD; + int bits; + + DBGSTART; + + /* gamma table size */ + if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) + { + size = 16384; + bits = 14; + } + else + { + size = 4096; + bits = 12; + } + + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3); + + RIE(sanei_genesys_generate_gamma_buffer(dev, sensor, bits, size-1, size, gamma.data())); + + /* table address */ + switch (dev->reg.find_reg(0x05).value >> 6) + { + case 0: /* 600 dpi */ + address = 0x09000; + break; + case 1: /* 1200 dpi */ + address = 0x11000; + break; + case 2: /* 2400 dpi */ + address = 0x20000; + break; + default: + return SANE_STATUS_INVAL; + } + + /* send address */ + status = sanei_genesys_set_buffer_address (dev, address); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* send data */ + status = sanei_genesys_bulk_write_data(dev, 0x3c, gamma.data(), size * 2 * 3); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send gamma table: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief this function does the led calibration. + * this function does the led calibration by scanning one line of the calibration + * area below scanner's top on white strip. The scope of this function is + * currently limited to the XP200 + */ +static SANE_Status +gl646_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs) +{ + (void) regs; + int total_size; + unsigned int i, j; + SANE_Status status = SANE_STATUS_GOOD; + int val; + unsigned int channels; + int avg[3], avga, avge; + int turn; + uint16_t expr, expg, expb; + Genesys_Settings settings; + SANE_Int resolution; + + SANE_Bool acceptable = SANE_FALSE; + + DBG(DBG_proc, "%s\n", __func__); + if (!dev->model->is_cis) + { + DBG(DBG_proc, "%s: not a cis scanner, nothing to do...\n", __func__); + return SANE_STATUS_GOOD; + } + + /* get led calibration resolution */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + channels = 3; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + } + else + { + channels = 1; + settings.scan_mode = ScanColorMode::GRAY; + } + resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels); + + /* offset calibration is always done in color mode */ + settings.scan_method = ScanMethod::FLATBED; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = + (sensor.sensor_pixels * resolution) / sensor.optical_res; + settings.lines = 1; + settings.depth = 16; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + /* colors * bytes_per_color * scan lines */ + total_size = settings.pixels * channels * 2 * 1; + + std::vector line(total_size); + +/* + we try to get equal bright leds here: + + loop: + average per color + adjust exposure times + + Sensor_Master uint8_t regs_0x10_0x15[6]; + */ + expr = sensor.exposure.red; + expg = sensor.exposure.green; + expb = sensor.exposure.blue; + + turn = 0; + + do + { + sensor.exposure.red = expr; + sensor.exposure.green = expg; + sensor.exposure.blue = expb; + + DBG(DBG_info, "%s: starting first line reading\n", __func__); + + status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl646_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, settings.pixels, 1); + } + + acceptable = SANE_TRUE; + + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < settings.pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * settings.pixels + 1] * 256 + + line[i * 2 + j * 2 * settings.pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= settings.pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + acceptable = SANE_TRUE; + + if (!acceptable) + { + avga = (avg[0] + avg[1] + avg[2]) / 3; + expr = (expr * avga) / avg[0]; + expg = (expg * avga) / avg[1]; + expb = (expb * avga) / avg[2]; + + /* keep exposure time in a working window */ + avge = (expr + expg + expb) / 3; + if (avge > 0x2000) + { + expr = (expr * 0x2000) / avge; + expg = (expg * 0x2000) / avge; + expb = (expb * 0x2000) / avge; + } + if (avge < 0x400) + { + expr = (expr * 0x400) / avge; + expg = (expg * 0x400) / avge; + expb = (expb * 0x400) / avge; + } + } + + turn++; + + } + while (!acceptable && turn < 100); + + DBG(DBG_info,"%s: acceptable exposure: 0x%04x,0x%04x,0x%04x\n", __func__, expr, expg, expb); + + DBGCOMPLETED; + return status; +} + +/** + * average dark pixels of a scan + */ +static int +dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black) +{ + unsigned int i, j, k, average, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average value on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + for (i = 0; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + average = 0; + for (i = 0; i < channels; i++) + average += avg[i]; + average /= channels; + DBG(DBG_info, "%s: average = %d\n", __func__, average); + return average; +} + + +/** @brief calibration for AD frontend devices + * we do simple scan until all black_pixels are higher than 0, + * raising offset at each turn. + */ +static SANE_Status +ad_fe_offset_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + SANE_Status status = SANE_STATUS_GOOD; + unsigned int channels; + int pass = 0; + SANE_Int resolution; + Genesys_Settings settings; + unsigned int x, y, adr, min; + unsigned int bottom, black_pixels; + + DBG(DBG_proc, "%s: start\n", __func__); + channels = 3; + resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels); + black_pixels = + (sensor.black_pixels * resolution) / sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + settings.scan_method = ScanMethod::FLATBED; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = + (sensor.sensor_pixels * resolution) / sensor.optical_res; + settings.lines = CALIBRATION_LINES; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + /* scan first line of data with no gain */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + std::vector line; + + /* scan with no move */ + bottom = 1; + do + { + pass++; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + status = + simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to scan first line\n", __func__); + return status; + } + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + snprintf(title, 30, "gl646_offset%03d.pnm", (int)bottom); + sanei_genesys_write_pnm_file (title, line.data(), 8, channels, + settings.pixels, settings.lines); + } + + min = 0; + for (y = 0; y < settings.lines; y++) + { + for (x = 0; x < black_pixels; x++) + { + adr = (x + y * settings.pixels) * channels; + if (line[adr] > min) + min = line[adr]; + if (line[adr + 1] > min) + min = line[adr + 1]; + if (line[adr + 2] > min) + min = line[adr + 2]; + } + } + + DBG(DBG_io2, "%s: pass=%d, min=%d\n", __func__, pass, min); + bottom++; + } + while (pass < 128 && min == 0); + if (pass == 128) + { + DBG(DBG_error, "%s: failed to find correct offset\n", __func__); + return SANE_STATUS_INVAL; + } + + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + DBG(DBG_proc, "%s: end\n", __func__); + return status; +} + +#define DARK_TARGET 8 +/** + * This function does the offset calibration by scanning one line of the calibration + * area below scanner's top. There is a black margin and the remaining is white. + * genesys_search_start() must have been called so that the offsets and margins + * are already known. + * @param dev scanner's device + * @return SANE_STATUS_GOOD if success, else error code is failure +*/ +static SANE_Status +gl646_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + (void) regs; + SANE_Status status = SANE_STATUS_GOOD; + unsigned int channels; + int pass = 0, avg; + SANE_Int resolution; + Genesys_Settings settings; + int topavg, bottomavg; + int top, bottom, black_pixels; + + /* Analog Device fronted have a different calibration */ + if (dev->model->dac_type == DAC_AD_XP200) + { + return ad_fe_offset_calibration (dev, sensor); + } + + DBG(DBG_proc, "%s: start\n", __func__); + + /* setup for a RGB scan, one full sensor's width line */ + /* resolution is the one from the final scan */ + channels = 3; + if (dev->settings.xres > sensor.optical_res) { + resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels); + } else { + resolution = get_closest_resolution(dev->model->ccd_type, dev->settings.xres, channels); + } + black_pixels = + (sensor.black_pixels * resolution) / sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + settings.scan_method = ScanMethod::FLATBED; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = + (sensor.sensor_pixels * resolution) / sensor.optical_res; + settings.lines = CALIBRATION_LINES; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + /* scan first line of data with no gain, but with offset from + * last calibration */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* scan with no move */ + bottom = 90; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + + std::vector first_line, second_line; + + status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, first_line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to scan first line\n", __func__); + return status; + } + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + snprintf(title, 30, "gl646_offset%03d.pnm", bottom); + sanei_genesys_write_pnm_file(title, first_line.data(), 8, channels, + settings.pixels, settings.lines); + } + bottomavg = dark_average(first_line.data(), settings.pixels, settings.lines, channels, + black_pixels); + DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); + + /* now top value */ + top = 231; + dev->frontend.set_offset(0, top); + dev->frontend.set_offset(1, top); + dev->frontend.set_offset(2, top); + status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to scan first line\n", __func__); + return status; + } + + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + snprintf(title, 30, "gl646_offset%03d.pnm", top); + sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels, + settings.pixels, settings.lines); + } + topavg = dark_average(second_line.data(), settings.pixels, settings.lines, channels, + black_pixels); + DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); + + /* loop until acceptable level */ + while ((pass < 32) && (top - bottom > 1)) + { + pass++; + + /* settings for new scan */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + /* scan with no move */ + status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to scan first line\n", __func__); + return status; + } + + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + snprintf(title, 30, "gl646_offset%03d.pnm", dev->frontend.get_offset(1)); + sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels, + settings.pixels, settings.lines); + } + + avg = + dark_average (second_line.data(), settings.pixels, settings.lines, channels, + black_pixels); + DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); + + /* compute new boundaries */ + if (topavg == avg) + { + topavg = avg; + top = dev->frontend.get_offset(1); + } + else + { + bottomavg = avg; + bottom = dev->frontend.get_offset(1); + } + } + + /* in case of debug do a final scan to get result */ + if (DBG_LEVEL >= DBG_data) + { + status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to scan final line\n", __func__); + return status; + } + sanei_genesys_write_pnm_file("gl646_offset-final.pnm", second_line.data(), 8, channels, + settings.pixels, settings.lines); + } + + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + DBG(DBG_proc, "%s: end\n", __func__); + return status; +} + +/** @brief gain calibration for Analog Device frontends + * Alternative coarse gain calibration + */ +static SANE_Status +ad_fe_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) +{ + (void) regs; + unsigned int i, channels, val; + unsigned int size, count, resolution, pass; + SANE_Status status = SANE_STATUS_GOOD; + float average; + Genesys_Settings settings; + char title[32]; + + DBGSTART; + + /* setup for a RGB scan, one full sensor's width line */ + /* resolution is the one from the final scan */ + channels = 3; + resolution = get_closest_resolution(dev->model->ccd_type, dpi, channels); + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + + settings.scan_method = ScanMethod::FLATBED; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = + (sensor.sensor_pixels * resolution) / sensor.optical_res; + settings.lines = CALIBRATION_LINES; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + size = channels * settings.pixels * settings.lines; + + /* start gain value */ + dev->frontend.set_gain(0, 1); + dev->frontend.set_gain(1, 1); + dev->frontend.set_gain(2, 1); + + average = 0; + pass = 0; + + std::vector line; + + /* loop until each channel raises to acceptable level */ + while ((average < sensor.gain_white_ref) && (pass < 30)) + { + /* scan with no move */ + status = + simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to scan first line\n", __func__); + return status; + } + + /* log scanning data */ + if (DBG_LEVEL >= DBG_data) + { + sprintf (title, "gl646_alternative_gain%02d.pnm", (int)pass); + sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels, + settings.lines); + } + pass++; + + /* computes white average */ + average = 0; + count = 0; + for (i = 0; i < size; i++) + { + val = line[i]; + average += val; + count++; + } + average = average / count; + + uint8_t gain0 = dev->frontend.get_gain(0); + // adjusts gain for the channel + if (average < sensor.gain_white_ref) { + gain0 += 1; + } + + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + + DBG(DBG_proc, "%s: average = %.2f, gain = %d\n", __func__, average, gain0); + } + + DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2)); + DBGCOMPLETED; + return status; +} + +/** + * Alternative coarse gain calibration + * this on uses the settings from offset_calibration. First scan moves so + * we can go to calibration area for XPA. + * @param dev device for scan + * @param dpi resolutnio to calibrate at + */ +static SANE_Status +gl646_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) +{ + unsigned int i, j, k, channels, val, maximum, idx; + unsigned int count, resolution, pass; + SANE_Status status = SANE_STATUS_GOOD; + float average[3]; + Genesys_Settings settings; + char title[32]; + + if (dev->model->ccd_type == CIS_XP200) + { + return ad_fe_coarse_gain_calibration (dev, sensor, regs, sensor.optical_res); + } + DBGSTART; + + /* setup for a RGB scan, one full sensor's width line */ + /* resolution is the one from the final scan */ + channels = 3; + + /* we are searching a sensor resolution */ + if (dpi > sensor.optical_res) { + resolution = sensor.optical_res; + } else { + resolution = get_closest_resolution(dev->model->ccd_type, dev->settings.xres, channels); + } + + settings.scan_method = dev->settings.scan_method; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_y = 0; + if (settings.scan_method == ScanMethod::FLATBED) + { + settings.tl_x = 0; + settings.pixels = (sensor.sensor_pixels * resolution) / sensor.optical_res; + } + else + { + settings.tl_x = SANE_UNFIX (dev->model->x_offset_ta); + settings.pixels = (SANE_UNFIX (dev->model->x_size_ta) * resolution) / MM_PER_INCH; + } + settings.lines = CALIBRATION_LINES; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + /* start gain value */ + dev->frontend.set_gain(0, 1); + dev->frontend.set_gain(1, 1); + dev->frontend.set_gain(2, 1); + + if (channels > 1) + { + average[0] = 0; + average[1] = 0; + average[2] = 0; + idx = 0; + } + else + { + average[0] = 255; + average[1] = 255; + average[2] = 255; + switch (dev->settings.color_filter) { + case ColorFilter::RED: idx = 0; break; + case ColorFilter::GREEN: idx = 1; break; + case ColorFilter::BLUE: idx = 2; break; + default: idx = 0; break; // should not happen + } + average[idx] = 0; + } + pass = 0; + + std::vector line; + + /* loop until each channel raises to acceptable level */ + while (((average[0] < sensor.gain_white_ref) + || (average[1] < sensor.gain_white_ref) + || (average[2] < sensor.gain_white_ref)) && (pass < 30)) + { + /* scan with no move */ + status = + simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to scan first line\n", __func__); + return status; + } + + /* log scanning data */ + if (DBG_LEVEL >= DBG_data) + { + sprintf (title, "gl646_gain%02d.pnm", (int)pass); + sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels, + settings.lines); + } + pass++; + + /* average high level for each channel and compute gain + to reach the target code + we only use the central half of the CCD data */ + for (k = idx; k < idx + channels; k++) + { + /* we find the maximum white value, so we can deduce a threshold + to average white values */ + maximum = 0; + for (i = 0; i < settings.lines; i++) + { + for (j = 0; j < settings.pixels; j++) + { + val = line[i * channels * settings.pixels + j + k]; + if (val > maximum) + maximum = val; + } + } + + /* threshold */ + maximum *= 0.9; + + /* computes white average */ + average[k] = 0; + count = 0; + for (i = 0; i < settings.lines; i++) + { + for (j = 0; j < settings.pixels; j++) + { + /* averaging only white points allow us not to care about dark margins */ + val = line[i * channels * settings.pixels + j + k]; + if (val > maximum) + { + average[k] += val; + count++; + } + } + } + average[k] = average[k] / count; + + /* adjusts gain for the channel */ + if (average[k] < sensor.gain_white_ref) + dev->frontend.set_gain(k, dev->frontend.get_gain(k) + 1); + + DBG(DBG_proc, "%s: channel %d, average = %.2f, gain = %d\n", __func__, k, average[k], + dev->frontend.get_gain(k)); + } + } + + if (channels < 3) { + dev->frontend.set_gain(1, dev->frontend.get_gain(0)); + dev->frontend.set_gain(2, dev->frontend.get_gain(0)); + } + + DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2)); + DBGCOMPLETED; + return status; +} + +/** + * sets up the scanner's register for warming up. We scan 2 lines without moving. + * + */ +static SANE_Status +gl646_init_regs_for_warmup (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * local_reg, + int *channels, int *total_size) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Settings settings; + int resolution, lines; + + DBG(DBG_proc, "%s: start\n", __func__); + + dev->frontend = dev->frontend_initial; + + resolution = get_closest_resolution(dev->model->ccd_type, 300, 1); + + /* set up for a half width 2 lines gray scan without moving */ + settings.scan_method = ScanMethod::FLATBED; + settings.scan_mode = ScanColorMode::GRAY; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = + (sensor.sensor_pixels * resolution) / sensor.optical_res; + settings.lines = 2; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + /* setup for scan */ + status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: setup_for_scan failed (%s)\n", __func__, sane_strstatus(status)); + return status; + } + + /* we are not going to move, so clear these bits */ + dev->reg.find_reg(0x02).value &= ~(REG02_FASTFED | REG02_AGOHOME); + + /* don't enable any correction for this scan */ + dev->reg.find_reg(0x01).value &= ~REG01_DVDSET; + + /* copy to local_reg */ + *local_reg = dev->reg; + + /* turn off motor during this scan */ + sanei_genesys_set_motor_power(*local_reg, false); + + /* returned value to higher level warmup function */ + *channels = 1; + uint32_t value = 0; + sanei_genesys_get_triple(local_reg, REG_LINCNT, &value); + lines = value + 1; + *total_size = lines * settings.pixels; + + /* now registers are ok, write them to scanner */ + RIE (gl646_set_fe(dev, sensor, AFE_SET, settings.xres)); + RIE(sanei_genesys_bulk_write_register(dev, *local_reg)); + + DBGCOMPLETED; + return status; +} + + +/* + * this function moves head without scanning, forward, then backward + * so that the head goes to park position. + * as a by-product, also check for lock + */ +static SANE_Status +gl646_repark_head (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Settings settings; + unsigned int expected, steps; + + DBG(DBG_proc, "%s: start\n", __func__); + + settings.scan_method = ScanMethod::FLATBED; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = get_closest_resolution(dev->model->ccd_type, 75, 1); + settings.yres = settings.xres; + settings.tl_x = 0; + settings.tl_y = 5; + settings.pixels = 600; + settings.lines = 4; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres); + + status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_FALSE, SANE_FALSE, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* TODO seems wrong ... no effective scan */ + dev->reg.find_reg(0x01).value &= ~REG01_SCAN; + + status = sanei_genesys_bulk_write_register(dev, dev->reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* start scan */ + status = gl646_begin_scan(dev, sensor, &dev->reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: \n", __func__); + return status; + } + + uint32_t value32 = 0; + sanei_genesys_get_triple(&dev->reg, REG_FEEDL, &value32); + expected = value32; + do + { + sanei_genesys_sleep_ms(100); + status = sanei_genesys_read_feed_steps (dev, &steps); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read feed steps: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + while (steps < expected); + + /* toggle motor flag, put an huge step number and redo move backward */ + status = gl646_slow_back_home (dev, 1); + DBG(DBG_proc, "%s: end\n", __func__); + return status; +} + +/* * + * initialize ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + * @param dev device description of the scanner to initailize + * @return SANE_STATUS_GOOD if success, error code if failure + */ +static SANE_Status +gl646_init (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + struct timeval tv; + uint8_t cold = 0, val = 0; + uint32_t addr = 0xdead; + size_t len; + + DBG_INIT (); + DBG(DBG_proc, "%s: start\n", __func__); + + /* to detect real power up condition, we write to REG41 + * with pwrbit set, then read it back. When scanner is cold (just replugged) + * PWRBIT will be set in the returned value + */ + RIE (sanei_genesys_get_status (dev, &cold)); + DBG(DBG_info, "%s: status=0x%02x\n", __func__, cold); + cold = !(cold & REG41_PWRBIT); + if (cold) + { + DBG(DBG_info, "%s: device is cold\n", __func__); + } + else + { + DBG(DBG_info, "%s: device is hot\n", __func__); + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + /* if scanning session hasn't been initialized, set it up */ + if (!dev->already_initialized) + { + dev->dark_average_data.clear(); + dev->white_average_data.clear(); + + dev->settings.color_filter = ColorFilter::GREEN; + gettimeofday (&tv, NULL); + dev->init_date = tv.tv_sec; + + /* Set default values for registers */ + gl646_init_regs (dev); + + /* Init shading data */ + RIE (sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels)); + + /* initial calibration reg values */ + dev->calib_reg = dev->reg; + } + + /* execute physical unit init only if cold */ + if (cold) + { + DBG(DBG_info, "%s: device is cold\n", __func__); + + val = 0x04; + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_INIT, INDEX, 1, &val); + + /* ASIC reset */ + RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); + sanei_genesys_sleep_ms(100); + + /* Write initial registers */ + RIE(sanei_genesys_bulk_write_register(dev, dev->reg)); + + /* Test ASIC and RAM */ + if (!(dev->model->flags & GENESYS_FLAG_LAZY_INIT)) + { + RIE (gl646_asic_test (dev)); + } + + /* send gamma tables if needed */ + status = gl646_send_gamma_table(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send generic gamma tables: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* Set powersaving (default = 15 minutes) */ + RIE (gl646_set_powersaving (dev, 15)); + } /* end if cold */ + + /* Set analog frontend */ + RIE (gl646_set_fe(dev, sensor, AFE_INIT, 0)); + + /* GPO enabling for XP200 */ + if (dev->model->ccd_type == CIS_XP200) + { + sanei_genesys_write_register (dev, 0x68, dev->gpo.enable[0]); + sanei_genesys_write_register (dev, 0x69, dev->gpo.enable[1]); + + // enable GPIO + gl646_gpio_output_enable(dev->usb_dev, 6); + + // writes 0 to GPIO + gl646_gpio_write(dev->usb_dev, 0); + + // clear GPIO enable + gl646_gpio_output_enable(dev->usb_dev, 0); + + sanei_genesys_write_register (dev, 0x66, 0x10); + sanei_genesys_write_register (dev, 0x66, 0x00); + sanei_genesys_write_register (dev, 0x66, 0x10); + } + + /* MD6471/G2410 and XP200 read/write data from an undocumented memory area which + * is after the second slope table */ + if (dev->model->gpo_type != GPO_HP3670 + && dev->model->gpo_type != GPO_HP2400) + { + switch (sensor.optical_res) + { + case 600: + addr = 0x08200; + break; + case 1200: + addr = 0x10200; + break; + case 2400: + addr = 0x1fa00; + break; + } + status = sanei_genesys_set_buffer_address (dev, addr); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up control address\n", __func__); + return SANE_STATUS_INVAL; + } + sanei_usb_set_timeout (2 * 1000); + len = 6; + status = gl646_bulk_read_data (dev, 0x45, dev->control, len); + /* for some reason, read fails here for MD6471, HP2300 and XP200 + * one time out of 2 scanimage launches + */ + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_warn, "%s: failed to read control\n", __func__); + status = gl646_bulk_read_data (dev, 0x45, dev->control, len); + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_warn, "%s: failed to read control\n", __func__); + return SANE_STATUS_INVAL; + } + else + { + DBG(DBG_info, "%s: control read=0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, + dev->control[0], dev->control[1], dev->control[2], dev->control[3], dev->control[4], + dev->control[5]); + } + sanei_usb_set_timeout (30 * 1000); + } + else + /* HP2400 and HP3670 case */ + { + dev->control[0] = 0x00; + dev->control[1] = 0x00; + dev->control[2] = 0x01; + dev->control[3] = 0x00; + dev->control[4] = 0x00; + dev->control[5] = 0x00; + } + + /* ensure head is correctly parked, and check lock */ + if (dev->model->is_sheetfed == SANE_FALSE) + { + if (dev->model->flags & GENESYS_FLAG_REPARK) + { + status = gl646_repark_head (dev); + if (status != SANE_STATUS_GOOD) + { + if (status == SANE_STATUS_INVAL) + { + DBG(DBG_error0, "Your scanner is locked. Please move the lock switch to the " + "unlocked position\n"); + return SANE_STATUS_JAMMED; + } + else + DBG(DBG_error, "%s: gl646_repark_head failed: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + else + { + RIE (gl646_slow_back_home (dev, SANE_TRUE)); + } + } + + /* here session and device are initialized */ + dev->already_initialized = SANE_TRUE; + + DBG(DBG_proc, "%s: end\n", __func__); + return SANE_STATUS_GOOD; +} + +static +SANE_Status +gl646_move_to_ta (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + if (simple_move (dev, SANE_UNFIX (dev->model->y_offset_calib_ta)) != + SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to move to calibration area\n", __func__); + return status; + } + DBGCOMPLETED; + return status; +} + + +/** + * Does a simple scan: ie no line reordering and avanced data buffering and + * shading correction. Memory for data is allocated in this function + * and must be freed by caller. + * @param dev device of the scanner + * @param settings parameters of the scan + * @param move SANE_TRUE if moving during scan + * @param forward SANE_TRUE if moving forward during scan + * @param shading SANE_TRUE to enable shading correction + * @param data pointer for the data + */ +static SANE_Status +simple_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Settings settings, SANE_Bool move, + SANE_Bool forward, SANE_Bool shading, std::vector& data) +{ + SANE_Status status = SANE_STATUS_INVAL; + unsigned int size, lines, x, y, bpp; + SANE_Bool empty, split; + int count; + uint8_t val; + + DBG(DBG_proc, "%s: starting\n", __func__); + DBG(DBG_io, "%s: move=%d, forward=%d, shading=%d\n", __func__, move, forward, shading); + + /* round up to multiple of 3 in case of CIS scanner */ + if (dev->model->is_cis == SANE_TRUE) + { + settings.lines = ((settings.lines + 2) / 3) * 3; + } + + /* setup for move then scan */ + if (move == SANE_TRUE && settings.tl_y > 0) + { + split = SANE_FALSE; + } + else + { + split = SANE_TRUE; + } + status = setup_for_scan(dev, sensor, &dev->reg, settings, split, SANE_FALSE, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: setup_for_scan failed (%s)\n", __func__, sane_strstatus(status)); + return status; + } + + /* allocate memory fo scan : LINCNT may have been adjusted for CCD reordering */ + if (dev->model->is_cis == SANE_TRUE) + { + uint32_t value = 0; + sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &value); + lines = value / 3; + } + else + { + uint32_t value = 0; + sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &value); + lines = value + 1; + } + size = lines * settings.pixels; + if (settings.depth == 16) + bpp = 2; + else + bpp = 1; + size *= bpp; + if (settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + size *= 3; + data.clear(); + data.resize(size); + + DBG(DBG_io, "%s: allocated %d bytes of memory for %d lines\n", __func__, size, lines); + + /* put back real line number in settings */ + settings.lines = lines; + + /* initialize frontend */ + status = gl646_set_fe(dev, sensor, AFE_SET, settings.xres); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* no shading correction and not watch dog for simple scan */ + dev->reg.find_reg(0x01).value &= ~(REG01_DVDSET | REG01_DOGENB); + if (shading == SANE_TRUE) + { + dev->reg.find_reg(0x01).value |= REG01_DVDSET; + } + + /* enable gamma table for the scan */ + dev->reg.find_reg(0x05).value |= REG05_GMMENB; + + /* one table movement for simple scan */ + dev->reg.find_reg(0x02).value &= ~REG02_FASTFED; + + if (move == SANE_FALSE) + { + sanei_genesys_set_motor_power(dev->reg, false); + + /* no automatic go home if no movement */ + dev->reg.find_reg(0x02).value &= ~REG02_AGOHOME; + } + if (forward == SANE_FALSE) + { + dev->reg.find_reg(0x02).value |= REG02_MTRREV; + } + else + { + dev->reg.find_reg(0x02).value &= ~REG02_MTRREV; + } + + /* no automatic go home when using XPA */ + if (settings.scan_method == ScanMethod::TRANSPARENCY) + { + dev->reg.find_reg(0x02).value &= ~REG02_AGOHOME; + } + + /* write scan registers */ + status = sanei_genesys_bulk_write_register(dev, dev->reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* starts scan */ + status = gl646_begin_scan(dev, sensor, &dev->reg, move); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: \n", __func__); + return status; + } + + /* wait for buffers to be filled */ + count = 0; + do + { + sanei_genesys_sleep_ms(10); + RIE (sanei_genesys_get_status (dev, &val)); + if (DBG_LEVEL > DBG_info) + { + print_status (val); + } + RIE (sanei_genesys_test_buffer_empty (dev, &empty)); + count++; + } + while (empty && count < 1000); + if (count == 1000) + { + DBG(DBG_error, "%s: failed toread data\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner (dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* in case of CIS scanner, we must reorder data */ + if (dev->model->is_cis == SANE_TRUE + && settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + /* alloc one line sized working buffer */ + std::vector buffer(settings.pixels * 3 * bpp); + + /* reorder one line of data and put it back to buffer */ + if (bpp == 1) + { + for (y = 0; y < lines; y++) + { + /* reorder line */ + for (x = 0; x < settings.pixels; x++) + { + buffer[x * 3] = data[y * settings.pixels * 3 + x]; + buffer[x * 3 + 1] = data[y * settings.pixels * 3 + settings.pixels + x]; + buffer[x * 3 + 2] = data[y * settings.pixels * 3 + 2 * settings.pixels + x]; + } + /* copy line back */ + memcpy (data.data() + settings.pixels * 3 * y, buffer.data(), + settings.pixels * 3); + } + } + else + { + for (y = 0; y < lines; y++) + { + /* reorder line */ + for (x = 0; x < settings.pixels; x++) + { + buffer[x * 6] = data[y * settings.pixels * 6 + x * 2]; + buffer[x * 6 + 1] = data[y * settings.pixels * 6 + x * 2 + 1]; + buffer[x * 6 + 2] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2]; + buffer[x * 6 + 3] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2 + 1]; + buffer[x * 6 + 4] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2]; + buffer[x * 6 + 5] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2 + 1]; + } + /* copy line back */ + memcpy (data.data() + settings.pixels * 6 * y, buffer.data(), + settings.pixels * 6); + } + } + } + + /* end scan , waiting the motor to stop if needed (if moving), but without ejecting doc */ + status = end_scan(dev, &dev->reg, SANE_TRUE, SANE_FALSE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: end\n", __func__); + return status; +} + +/** + * Does a simple move of the given distance by doing a scan at lowest resolution + * shading correction. Memory for data is allocated in this function + * and must be freed by caller. + * @param dev device of the scanner + * @param distance distance to move in MM + */ +static SANE_Status +simple_move (Genesys_Device * dev, SANE_Int distance) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Settings settings; + + DBG(DBG_proc, "%s: %d mm\n", __func__, distance); + + int resolution = get_lowest_resolution(dev->model->ccd_type, 3); + + const auto& sensor = sanei_genesys_find_sensor(dev, resolution); + + /* TODO give a no AGOHOME flag */ + settings.scan_method = ScanMethod::TRANSPARENCY; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_y = 0; + settings.tl_x = 0; + settings.pixels = + (sensor.sensor_pixels * settings.xres) / sensor.optical_res; + settings.lines = (distance * settings.xres) / MM_PER_INCH; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + std::vector data; + status = simple_scan(dev, sensor, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, data); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: simple_scan failed\n", __func__); + } + + DBGCOMPLETED + return status; +} + +/** + * update the status of the required sensor in the scanner session + * the button fileds are used to make events 'sticky' + */ +static SANE_Status +gl646_update_hardware_sensors (Genesys_Scanner * session) +{ + Genesys_Device *dev = session->dev; + uint8_t value; + + // do what is needed to get a new set of events, but try to not loose any of them. + gl646_gpio_read(dev->usb_dev, &value); + DBG(DBG_io, "%s: GPIO=0x%02x\n", __func__, value); + + // scan button + if (dev->model->buttons & GENESYS_HAS_SCAN_SW) { + switch (dev->model->gpo_type) { + case GPO_XP200: + session->buttons[BUTTON_SCAN_SW].write((value & 0x02) != 0); + break; + case GPO_5345: + session->buttons[BUTTON_SCAN_SW].write(value == 0x16); + break; + case GPO_HP2300: + session->buttons[BUTTON_SCAN_SW].write(value == 0x6c); + break; + case GPO_HP3670: + case GPO_HP2400: + session->buttons[BUTTON_SCAN_SW].write((value & 0x20) == 0); + break; + default: + return SANE_STATUS_UNSUPPORTED; + } + } + + // email button + if (dev->model->buttons & GENESYS_HAS_EMAIL_SW) { + switch (dev->model->gpo_type) { + case GPO_5345: + session->buttons[BUTTON_EMAIL_SW].write(value == 0x12); + break; + case GPO_HP3670: + case GPO_HP2400: + session->buttons[BUTTON_EMAIL_SW].write((value & 0x08) == 0); + break; + default: + return SANE_STATUS_UNSUPPORTED; + } + } + + // copy button + if (dev->model->buttons & GENESYS_HAS_COPY_SW) { + switch (dev->model->gpo_type) { + case GPO_5345: + session->buttons[BUTTON_COPY_SW].write(value == 0x11); + break; + case GPO_HP2300: + session->buttons[BUTTON_COPY_SW].write(value == 0x5c); + break; + case GPO_HP3670: + case GPO_HP2400: + session->buttons[BUTTON_COPY_SW].write((value & 0x10) == 0); + break; + default: + return SANE_STATUS_UNSUPPORTED; + } + } + + // power button + if (dev->model->buttons & GENESYS_HAS_POWER_SW) { + switch (dev->model->gpo_type) { + case GPO_5345: + session->buttons[BUTTON_POWER_SW].write(value == 0x14); + break; + default: + return SANE_STATUS_UNSUPPORTED; + } + } + + // ocr button + if (dev->model->buttons & GENESYS_HAS_OCR_SW) { + switch (dev->model->gpo_type) { + case GPO_5345: + session->buttons[BUTTON_OCR_SW].write(value == 0x13); + break; + default: + return SANE_STATUS_UNSUPPORTED; + } + } + + // document detection + if (dev->model->buttons & GENESYS_HAS_PAGE_LOADED_SW) { + switch (dev->model->gpo_type) { + case GPO_XP200: + session->buttons[BUTTON_PAGE_LOADED_SW].write((value & 0x04) != 0); + break; + default: + return SANE_STATUS_UNSUPPORTED; + } + } + + /* XPA detection */ + if (dev->model->flags & GENESYS_FLAG_XPA) + { + switch (dev->model->gpo_type) + { + case GPO_HP3670: + case GPO_HP2400: + /* test if XPA is plugged-in */ + if ((value & 0x40) == 0) + { + DBG(DBG_io, "%s: enabling XPA\n", __func__); + session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE; + } + else + { + DBG(DBG_io, "%s: disabling XPA\n", __func__); + session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; + } + break; + default: + return SANE_STATUS_UNSUPPORTED; + } + } + + return SANE_STATUS_GOOD; +} + + +static SANE_Status +write_control (Genesys_Device * dev, const Genesys_Sensor& sensor, int resolution) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t control[4]; + uint32_t addr = 0xdead; + + /* 2300 does not write to 'control' */ + if (dev->model->motor_type == MOTOR_HP2300) + return SANE_STATUS_GOOD; + + /* MD6471/G2410/HP2300 and XP200 read/write data from an undocumented memory area which + * is after the second slope table */ + switch (sensor.optical_res) + { + case 600: + addr = 0x08200; + break; + case 1200: + addr = 0x10200; + break; + case 2400: + addr = 0x1fa00; + break; + default: + DBG(DBG_error, "%s: failed to compute control address\n", __func__); + return SANE_STATUS_INVAL; + } + + /* XP200 sets dpi, what other scanner put is unknown yet */ + switch (dev->model->motor_type) + { + case MOTOR_XP200: + /* we put scan's dpi, not motor one */ + control[0] = LOBYTE (resolution); + control[1] = HIBYTE (resolution); + control[2] = dev->control[4]; + control[3] = dev->control[5]; + break; + case MOTOR_HP3670: + case MOTOR_HP2400: + case MOTOR_5345: + default: + control[0] = dev->control[2]; + control[1] = dev->control[3]; + control[2] = dev->control[4]; + control[3] = dev->control[5]; + break; + } + + DBG(DBG_info, "%s: control write=0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, control[0], control[1], + control[2], control[3]); + status = sanei_genesys_set_buffer_address (dev, addr); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up control address\n", __func__); + return SANE_STATUS_INVAL; + } + status = sanei_genesys_bulk_write_data(dev, 0x3c, control, 4); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up control\n", __func__); + return SANE_STATUS_INVAL; + } + return status; +} + +/** + * check if a stored calibration is compatible with requested scan. + * @return true if compatible, false if not. + * Whenever an error is met, it is returned. + * @param dev scanner device + * @param cache cache entry to test + * @param for_overwrite reserved for future use ... + */ +static bool +gl646_is_compatible_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Calibration_Cache * cache, + int for_overwrite) +{ + (void) sensor; +#ifdef HAVE_SYS_TIME_H + struct timeval time; +#endif + int compatible = 1; + + DBG(DBG_proc, "%s: start (for_overwrite=%d)\n", __func__, for_overwrite); + + if (cache == NULL) + return false; + + /* build minimal current_setup for calibration cache use only, it will be better + * computed when during setup for scan + */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + dev->current_setup.channels = 3; + } + else + { + dev->current_setup.channels = 1; + } + dev->current_setup.xres = dev->settings.xres; + + DBG(DBG_io, "%s: requested=(%d,%f), tested=(%d,%f)\n", __func__, dev->current_setup.channels, + dev->current_setup.xres, cache->used_setup.channels, cache->used_setup.xres); + + /* a calibration cache is compatible if color mode and x dpi match the user + * requested scan. In the case of CIS scanners, dpi isn't a criteria */ + if (dev->model->is_cis == SANE_FALSE) + { + compatible = + ((dev->current_setup.channels == cache->used_setup.channels) + && (((int) dev->current_setup.xres) == + ((int) cache->used_setup.xres))); + } + else + { + compatible = + (dev->current_setup.channels == cache->used_setup.channels); + } + if (dev->current_setup.params.scan_method != cache->used_setup.params.scan_method) + { + DBG(DBG_io, "%s: current method=%d, used=%d\n", __func__, + static_cast(dev->current_setup.params.scan_method), + static_cast(cache->used_setup.params.scan_method)); + compatible = 0; + } + if (!compatible) + { + DBG(DBG_proc, "%s: completed, non compatible cache\n", __func__); + return false; + } + + /* a cache entry expires after 30 minutes for non sheetfed scanners */ + /* this is not taken into account when overwriting cache entries */ +#ifdef HAVE_SYS_TIME_H + if(for_overwrite == SANE_FALSE) + { + gettimeofday (&time, NULL); + if ((time.tv_sec - cache->last_calibration > 30 * 60) + && (dev->model->is_sheetfed == SANE_FALSE)) + { + DBG(DBG_proc, "%s: expired entry, non compatible cache\n", __func__); + return false; + } + } +#endif + + DBG(DBG_proc, "%s: completed, cache compatible\n", __func__); + return true; +} + +/** + * search for a full width black or white strip. + * @param dev scanner device + * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward + * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip + * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not + */ +static SANE_Status +gl646_search_strip(Genesys_Device * dev, const Genesys_Sensor& sensor, SANE_Bool forward, SANE_Bool black) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Bool half_ccd = SANE_FALSE; + Genesys_Settings settings; + int res = get_closest_resolution(dev->model->ccd_type, 75, 1); + unsigned int pass, count, found, x, y; + char title[80]; + + DBG(DBG_proc, "%s: start\n", __func__); + /* adapt to half_ccd case */ + if (sensor.ccd_size_divisor > 1) + { + /* walk the master mode list to find if half_ccd */ + // FIXME: possibly wrong channel count for is_half_ccd + if (is_half_ccd (dev->model->ccd_type, res, 3) == SANE_TRUE) + { + half_ccd = SANE_TRUE; + } + } + + /* we set up for a lowest available resolution color grey scan, full width */ + settings.scan_method = ScanMethod::FLATBED; + settings.scan_mode = ScanColorMode::GRAY; + settings.xres = res; + settings.yres = res; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = (SANE_UNFIX (dev->model->x_size) * res) / MM_PER_INCH; + if (half_ccd == SANE_TRUE) + { + settings.pixels /= 2; + } + + /* 15 mm at at time */ + settings.lines = (15 * settings.yres) / MM_PER_INCH; /* may become a parameter from genesys_devices.c */ + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + settings.dynamic_lineart = SANE_FALSE; + + /* signals if a strip of the given color has been found */ + found = 0; + + /* detection pass done */ + pass = 0; + + std::vector data; + + /* loop until strip is found or maximum pass number done */ + while (pass < 20 && !found) + { + /* scan a full width strip */ + status = + simple_scan(dev, sensor, settings, SANE_TRUE, forward, SANE_FALSE, data); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: simple_scan failed\n", __func__); + return status; + } + if (DBG_LEVEL >= DBG_data) + { + sprintf (title, "gl646_search_strip_%s%02d.pnm", forward ? "fwd" : "bwd", + (int)pass); + sanei_genesys_write_pnm_file (title, data.data(), settings.depth, 1, + settings.pixels, settings.lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < settings.lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < settings.pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * settings.pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * settings.pixels + x] < 60) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / settings.pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < settings.lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < settings.pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * settings.pixels + x] > 60) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * settings.pixels + x] < 60) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (settings.pixels * settings.lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count); + } + } + pass++; + } + if (found) + { + status = SANE_STATUS_GOOD; + DBG(DBG_info, "%s: strip found\n", __func__); + } + else + { + status = SANE_STATUS_UNSUPPORTED; + DBG(DBG_info, "%s: strip not found\n", __func__); + } + return status; +} + +/** the gl646 command set */ +static Genesys_Command_Set gl646_cmd_set = { + "gl646-generic", /* the name of this set */ + + gl646_needs_home_before_init_regs_for_scan, + + gl646_init, + gl646_init_regs_for_warmup, + gl646_init_regs_for_coarse_calibration, + gl646_init_regs_for_shading, + gl646_init_regs_for_scan, + + gl646_get_filter_bit, + gl646_get_lineart_bit, + gl646_get_bitset_bit, + gl646_get_gain4_bit, + gl646_get_fast_feed_bit, + gl646_test_buffer_empty_bit, + gl646_test_motor_flag_bit, + + gl646_public_set_fe, + gl646_set_powersaving, + gl646_save_power, + + gl646_begin_scan, + gl646_end_scan, + + gl646_send_gamma_table, + + gl646_search_start_position, + + gl646_offset_calibration, + gl646_coarse_gain_calibration, + gl646_led_calibration, + + NULL, + gl646_slow_back_home, + NULL, + + sanei_genesys_bulk_write_register, + sanei_genesys_bulk_write_data, + gl646_bulk_read_data, + + gl646_update_hardware_sensors, + + /* sheetfed related functions */ + gl646_load_document, + gl646_detect_document_end, + gl646_eject_document, + gl646_search_strip, + + gl646_is_compatible_calibration, + gl646_move_to_ta, + NULL, + NULL, + NULL +}; + +SANE_Status +sanei_gl646_init_cmd_set (Genesys_Device * dev) +{ + dev->model->cmd_set = &gl646_cmd_set; + return SANE_STATUS_GOOD; +} diff --git a/backend/genesys_gl646.h b/backend/genesys_gl646.h index 4c47d03..766176a 100644 --- a/backend/genesys_gl646.h +++ b/backend/genesys_gl646.h @@ -165,111 +165,21 @@ #include "genesys.h" -enum -{ - reg_0x01 = 0, - reg_0x02, - reg_0x03, - reg_0x04, - reg_0x05, - reg_0x06, - reg_0x07, - reg_0x08, - reg_0x09, - reg_0x0a, - reg_0x0b, - reg_0x10, - reg_0x11, - reg_0x12, - reg_0x13, - reg_0x14, - reg_0x15, - reg_0x16, - reg_0x17, - reg_0x18, - reg_0x19, - reg_0x1a, - reg_0x1b, - reg_0x1c, - reg_0x1d, - reg_0x1e, - reg_0x1f, - reg_0x20, - reg_0x21, - reg_0x22, - reg_0x23, - reg_0x24, - reg_0x25, - reg_0x26, - reg_0x27, - reg_0x28, - reg_0x29, - reg_0x2c, - reg_0x2d, - reg_0x2e, - reg_0x2f, - reg_0x30, - reg_0x31, - reg_0x32, - reg_0x33, - reg_0x34, - reg_0x35, - reg_0x36, - reg_0x37, - reg_0x38, - reg_0x39, - reg_0x3d, - reg_0x3e, - reg_0x3f, - reg_0x52, - reg_0x53, - reg_0x54, - reg_0x55, - reg_0x56, - reg_0x57, - reg_0x58, - reg_0x59, - reg_0x5a, - reg_0x5b, - reg_0x5c, - reg_0x5d, - reg_0x5e, - reg_0x60, - reg_0x61, - reg_0x62, - reg_0x63, - reg_0x64, - reg_0x65, - reg_0x66, - reg_0x67, - reg_0x68, - reg_0x69, - reg_0x6a, - reg_0x6b, - reg_0x6c, - reg_0x6d, - GENESYS_GL646_MAX_REGS -}; +static SANE_Status gl646_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t set, int dpi); -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl646_set_fe (Genesys_Device * dev, uint8_t set, int dpi); +static SANE_Status gl646_public_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t set); -#ifndef UNIT_TESTING static -#endif -SANE_Status gl646_public_set_fe (Genesys_Device * dev, uint8_t set); - -GENESYS_STATIC SANE_Status gl646_save_power (Genesys_Device * dev, SANE_Bool enable); -GENESYS_STATIC +static SANE_Status gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); -GENESYS_STATIC +static SANE_Status gl646_move_to_ta (Genesys_Device * dev); @@ -285,8 +195,9 @@ gl646_move_to_ta (Genesys_Device * dev); * @param ycorrection true if scanner's Y geometry must be taken into account to * compute Y, ie add top margins */ -GENESYS_STATIC SANE_Status +static SANE_Status setup_for_scan (Genesys_Device *device, + const Genesys_Sensor& sensor, Genesys_Register_Set *regs, Genesys_Settings settings, SANE_Bool split, @@ -300,15 +211,11 @@ setup_for_scan (Genesys_Device *device, * */ static SANE_Status gl646_setup_registers (Genesys_Device * dev, - Genesys_Register_Set * regs, - Genesys_Settings scan_settings, - uint16_t * slope_table1, - uint16_t * slope_table2, - SANE_Int resolution, - uint32_t move, - uint32_t linecnt, - uint16_t startx, - uint16_t endx, SANE_Bool color, SANE_Int depth); + const Genesys_Sensor& sensor, + Genesys_Register_Set * regs, SetupParams& params, + uint16_t * slope_table1, + uint16_t * slope_table2, + bool xcorrection); /** * Does a simple move of the given distance by doing a scan at lowest resolution @@ -317,10 +224,7 @@ gl646_setup_registers (Genesys_Device * dev, * @param dev device of the scanner * @param distance distance to move in MM */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status +static SANE_Status simple_move (Genesys_Device * dev, SANE_Int distance); /** @@ -335,12 +239,10 @@ simple_move (Genesys_Device * dev, SANE_Int distance); * @param shading flag to tell if shading correction should be done * @param data pointer that will point to the scanned data */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -simple_scan (Genesys_Device * dev, Genesys_Settings settings, SANE_Bool move, SANE_Bool forward, - SANE_Bool shading, unsigned char **data); +static SANE_Status +simple_scan(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Settings settings, SANE_Bool move, SANE_Bool forward, + SANE_Bool shading, std::vector& data); /** * Send the stop scan command @@ -351,7 +253,8 @@ end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, /** * writes control data to an area behind the last motor table. */ -static SANE_Status write_control (Genesys_Device * dev, int resolution); +static SANE_Status write_control (Genesys_Device * dev, const Genesys_Sensor& sensor, + int resolution); /** @@ -359,10 +262,7 @@ static SANE_Status write_control (Genesys_Device * dev, int resolution); */ static void gl646_init_regs (Genesys_Device * dev); -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl646_load_document (Genesys_Device * dev); +static SANE_Status gl646_load_document (Genesys_Device * dev); static SANE_Status gl646_detect_document_end (Genesys_Device * dev); @@ -381,7 +281,7 @@ typedef struct /* key */ SANE_Int motor; SANE_Int dpi; - SANE_Bool color; + unsigned channels; /* settings */ SANE_Int ydpi; /* real motor dpi, may be different from the resolution */ @@ -408,7 +308,7 @@ typedef struct /* key */ SANE_Int sensor; /**< sensor identifier */ SANE_Int dpi; /**< required dpi */ - SANE_Bool color; /**< SANE_TRUE if color scan */ + unsigned channels; // 3 channels if color scan, 1 channel for gray scan /* settings */ SANE_Int xdpi; /**< real sensor dpi, may be different from the required resolution */ @@ -448,88 +348,87 @@ static uint8_t xp200_gray[6]={0x05, 0x0a, 0x0f, 0xa0, 0x10, 0x10}; * master sensor settings, for a given sensor and dpi, * it gives exposure and CCD time */ -/* *INDENT-OFF* */ static Sensor_Master sensor_master[] = { /* HP3670 master settings */ - {CCD_HP3670, 75, SANE_TRUE , 75, 4879, 300, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 100, SANE_TRUE , 100, 4487, 400, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 150, SANE_TRUE , 150, 4879, 600, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 300, SANE_TRUE , 300, 4503, 1200, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 600, SANE_TRUE , 600, 10251, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x43}, - {CCD_HP3670,1200, SANE_TRUE , 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, - {CCD_HP3670,2400, SANE_TRUE , 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, - {CCD_HP3670, 75, SANE_FALSE, 75, 4879, 300, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 100, SANE_FALSE, 100, 4487, 400, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 150, SANE_FALSE, 150, 4879, 600, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 300, SANE_FALSE, 300, 4503, 1200, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 600, SANE_FALSE, 600, 10251, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x43}, - {CCD_HP3670,1200, SANE_FALSE, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, - {CCD_HP3670,2400, SANE_FALSE, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, + {CCD_HP3670, 75, 3, 75, 4879, 300, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, + {CCD_HP3670, 100, 3, 100, 4487, 400, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, + {CCD_HP3670, 150, 3, 150, 4879, 600, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, + {CCD_HP3670, 300, 3, 300, 4503, 1200, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, + {CCD_HP3670, 600, 3, 600, 10251, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x43}, + {CCD_HP3670,1200, 3, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, + {CCD_HP3670,2400, 3, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, + {CCD_HP3670, 75, 1, 75, 4879, 300, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, + {CCD_HP3670, 100, 1, 100, 4487, 400, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, + {CCD_HP3670, 150, 1, 150, 4879, 600, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, + {CCD_HP3670, 300, 1, 300, 4503, 1200, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, + {CCD_HP3670, 600, 1, 600, 10251, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x43}, + {CCD_HP3670,1200, 1, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, + {CCD_HP3670,2400, 1, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, /* HP 2400 master settings */ - {CCD_HP2400, 50, SANE_TRUE , 50, 7211, 200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 100, SANE_TRUE , 100, 7211, 400, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 150, SANE_TRUE , 150, 7211, 600, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 300, SANE_TRUE , 300, 8751, 1200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 600, SANE_TRUE , 600, 18760, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x02}, - {CCD_HP2400,1200, SANE_TRUE , 1200, 21749, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x42}, - {CCD_HP2400, 50, SANE_FALSE, 50, 7211, 200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 100, SANE_FALSE, 100, 7211, 400, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 150, SANE_FALSE, 150, 7211, 600, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 300, SANE_FALSE, 300, 8751, 1200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 600, SANE_FALSE, 600, 18760, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x02}, - {CCD_HP2400,1200, SANE_FALSE, 1200, 21749, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x42}, + {CCD_HP2400, 50, 3, 50, 7211, 200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, + {CCD_HP2400, 100, 3, 100, 7211, 400, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, + {CCD_HP2400, 150, 3, 150, 7211, 600, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, + {CCD_HP2400, 300, 3, 300, 8751, 1200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, + {CCD_HP2400, 600, 3, 600, 18760, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x02}, + {CCD_HP2400,1200, 3, 1200, 21749, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x42}, + {CCD_HP2400, 50, 1, 50, 7211, 200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, + {CCD_HP2400, 100, 1, 100, 7211, 400, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, + {CCD_HP2400, 150, 1, 150, 7211, 600, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, + {CCD_HP2400, 300, 1, 300, 8751, 1200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, + {CCD_HP2400, 600, 1, 600, 18760, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x02}, + {CCD_HP2400,1200, 1, 1200, 21749, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x42}, /* XP 200 master settings */ - {CIS_XP200 , 75, SANE_TRUE , 75, 5700, 75, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 100, SANE_TRUE , 100, 5700, 100, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 200, SANE_TRUE , 200, 5700, 200, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 300, SANE_TRUE , 300, 9000, 300, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 600, SANE_TRUE , 600, 16000, 600, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - - {CIS_XP200 , 75, SANE_FALSE, 75, 16000, 75, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 100, SANE_FALSE, 100, 7800, 100, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 200, SANE_FALSE, 200, 11000, 200, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 300, SANE_FALSE, 300, 13000, 300, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 600, SANE_FALSE, 600, 24000, 600, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 75, 3, 75, 5700, 75, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 100, 3, 100, 5700, 100, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 200, 3, 200, 5700, 200, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 300, 3, 300, 9000, 300, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 600, 3, 600, 16000, 600, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, + + {CIS_XP200 , 75, 1, 75, 16000, 75, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 100, 1, 100, 7800, 100, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 200, 1, 200, 11000, 200, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 300, 1, 300, 13000, 300, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, + {CIS_XP200 , 600, 1, 600, 24000, 600, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, /* HP 2300 master settings */ - {CCD_HP2300, 75, SANE_TRUE , 75, 4480, 150, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 150, SANE_TRUE , 150, 4350, 300, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 300, SANE_TRUE, 300, 4350, 600, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 600, SANE_TRUE , 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - {CCD_HP2300,1200, SANE_TRUE , 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - {CCD_HP2300, 75, SANE_FALSE, 75, 4480, 150, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 150, SANE_FALSE, 150, 4350, 300, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 300, SANE_FALSE, 300, 4350, 600, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 600, SANE_FALSE, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - {CCD_HP2300,1200, SANE_FALSE, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, + {CCD_HP2300, 75, 3, 75, 4480, 150, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, + {CCD_HP2300, 150, 3, 150, 4350, 300, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, + {CCD_HP2300, 300, 3, 300, 4350, 600, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, + {CCD_HP2300, 600, 3, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, + {CCD_HP2300,1200, 3, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, + {CCD_HP2300, 75, 1, 75, 4480, 150, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, + {CCD_HP2300, 150, 1, 150, 4350, 300, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, + {CCD_HP2300, 300, 1, 300, 4350, 600, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, + {CCD_HP2300, 600, 1, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, + {CCD_HP2300,1200, 1, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, /* non half ccd 300 dpi settings - {CCD_HP2300, 300, SANE_TRUE , 300, 8700, 300, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - {CCD_HP2300, 300, SANE_FALSE, 300, 8700, 300, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, + {CCD_HP2300, 300, 3, 300, 8700, 300, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, + {CCD_HP2300, 300, 1, 300, 8700, 300, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, */ /* MD5345/6471 master settings */ - {CCD_5345 , 50, SANE_TRUE , 50, 12000, 100, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 75, SANE_TRUE , 75, 11000, 150, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 100, SANE_TRUE , 100, 11000, 200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 150, SANE_TRUE , 150, 11000, 300, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 200, SANE_TRUE , 200, 11000, 400, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 300, SANE_TRUE , 300, 11000, 600, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 400, SANE_TRUE , 400, 11000, 800, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 600, SANE_TRUE , 600, 11000,1200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 ,1200, SANE_TRUE ,1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, - {CCD_5345 ,2400, SANE_TRUE ,1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, - {CCD_5345 , 50, SANE_FALSE, 50, 12000, 100, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 75, SANE_FALSE, 75, 11000, 150, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 100, SANE_FALSE, 100, 11000, 200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 150, SANE_FALSE, 150, 11000, 300, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 200, SANE_FALSE, 200, 11000, 400, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 300, SANE_FALSE, 300, 11000, 600, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 400, SANE_FALSE, 400, 11000, 800, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 600, SANE_FALSE, 600, 11000,1200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 ,1200, SANE_FALSE,1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, - {CCD_5345 ,2400, SANE_FALSE,1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, + {CCD_5345 , 50, 3, 50, 12000, 100, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 75, 3, 75, 11000, 150, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 100, 3, 100, 11000, 200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 150, 3, 150, 11000, 300, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 200, 3, 200, 11000, 400, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 300, 3, 300, 11000, 600, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 400, 3, 400, 11000, 800, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 600, 3, 600, 11000,1200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 ,1200, 3, 1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, + {CCD_5345 ,2400, 3, 1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, + {CCD_5345 , 50, 1, 50, 12000, 100, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 75, 1, 75, 11000, 150, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 100, 1, 100, 11000, 200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 150, 1, 150, 11000, 300, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 200, 1, 200, 11000, 400, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 300, 1, 300, 11000, 600, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 400, 1, 400, 11000, 800, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 , 600, 1, 600, 11000,1200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, + {CCD_5345 ,1200, 1, 1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, + {CCD_5345 ,2400, 1, 1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, }; @@ -539,88 +438,88 @@ static Sensor_Master sensor_master[] = { */ static Motor_Master motor_master[] = { /* HP3670 motor settings */ - {MOTOR_HP3670, 75, SANE_TRUE , 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 1, 200, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 100, SANE_TRUE , 100, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 143, 2905, 187, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 150, SANE_TRUE , 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 73, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 300, SANE_TRUE , 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 11, 1055, 563, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 600, SANE_TRUE , 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 10687, 5126, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670,1200, SANE_TRUE ,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 6375, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670,2400, SANE_TRUE ,2400, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 12750, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 75, SANE_FALSE, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 1, 200, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 100, SANE_FALSE, 100, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 143, 2905, 187, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 150, SANE_FALSE, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 73, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 300, SANE_FALSE, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 11, 1055, 563, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 600, SANE_FALSE, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 10687, 5126, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670,1200, SANE_FALSE,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 6375, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670,2400, SANE_TRUE ,2400, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 12750, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 75, 3, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 1, 200, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 100, 3, 100, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 143, 2905, 187, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 150, 3, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 73, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 300, 3, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 11, 1055, 563, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 600, 3, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 10687, 5126, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670,1200, 3,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 6375, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670,2400, 3,2400, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 12750, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 75, 1, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 1, 200, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 100, 1, 100, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 143, 2905, 187, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 150, 1, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 73, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 300, 1, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 11, 1055, 563, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670, 600, 1, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 10687, 5126, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670,1200, 1,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 6375, 192, 3399, 337, 0.3, 0.4, 192}, + {MOTOR_HP3670,2400, 3,2400, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 12750, 192, 3399, 337, 0.3, 0.4, 192}, /* HP2400/G2410 motor settings base motor dpi = 600 */ - {MOTOR_HP2400, 50, SANE_TRUE , 50, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 100, SANE_TRUE , 100, HALF_STEP, SANE_FALSE, SANE_TRUE, 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 150, SANE_TRUE , 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 15902, 902, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 300, SANE_TRUE , 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 32, 16703, 2188, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 600, SANE_TRUE , 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 18761, 18761, 192, 4905, 627, 0.30, 0.4, 192}, - {MOTOR_HP2400,1200, SANE_TRUE ,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 43501, 43501, 192, 4905, 627, 0.30, 0.4, 192}, - {MOTOR_HP2400, 50, SANE_FALSE, 50, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 100, SANE_FALSE, 100, HALF_STEP, SANE_FALSE, SANE_TRUE, 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 150, SANE_FALSE, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 15902, 902, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 300, SANE_FALSE, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 32, 16703, 2188, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 600, SANE_FALSE, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 18761, 18761, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400,1200, SANE_FALSE,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 43501, 43501, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 50, 3, 50, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 100, 3, 100, HALF_STEP, SANE_FALSE, SANE_TRUE, 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 150, 3, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 15902, 902, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 300, 3, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 32, 16703, 2188, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 600, 3, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 18761, 18761, 192, 4905, 627, 0.30, 0.4, 192}, + {MOTOR_HP2400,1200, 3,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 43501, 43501, 192, 4905, 627, 0.30, 0.4, 192}, + {MOTOR_HP2400, 50, 1, 50, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 100, 1, 100, HALF_STEP, SANE_FALSE, SANE_TRUE, 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 150, 1, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 15902, 902, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 300, 1, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 32, 16703, 2188, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400, 600, 1, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 18761, 18761, 192, 4905, 337, 0.30, 0.4, 192}, + {MOTOR_HP2400,1200, 1,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 43501, 43501, 192, 4905, 337, 0.30, 0.4, 192}, /* XP 200 motor settings */ - {MOTOR_XP200, 75, SANE_TRUE, 75, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2136, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 100, SANE_TRUE, 100, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2850, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 200, SANE_TRUE, 200, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6999, 5700, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 250, SANE_TRUE, 250, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6999, 6999, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 300, SANE_TRUE, 300, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 13500, 13500, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 600, SANE_TRUE, 600, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 31998, 31998, 2, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 75, SANE_FALSE, 75, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2000, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 100, SANE_FALSE, 100, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 1300, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 200, SANE_FALSE, 200, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 6000, 3666, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 300, SANE_FALSE, 300, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6500, 6500, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 600, SANE_FALSE, 600, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 24000, 24000, 2, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 75, 3, 75, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2136, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 100, 3, 100, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2850, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 200, 3, 200, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6999, 5700, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 250, 3, 250, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6999, 6999, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 300, 3, 300, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 13500, 13500, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 600, 3, 600, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 31998, 31998, 2, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 75, 1, 75, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2000, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 100, 1, 100, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 1300, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 200, 1, 200, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 6000, 3666, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 300, 1, 300, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6500, 6500, 8, 12000, 1200, 0.3, 0.5, 1}, + {MOTOR_XP200, 600, 1, 600, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 24000, 24000, 2, 12000, 1200, 0.3, 0.5, 1}, /* HP scanjet 2300c */ - {MOTOR_HP2300, 75, SANE_TRUE, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8139, 560, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 150, SANE_TRUE, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 7903, 543, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 300, SANE_TRUE, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 2175, 1087, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 600, SANE_TRUE, 600, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 8700, 4350, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300,1200, SANE_TRUE,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 17400, 8700, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 75, SANE_FALSE, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8139, 560, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 150, SANE_FALSE, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 7903, 543, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 300, SANE_FALSE, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 2175, 1087, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 600, SANE_FALSE, 600, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 8700, 4350, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300,1200, SANE_FALSE,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 17400, 8700, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 75, 3, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8139, 560, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 150, 3, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 7903, 543, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 300, 3, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 2175, 1087, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 600, 3, 600, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 8700, 4350, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300,1200, 3,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 17400, 8700, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 75, 1, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8139, 560, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 150, 1, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 7903, 543, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 300, 1, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 2175, 1087, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 600, 1, 600, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 8700, 4350, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300,1200, 1,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 17400, 8700, 120, 4905, 337, 0.3, 0.4, 16}, /* non half ccd settings for 300 dpi - {MOTOR_HP2300, 300, SANE_TRUE, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 44, 5386, 2175, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 300, SANE_FALSE, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 44, 5386, 2175, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 300, 3, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 44, 5386, 2175, 120, 4905, 337, 0.3, 0.4, 16}, + {MOTOR_HP2300, 300, 1, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 44, 5386, 2175, 120, 4905, 337, 0.3, 0.4, 16}, */ /* MD5345/6471 motor settings */ /* vfinal=(exposure/(1200/dpi))/step_type */ - {MOTOR_5345, 50, SANE_TRUE , 50, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 250, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 75, SANE_TRUE , 75, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 343, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 100, SANE_TRUE , 100, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 458, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 150, SANE_TRUE , 150, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 687, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 200, SANE_TRUE , 200, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 916, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 300, SANE_TRUE, 300, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 1375, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 400, SANE_TRUE, 400, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2000, 1833, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 500, SANE_TRUE, 500, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2291, 2291, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 600, SANE_TRUE, 600, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 1200, SANE_TRUE ,1200, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 146}, - {MOTOR_5345, 2400, SANE_TRUE ,2400, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 5500, 5500, 255, 2000, 300, 0.3, 0.4, 146}, - {MOTOR_5345, 50, SANE_FALSE, 50, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 250, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 75, SANE_FALSE, 75, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 343, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 100, SANE_FALSE, 100, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 458, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 150, SANE_FALSE, 150, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 687, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 200, SANE_FALSE, 200, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 916, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 300, SANE_FALSE, 300, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 1375, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 400, SANE_FALSE, 400, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2000, 1833, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 500, SANE_FALSE, 500, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2291, 2291, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 600, SANE_FALSE, 600, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 1200, SANE_FALSE,1200, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 146}, - {MOTOR_5345, 2400, SANE_FALSE,2400, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 5500, 5500, 255, 2000, 300, 0.3, 0.4, 146}, /* 5500 guessed */ + {MOTOR_5345, 50, 3, 50, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 250, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 75, 3, 75, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 343, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 100, 3, 100, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 458, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 150, 3, 150, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 687, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 200, 3, 200, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 916, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 300, 3, 300, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 1375, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 400, 3, 400, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2000, 1833, 255, 2000, 300, 0.3, 0.4, 32}, + {MOTOR_5345, 500, 3, 500, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2291, 2291, 255, 2000, 300, 0.3, 0.4, 32}, + {MOTOR_5345, 600, 3, 600, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 32}, + {MOTOR_5345, 1200, 3,1200, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 146}, + {MOTOR_5345, 2400, 3,2400, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 5500, 5500, 255, 2000, 300, 0.3, 0.4, 146}, + {MOTOR_5345, 50, 1, 50, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 250, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 75, 1, 75, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 343, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 100, 1, 100, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 458, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 150, 1, 150, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 687, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 200, 1, 200, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 916, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 300, 1, 300, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 1375, 255, 2000, 300, 0.3, 0.4, 64}, + {MOTOR_5345, 400, 1, 400, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2000, 1833, 255, 2000, 300, 0.3, 0.4, 32}, + {MOTOR_5345, 500, 1, 500, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2291, 2291, 255, 2000, 300, 0.3, 0.4, 32}, + {MOTOR_5345, 600, 1, 600, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 32}, + {MOTOR_5345, 1200, 1,1200, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 146}, + {MOTOR_5345, 2400, 1,2400, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 5500, 5500, 255, 2000, 300, 0.3, 0.4, 146}, /* 5500 guessed */ }; /** @@ -693,4 +592,3 @@ static Sensor_Settings sensor_settings[] = { {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83} /* half ccd settings */ }, }; -/* *INDENT-ON* */ diff --git a/backend/genesys_gl841.c b/backend/genesys_gl841.c deleted file mode 100644 index 43c01ff..0000000 --- a/backend/genesys_gl841.c +++ /dev/null @@ -1,6383 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003 Oliver Rauch - Copyright (C) 2003, 2004 Henning Meier-Geinitz - Copyright (C) 2004 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz - Copyright (C) 2005 Philipp Schmid - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2006 Laurent Charpentier - Copyright (C) 2010 Chris Berry and Michael Rickmann - for Plustek Opticbook 3600 support - - - 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. -*/ - -#undef BACKEND_NAME -#define BACKEND_NAME genesys_gl841 - -#include "genesys_gl841.h" - -/**************************************************************************** - Low level function - ****************************************************************************/ - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - -/* Write to many registers */ -/* Note: There is no known bulk register write, - this function is sending single registers instead */ -static SANE_Status -gl841_bulk_write_register (Genesys_Device * dev, - Genesys_Register_Set * reg, size_t elems) -{ - SANE_Status status = SANE_STATUS_GOOD; - unsigned int i, c; - uint8_t buffer[GENESYS_MAX_REGS * 2]; - - /* handle differently sized register sets, reg[0x00] is the last one */ - i = 0; - while ((i < elems) && (reg[i].address != 0)) - i++; - - elems = i; - - DBG (DBG_io, "gl841_bulk_write_register (elems = %lu)\n", - (u_long) elems); - - for (i = 0; i < elems; i++) { - - buffer[i * 2 + 0] = reg[i].address; - buffer[i * 2 + 1] = reg[i].value; - - DBG (DBG_io2, "reg[0x%02x] = 0x%02x\n", buffer[i * 2 + 0], - buffer[i * 2 + 1]); - } - - for (i = 0; i < elems;) { - c = elems - i; - if (c > 32) /*32 is max. checked that.*/ - c = 32; - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_SET_REGISTER, INDEX, c * 2, buffer + i * 2); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_bulk_write_register: failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - i += c; - } - - DBG (DBG_io, "gl841_bulk_write_register: wrote %lu registers\n", - (u_long) elems); - return status; -} - -/* Write bulk data (e.g. shading, gamma) */ -static SANE_Status -gl841_bulk_write_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size; - uint8_t outdata[8]; - - DBG (DBG_io, "gl841_bulk_write_data writing %lu bytes\n", - (u_long) len); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_bulk_write_data failed while setting register: %s\n", - sane_strstatus (status)); - return status; - } - - while (len) - { - if (len > BULKOUT_MAXSIZE) - size = BULKOUT_MAXSIZE; - else - size = len; - - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - outdata[2] = VALUE_BUFFER & 0xff; - outdata[3] = (VALUE_BUFFER >> 8) & 0xff; - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), - outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_bulk_write_data failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_usb_write_bulk (dev->dn, data, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_bulk_write_data failed while writing bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "gl841_bulk_write_data wrote %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (len - size)); - - len -= size; - data += size; - } - - DBG (DBG_io, "gl841_bulk_write_data: completed\n"); - - return status; -} - -/* for debugging transfer rate*/ -/* -#include -static struct timeval start_time; -static void -starttime(){ - gettimeofday(&start_time,NULL); -} -static void -printtime(char *p) { - struct timeval t; - long long int dif; - gettimeofday(&t,NULL); - dif = t.tv_sec - start_time.tv_sec; - dif = dif*1000000 + t.tv_usec - start_time.tv_usec; - fprintf(stderr,"%s %lluµs\n",p,dif); -} -*/ - -/* Read bulk data (e.g. scanned data) */ -static SANE_Status -gl841_bulk_read_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size, target; - uint8_t outdata[8], *buffer; - - DBG (DBG_io, "gl841_bulk_read_data: requesting %lu bytes\n", - (u_long) len); - - if (len == 0) - return SANE_STATUS_GOOD; - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_bulk_read_data failed while setting register: %s\n", - sane_strstatus (status)); - return status; - } - - outdata[0] = BULK_IN; - outdata[1] = BULK_RAM; - outdata[2] = VALUE_BUFFER & 0xff; - outdata[3] = (VALUE_BUFFER >> 8) & 0xff; - outdata[4] = (len & 0xff); - outdata[5] = ((len >> 8) & 0xff); - outdata[6] = ((len >> 16) & 0xff); - outdata[7] = ((len >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_bulk_read_data failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - target = len; - buffer = data; - while (target) - { - if (target > BULKIN_MAXSIZE) - size = BULKIN_MAXSIZE; - else - size = target; - - DBG (DBG_io2, - "gl841_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) size); - - status = sanei_usb_read_bulk (dev->dn, data, &size); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "gl841_bulk_read_data read %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (target - size)); - - target -= size; - data += size; - } - - - if (DBG_LEVEL >= DBG_data && dev->binary!=NULL) - { - fwrite(buffer, len, 1, dev->binary); - } - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Set address for writing data */ -static SANE_Status -gl841_set_buffer_address_gamma (Genesys_Device * dev, uint32_t addr) -{ - SANE_Status status; - - DBG (DBG_io, "gl841_set_buffer_address_gamma: setting address to 0x%05x\n", - addr & 0xfffffff0); - - addr = addr >> 4; - - status = sanei_genesys_write_register (dev, 0x5c, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_set_buffer_address_gamma: failed while writing low byte: %s\n", - sane_strstatus (status)); - return status; - } - - addr = addr >> 8; - status = sanei_genesys_write_register (dev, 0x5b, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_set_buffer_address_gamma: failed while writing high byte: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io, "gl841_set_buffer_address_gamma: completed\n"); - - return status; -} - -/* Write bulk data (e.g. gamma) */ -GENESYS_STATIC SANE_Status -gl841_bulk_write_data_gamma (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size; - uint8_t outdata[8]; - - DBG (DBG_io, "gl841_bulk_write_data_gamma writing %lu bytes\n", - (u_long) len); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_bulk_write_data_gamma failed while setting register: %s\n", - sane_strstatus (status)); - return status; - } - - while (len) - { - if (len > BULKOUT_MAXSIZE) - size = BULKOUT_MAXSIZE; - else - size = len; - - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - outdata[2] = 0x00;/* 0x82 works, too */ - outdata[3] = 0x00; - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), - outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_bulk_write_data_gamma failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_usb_write_bulk (dev->dn, data, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "genesys_bulk_write_data_gamma failed while writing bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "genesys_bulk_write_data:gamma wrote %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (len - size)); - - len -= size; - data += size; - } - - DBG (DBG_io, "genesys_bulk_write_data_gamma: completed\n"); - - return status; -} - - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl841_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_get_filter_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_get_lineart_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_get_bitset_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_get_gain4_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** copy sensor specific settings */ -/* *dev : device infos - *regs : registers to be set - extended : do extended set up - half_ccd: set up for half ccd resolution - all registers 08-0B, 10-1D, 52-59 are set up. They shouldn't - appear anywhere else but in register_ini - -Responsible for signals to CCD/CIS: - CCD_CK1X (CK1INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1MTGL(0x1C),CK1LOW(0x1D),CK1MAP(0x74,0x75,0x76),CK1NEG(0x7D)) - CCD_CK2X (CK2INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1LOW(0x1D),CK1NEG(0x7D)) - CCD_CK3X (MANUAL3(0x1A),CK3INV(0x1A),CK3MTGL(0x1C),CK3LOW(0x1D),CK3MAP(0x77,0x78,0x79),CK3NEG(0x7D)) - CCD_CK4X (MANUAL3(0x1A),CK4INV(0x1A),CK4MTGL(0x1C),CK4LOW(0x1D),CK4MAP(0x7A,0x7B,0x7C),CK4NEG(0x7D)) - CCD_CPX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),CPH(0x72),CPL(0x73),CPNEG(0x7D)) - CCD_RSX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),RSH(0x70),RSL(0x71),RSNEG(0x7D)) - CCD_TGX (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPR(0x10,0x11),TGSHLD(0x1D)) - CCD_TGG (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPG(0x12,0x13),TGSHLD(0x1D)) - CCD_TGB (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPB(0x14,0x15),TGSHLD(0x1D)) - LAMP_SW (EXPR(0x10,0x11),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) - XPA_SW (EXPG(0x12,0x13),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) - LAMP_B (EXPB(0x14,0x15),LAMP_PWR(0x03)) - -other registers: - CISSET(0x01),CNSET(0x18),DCKSEL(0x18),SCANMOD(0x18),EXPDMY(0x19),LINECLP(0x1A),CKAREA(0x1C),TGTIME(0x1C),LINESEL(0x1E),DUMMY(0x34) - -Responsible for signals to AFE: - VSMP (VSMP(0x58),VSMPW(0x58)) - BSMP (BSMP(0x59),BSMPW(0x59)) - -other register settings depending on this: - RHI(0x52),RLOW(0x53),GHI(0x54),GLOW(0x55),BHI(0x56),BLOW(0x57), - -*/ -static void -sanei_gl841_setup_sensor (Genesys_Device * dev, - Genesys_Register_Set * regs, - SANE_Bool extended, SANE_Bool half_ccd) -{ - Genesys_Register_Set *r; - int i; - - DBG (DBG_proc, "gl841_setup_sensor\n"); - - /* that one is tricky at least ....*/ - r = sanei_genesys_get_address (regs, 0x70); - for (i = 0; i < 4; i++, r++) - r->value = dev->sensor.regs_0x08_0x0b[i]; - - r = sanei_genesys_get_address (regs, 0x16); - for (i = 0x06; i < 0x0a; i++, r++) - r->value = dev->sensor.regs_0x10_0x1d[i]; - - r = sanei_genesys_get_address (regs, 0x1a); - for (i = 0x0a; i < 0x0e; i++, r++) - r->value = dev->sensor.regs_0x10_0x1d[i]; - - r = sanei_genesys_get_address (regs, 0x52); - for (i = 0; i < 9; i++, r++) - r->value = dev->sensor.regs_0x52_0x5e[i]; - - /* don't go any further if no extended setup */ - if (!extended) - return; - - /* todo : add more CCD types if needed */ - /* we might want to expand the Sensor struct to have these - 2 kind of settings */ - if (dev->model->ccd_type == CCD_5345) - { - if (half_ccd) - { - /* settings for CCD used at half is max resolution */ - r = sanei_genesys_get_address (regs, 0x70); - r->value = 0x00; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 0x05; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 0x06; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 0x08; - r = sanei_genesys_get_address (regs, 0x18); - r->value = 0x28; - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ - } - else - { - /* swap latch times */ - r = sanei_genesys_get_address (regs, 0x18); - r->value = 0x30; - r = sanei_genesys_get_address (regs, 0x52); - for (i = 0; i < 6; i++, r++) - r->value = dev->sensor.regs_0x52_0x5e[(i + 3) % 6]; - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x20 | (r->value & 0x03); /* VSMP=4 */ - } - return; - } - - if (dev->model->ccd_type == CCD_HP2300) - { - /* settings for CCD used at half is max resolution */ - if (half_ccd) - { - r = sanei_genesys_get_address (regs, 0x70); - r->value = 0x16; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 0x00; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 0x01; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 0x03; - /* manual clock programming */ - r = sanei_genesys_get_address (regs, 0x1d); - r->value |= 0x80; - } - else - { - r = sanei_genesys_get_address (regs, 0x70); - r->value = 1; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 3; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 4; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 6; - } - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ - return; - } -} - -/** Test if the ASIC works - */ -/*TODO: make this functional*/ -static SANE_Status -sanei_gl841_asic_test (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val; - uint8_t *data; - uint8_t *verify_data; - size_t size, verify_size; - unsigned int i; - - DBG (DBG_proc, "sanei_gl841_asic_test\n"); - - return SANE_STATUS_INVAL; - - /* set and read exposure time, compare if it's the same */ - status = sanei_genesys_write_register (dev, 0x38, 0xde); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sanei_gl841_asic_test: failed to write register: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_write_register (dev, 0x39, 0xad); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sanei_gl841_asic_test: failed to write register: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_read_register (dev, 0x38, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sanei_gl841_asic_test: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val != 0xde) /* value of register 0x38 */ - { - DBG (DBG_error, - "sanei_gl841_asic_test: register contains invalid value\n"); - return SANE_STATUS_IO_ERROR; - } - - status = sanei_genesys_read_register (dev, 0x39, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sanei_gl841_asic_test: failed to read register: %s\n", - sane_strstatus (status)); - return status; - } - if (val != 0xad) /* value of register 0x39 */ - { - DBG (DBG_error, - "sanei_gl841_asic_test: register contains invalid value\n"); - return SANE_STATUS_IO_ERROR; - } - - /* ram test: */ - size = 0x40000; - verify_size = size + 0x80; - /* todo: looks like the read size must be a multiple of 128? - otherwise the read doesn't succeed the second time after the scanner has - been plugged in. Very strange. */ - - data = (uint8_t *) malloc (size); - if (!data) - { - DBG (DBG_error, "sanei_gl841_asic_test: could not allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - verify_data = (uint8_t *) malloc (verify_size); - if (!verify_data) - { - free (data); - DBG (DBG_error, "sanei_gl841_asic_test: could not allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - for (i = 0; i < (size - 1); i += 2) - { - data[i] = i / 512; - data[i + 1] = (i / 2) % 256; - } - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_gl841_asic_test: failed to set buffer address: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - -/* status = gl841_bulk_write_data (dev, 0x3c, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_gl841_asic_test: failed to bulk write data: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - }*/ - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_gl841_asic_test: failed to set buffer address: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - status = - gl841_bulk_read_data (dev, 0x45, (uint8_t *) verify_data, - verify_size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sanei_gl841_asic_test: failed to bulk read data: %s\n", - sane_strstatus (status)); - free (data); - free (verify_data); - return status; - } - - /* todo: why i + 2 ? */ - for (i = 0; i < size; i++) - { - if (verify_data[i] != data[i]) - { - DBG (DBG_error, "sanei_gl841_asic_test: data verification error\n"); - DBG (DBG_info, "0x%.8x: got %.2x %.2x %.2x %.2x, expected %.2x %.2x %.2x %.2x\n", - i, - verify_data[i], - verify_data[i+1], - verify_data[i+2], - verify_data[i+3], - data[i], - data[i+1], - data[i+2], - data[i+3]); - free (data); - free (verify_data); - return SANE_STATUS_IO_ERROR; - } - } - - free (data); - free (verify_data); - - DBG (DBG_info, "sanei_gl841_asic_test: completed\n"); - - return SANE_STATUS_GOOD; -} - -/* returns the max register bulk size */ -static int -gl841_bulk_full_size (void) -{ - return GENESYS_GL841_MAX_REGS; -} - -/* - * Set all registers LiDE 80 to default values - * (function called only once at the beginning) - * we are doing a special case to ease development - */ -static void -gl841_init_lide80 (Genesys_Device * dev) -{ - uint8_t val; - int index=0; - - INITREG (0x01, 0x82); /* 0x02 = SHDAREA and no CISSET ! */ - INITREG (0x02, 0x10); - INITREG (0x03, 0x50); - INITREG (0x04, 0x02); - INITREG (0x05, 0x4c); /* 1200 DPI */ - INITREG (0x06, 0x38); /* 0x38 scanmod=1, pwrbit, GAIN4 */ - INITREG (0x07, 0x00); - INITREG (0x08, 0x00); - INITREG (0x09, 0x11); - INITREG (0x0a, 0x00); - - INITREG (0x10, 0x40); - INITREG (0x11, 0x00); - INITREG (0x12, 0x40); - INITREG (0x13, 0x00); - INITREG (0x14, 0x40); - INITREG (0x15, 0x00); - INITREG (0x16, 0x00); - INITREG (0x17, 0x01); - INITREG (0x18, 0x00); - INITREG (0x19, 0x06); - INITREG (0x1a, 0x00); - INITREG (0x1b, 0x00); - INITREG (0x1c, 0x00); - INITREG (0x1d, 0x04); - INITREG (0x1e, 0x10); - INITREG (0x1f, 0x04); - INITREG (0x20, 0x02); - INITREG (0x21, 0x10); - INITREG (0x22, 0x20); - INITREG (0x23, 0x20); - INITREG (0x24, 0x10); - INITREG (0x25, 0x00); - INITREG (0x26, 0x00); - INITREG (0x27, 0x00); - - INITREG (0x29, 0xff); - - INITREG (0x2c, dev->sensor.optical_res>>8); - INITREG (0x2d, dev->sensor.optical_res & 0xff); - INITREG (0x2e, 0x80); - INITREG (0x2f, 0x80); - INITREG (0x30, 0x00); - INITREG (0x31, 0x10); - INITREG (0x32, 0x15); - INITREG (0x33, 0x0e); - INITREG (0x34, 0x40); - INITREG (0x35, 0x00); - INITREG (0x36, 0x2a); - INITREG (0x37, 0x30); - INITREG (0x38, 0x2a); - INITREG (0x39, 0xf8); - - INITREG (0x3d, 0x00); - INITREG (0x3e, 0x00); - INITREG (0x3f, 0x00); - - INITREG (0x52, 0x03); - INITREG (0x53, 0x07); - INITREG (0x54, 0x00); - INITREG (0x55, 0x00); - INITREG (0x56, 0x00); - INITREG (0x57, 0x00); - INITREG (0x58, 0x29); - INITREG (0x59, 0x69); - INITREG (0x5a, 0x55); - - INITREG (0x5d, 0x20); - INITREG (0x5e, 0x41); - INITREG (0x5f, 0x40); - INITREG (0x60, 0x00); - INITREG (0x61, 0x00); - INITREG (0x62, 0x00); - INITREG (0x63, 0x00); - INITREG (0x64, 0x00); - INITREG (0x65, 0x00); - INITREG (0x66, 0x00); - INITREG (0x67, 0x40); - INITREG (0x68, 0x40); - INITREG (0x69, 0x20); - INITREG (0x6a, 0x20); - INITREG (0x6c, dev->gpo.value[0]); - INITREG (0x6d, dev->gpo.value[1]); - INITREG (0x6e, dev->gpo.enable[0]); - INITREG (0x6f, dev->gpo.enable[1]); - INITREG (0x70, 0x00); - INITREG (0x71, 0x05); - INITREG (0x72, 0x07); - INITREG (0x73, 0x09); - INITREG (0x74, 0x00); - INITREG (0x75, 0x01); - INITREG (0x76, 0xff); - INITREG (0x77, 0x00); - INITREG (0x78, 0x0f); - INITREG (0x79, 0xf0); - INITREG (0x7a, 0xf0); - INITREG (0x7b, 0x00); - INITREG (0x7c, 0x1e); - INITREG (0x7d, 0x11); - INITREG (0x7e, 0x00); - INITREG (0x7f, 0x50); - INITREG (0x80, 0x00); - INITREG (0x81, 0x00); - INITREG (0x82, 0x0f); - INITREG (0x83, 0x00); - INITREG (0x84, 0x0e); - INITREG (0x85, 0x00); - INITREG (0x86, 0x0d); - INITREG (0x87, 0x02); - INITREG (0x88, 0x00); - INITREG (0x89, 0x00); - - /* specific scanner settings, clock and gpio first */ - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x0c); - sanei_genesys_write_register (dev, 0x06, 0x10); - sanei_genesys_write_register (dev, REG6E, 0x6d); - sanei_genesys_write_register (dev, REG6F, 0x80); - sanei_genesys_write_register (dev, REG6B, 0x0e); - sanei_genesys_read_register (dev, REG6C, &val); - sanei_genesys_write_register (dev, REG6C, 0x00); - sanei_genesys_read_register (dev, REG6D, &val); - sanei_genesys_write_register (dev, REG6D, 0x8f); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x0e); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x0e); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x0a); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x02); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x06); - - sanei_genesys_write_0x8c (dev, 0x10, 0x94); - sanei_genesys_write_register (dev, 0x09, 0x10); - - /* set up GPIO : no address, so no bulk write, doesn't written directly either ? */ - /* - dev->reg[reg_0x6c].value = dev->gpo.value[0]; - dev->reg[reg_0x6d].value = dev->gpo.value[1]; - dev->reg[reg_0x6e].value = dev->gpo.enable[0]; - dev->reg[reg_0x6f].value = dev->gpo.enable[1]; */ - - dev->reg[reg_0x6b].value |= REG6B_GPO18; - dev->reg[reg_0x6b].value &= ~REG6B_GPO17; - - sanei_gl841_setup_sensor (dev, dev->reg, 0, 0); -} - -/* - * Set all registers to default values - * (function called only once at the beginning) - */ -static void -gl841_init_registers (Genesys_Device * dev) -{ - int nr, addr; - - DBG (DBG_proc, "gl841_init_registers\n"); - - nr = 0; - memset (dev->reg, 0, GENESYS_MAX_REGS * sizeof (Genesys_Register_Set)); - if (strcmp (dev->model->name, "canon-lide-80") == 0) - { - gl841_init_lide80(dev); - return ; - } - - for (addr = 1; addr <= 0x0a; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x10; addr <= 0x27; addr++) - dev->reg[nr++].address = addr; - dev->reg[nr++].address = 0x29; - for (addr = 0x2c; addr <= 0x39; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x3d; addr <= 0x3f; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x52; addr <= 0x5a; addr++) - dev->reg[nr++].address = addr; - for (addr = 0x5d; addr <= 0x87; addr++) - dev->reg[nr++].address = addr; - - - dev->reg[reg_0x01].value = 0x20; /* (enable shading), CCD, color, 1M */ - if (dev->model->is_cis == SANE_TRUE) - { - dev->reg[reg_0x01].value |= REG01_CISSET; - } - else - { - dev->reg[reg_0x01].value &= ~REG01_CISSET; - } - - dev->reg[reg_0x02].value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ - dev->reg[reg_0x02].value |= REG02_AGOHOME; - dev->reg[reg_0x02].value |= REG02_MTRPWR; - dev->reg[reg_0x02].value |= REG02_FASTFED; - - dev->reg[reg_0x03].value = 0x1f /*0x17 */ ; /* lamp on */ - dev->reg[reg_0x03].value |= REG03_AVEENB; - - if (dev->model->ccd_type == CCD_PLUSTEK_3600) /* AD front end */ - { - dev->reg[reg_0x04].value = (2 << REG04S_AFEMOD) | 0x02; - } - else /* Wolfson front end */ - { - dev->reg[reg_0x04].value |= 1 << REG04S_AFEMOD; - } - - dev->reg[reg_0x05].value = 0x00; /* disable gamma, 24 clocks/pixel */ - if (dev->sensor.sensor_pixels < 0x1500) - dev->reg[reg_0x05].value |= REG05_DPIHW_600; - else if (dev->sensor.sensor_pixels < 0x2a80) - dev->reg[reg_0x05].value |= REG05_DPIHW_1200; - else if (dev->sensor.sensor_pixels < 0x5400) - dev->reg[reg_0x05].value |= REG05_DPIHW_2400; - else - { - dev->reg[reg_0x05].value |= REG05_DPIHW_2400; - DBG (DBG_warn, - "gl841_init_registers: Cannot handle sensor pixel count %d\n", - dev->sensor.sensor_pixels); - } - - - dev->reg[reg_0x06].value |= REG06_PWRBIT; - dev->reg[reg_0x06].value |= REG06_GAIN4; - - /* XP300 CCD needs different clock and clock/pixels values */ - if (dev->model->ccd_type != CCD_XP300 && dev->model->ccd_type != CCD_DP685 - && dev->model->ccd_type != CCD_PLUSTEK_3600) - { - dev->reg[reg_0x06].value |= 0 << REG06S_SCANMOD; - dev->reg[reg_0x09].value |= 1 << REG09S_CLKSET; - } - else - { - dev->reg[reg_0x06].value |= 0x05 << REG06S_SCANMOD; /* 15 clocks/pixel */ - dev->reg[reg_0x09].value = 0; /* 24 MHz CLKSET */ - } - - dev->reg[reg_0x1e].value = 0xf0; /* watch-dog time */ - - dev->reg[reg_0x17].value |= 1 << REG17S_TGW; - - dev->reg[reg_0x19].value = 0x50; - - dev->reg[reg_0x1d].value |= 1 << REG1DS_TGSHLD; - - dev->reg[reg_0x1e].value |= 1 << REG1ES_WDTIME; - -/*SCANFED*/ - dev->reg[reg_0x1f].value = 0x01; - -/*BUFSEL*/ - dev->reg[reg_0x20].value = 0x20; - -/*LAMPPWM*/ - dev->reg[reg_0x29].value = 0xff; - -/*BWHI*/ - dev->reg[reg_0x2e].value = 0x80; - -/*BWLOW*/ - dev->reg[reg_0x2f].value = 0x80; - -/*LPERIOD*/ - dev->reg[reg_0x38].value = 0x4f; - dev->reg[reg_0x39].value = 0xc1; - -/*VSMPW*/ - dev->reg[reg_0x58].value |= 3 << REG58S_VSMPW; - -/*BSMPW*/ - dev->reg[reg_0x59].value |= 3 << REG59S_BSMPW; - -/*RLCSEL*/ - dev->reg[reg_0x5a].value |= REG5A_RLCSEL; - -/*STOPTIM*/ - dev->reg[reg_0x5e].value |= 0x2 << REG5ES_STOPTIM; - - sanei_gl841_setup_sensor (dev, dev->reg, 0, 0); - - /* set up GPIO */ - dev->reg[reg_0x6c].value = dev->gpo.value[0]; - dev->reg[reg_0x6d].value = dev->gpo.value[1]; - dev->reg[reg_0x6e].value = dev->gpo.enable[0]; - dev->reg[reg_0x6f].value = dev->gpo.enable[1]; - - /* TODO there is a switch calling to be written here */ - if (dev->model->gpo_type == GPO_CANONLIDE35) - { - dev->reg[reg_0x6b].value |= REG6B_GPO18; - dev->reg[reg_0x6b].value &= ~REG6B_GPO17; - } - if (dev->model->gpo_type == GPO_CANONLIDE80) - { - dev->reg[reg_0x6b].value |= REG6B_GPO18; - dev->reg[reg_0x6b].value &= ~REG6B_GPO17; - } - - if (dev->model->gpo_type == GPO_XP300) - { - dev->reg[reg_0x6b].value |= REG6B_GPO17; - } - - if (dev->model->gpo_type == GPO_DP685) - { - /* REG6B_GPO18 lights on green led */ - dev->reg[reg_0x6b].value |= REG6B_GPO17|REG6B_GPO18; - } - - DBG (DBG_proc, "gl841_init_registers complete\n"); -} - -/* Send slope table for motor movement - slope_table in machine byte order - */ -GENESYS_STATIC SANE_Status -gl841_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - int dpihw; - int start_address; - SANE_Status status; - uint8_t *table; - char msg[4000]; -/*#ifdef WORDS_BIGENDIAN*/ - int i; -/*#endif*/ - - DBG (DBG_proc, "gl841_send_slope_table (table_nr = %d, steps = %d)\n", - table_nr, steps); - - dpihw = dev->reg[reg_0x05].value >> 6; - - if (dpihw == 0) /* 600 dpi */ - start_address = 0x08000; - else if (dpihw == 1) /* 1200 dpi */ - start_address = 0x10000; - else if (dpihw == 2) /* 2400 dpi */ - start_address = 0x20000; - else /* reserved */ - return SANE_STATUS_INVAL; - -/*#ifdef WORDS_BIGENDIAN*/ - table = (uint8_t*)malloc(steps * 2); - for(i = 0; i < steps; i++) { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } -/*#else - table = (uint8_t*)slope_table; - #endif*/ - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), ",%d", slope_table[i]); - } - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - status = - sanei_genesys_set_buffer_address (dev, start_address + table_nr * 0x200); - if (status != SANE_STATUS_GOOD) - { -/*#ifdef WORDS_BIGENDIAN*/ - free(table); -/*#endif*/ - DBG (DBG_error, - "gl841_send_slope_table: failed to set buffer address: %s\n", - sane_strstatus (status)); - return status; - } - - status = - gl841_bulk_write_data (dev, 0x3c, (uint8_t *) table, - steps * 2); - if (status != SANE_STATUS_GOOD) - { -/*#ifdef WORDS_BIGENDIAN*/ - free(table); -/*#endif*/ - DBG (DBG_error, - "gl841_send_slope_table: failed to send slope table: %s\n", - sane_strstatus (status)); - return status; - } - -/*#ifdef WORDS_BIGENDIAN*/ - free(table); -/*#endif*/ - DBG (DBG_proc, "gl841_send_slope_table: completed\n"); - return status; -} - -static SANE_Status -gl841_set_lide80_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - if (set == AFE_INIT) - { - DBG (DBG_proc, "%s(): setting DAC %u\n", __func__, - dev->model->dac_type); - - /* sets to default values */ - sanei_genesys_init_fe (dev); - - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.reg[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: writing reg 0x03 failed: %s\n", __func__, - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x06, dev->frontend.reg[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: writing reg 0x06 failed: %s\n", __func__, - sane_strstatus (status)); - return status; - } - } - - if (set == AFE_SET) - { - status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x06, dev->frontend.offset[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: writing offset failed: %s\n", __func__, - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.gain[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: writing gain failed: %s\n", __func__, - sane_strstatus (status)); - return status; - } - } - - return status; - DBGCOMPLETED; -} - -/* Set values of Analog Device type frontend */ -static SANE_Status -gl841_set_ad_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - - /* special case for LiDE 80 analog frontend */ - if(dev->model->dac_type==DAC_CANONLIDE80) - { - return gl841_set_lide80_fe(dev, set); - } - - DBG (DBG_proc, "gl841_set_ad_fe(): start\n"); - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl841_set_ad_fe(): setting DAC %u\n", - dev->model->dac_type); - - /* sets to default values */ - sanei_genesys_init_fe (dev); - - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: writing reg 0x00 failed: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x01, dev->frontend.reg[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: writing reg 0x01 failed: %s\n", - sane_strstatus (status)); - return status; - } - - for (i = 0; i < 6; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x02 + i, 0x00); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_set_ad_fe: writing sign[%d] failed: %s\n", 0x02 + i, - sane_strstatus (status)); - return status; - } - } - } - if (set == AFE_SET) - { - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: writing reg 0x00 failed: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x01, dev->frontend.reg[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: writing reg 0x01 failed: %s\n", - sane_strstatus (status)); - return status; - } - - /* Write fe 0x02 (red gain)*/ - status = sanei_genesys_fe_write_data (dev, 0x02, dev->frontend.gain[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: writing fe 0x02 (gain r) fail: %s\n", - sane_strstatus (status)); - return status; - } - - /* Write fe 0x03 (green gain)*/ - status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.gain[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: writing fe 0x03 (gain g) fail: %s\n", - sane_strstatus (status)); - return status; - } - - /* Write fe 0x04 (blue gain)*/ - status = sanei_genesys_fe_write_data (dev, 0x04, dev->frontend.gain[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: writing fe 0x04 (gain b) fail: %s\n", - sane_strstatus (status)); - return status; - } - - /* Write fe 0x05 (red offset)*/ - status = - sanei_genesys_fe_write_data (dev, 0x05, dev->frontend.offset[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: write fe 0x05 (offset r) fail: %s\n", - sane_strstatus (status)); - return status; - } - - /* Write fe 0x06 (green offset)*/ - status = - sanei_genesys_fe_write_data (dev, 0x06, dev->frontend.offset[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: write fe 0x06 (offset g) fail: %s\n", - sane_strstatus (status)); - return status; - } - - /* Write fe 0x07 (blue offset)*/ - status = - sanei_genesys_fe_write_data (dev, 0x07, dev->frontend.offset[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_ad_fe: write fe 0x07 (offset b) fail: %s\n", - sane_strstatus (status)); - return status; - } - } - DBG (DBG_proc, "gl841_set_ad_fe(): end\n"); - - return status; -} - -/* Set values of analog frontend */ -static SANE_Status -gl841_set_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status; - int i; - - DBG (DBG_proc, "gl841_set_fe (%s)\n", - set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?"); - - /* Analog Device type frontend */ - if ((dev->reg[reg_0x04].value & REG04_FESET) == 0x02) - { - return gl841_set_ad_fe (dev, set); - } - - if ((dev->reg[reg_0x04].value & REG04_FESET) != 0x00) - { - DBG (DBG_proc, "gl841_set_fe(): unsupported frontend type %d\n", - dev->reg[reg_0x04].value & REG04_FESET); - return SANE_STATUS_UNSUPPORTED; - } - - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl841_set_fe(): setting DAC %u\n", - dev->model->dac_type); - sanei_genesys_init_fe (dev); - - /* reset only done on init */ - status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_fe: reset fe failed: %s\n", - sane_strstatus (status)); - return status; - /* - if (dev->model->ccd_type == CCD_HP2300 - || dev->model->ccd_type == CCD_HP2400) - { - val = 0x07; - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, - REQUEST_REGISTER, GPIO_OUTPUT_ENABLE, - INDEX, 1, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_set_fe failed resetting frontend: %s\n", - sane_strstatus (status)); - return status; - } - }*/ - } - DBG (DBG_proc, "gl841_set_fe(): frontend reset complete\n"); - } - - - if (set == AFE_POWER_SAVE) - { - status = sanei_genesys_fe_write_data (dev, 0x01, 0x02); - if (status != SANE_STATUS_GOOD) - DBG (DBG_error, "gl841_set_fe: writing data failed: %s\n", - sane_strstatus (status)); - return status; - } - - /* todo : base this test on cfg reg3 or a CCD family flag to be created */ - /*if (dev->model->ccd_type!=CCD_HP2300 && dev->model->ccd_type!=CCD_HP2400) */ - { - - status = sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_fe: writing reg0 failed: %s\n", - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x02, dev->frontend.reg[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_fe: writing reg2 failed: %s\n", - sane_strstatus (status)); - return status; - } - } - - status = sanei_genesys_fe_write_data (dev, 0x01, dev->frontend.reg[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_fe: writing reg1 failed: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x03, dev->frontend.reg[3]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_fe: writing reg3 failed: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x06, dev->frontend.reg2[0]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_fe: writing reg6 failed: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x08, dev->frontend.reg2[1]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_fe: writing reg8 failed: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x09, dev->frontend.reg2[2]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_set_fe: writing reg9 failed: %s\n", - sane_strstatus (status)); - return status; - } - - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x24 + i, dev->frontend.sign[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_set_fe: writing sign[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x28 + i, dev->frontend.gain[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_set_fe: writing gain[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - - status = - sanei_genesys_fe_write_data (dev, 0x20 + i, - dev->frontend.offset[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_set_fe: writing offset[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - } - - - DBG (DBG_proc, "gl841_set_fe: completed\n"); - - return SANE_STATUS_GOOD; -} - -#define MOTOR_ACTION_FEED 1 -#define MOTOR_ACTION_GO_HOME 2 -#define MOTOR_ACTION_HOME_FREE 3 - -/** @brief turn off motor - * - */ -static SANE_Status -gl841_init_motor_regs_off(Genesys_Register_Set * reg, - unsigned int scan_lines) -{ - unsigned int feedl; - Genesys_Register_Set * r; - - DBG (DBG_proc, "gl841_init_motor_regs_off : scan_lines=%d\n", - scan_lines); - - feedl = 2; - - r = sanei_genesys_get_address (reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address (reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address (reg, 0x25); - r->value = (scan_lines >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x26); - r->value = (scan_lines >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x27); - r->value = scan_lines & 0xff; - - r = sanei_genesys_get_address (reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - - r->value &= ~0x10; - - r->value &= ~0x06; - - r->value &= ~0x08; - - r->value &= ~0x20; - - r->value &= ~0x40; - - r = sanei_genesys_get_address (reg, 0x67); - r->value = 0x3f; - - r = sanei_genesys_get_address (reg, 0x68); - r->value = 0x3f; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = 0; - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x69); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x6a); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x5f); - r->value = 0; - - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief write motor table frequency - * Write motor frequency data table. - * @param dev device to set up motor - * @param ydpi motor target resolution - * @return SANE_STATUS_GOOD on success - */ -GENESYS_STATIC SANE_Status gl841_write_freq(Genesys_Device *dev, unsigned int ydpi) -{ -SANE_Status status; -/**< fast table */ -uint8_t tdefault[] = {0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76}; -uint8_t t1200[] = {0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20}; -uint8_t t300[] = {0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60}; -uint8_t t150[] = {0x0c,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0x40,0x14,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x0c,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0x11,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x0c,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0x40,0xd4,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x0c,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0x11,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60}; - -uint8_t *table; - - DBGSTART; - if(dev->model->motor_type == MOTOR_CANONLIDE80) - { - switch(ydpi) - { - case 3600: - case 1200: - table=t1200; - break; - case 900: - case 300: - table=t300; - break; - case 450: - case 150: - table=t150; - break; - default: - table=tdefault; - } - RIE(sanei_genesys_write_register(dev, 0x66, 0x00)); - RIE(sanei_genesys_write_register(dev, 0x5b, 0x0c)); - RIE(sanei_genesys_write_register(dev, 0x5c, 0x00)); - RIE(gl841_bulk_write_data_gamma (dev, 0x28, table, 128)); - RIE(sanei_genesys_write_register(dev, 0x5b, 0x00)); - RIE(sanei_genesys_write_register(dev, 0x5c, 0x00)); - } - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl841_init_motor_regs(Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int feed_steps,/*1/base_ydpi*/ -/*maybe float for half/quarter step resolution?*/ - unsigned int action, - unsigned int flags) -{ - SANE_Status status; - unsigned int fast_exposure; - int scan_power_mode; - int use_fast_fed = 0; - uint16_t fast_slope_table[256]; - unsigned int fast_slope_steps = 0; - unsigned int feedl; - Genesys_Register_Set * r; -/*number of scan lines to add in a scan_lines line*/ - - DBG (DBG_proc, "gl841_init_motor_regs : feed_steps=%d, action=%d, flags=%x\n", - feed_steps, - action, - flags); - - memset(fast_slope_table,0xff,512); - - gl841_send_slope_table (dev, 0, fast_slope_table, 256); - gl841_send_slope_table (dev, 1, fast_slope_table, 256); - gl841_send_slope_table (dev, 2, fast_slope_table, 256); - gl841_send_slope_table (dev, 3, fast_slope_table, 256); - gl841_send_slope_table (dev, 4, fast_slope_table, 256); - - gl841_write_freq(dev, dev->motor.base_ydpi / 4); - - fast_slope_steps = 256; - if (action == MOTOR_ACTION_FEED || action == MOTOR_ACTION_GO_HOME) - { - /* FEED and GO_HOME can use fastest slopes available */ - fast_exposure = gl841_exposure_time(dev, - dev->motor.base_ydpi / 4, - 0, - 0, - 0, - &scan_power_mode); - DBG (DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); - } - - if (action == MOTOR_ACTION_HOME_FREE) { -/* HOME_FREE must be able to stop in one step, so do not try to get faster */ - fast_exposure = dev->motor.slopes[0][0].maximum_start_speed; - } - - sanei_genesys_create_slope_table3 ( - dev, - fast_slope_table, - 256, - fast_slope_steps, - 0, - fast_exposure, - dev->motor.base_ydpi / 4, - &fast_slope_steps, - &fast_exposure, 0); - - feedl = feed_steps - fast_slope_steps*2; - use_fast_fed = 1; - -/* all needed slopes available. we did even decide which mode to use. - what next? - - transfer slopes -SCAN: -flags \ use_fast_fed ! 0 1 -------------------------\-------------------- - 0 ! 0,1,2 0,1,2,3 -MOTOR_FLAG_AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 -OFF: none -FEED: 3 -GO_HOME: 3 -HOME_FREE: 3 - - setup registers - * slope specific registers (already done) - * DECSEL for HOME_FREE/GO_HOME/SCAN - * FEEDL - * MTRREV - * MTRPWR - * FASTFED - * STEPSEL - * MTRPWM - * FSTPSEL - * FASTPWM - * HOMENEG - * BWDSTEP - * FWDSTEP - * Z1 - * Z2 - */ - - r = sanei_genesys_get_address (reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address (reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address (reg, 0x25); - r->value = 0; - r = sanei_genesys_get_address (reg, 0x26); - r->value = 0; - r = sanei_genesys_get_address (reg, 0x27); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - - r->value |= 0x10; - - if (action == MOTOR_ACTION_GO_HOME) - r->value |= 0x06; - else - r->value &= ~0x06; - - if (use_fast_fed) - r->value |= 0x08; - else - r->value &= ~0x08; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= 0x20; - else - r->value &= ~0x20; - - r->value &= ~0x40; - - status = gl841_send_slope_table (dev, 3, fast_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - - r = sanei_genesys_get_address (reg, 0x67); - r->value = 0x3f; - - r = sanei_genesys_get_address (reg, 0x68); - r->value = 0x3f; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = 0; - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x69); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x6a); - r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); - - r = sanei_genesys_get_address (reg, 0x5f); - r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); - - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl841_init_motor_regs_scan(Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time,/*pixel*/ - float scan_yres,/*dpi, motor resolution*/ - int scan_step_type,/*0: full, 1: half, 2: quarter*/ - unsigned int scan_lines,/*lines, scan resolution*/ - unsigned int scan_dummy, -/*number of scan lines to add in a scan_lines line*/ - unsigned int feed_steps,/*1/base_ydpi*/ -/*maybe float for half/quarter step resolution?*/ - int scan_power_mode, - unsigned int flags) -{ - SANE_Status status; - unsigned int fast_exposure; - int use_fast_fed = 0; - int dummy_power_mode; - unsigned int fast_time; - unsigned int slow_time; - uint16_t slow_slope_table[256]; - uint16_t fast_slope_table[256]; - uint16_t back_slope_table[256]; - unsigned int slow_slope_time; - unsigned int fast_slope_time; - unsigned int slow_slope_steps = 0; - unsigned int fast_slope_steps = 0; - unsigned int back_slope_steps = 0; - unsigned int feedl; - Genesys_Register_Set * r; - unsigned int min_restep = 0x20; - uint32_t z1, z2; - - DBG (DBG_proc, "gl841_init_motor_regs_scan : scan_exposure_time=%d, " - "scan_yres=%g, scan_step_type=%d, scan_lines=%d, scan_dummy=%d, " - "feed_steps=%d, scan_power_mode=%d, flags=%x\n", - scan_exposure_time, - scan_yres, - scan_step_type, - scan_lines, - scan_dummy, - feed_steps, - scan_power_mode, - flags); - - fast_exposure = gl841_exposure_time(dev, - dev->motor.base_ydpi / 4, - 0, - 0, - 0, - &dummy_power_mode); - - DBG (DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); - - memset(slow_slope_table,0xff,512); - - gl841_send_slope_table (dev, 0, slow_slope_table, 256); - gl841_send_slope_table (dev, 1, slow_slope_table, 256); - gl841_send_slope_table (dev, 2, slow_slope_table, 256); - gl841_send_slope_table (dev, 3, slow_slope_table, 256); - gl841_send_slope_table (dev, 4, slow_slope_table, 256); - - /* motor frequency table */ - gl841_write_freq(dev, scan_yres); - -/* - we calculate both tables for SCAN. the fast slope step count depends on - how many steps we need for slow acceleration and how much steps we are - allowed to use. - */ - slow_slope_time = sanei_genesys_create_slope_table3 ( - dev, - slow_slope_table, 256, - 256, - scan_step_type, - scan_exposure_time, - scan_yres, - &slow_slope_steps, - NULL, - scan_power_mode); - - sanei_genesys_create_slope_table3 ( - dev, - back_slope_table, 256, - 256, - scan_step_type, - 0, - scan_yres, - &back_slope_steps, - NULL, - scan_power_mode); - - if (feed_steps < (slow_slope_steps >> scan_step_type)) { - /*TODO: what should we do here?? go back to exposure calculation?*/ - feed_steps = slow_slope_steps >> scan_step_type; - } - - if (feed_steps > fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type)) - fast_slope_steps = 256; - else -/* we need to shorten fast_slope_steps here. */ - fast_slope_steps = (feed_steps - - (slow_slope_steps >> scan_step_type))/2; - - DBG(DBG_info,"gl841_init_motor_regs_scan: Maximum allowed slope steps for fast slope: %d\n",fast_slope_steps); - - fast_slope_time = sanei_genesys_create_slope_table3 ( - dev, - fast_slope_table, 256, - fast_slope_steps, - 0, - fast_exposure, - dev->motor.base_ydpi / 4, - &fast_slope_steps, - &fast_exposure, - scan_power_mode); - - /* fast fed special cases handling */ - if (dev->model->gpo_type == GPO_XP300 - || dev->model->gpo_type == GPO_DP685) - { - /* quirk: looks like at least this scanner is unable to use - 2-feed mode */ - use_fast_fed = 0; - } - else if (feed_steps < fast_slope_steps*2 + (slow_slope_steps >> scan_step_type)) { - use_fast_fed = 0; - DBG(DBG_info,"gl841_init_motor_regs_scan: feed too short, slow move forced.\n"); - } else { -/* for deciding whether we should use fast mode we need to check how long we - need for (fast)accelerating, moving, decelerating, (TODO: stopping?) - (slow)accelerating again versus (slow)accelerating and moving. we need - fast and slow tables here. -*/ -/*NOTE: scan_exposure_time is per scan_yres*/ -/*NOTE: fast_exposure is per base_ydpi/4*/ -/*we use full steps as base unit here*/ - fast_time = - fast_exposure / 4 * - (feed_steps - fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type)) - + fast_slope_time*2 + slow_slope_time; - slow_time = - (scan_exposure_time * scan_yres) / dev->motor.base_ydpi * - (feed_steps - (slow_slope_steps >> scan_step_type)) - + slow_slope_time; - - DBG(DBG_info,"gl841_init_motor_regs_scan: Time for slow move: %d\n", - slow_time); - DBG(DBG_info,"gl841_init_motor_regs_scan: Time for fast move: %d\n", - fast_time); - - use_fast_fed = fast_time < slow_time; - } - - if (use_fast_fed) - feedl = feed_steps - fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type); - else - if ((feed_steps << scan_step_type) < slow_slope_steps) - feedl = 0; - else - feedl = (feed_steps << scan_step_type) - slow_slope_steps; - DBG(DBG_info,"gl841_init_motor_regs_scan: Decided to use %s mode\n", - use_fast_fed?"fast feed":"slow feed"); - -/* all needed slopes available. we did even decide which mode to use. - what next? - - transfer slopes -SCAN: -flags \ use_fast_fed ! 0 1 -------------------------\-------------------- - 0 ! 0,1,2 0,1,2,3 -MOTOR_FLAG_AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 -OFF: none -FEED: 3 -GO_HOME: 3 -HOME_FREE: 3 - - setup registers - * slope specific registers (already done) - * DECSEL for HOME_FREE/GO_HOME/SCAN - * FEEDL - * MTRREV - * MTRPWR - * FASTFED - * STEPSEL - * MTRPWM - * FSTPSEL - * FASTPWM - * HOMENEG - * BWDSTEP - * FWDSTEP - * Z1 - * Z2 - */ - - r = sanei_genesys_get_address (reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address (reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address (reg, 0x25); - r->value = (scan_lines >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x26); - r->value = (scan_lines >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x27); - r->value = scan_lines & 0xff; - - r = sanei_genesys_get_address (reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - r->value |= 0x10; - - r->value &= ~0x06; - - if (use_fast_fed) - r->value |= 0x08; - else - r->value &= ~0x08; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= 0x20; - else - r->value &= ~0x20; - - if (flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - r->value |= 0x40; - else - r->value &= ~0x40; - - status = gl841_send_slope_table (dev, 0, slow_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - - status = gl841_send_slope_table (dev, 1, back_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - - status = gl841_send_slope_table (dev, 2, slow_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - - if (use_fast_fed) { - status = gl841_send_slope_table (dev, 3, fast_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - } - - if (flags & MOTOR_FLAG_AUTO_GO_HOME){ - status = gl841_send_slope_table (dev, 4, fast_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - } - - -/* now reg 0x21 and 0x24 are available, we can calculate reg 0x22 and 0x23, - reg 0x60-0x62 and reg 0x63-0x65 - rule: - 2*STEPNO+FWDSTEP=2*FASTNO+BWDSTEP -*/ -/* steps of table 0*/ - if (min_restep < slow_slope_steps*2+2) - min_restep = slow_slope_steps*2+2; -/* steps of table 1*/ - if (min_restep < back_slope_steps*2+2) - min_restep = back_slope_steps*2+2; -/* steps of table 0*/ - r = sanei_genesys_get_address (reg, REG_FWDSTEP); - r->value = min_restep - slow_slope_steps*2; -/* steps of table 1*/ - r = sanei_genesys_get_address (reg, REG_BWDSTEP); - r->value = min_restep - back_slope_steps*2; - -/* - for z1/z2: - in dokumentation mentioned variables a-d: - a = time needed for acceleration, table 1 - b = time needed for reg 0x1f... wouldn't that be reg0x1f*exposure_time? - c = time needed for acceleration, table 1 - d = time needed for reg 0x22... wouldn't that be reg0x22*exposure_time? - z1 = (c+d-1) % exposure_time - z2 = (a+b-1) % exposure_time -*/ -/* i don't see any effect of this. i can only guess that this will enhance - sub-pixel accuracy - z1 = (slope_0_time-1) % exposure_time; - z2 = (slope_0_time-1) % exposure_time; -*/ - z1 = z2 = 0; - - DBG (DBG_info, "gl841_init_motor_regs_scan: z1 = %d\n", z1); - DBG (DBG_info, "gl841_init_motor_regs_scan: z2 = %d\n", z2); - r = sanei_genesys_get_address (reg, 0x60); - r->value = ((z1 >> 16) & 0xff); - r = sanei_genesys_get_address (reg, 0x61); - r->value = ((z1 >> 8) & 0xff); - r = sanei_genesys_get_address (reg, 0x62); - r->value = (z1 & 0xff); - r = sanei_genesys_get_address (reg, 0x63); - r->value = ((z2 >> 16) & 0xff); - r = sanei_genesys_get_address (reg, 0x64); - r->value = ((z2 >> 8) & 0xff); - r = sanei_genesys_get_address (reg, 0x65); - r->value = (z2 & 0xff); - - r = sanei_genesys_get_address (reg, REG1E); - r->value &= REG1E_WDTIME; - r->value |= scan_dummy; - - r = sanei_genesys_get_address (reg, 0x67); - r->value = 0x3f | (scan_step_type << 6); - - r = sanei_genesys_get_address (reg, 0x68); - r->value = 0x3f; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = (slow_slope_steps >> 1) + (slow_slope_steps & 1); - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = (back_slope_steps >> 1) + (back_slope_steps & 1); - - r = sanei_genesys_get_address (reg, 0x69); - r->value = (slow_slope_steps >> 1) + (slow_slope_steps & 1); - - r = sanei_genesys_get_address (reg, 0x6a); - r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); - - r = sanei_genesys_get_address (reg, 0x5f); - r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); - - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static int -gl841_get_dpihw(Genesys_Device * dev) -{ - Genesys_Register_Set * r; - r = sanei_genesys_get_address (dev->reg, 0x05); - if ((r->value & REG05_DPIHW) == REG05_DPIHW_600) - return 600; - if ((r->value & REG05_DPIHW) == REG05_DPIHW_1200) - return 1200; - if ((r->value & REG05_DPIHW) == REG05_DPIHW_2400) - return 2400; - return 0; -} - -static SANE_Status -gl841_init_optical_regs_off(Genesys_Register_Set * reg) -{ - Genesys_Register_Set * r; - - DBGSTART; - - r = sanei_genesys_get_address (reg, 0x01); - r->value &= ~REG01_SCAN; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_init_optical_regs_scan(Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int exposure_time, - unsigned int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, - int color_filter, - int flags - ) -{ - unsigned int words_per_line; - unsigned int end; - unsigned int dpiset; - unsigned int i; - Genesys_Register_Set * r; - SANE_Status status; - uint16_t expavg, expr, expb, expg; - - DBG (DBG_proc, "gl841_init_optical_regs_scan : exposure_time=%d, " - "used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", - exposure_time, - used_res, - start, - pixels, - channels, - depth, - half_ccd, - flags); - - end = start + pixels; - - status = gl841_set_fe (dev, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_init_optical_regs_scan: failed to set frontend: %s\n", - sane_strstatus (status)); - return status; - } - - /* adjust used_res for chosen dpihw */ - used_res = used_res * gl841_get_dpihw(dev) / dev->sensor.optical_res; - -/* - with half_ccd the optical resolution of the ccd is halved. We don't apply this - to dpihw, so we need to double dpiset. - - For the scanner only the ratio of dpiset and dpihw is of relevance to scale - down properly. -*/ - if (half_ccd) - dpiset = used_res * 2; - else - dpiset = used_res; - - /* gpio part.*/ - if (dev->model->gpo_type == GPO_CANONLIDE35) - { - r = sanei_genesys_get_address (reg, REG6C); - if (half_ccd) - r->value &= ~0x80; - else - r->value |= 0x80; - } - if (dev->model->gpo_type == GPO_CANONLIDE80) - { - r = sanei_genesys_get_address (reg, REG6C); - if (half_ccd) - { - r->value &= ~0x40; - r->value |= 0x20; - } - else - { - r->value &= ~0x20; - r->value |= 0x40; - } - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, 0x01); - r->value |= REG01_SCAN; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - r->value &= ~REG01_DVDSET; - else - r->value |= REG01_DVDSET; - - /* average looks better than deletion, and we are already set up to - use one of the average enabled resolutions - */ - r = sanei_genesys_get_address (reg, 0x03); - r->value |= REG03_AVEENB; - if (flags & OPTICAL_FLAG_DISABLE_LAMP) - r->value &= ~REG03_LAMPPWR; - else - r->value |= REG03_LAMPPWR; - - /* exposure times */ - r = sanei_genesys_get_address (reg, 0x10); - for (i = 0; i < 6; i++, r++) { - if (flags & OPTICAL_FLAG_DISABLE_LAMP) - r->value = 0x01;/* 0x0101 is as off as possible */ - else - { /* EXP[R,G,B] only matter for CIS scanners */ - if (dev->sensor.regs_0x10_0x1d[i] == 0x00) - r->value = 0x01; /*0x00 will not be accepted*/ - else - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - } - - r = sanei_genesys_get_address (reg, 0x19); - if (flags & OPTICAL_FLAG_DISABLE_LAMP) - r->value = 0xff; - else - r->value = 0x50; - - /* BW threshold */ - r = sanei_genesys_get_address (reg, 0x2e); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, 0x2f); - r->value = dev->settings.threshold; - - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, 0x04); - switch (depth) { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - /* AFEMOD should depend on FESET, and we should set these - * bits separately */ - r->value &= ~(REG04_FILTER | REG04_AFEMOD); - if (flags & OPTICAL_FLAG_ENABLE_LEDADD) - { - r->value |= 0x10; /* no filter */ - } - else if (channels == 1) - { - switch (color_filter) - { - case 0: - r->value |= 0x14; /* red filter */ - break; - case 1: - r->value |= 0x18; /* green filter */ - break; - case 2: - r->value |= 0x1c; /* blue filter */ - break; - default: - r->value |= 0x10; /* no filter */ - break; - } - } - else - { - if (dev->model->ccd_type == CCD_PLUSTEK_3600) - { - r->value |= 0x22; /* slow color pixel by pixel */ - } - else - { - r->value |= 0x10; /* color pixel by pixel */ - } - } - - /* CIS scanners can do true gray by setting LEDADD */ - r = sanei_genesys_get_address (reg, 0x87); - r->value &= ~REG87_LEDADD; - if (flags & OPTICAL_FLAG_ENABLE_LEDADD) - { - r->value |= REG87_LEDADD; - sanei_genesys_get_double (reg, REG_EXPR, &expr); - sanei_genesys_get_double (reg, REG_EXPG, &expg); - sanei_genesys_get_double (reg, REG_EXPB, &expb); - - /* use minimal exposure for best image quality */ - expavg = expg; - if (expr < expg) - expavg = expr; - if (expb < expavg) - expavg = expb; - - sanei_genesys_set_double (dev->reg, REG_EXPR, expavg); - sanei_genesys_set_double (dev->reg, REG_EXPG, expavg); - sanei_genesys_set_double (dev->reg, REG_EXPB, expavg); - } - - /* enable gamma tables */ - r = sanei_genesys_get_address (reg, 0x05); - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - /* sensor parameters */ - sanei_gl841_setup_sensor (dev, dev->reg, 1, half_ccd); - - r = sanei_genesys_get_address (reg, 0x29); - r->value = 255; /*<<<"magic" number, only suitable for cis*/ - - sanei_genesys_set_double(reg, REG_DPISET, dpiset); - sanei_genesys_set_double(reg, REG_STRPIXEL, start); - sanei_genesys_set_double(reg, REG_ENDPIXEL, end); - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d\n",__func__,start,end); - - /* words(16bit) before gamma, conversion to 8 bit or lineart*/ - words_per_line = (pixels * dpiset) / gl841_get_dpihw(dev); - - words_per_line *= channels; - - if (depth == 1) - words_per_line = (words_per_line >> 3) + ((words_per_line & 7)?1:0); - else - words_per_line *= depth / 8; - - dev->wpl = words_per_line; - dev->bpl = words_per_line; - - r = sanei_genesys_get_address (reg, 0x35); - r->value = LOBYTE (HIWORD (words_per_line)); - r = sanei_genesys_get_address (reg, 0x36); - r->value = HIBYTE (LOWORD (words_per_line)); - r = sanei_genesys_get_address (reg, 0x37); - r->value = LOBYTE (LOWORD (words_per_line)); - - sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); - - r = sanei_genesys_get_address (reg, 0x34); - r->value = dev->sensor.dummy_pixel; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static int -gl841_get_led_exposure(Genesys_Device * dev) -{ - int d,r,g,b,m; - if (!dev->model->is_cis) - return 0; - d = dev->reg[reg_0x19].value; - r = dev->sensor.regs_0x10_0x1d[1] | (dev->sensor.regs_0x10_0x1d[0] << 8); - g = dev->sensor.regs_0x10_0x1d[3] | (dev->sensor.regs_0x10_0x1d[2] << 8); - b = dev->sensor.regs_0x10_0x1d[5] | (dev->sensor.regs_0x10_0x1d[4] << 8); - - m = r; - if (m < g) - m = g; - if (m < b) - m = b; - - return m + d; -} - -/** @brief compute exposure time - * Compute exposure time for the device and the given scan resolution, - * also compute scan_power_mode - */ -GENESYS_STATIC int -gl841_exposure_time(Genesys_Device *dev, - float slope_dpi, - int scan_step_type, - int start, - int used_pixels, - int *scan_power_mode) -{ -int exposure_time = 0; -int exposure_time2 = 0; -int led_exposure; - - *scan_power_mode=0; - led_exposure=gl841_get_led_exposure(dev); - exposure_time = sanei_genesys_exposure_time2( - dev, - slope_dpi, - scan_step_type, - start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ - led_exposure, - *scan_power_mode); - - while(*scan_power_mode + 1 < dev->motor.power_mode_count) { - exposure_time2 = sanei_genesys_exposure_time2( - dev, - slope_dpi, - scan_step_type, - start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ - led_exposure, - *scan_power_mode + 1); - if (exposure_time < exposure_time2) - break; - exposure_time = exposure_time2; - (*scan_power_mode)++; - } - - return exposure_time; -} - -/**@brief compute scan_step_type - * Try to do at least 4 steps per line. if that is impossible we will have to - * live with that. - * @param dev device - * @param yres motor resolution - */ -GENESYS_STATIC int -gl841_scan_step_type(Genesys_Device *dev, int yres) -{ -int scan_step_type=0; - - /* TODO : check if there is a bug around the use of max_step_type */ - /* should be <=1, need to chek all devices entry in genesys_devices */ - if (yres*4 < dev->motor.base_ydpi || dev->motor.max_step_type <= 0) - { - scan_step_type = 0; - } - else if (yres*4 < dev->motor.base_ydpi*2 || dev->motor.max_step_type <= 1) - { - scan_step_type = 1; - } - else - { - scan_step_type = 2; - } - - /* this motor behaves differently */ - if (dev->model->motor_type==MOTOR_CANONLIDE80) - { - /* driven by 'frequency' tables ? */ - scan_step_type = 0; - } - - return scan_step_type; -} - -/* set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -GENESYS_STATIC -SANE_Status -gl841_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres,/*dpi*/ - float yres,/*dpi*/ - float startx,/*optical_res, from dummy_pixel+1*/ - float starty,/*base_ydpi, from home!*/ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int color_filter, - unsigned int flags - ) -{ - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; - int exposure_time; - int scan_power_mode; - int i; - int stagger; - int avg; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - SANE_Status status; - unsigned int oflags; /**> optical flags */ - - DBG (DBG_info, - "gl841_init_scan_regs settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g/%g\n" - "Depth/Channels: %u/%u\n" - "Flags : %x\n\n", - xres, yres, lines, pixels, - startx, starty, - depth, channels, - flags); - -/* -results: - -for scanner: -half_ccd -start -end -dpiset -exposure_time -dummy -z1 -z2 - -for ordered_read: - dev->words_per_line - dev->read_factor - dev->requested_buffer_size - dev->read_buffer_size - dev->read_pos - dev->read_bytes_in_buffer - dev->read_bytes_left - dev->max_shift - dev->stagger - -independent of our calculated values: - dev->total_bytes_read - dev->bytes_to_read - */ - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if (dev->sensor.optical_res < 2 * xres || - !(dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)) { - half_ccd = SANE_FALSE; - } else { - half_ccd = SANE_TRUE; - } - -/* optical_res */ - - optical_res = dev->sensor.optical_res; - if (half_ccd) - optical_res /= 2; - -/* stagger */ - - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "gl841_init_scan_regs : stagger=%d lines\n", - stagger); - -/* used_res */ - i = optical_res / xres; - -/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ - - if (i < 2 || (flags & SCAN_FLAG_USE_OPTICAL_RES)) /* optical_res >= xres > optical_res/2 */ - used_res = optical_res; - else if (i < 3) /* optical_res/2 >= xres > optical_res/3 */ - used_res = optical_res/2; - else if (i < 4) /* optical_res/3 >= xres > optical_res/4 */ - used_res = optical_res/3; - else if (i < 5) /* optical_res/4 >= xres > optical_res/5 */ - used_res = optical_res/4; - else if (i < 6) /* optical_res/5 >= xres > optical_res/6 */ - used_res = optical_res/5; - else if (i < 8) /* optical_res/6 >= xres > optical_res/8 */ - used_res = optical_res/6; - else if (i < 10) /* optical_res/8 >= xres > optical_res/10 */ - used_res = optical_res/8; - else if (i < 12) /* optical_res/10 >= xres > optical_res/12 */ - used_res = optical_res/10; - else if (i < 15) /* optical_res/12 >= xres > optical_res/15 */ - used_res = optical_res/12; - else - used_res = optical_res/15; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - /* add x coordinates */ - start = ((dev->sensor.CCD_start_xoffset + startx) * used_res) / dev->sensor.optical_res; - - /* needs to be aligned for used_res */ - start = (start * optical_res) / used_res; - - start += dev->sensor.dummy_pixel + 1; - - if (stagger > 0) - start |= 1; - - /* in case of SHDAREA, we need to align start - * on pixel average factor, startx is different of - * 0 only when calling for function to setup for - * scan, where shading data needs to be align */ - if((dev->reg[reg_0x01].value & REG01_SHDAREA) != 0) - { - avg=optical_res/used_res; - start=(start/avg)*avg; - } - - /* compute correct pixels number */ - /* pixels */ - used_pixels = (pixels * optical_res) / xres; - - /* round up pixels number if needed */ - if (used_pixels * xres < pixels * optical_res) - used_pixels++; - -/* dummy */ - /* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1 - dummy line. Maybe the dummy line adds correctness since the motor runs - slower (higher dpi) - */ -/* for cis this creates better aligned color lines: -dummy \ scanned lines - 0: R G B R ... - 1: R G B - R ... - 2: R G B - - R ... - 3: R G B - - - R ... - 4: R G B - - - - R ... - 5: R G B - - - - - R ... - 6: R G B - - - - - - R ... - 7: R G B - - - - - - - R ... - 8: R G B - - - - - - - - R ... - 9: R G B - - - - - - - - - R ... - 10: R G B - - - - - - - - - - R ... - 11: R G B - - - - - - - - - - - R ... - 12: R G B - - - - - - - - - - - - R ... - 13: R G B - - - - - - - - - - - - - R ... - 14: R G B - - - - - - - - - - - - - - R ... - 15: R G B - - - - - - - - - - - - - - - R ... - -- pierre - */ - dummy = 0; - -/* slope_dpi */ -/* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = yres*channels; - else - slope_dpi = yres; - - slope_dpi = slope_dpi * (1 + dummy); - - scan_step_type = gl841_scan_step_type(dev, yres); - exposure_time = gl841_exposure_time(dev, - slope_dpi, - scan_step_type, - start, - used_pixels, - &scan_power_mode); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if(flags & SCAN_FLAG_DYNAMIC_LINEART) - { - depth=8; - } - - oflags=0; - if (flags & SCAN_FLAG_DISABLE_SHADING) - { - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - } - if ((flags & SCAN_FLAG_DISABLE_GAMMA) || (depth==16)) - { - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - } - if (flags & SCAN_FLAG_DISABLE_LAMP) - { - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - } - if (flags & SCAN_FLAG_ENABLE_LEDADD) - { - oflags |= OPTICAL_FLAG_ENABLE_LEDADD; - } - - status = gl841_init_optical_regs_scan(dev, - reg, - exposure_time, - used_res, - start, - used_pixels, - channels, - depth, - half_ccd, - color_filter, - oflags); - if (status != SANE_STATUS_GOOD) - { - return status; - } - -/*** motor parameters ***/ - - /* scanned area must be enlarged by max color shift needed */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,flags); - - /* lincnt */ - lincnt = lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = starty; - DBG (DBG_info, "gl841_init_scan_regs: move=%d steps\n", move); - - /* subtract current head position */ - move -= dev->scanhead_position_in_steps; - DBG (DBG_info, "gl841_init_scan_regs: move=%d steps\n", move); - - if (move < 0) - move = 0; - - /* round it */ -/* the move is not affected by dummy -- pierre */ -/* move = ((move + dummy) / (dummy + 1)) * (dummy + 1); - DBG (DBG_info, "gl841_init_scan_regs: move=%d steps\n", move);*/ - - if (flags & SCAN_FLAG_SINGLE_LINE) - status = gl841_init_motor_regs_off(reg, dev->model->is_cis?lincnt*channels:lincnt); - else - status = gl841_init_motor_regs_scan(dev, - reg, - exposure_time, - slope_dpi, - scan_step_type, - dev->model->is_cis?lincnt*channels:lincnt, - dummy, - move, - scan_power_mode, - (flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE)? - MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE:0 - ); - - if (status != SANE_STATUS_GOOD) - return status; - - - /*** prepares data reordering ***/ - -/* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * channels * depth) / 8; - - requested_buffer_size = 8 * bytes_per_line; - /* we must use a round number of bytes_per_line */ - if (requested_buffer_size > BULKIN_MAXSIZE) - requested_buffer_size = - (BULKIN_MAXSIZE / bytes_per_line) * bytes_per_line; - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * channels * depth) / 8; - - RIE(sanei_genesys_buffer_free(&(dev->read_buffer))); - RIE(sanei_genesys_buffer_alloc(&(dev->read_buffer), read_buffer_size)); - - RIE(sanei_genesys_buffer_free(&(dev->lines_buffer))); - RIE(sanei_genesys_buffer_alloc(&(dev->lines_buffer), read_buffer_size)); - - RIE(sanei_genesys_buffer_free(&(dev->shrink_buffer))); - RIE(sanei_genesys_buffer_alloc(&(dev->shrink_buffer), - requested_buffer_size)); - - RIE(sanei_genesys_buffer_free(&(dev->out_buffer))); - RIE(sanei_genesys_buffer_alloc(&(dev->out_buffer), - (8 * dev->settings.pixels * channels * depth) / 8)); - - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG (DBG_info, - "gl841_init_scan_regs: physical bytes to read = %lu\n", - (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - - dev->current_setup.pixels = (used_pixels * used_res)/optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - -/* TODO: should this be done elsewhere? */ - /* scan bytes to send to the frontend */ - /* theory : - target_size = - (dev->settings.pixels * dev->settings.lines * channels * depth) / 8; - but it suffers from integer overflow so we do the following: - - 1 bit color images store color data byte-wise, eg byte 0 contains - 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains - 8 bits of blue. - This does not fix the overflow, though. - 644mp*16 = 10gp, leading to an overflow - -- pierre - */ - - dev->total_bytes_read = 0; - if (depth == 1) - dev->total_bytes_to_read = - ((dev->settings.pixels * dev->settings.lines) / 8 + - (((dev->settings.pixels * dev->settings.lines)%8)?1:0) - ) * channels; - else - dev->total_bytes_to_read = - dev->settings.pixels * dev->settings.lines * channels * (depth / 8); - - DBG (DBG_info, "gl841_init_scan_regs: total bytes to send = %lu\n", - (u_long) dev->total_bytes_to_read); -/* END TODO */ - - DBG (DBG_proc, "gl841_init_scan_regs: completed\n"); - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_calculate_current_setup (Genesys_Device * dev) -{ - int channels; - int depth; - int start; - - float xres;/*dpi*/ - float yres;/*dpi*/ - float startx;/*optical_res, from dummy_pixel+1*/ - float pixels; - float lines; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure_time; - int scan_power_mode; - int i; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int max_shift; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - - DBG (DBG_info, - "gl841_calculate_current_setup settings:\n" - "Resolution: %uDPI\n" - "Lines : %u\n" - "PPL : %u\n" - "Startpos : %.3f/%.3f\n" - "Scan mode : %d\n\n", - dev->settings.yres, dev->settings.lines, dev->settings.pixels, - dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); - -/* channels */ - if (dev->settings.scan_mode == 4) /* single pass color */ - channels = 3; - else - channels = 1; - -/* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == 0) - depth = 1; - -/* start */ - start = SANE_UNFIX (dev->model->x_offset); - - start += dev->settings.tl_x; - - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - - xres = dev->settings.xres;/*dpi*/ - yres = dev->settings.yres;/*dpi*/ - startx = start;/*optical_res, from dummy_pixel+1*/ - pixels = dev->settings.pixels; - lines = dev->settings.lines; - - DBG (DBG_info, - "gl841_calculate_current_setup settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g\n" - "Depth/Channels: %u/%u\n\n", - xres, yres, lines, pixels, - startx, - depth, channels); - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if ((dev->sensor.optical_res < 2 * xres) || - !(dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)) { - half_ccd = SANE_FALSE; - } else { - half_ccd = SANE_TRUE; - } - -/* optical_res */ - - optical_res = dev->sensor.optical_res; - if (half_ccd) - optical_res /= 2; - -/* stagger */ - - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "gl841_calculate_current_setup: stagger=%d lines\n", - stagger); - -/* used_res */ - i = optical_res / xres; - -/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ - - if (i < 2) /* optical_res >= xres > optical_res/2 */ - used_res = optical_res; - else if (i < 3) /* optical_res/2 >= xres > optical_res/3 */ - used_res = optical_res/2; - else if (i < 4) /* optical_res/3 >= xres > optical_res/4 */ - used_res = optical_res/3; - else if (i < 5) /* optical_res/4 >= xres > optical_res/5 */ - used_res = optical_res/4; - else if (i < 6) /* optical_res/5 >= xres > optical_res/6 */ - used_res = optical_res/5; - else if (i < 8) /* optical_res/6 >= xres > optical_res/8 */ - used_res = optical_res/6; - else if (i < 10) /* optical_res/8 >= xres > optical_res/10 */ - used_res = optical_res/8; - else if (i < 12) /* optical_res/10 >= xres > optical_res/12 */ - used_res = optical_res/10; - else if (i < 15) /* optical_res/12 >= xres > optical_res/15 */ - used_res = optical_res/12; - else - used_res = optical_res/15; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ -/* start */ - /* add x coordinates */ - start = - ((dev->sensor.CCD_start_xoffset + startx) * used_res) / - dev->sensor.optical_res; - -/* needs to be aligned for used_res */ - start = (start * optical_res) / used_res; - - start += dev->sensor.dummy_pixel + 1; - - if (stagger > 0) - start |= 1; - - /* compute correct pixels number */ -/* pixels */ - used_pixels = - (pixels * optical_res) / xres; - - /* round up pixels number if needed */ - if (used_pixels * xres < pixels * optical_res) - used_pixels++; - -/* dummy */ - /* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1 - dummy line. Maybe the dummy line adds correctness since the motor runs - slower (higher dpi) - */ -/* for cis this creates better aligned color lines: -dummy \ scanned lines - 0: R G B R ... - 1: R G B - R ... - 2: R G B - - R ... - 3: R G B - - - R ... - 4: R G B - - - - R ... - 5: R G B - - - - - R ... - 6: R G B - - - - - - R ... - 7: R G B - - - - - - - R ... - 8: R G B - - - - - - - - R ... - 9: R G B - - - - - - - - - R ... - 10: R G B - - - - - - - - - - R ... - 11: R G B - - - - - - - - - - - R ... - 12: R G B - - - - - - - - - - - - R ... - 13: R G B - - - - - - - - - - - - - R ... - 14: R G B - - - - - - - - - - - - - - R ... - 15: R G B - - - - - - - - - - - - - - - R ... - -- pierre - */ - dummy = 0; - -/* slope_dpi */ -/* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = yres*channels; - else - slope_dpi = yres; - - slope_dpi = slope_dpi * (1 + dummy); - - scan_step_type = gl841_scan_step_type(dev, yres); - exposure_time = gl841_exposure_time(dev, - slope_dpi, - scan_step_type, - start, - used_pixels, - &scan_power_mode); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /* scanned area must be enlarged by max color shift needed */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); - - /* lincnt */ - lincnt = lines + max_shift + stagger; - - dev->current_setup.pixels = (used_pixels * used_res)/optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static void -gl841_set_motor_power (Genesys_Register_Set * regs, SANE_Bool set) -{ - - DBG (DBG_proc, "gl841_set_motor_power\n"); - - if (set) - { - sanei_genesys_set_reg_from_set (regs, 0x02, - sanei_genesys_read_reg_from_set (regs, - 0x02) | - REG02_MTRPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, 0x02, - sanei_genesys_read_reg_from_set (regs, - 0x02) & - ~REG02_MTRPWR); - } -} - -static void -gl841_set_lamp_power (Genesys_Device * dev, - Genesys_Register_Set * regs, SANE_Bool set) -{ - Genesys_Register_Set * r; - int i; - - if (set) - { - sanei_genesys_set_reg_from_set (regs, 0x03, - sanei_genesys_read_reg_from_set (regs, - 0x03) | - REG03_LAMPPWR); - - r = sanei_genesys_get_address (regs, 0x10); - for (i = 0; i < 6; i++, r++) { - if (dev->sensor.regs_0x10_0x1d[i] == 0x00) - r->value = 0x01;/*0x00 will not be accepted*/ - else - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - r = sanei_genesys_get_address (regs, 0x19); - r->value = 0x50; - } - else - { - sanei_genesys_set_reg_from_set (regs, 0x03, - sanei_genesys_read_reg_from_set (regs, - 0x03) & - ~REG03_LAMPPWR); - - r = sanei_genesys_get_address (regs, 0x10); - for (i = 0; i < 6; i++, r++) { - r->value = 0x01;/* 0x0101 is as off as possible */ - } - r = sanei_genesys_get_address (regs, 0x19); - r->value = 0xff; - } -} - -/*for fast power saving methods only, like disabling certain amplifiers*/ -static SANE_Status -gl841_save_power(Genesys_Device * dev, SANE_Bool enable) { - uint8_t val; - - DBG(DBG_proc, "gl841_save_power: enable = %d\n", enable); - - if (enable) - { - if (dev->model->gpo_type == GPO_CANONLIDE35) - { -/* expect GPIO17 to be enabled, and GPIO9 to be disabled, - while GPIO8 is disabled*/ -/* final state: GPIO8 disabled, GPIO9 enabled, GPIO17 disabled, - GPIO18 disabled*/ - - sanei_genesys_read_register(dev, REG6D, &val); - sanei_genesys_write_register(dev, REG6D, val | 0x80); - - usleep(1000); - - /*enable GPIO9*/ - sanei_genesys_read_register(dev, REG6C, &val); - sanei_genesys_write_register(dev, REG6C, val | 0x01); - - /*disable GPO17*/ - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO17); - - /*disable GPO18*/ - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO18); - - usleep(1000); - - sanei_genesys_read_register(dev, REG6D, &val); - sanei_genesys_write_register(dev, REG6D, val & ~0x80); - - } - if (dev->model->gpo_type == GPO_DP685) - { - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO17); - dev->reg[reg_0x6b].value &= ~REG6B_GPO17; - dev->calib_reg[reg_0x6b].value &= ~REG6B_GPO17; - } - - gl841_set_fe (dev, AFE_POWER_SAVE); - - } - else - { - if (dev->model->gpo_type == GPO_CANONLIDE35) - { -/* expect GPIO17 to be enabled, and GPIO9 to be disabled, - while GPIO8 is disabled*/ -/* final state: GPIO8 enabled, GPIO9 disabled, GPIO17 enabled, - GPIO18 enabled*/ - - sanei_genesys_read_register(dev, REG6D, &val); - sanei_genesys_write_register(dev, REG6D, val | 0x80); - - usleep(10000); - - /*disable GPIO9*/ - sanei_genesys_read_register(dev, REG6C, &val); - sanei_genesys_write_register(dev, REG6C, val & ~0x01); - - /*enable GPIO10*/ - sanei_genesys_read_register(dev, REG6C, &val); - sanei_genesys_write_register(dev, REG6C, val | 0x02); - - /*enable GPO17*/ - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO17); - dev->reg[reg_0x6b].value |= REG6B_GPO17; - dev->calib_reg[reg_0x6b].value |= REG6B_GPO17; - - /*enable GPO18*/ - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO18); - dev->reg[reg_0x6b].value |= REG6B_GPO18; - dev->calib_reg[reg_0x6b].value |= REG6B_GPO18; - - } - if (dev->model->gpo_type == GPO_DP665 - || dev->model->gpo_type == GPO_DP685) - { - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO17); - dev->reg[reg_0x6b].value |= REG6B_GPO17; - dev->calib_reg[reg_0x6b].value |= REG6B_GPO17; - } - - } - - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_set_powersaving (Genesys_Device * dev, - int delay /* in minutes */ ) -{ - SANE_Status status; - Genesys_Register_Set local_reg[7]; - int rate, exposure_time, tgtime, time; - - DBG (DBG_proc, "gl841_set_powersaving (delay = %d)\n", delay); - - local_reg[0].address = 0x01; - local_reg[0].value = sanei_genesys_read_reg_from_set (dev->reg, 0x01); /* disable fastmode */ - - local_reg[1].address = 0x03; - local_reg[1].value = sanei_genesys_read_reg_from_set (dev->reg, 0x03); /* Lamp power control */ - - local_reg[2].address = 0x05; - local_reg[2].value = sanei_genesys_read_reg_from_set (dev->reg, 0x05) /*& ~REG05_BASESEL*/; /* 24 clocks/pixel */ - - local_reg[3].address = 0x18; /* Set CCD type */ - local_reg[3].value = 0x00; - - local_reg[4].address = 0x38; /* line period low */ - local_reg[4].value = 0x00; - - local_reg[5].address = 0x39; /* line period high */ - local_reg[5].value = 0x00; - - local_reg[6].address = 0x1c; /* period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE */ - local_reg[6].value = sanei_genesys_read_reg_from_set (dev->reg, 0x05) & ~REG1C_TGTIME; - - if (!delay) - local_reg[1].value = local_reg[1].value & 0xf0; /* disable lampdog and set lamptime = 0 */ - else if (delay < 20) - local_reg[1].value = (local_reg[1].value & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ - else - local_reg[1].value = (local_reg[1].value & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ - - time = delay * 1000 * 60; /* -> msec */ - exposure_time = - (uint32_t) (time * 32000.0 / - (24.0 * 64.0 * (local_reg[1].value & REG03_LAMPTIM) * - 1024.0) + 0.5); - /* 32000 = system clock, 24 = clocks per pixel */ - rate = (exposure_time + 65536) / 65536; - if (rate > 4) - { - rate = 8; - tgtime = 3; - } - else if (rate > 2) - { - rate = 4; - tgtime = 2; - } - else if (rate > 1) - { - rate = 2; - tgtime = 1; - } - else - { - rate = 1; - tgtime = 0; - } - - local_reg[6].value |= tgtime; - exposure_time /= rate; - - if (exposure_time > 65535) - exposure_time = 65535; - - local_reg[4].value = exposure_time >> 8; /* highbyte */ - local_reg[5].value = exposure_time & 255; /* lowbyte */ - - status = - gl841_bulk_write_register (dev, local_reg, - sizeof (local_reg)/sizeof (local_reg[0])); - if (status != SANE_STATUS_GOOD) - DBG (DBG_error, - "gl841_set_powersaving: failed to bulk write registers: %s\n", - sane_strstatus (status)); - - DBG (DBG_proc, "gl841_set_powersaving: completed\n"); - return status; -} - -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl841_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl841_stop_action (Genesys_Device * dev) -{ - Genesys_Register_Set local_reg[GENESYS_GL841_MAX_REGS+1]; - SANE_Status status; - uint8_t val40, val; - unsigned int loop; - - DBG (DBG_proc, "%s\n", __func__); - - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - status = sanei_genesys_read_register(dev, 0x40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n",__func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBG (DBG_info, "%s: already stopped\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - memcpy (local_reg, dev->reg, (GENESYS_GL841_MAX_REGS+1) * sizeof (Genesys_Register_Set)); - - gl841_init_optical_regs_off(local_reg); - - gl841_init_motor_regs_off(local_reg,0); - status = gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* looks like writing the right registers to zero is enough to get the chip - out of scan mode into command mode, actually triggering(writing to - register 0x0f) seems to be unnecessary */ - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_read_register(dev, 0x40, &val40); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n",__func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - usleep(100*1000); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - -static SANE_Status -gl841_get_paper_sensor(Genesys_Device * dev, SANE_Bool * paper_loaded) -{ - SANE_Status status; - uint8_t val; - - status = sanei_genesys_read_register(dev, REG6D, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_get_paper_sensor: failed to read gpio: %s\n", - sane_strstatus (status)); - return status; - } - *paper_loaded = (val & 0x1) == 0; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_eject_document (Genesys_Device * dev) -{ - Genesys_Register_Set local_reg[GENESYS_GL841_MAX_REGS+1]; - SANE_Status status; - uint8_t val; - SANE_Bool paper_loaded; - unsigned int init_steps; - float feed_mm; - int loop; - - DBG (DBG_proc, "gl841_eject_document\n"); - - if (dev->model->is_sheetfed == SANE_FALSE) - { - DBG (DBG_proc, "gl841_eject_document: there is no \"eject sheet\"-concept for non sheet fed\n"); - DBG (DBG_proc, "gl841_eject_document: finished\n"); - return SANE_STATUS_GOOD; - } - - - memset (local_reg, 0, sizeof (local_reg)); - val = 0; - - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_eject_document: failed to read status register: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_eject_document: failed to stop motor: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - memcpy (local_reg, dev->reg, (GENESYS_GL841_MAX_REGS+1) * sizeof (Genesys_Register_Set)); - - gl841_init_optical_regs_off(local_reg); - - gl841_init_motor_regs(dev,local_reg, - 65536,MOTOR_ACTION_FEED,0); - - status = - gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_eject_document: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl841_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_eject_document: failed to start motor: %s\n", - sane_strstatus (status)); - gl841_stop_action (dev); - /* send original registers */ - gl841_bulk_write_register (dev, dev->reg, GENESYS_GL841_MAX_REGS); - return status; - } - - RIE(gl841_get_paper_sensor(dev, &paper_loaded)); - if (paper_loaded) - { - DBG (DBG_info, - "gl841_eject_document: paper still loaded\n"); - /* force document TRUE, because it is definitely present */ - dev->document = SANE_TRUE; - dev->scanhead_position_in_steps = 0; - - loop = 300; - while (loop > 0) /* do not wait longer then 30 seconds */ - { - - RIE(gl841_get_paper_sensor(dev, &paper_loaded)); - - if (!paper_loaded) - { - DBG (DBG_info, - "gl841_eject_document: reached home position\n"); - DBG (DBG_proc, "gl841_eject_document: finished\n"); - break; - } - usleep (100000); /* sleep 100 ms */ - --loop; - } - - if (loop == 0) - { - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl841_stop_action (dev); - DBG (DBG_error, - "gl841_eject_document: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; - } - } - - feed_mm = SANE_UNFIX(dev->model->eject_feed); - if (dev->document) - { - feed_mm += SANE_UNFIX(dev->model->post_scan); - } - - status = sanei_genesys_read_feed_steps(dev, &init_steps); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_eject_document: failed to read feed steps: %s\n", - sane_strstatus (status)); - return status; - } - - /* now feed for extra steps */ - loop = 0; - while (loop < 300) /* do not wait longer then 30 seconds */ - { - unsigned int steps; - - status = sanei_genesys_read_feed_steps(dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_eject_document: failed to read feed steps: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_info, "gl841_eject_document: init_steps: %d, steps: %d\n", - init_steps, steps); - - if (steps > init_steps + (feed_mm * dev->motor.base_ydpi) / MM_PER_INCH) - { - break; - } - - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - status = gl841_stop_action(dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_eject_document: failed to stop motor: %s\n", - sane_strstatus (status)); - return status; - } - - dev->document = SANE_FALSE; - - DBG (DBG_proc, "gl841_eject_document: finished\n"); - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl841_load_document (Genesys_Device * dev) -{ - SANE_Status status; - SANE_Bool paper_loaded; - int loop = 300; - DBG (DBG_proc, "gl841_load_document\n"); - while (loop > 0) /* do not wait longer then 30 seconds */ - { - - RIE(gl841_get_paper_sensor(dev, &paper_loaded)); - - if (paper_loaded) - { - DBG (DBG_info, - "gl841_load_document: document inserted\n"); - - /* when loading OK, document is here */ - dev->document = SANE_TRUE; - - usleep (1000000); /* give user 1000ms to place document correctly */ - break; - } - usleep (100000); /* sleep 100 ms */ - --loop; - } - - if (loop == 0) - { - /* when we come here then the user needed to much time for this */ - DBG (DBG_error, - "gl841_load_document: timeout while waiting for document\n"); - return SANE_STATUS_IO_ERROR; - } - - DBG (DBG_proc, "gl841_load_document: finished\n"); - return SANE_STATUS_GOOD; -} - -/** - * detects end of document and adjust current scan - * to take it into account - * used by sheetfed scanners - */ -static SANE_Status -gl841_detect_document_end (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool paper_loaded; - unsigned int scancnt = 0, lincnt, postcnt; - uint8_t val; - size_t total_bytes_to_read; - - DBG (DBG_proc, "%s: begin\n", __func__); - - RIE (gl841_get_paper_sensor (dev, &paper_loaded)); - - /* sheetfed scanner uses home sensor as paper present */ - if ((dev->document == SANE_TRUE) && !paper_loaded) - { - DBG (DBG_info, "%s: no more document\n", __func__); - dev->document = SANE_FALSE; - - /* we can't rely on total_bytes_to_read since the frontend - * might have been slow to read data, so we re-evaluate the - * amount of data to scan form the hardware settings - */ - status=sanei_genesys_read_scancnt(dev,&scancnt); - if(status!=SANE_STATUS_GOOD) - { - dev->total_bytes_to_read = dev->total_bytes_read; - dev->read_bytes_left = 0; - DBG (DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; - } - if (dev->settings.scan_mode == SCAN_MODE_COLOR && dev->model->is_cis) - { - scancnt/=3; - } - DBG (DBG_io, "%s: scancnt=%u lines\n",__func__, scancnt); - - RIE(sanei_genesys_read_register(dev, 0x25, &val)); - lincnt=65536*val; - RIE(sanei_genesys_read_register(dev, 0x26, &val)); - lincnt+=256*val; - RIE(sanei_genesys_read_register(dev, 0x27, &val)); - lincnt+=val; - DBG (DBG_io, "%s: lincnt=%u lines\n",__func__, lincnt); - postcnt=(SANE_UNFIX(dev->model->post_scan)/MM_PER_INCH)*dev->settings.yres; - DBG (DBG_io, "%s: postcnt=%u lines\n",__func__, postcnt); - - /* the current scancnt is also the final one, so we use it to - * compute total bytes to read. We also add the line count to eject document */ - total_bytes_to_read=(scancnt+postcnt)*dev->wpl; - - DBG (DBG_io, "%s: old total_bytes_to_read=%u\n",__func__,(unsigned int)dev->total_bytes_to_read); - DBG (DBG_io, "%s: new total_bytes_to_read=%u\n",__func__,(unsigned int)total_bytes_to_read); - - /* assign new end value */ - if(dev->total_bytes_to_read>total_bytes_to_read) - { - DBG (DBG_io, "%s: scan shorten\n",__func__); - dev->total_bytes_to_read=total_bytes_to_read; - } - } - - DBG (DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - -/* Send the low-level scan command */ -/* todo : is this that useful ? */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl841_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - SANE_Status status; - Genesys_Register_Set local_reg[4]; - uint8_t val; - - DBG (DBG_proc, "gl841_begin_scan\n"); - - if (dev->model->gpo_type == GPO_CANONLIDE80) - { - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - val = REG6B_GPO18; - RIE (sanei_genesys_write_register (dev, REG6B, val)); - } - - local_reg[0].address = 0x03; - if (dev->model->ccd_type != CCD_PLUSTEK_3600) - { - local_reg[0].value = sanei_genesys_read_reg_from_set (reg, 0x03) | REG03_LAMPPWR; - } - else - { - local_reg[0].value = sanei_genesys_read_reg_from_set (reg, 0x03); /* TODO PLUSTEK_3600: why ?? */ - } - - local_reg[1].address = 0x01; - local_reg[1].value = sanei_genesys_read_reg_from_set (reg, 0x01) | REG01_SCAN; /* set scan bit */ - - local_reg[2].address = 0x0d; - local_reg[2].value = 0x01; - - local_reg[3].address = 0x0f; - if (start_motor) - local_reg[3].value = 0x01; - else - local_reg[3].value = 0x00; /* do not start motor yet */ - - status = - gl841_bulk_write_register (dev, local_reg, - sizeof (local_reg)/sizeof (local_reg[0])); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_begin_scan: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "gl841_begin_scan: completed\n"); - - return status; -} - - -/* Send the stop scan command */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl841_end_scan (Genesys_Device * dev, Genesys_Register_Set __sane_unused__ * reg, - SANE_Bool check_stop) -{ - SANE_Status status; - - DBG (DBG_proc, "gl841_end_scan (check_stop = %d)\n", check_stop); - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_end_scan: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - } - - DBG (DBG_proc, "gl841_end_scan: completed\n"); - - return status; -} - -/* Moves the slider to steps */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl841_feed (Genesys_Device * dev, int steps) -{ - Genesys_Register_Set local_reg[GENESYS_GL841_MAX_REGS+1]; - SANE_Status status; - uint8_t val; - int loop; - - DBG (DBG_proc, "gl841_feed (steps = %d)\n", steps); - - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl841_feed: failed to stop action: %s\n", - sane_strstatus (status)); - return status; - } - - memcpy (local_reg, dev->reg, (GENESYS_GL841_MAX_REGS+1) * sizeof (Genesys_Register_Set)); - - gl841_init_optical_regs_off(local_reg); - - gl841_init_motor_regs(dev,local_reg, steps,MOTOR_ACTION_FEED,0); - - status = gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_feed: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl841_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_feed: failed to start motor: %s\n", - sane_strstatus (status)); - gl841_stop_action (dev); - /* send original registers */ - gl841_bulk_write_register (dev, dev->reg, GENESYS_GL841_MAX_REGS); - return status; - } - - loop = 0; - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_feed: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - - if (!(val & REG41_MOTORENB)) /* motor enabled */ - { - DBG (DBG_proc, "gl841_feed: finished\n"); - dev->scanhead_position_in_steps += steps; - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl841_stop_action (dev); - - DBG (DBG_error, - "gl841_feed: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; -} - -/* Moves the slider to the home (top) position slowly */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl841_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg[GENESYS_GL841_MAX_REGS+1]; - SANE_Status status; - Genesys_Register_Set *r; - uint8_t val; - int loop = 0; - - DBG (DBG_proc, "gl841_slow_back_home (wait_until_home = %d)\n", - wait_until_home); - - if (dev->model->is_sheetfed == SANE_TRUE) - { - DBG (DBG_proc, "gl841_slow_back_home: there is no \"home\"-concept for sheet fed\n"); - DBG (DBG_proc, "gl841_slow_back_home: finished\n"); - return SANE_STATUS_GOOD; - } - - /* reset gpio pin */ - if (dev->model->gpo_type == GPO_CANONLIDE35) - { - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val = dev->gpo.value[0]; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - } - if (dev->model->gpo_type == GPO_CANONLIDE80) - { - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - val = REG6B_GPO18 | REG6B_GPO17; - RIE (sanei_genesys_write_register (dev, REG6B, val)); - } - gl841_save_power(dev, SANE_FALSE); - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - usleep (100000); /* sleep 100 ms */ - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - dev->scanhead_position_in_steps = 0; - - if (val & REG41_HOMESNR) /* is sensor at home? */ - { - DBG (DBG_info, - "gl841_slow_back_home: already at home, completed\n"); - dev->scanhead_position_in_steps = 0; - return SANE_STATUS_GOOD; - } - - /* end previous scan if any */ - r = sanei_genesys_get_address (dev->reg, REG01); - r->value &= ~REG01_SCAN; - status = sanei_genesys_write_register (dev, REG01, r->value); - - /* if motor is on, stop current action */ - if (val & REG41_MOTORENB) - { - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_slow_back_home: failed to stop motor: %s\n", - sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - } - - memcpy (local_reg, dev->reg, (GENESYS_GL841_MAX_REGS+1) * sizeof (Genesys_Register_Set)); - - gl841_init_motor_regs(dev,local_reg, 65536,MOTOR_ACTION_GO_HOME,0); - - /* set up for reverse and no scan */ - r = sanei_genesys_get_address (local_reg, REG02); - r->value |= REG02_MTRREV; - r = sanei_genesys_get_address (local_reg, REG01); - r->value &= ~REG01_SCAN; - - RIE (gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS)); - - status = gl841_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_slow_back_home: failed to start motor: %s\n", - sane_strstatus (status)); - gl841_stop_action (dev); - /* send original registers */ - gl841_bulk_write_register (dev, dev->reg, GENESYS_GL841_MAX_REGS); - return status; - } - - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - - if (val & REG41_HOMESNR) /* home sensor */ - { - DBG (DBG_info, "gl841_slow_back_home: reached home position\n"); - DBG (DBG_proc, "gl841_slow_back_home: finished\n"); - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl841_stop_action (dev); - DBG (DBG_error, - "gl841_slow_back_home: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; - } - - DBG (DBG_info, "gl841_slow_back_home: scanhead is still moving\n"); - DBG (DBG_proc, "gl841_slow_back_home: finished\n"); - return SANE_STATUS_GOOD; -} - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl841_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status; - uint8_t *data; - Genesys_Register_Set local_reg[GENESYS_GL841_MAX_REGS+1]; - int steps; - - int pixels = 600; - int dpi = 300; - - DBGSTART; - - memcpy (local_reg, dev->reg, (GENESYS_GL841_MAX_REGS +1) * sizeof (Genesys_Register_Set)); - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - status = gl841_init_scan_regs (dev, - local_reg, - dpi, - dpi, - 0, - 0,/*we should give a small offset here~60 steps*/ - 600, - dev->model->search_lines, - 8, - 1, - 1,/*green*/ - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE); - if(status!=SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to init scan registers: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* send to scanner */ - status = - gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - size = pixels * dev->model->search_lines; - - data = malloc (size); - if (!data) - { - DBG (DBG_error, - "gl841_search_start_position: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - status = gl841_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl841_search_start_position: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl841_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("search_position.pnm", data, 8, 1, pixels, - dev->model->search_lines); - - status = gl841_end_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl841_search_start_position: failed to end scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* update regs to copy ASIC internal state */ - memcpy (dev->reg, local_reg, (GENESYS_GL841_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - -/*TODO: find out where sanei_genesys_search_reference_point - stores information, and use that correctly*/ - status = - sanei_genesys_search_reference_point (dev, data, 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl841_search_start_position: failed to set search reference point: %s\n", - sane_strstatus (status)); - return status; - } - - free (data); - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl841_init_regs_for_coarse_calibration (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t channels; - uint8_t cksel; - - DBGSTART; - - cksel = (dev->calib_reg[reg_0x18].value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - status = gl841_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - dev->sensor.optical_res / cksel, /* XXX STEF XXX !!! */ - 20, - 16, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE - ); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_init_register_for_coarse_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_info, - "gl841_init_register_for_coarse_calibration: optical sensor res: %d dpi, actual res: %d\n", - dev->sensor.optical_res / cksel, dev->settings.xres); - - status = - gl841_bulk_write_register (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_init_register_for_coarse_calibration: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - -/* if (DBG_LEVEL >= DBG_info) - sanei_gl841_print_registers (dev->calib_reg);*/ - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -static SANE_Status -gl841_init_regs_for_shading (Genesys_Device * dev) -{ - SANE_Status status; - SANE_Int ydpi; - float starty=0; - - DBGSTART; - DBG (DBG_proc, "%s: lines = %d\n", __func__, (int)(dev->calib_lines)); - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL841_MAX_REGS * sizeof (Genesys_Register_Set)); - - ydpi = dev->motor.base_ydpi; - if (dev->model->motor_type == MOTOR_PLUSTEK_3600) /* TODO PLUSTEK_3600: 1200dpi not yet working, produces dark bar */ - { - ydpi = 600; - } - if (dev->model->motor_type == MOTOR_CANONLIDE80) - { - ydpi = gl841_get_dpihw(dev); - /* get over extra dark area for this model */ - starty = 140; - } - - dev->calib_channels = 3; - dev->calib_lines = dev->model->shading_lines; - status = gl841_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - ydpi, - 0, - starty, - (dev->sensor.sensor_pixels * dev->settings.xres) / dev->sensor.optical_res, - dev->calib_lines, - 16, - dev->calib_channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_USE_OPTICAL_RES | - /*SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE |*/ - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - dev->calib_pixels = dev->current_setup.pixels; - dev->scanhead_position_in_steps += dev->calib_lines + starty; - - status = gl841_bulk_write_register (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* set up registers for the actual scan - */ -static SANE_Status -gl841_init_regs_for_scan (Genesys_Device * dev) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status; - - DBG (DBG_info, - "gl841_init_regs_for_scan settings:\nResolution: %uDPI\n" - "Lines : %u\nPPL : %u\nStartpos : %.3f/%.3f\nScan mode : %d\n\n", - dev->settings.yres, dev->settings.lines, dev->settings.pixels, - dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); - - gl841_slow_back_home(dev,SANE_TRUE); - -/* channels */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - -/* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == SCAN_MODE_LINEART) - depth = 1; - - - /* steps to move to reach scanning area: - - first we move to physical start of scanning - either by a fixed steps amount from the black strip - or by a fixed amount from parking position, - minus the steps done during shading calibration - - then we move by the needed offset whitin physical - scanning area - - assumption: steps are expressed at maximum motor resolution - - we need: - SANE_Fixed y_offset; - SANE_Fixed y_size; - SANE_Fixed y_offset_calib; - mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ - - /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is - relative from origin, else, it is from parking position */ - - move_dpi = dev->motor.base_ydpi; - - move = 0; - if (dev->model->flags & GENESYS_FLAG_SEARCH_START) - { - move += SANE_UNFIX (dev->model->y_offset_calib); - } - - DBG (DBG_info, "gl841_init_regs_for_scan: move=%f steps\n", move); - - move += SANE_UNFIX (dev->model->y_offset); - DBG (DBG_info, "gl841_init_regs_for_scan: move=%f steps\n", move); - - move += dev->settings.tl_y; - DBG (DBG_info, "gl841_init_regs_for_scan: move=%f steps\n", move); - - move = (move * move_dpi) / MM_PER_INCH; - -/* start */ - start = SANE_UNFIX (dev->model->x_offset); - - start += dev->settings.tl_x; - - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - flags=0; - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - flags = 0; - - /* true gray (led add for cis scanners) */ - if(dev->model->is_cis && dev->settings.true_gray - && dev->settings.scan_mode != SCAN_MODE_COLOR) - { - DBG (DBG_io, "%s: activating LEDADD\n", __func__); - flags |= SCAN_FLAG_ENABLE_LEDADD; - } - - /* enable emulated lineart from gray data */ - if(dev->settings.scan_mode == SCAN_MODE_LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - status = gl841_init_scan_regs (dev, - dev->reg, - dev->settings.xres, - dev->settings.yres, - start, - move, - dev->settings.pixels, - dev->settings.lines, - depth, - channels, - dev->settings.color_filter, - flags); - - if (status != SANE_STATUS_GOOD) - return status; - - - DBG (DBG_proc, "gl841_init_register_for_scan: completed\n"); - return SANE_STATUS_GOOD; -} - -/* - * this function sends generic gamma table (ie linear ones) - * or the Sensor specific one if provided - */ -static SANE_Status -gl841_send_gamma_table (Genesys_Device * dev) -{ - int size; - SANE_Status status; - uint8_t *gamma; - - DBGSTART; - - size = 256; - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - gamma = (uint8_t *) malloc (size * 2 * 3); - if (gamma==NULL) - { - return SANE_STATUS_NO_MEM; - } - - RIE(sanei_genesys_generate_gamma_buffer(dev, 16, 65535, size, gamma)); - - /* send address */ - status = gl841_set_buffer_address_gamma (dev, 0x00000); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "gl841_send_gamma_table: failed to set buffer address: %s\n", - sane_strstatus (status)); - return status; - } - - /* send data */ - status = gl841_bulk_write_data_gamma (dev, 0x28, (uint8_t *) gamma, size * 2 * 3); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "gl841_send_gamma_table: failed to send gamma table: %s\n", - sane_strstatus (status)); - return status; - } - - free (gamma); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* this function does the led calibration by scanning one line of the calibration - area below scanner's top on white strip. - --needs working coarse/gain -*/ -GENESYS_STATIC SANE_Status -gl841_led_calibration (Genesys_Device * dev) -{ - int num_pixels; - int total_size; - uint8_t *line; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels; - int avg[3], avga, avge; - int turn; - char fn[20]; - uint16_t exp[3], target; - Genesys_Register_Set *r; - int move; - - SANE_Bool acceptable = SANE_FALSE; - - /* these 2 boundaries should be per sensor */ - uint16_t min_exposure=500; - uint16_t max_exposure; - - DBGSTART; - - /* feed to white strip if needed */ - if (dev->model->y_offset_calib>0) - { - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * (dev->motor.base_ydpi)) / MM_PER_INCH; - DBG (DBG_io, "%s: move=%d lines\n", __func__, move); - status = gl841_feed(dev, move); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to feed: %s\n", __func__, - sane_strstatus (status)); - return status; - } - } - - /* offset calibration is always done in color mode */ - channels = 3; - - status = gl841_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - (dev->sensor.sensor_pixels*dev->settings.xres) / dev->sensor.optical_res, - 1, - 16, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES - ); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to setup scan: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - RIE (gl841_bulk_write_register(dev, dev->calib_reg, GENESYS_GL841_MAX_REGS)); - - num_pixels = dev->current_setup.pixels; - - total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ - - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - */ - - exp[0] = (dev->sensor.regs_0x10_0x1d[0] << 8) | dev->sensor.regs_0x10_0x1d[1]; - exp[1] = (dev->sensor.regs_0x10_0x1d[2] << 8) | dev->sensor.regs_0x10_0x1d[3]; - exp[2] = (dev->sensor.regs_0x10_0x1d[4] << 8) | dev->sensor.regs_0x10_0x1d[5]; - - turn = 0; - /* max exposure is set to ~2 time initial average - * exposure, or 2 time last calibration exposure */ - max_exposure=((exp[0]+exp[1]+exp[2])/3)*2; - target=dev->sensor.gain_white_ref*256; - - do { - - dev->sensor.regs_0x10_0x1d[0] = (exp[0] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[1] = exp[0] & 0xff; - dev->sensor.regs_0x10_0x1d[2] = (exp[1] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[3] = exp[1] & 0xff; - dev->sensor.regs_0x10_0x1d[4] = (exp[2] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[5] = exp[2] & 0xff; - - r = &(dev->calib_reg[reg_0x10]); - for (i = 0; i < 6; i++, r++) { - r->value = dev->sensor.regs_0x10_0x1d[i]; - RIE (sanei_genesys_write_register (dev, 0x10+i, dev->sensor.regs_0x10_0x1d[i])); - } - - RIE (gl841_bulk_write_register (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS)); - - DBG (DBG_info, "%s: starting line reading\n", __func__); - RIE (gl841_begin_scan (dev, dev->calib_reg, SANE_TRUE)); - RIE (sanei_genesys_read_data_from_scanner (dev, line, total_size)); - - if (DBG_LEVEL >= DBG_data) { - snprintf(fn,20,"led_%d.pnm",turn); - sanei_genesys_write_pnm_file (fn, - line, - 16, - channels, - num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG(DBG_info,"%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - acceptable = SANE_TRUE; - - /* exposure is acceptable if each color is in the %5 range - * of other color channels */ - if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || - avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || - avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) - { - acceptable = SANE_FALSE; - } - - /* led exposure is not acceptable if white level is too low - * ~80 hardcoded value for white level */ - if(avg[0]<20000 || avg[1]<20000 || avg[2]<20000) - { - acceptable = SANE_FALSE; - } - - /* for scanners using target value */ - if(target>0) - { - acceptable = SANE_TRUE; - for(i=0;i<3;i++) - { - /* we accept +- 2% delta from target */ - if(abs(avg[i]-target)>target/50) - { - exp[i]=(exp[i]*target)/avg[i]; - acceptable = SANE_FALSE; - } - } - } - else - { - if (!acceptable) - { - avga = (avg[0]+avg[1]+avg[2])/3; - exp[0] = (exp[0] * avga) / avg[0]; - exp[1] = (exp[1] * avga) / avg[1]; - exp[2] = (exp[2] * avga) / avg[2]; - /* - keep the resulting exposures below this value. - too long exposure drives the ccd into saturation. - we may fix this by relying on the fact that - we get a striped scan without shading, by means of - statistical calculation - */ - avge = (exp[0] + exp[1] + exp[2]) / 3; - - if (avge > max_exposure) { - exp[0] = (exp[0] * max_exposure) / avge; - exp[1] = (exp[1] * max_exposure) / avge; - exp[2] = (exp[2] * max_exposure) / avge; - } - if (avge < min_exposure) { - exp[0] = (exp[0] * min_exposure) / avge; - exp[1] = (exp[1] * min_exposure) / avge; - exp[2] = (exp[2] * min_exposure) / avge; - } - - } - } - - RIE (gl841_stop_action (dev)); - - turn++; - - } while (!acceptable && turn < 100); - - DBG(DBG_info,"%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0],exp[1],exp[2]); - - /* cleanup before return */ - free (line); - - gl841_slow_back_home(dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - -/** @brief calibration for AD frontend devices - * offset calibration assumes that the scanning head is on a black area - * For LiDE80 analog frontend - * 0x0003 : is gain and belongs to [0..63] - * 0x0006 : is offset - * We scan a line with no gain until average offset reaches the target - */ -static SANE_Status -ad_fe_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int num_pixels; - int total_size; - uint8_t *line; - int i; - int average; - int turn; - char fn[20]; - int top; - int bottom; - int target; - - DBGSTART; - - /* don't impact 3600 behavior since we can't test it */ - if (dev->model->ccd_type == CCD_PLUSTEK_3600) - { - DBGCOMPLETED; - return status; - } - - status = gl841_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - (dev->sensor.sensor_pixels*dev->settings.xres) / dev->sensor.optical_res, - 1, - 8, - 3, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_offset_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - num_pixels = dev->current_setup.pixels; - total_size = num_pixels * 3 * 2 * 1; - - line = malloc (total_size); - if (line==NULL) - { - DBGCOMPLETED; - return SANE_STATUS_NO_MEM; - } - - dev->frontend.gain[0] = 0x00; - dev->frontend.gain[1] = 0x00; - dev->frontend.gain[2] = 0x00; - - /* loop on scan until target offset is reached */ - turn=0; - target=24; - bottom=0; - top=255; - do { - /* set up offset mid range */ - dev->frontend.offset[0] = (top+bottom)/2; - dev->frontend.offset[1] = (top+bottom)/2; - dev->frontend.offset[2] = (top+bottom)/2; - - /* scan line */ - DBG (DBG_info, "%s: starting line reading\n",__func__); - gl841_bulk_write_register (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS); - gl841_set_fe(dev, AFE_SET); - gl841_begin_scan (dev, dev->calib_reg, SANE_TRUE); - sanei_genesys_read_data_from_scanner (dev, line, total_size); - gl841_stop_action (dev); - if (DBG_LEVEL >= DBG_data) { - snprintf(fn,20,"offset_%02d.pnm",turn); - sanei_genesys_write_pnm_file (fn, line, 8, 3, num_pixels, 1); - } - - /* search for minimal value */ - average=0; - for(i=0;itarget) - { - top=(top+bottom)/2; - } - else - { - bottom=(top+bottom)/2; - } - turn++; - } while ((top-bottom)>1 && turn < 100); - - dev->frontend.offset[0]=0; - dev->frontend.offset[1]=0; - dev->frontend.offset[2]=0; - free(line); - DBG (DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.offset[0], - dev->frontend.offset[1], - dev->frontend.offset[2]); - DBGCOMPLETED; - return status; -} - -/* this function does the offset calibration by scanning one line of the calibration - area below scanner's top. There is a black margin and the remaining is white. - sanei_genesys_search_start() must have been called so that the offsets and margins - are allready known. - -this function expects the slider to be where? -*/ -GENESYS_STATIC SANE_Status -gl841_offset_calibration (Genesys_Device * dev) -{ - int num_pixels; - int total_size; - uint8_t *first_line, *second_line; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels; - int off[3],offh[3],offl[3],off1[3],off2[3]; - int min1[3],min2[3]; - int cmin[3],cmax[3]; - int turn; - char fn[20]; - SANE_Bool acceptable = SANE_FALSE; - int mintgt = 0x400; - - DBG (DBG_proc, "gl841_offset_calibration\n"); - - /* Analog Device fronted have a different calibration */ - if ((dev->reg[reg_0x04].value & REG04_FESET) == 0x02) - { - return ad_fe_offset_calibration (dev); - } - - /* offset calibration is always done in color mode */ - channels = 3; - - status = gl841_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - (dev->sensor.sensor_pixels*dev->settings.xres) / dev->sensor.optical_res, - 1, - 16, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES | - SCAN_FLAG_DISABLE_LAMP - ); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_offset_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - num_pixels = dev->current_setup.pixels; - - total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ - - first_line = malloc (total_size); - if (!first_line) - return SANE_STATUS_NO_MEM; - - second_line = malloc (total_size); - if (!second_line) - { - free (first_line); - return SANE_STATUS_NO_MEM; - } - - /* scan first line of data with no offset nor gain */ -/*WM8199: gain=0.73; offset=-260mV*/ -/*okay. the sensor black level is now at -260mV. we only get 0 from AFE...*/ -/* we should probably do real calibration here: - * -detect acceptable offset with binary search - * -calculate offset from this last version - * - * acceptable offset means - * - few completely black pixels(<10%?) - * - few completely white pixels(<10%?) - * - * final offset should map the minimum not completely black - * pixel to 0(16 bits) - * - * this does account for dummy pixels at the end of ccd - * this assumes slider is at black strip(which is not quite as black as "no - * signal"). - * - */ - dev->frontend.gain[0] = 0x00; - dev->frontend.gain[1] = 0x00; - dev->frontend.gain[2] = 0x00; - offh[0] = 0xff; - offh[1] = 0xff; - offh[2] = 0xff; - offl[0] = 0x00; - offl[1] = 0x00; - offl[2] = 0x00; - turn = 0; - - do { - - RIEF2 (gl841_bulk_write_register - (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS), first_line, second_line); - - for (j=0; j < channels; j++) { - off[j] = (offh[j]+offl[j])/2; - dev->frontend.offset[j] = off[j]; - } - - status = gl841_set_fe(dev, AFE_SET); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_offset_calibration: failed to setup frontend: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_info, - "gl841_offset_calibration: starting first line reading\n"); - RIEF2 (gl841_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - - RIEF2 (sanei_genesys_read_data_from_scanner (dev, first_line, total_size), first_line, second_line); - - if (DBG_LEVEL >= DBG_data) { - snprintf(fn,20,"offset1_%02d.pnm",turn); - sanei_genesys_write_pnm_file (fn, - first_line, - 16, - channels, - num_pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - cmin[j] = 0; - cmax[j] = 0; - - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - first_line[i * 2 + j * 2 * num_pixels]; - else - val = - first_line[i * 2 * channels + 2 * j + 1] * 256 + - first_line[i * 2 * channels + 2 * j]; - if (val < 10) - cmin[j]++; - if (val > 65525) - cmax[j]++; - } - - /* TODO the DP685 has a black strip in the middle of the sensor - * should be handled in a more elegant way , could be a bug */ - if (dev->model->ccd_type == CCD_DP685) - cmin[j] -= 20; - - if (cmin[j] > num_pixels/100) { - acceptable = SANE_FALSE; - if (dev->model->is_cis) - offl[0] = off[0]; - else - offl[j] = off[j]; - } - if (cmax[j] > num_pixels/100) { - acceptable = SANE_FALSE; - if (dev->model->is_cis) - offh[0] = off[0]; - else - offh[j] = off[j]; - } - } - - DBG(DBG_info,"gl841_offset_calibration: black/white pixels: " - "%d/%d,%d/%d,%d/%d\n", - cmin[0],cmax[0],cmin[1],cmax[1],cmin[2],cmax[2]); - - if (dev->model->is_cis) { - offh[2] = offh[1] = offh[0]; - offl[2] = offl[1] = offl[0]; - } - - RIEF2 (gl841_stop_action (dev), first_line, second_line); - - turn++; - } while (!acceptable && turn < 100); - - DBG(DBG_info,"gl841_offset_calibration: acceptable offsets: %d,%d,%d\n", - off[0],off[1],off[2]); - - - for (j = 0; j < channels; j++) - { - off1[j] = off[j]; - - min1[j] = 65536; - - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - first_line[i * 2 + j * 2 * num_pixels]; - else - val = - first_line[i * 2 * channels + 2 * j + 1] * 256 + - first_line[i * 2 * channels + 2 * j]; - if (min1[j] > val && val >= 10) - min1[j] = val; - } - } - - - offl[0] = off[0]; - offl[1] = off[0]; - offl[2] = off[0]; - turn = 0; - - do { - - for (j=0; j < channels; j++) { - off[j] = (offh[j]+offl[j])/2; - dev->frontend.offset[j] = off[j]; - } - - status = gl841_set_fe(dev, AFE_SET); - - if (status != SANE_STATUS_GOOD) - { - free (first_line); - free (second_line); - DBG (DBG_error, - "gl841_offset_calibration: failed to setup frontend: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_info, - "gl841_offset_calibration: starting second line reading\n"); - RIEF2 (gl841_bulk_write_register - (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS), first_line, second_line); - RIEF2 (gl841_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); - - if (DBG_LEVEL >= DBG_data) { - snprintf(fn,20,"offset2_%02d.pnm",turn); - sanei_genesys_write_pnm_file (fn, - second_line, - 16, - channels, - num_pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - cmin[j] = 0; - cmax[j] = 0; - - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - second_line[i * 2 + j * 2 * num_pixels]; - else - val = - second_line[i * 2 * channels + 2 * j + 1] * 256 + - second_line[i * 2 * channels + 2 * j]; - if (val < 10) - cmin[j]++; - if (val > 65525) - cmax[j]++; - } - - if (cmin[j] > num_pixels/100) { - acceptable = SANE_FALSE; - if (dev->model->is_cis) - offl[0] = off[0]; - else - offl[j] = off[j]; - } - if (cmax[j] > num_pixels/100) { - acceptable = SANE_FALSE; - if (dev->model->is_cis) - offh[0] = off[0]; - else - offh[j] = off[j]; - } - } - - DBG(DBG_info,"gl841_offset_calibration: black/white pixels: " - "%d/%d,%d/%d,%d/%d\n", - cmin[0],cmax[0],cmin[1],cmax[1],cmin[2],cmax[2]); - - if (dev->model->is_cis) { - offh[2] = offh[1] = offh[0]; - offl[2] = offl[1] = offl[0]; - } - - RIEF2 (gl841_stop_action (dev), first_line, second_line); - - turn++; - - } while (!acceptable && turn < 100); - - DBG(DBG_info,"gl841_offset_calibration: acceptable offsets: %d,%d,%d\n", - off[0],off[1],off[2]); - - - for (j = 0; j < channels; j++) - { - off2[j] = off[j]; - - min2[j] = 65536; - - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - second_line[i * 2 + j * 2 * num_pixels]; - else - val = - second_line[i * 2 * channels + 2 * j + 1] * 256 + - second_line[i * 2 * channels + 2 * j]; - if (min2[j] > val && val != 0) - min2[j] = val; - } - } - - DBG(DBG_info,"gl841_offset_calibration: first set: %d/%d,%d/%d,%d/%d\n", - off1[0],min1[0],off1[1],min1[1],off1[2],min1[2]); - - DBG(DBG_info,"gl841_offset_calibration: second set: %d/%d,%d/%d,%d/%d\n", - off2[0],min2[0],off2[1],min2[1],off2[2],min2[2]); - -/* - calculate offset for each channel - based on minimal pixel value min1 at offset off1 and minimal pixel value min2 - at offset off2 - - to get min at off, values are linearly interpolated: - min=real+off*fact - min1=real+off1*fact - min2=real+off2*fact - - fact=(min1-min2)/(off1-off2) - real=min1-off1*(min1-min2)/(off1-off2) - - off=(min-min1+off1*(min1-min2)/(off1-off2))/((min1-min2)/(off1-off2)) - - off=(min*(off1-off2)+min1*off2-off1*min2)/(min1-min2) - - */ - for (j = 0; j < channels; j++) - { - if (min2[j]-min1[j] == 0) { -/*TODO: try to avoid this*/ - DBG(DBG_warn,"gl841_offset_calibration: difference too small\n"); - if (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j] >= 0) - off[j] = 0x0000; - else - off[j] = 0xffff; - } else - off[j] = (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j])/(min1[j]-min2[j]); - if (off[j] > 255) - off[j] = 255; - if (off[j] < 0) - off[j] = 0; - dev->frontend.offset[j] = off[j]; - } - - DBG(DBG_info,"gl841_offset_calibration: final offsets: %d,%d,%d\n", - off[0],off[1],off[2]); - - if (dev->model->is_cis) { - if (off[0] < off[1]) - off[0] = off[1]; - if (off[0] < off[2]) - off[0] = off[2]; - dev->frontend.offset[0] = off[0]; - dev->frontend.offset[1] = off[0]; - dev->frontend.offset[2] = off[0]; - } - - if (channels == 1) - { - dev->frontend.offset[1] = dev->frontend.offset[0]; - dev->frontend.offset[2] = dev->frontend.offset[0]; - } - - /* cleanup before return */ - free (first_line); - free (second_line); - DBG (DBG_proc, "gl841_offset_calibration: completed\n"); - return status; -} - - -/* alternative coarse gain calibration - this on uses the settings from offset_calibration and - uses only one scanline - */ -/* - with offset and coarse calibration we only want to get our input range into - a reasonable shape. the fine calibration of the upper and lower bounds will - be done with shading. - */ -GENESYS_STATIC SANE_Status -gl841_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - int num_pixels; - int total_size; - uint8_t *line; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3]; - int val; - int lines=1; - int move; - - DBG (DBG_proc, "%s: dpi=%d\n", __func__, dpi); - - /* feed to white strip if needed */ - if (dev->model->y_offset_calib>0) - { - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * (dev->motor.base_ydpi)) / MM_PER_INCH; - DBG (DBG_io, "%s: move=%d lines\n", __func__, move); - status = gl841_feed(dev, move); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to feed: %s\n", __func__, - sane_strstatus (status)); - return status; - } - } - - /* coarse gain calibration is allways done in color mode */ - channels = 3; - - status = gl841_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - (dev->sensor.sensor_pixels*dev->settings.xres) / dev->sensor.optical_res, - lines, - 16, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES - ); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - RIE (gl841_bulk_write_register (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS)); - - num_pixels = dev->current_setup.pixels; - - total_size = num_pixels * channels * 2 * lines; /* colors * bytes_per_color * scan lines */ - - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - - RIEF (gl841_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, total_size), line); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("coarse.pnm", line, 16, channels, num_pixels, lines); - - /* average high level for each channel and compute gain - to reach the target code - we only use the central half of the CCD data */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - - if (val > max[j]) - max[j] = val; - } - - gain[j] = 65535.0/max[j]; - - if (dev->model->dac_type == DAC_CANONLIDE35 || - dev->model->dac_type == DAC_WOLFSON_XP300 || - dev->model->dac_type == DAC_WOLFSON_DSM600) - { - gain[j] *= 0.69;/*seems we don't get the real maximum. empirically derived*/ - if (283 - 208/gain[j] > 255) - dev->frontend.gain[j] = 255; - else if (283 - 208/gain[j] < 0) - dev->frontend.gain[j] = 0; - else - dev->frontend.gain[j] = 283 - 208/gain[j]; - } - else if (dev->model->dac_type == DAC_CANONLIDE80) - { - dev->frontend.gain[j] = gain[j]*12; - } - - DBG (DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, - j, max[j], gain[j],dev->frontend.gain[j]); - } - - for (j = 0; j < channels; j++) - { - if(gain[j] > 10) - { - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**** ****\n"); - DBG (DBG_error0, "**** Extremely low Brightness detected. ****\n"); - DBG (DBG_error0, "**** Check the scanning head is ****\n"); - DBG (DBG_error0, "**** unlocked and moving. ****\n"); - DBG (DBG_error0, "**** ****\n"); - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**********************************************\n"); -#ifdef SANE_STATUS_HW_LOCKED - return SANE_STATUS_HW_LOCKED; -#else - return SANE_STATUS_JAMMED; -#endif - } - - } - - if (dev->model->is_cis) { - if (dev->frontend.gain[0] > dev->frontend.gain[1]) - dev->frontend.gain[0] = dev->frontend.gain[1]; - if (dev->frontend.gain[0] > dev->frontend.gain[2]) - dev->frontend.gain[0] = dev->frontend.gain[2]; - dev->frontend.gain[2] = dev->frontend.gain[1] = dev->frontend.gain[0]; - } - - if (channels == 1) - { - dev->frontend.gain[0] = dev->frontend.gain[1]; - dev->frontend.gain[2] = dev->frontend.gain[1]; - } - - free (line); - DBG (DBG_info, "%s: gain=(%d,%d,%d)\n", __func__, - dev->frontend.gain[0], - dev->frontend.gain[1], - dev->frontend.gain[2]); - - RIE (gl841_stop_action (dev)); - - gl841_slow_back_home(dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - -/* - * wait for lamp warmup by scanning the same line until difference - * between 2 scans is below a threshold - */ -static SANE_Status -gl841_init_regs_for_warmup (Genesys_Device * dev, - Genesys_Register_Set * local_reg, - int *channels, int *total_size) -{ - int num_pixels = (int) (4 * 300); - SANE_Status status = SANE_STATUS_GOOD; - - DBG (DBG_proc, "sanei_gl841_warmup_lamp\n"); - - memcpy (local_reg, dev->reg, (GENESYS_GL841_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - -/* okay.. these should be defaults stored somewhere */ - dev->frontend.gain[0] = 0x00; - dev->frontend.gain[1] = 0x00; - dev->frontend.gain[2] = 0x00; - dev->frontend.offset[0] = 0x80; - dev->frontend.offset[1] = 0x80; - dev->frontend.offset[2] = 0x80; - - status = gl841_init_scan_regs (dev, - local_reg, - dev->sensor.optical_res, - dev->settings.yres, - dev->sensor.dummy_pixel, - 0, - num_pixels, - 1, - 16, - *channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES - ); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_init_regs_for_warmup: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - num_pixels = dev->current_setup.pixels; - - *total_size = num_pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */ - - RIE (gl841_bulk_write_register - (dev, local_reg, GENESYS_GL841_MAX_REGS)); - - return status; -} - - -/* - * this function moves head without scanning, forward, then backward - * so that the head goes to park position. - * as a by-product, also check for lock - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -sanei_gl841_repark_head (Genesys_Device * dev) -{ - SANE_Status status; - - DBG (DBG_proc, "sanei_gl841_repark_head\n"); - - status = gl841_feed(dev,232); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_repark_head: failed to feed: %s\n", - sane_strstatus (status)); - return status; - } - - /* toggle motor flag, put an huge step number and redo move backward */ - status = gl841_slow_back_home (dev, SANE_TRUE); - DBG (DBG_proc, "gl841_park_head: completed\n"); - return status; -} - -static SANE_Status -gl841_is_compatible_calibration (Genesys_Device * dev, - Genesys_Calibration_Cache *cache, - int for_overwrite) -{ - SANE_Status status; -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - - DBGSTART; - - /* calibration cache not working yet for this model */ - if (dev->model->ccd_type == CCD_PLUSTEK_3600) - { - return SANE_STATUS_UNSUPPORTED; - } - - status = gl841_calculate_current_setup (dev); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_is_compatible_calibration: failed to calculate current setup: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "gl841_is_compatible_calibration: checking\n"); - - if (dev->current_setup.half_ccd != cache->used_setup.half_ccd) - return SANE_STATUS_UNSUPPORTED; - - /* a cache entry expires after 30 minutes for non sheetfed scanners */ - /* this is not taken into account when overwriting cache entries */ -#ifdef HAVE_SYS_TIME_H - if(for_overwrite == SANE_FALSE) - { - gettimeofday (&time, NULL); - if ((time.tv_sec - cache->last_calibration > 30 * 60) - && (dev->model->is_sheetfed == SANE_FALSE)) - { - DBG (DBG_proc, "%s: expired entry, non compatible cache\n",__func__); - return SANE_STATUS_UNSUPPORTED; - } - } -#endif - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* - * initialize ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -static SANE_Status -gl841_init (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val; - size_t size; - uint8_t *line; - int i; - - DBG_INIT (); - DBGSTART; - - dev->scanhead_position_in_steps = 0; - - /* Check if the device has already been initialized and powered up */ - if (dev->already_initialized) - { - RIE (sanei_genesys_get_status (dev, &val)); - if (val & REG41_PWRBIT) - { - DBG (DBG_info, "gl841_init: already initialized\n"); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - } - - dev->dark_average_data = NULL; - dev->white_average_data = NULL; - - dev->settings.color_filter = 0; - - /* ASIC reset */ - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - - /* Set default values for registers */ - gl841_init_registers (dev); - - /* Write initial registers */ - RIE (gl841_bulk_write_register (dev, dev->reg, GENESYS_GL841_MAX_REGS)); - - /* Test ASIC and RAM */ - if (!(dev->model->flags & GENESYS_FLAG_LAZY_INIT)) - { - RIE (sanei_gl841_asic_test (dev)); - } - - /* Set analog frontend */ - RIE (gl841_set_fe (dev, AFE_INIT)); - - /* Move home */ - RIE (gl841_slow_back_home (dev, SANE_TRUE)); - - /* Init shading data */ - RIE (sanei_genesys_init_shading_data (dev, dev->sensor.sensor_pixels)); - - /* ensure head is correctly parked, and check lock */ - if (dev->model->flags & GENESYS_FLAG_REPARK) - { - status = sanei_gl841_repark_head (dev); - if (status != SANE_STATUS_GOOD) - { - if (status == SANE_STATUS_INVAL) - DBG (DBG_error0, - "Your scanner is locked. Please move the lock switch " - "to the unlocked position\n"); - else - DBG (DBG_error, - "gl841_init: sanei_gl841_repark_head failed: %s\n", - sane_strstatus (status)); - return status; - } - } - - /* initalize sensor gamma tables */ - size = 256; - - for(i=0;i<3;i++) - { - if (dev->sensor.gamma_table[i] == NULL) - { - dev->sensor.gamma_table[i] = (uint16_t *) malloc (2 * size); - if (dev->sensor.gamma_table[i] == NULL) - { - DBG (DBG_error, - "gl841_init: could not allocate memory for gamma table %d\n",i); - return SANE_STATUS_NO_MEM; - } - sanei_genesys_create_gamma_table (dev->sensor.gamma_table[i], - size, - 65535, - 65535, - dev->sensor.gamma[i]); - } - } - - /* send gamma tables */ - status = gl841_send_gamma_table (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_init: failed to send initial gamma tables: %s\n", - sane_strstatus (status)); - return status; - } - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, (GENESYS_GL841_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - - status = gl841_init_scan_regs (dev, - dev->calib_reg, - 300, - 300, - 0, - 0, - (16 * 300) / dev->sensor.optical_res, - 1, - 16, - 3, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES - ); - - RIE (gl841_bulk_write_register - (dev, dev->calib_reg, GENESYS_GL841_MAX_REGS)); - - size = dev->current_setup.pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */ - - line = malloc (size); - if (!line) - return SANE_STATUS_NO_MEM; - - DBG (DBG_info, - "gl841_init: starting dummy data reading\n"); - RIEF (gl841_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - - sanei_usb_set_timeout(1000);/* 1 second*/ - -/*ignore errors. next read will succeed*/ - sanei_genesys_read_data_from_scanner (dev, line, size); - free(line); - - sanei_usb_set_timeout(30 * 1000);/* 30 seconds*/ - - RIE (gl841_end_scan (dev, dev->calib_reg, SANE_TRUE)); - - - memcpy (dev->calib_reg, dev->reg, (GENESYS_GL841_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - - /* Set powersaving (default = 15 minutes) */ - RIE (gl841_set_powersaving (dev, 15)); - dev->already_initialized = SANE_TRUE; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not lose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - if (s->dev->model->gpo_type == GPO_CANONLIDE35 - || s->dev->model->gpo_type == GPO_CANONLIDE80) - { - RIE(sanei_genesys_read_register(s->dev, REG6D, &val)); - - if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) - s->val[OPT_SCAN_SW].b = (val & 0x01) == 0; - if (s->val[OPT_FILE_SW].b == s->last_val[OPT_FILE_SW].b) - s->val[OPT_FILE_SW].b = (val & 0x02) == 0; - if (s->val[OPT_EMAIL_SW].b == s->last_val[OPT_EMAIL_SW].b) - s->val[OPT_EMAIL_SW].b = (val & 0x04) == 0; - if (s->val[OPT_COPY_SW].b == s->last_val[OPT_COPY_SW].b) - s->val[OPT_COPY_SW].b = (val & 0x08) == 0; - } - - if (s->dev->model->gpo_type == GPO_XP300 || - s->dev->model->gpo_type == GPO_DP665 || - s->dev->model->gpo_type == GPO_DP685) - { - RIE(sanei_genesys_read_register(s->dev, REG6D, &val)); - - if (s->val[OPT_PAGE_LOADED_SW].b == s->last_val[OPT_PAGE_LOADED_SW].b) - s->val[OPT_PAGE_LOADED_SW].b = (val & 0x01) == 0; - if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) - s->val[OPT_SCAN_SW].b = (val & 0x02) == 0; - } - - return status; -} - -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl841_search_strip (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black) -{ - unsigned int pixels, lines, channels; - SANE_Status status; - Genesys_Register_Set local_reg[GENESYS_GL841_MAX_REGS + 1]; - size_t size; - uint8_t *data; - int steps, depth, dpi; - unsigned int pass, count, found, x, y, length; - char title[80]; - Genesys_Register_Set *r; - uint8_t white_level=90; /**< default white level to detect white dots */ - uint8_t black_level=60; /**< default black level to detect black dots */ - - DBG (DBG_proc, "gl841_search_strip %s %s\n", black ? "black" : "white", - forward ? "forward" : "reverse"); - - /* use maximum gain when doing forward white strip detection - * since we don't have calibrated the sensor yet */ - if(!black && forward) - { - dev->frontend.gain[0] = 0xff; - dev->frontend.gain[1] = 0xff; - dev->frontend.gain[2] = 0xff; - } - - gl841_set_fe (dev, AFE_SET); - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_search_strip: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - - /* set up for a gray scan at lowest dpi */ - dpi = 9600; - for (x = 0; x < MAX_RESOLUTIONS; x++) - { - if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) - dpi = dev->model->xdpi_values[x]; - } - channels = 1; - - /* shading calibation is done with dev->motor.base_ydpi */ - /* lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; */ - lines = (10*dpi)/MM_PER_INCH; - - depth = 8; - pixels = (dev->sensor.sensor_pixels * dpi) / dev->sensor.optical_res; - size = pixels * channels * lines * (depth / 8); - data = malloc (size); - if (!data) - { - DBG (DBG_error, "gl841_search_strip: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - /* 20 cm max length for calibration sheet */ - length = ((200 * dpi) / MM_PER_INCH)/lines; - - dev->scanhead_position_in_steps = 0; - - memcpy (local_reg, dev->reg, - (GENESYS_GL841_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - - status = gl841_init_scan_regs (dev, - local_reg, - dpi, - dpi, - 0, - 0, - pixels, - lines, - depth, - channels, - 0, - SCAN_FLAG_DISABLE_SHADING | SCAN_FLAG_DISABLE_GAMMA); - if (status != SANE_STATUS_GOOD) - { - free(data); - DBG (DBG_error, "%s: failed to setup for scan: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* set up for reverse or forward */ - r = sanei_genesys_get_address (local_reg, 0x02); - if (forward) - r->value &= ~4; - else - r->value |= 4; - - - status = gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - free(data); - DBG (DBG_error, - "gl841_search_strip: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl841_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl841_search_strip: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl841_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, "gl841_search_strip: gl841_stop_action failed\n"); - return status; - } - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s_%s%02u.pnm", black ? "black" : "white", - forward ? "fwd" : "bwd", pass); - sanei_genesys_write_pnm_file (title, data, depth, channels, pixels, - lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < length && !found) - { - status = - gl841_bulk_write_register (dev, local_reg, GENESYS_GL841_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl841_search_strip: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - /* now start scan */ - status = gl841_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl841_search_strip: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl841_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, "gl841_search_strip: gl841_stop_action failed\n"); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s_%s%02u.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", pass); - sanei_genesys_write_pnm_file (title, data, depth, channels, pixels, - lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > white_level) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < black_level) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG (DBG_data, - "gl841_search_strip: strip found forward during pass %d at line %d\n", - pass, y); - } - else - { - DBG (DBG_data, - "gl841_search_strip: pixels=%d, count=%d (%d%%)\n", - pixels, count, (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > white_level) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < black_level) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG (DBG_data, - "gl841_search_strip: strip found backward during pass %d \n", - pass); - } - else - { - DBG (DBG_data, - "gl841_search_strip: pixels=%d, count=%d (%d%%)\n", pixels, - count, (100 * count) / pixels); - } - } - pass++; - } - free (data); - if (found) - { - status = SANE_STATUS_GOOD; - DBG (DBG_info, "gl841_search_strip: %s strip found\n", - black ? "black" : "white"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG (DBG_info, "gl841_search_strip: %s strip not found\n", - black ? "black" : "white"); - } - - DBG (DBG_proc, "gl841_search_strip: completed\n"); - return status; -} - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -GENESYS_STATIC -SANE_Status -gl841_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t length, x, factor, pixels, i; - uint32_t half; - uint32_t lines, channels; - uint16_t dpiset, dpihw, strpixel ,endpixel, beginpixel; - uint8_t *buffer,*ptr,*src; - - DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); - - /* old method if no SHDAREA */ - if((dev->reg[reg_0x01].value & REG01_SHDAREA) == 0) - { - /* start address */ - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set buffer address: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* shading data whole line */ - status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send shading table: %s\n", __func__, - sane_strstatus (status)); - return status; - } - DBGCOMPLETED; - return status; - } - - /* data is whole line, we extract only the part for the scanned area */ - length = (uint32_t) (size / 3); - sanei_genesys_get_double(dev->reg,REG_STRPIXEL,&strpixel); - sanei_genesys_get_double(dev->reg,REG_ENDPIXEL,&endpixel); - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d\n",__func__,strpixel,endpixel,endpixel-strpixel); - - /* compute deletion/average factor */ - sanei_genesys_get_double(dev->reg,REG_DPISET,&dpiset); - dpihw = gl841_get_dpihw(dev); - half=dev->current_setup.half_ccd+1; - factor=dpihw/dpiset; - DBG( DBG_io2, "%s: dpihw=%d, dpiset=%d, half_ccd=%d, factor=%d\n",__func__,dpihw,dpiset,half-1,factor); - - /* binary data logging */ - if(DBG_LEVEL>=DBG_data) - { - dev->binary=fopen("binary.pnm","wb"); - sanei_genesys_get_triple(dev->reg, REG_LINCNT, &lines); - channels=dev->current_setup.channels; - if(dev->binary!=NULL) - { - fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); - } - } - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; /* 2 words of 2 bytes */ - endpixel*=2*2; - pixels=endpixel-strpixel; - - /* shading pixel begin is start pixel minus start pixel during shading - * calibration. Currently only cases handled are full and half ccd resolution. - */ - beginpixel = dev->sensor.CCD_start_xoffset / half; - beginpixel += dev->sensor.dummy_pixel + 1; - DBG(DBG_io2, "%s: ORIGIN PIXEL=%d\n", __func__, beginpixel); - beginpixel = (strpixel-beginpixel*2*2)/factor; - DBG(DBG_io2, "%s: BEGIN PIXEL=%d\n",__func__,beginpixel/4); - - DBG(DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__func__,length, length/4); - buffer=(uint8_t *)malloc(pixels); - memset(buffer,0,pixels); - - /* write actual shading data contigously - * channel by channel, starting at addr 0x0000 - * */ - for(i=0;i<3;i++) - { - /* copy data to work buffer and process it */ - /* coefficent destination */ - ptr=buffer; - - /* iterate on both sensor segment, data has been averaged, - * so is in the right order and we only have to copy it */ - for(x=0;xmodel->cmd_set->bulk_write_data (dev, 0x3c, buffer, pixels), buffer); - } - - free(buffer); - DBGCOMPLETED; - - return status; -} - - -/** the gl841 command set */ -static Genesys_Command_Set gl841_cmd_set = { - "gl841-generic", /* the name of this set */ - - gl841_init, - gl841_init_regs_for_warmup, - gl841_init_regs_for_coarse_calibration, - gl841_init_regs_for_shading, - gl841_init_regs_for_scan, - - gl841_get_filter_bit, - gl841_get_lineart_bit, - gl841_get_bitset_bit, - gl841_get_gain4_bit, - gl841_get_fast_feed_bit, - gl841_test_buffer_empty_bit, - gl841_test_motor_flag_bit, - - gl841_bulk_full_size, - - gl841_set_fe, - gl841_set_powersaving, - gl841_save_power, - - gl841_set_motor_power, - gl841_set_lamp_power, - - gl841_begin_scan, - gl841_end_scan, - - gl841_send_gamma_table, - - gl841_search_start_position, - - gl841_offset_calibration, - gl841_coarse_gain_calibration, - gl841_led_calibration, - - gl841_slow_back_home, - NULL, - - gl841_bulk_write_register, - gl841_bulk_write_data, - gl841_bulk_read_data, - - gl841_update_hardware_sensors, - - gl841_load_document, - gl841_detect_document_end, - gl841_eject_document, - gl841_search_strip, - - gl841_is_compatible_calibration, - NULL, - gl841_send_shading_data, - gl841_calculate_current_setup, - NULL, - NULL -}; - -SANE_Status -sanei_gl841_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl841_cmd_set; - return SANE_STATUS_GOOD; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl841.cc b/backend/genesys_gl841.cc new file mode 100644 index 0000000..9e8fc15 --- /dev/null +++ b/backend/genesys_gl841.cc @@ -0,0 +1,5624 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003 Oliver Rauch + Copyright (C) 2003, 2004 Henning Meier-Geinitz + Copyright (C) 2004 Gerhard Jaeger + Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2005 Philipp Schmid + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2006 Laurent Charpentier + Copyright (C) 2010 Chris Berry and Michael Rickmann + for Plustek Opticbook 3600 support + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_gl841.h" + +#include + +/**************************************************************************** + Low level function + ****************************************************************************/ + +/* ------------------------------------------------------------------------ */ +/* Read and write RAM, registers and AFE */ +/* ------------------------------------------------------------------------ */ + +/* Set address for writing data */ +static SANE_Status +gl841_set_buffer_address_gamma (Genesys_Device * dev, uint32_t addr) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xfffffff0); + + addr = addr >> 4; + + status = sanei_genesys_write_register (dev, 0x5c, (addr & 0xff)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while writing low byte: %s\n", __func__, sane_strstatus(status)); + return status; + } + + addr = addr >> 8; + status = sanei_genesys_write_register (dev, 0x5b, (addr & 0xff)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while writing high byte: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_io, "%s: completed\n", __func__); + + return status; +} + +/**************************************************************************** + Mid level functions + ****************************************************************************/ + +static SANE_Bool +gl841_get_fast_feed_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x02); + if (r && (r->value & REG02_FASTFED)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl841_get_filter_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x04); + if (r && (r->value & REG04_FILTER)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl841_get_lineart_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x04); + if (r && (r->value & REG04_LINEART)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl841_get_bitset_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x04); + if (r && (r->value & REG04_BITSET)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl841_get_gain4_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x06); + if (r && (r->value & REG06_GAIN4)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl841_test_buffer_empty_bit (SANE_Byte val) +{ + if (val & REG41_BUFEMPTY) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl841_test_motor_flag_bit (SANE_Byte val) +{ + if (val & REG41_MOTORENB) + return SANE_TRUE; + return SANE_FALSE; +} + +/** copy sensor specific settings */ +/* *dev : device infos + *regs : registers to be set + extended : do extended set up + half_ccd: set up for half ccd resolution + all registers 08-0B, 10-1D, 52-59 are set up. They shouldn't + appear anywhere else but in register_ini + +Responsible for signals to CCD/CIS: + CCD_CK1X (CK1INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1MTGL(0x1C),CK1LOW(0x1D),CK1MAP(0x74,0x75,0x76),CK1NEG(0x7D)) + CCD_CK2X (CK2INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1LOW(0x1D),CK1NEG(0x7D)) + CCD_CK3X (MANUAL3(0x1A),CK3INV(0x1A),CK3MTGL(0x1C),CK3LOW(0x1D),CK3MAP(0x77,0x78,0x79),CK3NEG(0x7D)) + CCD_CK4X (MANUAL3(0x1A),CK4INV(0x1A),CK4MTGL(0x1C),CK4LOW(0x1D),CK4MAP(0x7A,0x7B,0x7C),CK4NEG(0x7D)) + CCD_CPX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),CPH(0x72),CPL(0x73),CPNEG(0x7D)) + CCD_RSX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),RSH(0x70),RSL(0x71),RSNEG(0x7D)) + CCD_TGX (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPR(0x10,0x11),TGSHLD(0x1D)) + CCD_TGG (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPG(0x12,0x13),TGSHLD(0x1D)) + CCD_TGB (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPB(0x14,0x15),TGSHLD(0x1D)) + LAMP_SW (EXPR(0x10,0x11),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) + XPA_SW (EXPG(0x12,0x13),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) + LAMP_B (EXPB(0x14,0x15),LAMP_PWR(0x03)) + +other registers: + CISSET(0x01),CNSET(0x18),DCKSEL(0x18),SCANMOD(0x18),EXPDMY(0x19),LINECLP(0x1A),CKAREA(0x1C),TGTIME(0x1C),LINESEL(0x1E),DUMMY(0x34) + +Responsible for signals to AFE: + VSMP (VSMP(0x58),VSMPW(0x58)) + BSMP (BSMP(0x59),BSMPW(0x59)) + +other register settings depending on this: + RHI(0x52),RLOW(0x53),GHI(0x54),GLOW(0x55),BHI(0x56),BLOW(0x57), + +*/ +static void sanei_gl841_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * regs, + SANE_Bool extended, SANE_Bool half_ccd) +{ + DBG(DBG_proc, "%s\n", __func__); + + // that one is tricky at least + for (uint16_t addr = 0x08; addr <= 0x0b; ++addr) { + regs->set8(0x70 + addr - 0x08, sensor.custom_regs.get_value(addr)); + } + + // ignore registers in range [0x10..0x16) + for (uint16_t addr = 0x16; addr < 0x1e; ++addr) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + // ignore registers in range [0x5b..0x5e] + for (uint16_t addr = 0x52; addr < 0x52 + 9; ++addr) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + /* don't go any further if no extended setup */ + if (!extended) + return; + + /* todo : add more CCD types if needed */ + /* we might want to expand the Sensor struct to have these + 2 kind of settings */ + if (dev->model->ccd_type == CCD_5345) + { + if (half_ccd) + { + GenesysRegister* r; + /* settings for CCD used at half is max resolution */ + r = sanei_genesys_get_address (regs, 0x70); + r->value = 0x00; + r = sanei_genesys_get_address (regs, 0x71); + r->value = 0x05; + r = sanei_genesys_get_address (regs, 0x72); + r->value = 0x06; + r = sanei_genesys_get_address (regs, 0x73); + r->value = 0x08; + r = sanei_genesys_get_address (regs, 0x18); + r->value = 0x28; + r = sanei_genesys_get_address (regs, 0x58); + r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ + } + else + { + GenesysRegister* r; + /* swap latch times */ + r = sanei_genesys_get_address (regs, 0x18); + r->value = 0x30; + regs->set8(0x52, sensor.custom_regs.get_value(0x55)); + regs->set8(0x53, sensor.custom_regs.get_value(0x56)); + regs->set8(0x54, sensor.custom_regs.get_value(0x57)); + regs->set8(0x55, sensor.custom_regs.get_value(0x52)); + regs->set8(0x56, sensor.custom_regs.get_value(0x53)); + regs->set8(0x57, sensor.custom_regs.get_value(0x54)); + r = sanei_genesys_get_address (regs, 0x58); + r->value = 0x20 | (r->value & 0x03); /* VSMP=4 */ + } + return; + } + + if (dev->model->ccd_type == CCD_HP2300) + { + /* settings for CCD used at half is max resolution */ + GenesysRegister* r; + if (half_ccd) + { + r = sanei_genesys_get_address (regs, 0x70); + r->value = 0x16; + r = sanei_genesys_get_address (regs, 0x71); + r->value = 0x00; + r = sanei_genesys_get_address (regs, 0x72); + r->value = 0x01; + r = sanei_genesys_get_address (regs, 0x73); + r->value = 0x03; + /* manual clock programming */ + r = sanei_genesys_get_address (regs, 0x1d); + r->value |= 0x80; + } + else + { + r = sanei_genesys_get_address (regs, 0x70); + r->value = 1; + r = sanei_genesys_get_address (regs, 0x71); + r->value = 3; + r = sanei_genesys_get_address (regs, 0x72); + r->value = 4; + r = sanei_genesys_get_address (regs, 0x73); + r->value = 6; + } + r = sanei_genesys_get_address (regs, 0x58); + r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ + return; + } +} + +/** Test if the ASIC works + */ +/*TODO: make this functional*/ +static SANE_Status +sanei_gl841_asic_test (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + size_t size, verify_size; + unsigned int i; + + DBG(DBG_proc, "%s\n", __func__); + + return SANE_STATUS_INVAL; + + /* set and read exposure time, compare if it's the same */ + status = sanei_genesys_write_register (dev, 0x38, 0xde); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_write_register (dev, 0x39, 0xad); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_read_register (dev, 0x38, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (val != 0xde) /* value of register 0x38 */ + { + DBG(DBG_error, "%s: register contains invalid value\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + status = sanei_genesys_read_register (dev, 0x39, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (val != 0xad) /* value of register 0x39 */ + { + DBG(DBG_error, "%s: register contains invalid value\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + /* ram test: */ + size = 0x40000; + verify_size = size + 0x80; + /* todo: looks like the read size must be a multiple of 128? + otherwise the read doesn't succeed the second time after the scanner has + been plugged in. Very strange. */ + + std::vector data(size); + std::vector verify_data(verify_size); + + for (i = 0; i < (size - 1); i += 2) + { + data[i] = i / 512; + data[i + 1] = (i / 2) % 256; + } + + status = sanei_genesys_set_buffer_address (dev, 0x0000); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + +/* status = sanei_genesys_bulk_write_data(dev, 0x3c, data, size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write data: %s\n", __func__, sane_strstatus(status)); + free (data); + free (verify_data); + return status; + }*/ + + status = sanei_genesys_set_buffer_address (dev, 0x0000); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_bulk_read_data(dev, 0x45, verify_data.data(), verify_size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* todo: why i + 2 ? */ + for (i = 0; i < size; i++) + { + if (verify_data[i] != data[i]) + { + DBG(DBG_error, "%s: data verification error\n", __func__); + DBG(DBG_info, "0x%.8x: got %.2x %.2x %.2x %.2x, expected %.2x %.2x %.2x %.2x\n", + i, + verify_data[i], + verify_data[i+1], + verify_data[i+2], + verify_data[i+3], + data[i], + data[i+1], + data[i+2], + data[i+3]); + return SANE_STATUS_IO_ERROR; + } + } + + DBG(DBG_info, "%s: completed\n", __func__); + + return SANE_STATUS_GOOD; +} + +/* + * Set all registers LiDE 80 to default values + * (function called only once at the beginning) + * we are doing a special case to ease development + */ +static void +gl841_init_lide80 (Genesys_Device * dev) +{ + uint8_t val; + + INITREG (0x01, 0x82); /* 0x02 = SHDAREA and no CISSET ! */ + INITREG (0x02, 0x10); + INITREG (0x03, 0x50); + INITREG (0x04, 0x02); + INITREG (0x05, 0x4c); /* 1200 DPI */ + INITREG (0x06, 0x38); /* 0x38 scanmod=1, pwrbit, GAIN4 */ + INITREG (0x07, 0x00); + INITREG (0x08, 0x00); + INITREG (0x09, 0x11); + INITREG (0x0a, 0x00); + + INITREG (0x10, 0x40); + INITREG (0x11, 0x00); + INITREG (0x12, 0x40); + INITREG (0x13, 0x00); + INITREG (0x14, 0x40); + INITREG (0x15, 0x00); + INITREG (0x16, 0x00); + INITREG (0x17, 0x01); + INITREG (0x18, 0x00); + INITREG (0x19, 0x06); + INITREG (0x1a, 0x00); + INITREG (0x1b, 0x00); + INITREG (0x1c, 0x00); + INITREG (0x1d, 0x04); + INITREG (0x1e, 0x10); + INITREG (0x1f, 0x04); + INITREG (0x20, 0x02); + INITREG (0x21, 0x10); + INITREG (0x22, 0x20); + INITREG (0x23, 0x20); + INITREG (0x24, 0x10); + INITREG (0x25, 0x00); + INITREG (0x26, 0x00); + INITREG (0x27, 0x00); + + INITREG (0x29, 0xff); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + INITREG (0x2c, sensor.optical_res>>8); + INITREG (0x2d, sensor.optical_res & 0xff); + INITREG (0x2e, 0x80); + INITREG (0x2f, 0x80); + INITREG (0x30, 0x00); + INITREG (0x31, 0x10); + INITREG (0x32, 0x15); + INITREG (0x33, 0x0e); + INITREG (0x34, 0x40); + INITREG (0x35, 0x00); + INITREG (0x36, 0x2a); + INITREG (0x37, 0x30); + INITREG (0x38, 0x2a); + INITREG (0x39, 0xf8); + + INITREG (0x3d, 0x00); + INITREG (0x3e, 0x00); + INITREG (0x3f, 0x00); + + INITREG (0x52, 0x03); + INITREG (0x53, 0x07); + INITREG (0x54, 0x00); + INITREG (0x55, 0x00); + INITREG (0x56, 0x00); + INITREG (0x57, 0x00); + INITREG (0x58, 0x29); + INITREG (0x59, 0x69); + INITREG (0x5a, 0x55); + + INITREG (0x5d, 0x20); + INITREG (0x5e, 0x41); + INITREG (0x5f, 0x40); + INITREG (0x60, 0x00); + INITREG (0x61, 0x00); + INITREG (0x62, 0x00); + INITREG (0x63, 0x00); + INITREG (0x64, 0x00); + INITREG (0x65, 0x00); + INITREG (0x66, 0x00); + INITREG (0x67, 0x40); + INITREG (0x68, 0x40); + INITREG (0x69, 0x20); + INITREG (0x6a, 0x20); + INITREG (0x6c, dev->gpo.value[0]); + INITREG (0x6d, dev->gpo.value[1]); + INITREG (0x6e, dev->gpo.enable[0]); + INITREG (0x6f, dev->gpo.enable[1]); + INITREG (0x70, 0x00); + INITREG (0x71, 0x05); + INITREG (0x72, 0x07); + INITREG (0x73, 0x09); + INITREG (0x74, 0x00); + INITREG (0x75, 0x01); + INITREG (0x76, 0xff); + INITREG (0x77, 0x00); + INITREG (0x78, 0x0f); + INITREG (0x79, 0xf0); + INITREG (0x7a, 0xf0); + INITREG (0x7b, 0x00); + INITREG (0x7c, 0x1e); + INITREG (0x7d, 0x11); + INITREG (0x7e, 0x00); + INITREG (0x7f, 0x50); + INITREG (0x80, 0x00); + INITREG (0x81, 0x00); + INITREG (0x82, 0x0f); + INITREG (0x83, 0x00); + INITREG (0x84, 0x0e); + INITREG (0x85, 0x00); + INITREG (0x86, 0x0d); + INITREG (0x87, 0x02); + INITREG (0x88, 0x00); + INITREG (0x89, 0x00); + + /* specific scanner settings, clock and gpio first */ + sanei_genesys_read_register (dev, REG6B, &val); + sanei_genesys_write_register (dev, REG6B, 0x0c); + sanei_genesys_write_register (dev, 0x06, 0x10); + sanei_genesys_write_register (dev, REG6E, 0x6d); + sanei_genesys_write_register (dev, REG6F, 0x80); + sanei_genesys_write_register (dev, REG6B, 0x0e); + sanei_genesys_read_register (dev, REG6C, &val); + sanei_genesys_write_register (dev, REG6C, 0x00); + sanei_genesys_read_register (dev, REG6D, &val); + sanei_genesys_write_register (dev, REG6D, 0x8f); + sanei_genesys_read_register (dev, REG6B, &val); + sanei_genesys_write_register (dev, REG6B, 0x0e); + sanei_genesys_read_register (dev, REG6B, &val); + sanei_genesys_write_register (dev, REG6B, 0x0e); + sanei_genesys_read_register (dev, REG6B, &val); + sanei_genesys_write_register (dev, REG6B, 0x0a); + sanei_genesys_read_register (dev, REG6B, &val); + sanei_genesys_write_register (dev, REG6B, 0x02); + sanei_genesys_read_register (dev, REG6B, &val); + sanei_genesys_write_register (dev, REG6B, 0x06); + + sanei_genesys_write_0x8c (dev, 0x10, 0x94); + sanei_genesys_write_register (dev, 0x09, 0x10); + + /* set up GPIO : no address, so no bulk write, doesn't written directly either ? */ + /* + dev->reg.find_reg(0x6c).value = dev->gpo.value[0]; + dev->reg.find_reg(0x6d).value = dev->gpo.value[1]; + dev->reg.find_reg(0x6e).value = dev->gpo.enable[0]; + dev->reg.find_reg(0x6f).value = dev->gpo.enable[1]; */ + + // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was + // effectively changed. The current behavior matches the old code, but should probably be fixed. + dev->reg.find_reg(0x6c).value |= REG6B_GPO18; + dev->reg.find_reg(0x6c).value &= ~REG6B_GPO17; + + sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 0); +} + +/* + * Set all registers to default values + * (function called only once at the beginning) + */ +static void +gl841_init_registers (Genesys_Device * dev) +{ + int addr; + + DBG(DBG_proc, "%s\n", __func__); + + dev->reg.clear(); + if (dev->model->model_id == MODEL_CANON_LIDE_80) + { + gl841_init_lide80(dev); + return ; + } + + for (addr = 1; addr <= 0x0a; addr++) { + dev->reg.init_reg(addr, 0); + } + for (addr = 0x10; addr <= 0x27; addr++) { + dev->reg.init_reg(addr, 0); + } + dev->reg.init_reg(0x29, 0); + for (addr = 0x2c; addr <= 0x39; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x3d; addr <= 0x3f; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x52; addr <= 0x5a; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x5d; addr <= 0x87; addr++) + dev->reg.init_reg(addr, 0); + + + dev->reg.find_reg(0x01).value = 0x20; /* (enable shading), CCD, color, 1M */ + if (dev->model->is_cis == SANE_TRUE) { + dev->reg.find_reg(0x01).value |= REG01_CISSET; + } else { + dev->reg.find_reg(0x01).value &= ~REG01_CISSET; + } + + dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ + dev->reg.find_reg(0x02).value |= REG02_AGOHOME; + sanei_genesys_set_motor_power(dev->reg, true); + dev->reg.find_reg(0x02).value |= REG02_FASTFED; + + dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */ + dev->reg.find_reg(0x03).value |= REG03_AVEENB; + + if (dev->model->ccd_type == CCD_PLUSTEK_3600) /* AD front end */ + { + dev->reg.find_reg(0x04).value = (2 << REG04S_AFEMOD) | 0x02; + } + else /* Wolfson front end */ + { + dev->reg.find_reg(0x04).value |= 1 << REG04S_AFEMOD; + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + dev->reg.find_reg(0x05).value = 0x00; /* disable gamma, 24 clocks/pixel */ + if (sensor.sensor_pixels < 0x1500) + dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; + else if (sensor.sensor_pixels < 0x2a80) + dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; + else if (sensor.sensor_pixels < 0x5400) + dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; + else + { + dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; + DBG(DBG_warn, "%s: Cannot handle sensor pixel count %d\n", __func__, + sensor.sensor_pixels); + } + + + dev->reg.find_reg(0x06).value |= REG06_PWRBIT; + dev->reg.find_reg(0x06).value |= REG06_GAIN4; + + /* XP300 CCD needs different clock and clock/pixels values */ + if (dev->model->ccd_type != CCD_XP300 && dev->model->ccd_type != CCD_DP685 + && dev->model->ccd_type != CCD_PLUSTEK_3600) + { + dev->reg.find_reg(0x06).value |= 0 << REG06S_SCANMOD; + dev->reg.find_reg(0x09).value |= 1 << REG09S_CLKSET; + } + else + { + dev->reg.find_reg(0x06).value |= 0x05 << REG06S_SCANMOD; /* 15 clocks/pixel */ + dev->reg.find_reg(0x09).value = 0; /* 24 MHz CLKSET */ + } + + dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */ + + dev->reg.find_reg(0x17).value |= 1 << REG17S_TGW; + + dev->reg.find_reg(0x19).value = 0x50; + + dev->reg.find_reg(0x1d).value |= 1 << REG1DS_TGSHLD; + + dev->reg.find_reg(0x1e).value |= 1 << REG1ES_WDTIME; + +/*SCANFED*/ + dev->reg.find_reg(0x1f).value = 0x01; + +/*BUFSEL*/ + dev->reg.find_reg(0x20).value = 0x20; + +/*LAMPPWM*/ + dev->reg.find_reg(0x29).value = 0xff; + +/*BWHI*/ + dev->reg.find_reg(0x2e).value = 0x80; + +/*BWLOW*/ + dev->reg.find_reg(0x2f).value = 0x80; + +/*LPERIOD*/ + dev->reg.find_reg(0x38).value = 0x4f; + dev->reg.find_reg(0x39).value = 0xc1; + +/*VSMPW*/ + dev->reg.find_reg(0x58).value |= 3 << REG58S_VSMPW; + +/*BSMPW*/ + dev->reg.find_reg(0x59).value |= 3 << REG59S_BSMPW; + +/*RLCSEL*/ + dev->reg.find_reg(0x5a).value |= REG5A_RLCSEL; + +/*STOPTIM*/ + dev->reg.find_reg(0x5e).value |= 0x2 << REG5ES_STOPTIM; + + sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 0); + + /* set up GPIO */ + dev->reg.find_reg(0x6c).value = dev->gpo.value[0]; + dev->reg.find_reg(0x6d).value = dev->gpo.value[1]; + dev->reg.find_reg(0x6e).value = dev->gpo.enable[0]; + dev->reg.find_reg(0x6f).value = dev->gpo.enable[1]; + + /* TODO there is a switch calling to be written here */ + if (dev->model->gpo_type == GPO_CANONLIDE35) + { + dev->reg.find_reg(0x6b).value |= REG6B_GPO18; + dev->reg.find_reg(0x6b).value &= ~REG6B_GPO17; + } + + if (dev->model->gpo_type == GPO_XP300) + { + dev->reg.find_reg(0x6b).value |= REG6B_GPO17; + } + + if (dev->model->gpo_type == GPO_DP685) + { + /* REG6B_GPO18 lights on green led */ + dev->reg.find_reg(0x6b).value |= REG6B_GPO17|REG6B_GPO18; + } + + DBG(DBG_proc, "%s complete\n", __func__); +} + +/* Send slope table for motor movement + slope_table in machine byte order + */ +static SANE_Status +gl841_send_slope_table (Genesys_Device * dev, int table_nr, + uint16_t * slope_table, int steps) +{ + int dpihw; + int start_address; + SANE_Status status = SANE_STATUS_GOOD; + char msg[4000]; +/*#ifdef WORDS_BIGENDIAN*/ + int i; +/*#endif*/ + + DBG(DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, table_nr, steps); + + dpihw = dev->reg.find_reg(0x05).value >> 6; + + if (dpihw == 0) /* 600 dpi */ + start_address = 0x08000; + else if (dpihw == 1) /* 1200 dpi */ + start_address = 0x10000; + else if (dpihw == 2) /* 2400 dpi */ + start_address = 0x20000; + else /* reserved */ + return SANE_STATUS_INVAL; + + std::vector table(steps * 2); + for(i = 0; i < steps; i++) { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + sprintf (msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) + { + sprintf (msg+strlen(msg), ",%d", slope_table[i]); + } + DBG(DBG_io, "%s: %s\n", __func__, msg); + } + + status = + sanei_genesys_set_buffer_address (dev, start_address + table_nr * 0x200); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_bulk_write_data(dev, 0x3c, table.data(), steps * 2); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send slope table: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: completed\n", __func__); + return status; +} + +static SANE_Status +gl841_set_lide80_fe (Genesys_Device * dev, uint8_t set) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + + dev->frontend = dev->frontend_initial; + + /* write them to analog frontend */ + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg 0x03 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x06, dev->frontend.regs.get_value(0x02)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg 0x06 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + if (set == AFE_SET) + { + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x06, dev->frontend.regs.get_value(0x20)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing offset failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x28)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing gain failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + return status; + DBGCOMPLETED; +} + +/* Set values of Analog Device type frontend */ +static SANE_Status +gl841_set_ad_fe (Genesys_Device * dev, uint8_t set) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + + /* special case for LiDE 80 analog frontend */ + if(dev->model->dac_type==DAC_CANONLIDE80) + { + return gl841_set_lide80_fe(dev, set); + } + + DBG(DBG_proc, "%s(): start\n", __func__); + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + + dev->frontend = dev->frontend_initial; + + /* write them to analog frontend */ + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg 0x01 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + for (i = 0; i < 6; i++) + { + status = + sanei_genesys_fe_write_data (dev, 0x02 + i, 0x00); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, 0x02 + i, + sane_strstatus(status)); + return status; + } + } + } + if (set == AFE_SET) + { + /* write them to analog frontend */ + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg 0x01 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* Write fe 0x02 (red gain)*/ + status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.get_gain(0)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing fe 0x02 (gain r) fail: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* Write fe 0x03 (green gain)*/ + status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.get_gain(1)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing fe 0x03 (gain g) fail: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* Write fe 0x04 (blue gain)*/ + status = sanei_genesys_fe_write_data(dev, 0x04, dev->frontend.get_gain(2)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing fe 0x04 (gain b) fail: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* Write fe 0x05 (red offset)*/ + status = + sanei_genesys_fe_write_data(dev, 0x05, dev->frontend.get_offset(0)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: write fe 0x05 (offset r) fail: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* Write fe 0x06 (green offset)*/ + status = + sanei_genesys_fe_write_data(dev, 0x06, dev->frontend.get_offset(1)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: write fe 0x06 (offset g) fail: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* Write fe 0x07 (blue offset)*/ + status = + sanei_genesys_fe_write_data(dev, 0x07, dev->frontend.get_offset(2)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: write fe 0x07 (offset b) fail: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + DBG(DBG_proc, "%s(): end\n", __func__); + + return status; +} + +/* Set values of analog frontend */ +static SANE_Status +gl841_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) +{ + (void) sensor; + SANE_Status status = SANE_STATUS_GOOD; + int i; + + DBG(DBG_proc, "%s (%s)\n", __func__, + set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == + AFE_POWER_SAVE ? "powersave" : "huh?"); + + /* Analog Device type frontend */ + if ((dev->reg.find_reg(0x04).value & REG04_FESET) == 0x02) + { + return gl841_set_ad_fe (dev, set); + } + + if ((dev->reg.find_reg(0x04).value & REG04_FESET) != 0x00) + { + DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, + dev->reg.find_reg(0x04).value & REG04_FESET); + return SANE_STATUS_UNSUPPORTED; + } + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + dev->frontend = dev->frontend_initial; + + /* reset only done on init */ + status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: reset fe failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); + } + + + if (set == AFE_POWER_SAVE) + { + status = sanei_genesys_fe_write_data (dev, 0x01, 0x02); + if (status != SANE_STATUS_GOOD) { + DBG(DBG_error, "%s: writing data failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + return status; + } + + /* todo : base this test on cfg reg3 or a CCD family flag to be created */ + /*if (dev->model->ccd_type!=CCD_HP2300 && dev->model->ccd_type!=CCD_HP2400) */ + { + + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg0 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.regs.get_value(0x02)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg2 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x03)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg3 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_fe_write_data (dev, 0x06, dev->frontend.reg2[0]); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg6 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_fe_write_data (dev, 0x08, dev->frontend.reg2[1]); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg8 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_fe_write_data (dev, 0x09, dev->frontend.reg2[2]); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg9 failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + for (i = 0; i < 3; i++) + { + status = + sanei_genesys_fe_write_data(dev, 0x24 + i, dev->frontend.regs.get_value(0x24 + i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing gain[%d] failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + + status = + sanei_genesys_fe_write_data(dev, 0x20 + i, + dev->frontend.get_offset(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing offset[%d] failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + + + DBG(DBG_proc, "%s: completed\n", __func__); + + return SANE_STATUS_GOOD; +} + +#define MOTOR_ACTION_FEED 1 +#define MOTOR_ACTION_GO_HOME 2 +#define MOTOR_ACTION_HOME_FREE 3 + +/** @brief turn off motor + * + */ +static SANE_Status +gl841_init_motor_regs_off(Genesys_Register_Set * reg, + unsigned int scan_lines) +{ + unsigned int feedl; + GenesysRegister* r; + + DBG(DBG_proc, "%s : scan_lines=%d\n", __func__, scan_lines); + + feedl = 2; + + r = sanei_genesys_get_address (reg, 0x3d); + r->value = (feedl >> 16) & 0xf; + r = sanei_genesys_get_address (reg, 0x3e); + r->value = (feedl >> 8) & 0xff; + r = sanei_genesys_get_address (reg, 0x3f); + r->value = feedl & 0xff; + r = sanei_genesys_get_address (reg, 0x5e); + r->value &= ~0xe0; + + r = sanei_genesys_get_address (reg, 0x25); + r->value = (scan_lines >> 16) & 0xf; + r = sanei_genesys_get_address (reg, 0x26); + r->value = (scan_lines >> 8) & 0xff; + r = sanei_genesys_get_address (reg, 0x27); + r->value = scan_lines & 0xff; + + r = sanei_genesys_get_address (reg, 0x02); + r->value &= ~0x01; /*LONGCURV OFF*/ + r->value &= ~0x80; /*NOT_HOME OFF*/ + + r->value &= ~0x10; + + r->value &= ~0x06; + + r->value &= ~0x08; + + r->value &= ~0x20; + + r->value &= ~0x40; + + r = sanei_genesys_get_address (reg, 0x67); + r->value = 0x3f; + + r = sanei_genesys_get_address (reg, 0x68); + r->value = 0x3f; + + r = sanei_genesys_get_address (reg, REG_STEPNO); + r->value = 0; + + r = sanei_genesys_get_address (reg, REG_FASTNO); + r->value = 0; + + r = sanei_genesys_get_address (reg, 0x69); + r->value = 0; + + r = sanei_genesys_get_address (reg, 0x6a); + r->value = 0; + + r = sanei_genesys_get_address (reg, 0x5f); + r->value = 0; + + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief write motor table frequency + * Write motor frequency data table. + * @param dev device to set up motor + * @param ydpi motor target resolution + * @return SANE_STATUS_GOOD on success + */ +static SANE_Status gl841_write_freq(Genesys_Device *dev, unsigned int ydpi) +{ +SANE_Status status = SANE_STATUS_GOOD; +/**< fast table */ +uint8_t tdefault[] = {0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76}; +uint8_t t1200[] = {0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20}; +uint8_t t300[] = {0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60}; +uint8_t t150[] = {0x0c,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0x40,0x14,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x0c,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0x11,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x0c,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0x40,0xd4,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x0c,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0x11,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60}; + +uint8_t *table; + + DBGSTART; + if(dev->model->motor_type == MOTOR_CANONLIDE80) + { + switch(ydpi) + { + case 3600: + case 1200: + table=t1200; + break; + case 900: + case 300: + table=t300; + break; + case 450: + case 150: + table=t150; + break; + default: + table=tdefault; + } + RIE(sanei_genesys_write_register(dev, 0x66, 0x00)); + RIE(sanei_genesys_write_register(dev, 0x5b, 0x0c)); + RIE(sanei_genesys_write_register(dev, 0x5c, 0x00)); + RIE(sanei_genesys_bulk_write_data(dev, 0x28, table, 128)); + RIE(sanei_genesys_write_register(dev, 0x5b, 0x00)); + RIE(sanei_genesys_write_register(dev, 0x5c, 0x00)); + } + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +static SANE_Status +gl841_init_motor_regs(Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int feed_steps,/*1/base_ydpi*/ +/*maybe float for half/quarter step resolution?*/ + unsigned int action, + unsigned int flags) +{ + SANE_Status status = SANE_STATUS_GOOD; + unsigned int fast_exposure; + int scan_power_mode; + int use_fast_fed = 0; + uint16_t fast_slope_table[256]; + unsigned int fast_slope_steps = 0; + unsigned int feedl; + GenesysRegister* r; +/*number of scan lines to add in a scan_lines line*/ + + DBG(DBG_proc, "%s : feed_steps=%d, action=%d, flags=%x\n", __func__, feed_steps, action, flags); + + memset(fast_slope_table,0xff,512); + + gl841_send_slope_table (dev, 0, fast_slope_table, 256); + gl841_send_slope_table (dev, 1, fast_slope_table, 256); + gl841_send_slope_table (dev, 2, fast_slope_table, 256); + gl841_send_slope_table (dev, 3, fast_slope_table, 256); + gl841_send_slope_table (dev, 4, fast_slope_table, 256); + + gl841_write_freq(dev, dev->motor.base_ydpi / 4); + + fast_slope_steps = 256; + if (action == MOTOR_ACTION_FEED || action == MOTOR_ACTION_GO_HOME) + { + /* FEED and GO_HOME can use fastest slopes available */ + fast_exposure = gl841_exposure_time(dev, sensor, + dev->motor.base_ydpi / 4, + 0, + 0, + 0, + &scan_power_mode); + DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); + } + + if (action == MOTOR_ACTION_HOME_FREE) { +/* HOME_FREE must be able to stop in one step, so do not try to get faster */ + fast_exposure = dev->motor.slopes[0][0].maximum_start_speed; + } + + sanei_genesys_create_slope_table3 ( + dev, + fast_slope_table, + 256, + fast_slope_steps, + 0, + fast_exposure, + dev->motor.base_ydpi / 4, + &fast_slope_steps, + &fast_exposure, 0); + + feedl = feed_steps - fast_slope_steps*2; + use_fast_fed = 1; + +/* all needed slopes available. we did even decide which mode to use. + what next? + - transfer slopes +SCAN: +flags \ use_fast_fed ! 0 1 +------------------------\-------------------- + 0 ! 0,1,2 0,1,2,3 +MOTOR_FLAG_AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 +OFF: none +FEED: 3 +GO_HOME: 3 +HOME_FREE: 3 + - setup registers + * slope specific registers (already done) + * DECSEL for HOME_FREE/GO_HOME/SCAN + * FEEDL + * MTRREV + * MTRPWR + * FASTFED + * STEPSEL + * MTRPWM + * FSTPSEL + * FASTPWM + * HOMENEG + * BWDSTEP + * FWDSTEP + * Z1 + * Z2 + */ + + r = sanei_genesys_get_address(reg, 0x3d); + r->value = (feedl >> 16) & 0xf; + r = sanei_genesys_get_address(reg, 0x3e); + r->value = (feedl >> 8) & 0xff; + r = sanei_genesys_get_address(reg, 0x3f); + r->value = feedl & 0xff; + r = sanei_genesys_get_address(reg, 0x5e); + r->value &= ~0xe0; + + r = sanei_genesys_get_address(reg, 0x25); + r->value = 0; + r = sanei_genesys_get_address(reg, 0x26); + r->value = 0; + r = sanei_genesys_get_address(reg, 0x27); + r->value = 0; + + r = sanei_genesys_get_address(reg, 0x02); + r->value &= ~0x01; /*LONGCURV OFF*/ + r->value &= ~0x80; /*NOT_HOME OFF*/ + + r->value |= 0x10; + + if (action == MOTOR_ACTION_GO_HOME) + r->value |= 0x06; + else + r->value &= ~0x06; + + if (use_fast_fed) + r->value |= 0x08; + else + r->value &= ~0x08; + + if (flags & MOTOR_FLAG_AUTO_GO_HOME) + r->value |= 0x20; + else + r->value &= ~0x20; + + r->value &= ~0x40; + + status = gl841_send_slope_table (dev, 3, fast_slope_table, 256); + + if (status != SANE_STATUS_GOOD) + return status; + + r = sanei_genesys_get_address(reg, 0x67); + r->value = 0x3f; + + r = sanei_genesys_get_address(reg, 0x68); + r->value = 0x3f; + + r = sanei_genesys_get_address(reg, REG_STEPNO); + r->value = 0; + + r = sanei_genesys_get_address(reg, REG_FASTNO); + r->value = 0; + + r = sanei_genesys_get_address(reg, 0x69); + r->value = 0; + + r = sanei_genesys_get_address(reg, 0x6a); + r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); + + r = sanei_genesys_get_address(reg, 0x5f); + r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); + + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl841_init_motor_regs_scan(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int scan_exposure_time,/*pixel*/ + float scan_yres,/*dpi, motor resolution*/ + int scan_step_type,/*0: full, 1: half, 2: quarter*/ + unsigned int scan_lines,/*lines, scan resolution*/ + unsigned int scan_dummy, +/*number of scan lines to add in a scan_lines line*/ + unsigned int feed_steps,/*1/base_ydpi*/ +/*maybe float for half/quarter step resolution?*/ + int scan_power_mode, + unsigned int flags) +{ + SANE_Status status = SANE_STATUS_GOOD; + unsigned int fast_exposure; + int use_fast_fed = 0; + int dummy_power_mode; + unsigned int fast_time; + unsigned int slow_time; + uint16_t slow_slope_table[256]; + uint16_t fast_slope_table[256]; + uint16_t back_slope_table[256]; + unsigned int slow_slope_time; + unsigned int fast_slope_time; + unsigned int slow_slope_steps = 0; + unsigned int fast_slope_steps = 0; + unsigned int back_slope_steps = 0; + unsigned int feedl; + GenesysRegister* r; + unsigned int min_restep = 0x20; + uint32_t z1, z2; + + DBG(DBG_proc, "%s : scan_exposure_time=%d, scan_yres=%g, scan_step_type=%d, scan_lines=%d," + " scan_dummy=%d, feed_steps=%d, scan_power_mode=%d, flags=%x\n", __func__, + scan_exposure_time, + scan_yres, + scan_step_type, + scan_lines, + scan_dummy, + feed_steps, + scan_power_mode, + flags); + + fast_exposure = gl841_exposure_time(dev, sensor, + dev->motor.base_ydpi / 4, + 0, + 0, + 0, + &dummy_power_mode); + + DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); + + memset(slow_slope_table,0xff,512); + + gl841_send_slope_table (dev, 0, slow_slope_table, 256); + gl841_send_slope_table (dev, 1, slow_slope_table, 256); + gl841_send_slope_table (dev, 2, slow_slope_table, 256); + gl841_send_slope_table (dev, 3, slow_slope_table, 256); + gl841_send_slope_table (dev, 4, slow_slope_table, 256); + + /* motor frequency table */ + gl841_write_freq(dev, scan_yres); + +/* + we calculate both tables for SCAN. the fast slope step count depends on + how many steps we need for slow acceleration and how much steps we are + allowed to use. + */ + slow_slope_time = sanei_genesys_create_slope_table3 ( + dev, + slow_slope_table, 256, + 256, + scan_step_type, + scan_exposure_time, + scan_yres, + &slow_slope_steps, + NULL, + scan_power_mode); + + sanei_genesys_create_slope_table3 ( + dev, + back_slope_table, 256, + 256, + scan_step_type, + 0, + scan_yres, + &back_slope_steps, + NULL, + scan_power_mode); + + if (feed_steps < (slow_slope_steps >> scan_step_type)) { + /*TODO: what should we do here?? go back to exposure calculation?*/ + feed_steps = slow_slope_steps >> scan_step_type; + } + + if (feed_steps > fast_slope_steps*2 - + (slow_slope_steps >> scan_step_type)) + fast_slope_steps = 256; + else +/* we need to shorten fast_slope_steps here. */ + fast_slope_steps = (feed_steps - + (slow_slope_steps >> scan_step_type))/2; + + DBG(DBG_info, "%s: Maximum allowed slope steps for fast slope: %d\n", __func__, + fast_slope_steps); + + fast_slope_time = sanei_genesys_create_slope_table3 ( + dev, + fast_slope_table, 256, + fast_slope_steps, + 0, + fast_exposure, + dev->motor.base_ydpi / 4, + &fast_slope_steps, + &fast_exposure, + scan_power_mode); + + /* fast fed special cases handling */ + if (dev->model->gpo_type == GPO_XP300 + || dev->model->gpo_type == GPO_DP685) + { + /* quirk: looks like at least this scanner is unable to use + 2-feed mode */ + use_fast_fed = 0; + } + else if (feed_steps < fast_slope_steps*2 + (slow_slope_steps >> scan_step_type)) { + use_fast_fed = 0; + DBG(DBG_info, "%s: feed too short, slow move forced.\n", __func__); + } else { +/* for deciding whether we should use fast mode we need to check how long we + need for (fast)accelerating, moving, decelerating, (TODO: stopping?) + (slow)accelerating again versus (slow)accelerating and moving. we need + fast and slow tables here. +*/ +/*NOTE: scan_exposure_time is per scan_yres*/ +/*NOTE: fast_exposure is per base_ydpi/4*/ +/*we use full steps as base unit here*/ + fast_time = + fast_exposure / 4 * + (feed_steps - fast_slope_steps*2 - + (slow_slope_steps >> scan_step_type)) + + fast_slope_time*2 + slow_slope_time; + slow_time = + (scan_exposure_time * scan_yres) / dev->motor.base_ydpi * + (feed_steps - (slow_slope_steps >> scan_step_type)) + + slow_slope_time; + + DBG(DBG_info, "%s: Time for slow move: %d\n", __func__, slow_time); + DBG(DBG_info, "%s: Time for fast move: %d\n", __func__, fast_time); + + use_fast_fed = fast_time < slow_time; + } + + if (use_fast_fed) + feedl = feed_steps - fast_slope_steps*2 - + (slow_slope_steps >> scan_step_type); + else + if ((feed_steps << scan_step_type) < slow_slope_steps) + feedl = 0; + else + feedl = (feed_steps << scan_step_type) - slow_slope_steps; + DBG(DBG_info, "%s: Decided to use %s mode\n", __func__, use_fast_fed?"fast feed":"slow feed"); + +/* all needed slopes available. we did even decide which mode to use. + what next? + - transfer slopes +SCAN: +flags \ use_fast_fed ! 0 1 +------------------------\-------------------- + 0 ! 0,1,2 0,1,2,3 +MOTOR_FLAG_AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 +OFF: none +FEED: 3 +GO_HOME: 3 +HOME_FREE: 3 + - setup registers + * slope specific registers (already done) + * DECSEL for HOME_FREE/GO_HOME/SCAN + * FEEDL + * MTRREV + * MTRPWR + * FASTFED + * STEPSEL + * MTRPWM + * FSTPSEL + * FASTPWM + * HOMENEG + * BWDSTEP + * FWDSTEP + * Z1 + * Z2 + */ + + r = sanei_genesys_get_address (reg, 0x3d); + r->value = (feedl >> 16) & 0xf; + r = sanei_genesys_get_address (reg, 0x3e); + r->value = (feedl >> 8) & 0xff; + r = sanei_genesys_get_address (reg, 0x3f); + r->value = feedl & 0xff; + r = sanei_genesys_get_address (reg, 0x5e); + r->value &= ~0xe0; + + r = sanei_genesys_get_address (reg, 0x25); + r->value = (scan_lines >> 16) & 0xf; + r = sanei_genesys_get_address (reg, 0x26); + r->value = (scan_lines >> 8) & 0xff; + r = sanei_genesys_get_address (reg, 0x27); + r->value = scan_lines & 0xff; + + r = sanei_genesys_get_address (reg, 0x02); + r->value &= ~0x01; /*LONGCURV OFF*/ + r->value &= ~0x80; /*NOT_HOME OFF*/ + r->value |= 0x10; + + r->value &= ~0x06; + + if (use_fast_fed) + r->value |= 0x08; + else + r->value &= ~0x08; + + if (flags & MOTOR_FLAG_AUTO_GO_HOME) + r->value |= 0x20; + else + r->value &= ~0x20; + + if (flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) + r->value |= 0x40; + else + r->value &= ~0x40; + + status = gl841_send_slope_table (dev, 0, slow_slope_table, 256); + + if (status != SANE_STATUS_GOOD) + return status; + + status = gl841_send_slope_table (dev, 1, back_slope_table, 256); + + if (status != SANE_STATUS_GOOD) + return status; + + status = gl841_send_slope_table (dev, 2, slow_slope_table, 256); + + if (status != SANE_STATUS_GOOD) + return status; + + if (use_fast_fed) { + status = gl841_send_slope_table (dev, 3, fast_slope_table, 256); + + if (status != SANE_STATUS_GOOD) + return status; + } + + if (flags & MOTOR_FLAG_AUTO_GO_HOME){ + status = gl841_send_slope_table (dev, 4, fast_slope_table, 256); + + if (status != SANE_STATUS_GOOD) + return status; + } + + +/* now reg 0x21 and 0x24 are available, we can calculate reg 0x22 and 0x23, + reg 0x60-0x62 and reg 0x63-0x65 + rule: + 2*STEPNO+FWDSTEP=2*FASTNO+BWDSTEP +*/ +/* steps of table 0*/ + if (min_restep < slow_slope_steps*2+2) + min_restep = slow_slope_steps*2+2; +/* steps of table 1*/ + if (min_restep < back_slope_steps*2+2) + min_restep = back_slope_steps*2+2; +/* steps of table 0*/ + r = sanei_genesys_get_address (reg, REG_FWDSTEP); + r->value = min_restep - slow_slope_steps*2; +/* steps of table 1*/ + r = sanei_genesys_get_address (reg, REG_BWDSTEP); + r->value = min_restep - back_slope_steps*2; + +/* + for z1/z2: + in dokumentation mentioned variables a-d: + a = time needed for acceleration, table 1 + b = time needed for reg 0x1f... wouldn't that be reg0x1f*exposure_time? + c = time needed for acceleration, table 1 + d = time needed for reg 0x22... wouldn't that be reg0x22*exposure_time? + z1 = (c+d-1) % exposure_time + z2 = (a+b-1) % exposure_time +*/ +/* i don't see any effect of this. i can only guess that this will enhance + sub-pixel accuracy + z1 = (slope_0_time-1) % exposure_time; + z2 = (slope_0_time-1) % exposure_time; +*/ + z1 = z2 = 0; + + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + r = sanei_genesys_get_address (reg, 0x60); + r->value = ((z1 >> 16) & 0xff); + r = sanei_genesys_get_address (reg, 0x61); + r->value = ((z1 >> 8) & 0xff); + r = sanei_genesys_get_address (reg, 0x62); + r->value = (z1 & 0xff); + r = sanei_genesys_get_address (reg, 0x63); + r->value = ((z2 >> 16) & 0xff); + r = sanei_genesys_get_address (reg, 0x64); + r->value = ((z2 >> 8) & 0xff); + r = sanei_genesys_get_address (reg, 0x65); + r->value = (z2 & 0xff); + + r = sanei_genesys_get_address (reg, REG1E); + r->value &= REG1E_WDTIME; + r->value |= scan_dummy; + + r = sanei_genesys_get_address (reg, 0x67); + r->value = 0x3f | (scan_step_type << 6); + + r = sanei_genesys_get_address (reg, 0x68); + r->value = 0x3f; + + r = sanei_genesys_get_address (reg, REG_STEPNO); + r->value = (slow_slope_steps >> 1) + (slow_slope_steps & 1); + + r = sanei_genesys_get_address (reg, REG_FASTNO); + r->value = (back_slope_steps >> 1) + (back_slope_steps & 1); + + r = sanei_genesys_get_address (reg, 0x69); + r->value = (slow_slope_steps >> 1) + (slow_slope_steps & 1); + + r = sanei_genesys_get_address (reg, 0x6a); + r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); + + r = sanei_genesys_get_address (reg, 0x5f); + r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); + + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static int +gl841_get_dpihw(Genesys_Device * dev) +{ + GenesysRegister* r; + r = sanei_genesys_get_address(&dev->reg, 0x05); + if ((r->value & REG05_DPIHW) == REG05_DPIHW_600) + return 600; + if ((r->value & REG05_DPIHW) == REG05_DPIHW_1200) + return 1200; + if ((r->value & REG05_DPIHW) == REG05_DPIHW_2400) + return 2400; + return 0; +} + +static SANE_Status +gl841_init_optical_regs_off(Genesys_Register_Set * reg) +{ + GenesysRegister* r; + + DBGSTART; + + r = sanei_genesys_get_address(reg, 0x01); + r->value &= ~REG01_SCAN; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl841_init_optical_regs_scan(Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int exposure_time, + unsigned int used_res, + unsigned int start, + unsigned int pixels, + int channels, + int depth, + SANE_Bool half_ccd, + ColorFilter color_filter, + int flags + ) +{ + unsigned int words_per_line; + unsigned int end; + unsigned int dpiset; + GenesysRegister* r; + SANE_Status status = SANE_STATUS_GOOD; + uint16_t expavg, expr, expb, expg; + + DBG(DBG_proc, "%s : exposure_time=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " + "half_ccd=%d, flags=%x\n", __func__, + exposure_time, + used_res, + start, + pixels, + channels, + depth, + half_ccd, + flags); + + end = start + pixels; + + status = gl841_set_fe(dev, sensor, AFE_SET); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* adjust used_res for chosen dpihw */ + used_res = used_res * gl841_get_dpihw(dev) / sensor.optical_res; + +/* + with half_ccd the optical resolution of the ccd is halved. We don't apply this + to dpihw, so we need to double dpiset. + + For the scanner only the ratio of dpiset and dpihw is of relevance to scale + down properly. +*/ + if (half_ccd) + dpiset = used_res * 2; + else + dpiset = used_res; + + /* gpio part.*/ + if (dev->model->gpo_type == GPO_CANONLIDE35) + { + r = sanei_genesys_get_address (reg, REG6C); + if (half_ccd) + r->value &= ~0x80; + else + r->value |= 0x80; + } + if (dev->model->gpo_type == GPO_CANONLIDE80) + { + r = sanei_genesys_get_address (reg, REG6C); + if (half_ccd) + { + r->value &= ~0x40; + r->value |= 0x20; + } + else + { + r->value &= ~0x20; + r->value |= 0x40; + } + } + + /* enable shading */ + r = sanei_genesys_get_address (reg, 0x01); + r->value |= REG01_SCAN; + if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + r->value &= ~REG01_DVDSET; + else + r->value |= REG01_DVDSET; + + /* average looks better than deletion, and we are already set up to + use one of the average enabled resolutions + */ + r = sanei_genesys_get_address (reg, 0x03); + r->value |= REG03_AVEENB; + sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); + + /* BW threshold */ + r = sanei_genesys_get_address (reg, 0x2e); + r->value = dev->settings.threshold; + r = sanei_genesys_get_address (reg, 0x2f); + r->value = dev->settings.threshold; + + + /* monochrome / color scan */ + r = sanei_genesys_get_address (reg, 0x04); + switch (depth) { + case 1: + r->value &= ~REG04_BITSET; + r->value |= REG04_LINEART; + break; + case 8: + r->value &= ~(REG04_LINEART | REG04_BITSET); + break; + case 16: + r->value &= ~REG04_LINEART; + r->value |= REG04_BITSET; + break; + } + + /* AFEMOD should depend on FESET, and we should set these + * bits separately */ + r->value &= ~(REG04_FILTER | REG04_AFEMOD); + if (flags & OPTICAL_FLAG_ENABLE_LEDADD) + { + r->value |= 0x10; /* no filter */ + } + else if (channels == 1) + { + switch (color_filter) + { + case ColorFilter::RED: + r->value |= 0x14; + break; + case ColorFilter::GREEN: + r->value |= 0x18; + break; + case ColorFilter::BLUE: + r->value |= 0x1c; + break; + default: + r->value |= 0x10; + break; + } + } + else + { + if (dev->model->ccd_type == CCD_PLUSTEK_3600) + { + r->value |= 0x22; /* slow color pixel by pixel */ + } + else + { + r->value |= 0x10; /* color pixel by pixel */ + } + } + + /* CIS scanners can do true gray by setting LEDADD */ + r = sanei_genesys_get_address (reg, 0x87); + r->value &= ~REG87_LEDADD; + if (flags & OPTICAL_FLAG_ENABLE_LEDADD) + { + r->value |= REG87_LEDADD; + sanei_genesys_get_double (reg, REG_EXPR, &expr); + sanei_genesys_get_double (reg, REG_EXPG, &expg); + sanei_genesys_get_double (reg, REG_EXPB, &expb); + + /* use minimal exposure for best image quality */ + expavg = expg; + if (expr < expg) + expavg = expr; + if (expb < expavg) + expavg = expb; + + sanei_genesys_set_double(&dev->reg, REG_EXPR, expavg); + sanei_genesys_set_double(&dev->reg, REG_EXPG, expavg); + sanei_genesys_set_double(&dev->reg, REG_EXPB, expavg); + } + + /* enable gamma tables */ + r = sanei_genesys_get_address (reg, 0x05); + if (flags & OPTICAL_FLAG_DISABLE_GAMMA) + r->value &= ~REG05_GMMENB; + else + r->value |= REG05_GMMENB; + + /* sensor parameters */ + sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 1, half_ccd); + + r = sanei_genesys_get_address (reg, 0x29); + r->value = 255; /*<<<"magic" number, only suitable for cis*/ + + sanei_genesys_set_double(reg, REG_DPISET, dpiset); + sanei_genesys_set_double(reg, REG_STRPIXEL, start); + sanei_genesys_set_double(reg, REG_ENDPIXEL, end); + DBG(DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d\n", __func__, start, end); + + /* words(16bit) before gamma, conversion to 8 bit or lineart*/ + words_per_line = (pixels * dpiset) / gl841_get_dpihw(dev); + + words_per_line *= channels; + + if (depth == 1) + words_per_line = (words_per_line >> 3) + ((words_per_line & 7)?1:0); + else + words_per_line *= depth / 8; + + dev->wpl = words_per_line; + dev->bpl = words_per_line; + + r = sanei_genesys_get_address (reg, 0x35); + r->value = LOBYTE (HIWORD (words_per_line)); + r = sanei_genesys_get_address (reg, 0x36); + r->value = HIBYTE (LOWORD (words_per_line)); + r = sanei_genesys_get_address (reg, 0x37); + r->value = LOBYTE (LOWORD (words_per_line)); + + sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); + + r = sanei_genesys_get_address (reg, 0x34); + r->value = sensor.dummy_pixel; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static int +gl841_get_led_exposure(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int d,r,g,b,m; + if (!dev->model->is_cis) + return 0; + d = dev->reg.find_reg(0x19).value; + + r = sensor.exposure.red; + g = sensor.exposure.green; + b = sensor.exposure.blue; + + m = r; + if (m < g) + m = g; + if (m < b) + m = b; + + return m + d; +} + +/** @brief compute exposure time + * Compute exposure time for the device and the given scan resolution, + * also compute scan_power_mode + */ +static int +gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, + float slope_dpi, + int scan_step_type, + int start, + int used_pixels, + int *scan_power_mode) +{ +int exposure_time = 0; +int exposure_time2 = 0; +int led_exposure; + + *scan_power_mode=0; + led_exposure=gl841_get_led_exposure(dev, sensor); + exposure_time = sanei_genesys_exposure_time2( + dev, + slope_dpi, + scan_step_type, + start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ + led_exposure, + *scan_power_mode); + + while(*scan_power_mode + 1 < dev->motor.power_mode_count) { + exposure_time2 = sanei_genesys_exposure_time2( + dev, + slope_dpi, + scan_step_type, + start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ + led_exposure, + *scan_power_mode + 1); + if (exposure_time < exposure_time2) + break; + exposure_time = exposure_time2; + (*scan_power_mode)++; + } + + return exposure_time; +} + +/**@brief compute scan_step_type + * Try to do at least 4 steps per line. if that is impossible we will have to + * live with that. + * @param dev device + * @param yres motor resolution + */ +static int +gl841_scan_step_type(Genesys_Device *dev, int yres) +{ +int scan_step_type=0; + + /* TODO : check if there is a bug around the use of max_step_type */ + /* should be <=1, need to chek all devices entry in genesys_devices */ + if (yres*4 < dev->motor.base_ydpi || dev->motor.max_step_type <= 0) + { + scan_step_type = 0; + } + else if (yres*4 < dev->motor.base_ydpi*2 || dev->motor.max_step_type <= 1) + { + scan_step_type = 1; + } + else + { + scan_step_type = 2; + } + + /* this motor behaves differently */ + if (dev->model->motor_type==MOTOR_CANONLIDE80) + { + /* driven by 'frequency' tables ? */ + scan_step_type = 0; + } + + return scan_step_type; +} + +/* set up registers for an actual scan + * + * this function sets up the scanner to scan in normal or single line mode + */ +static +SANE_Status +gl841_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SetupParams& params) +{ + params.assert_valid(); + + int used_res; + int start, used_pixels; + int bytes_per_line; + int move; + unsigned int lincnt; + int exposure_time; + int scan_power_mode; + int i; + int stagger; + int avg; + + int slope_dpi = 0; + int dummy = 0; + int scan_step_type = 1; + int max_shift; + size_t requested_buffer_size, read_buffer_size; + + SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ + int optical_res; + SANE_Status status = SANE_STATUS_GOOD; + unsigned int oflags; /**> optical flags */ + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + +/* +results: + +for scanner: +half_ccd +start +end +dpiset +exposure_time +dummy +z1 +z2 + +for ordered_read: + dev->words_per_line + dev->read_factor + dev->requested_buffer_size + dev->read_buffer_size + dev->read_pos + dev->read_bytes_in_buffer + dev->read_bytes_left + dev->max_shift + dev->stagger + +independent of our calculated values: + dev->total_bytes_read + dev->bytes_to_read + */ + +/* half_ccd */ + /* we have 2 domains for ccd: xres below or above half ccd max dpi */ + if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) { + half_ccd = SANE_TRUE; + } else { + half_ccd = SANE_FALSE; + } + +/* optical_res */ + + optical_res = sensor.optical_res; + if (half_ccd) + optical_res /= 2; + +/* stagger */ + + if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG(DBG_info, "%s : stagger=%d lines\n", __func__, stagger); + +/* used_res */ + i = optical_res / params.xres; + +/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ + + if (i < 2 || (params.flags & SCAN_FLAG_USE_OPTICAL_RES)) /* optical_res >= xres > optical_res/2 */ + used_res = optical_res; + else if (i < 3) /* optical_res/2 >= xres > optical_res/3 */ + used_res = optical_res/2; + else if (i < 4) /* optical_res/3 >= xres > optical_res/4 */ + used_res = optical_res/3; + else if (i < 5) /* optical_res/4 >= xres > optical_res/5 */ + used_res = optical_res/4; + else if (i < 6) /* optical_res/5 >= xres > optical_res/6 */ + used_res = optical_res/5; + else if (i < 8) /* optical_res/6 >= xres > optical_res/8 */ + used_res = optical_res/6; + else if (i < 10) /* optical_res/8 >= xres > optical_res/10 */ + used_res = optical_res/8; + else if (i < 12) /* optical_res/10 >= xres > optical_res/12 */ + used_res = optical_res/10; + else if (i < 15) /* optical_res/12 >= xres > optical_res/15 */ + used_res = optical_res/12; + else + used_res = optical_res/15; + + /* compute scan parameters values */ + /* pixels are allways given at half or full CCD optical resolution */ + /* use detected left margin and fixed value */ + /* start */ + /* add x coordinates */ + start = ((sensor.CCD_start_xoffset + params.startx) * used_res) / sensor.optical_res; + + /* needs to be aligned for used_res */ + start = (start * optical_res) / used_res; + + start += sensor.dummy_pixel + 1; + + if (stagger > 0) + start |= 1; + + /* in case of SHDAREA, we need to align start + * on pixel average factor, startx is different of + * 0 only when calling for function to setup for + * scan, where shading data needs to be align */ + if((dev->reg.find_reg(0x01).value & REG01_SHDAREA) != 0) + { + avg=optical_res/used_res; + start=(start/avg)*avg; + } + + /* compute correct pixels number */ + /* pixels */ + used_pixels = (params.pixels * optical_res) / params.xres; + + /* round up pixels number if needed */ + if (used_pixels * params.xres < params.pixels * optical_res) + used_pixels++; + +/* dummy */ + /* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1 + dummy line. Maybe the dummy line adds correctness since the motor runs + slower (higher dpi) + */ +/* for cis this creates better aligned color lines: +dummy \ scanned lines + 0: R G B R ... + 1: R G B - R ... + 2: R G B - - R ... + 3: R G B - - - R ... + 4: R G B - - - - R ... + 5: R G B - - - - - R ... + 6: R G B - - - - - - R ... + 7: R G B - - - - - - - R ... + 8: R G B - - - - - - - - R ... + 9: R G B - - - - - - - - - R ... + 10: R G B - - - - - - - - - - R ... + 11: R G B - - - - - - - - - - - R ... + 12: R G B - - - - - - - - - - - - R ... + 13: R G B - - - - - - - - - - - - - R ... + 14: R G B - - - - - - - - - - - - - - R ... + 15: R G B - - - - - - - - - - - - - - - R ... + -- pierre + */ + dummy = 0; + +/* slope_dpi */ +/* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) + slope_dpi = params.yres* params.channels; + else + slope_dpi = params.yres; + + slope_dpi = slope_dpi * (1 + dummy); + + scan_step_type = gl841_scan_step_type(dev, params.yres); + exposure_time = gl841_exposure_time(dev, sensor, + slope_dpi, + scan_step_type, + start, + used_pixels, + &scan_power_mode); + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + + /*** optical parameters ***/ + /* in case of dynamic lineart, we use an internal 8 bit gray scan + * to generate 1 lineart data */ + if(params.flags & SCAN_FLAG_DYNAMIC_LINEART) + { + params.depth=8; + } + + oflags=0; + if (params.flags & SCAN_FLAG_DISABLE_SHADING) + { + oflags |= OPTICAL_FLAG_DISABLE_SHADING; + } + if ((params.flags & SCAN_FLAG_DISABLE_GAMMA) || (params.depth==16)) + { + oflags |= OPTICAL_FLAG_DISABLE_GAMMA; + } + if (params.flags & SCAN_FLAG_DISABLE_LAMP) + { + oflags |= OPTICAL_FLAG_DISABLE_LAMP; + } + if (params.flags & SCAN_FLAG_ENABLE_LEDADD) + { + oflags |= OPTICAL_FLAG_ENABLE_LEDADD; + } + + status = gl841_init_optical_regs_scan(dev, sensor, + reg, + exposure_time, + used_res, + start, + used_pixels, + params.channels, + params.depth, + half_ccd, + params.color_filter, + oflags); + if (status != SANE_STATUS_GOOD) + { + return status; + } + +/*** motor parameters ***/ + + /* scanned area must be enlarged by max color shift needed */ + max_shift=sanei_genesys_compute_max_shift(dev, params.channels,params.yres,params.flags); + + /* lincnt */ + lincnt = params.lines + max_shift + stagger; + + /* add tl_y to base movement */ + move = params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + /* subtract current head position */ + move -= dev->scanhead_position_in_steps; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + if (move < 0) + move = 0; + + /* round it */ +/* the move is not affected by dummy -- pierre */ +/* move = ((move + dummy) / (dummy + 1)) * (dummy + 1); + DBG(DBG_info, "%s: move=%d steps\n", __func__, move);*/ + + if (params.flags & SCAN_FLAG_SINGLE_LINE) + status = gl841_init_motor_regs_off(reg, dev->model->is_cis?lincnt* params.channels:lincnt); + else + status = gl841_init_motor_regs_scan(dev, sensor, + reg, + exposure_time, + slope_dpi, + scan_step_type, + dev->model->is_cis?lincnt* params.channels:lincnt, + dummy, + move, + scan_power_mode, + (params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE)? + MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE:0 + ); + + if (status != SANE_STATUS_GOOD) + return status; + + + /*** prepares data reordering ***/ + +/* words_per_line */ + bytes_per_line = (used_pixels * used_res) / optical_res; + bytes_per_line = (bytes_per_line * params.channels * params.depth) / 8; + + requested_buffer_size = 8 * bytes_per_line; + /* we must use a round number of bytes_per_line */ + if (requested_buffer_size > sanei_genesys_get_bulk_max_size(dev)) + requested_buffer_size = + (sanei_genesys_get_bulk_max_size(dev) / bytes_per_line) * bytes_per_line; + + read_buffer_size = + 2 * requested_buffer_size + + ((max_shift + stagger) * used_pixels * params.channels * params.depth) / 8; + + dev->read_buffer.clear(); + dev->read_buffer.alloc(read_buffer_size); + + dev->lines_buffer.clear(); + dev->lines_buffer.alloc(read_buffer_size); + + dev->shrink_buffer.clear(); + dev->shrink_buffer.alloc(requested_buffer_size); + + dev->out_buffer.clear(); + dev->out_buffer.alloc((8 * dev->settings.pixels * params.channels * params.depth) / 8); + + dev->read_bytes_left = bytes_per_line * lincnt; + + DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); + dev->read_active = SANE_TRUE; + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res)/optical_res; + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure_time; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + +/* TODO: should this be done elsewhere? */ + /* scan bytes to send to the frontend */ + /* theory : + target_size = + (dev->settings.pixels * dev->settings.lines * channels * depth) / 8; + but it suffers from integer overflow so we do the following: + + 1 bit color images store color data byte-wise, eg byte 0 contains + 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains + 8 bits of blue. + This does not fix the overflow, though. + 644mp*16 = 10gp, leading to an overflow + -- pierre + */ + + dev->total_bytes_read = 0; + if (params.depth == 1) + dev->total_bytes_to_read = + ((dev->settings.pixels * dev->settings.lines) / 8 + + (((dev->settings.pixels * dev->settings.lines)%8)?1:0) + ) * params.channels; + else + dev->total_bytes_to_read = + dev->settings.pixels * dev->settings.lines * params.channels * (params.depth / 8); + + DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); +/* END TODO */ + + DBG(DBG_proc, "%s: completed\n", __func__); + return SANE_STATUS_GOOD; +} + +static void gl841_calculate_current_setup(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int depth; + int start; + + int used_res; + int used_pixels; + unsigned int lincnt; + int exposure_time; + int scan_power_mode; + int i; + int stagger; + + int slope_dpi = 0; + int dummy = 0; + int scan_step_type = 1; + int max_shift; + + SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ + int optical_res; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + +/* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + +/* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + +/* start */ + start = SANE_UNFIX (dev->model->x_offset); + + start += dev->settings.tl_x; + + start = (start * sensor.optical_res) / MM_PER_INCH; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; + params.starty = 0; // not used + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = 0; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + +/* half_ccd */ + /* we have 2 domains for ccd: xres below or above half ccd max dpi */ + if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) { + half_ccd = SANE_TRUE; + } else { + half_ccd = SANE_FALSE; + } + +/* optical_res */ + + optical_res = sensor.optical_res; + if (half_ccd) + optical_res /= 2; + +/* stagger */ + + if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG(DBG_info, "%s: stagger=%d lines\n", __func__, stagger); + +/* used_res */ + i = optical_res / params.xres; + +/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ + + if (i < 2) /* optical_res >= xres > optical_res/2 */ + used_res = optical_res; + else if (i < 3) /* optical_res/2 >= xres > optical_res/3 */ + used_res = optical_res/2; + else if (i < 4) /* optical_res/3 >= xres > optical_res/4 */ + used_res = optical_res/3; + else if (i < 5) /* optical_res/4 >= xres > optical_res/5 */ + used_res = optical_res/4; + else if (i < 6) /* optical_res/5 >= xres > optical_res/6 */ + used_res = optical_res/5; + else if (i < 8) /* optical_res/6 >= xres > optical_res/8 */ + used_res = optical_res/6; + else if (i < 10) /* optical_res/8 >= xres > optical_res/10 */ + used_res = optical_res/8; + else if (i < 12) /* optical_res/10 >= xres > optical_res/12 */ + used_res = optical_res/10; + else if (i < 15) /* optical_res/12 >= xres > optical_res/15 */ + used_res = optical_res/12; + else + used_res = optical_res/15; + + /* compute scan parameters values */ + /* pixels are allways given at half or full CCD optical resolution */ + /* use detected left margin and fixed value */ + start = ((sensor.CCD_start_xoffset + params.startx) * used_res) / sensor.optical_res; + +/* needs to be aligned for used_res */ + start = (start * optical_res) / used_res; + + start += sensor.dummy_pixel + 1; + + if (stagger > 0) { + start |= 1; + } + + used_pixels = (params.pixels * optical_res) / params.xres; + + // round up pixels number if needed + if (used_pixels * params.xres < params.pixels * optical_res) { + used_pixels++; + } + + /* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1 + dummy line. Maybe the dummy line adds correctness since the motor runs + slower (higher dpi) + */ +/* for cis this creates better aligned color lines: +dummy \ scanned lines + 0: R G B R ... + 1: R G B - R ... + 2: R G B - - R ... + 3: R G B - - - R ... + 4: R G B - - - - R ... + 5: R G B - - - - - R ... + 6: R G B - - - - - - R ... + 7: R G B - - - - - - - R ... + 8: R G B - - - - - - - - R ... + 9: R G B - - - - - - - - - R ... + 10: R G B - - - - - - - - - - R ... + 11: R G B - - - - - - - - - - - R ... + 12: R G B - - - - - - - - - - - - R ... + 13: R G B - - - - - - - - - - - - - R ... + 14: R G B - - - - - - - - - - - - - - R ... + 15: R G B - - - - - - - - - - - - - - - R ... + -- pierre + */ + dummy = 0; + +/* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) { + slope_dpi = params.yres * params.channels; + } else { + slope_dpi = params.yres; + } + + slope_dpi = slope_dpi * (1 + dummy); + + scan_step_type = gl841_scan_step_type(dev, params.yres); + exposure_time = gl841_exposure_time(dev, sensor, + slope_dpi, + scan_step_type, + start, + used_pixels, + &scan_power_mode); + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + + /* scanned area must be enlarged by max color shift needed */ + max_shift = sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); + + lincnt = params.lines + max_shift + stagger; + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res)/optical_res; + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure_time; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + + DBGCOMPLETED; +} + +/*for fast power saving methods only, like disabling certain amplifiers*/ +static SANE_Status gl841_save_power(Genesys_Device * dev, SANE_Bool enable) +{ + uint8_t val; + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); + + if (enable) + { + if (dev->model->gpo_type == GPO_CANONLIDE35) + { +/* expect GPIO17 to be enabled, and GPIO9 to be disabled, + while GPIO8 is disabled*/ +/* final state: GPIO8 disabled, GPIO9 enabled, GPIO17 disabled, + GPIO18 disabled*/ + + sanei_genesys_read_register(dev, REG6D, &val); + sanei_genesys_write_register(dev, REG6D, val | 0x80); + + sanei_genesys_sleep_ms(1); + + /*enable GPIO9*/ + sanei_genesys_read_register(dev, REG6C, &val); + sanei_genesys_write_register(dev, REG6C, val | 0x01); + + /*disable GPO17*/ + sanei_genesys_read_register(dev, REG6B, &val); + sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO17); + + /*disable GPO18*/ + sanei_genesys_read_register(dev, REG6B, &val); + sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO18); + + sanei_genesys_sleep_ms(1); + + sanei_genesys_read_register(dev, REG6D, &val); + sanei_genesys_write_register(dev, REG6D, val & ~0x80); + + } + if (dev->model->gpo_type == GPO_DP685) + { + sanei_genesys_read_register(dev, REG6B, &val); + sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO17); + dev->reg.find_reg(0x6b).value &= ~REG6B_GPO17; + dev->calib_reg.find_reg(0x6b).value &= ~REG6B_GPO17; + } + + gl841_set_fe(dev, sensor, AFE_POWER_SAVE); + + } + else + { + if (dev->model->gpo_type == GPO_CANONLIDE35) + { +/* expect GPIO17 to be enabled, and GPIO9 to be disabled, + while GPIO8 is disabled*/ +/* final state: GPIO8 enabled, GPIO9 disabled, GPIO17 enabled, + GPIO18 enabled*/ + + sanei_genesys_read_register(dev, REG6D, &val); + sanei_genesys_write_register(dev, REG6D, val | 0x80); + + sanei_genesys_sleep_ms(10); + + /*disable GPIO9*/ + sanei_genesys_read_register(dev, REG6C, &val); + sanei_genesys_write_register(dev, REG6C, val & ~0x01); + + /*enable GPIO10*/ + sanei_genesys_read_register(dev, REG6C, &val); + sanei_genesys_write_register(dev, REG6C, val | 0x02); + + /*enable GPO17*/ + sanei_genesys_read_register(dev, REG6B, &val); + sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO17); + dev->reg.find_reg(0x6b).value |= REG6B_GPO17; + dev->calib_reg.find_reg(0x6b).value |= REG6B_GPO17; + + /*enable GPO18*/ + sanei_genesys_read_register(dev, REG6B, &val); + sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO18); + dev->reg.find_reg(0x6b).value |= REG6B_GPO18; + dev->calib_reg.find_reg(0x6b).value |= REG6B_GPO18; + + } + if (dev->model->gpo_type == GPO_DP665 + || dev->model->gpo_type == GPO_DP685) + { + sanei_genesys_read_register(dev, REG6B, &val); + sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO17); + dev->reg.find_reg(0x6b).value |= REG6B_GPO17; + dev->calib_reg.find_reg(0x6b).value |= REG6B_GPO17; + } + + } + + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl841_set_powersaving (Genesys_Device * dev, + int delay /* in minutes */ ) +{ + SANE_Status status = SANE_STATUS_GOOD; + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); + int rate, exposure_time, tgtime, time; + + DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); + + local_reg.init_reg(0x01, dev->reg.get8(0x01)); /* disable fastmode */ + local_reg.init_reg(0x03, dev->reg.get8(0x03)); /* Lamp power control */ + local_reg.init_reg(0x05, dev->reg.get8(0x05)); /*& ~REG05_BASESEL*/; /* 24 clocks/pixel */ + local_reg.init_reg(0x18, 0x00); // Set CCD type + local_reg.init_reg(0x38, 0x00); + local_reg.init_reg(0x39, 0x00); + + // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE + local_reg.init_reg(0x1c, dev->reg.get8(0x05) & ~REG1C_TGTIME); + + if (!delay) { + local_reg.find_reg(0x03).value = local_reg.find_reg(0x03).value & 0xf0; /* disable lampdog and set lamptime = 0 */ + } else if (delay < 20) { + local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ + } else { + local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ + } + + time = delay * 1000 * 60; /* -> msec */ + exposure_time = + (uint32_t) (time * 32000.0 / + (24.0 * 64.0 * (local_reg.find_reg(0x03).value & REG03_LAMPTIM) * + 1024.0) + 0.5); + /* 32000 = system clock, 24 = clocks per pixel */ + rate = (exposure_time + 65536) / 65536; + if (rate > 4) + { + rate = 8; + tgtime = 3; + } + else if (rate > 2) + { + rate = 4; + tgtime = 2; + } + else if (rate > 1) + { + rate = 2; + tgtime = 1; + } + else + { + rate = 1; + tgtime = 0; + } + + local_reg.find_reg(0x1c).value |= tgtime; + exposure_time /= rate; + + if (exposure_time > 65535) + exposure_time = 65535; + + local_reg.set8(0x38, exposure_time >> 8); + local_reg.set8(0x39, exposure_time & 255); /* lowbyte */ + + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + + DBG(DBG_proc, "%s: completed\n", __func__); + return status; +} + +static SANE_Status +gl841_start_action (Genesys_Device * dev) +{ + return sanei_genesys_write_register (dev, 0x0f, 0x01); +} + +static SANE_Status +gl841_stop_action (Genesys_Device * dev) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val40, val; + unsigned int loop; + + DBG(DBG_proc, "%s\n", __func__); + + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + status = sanei_genesys_read_register(dev, 0x40, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* only stop action if needed */ + if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) + { + DBG(DBG_info, "%s: already stopped\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + local_reg = dev->reg; + + gl841_init_optical_regs_off(&local_reg); + + gl841_init_motor_regs_off(&local_reg,0); + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* looks like writing the right registers to zero is enough to get the chip + out of scan mode into command mode, actually triggering(writing to + register 0x0f) seems to be unnecessary */ + + loop = 10; + while (loop > 0) + { + status = sanei_genesys_read_register(dev, 0x40, &val40); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* if scanner is in command mode, we are done */ + if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) + { + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + sanei_genesys_sleep_ms(100); + loop--; + } + + DBGCOMPLETED; + return SANE_STATUS_IO_ERROR; +} + +static SANE_Status +gl841_get_paper_sensor(Genesys_Device * dev, SANE_Bool * paper_loaded) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + status = sanei_genesys_read_register(dev, REG6D, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read gpio: %s\n", __func__, sane_strstatus(status)); + return status; + } + *paper_loaded = (val & 0x1) == 0; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl841_eject_document (Genesys_Device * dev) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + SANE_Bool paper_loaded; + unsigned int init_steps; + float feed_mm; + int loop; + + DBG(DBG_proc, "%s\n", __func__); + + if (dev->model->is_sheetfed == SANE_FALSE) + { + DBG(DBG_proc, "%s: there is no \"eject sheet\"-concept for non sheet fed\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; + } + + + local_reg.clear(); + val = 0; + + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read status register: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl841_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + + local_reg = dev->reg; + + gl841_init_optical_regs_off(&local_reg); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + gl841_init_motor_regs(dev, sensor, &local_reg, + 65536,MOTOR_ACTION_FEED,0); + + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + try { + status = gl841_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl841_stop_action(dev); + } catch (...) {} + try { + // restore original registers + sanei_genesys_bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl841_stop_action (dev); + /* send original registers */ + sanei_genesys_bulk_write_register(dev, dev->reg); + return status; + } + + RIE(gl841_get_paper_sensor(dev, &paper_loaded)); + if (paper_loaded) + { + DBG(DBG_info, "%s: paper still loaded\n", __func__); + /* force document TRUE, because it is definitely present */ + dev->document = SANE_TRUE; + dev->scanhead_position_in_steps = 0; + + loop = 300; + while (loop > 0) /* do not wait longer then 30 seconds */ + { + + RIE(gl841_get_paper_sensor(dev, &paper_loaded)); + + if (!paper_loaded) + { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + break; + } + sanei_genesys_sleep_ms(100); + --loop; + } + + if (loop == 0) + { + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl841_stop_action (dev); + DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); + return SANE_STATUS_IO_ERROR; + } + } + + feed_mm = SANE_UNFIX(dev->model->eject_feed); + if (dev->document) + { + feed_mm += SANE_UNFIX(dev->model->post_scan); + } + + status = sanei_genesys_read_feed_steps(dev, &init_steps); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read feed steps: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* now feed for extra steps */ + loop = 0; + while (loop < 300) /* do not wait longer then 30 seconds */ + { + unsigned int steps; + + status = sanei_genesys_read_feed_steps(dev, &steps); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read feed steps: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_info, "%s: init_steps: %d, steps: %d\n", __func__, init_steps, steps); + + if (steps > init_steps + (feed_mm * dev->motor.base_ydpi) / MM_PER_INCH) + { + break; + } + + sanei_genesys_sleep_ms(100); + ++loop; + } + + status = gl841_stop_action(dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status)); + return status; + } + + dev->document = SANE_FALSE; + + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; +} + + +static SANE_Status +gl841_load_document (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Bool paper_loaded; + int loop = 300; + DBG(DBG_proc, "%s\n", __func__); + while (loop > 0) /* do not wait longer then 30 seconds */ + { + + RIE(gl841_get_paper_sensor(dev, &paper_loaded)); + + if (paper_loaded) + { + DBG(DBG_info, "%s: document inserted\n", __func__); + + /* when loading OK, document is here */ + dev->document = SANE_TRUE; + + // give user some time to place document correctly + sanei_genesys_sleep_ms(1000); + break; + } + sanei_genesys_sleep_ms(100); + --loop; + } + + if (loop == 0) + { + /* when we come here then the user needed to much time for this */ + DBG(DBG_error, "%s: timeout while waiting for document\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; +} + +/** + * detects end of document and adjust current scan + * to take it into account + * used by sheetfed scanners + */ +static SANE_Status +gl841_detect_document_end (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Bool paper_loaded; + unsigned int scancnt = 0, lincnt, postcnt; + uint8_t val; + size_t total_bytes_to_read; + + DBG(DBG_proc, "%s: begin\n", __func__); + + RIE (gl841_get_paper_sensor (dev, &paper_loaded)); + + /* sheetfed scanner uses home sensor as paper present */ + if ((dev->document == SANE_TRUE) && !paper_loaded) + { + DBG(DBG_info, "%s: no more document\n", __func__); + dev->document = SANE_FALSE; + + /* we can't rely on total_bytes_to_read since the frontend + * might have been slow to read data, so we re-evaluate the + * amount of data to scan form the hardware settings + */ + try { + status = sanei_genesys_read_scancnt(dev, &scancnt); + } catch (...) { + dev->total_bytes_to_read = dev->total_bytes_read; + dev->read_bytes_left = 0; + throw; + } + + if(status!=SANE_STATUS_GOOD) + { + dev->total_bytes_to_read = dev->total_bytes_read; + dev->read_bytes_left = 0; + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; + } + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS && dev->model->is_cis) + { + scancnt/=3; + } + DBG(DBG_io, "%s: scancnt=%u lines\n", __func__, scancnt); + + RIE(sanei_genesys_read_register(dev, 0x25, &val)); + lincnt=65536*val; + RIE(sanei_genesys_read_register(dev, 0x26, &val)); + lincnt+=256*val; + RIE(sanei_genesys_read_register(dev, 0x27, &val)); + lincnt+=val; + DBG(DBG_io, "%s: lincnt=%u lines\n", __func__, lincnt); + postcnt=(SANE_UNFIX(dev->model->post_scan)/MM_PER_INCH)*dev->settings.yres; + DBG(DBG_io, "%s: postcnt=%u lines\n", __func__, postcnt); + + /* the current scancnt is also the final one, so we use it to + * compute total bytes to read. We also add the line count to eject document */ + total_bytes_to_read=(scancnt+postcnt)*dev->wpl; + + DBG(DBG_io, "%s: old total_bytes_to_read=%u\n", __func__, + (unsigned int)dev->total_bytes_to_read); + DBG(DBG_io, "%s: new total_bytes_to_read=%u\n", __func__, (unsigned int)total_bytes_to_read); + + /* assign new end value */ + if(dev->total_bytes_to_read>total_bytes_to_read) + { + DBG(DBG_io, "%s: scan shorten\n", __func__); + dev->total_bytes_to_read=total_bytes_to_read; + } + } + + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; +} + +/* Send the low-level scan command */ +/* todo : is this that useful ? */ +static SANE_Status +gl841_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SANE_Bool start_motor) +{ + (void) sensor; + SANE_Status status = SANE_STATUS_GOOD; + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); + uint8_t val; + + DBG(DBG_proc, "%s\n", __func__); + + if (dev->model->gpo_type == GPO_CANONLIDE80) + { + RIE (sanei_genesys_read_register (dev, REG6B, &val)); + val = REG6B_GPO18; + RIE (sanei_genesys_write_register (dev, REG6B, val)); + } + + if (dev->model->ccd_type != CCD_PLUSTEK_3600) { + local_reg.init_reg(0x03, sanei_genesys_read_reg_from_set(reg, 0x03) | REG03_LAMPPWR); + } else { + // TODO PLUSTEK_3600: why ?? + local_reg.init_reg(0x03, sanei_genesys_read_reg_from_set(reg, 0x03)); + } + + local_reg.init_reg(0x01, sanei_genesys_read_reg_from_set(reg, 0x01) | REG01_SCAN); /* set scan bit */ + local_reg.init_reg(0x0d, 0x01); + + if (start_motor) { + local_reg.init_reg(0x0f, 0x01); + } else { + // do not start motor yet + local_reg.init_reg(0x0f, 0x00); + } + + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: completed\n", __func__); + + return status; +} + + +/* Send the stop scan command */ +static SANE_Status +gl841_end_scan (Genesys_Device * dev, Genesys_Register_Set __sane_unused__ * reg, + SANE_Bool check_stop) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); + + if (dev->model->is_sheetfed == SANE_TRUE) + { + status = SANE_STATUS_GOOD; + } + else /* flat bed scanners */ + { + status = gl841_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + DBG(DBG_proc, "%s: completed\n", __func__); + + return status; +} + +/* Moves the slider to steps */ +static SANE_Status +gl841_feed (Genesys_Device * dev, int steps) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + int loop; + + DBG(DBG_proc, "%s (steps = %d)\n", __func__, steps); + + status = gl841_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop action: %s\n", __func__, sane_strstatus(status)); + return status; + } + + // FIXME: we should pick sensor according to the resolution scanner is currently operating on + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + local_reg = dev->reg; + + gl841_init_optical_regs_off(&local_reg); + + gl841_init_motor_regs(dev, sensor, &local_reg, steps,MOTOR_ACTION_FEED,0); + + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + try { + status = gl841_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl841_stop_action (dev); + } catch (...) {} + try { + // send original registers + sanei_genesys_bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl841_stop_action (dev); + /* send original registers */ + sanei_genesys_bulk_write_register(dev, dev->reg); + return status; + } + + loop = 0; + while (loop < 300) /* do not wait longer then 30 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (!(val & REG41_MOTORENB)) /* motor enabled */ + { + DBG(DBG_proc, "%s: finished\n", __func__); + dev->scanhead_position_in_steps += steps; + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + ++loop; + } + + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl841_stop_action (dev); + + DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); + return SANE_STATUS_IO_ERROR; +} + +/* Moves the slider to the home (top) position slowly */ +static SANE_Status +gl841_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + uint8_t val; + int loop = 0; + + DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); + + if (dev->model->is_sheetfed == SANE_TRUE) + { + DBG(DBG_proc, "%s: there is no \"home\"-concept for sheet fed\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; + } + + /* reset gpio pin */ + if (dev->model->gpo_type == GPO_CANONLIDE35) + { + RIE (sanei_genesys_read_register (dev, REG6C, &val)); + val = dev->gpo.value[0]; + RIE (sanei_genesys_write_register (dev, REG6C, val)); + } + if (dev->model->gpo_type == GPO_CANONLIDE80) + { + RIE (sanei_genesys_read_register (dev, REG6B, &val)); + val = REG6B_GPO18 | REG6B_GPO17; + RIE (sanei_genesys_write_register (dev, REG6B, val)); + } + gl841_save_power(dev, SANE_FALSE); + + /* first read gives HOME_SENSOR true */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + sanei_genesys_sleep_ms(100); + + /* second is reliable */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + dev->scanhead_position_in_steps = 0; + + if (val & REG41_HOMESNR) /* is sensor at home? */ + { + DBG(DBG_info, "%s: already at home, completed\n", __func__); + dev->scanhead_position_in_steps = 0; + return SANE_STATUS_GOOD; + } + + /* end previous scan if any */ + r = sanei_genesys_get_address(&dev->reg, REG01); + r->value &= ~REG01_SCAN; + status = sanei_genesys_write_register (dev, REG01, r->value); + + /* if motor is on, stop current action */ + if (val & REG41_MOTORENB) + { + status = gl841_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status)); + return SANE_STATUS_IO_ERROR; + } + } + + local_reg = dev->reg; + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + gl841_init_motor_regs(dev, sensor, &local_reg, 65536,MOTOR_ACTION_GO_HOME,0); + + /* set up for reverse and no scan */ + r = sanei_genesys_get_address(&local_reg, REG02); + r->value |= REG02_MTRREV; + r = sanei_genesys_get_address(&local_reg, REG01); + r->value &= ~REG01_SCAN; + + RIE (sanei_genesys_bulk_write_register(dev, local_reg)); + + try { + status = gl841_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl841_stop_action(dev); + } catch (...) {} + try { + sanei_genesys_bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl841_stop_action (dev); + /* send original registers */ + sanei_genesys_bulk_write_register(dev, dev->reg); + return status; + } + + if (wait_until_home) + { + while (loop < 300) /* do not wait longer then 30 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + if (val & REG41_HOMESNR) /* home sensor */ + { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + ++loop; + } + + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl841_stop_action (dev); + DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + DBG(DBG_info, "%s: scanhead is still moving\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; +} + +/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels + area at 600 dpi from very top of scanner */ +static SANE_Status +gl841_search_start_position (Genesys_Device * dev) +{ + int size; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg; + int steps; + + int pixels = 600; + int dpi = 300; + + DBGSTART; + + local_reg = dev->reg; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); + + SetupParams params; + params.xres = dpi; + params.yres = dpi; + params.startx = 0; + params.starty = 0; /*we should give a small offset here~60 steps*/ + params.pixels = 600; + params.lines = dev->model->search_lines; + params.depth = 8; + params.channels = 1; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::GREEN; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; + + status = gl841_init_scan_regs(dev, sensor, &local_reg, params); + + if(status!=SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to init scan registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* send to scanner */ + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + size = pixels * dev->model->search_lines; + + std::vector data(size); + + status = gl841_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl841_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + + status = gl841_end_scan(dev, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + +/*TODO: find out where sanei_genesys_search_reference_point + stores information, and use that correctly*/ + status = + sanei_genesys_search_reference_point (dev, sensor, data.data(), 0, dpi, pixels, + dev->model->search_lines); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + return SANE_STATUS_GOOD; +} + +/* + * sets up register for coarse gain calibration + * todo: check it for scanners using it */ +static SANE_Status +gl841_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t channels; + uint8_t cksel; + + DBGSTART; + + cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ + + /* set line size */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else { + channels = 1; + } + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = 0; + params.starty = 0; + params.pixels = sensor.optical_res / cksel; /* XXX STEF XXX !!! */ + params.lines = 20; + params.depth = 16; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl841_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / cksel, dev->settings.xres); + + status = sanei_genesys_bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + +/* if (DBG_LEVEL >= DBG_info) + sanei_gl841_print_registers (regs);*/ + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/* init registers for shading calibration */ +static SANE_Status +gl841_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Int ydpi; + float starty=0; + + DBGSTART; + DBG(DBG_proc, "%s: lines = %d\n", __func__, (int)(dev->calib_lines)); + + /* initial calibration reg values */ + regs = dev->reg; + + ydpi = dev->motor.base_ydpi; + if (dev->model->motor_type == MOTOR_PLUSTEK_3600) /* TODO PLUSTEK_3600: 1200dpi not yet working, produces dark bar */ + { + ydpi = 600; + } + if (dev->model->motor_type == MOTOR_CANONLIDE80) + { + ydpi = gl841_get_dpihw(dev); + /* get over extra dark area for this model. + It looks like different devices have dark areas of different width + due to manufacturing variability. The initial value of starty was 140, + but it moves the sensor almost past the dark area completely in places + on certain devices. + + On a particular device the black area starts at roughly position + 160 to 230 depending on location (the dark area is not completely + parallel to the frame). + */ + starty = 70; + } + + dev->calib_channels = 3; + dev->calib_lines = dev->model->shading_lines; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = ydpi; + params.startx = 0; + params.starty = starty; + params.pixels = (sensor.sensor_pixels * dev->settings.xres) / sensor.optical_res; + params.lines = dev->calib_lines; + params.depth = 16; + params.channels = dev->calib_channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_USE_OPTICAL_RES | + /*SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE |*/ + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl841_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + dev->calib_pixels = dev->current_setup.pixels; + dev->scanhead_position_in_steps += dev->calib_lines + starty; + + status = sanei_genesys_bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* set up registers for the actual scan + */ +static SANE_Status +gl841_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int flags; + int depth; + float move; + int move_dpi; + float start; + + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + +/* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + +/* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + + /* steps to move to reach scanning area: + - first we move to physical start of scanning + either by a fixed steps amount from the black strip + or by a fixed amount from parking position, + minus the steps done during shading calibration + - then we move by the needed offset whitin physical + scanning area + + assumption: steps are expressed at maximum motor resolution + + we need: + SANE_Fixed y_offset; + SANE_Fixed y_size; + SANE_Fixed y_offset_calib; + mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ + + /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is + relative from origin, else, it is from parking position */ + + move_dpi = dev->motor.base_ydpi; + + move = 0; + if (dev->model->flags & GENESYS_FLAG_SEARCH_START) + { + move += SANE_UNFIX (dev->model->y_offset_calib); + } + + DBG(DBG_info, "%s move=%f steps\n", __func__, move); + + move += SANE_UNFIX (dev->model->y_offset); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + move += dev->settings.tl_y; + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + move = (move * move_dpi) / MM_PER_INCH; + +/* start */ + start = SANE_UNFIX (dev->model->x_offset); + + start += dev->settings.tl_x; + + start = (start * sensor.optical_res) / MM_PER_INCH; + + flags=0; + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + flags = 0; + + /* true gray (led add for cis scanners) */ + if(dev->model->is_cis && dev->settings.true_gray + && dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS + && dev->model->ccd_type != CIS_CANONLIDE80) + { + // on Lide 80 the LEDADD bit results in only red LED array being lit + DBG(DBG_io, "%s: activating LEDADD\n", __func__); + flags |= SCAN_FLAG_ENABLE_LEDADD; + } + + /* enable emulated lineart from gray data */ + if(dev->settings.scan_mode == ScanColorMode::LINEART + && dev->settings.dynamic_lineart) + { + flags |= SCAN_FLAG_DYNAMIC_LINEART; + } + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; + params.starty = move; + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = flags; + + status = gl841_init_scan_regs(dev, sensor, &dev->reg, params); + + if (status != SANE_STATUS_GOOD) + return status; + + + DBG(DBG_proc, "%s: completed\n", __func__); + return SANE_STATUS_GOOD; +} + +/* + * this function sends generic gamma table (ie linear ones) + * or the Sensor specific one if provided + */ +static SANE_Status +gl841_send_gamma_table(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int size; + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + size = 256; + + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3); + + RIE(sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data())); + + /* send address */ + status = gl841_set_buffer_address_gamma (dev, 0x00000); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* send data */ + status = sanei_genesys_bulk_write_data(dev, 0x28, gamma.data(), size * 2 * 3); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send gamma table: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/* this function does the led calibration by scanning one line of the calibration + area below scanner's top on white strip. + +-needs working coarse/gain +*/ +static SANE_Status +gl841_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs) +{ + int num_pixels; + int total_size; + int i, j; + SANE_Status status = SANE_STATUS_GOOD; + int val; + int channels; + int avg[3], avga, avge; + int turn; + uint16_t exp[3], target; + int move; + + SANE_Bool acceptable = SANE_FALSE; + + /* these 2 boundaries should be per sensor */ + uint16_t min_exposure=500; + uint16_t max_exposure; + + DBGSTART; + + /* feed to white strip if needed */ + if (dev->model->y_offset_calib>0) + { + move = SANE_UNFIX (dev->model->y_offset_calib); + move = (move * (dev->motor.base_ydpi)) / MM_PER_INCH; + DBG(DBG_io, "%s: move=%d lines\n", __func__, move); + status = gl841_feed(dev, move); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to feed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + /* offset calibration is always done in color mode */ + channels = 3; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = 0; + params.starty = 0; + params.pixels = (sensor.sensor_pixels*dev->settings.xres) / sensor.optical_res; + params.lines = 1; + params.depth = 16; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_USE_OPTICAL_RES; + + status = gl841_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + RIE(sanei_genesys_bulk_write_register(dev, regs)); + + num_pixels = dev->current_setup.pixels; + + total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ + + std::vector line(total_size); + +/* + we try to get equal bright leds here: + + loop: + average per color + adjust exposure times + */ + + exp[0] = sensor.exposure.red; + exp[1] = sensor.exposure.green; + exp[2] = sensor.exposure.blue; + + turn = 0; + /* max exposure is set to ~2 time initial average + * exposure, or 2 time last calibration exposure */ + max_exposure=((exp[0]+exp[1]+exp[2])/3)*2; + target=sensor.gain_white_ref*256; + + do { + sensor.exposure.red = exp[0]; + sensor.exposure.green = exp[1]; + sensor.exposure.blue = exp[2]; + + sanei_genesys_set_exposure(regs, sensor.exposure); + RIE(sanei_genesys_write_register(dev, 0x10, (sensor.exposure.red >> 8) & 0xff)); + RIE(sanei_genesys_write_register(dev, 0x11, sensor.exposure.red & 0xff)); + RIE(sanei_genesys_write_register(dev, 0x12, (sensor.exposure.green >> 8) & 0xff)); + RIE(sanei_genesys_write_register(dev, 0x13, sensor.exposure.green & 0xff)); + RIE(sanei_genesys_write_register(dev, 0x14, (sensor.exposure.blue >> 8) & 0xff)); + RIE(sanei_genesys_write_register(dev, 0x15, sensor.exposure.blue & 0xff)); + + RIE(sanei_genesys_bulk_write_register(dev, regs)); + + DBG(DBG_info, "%s: starting line reading\n", __func__); + RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) { + char fn[30]; + snprintf(fn, 30, "gl841_led_%d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, num_pixels, 1); + } + + /* compute average */ + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info,"%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + acceptable = SANE_TRUE; + + /* exposure is acceptable if each color is in the %5 range + * of other color channels */ + if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || + avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || + avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) + { + acceptable = SANE_FALSE; + } + + /* led exposure is not acceptable if white level is too low + * ~80 hardcoded value for white level */ + if(avg[0]<20000 || avg[1]<20000 || avg[2]<20000) + { + acceptable = SANE_FALSE; + } + + /* for scanners using target value */ + if(target>0) + { + acceptable = SANE_TRUE; + for(i=0;i<3;i++) + { + /* we accept +- 2% delta from target */ + if(abs(avg[i]-target)>target/50) + { + exp[i]=(exp[i]*target)/avg[i]; + acceptable = SANE_FALSE; + } + } + } + else + { + if (!acceptable) + { + avga = (avg[0]+avg[1]+avg[2])/3; + exp[0] = (exp[0] * avga) / avg[0]; + exp[1] = (exp[1] * avga) / avg[1]; + exp[2] = (exp[2] * avga) / avg[2]; + /* + keep the resulting exposures below this value. + too long exposure drives the ccd into saturation. + we may fix this by relying on the fact that + we get a striped scan without shading, by means of + statistical calculation + */ + avge = (exp[0] + exp[1] + exp[2]) / 3; + + if (avge > max_exposure) { + exp[0] = (exp[0] * max_exposure) / avge; + exp[1] = (exp[1] * max_exposure) / avge; + exp[2] = (exp[2] * max_exposure) / avge; + } + if (avge < min_exposure) { + exp[0] = (exp[0] * min_exposure) / avge; + exp[1] = (exp[1] * min_exposure) / avge; + exp[2] = (exp[2] * min_exposure) / avge; + } + + } + } + + RIE (gl841_stop_action (dev)); + + turn++; + + } while (!acceptable && turn < 100); + + DBG(DBG_info,"%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); + + gl841_slow_back_home(dev, SANE_TRUE); + + DBGCOMPLETED; + return status; +} + +/** @brief calibration for AD frontend devices + * offset calibration assumes that the scanning head is on a black area + * For LiDE80 analog frontend + * 0x0003 : is gain and belongs to [0..63] + * 0x0006 : is offset + * We scan a line with no gain until average offset reaches the target + */ +static SANE_Status +ad_fe_offset_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + int num_pixels; + int total_size; + int i; + int average; + int turn; + int top; + int bottom; + int target; + + DBGSTART; + + /* don't impact 3600 behavior since we can't test it */ + if (dev->model->ccd_type == CCD_PLUSTEK_3600) + { + DBGCOMPLETED; + return status; + } + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = 0; + params.starty = 0; + params.pixels = (sensor.sensor_pixels*dev->settings.xres) / sensor.optical_res; + params.lines = 1; + params.depth = 8; + params.channels = 3; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_USE_OPTICAL_RES; + + status = gl841_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + num_pixels = dev->current_setup.pixels; + total_size = num_pixels * 3 * 2 * 1; + + std::vector line(total_size); + + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* loop on scan until target offset is reached */ + turn=0; + target=24; + bottom=0; + top=255; + do { + /* set up offset mid range */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + /* scan line */ + DBG(DBG_info, "%s: starting line reading\n", __func__); + sanei_genesys_bulk_write_register(dev, regs); + gl841_set_fe(dev, sensor, AFE_SET); + gl841_begin_scan(dev, sensor, ®s, SANE_TRUE); + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + gl841_stop_action (dev); + if (DBG_LEVEL >= DBG_data) { + char fn[30]; + snprintf(fn, 30, "gl841_offset_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), 8, 3, num_pixels, 1); + } + + /* search for minimal value */ + average=0; + for(i=0;itarget) + { + top=(top+bottom)/2; + } + else + { + bottom=(top+bottom)/2; + } + turn++; + } while ((top-bottom)>1 && turn < 100); + + // FIXME: don't overwrite the calibrated values + dev->frontend.set_offset(0, 0); + dev->frontend.set_offset(1, 0); + dev->frontend.set_offset(2, 0); + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + DBGCOMPLETED; + return status; +} + +/* this function does the offset calibration by scanning one line of the calibration + area below scanner's top. There is a black margin and the remaining is white. + sanei_genesys_search_start() must have been called so that the offsets and margins + are allready known. + +this function expects the slider to be where? +*/ +static SANE_Status +gl841_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + int num_pixels; + int total_size; + int i, j; + SANE_Status status = SANE_STATUS_GOOD; + int val; + int channels; + int off[3],offh[3],offl[3],off1[3],off2[3]; + int min1[3],min2[3]; + int cmin[3],cmax[3]; + int turn; + SANE_Bool acceptable = SANE_FALSE; + int mintgt = 0x400; + + DBG(DBG_proc, "%s\n", __func__); + + /* Analog Device fronted have a different calibration */ + if ((dev->reg.find_reg(0x04).value & REG04_FESET) == 0x02) + { + return ad_fe_offset_calibration(dev, sensor, regs); + } + + /* offset calibration is always done in color mode */ + channels = 3; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = 0; + params.starty = 0; + params.pixels = (sensor.sensor_pixels*dev->settings.xres) / sensor.optical_res; + params.lines = 1; + params.depth = 16; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_USE_OPTICAL_RES | + SCAN_FLAG_DISABLE_LAMP; + + status = gl841_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + num_pixels = dev->current_setup.pixels; + + total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* scan first line of data with no offset nor gain */ +/*WM8199: gain=0.73; offset=-260mV*/ +/*okay. the sensor black level is now at -260mV. we only get 0 from AFE...*/ +/* we should probably do real calibration here: + * -detect acceptable offset with binary search + * -calculate offset from this last version + * + * acceptable offset means + * - few completely black pixels(<10%?) + * - few completely white pixels(<10%?) + * + * final offset should map the minimum not completely black + * pixel to 0(16 bits) + * + * this does account for dummy pixels at the end of ccd + * this assumes slider is at black strip(which is not quite as black as "no + * signal"). + * + */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + offh[0] = 0xff; + offh[1] = 0xff; + offh[2] = 0xff; + offl[0] = 0x00; + offl[1] = 0x00; + offl[2] = 0x00; + turn = 0; + + do { + + RIE(sanei_genesys_bulk_write_register(dev, regs)); + + for (j=0; j < channels; j++) { + off[j] = (offh[j]+offl[j])/2; + dev->frontend.set_offset(j, off[j]); + } + + status = gl841_set_fe(dev, sensor, AFE_SET); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup frontend: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_info, "%s: starting first line reading\n", __func__); + RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); + + RIE(sanei_genesys_read_data_from_scanner (dev, first_line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) { + char fn[30]; + snprintf(fn, 30, "gl841_offset1_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, first_line.data(), 16, channels, num_pixels, 1); + } + + acceptable = SANE_TRUE; + + for (j = 0; j < channels; j++) + { + cmin[j] = 0; + cmax[j] = 0; + + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + + first_line[i * 2 + j * 2 * num_pixels]; + else + val = + first_line[i * 2 * channels + 2 * j + 1] * 256 + + first_line[i * 2 * channels + 2 * j]; + if (val < 10) + cmin[j]++; + if (val > 65525) + cmax[j]++; + } + + /* TODO the DP685 has a black strip in the middle of the sensor + * should be handled in a more elegant way , could be a bug */ + if (dev->model->ccd_type == CCD_DP685) + cmin[j] -= 20; + + if (cmin[j] > num_pixels/100) { + acceptable = SANE_FALSE; + if (dev->model->is_cis) + offl[0] = off[0]; + else + offl[j] = off[j]; + } + if (cmax[j] > num_pixels/100) { + acceptable = SANE_FALSE; + if (dev->model->is_cis) + offh[0] = off[0]; + else + offh[j] = off[j]; + } + } + + DBG(DBG_info,"%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0], + cmin[1], cmax[1], cmin[2], cmax[2]); + + if (dev->model->is_cis) { + offh[2] = offh[1] = offh[0]; + offl[2] = offl[1] = offl[0]; + } + + RIE(gl841_stop_action(dev)); + + turn++; + } while (!acceptable && turn < 100); + + DBG(DBG_info,"%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); + + + for (j = 0; j < channels; j++) + { + off1[j] = off[j]; + + min1[j] = 65536; + + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + + first_line[i * 2 + j * 2 * num_pixels]; + else + val = + first_line[i * 2 * channels + 2 * j + 1] * 256 + + first_line[i * 2 * channels + 2 * j]; + if (min1[j] > val && val >= 10) + min1[j] = val; + } + } + + + offl[0] = off[0]; + offl[1] = off[0]; + offl[2] = off[0]; + turn = 0; + + do { + + for (j=0; j < channels; j++) { + off[j] = (offh[j]+offl[j])/2; + dev->frontend.set_offset(j, off[j]); + } + + status = gl841_set_fe(dev, sensor, AFE_SET); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup frontend: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(sanei_genesys_bulk_write_register(dev, regs)); + RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) { + char fn[30]; + snprintf(fn, 30, "gl841_offset2_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, second_line.data(), 16, channels, num_pixels, 1); + } + + acceptable = SANE_TRUE; + + for (j = 0; j < channels; j++) + { + cmin[j] = 0; + cmax[j] = 0; + + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + + second_line[i * 2 + j * 2 * num_pixels]; + else + val = + second_line[i * 2 * channels + 2 * j + 1] * 256 + + second_line[i * 2 * channels + 2 * j]; + if (val < 10) + cmin[j]++; + if (val > 65525) + cmax[j]++; + } + + if (cmin[j] > num_pixels/100) { + acceptable = SANE_FALSE; + if (dev->model->is_cis) + offl[0] = off[0]; + else + offl[j] = off[j]; + } + if (cmax[j] > num_pixels/100) { + acceptable = SANE_FALSE; + if (dev->model->is_cis) + offh[0] = off[0]; + else + offh[j] = off[j]; + } + } + + DBG(DBG_info, "%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0], + cmin[1], cmax[1], cmin[2], cmax[2]); + + if (dev->model->is_cis) { + offh[2] = offh[1] = offh[0]; + offl[2] = offl[1] = offl[0]; + } + + RIE(gl841_stop_action (dev)); + + turn++; + + } while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); + + + for (j = 0; j < channels; j++) + { + off2[j] = off[j]; + + min2[j] = 65536; + + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + + second_line[i * 2 + j * 2 * num_pixels]; + else + val = + second_line[i * 2 * channels + 2 * j + 1] * 256 + + second_line[i * 2 * channels + 2 * j]; + if (min2[j] > val && val != 0) + min2[j] = val; + } + } + + DBG(DBG_info, "%s: first set: %d/%d,%d/%d,%d/%d\n", __func__, off1[0], min1[0], off1[1], min1[1], + off1[2], min1[2]); + + DBG(DBG_info, "%s: second set: %d/%d,%d/%d,%d/%d\n", __func__, off2[0], min2[0], off2[1], min2[1], + off2[2], min2[2]); + +/* + calculate offset for each channel + based on minimal pixel value min1 at offset off1 and minimal pixel value min2 + at offset off2 + + to get min at off, values are linearly interpolated: + min=real+off*fact + min1=real+off1*fact + min2=real+off2*fact + + fact=(min1-min2)/(off1-off2) + real=min1-off1*(min1-min2)/(off1-off2) + + off=(min-min1+off1*(min1-min2)/(off1-off2))/((min1-min2)/(off1-off2)) + + off=(min*(off1-off2)+min1*off2-off1*min2)/(min1-min2) + + */ + for (j = 0; j < channels; j++) + { + if (min2[j]-min1[j] == 0) { +/*TODO: try to avoid this*/ + DBG(DBG_warn, "%s: difference too small\n", __func__); + if (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j] >= 0) + off[j] = 0x0000; + else + off[j] = 0xffff; + } else + off[j] = (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j])/(min1[j]-min2[j]); + if (off[j] > 255) + off[j] = 255; + if (off[j] < 0) + off[j] = 0; + dev->frontend.set_offset(j, off[j]); + } + + DBG(DBG_info, "%s: final offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); + + if (dev->model->is_cis) { + if (off[0] < off[1]) + off[0] = off[1]; + if (off[0] < off[2]) + off[0] = off[2]; + dev->frontend.set_offset(0, off[0]); + dev->frontend.set_offset(1, off[0]); + dev->frontend.set_offset(2, off[0]); + } + + if (channels == 1) + { + dev->frontend.set_offset(1, dev->frontend.get_offset(0)); + dev->frontend.set_offset(2, dev->frontend.get_offset(0)); + } + + DBG(DBG_proc, "%s: completed\n", __func__); + return status; +} + + +/* alternative coarse gain calibration + this on uses the settings from offset_calibration and + uses only one scanline + */ +/* + with offset and coarse calibration we only want to get our input range into + a reasonable shape. the fine calibration of the upper and lower bounds will + be done with shading. + */ +static SANE_Status +gl841_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) +{ + int num_pixels; + int total_size; + int i, j, channels; + SANE_Status status = SANE_STATUS_GOOD; + int max[3]; + float gain[3]; + int val; + int lines=1; + int move; + + DBG(DBG_proc, "%s: dpi=%d\n", __func__, dpi); + + /* feed to white strip if needed */ + if (dev->model->y_offset_calib>0) + { + move = SANE_UNFIX (dev->model->y_offset_calib); + move = (move * (dev->motor.base_ydpi)) / MM_PER_INCH; + DBG(DBG_io, "%s: move=%d lines\n", __func__, move); + status = gl841_feed(dev, move); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to feed: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + /* coarse gain calibration is allways done in color mode */ + channels = 3; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = 0; + params.starty = 0; + params.pixels = (sensor.sensor_pixels*dev->settings.xres) / sensor.optical_res; + params.lines = lines; + params.depth = 16; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_USE_OPTICAL_RES; + + status = gl841_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + RIE(sanei_genesys_bulk_write_register(dev, regs)); + + num_pixels = dev->current_setup.pixels; + + total_size = num_pixels * channels * 2 * lines; /* colors * bytes_per_color * scan lines */ + + std::vector line(total_size); + + RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl841_gain.pnm", line.data(), 16, channels, num_pixels, lines); + + /* average high level for each channel and compute gain + to reach the target code + we only use the central half of the CCD data */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + + if (val > max[j]) + max[j] = val; + } + + gain[j] = 65535.0/max[j]; + + uint8_t out_gain = 0; + + if (dev->model->dac_type == DAC_CANONLIDE35 || + dev->model->dac_type == DAC_WOLFSON_XP300 || + dev->model->dac_type == DAC_WOLFSON_DSM600) + { + gain[j] *= 0.69;/*seems we don't get the real maximum. empirically derived*/ + if (283 - 208/gain[j] > 255) + out_gain = 255; + else if (283 - 208/gain[j] < 0) + out_gain = 0; + else + out_gain = 283 - 208/gain[j]; + } + else if (dev->model->dac_type == DAC_CANONLIDE80) + { + out_gain = gain[j]*12; + } + dev->frontend.set_gain(j, out_gain); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], + out_gain); + } + + for (j = 0; j < channels; j++) + { + if(gain[j] > 10) + { + DBG (DBG_error0, "**********************************************\n"); + DBG (DBG_error0, "**********************************************\n"); + DBG (DBG_error0, "**** ****\n"); + DBG (DBG_error0, "**** Extremely low Brightness detected. ****\n"); + DBG (DBG_error0, "**** Check the scanning head is ****\n"); + DBG (DBG_error0, "**** unlocked and moving. ****\n"); + DBG (DBG_error0, "**** ****\n"); + DBG (DBG_error0, "**********************************************\n"); + DBG (DBG_error0, "**********************************************\n"); + return SANE_STATUS_JAMMED; + } + + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + if (channels == 1) { + dev->frontend.set_gain(0, dev->frontend.get_gain(1)); + dev->frontend.set_gain(2, dev->frontend.get_gain(1)); + } + + DBG(DBG_info, "%s: gain=(%d,%d,%d)\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2)); + + RIE (gl841_stop_action (dev)); + + gl841_slow_back_home(dev, SANE_TRUE); + + DBGCOMPLETED; + return status; +} + +/* + * wait for lamp warmup by scanning the same line until difference + * between 2 scans is below a threshold + */ +static SANE_Status +gl841_init_regs_for_warmup (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * local_reg, + int *channels, int *total_size) +{ + int num_pixels = (int) (4 * 300); + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s\n", __func__); + + *local_reg = dev->reg; + +/* okay.. these should be defaults stored somewhere */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + dev->frontend.set_offset(0, 0x80); + dev->frontend.set_offset(1, 0x80); + dev->frontend.set_offset(2, 0x80); + + SetupParams params; + params.xres = sensor.optical_res; + params.yres = dev->settings.yres; + params.startx = sensor.dummy_pixel; + params.starty = 0; + params.pixels = num_pixels; + params.lines = 1; + params.depth = 16; + params.channels = *channels; + params.scan_method = dev->settings.scan_method; + if (*channels == 3) { + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + } else { + params.scan_mode = ScanColorMode::GRAY; + } + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_USE_OPTICAL_RES; + + status = gl841_init_scan_regs(dev, sensor, local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + num_pixels = dev->current_setup.pixels; + + *total_size = num_pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */ + + RIE(sanei_genesys_bulk_write_register(dev, *local_reg)); + + return status; +} + + +/* + * this function moves head without scanning, forward, then backward + * so that the head goes to park position. + * as a by-product, also check for lock + */ +static SANE_Status +sanei_gl841_repark_head (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s\n", __func__); + + status = gl841_feed(dev,232); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to feed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* toggle motor flag, put an huge step number and redo move backward */ + status = gl841_slow_back_home (dev, SANE_TRUE); + DBG(DBG_proc, "%s: completed\n", __func__); + return status; +} + +static bool +gl841_is_compatible_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Calibration_Cache *cache, + int for_overwrite) +{ +#ifdef HAVE_SYS_TIME_H + struct timeval time; +#endif + + DBGSTART; + + /* calibration cache not working yet for this model */ + if (dev->model->ccd_type == CCD_PLUSTEK_3600) + { + return false; + } + + gl841_calculate_current_setup (dev, sensor); + + DBG(DBG_proc, "%s: checking\n", __func__); + + if (dev->current_setup.ccd_size_divisor != cache->used_setup.ccd_size_divisor) + return false; + + /* a cache entry expires after 30 minutes for non sheetfed scanners */ + /* this is not taken into account when overwriting cache entries */ +#ifdef HAVE_SYS_TIME_H + if(for_overwrite == SANE_FALSE) + { + gettimeofday (&time, NULL); + if ((time.tv_sec - cache->last_calibration > 30 * 60) + && (dev->model->is_sheetfed == SANE_FALSE)) + { + DBG(DBG_proc, "%s: expired entry, non compatible cache\n", __func__); + return false; + } + } +#endif + + DBGCOMPLETED; + return true; +} + +/* + * initialize ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +static SANE_Status +gl841_init (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + size_t size; + + DBG_INIT (); + DBGSTART; + + dev->scanhead_position_in_steps = 0; + + /* Check if the device has already been initialized and powered up */ + if (dev->already_initialized) + { + RIE (sanei_genesys_get_status (dev, &val)); + if (val & REG41_PWRBIT) + { + DBG(DBG_info, "%s: already initialized\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + } + + dev->dark_average_data.clear(); + dev->white_average_data.clear(); + + dev->settings.color_filter = ColorFilter::RED; + + /* ASIC reset */ + RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); + RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); + + /* Set default values for registers */ + gl841_init_registers (dev); + + /* Write initial registers */ + RIE(sanei_genesys_bulk_write_register(dev, dev->reg)); + + /* Test ASIC and RAM */ + if (!(dev->model->flags & GENESYS_FLAG_LAZY_INIT)) + { + RIE (sanei_gl841_asic_test (dev)); + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + /* Set analog frontend */ + RIE (gl841_set_fe(dev, sensor, AFE_INIT)); + + /* Move home */ + RIE (gl841_slow_back_home (dev, SANE_TRUE)); + + /* Init shading data */ + RIE (sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels)); + + /* ensure head is correctly parked, and check lock */ + if (dev->model->flags & GENESYS_FLAG_REPARK) + { + status = sanei_gl841_repark_head (dev); + if (status != SANE_STATUS_GOOD) + { + if (status == SANE_STATUS_INVAL) + DBG(DBG_error0, "Your scanner is locked. Please move the lock switch to the unlocked " + "position\n"); + else + DBG(DBG_error, "%s: sanei_gl841_repark_head failed: %s\n", __func__, + sane_strstatus(status)); + return status; + } + } + + /* send gamma tables */ + status = gl841_send_gamma_table(dev, sensor); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send initial gamma tables: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* initial calibration reg values */ + Genesys_Register_Set& regs = dev->calib_reg; + regs = dev->reg; + + SetupParams params; + params.xres = 300; + params.yres = 300; + params.startx = 0; + params.starty = 0; + params.pixels = (16 * 300) / sensor.optical_res; + params.lines = 1; + params.depth = 16; + params.channels = 3; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = ColorFilter::RED; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_USE_OPTICAL_RES; + + status = gl841_init_scan_regs(dev, sensor, ®s, params); + + RIE(sanei_genesys_bulk_write_register(dev, regs)); + + size = dev->current_setup.pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */ + + std::vector line(size); + + DBG(DBG_info, "%s: starting dummy data reading\n", __func__); + RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); + + sanei_usb_set_timeout(1000);/* 1 second*/ + +/*ignore errors. next read will succeed*/ + sanei_genesys_read_data_from_scanner(dev, line.data(), size); + + sanei_usb_set_timeout(30 * 1000);/* 30 seconds*/ + + RIE (gl841_end_scan(dev, ®s, SANE_TRUE)); + + regs = dev->reg; + + /* Set powersaving (default = 15 minutes) */ + RIE (gl841_set_powersaving (dev, 15)); + dev->already_initialized = SANE_TRUE; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl841_update_hardware_sensors (Genesys_Scanner * s) +{ + /* do what is needed to get a new set of events, but try to not lose + any of them. + */ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + if (s->dev->model->gpo_type == GPO_CANONLIDE35 + || s->dev->model->gpo_type == GPO_CANONLIDE80) + { + RIE(sanei_genesys_read_register(s->dev, REG6D, &val)); + s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_FILE_SW].write((val & 0x02) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); + s->buttons[BUTTON_COPY_SW].write((val & 0x08) == 0); + } + + if (s->dev->model->gpo_type == GPO_XP300 || + s->dev->model->gpo_type == GPO_DP665 || + s->dev->model->gpo_type == GPO_DP685) + { + RIE(sanei_genesys_read_register(s->dev, REG6D, &val)); + + s->buttons[BUTTON_PAGE_LOADED_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_SCAN_SW].write((val & 0x02) == 0); + } + + return status; +} + +/** @brief search for a full width black or white strip. + * This function searches for a black or white stripe across the scanning area. + * When searching backward, the searched area must completely be of the desired + * color since this area will be used for calibration which scans forward. + * @param dev scanner device + * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward + * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip + * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not + */ +static SANE_Status +gl841_search_strip(Genesys_Device * dev, const Genesys_Sensor& sensor, + SANE_Bool forward, SANE_Bool black) +{ + unsigned int pixels, lines, channels; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg; + size_t size; + int steps, depth, dpi; + unsigned int pass, count, found, x, y, length; + char title[80]; + GenesysRegister *r; + uint8_t white_level=90; /**< default white level to detect white dots */ + uint8_t black_level=60; /**< default black level to detect black dots */ + + DBG(DBG_proc, "%s %s %s\n", __func__, black ? "black" : "white", forward ? "forward" : "reverse"); + + /* use maximum gain when doing forward white strip detection + * since we don't have calibrated the sensor yet */ + if(!black && forward) + { + dev->frontend.set_gain(0, 0xff); + dev->frontend.set_gain(1, 0xff); + dev->frontend.set_gain(2, 0xff); + } + + gl841_set_fe(dev, sensor, AFE_SET); + status = gl841_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* set up for a gray scan at lowest dpi */ + dpi = 9600; + for (x = 0; x < MAX_RESOLUTIONS; x++) + { + if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) + dpi = dev->model->xdpi_values[x]; + } + channels = 1; + + /* shading calibation is done with dev->motor.base_ydpi */ + /* lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; */ + lines = (10*dpi)/MM_PER_INCH; + + depth = 8; + pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; + size = pixels * channels * lines * (depth / 8); + std::vector data(size); + + /* 20 cm max length for calibration sheet */ + length = ((200 * dpi) / MM_PER_INCH)/lines; + + dev->scanhead_position_in_steps = 0; + + local_reg = dev->reg; + + SetupParams params; + params.xres = dpi; + params.yres = dpi; + params.startx = 0; + params.starty = 0; + params.pixels = pixels; + params.lines = lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::RED; + params.flags = SCAN_FLAG_DISABLE_SHADING | SCAN_FLAG_DISABLE_GAMMA; + + status = gl841_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* set up for reverse or forward */ + r = sanei_genesys_get_address(&local_reg, 0x02); + if (forward) + r->value &= ~4; + else + r->value |= 4; + + + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl841_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl841_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl841_stop_action failed\n", __func__); + return status; + } + + pass = 0; + if (DBG_LEVEL >= DBG_data) + { + sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", black ? "black" : "white", + forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); + } + + /* loop until strip is found or maximum pass number done */ + found = 0; + while (pass < length && !found) + { + status = sanei_genesys_bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* now start scan */ + status = gl841_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error,"%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner (dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "g%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl841_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl841_stop_action failed\n", __func__); + return status; + } + + if (DBG_LEVEL >= DBG_data) + { + sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > white_level) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < black_level) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > white_level) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < black_level) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (pixels * lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + pass++; + } + + if (found) + { + status = SANE_STATUS_GOOD; + DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); + } + else + { + status = SANE_STATUS_UNSUPPORTED; + DBG(DBG_info, "%s: %s strip not found\n", __func__, black ? "black" : "white"); + } + + DBG(DBG_proc, "%s: completed\n", __func__); + return status; +} + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +static +SANE_Status +gl841_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, int size) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint32_t length, x, factor, pixels, i; + uint32_t lines, channels; + uint16_t dpiset, dpihw, strpixel ,endpixel, beginpixel; + uint8_t *ptr,*src; + + DBGSTART; + DBG(DBG_io2, "%s: writing %d bytes of shading data\n", __func__, size); + + /* old method if no SHDAREA */ + if((dev->reg.find_reg(0x01).value & REG01_SHDAREA) == 0) + { + /* start address */ + status = sanei_genesys_set_buffer_address (dev, 0x0000); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* shading data whole line */ + status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send shading table: %s\n", __func__, + sane_strstatus(status)); + return status; + } + DBGCOMPLETED; + return status; + } + + /* data is whole line, we extract only the part for the scanned area */ + length = (uint32_t) (size / 3); + sanei_genesys_get_double(&dev->reg,REG_STRPIXEL,&strpixel); + sanei_genesys_get_double(&dev->reg,REG_ENDPIXEL,&endpixel); + DBG(DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d\n", __func__, strpixel, endpixel, + endpixel-strpixel); + + /* compute deletion/average factor */ + sanei_genesys_get_double(&dev->reg,REG_DPISET,&dpiset); + dpihw = gl841_get_dpihw(dev); + unsigned ccd_size_divisor = dev->current_setup.ccd_size_divisor; + factor=dpihw/dpiset; + DBG(DBG_io2, "%s: dpihw=%d, dpiset=%d, ccd_size_divisor=%d, factor=%d\n", __func__, dpihw, dpiset, + ccd_size_divisor, factor); + + /* binary data logging */ + if(DBG_LEVEL>=DBG_data) + { + dev->binary=fopen("binary.pnm","wb"); + sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &lines); + channels=dev->current_setup.channels; + if(dev->binary!=NULL) + { + fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); + } + } + + /* turn pixel value into bytes 2x16 bits words */ + strpixel*=2*2; /* 2 words of 2 bytes */ + endpixel*=2*2; + pixels=endpixel-strpixel; + + /* shading pixel begin is start pixel minus start pixel during shading + * calibration. Currently only cases handled are full and half ccd resolution. + */ + beginpixel = sensor.CCD_start_xoffset / ccd_size_divisor; + beginpixel += sensor.dummy_pixel + 1; + DBG(DBG_io2, "%s: ORIGIN PIXEL=%d\n", __func__, beginpixel); + beginpixel = (strpixel-beginpixel*2*2)/factor; + DBG(DBG_io2, "%s: BEGIN PIXEL=%d\n", __func__, beginpixel/4); + + DBG(DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n", __func__, length, + length/4); + std::vector buffer(pixels, 0); + + /* write actual shading data contigously + * channel by channel, starting at addr 0x0000 + * */ + for(i=0;i<3;i++) + { + /* copy data to work buffer and process it */ + /* coefficent destination */ + ptr=buffer.data(); + + /* iterate on both sensor segment, data has been averaged, + * so is in the right order and we only have to copy it */ + for(x=0;xmodel->cmd_set->bulk_write_data(dev, 0x3c, buffer.data(), pixels)); + } + + DBGCOMPLETED; + + return status; +} + + +/** the gl841 command set */ +static Genesys_Command_Set gl841_cmd_set = { + "gl841-generic", /* the name of this set */ + + [](Genesys_Device* dev) -> bool { (void) dev; return true; }, + + gl841_init, + gl841_init_regs_for_warmup, + gl841_init_regs_for_coarse_calibration, + gl841_init_regs_for_shading, + gl841_init_regs_for_scan, + + gl841_get_filter_bit, + gl841_get_lineart_bit, + gl841_get_bitset_bit, + gl841_get_gain4_bit, + gl841_get_fast_feed_bit, + gl841_test_buffer_empty_bit, + gl841_test_motor_flag_bit, + + gl841_set_fe, + gl841_set_powersaving, + gl841_save_power, + + gl841_begin_scan, + gl841_end_scan, + + gl841_send_gamma_table, + + gl841_search_start_position, + + gl841_offset_calibration, + gl841_coarse_gain_calibration, + gl841_led_calibration, + + NULL, + gl841_slow_back_home, + NULL, + + sanei_genesys_bulk_write_register, + sanei_genesys_bulk_write_data, + sanei_genesys_bulk_read_data, + + gl841_update_hardware_sensors, + + gl841_load_document, + gl841_detect_document_end, + gl841_eject_document, + gl841_search_strip, + + gl841_is_compatible_calibration, + NULL, + gl841_send_shading_data, + gl841_calculate_current_setup, + NULL +}; + +SANE_Status +sanei_gl841_init_cmd_set (Genesys_Device * dev) +{ + dev->model->cmd_set = &gl841_cmd_set; + return SANE_STATUS_GOOD; +} diff --git a/backend/genesys_gl841.h b/backend/genesys_gl841.h index d1bd07e..3dbfc80 100644 --- a/backend/genesys_gl841.h +++ b/backend/genesys_gl841.h @@ -250,205 +250,14 @@ #define REG87_LEDADD 0x04 -enum -{ - reg_0x01 = 0, - reg_0x02, - reg_0x03, - reg_0x04, - reg_0x05, - reg_0x06, - reg_0x07, - reg_0x08, - reg_0x09, - reg_0x0a, - - reg_0x10, - reg_0x11, - reg_0x12, - reg_0x13, - reg_0x14, - reg_0x15, - reg_0x16, - reg_0x17, - reg_0x18, - reg_0x19, - reg_0x1a, - reg_0x1b, - reg_0x1c, - reg_0x1d, - reg_0x1e, - reg_0x1f, - reg_0x20, - reg_0x21, - reg_0x22, - reg_0x23, - reg_0x24, - reg_0x25, - reg_0x26, - reg_0x27, - - reg_0x29, - - reg_0x2c, - reg_0x2d, - reg_0x2e, - reg_0x2f, - reg_0x30, - reg_0x31, - reg_0x32, - reg_0x33, - reg_0x34, - reg_0x35, - reg_0x36, - reg_0x37, - reg_0x38, - reg_0x39, - - reg_0x3d, - reg_0x3e, - reg_0x3f, - - reg_0x52, - reg_0x53, - reg_0x54, - reg_0x55, - reg_0x56, - reg_0x57, - reg_0x58, - reg_0x59, - reg_0x5a, - - reg_0x5d, - reg_0x5e, - reg_0x5f, - reg_0x60, - reg_0x61, - reg_0x62, - reg_0x63, - reg_0x64, - reg_0x65, - reg_0x66, - reg_0x67, - reg_0x68, - reg_0x69, - reg_0x6a, - reg_0x6b, - reg_0x6c, - reg_0x6d, - reg_0x6e, - reg_0x6f, - reg_0x70, - reg_0x71, - reg_0x72, - reg_0x73, - reg_0x74, - reg_0x75, - reg_0x76, - reg_0x77, - reg_0x78, - reg_0x79, - reg_0x7a, - reg_0x7b, - reg_0x7c, - reg_0x7d, - reg_0x7e, - reg_0x7f, - reg_0x80, - reg_0x81, - reg_0x82, - reg_0x83, - reg_0x84, - reg_0x85, - reg_0x86, - reg_0x87, - reg_0x88, - reg_0x89, - GENESYS_GL841_MAX_REGS -}; - -#define INITREG(adr,val) {dev->reg[index].address=adr;dev->reg[index].value=val;index++;} +#define INITREG(adr,val) {dev->reg.init_reg(adr, val); } /** * prototypes declaration in case of unit testing */ -#ifdef UNIT_TESTING -SANE_Status -gl841_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, - float yres, - float startx, - float starty, - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int color_filter, - unsigned int flags); - -SANE_Status -gl841_begin_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - SANE_Bool start_motor); - -SANE_Status -gl841_end_scan (Genesys_Device * dev, - Genesys_Register_Set __sane_unused__ * reg, - SANE_Bool check_stop); - -SANE_Status -gl841_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); - -SANE_Status -sanei_gl841_repark_head (Genesys_Device * dev); - -SANE_Status -gl841_feed (Genesys_Device * dev, int steps); - -SANE_Status -gl841_init_motor_regs_scan(Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - int scan_power_mode, - unsigned int flags) ; - -SANE_Status -gl841_stop_action (Genesys_Device * dev); - -SANE_Status -gl841_start_action (Genesys_Device * dev); - -SANE_Status -gl841_init_motor_regs(Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int feed_steps, - unsigned int action, - unsigned int flags); - -SANE_Status gl841_send_slope_table (Genesys_Device * dev, int table_nr, uint16_t * slope_table, int steps); - -SANE_Status gl841_bulk_write_data_gamma (Genesys_Device * dev, uint8_t addr, uint8_t * data, size_t len); - -SANE_Status gl841_offset_calibration (Genesys_Device * dev); - -SANE_Status gl841_coarse_gain_calibration (Genesys_Device * dev, int dpi); - -SANE_Status gl841_led_calibration (Genesys_Device * dev); - -SANE_Status gl841_send_shading_data (Genesys_Device * dev, uint8_t * data, int size); - -int gl841_scan_step_type(Genesys_Device *dev, int yres); -SANE_Status gl841_write_freq(Genesys_Device *dev, unsigned int ydpi); -#endif - -GENESYS_STATIC -int gl841_exposure_time(Genesys_Device *dev, + +static +int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, float slope_dpi, int scan_step_type, int start, diff --git a/backend/genesys_gl843.c b/backend/genesys_gl843.c deleted file mode 100644 index b47fb7e..0000000 --- a/backend/genesys_gl843.c +++ /dev/null @@ -1,4477 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2013 Stéphane Voltz - - - 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. -*/ - -#undef BACKEND_NAME -#define BACKEND_NAME genesys_gl843 - -#include "genesys_gl843.h" - -/**************************************************************************** - Low level function - ****************************************************************************/ - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - - -/** - * Write bulk data (e.g. gamma or shading data) */ -static SANE_Status -gl843_bulk_write_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size; - uint8_t outdata[8]; - - DBGSTART; - DBG (DBG_io, "gl843_bulk_write_data writing %lu bytes\n", (u_long) len); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_bulk_write_data failed while setting register: %s\n", - sane_strstatus (status)); - return status; - } - - while (len) - { - if(len>65472) - size=65472; - else - size = len; - - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), - outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_bulk_write_data failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_usb_write_bulk (dev->dn, data, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_bulk_write_data failed while writing bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "gl843_bulk_write_data: wrote %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (len - size)); - - len -= size; - data += size; - } - - DBGCOMPLETED; - return status; -} - -/* Set address for writing data */ -static SANE_Status -gl843_set_buffer_address (Genesys_Device * dev, uint32_t addr) -{ - SANE_Status status; - - DBG (DBG_io, "gl843_set_buffer_address: setting address to 0x%05x\n", - addr & 0xffff); - - status = sanei_genesys_write_register (dev, 0x5b, ((addr >> 8) & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_set_buffer_address: failed while writing high byte: %s\n", - sane_strstatus (status)); - return status; - } - - status = sanei_genesys_write_register (dev, 0x5c, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_set_buffer_address: failed while writing low byte: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io, "gl843_set_buffer_address: completed\n"); - - return status; -} - -/** - * writes a block of data to RAM - * @param dev USB device - * @param addr RAM address to write to - * @param size size of the chunk of data - * @param data pointer to the data to write - */ -static SANE_Status -write_data (Genesys_Device * dev, uint32_t addr, uint32_t size, - uint8_t * data) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - status = gl843_set_buffer_address (dev, addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "write_data: failed while setting address for bulk write data: %s\n", - sane_strstatus (status)); - return status; - } - - /* write actual data */ - status = gl843_bulk_write_data (dev, 0x28, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "write_data: failed while writing bulk write data: %s\n", - sane_strstatus (status)); - return status; - } - - /* set back address to 0 */ - status = gl843_set_buffer_address (dev, 0); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "write_data: failed setting to default RAM address: %s\n", - sane_strstatus (status)); - return status; - } - DBGCOMPLETED; - return status; -} - - -static SANE_Status -gl843_bulk_read_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size; - uint8_t outdata[8]; - - DBGSTART; - DBG (DBG_io, - "gl843_bulk_read_data: requesting %lu bytes from 0x%02x addr\n", - (u_long) len, addr); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, 0, 1, &addr); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "write_data: failed to set register address %s\n", - sane_strstatus (status)); - return status; - } - - if (len == 0) - return SANE_STATUS_GOOD; - - outdata[0] = BULK_IN; - outdata[1] = BULK_RAM; - outdata[2] = VALUE_BUFFER; - outdata[3] = 0; - outdata[4] = (len & 0xff); - outdata[5] = ((len >> 8) & 0xff); - outdata[6] = ((len >> 16) & 0xff); - outdata[7] = ((len >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, INDEX, sizeof (outdata), outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_bulk_read_data failed while writing command: %s\n", - sane_strstatus (status)); - return status; - } - - while (len) - { - if (len > 0xF000) - size = 0xF000; - else - size = len; - if (size >= 512) - { - size /= 512; - size *= 512; - } - - DBG (DBG_io2, - "gl843_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) size); - - status = sanei_usb_read_bulk (dev->dn, data, &size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io2, - "gl843_bulk_read_data read %lu bytes, %lu remaining\n", - (u_long) size, (u_long) (len - size)); - - len -= size; - data += size; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl843_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_get_filter_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_get_lineart_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_get_bitset_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_get_gain4_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -/** - * compute the step multiplier used - */ -static int -gl843_get_step_multiplier (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - int value = 1; - - r = sanei_genesys_get_address (regs, REG9D); - if (r != NULL) - { - switch (r->value & 0x0c) - { - case 0x04: - value = 2; - break; - case 0x08: - value = 4; - break; - default: - value = 1; - } - } - DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); - return value; -} - -static SANE_Bool -gl843_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** @brief sensor profile - * search for the database of motor profiles and get the best one. Each - * profile is at a specific dpihw. Use first entry of table by default. - * @param sensor_type sensor id - * @param dpi hardware dpi for the scan - * @param flags to select between XPA, XPA+IR or regular scan from OPTICAL_FLAGS_* - * @return a pointer to a Sensor_Profile struct - */ -static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi, int flags) -{ - unsigned int i, count; - int idx; - Sensor_Profile *sp; - - if(flags & OPTICAL_FLAG_USE_XPA) - { - sp=xpa_sensors; - count=sizeof(xpa_sensors)/sizeof(Sensor_Profile); - } - else - { - sp=sensors; - count=sizeof(sensors)/sizeof(Sensor_Profile); - } - i=0; - idx=-1; - while(i=dpi - && sp[i].dpimodel->ccd_type, dpihw, flags); - - for (i = 0x06; i < 0x0e; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - if (r) - r->value = sensor->regs_0x10_0x1d[i]; - } - for (i = 0; i < 9; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - if (r) - r->value = sensor->regs_0x52_0x5e[i]; - } - - /* specific registers */ - r = sanei_genesys_get_address (regs, 0x0c); - if (r) - { - r->value = sensor->reg0c; - } - r = sanei_genesys_get_address (regs, 0x70); - if (r) - { - r->value = sensor->reg70; - } - r = sanei_genesys_get_address (regs, 0x71); - if (r) - { - r->value = sensor->reg71; - } - r = sanei_genesys_get_address (regs, 0x7d); - if (r) - { - if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE)) - { - r->value = 0x90; - } - } - r = sanei_genesys_get_address (regs, 0x9e); - if (r) - { - r->value = sensor->reg9e; - } - /* undocumented register */ - r = sanei_genesys_get_address (regs, 0xaa); - if (r) - { - r->value = sensor->regaa; - } - - /* CKxMAP */ - sanei_genesys_set_triple(regs,REG_CK1MAP,sensor->ck1map); - sanei_genesys_set_triple(regs,REG_CK3MAP,sensor->ck3map); - sanei_genesys_set_triple(regs,REG_CK4MAP,sensor->ck4map); - - DBGCOMPLETED; -} - - -/* returns the max register bulk size */ -static int -gl843_bulk_full_size (void) -{ - return GENESYS_GL843_MAX_REGS; -} - -/** @brief set all registers to default values . - * This function is called only once at the beginning and - * fills register startup values for registers reused across scans. - * Those that are rarely modified or not modified are written - * individually. - * @param dev device structure holding register set to initialize - */ -static void -gl843_init_registers (Genesys_Device * dev) -{ - DBGSTART; - - memset (dev->reg, 0, GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* default to KV-SS080 */ - SETREG (0xa2, 0x0f); - SETREG (0x01, 0x00); - SETREG (0x02, 0x78); - SETREG (0x03, 0x1f); - SETREG (0x04, 0x10); - SETREG (0x05, 0x80); - SETREG (0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ - SETREG (0x08, 0x00); - SETREG (0x09, 0x00); - SETREG (0x0a, 0x00); - SETREG (0x0b, 0x6a); - SETREG (0x10, 0x00); - SETREG (0x11, 0x00); - SETREG (0x12, 0x00); - SETREG (0x13, 0x00); - SETREG (0x14, 0x00); - SETREG (0x15, 0x00); - SETREG (0x16, 0x33); - SETREG (0x17, 0x1c); - SETREG (0x18, 0x10); - SETREG (0x19, 0x2a); - SETREG (0x1a, 0x04); - SETREG (0x1b, 0x00); - SETREG (0x1c, 0x20); - SETREG (0x1d, 0x04); - SETREG (0x1e, 0x10); - SETREG (0x1f, 0x01); - SETREG (0x20, 0x10); - SETREG (0x21, 0x04); - SETREG (0x22, 0x01); - SETREG (0x23, 0x01); - SETREG (0x24, 0x04); - SETREG (0x25, 0x00); - SETREG (0x26, 0x00); - SETREG (0x27, 0x00); - SETREG (0x2c, 0x02); - SETREG (0x2d, 0x58); - SETREG (0x2e, 0x80); - SETREG (0x2f, 0x80); - SETREG (0x30, 0x00); - SETREG (0x31, 0x14); - SETREG (0x32, 0x27); - SETREG (0x33, 0xec); - SETREG (0x34, 0x24); - SETREG (0x35, 0x00); - SETREG (0x36, 0xff); - SETREG (0x37, 0xff); - SETREG (0x38, 0x55); - SETREG (0x39, 0xf0); - SETREG (0x3d, 0x00); - SETREG (0x3e, 0x00); - SETREG (0x3f, 0x01); - SETREG (0x52, 0x01); - SETREG (0x53, 0x04); - SETREG (0x54, 0x07); - SETREG (0x55, 0x0a); - SETREG (0x56, 0x0d); - SETREG (0x57, 0x10); - SETREG (0x58, 0x1b); - SETREG (0x59, 0x00); - SETREG (0x5a, 0x40); - SETREG (0x5e, 0x23); - SETREG (0x5f, 0x01); - SETREG (0x60, 0x00); - SETREG (0x61, 0x00); - SETREG (0x62, 0x00); - SETREG (0x63, 0x00); - SETREG (0x64, 0x00); - SETREG (0x65, 0x00); - SETREG (0x67, 0x7f); - SETREG (0x68, 0x7f); - SETREG (0x69, 0x01); - SETREG (0x6a, 0x04); - SETREG (0x6b, 0x30); - SETREG (0x70, 0x01); - SETREG (0x71, 0x03); - SETREG (0x72, 0x04); - SETREG (0x73, 0x05); - - /* CKxMAP */ - SETREG (0x74, 0x00); - SETREG (0x75, 0x00); - SETREG (0x76, 0x3c); - SETREG (0x77, 0x00); - SETREG (0x78, 0x00); - SETREG (0x79, 0x9f); - SETREG (0x7a, 0x00); - SETREG (0x7b, 0x00); - SETREG (0x7c, 0x55); - - SETREG (0x7d, 0x00); - SETREG (0x7f, 0x00); - SETREG (0x80, 0x00); - if (strcmp (dev->model->name, "canon-canoscan-4400f") != 0) - { - SETREG (0x81, 0x00); - SETREG (0x82, 0x00); - SETREG (0x83, 0x00); - SETREG (0x84, 0x00); - SETREG (0x85, 0x00); - SETREG (0x86, 0x00); - } - SETREG (0x87, 0x00); - SETREG (0x9d, 0x04); - SETREG (0x9e, 0x00); - if (strcmp (dev->model->name, "canon-canoscan-8400f") != 0) - { - SETREG (0x0c, 0x00); - SETREG (0x94, 0xff); - SETREG (0xab, 0x50); - } - - /* so many time burnt for this register ....*/ - if (strcmp (dev->model->name, "canon-canoscan-4400f") != 0 - &&strcmp (dev->model->name, "canon-canoscan-8400f") != 0) - { - SETREG (0xaa, 0x00); - } - - /* G4050 values */ - if ((strcmp (dev->model->name, "hewlett-packard-scanjet-g4050") == 0) - || (strcmp (dev->model->name, "hewlett-packard-scanjet-4850c") == 0) - || (strcmp (dev->model->name, "hewlett-packard-scanjet-g4010") == 0)) - { - SETREG (0x03, 0x1d); - SETREG (0x05, 0x08); - SETREG (0x06, 0xd0); /* SCANMOD=110, PWRBIT and no GAIN4 */ - SETREG (0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ - SETREG (0x0a, 0x18); - SETREG (0x0b, 0x69); - - /* CIS exposure is used for XPA lamp movement */ - SETREG (0x10, 0x2c); - SETREG (0x11, 0x09); - SETREG (0x12, 0x22); - SETREG (0x13, 0xb8); - SETREG (0x14, 0x10); - SETREG (0x15, 0xf0); - - SETREG (0x6b, 0xf4); - - SETREG (0x70, 0x00); - SETREG (0x71, 0x02); - SETREG (0x72, 0x00); - SETREG (0x73, 0x00); - - SETREG (0x80, 0x50); - SETREG (0x9d, 0x08); - SETREG (0xab, 0x40); - - /* XXX STEF XXX TODO move to set for scan */ - SETREG (0x98, 0x03); - SETREG (0x99, 0x30); - SETREG (0x9a, 0x01); - SETREG (0x9b, 0x80); - SETREG (0xac, 0x00); - } - - if (strcmp (dev->model->name, "canon-canoscan-4400f") == 0) - { - SETREG (0x06, 0xf0); /* SCANMOD=111, PWRBIT and no GAIN4 */ - SETREG (0x0b, 0x69); /* 16M only */ - SETREG (0x1e, 0x20); - SETREG (0x22, 0xc8); - SETREG (0x23, 0xc8); - SETREG (0x5e, 0x3f); - SETREG (0x5f, 0xf0); - SETREG (0x6b, 0x72); - SETREG (0x72, 0x01); - SETREG (0x73, 0x03); - SETREG (0x80, 0x0c); - SETREG (0x87, 0x02); /* MCLOCK -> CK4MAP */ - SETREG (0x9d, 0x08); /* STEPTIM=2 */ - SETREG (0xa2, 0x1f); - SETREG (0xab, 0x00); - sanei_genesys_set_double(dev->reg,REG_EXPR,0x9c40); - sanei_genesys_set_double(dev->reg,REG_EXPG,0x9c40); - sanei_genesys_set_double(dev->reg,REG_EXPB,0x9c40); - } - - if (strcmp (dev->model->name, "canon-canoscan-8400f") == 0) - { - SETREG (0x03, 0x1c); - SETREG (0x06, 0xd0); /* SCANMOD=110, PWRBIT and no GAIN4 */ - SETREG (0x0a, 0x10); - SETREG (0x22, 0x50); - SETREG (0x23, 0x50); - SETREG (0x5e, 0x85); - SETREG (0x6b, 0xb1); - SETREG (0x1e, 0xa0); - SETREG (0x72, 0x03); - SETREG (0x73, 0x04); - SETREG (0x7d, 0x20); - SETREG (0x80, 0x28); - SETREG (0x87, 0x02); /* MCLOCK -> CK4MAP */ - SETREG (0x9d, 0x08); /* STEPTIM=2 */ - } - - /* fine tune upon device description */ - dev->reg[reg_0x05].value &= ~REG05_DPIHW; - switch (dev->sensor.optical_res) - { - case 600: - dev->reg[reg_0x05].value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg[reg_0x05].value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg[reg_0x05].value |= REG05_DPIHW_2400; - break; - case 4800: - dev->reg[reg_0x05].value |= REG05_DPIHW_4800; - break; - } - - /* initalize calibration reg */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - DBGCOMPLETED; -} - -/* Send slope table for motor movement - slope_table in machine byte order - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl843_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - SANE_Status status; - uint8_t *table; - int i; - char msg[10000]; - - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, - table_nr, steps); - - table = (uint8_t *) malloc (steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), "%d", slope_table[i]); - } - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - - /* slope table addresses are fixed : 0x4000, 0x4800, 0x5000, 0x5800, 0x6000 */ - /* XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14); */ - status = write_data (dev, 0x4000 + 0x800 * table_nr, steps * 2, table); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: write data failed writing slope table %d (%s)\n", - __func__, table_nr, sane_strstatus (status)); - } - - free (table); - DBGCOMPLETED; - return status; -} - - -/* Set values of analog frontend */ -static SANE_Status -gl843_set_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status; - uint8_t val; - int i; - - DBG (DBG_proc, "gl843_set_fe (%s)\n", - set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?"); - - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl843_set_fe(): setting DAC %u\n", - dev->model->dac_type); - sanei_genesys_init_fe (dev); - } - - /* check analog frontend type */ - RIE (sanei_genesys_read_register (dev, REG04, &val)); - if ((val & REG04_FESET) != 0x00) - { - /* for now there is no support for AD fe */ - DBG (DBG_proc, "gl843_set_fe(): unsupported frontend type %d\n", - dev->reg[reg_0x04].value & REG04_FESET); - return SANE_STATUS_UNSUPPORTED; - } - - DBG (DBG_proc, "gl843_set_fe(): frontend reset complete\n"); - - for (i = 1; i <= 3; i++) - { - status = sanei_genesys_fe_write_data (dev, i, dev->frontend.reg[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_set_fe: writing reg[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - } - - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x20 + i, dev->frontend.offset[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_set_fe: writing offset[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - } - - if (dev->model->ccd_type == CCD_KVSS080) - { - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x24 + i, - dev->frontend.sign[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_set_fe: writing sign[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - } - } - - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x28 + i, dev->frontend.gain[i]); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_set_fe: writing gain[%d] failed: %s\n", i, - sane_strstatus (status)); - return status; - } - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl843_init_motor_regs_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int exposure, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - int scan_power_mode, - unsigned int flags) -{ - SANE_Status status; - int use_fast_fed, coeff; - unsigned int lincnt; - uint16_t scan_table[1024]; - uint16_t fast_table[1024]; - int scan_steps,fast_steps, fast_step_type; - unsigned int feedl,factor,dist; - Genesys_Register_Set *r; - uint32_t z1, z2; - - DBGSTART; - DBG (DBG_info, "gl843_init_motor_regs_scan : exposure=%d, " - "scan_yres=%g, scan_step_type=%d, scan_lines=%d, scan_dummy=%d, " - "feed_steps=%d, scan_power_mode=%d, flags=%x\n", - exposure, scan_yres, scan_step_type, - scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); - - /* get step multiplier */ - factor = gl843_get_step_multiplier (reg); - - use_fast_fed = 0; - - if((scan_yres>=300 && feed_steps>900) || (flags & MOTOR_FLAG_FEED)) - use_fast_fed=1; - - lincnt=scan_lines; - sanei_genesys_set_triple(reg,REG_LINCNT,lincnt); - DBG (DBG_io, "%s: lincnt=%d\n", __func__, lincnt); - - /* compute register 02 value */ - r = sanei_genesys_get_address (reg, REG02); - r->value = 0x00; - r->value |= REG02_MTRPWR; - - if (use_fast_fed) - r->value |= REG02_FASTFED; - else - r->value &= ~REG02_FASTFED; - - /* in case of automatic go home, move until home sensor */ - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= REG02_AGOHOME | REG02_NOTHOME; - - /* disable backtracking */ - if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - ||(scan_yres>=2400) - ||(scan_yres>=dev->sensor.optical_res)) - r->value |= REG02_ACDCDIS; - - /* scan and backtracking slope table */ - sanei_genesys_slope_table(scan_table, - &scan_steps, - scan_yres, - exposure, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - gl843_motors); - RIE(gl843_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); - RIE(gl843_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); - - /* STEPNO */ - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = scan_steps; - - /* FSHDEC */ - r = sanei_genesys_get_address (reg, REG_FSHDEC); - r->value = scan_steps; - - /* fast table */ - fast_step_type=0; - if(scan_step_type<=fast_step_type) - { - fast_step_type=scan_step_type; - } - sanei_genesys_slope_table(fast_table, - &fast_steps, - sanei_genesys_get_lowest_ydpi(dev), - exposure, - dev->motor.base_ydpi, - fast_step_type, - factor, - dev->model->motor_type, - gl843_motors); - RIE(gl843_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); - RIE(gl843_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); - RIE(gl843_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); - - /* FASTNO */ - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = fast_steps; - - /* FMOVNO */ - r = sanei_genesys_get_address (reg, REG_FMOVNO); - r->value = fast_steps; - - /* substract acceleration distance from feedl */ - feedl=feed_steps; - feedl<<=scan_step_type; - - dist = scan_steps; - if (use_fast_fed) - { - dist += fast_steps*2; - } - DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); - - /* get sure when don't insane value : XXX STEF XXX in this case we should - * fall back to single table move */ - if(dist600) - { - z1=0; - z2=0; - } - - sanei_genesys_set_triple(reg,REG_Z1MOD,z1); - DBG (DBG_info, "gl843_init_motor_regs_scan: z1 = %d\n", z1); - - sanei_genesys_set_triple(reg,REG_Z2MOD,z2); - DBG (DBG_info, "gl843_init_motor_regs_scan: z2 = %d\n", z2); - - r = sanei_genesys_get_address (reg, REG1E); - r->value &= 0xf0; /* 0 dummy lines */ - r->value |= scan_dummy; /* dummy lines */ - - r = sanei_genesys_get_address (reg, REG67); - r->value = 0x3f | (scan_step_type << REG67S_STEPSEL); - - r = sanei_genesys_get_address (reg, REG68); - r->value = 0x3f | (scan_step_type << REG68S_FSTPSEL); - - /* steps for STOP table */ - r = sanei_genesys_get_address (reg, REG_FMOVDEC); - r->value = fast_steps; - - /* Vref XXX STEF XXX : optical divider or step type ? */ - r = sanei_genesys_get_address (reg, 0x80); - if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE)) - { - r->value = 0x50; - coeff=dev->sensor.optical_res/sanei_genesys_compute_dpihw(dev, scan_yres); - if (dev->model->motor_type == MOTOR_KVSS080) - { - if(coeff>=1) - { - r->value |= 0x05; - } - } - else { - switch(coeff) - { - case 4: - r->value |= 0x0a; - break; - case 2: - r->value |= 0x0f; - break; - case 1: - r->value |= 0x0f; - break; - } - } - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/**@brief compute exposure to use - * compute the sensor exposure based on target resolution - */ -static int gl843_compute_exposure(Genesys_Device *dev, int xres, int flags) -{ - Sensor_Profile *sensor; - - sensor=get_sensor_profile(dev->model->ccd_type, xres, flags); - return sensor->exposure; -} - -/** @brief setup optical related registers - * start and pixels are expressed in optical sensor resolution coordinate - * space. - * @param dev device to use - * @param reg registers to set up - * @param exposure exposure time to use - * @param used_res scanning resolution used, may differ from - * scan's one - * @param start logical start pixel coordinate - * @param pixels logical number of pixels to use - * @param channels number of color channles used (1 or 3) - * @param depth bit depth of the scan (1, 8 or 16 bits) - * @param half_ccd SANE_TRUE if timings are such that x coordiantes must be halved - * @param color_filter to choose the color channel used in gray scans - * @param flags to drive specific settings such no calibration, XPA use ... - * @return SANE_STATUS_GOOD if OK - */ -static SANE_Status -gl843_init_optical_regs_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int exposure, - int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, - int color_filter, - int flags) -{ - unsigned int words_per_line; - unsigned int startx, endx, used_pixels; - unsigned int dpiset, dpihw, factor; - unsigned int bytes; - unsigned int tgtime; /**> exposure time multiplier */ - unsigned int cksel; /**> clock per system pixel time in capturing image */ - Genesys_Register_Set *r; - SANE_Status status; - - DBG (DBG_proc, "gl843_init_optical_regs_scan : exposure=%d, " - "used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", - exposure, - used_res, start, pixels, channels, depth, half_ccd, flags); - - /* tgtime */ - tgtime=1; - if (dev->model->ccd_type == CCD_G4050 && used_res>2400) - { - tgtime=2; - } - DBG (DBG_io2, "%s: tgtime=%d\n", __func__, tgtime); - - /* to manage high resolution device while keeping good - * low resolution scanning speed, we make hardware dpi vary */ - dpihw=sanei_genesys_compute_dpihw(dev, used_res); - factor=dev->sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); - - /* sensor parameters */ - gl843_setup_sensor (dev, reg, dpihw, flags); - - /* resolution is divided according to CKSEL which is known once sensor is set up */ - r = sanei_genesys_get_address (reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); - dpiset = used_res * cksel; - - /* start and end coordinate in optical dpi coordinates */ - startx = (start + dev->sensor.dummy_pixel * tgtime)/cksel; - - used_pixels=pixels/cksel; - endx = startx + used_pixels; - - /* pixel coordinate factor correction when used dpihw is not maximal one */ - startx/=factor; - endx/=factor; - used_pixels=endx-startx; - - /* in case of stagger we have to start at an odd coordinate */ - if ((flags & OPTICAL_FLAG_STAGGER) - &&((startx & 1)==0)) - { - startx++; - endx++; - } - - status = gl843_set_fe (dev, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, REG01); - r->value &= ~REG01_SCAN; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - r->value &= ~REG01_DVDSET; - } - else - { - r->value |= REG01_DVDSET; - } - if(dpihw>600) - { - r->value |= REG01_SHDAREA; - } - else - { - r->value &= ~REG01_SHDAREA; - } - - r = sanei_genesys_get_address (reg, REG03); - r->value &= ~REG03_AVEENB; - if (flags & OPTICAL_FLAG_DISABLE_LAMP) - r->value &= ~REG03_LAMPPWR; - else - r->value |= REG03_LAMPPWR; - - /* select XPA */ - r->value &= ~REG03_XPASEL; - if (flags & OPTICAL_FLAG_USE_XPA) - { - r->value |= REG03_XPASEL; - } - - /* BW threshold */ - r = sanei_genesys_get_address (reg, REG2E); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, REG2F); - r->value = dev->settings.threshold; - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, REG04); - switch (depth) - { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - r->value &= ~(REG04_FILTER | REG04_AFEMOD); - if (channels == 1) - { - switch (color_filter) - { - case 0: - r->value |= 0x14; /* red filter */ - break; - case 2: - r->value |= 0x1c; /* blue filter */ - break; - default: - r->value |= 0x18; /* green filter */ - break; - } - } - else - r->value |= 0x10; /* mono */ - - /* register 05 */ - r = sanei_genesys_get_address (reg, REG05); - - /* set up dpihw */ - r->value &= ~REG05_DPIHW; - switch(dpihw) - { - case 600: - r->value |= REG05_DPIHW_600; - break; - case 1200: - r->value |= REG05_DPIHW_1200; - break; - case 2400: - r->value |= REG05_DPIHW_2400; - break; - case 4800: - r->value |= REG05_DPIHW_4800; - break; - } - - /* enable gamma tables */ - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - if(half_ccd) - { - sanei_genesys_set_double(reg,REG_DPISET,dpiset*4); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset*4); - } - else - { - sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); - } - - sanei_genesys_set_double(reg,REG_STRPIXEL,startx/tgtime); - sanei_genesys_set_double(reg,REG_ENDPIXEL,endx/tgtime); - - /* words(16bit) before gamma, conversion to 8 bit or lineart */ - words_per_line = (used_pixels * dpiset) / dpihw; - bytes = depth / 8; - if (depth == 1) - { - words_per_line = (words_per_line >> 3) + ((words_per_line & 7) ? 1 : 0); - } - else - { - words_per_line *= bytes; - } - - dev->wpl = words_per_line; - dev->bpl = words_per_line; - - DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long) dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); - - words_per_line *= channels; - - /* MAXWD is expressed in 2 words unit */ - /* nousedspace = (mem_bank_range * 1024 / 256 -1 ) * 4; */ - sanei_genesys_set_triple(reg,REG_MAXWD,(words_per_line)>>1); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); - - sanei_genesys_set_double(reg,REG_LPERIOD,exposure/tgtime); - DBG (DBG_io2, "%s: exposure used=%d\n", __func__, exposure/tgtime); - - r = sanei_genesys_get_address (reg, REG_DUMMY); - r->value = dev->sensor.dummy_pixel * tgtime; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl843_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int scan_mode, - int color_filter, - unsigned int flags) -{ - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; /**> line count to scan */ - unsigned int oflags, mflags; /**> optical and motor flags */ - int exposure; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int scan_power_mode = 0; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - SANE_Status status; - - DBG (DBG_info, - "gl843_init_scan_regs settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g/%g\n" - "Depth/Channels: %u/%u\n" - "Flags : %x\n\n", - xres, yres, lines, pixels, startx, starty, depth, channels, flags); - - - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if (dev->sensor.optical_res < 4 * xres || - !(dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)) - { - half_ccd = SANE_FALSE; - } - else - { - half_ccd = SANE_TRUE; - } - - /* optical_res */ - optical_res = dev->sensor.optical_res; - if (half_ccd) - optical_res /= 4; - - /* stagger starting at 2400, and not applied for calibration */ - stagger = 0; - if ( (yres>1200) - && ((flags & SCAN_FLAG_IGNORE_LINE_DISTANCE)==0) - && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - { - stagger = (4 * yres) / dev->motor.base_ydpi; - } - DBG (DBG_info, "%s : stagger=%d lines\n", __func__, stagger); - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - oflags = 0; - if (flags & SCAN_FLAG_DISABLE_SHADING) - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - if (flags & SCAN_FLAG_DISABLE_GAMMA) - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - if (flags & SCAN_FLAG_DISABLE_LAMP) - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - if (flags & SCAN_FLAG_CALIBRATION) - oflags |= OPTICAL_FLAG_DISABLE_DOUBLE; - if(stagger) - oflags |= OPTICAL_FLAG_STAGGER; - if (flags & SCAN_FLAG_USE_XPA) - oflags |= OPTICAL_FLAG_USE_XPA; - - /** @brief compute used resolution */ - if (flags & SCAN_FLAG_USE_OPTICAL_RES) - { - used_res = optical_res; - } - else - { - /* resolution is choosen from a fixed list and can be used directly - * unless we have ydpi higher than sensor's maximum one */ - if(xres>optical_res) - used_res=optical_res; - else - used_res = xres; - } - - /* compute scan parameters values */ - /* pixels are allways given at full optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - start = startx; - - /* compute correct pixels number */ - used_pixels = (pixels * optical_res) / xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); - - /* round up pixels number if needed */ - if (used_pixels * xres < pixels * optical_res) - used_pixels++; - - /* we want even number of pixels here */ - if(used_pixels & 1) - used_pixels++; - - dummy = 0; - /* dummy = 1; XXX STEF XXX */ - - /* slope_dpi */ - /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = yres * channels; - else - slope_dpi = yres; - slope_dpi = slope_dpi * (1 + dummy); - - /* scan_step_type */ - if(flags & SCAN_FLAG_FEEDING) - { - exposure=gl843_compute_exposure (dev, sanei_genesys_get_lowest_ydpi(dev), oflags); - scan_step_type=sanei_genesys_compute_step_type (gl843_motors, dev->model->motor_type, exposure); - } - else - { - exposure = gl843_compute_exposure (dev, used_res, oflags); - scan_step_type = sanei_genesys_compute_step_type(gl843_motors, dev->model->motor_type, exposure); - } - - DBG (DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); - DBG (DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); - - /*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if ((flags & SCAN_FLAG_DYNAMIC_LINEART) && (scan_mode == SCAN_MODE_LINEART)) - { - depth = 8; - } - /* no 16 bit gamma for this ASIC */ - if (depth == 16) - { - flags |= SCAN_FLAG_DISABLE_GAMMA; - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - } - - /* now _LOGICAL_ optical values used are known, setup registers */ - status = gl843_init_optical_regs_scan (dev, - reg, - exposure, - used_res, - start, - used_pixels, - channels, - depth, - half_ccd, - color_filter, - oflags); - if (status != SANE_STATUS_GOOD) - return status; - - /*** motor parameters ***/ - - /* it seems base_dpi of the G4050 motor is changed above 600 dpi*/ - if (dev->model->motor_type == MOTOR_G4050 && yres>600) - { - dev->ld_shift_r = (dev->model->ld_shift_r*3800)/dev->motor.base_ydpi; - dev->ld_shift_g = (dev->model->ld_shift_g*3800)/dev->motor.base_ydpi; - dev->ld_shift_b = (dev->model->ld_shift_b*3800)/dev->motor.base_ydpi; - } - else - { - dev->ld_shift_r = dev->model->ld_shift_r; - dev->ld_shift_g = dev->model->ld_shift_g; - dev->ld_shift_b = dev->model->ld_shift_b; - } - - /* max_shift */ - /* scanned area must be enlarged by max color shift needed */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,flags); - - /* lines to scan */ - lincnt = lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = starty; - DBG (DBG_info, "gl843_init_scan_regs: move=%d steps\n", move); - - - mflags=0; - if(flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) - mflags|=MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; - if(flags & SCAN_FLAG_FEEDING) - mflags|=MOTOR_FLAG_FEED; - if (flags & SCAN_FLAG_USE_XPA) - mflags |= MOTOR_FLAG_USE_XPA; - - status = gl843_init_motor_regs_scan (dev, - reg, - exposure, - slope_dpi, - scan_step_type, - dev->model->is_cis ? lincnt * channels : lincnt, - dummy, - move, - scan_power_mode, - mflags); - if (status != SANE_STATUS_GOOD) - return status; - - /*** prepares data reordering ***/ - - /* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * channels * depth) / 8; - - /* since we don't have sheetfed scanners to handle, - * use huge read buffer */ - /* TODO find the best size according to settings */ - requested_buffer_size = 16 * bytes_per_line; - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * channels * depth) / 8; - - RIE (sanei_genesys_buffer_free (&(dev->read_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->read_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->lines_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->lines_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->shrink_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->shrink_buffer), - requested_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->out_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->out_buffer), - (8 * dev->settings.pixels * channels * - depth) / 8)); - - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG (DBG_info, - "gl843_init_scan_regs: physical bytes to read = %lu\n", - (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - dev->total_bytes_read = 0; - if (depth == 1) - dev->total_bytes_to_read = - ((dev->settings.pixels * dev->settings.lines) / 8 + - (((dev->settings.pixels * dev->settings.lines) % 8) ? 1 : 0)) * - channels; - else - dev->total_bytes_to_read = - dev->settings.pixels * dev->settings.lines * channels * (depth / 8); - - DBG (DBG_info, "gl843_init_scan_regs: total bytes to send = %lu\n", - (u_long) dev->total_bytes_to_read); - - DBG (DBG_proc, "gl843_init_scan_regs: completed\n"); - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl843_calculate_current_setup (Genesys_Device * dev) -{ - int channels; - int depth; - int start; - - float xres; /*dpi */ - float yres; /*dpi */ - float startx; /*optical_res, from dummy_pixel+1 */ - float pixels; - float lines; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure; - int stagger; - - int max_shift; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - int oflags; - - DBG (DBG_info, - "gl843_calculate_current_setup settings:\n" - "Resolution: %ux%uDPI\n" - "Lines : %u\n" - "PPL : %u\n" - "Startpos : %.3f/%.3f\n" - "Scan mode : %d\n\n", - dev->settings.xres, - dev->settings.yres, dev->settings.lines, dev->settings.pixels, - dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); - - /* channels */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == SCAN_MODE_LINEART) - depth = 1; - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - /* optical flags */ - oflags=0; - if(dev->settings.scan_method==SCAN_METHOD_TRANSPARENCY) - { - oflags=OPTICAL_FLAG_USE_XPA; - } - - xres = dev->settings.xres; - yres = dev->settings.yres; - startx = start; - pixels = dev->settings.pixels; - lines = dev->settings.lines; - - DBG (DBG_info, - "gl843_calculate_current_setup settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g\n" - "Depth/Channels: %u/%u\n\n", - xres, yres, lines, pixels, startx, depth, channels); - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if ((dev->sensor.optical_res < 4 * xres) || - !(dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)) - { - half_ccd = SANE_FALSE; - } - else - { - half_ccd = SANE_TRUE; - } - - - /* optical_res */ - optical_res = dev->sensor.optical_res; - if (half_ccd) - optical_res /= 4; - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "%s: stagger=%d lines\n", __func__, stagger); - - if(xres<=optical_res) - used_res = xres; - else - used_res=optical_res; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - - /* compute correct pixels number */ - used_pixels = (pixels * optical_res) / xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); - - /* exposure */ - exposure = gl843_compute_exposure (dev, used_res, oflags); - DBG (DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); - - /* it seems base_dpi of the G4050 motor is changed above 600 dpi*/ - if (dev->model->motor_type == MOTOR_G4050 && yres>600) - { - dev->ld_shift_r = (dev->model->ld_shift_r*3800)/dev->motor.base_ydpi; - dev->ld_shift_g = (dev->model->ld_shift_g*3800)/dev->motor.base_ydpi; - dev->ld_shift_b = (dev->model->ld_shift_b*3800)/dev->motor.base_ydpi; - } - else - { - dev->ld_shift_r = dev->model->ld_shift_r; - dev->ld_shift_g = dev->model->ld_shift_g; - dev->ld_shift_b = dev->model->ld_shift_b; - } - - /* scanned area must be enlarged by max color shift needed */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); - - /* lincnt */ - lincnt = lines + max_shift + stagger; - - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBG (DBG_proc, "gl843_calculate_current_setup: completed\n"); - return SANE_STATUS_GOOD; -} - -static void -gl843_set_motor_power (Genesys_Register_Set * regs, SANE_Bool set) -{ - - DBG (DBG_proc, "gl843_set_motor_power\n"); - - if (set) - { - sanei_genesys_set_reg_from_set (regs, REG02, - sanei_genesys_read_reg_from_set (regs, - REG02) - | REG02_MTRPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, REG02, - sanei_genesys_read_reg_from_set (regs, - REG02) - & ~REG02_MTRPWR); - } -} - -static void -gl843_set_lamp_power (Genesys_Device * dev, - Genesys_Register_Set * regs, SANE_Bool set) -{ - Genesys_Register_Set *r; - int i; - uint8_t val; - - val = sanei_genesys_read_reg_from_set (regs, REG03); - if (set) - { - val |= REG03_LAMPPWR; - sanei_genesys_set_reg_from_set (regs, REG03, val); - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - } - else - { - val &= ~REG03_LAMPPWR; - sanei_genesys_set_reg_from_set (regs, REG03, val); - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = 0x00; - } - } -} - -/** - * for fast power saving methods only, like disabling certain amplifiers - * @param dev device to use - * @param enable true to set inot powersaving - * */ -static SANE_Status -gl843_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - uint8_t val; - SANE_Status status; - - DBG (DBG_proc, "gl843_save_power: enable = %d\n", enable); - if (dev == NULL) - return SANE_STATUS_INVAL; - - /* switch KV-SS080 lamp off */ - if (dev->model->gpo_type == GPO_KVSS080) - { - RIE(sanei_genesys_read_register (dev, REG6C, &val)); - if(enable) - val &= 0xef; - else - val |= 0x10; - RIE(sanei_genesys_write_register(dev,REG6C,val)); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl843_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG (DBG_proc, "gl843_set_powersaving (delay = %d)\n", delay); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return status; -} - -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl843_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -static SANE_Status -gl843_stop_action (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val40, val; - unsigned int loop; - - DBG (DBG_proc, "%s\n", __func__); - - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - val40 = 0; - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - DBG (DBG_proc, "%s: completed\n", __func__); - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBG (DBG_info, "%s: already stopped\n", __func__); - DBG (DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; - } - - /* ends scan 646 */ - val = sanei_genesys_read_reg_from_set (dev->reg, REG01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set (dev->reg, REG01, val); - status = sanei_genesys_write_register (dev, REG01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write register 01: %s\n", __func__, - sane_strstatus (status)); - return status; - } - usleep (100 * 1000); - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - val40 = 0; - status = sanei_genesys_read_register (dev, 0x40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) - && !(val & REG41_MOTORENB)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - usleep (100 * 1000); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - -static SANE_Status -gl843_get_paper_sensor (Genesys_Device * dev, SANE_Bool * paper_loaded) -{ - SANE_Status status; - uint8_t val; - - status = sanei_genesys_read_register (dev, REG6D, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_get_paper_sensor: failed to read gpio: %s\n", - sane_strstatus (status)); - return status; - } - *paper_loaded = (val & 0x1) == 0; - return SANE_STATUS_GOOD; - - return SANE_STATUS_INVAL; -} - -static SANE_Status -gl843_eject_document (Genesys_Device * dev) -{ - DBG (DBG_proc, "%s: not implemented \n", __func__); - if (dev == NULL) - return SANE_STATUS_INVAL; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl843_load_document (Genesys_Device * dev) -{ - DBG (DBG_proc, "%s: not implemented \n", __func__); - if (dev == NULL) - return SANE_STATUS_INVAL; - return SANE_STATUS_GOOD; -} - -/** - * detects end of document and adjust current scan - * to take it into account - * used by sheetfed scanners - */ -static SANE_Status -gl843_detect_document_end (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool paper_loaded; - unsigned int scancnt = 0; - int flines, channels, depth, bytes_remain, sublines, - bytes_to_flush, lines, sub_bytes, tmp, read_bytes_left; - DBG (DBG_proc, "%s: begin\n", __func__); - - RIE (gl843_get_paper_sensor (dev, &paper_loaded)); - - /* sheetfed scanner uses home sensor as paper present */ - if ((dev->document == SANE_TRUE) && !paper_loaded) - { - DBG (DBG_info, "%s: no more document\n", __func__); - dev->document = SANE_FALSE; - - channels = dev->current_setup.channels; - depth = dev->current_setup.depth; - read_bytes_left = (int) dev->read_bytes_left; - DBG (DBG_io, "gl843_detect_document_end: read_bytes_left=%d\n", - read_bytes_left); - - /* get lines read */ - status = sanei_genesys_read_scancnt (dev, &scancnt); - if (status != SANE_STATUS_GOOD) - { - flines = 0; - } - else - { - /* compute number of line read */ - tmp = (int) dev->total_bytes_read; - if (depth == 1 || dev->settings.scan_mode == SCAN_MODE_LINEART) - flines = tmp * 8 / dev->settings.pixels / channels; - else - flines = tmp / (depth / 8) / dev->settings.pixels / channels; - - /* number of scanned lines, but no read yet */ - flines = scancnt - flines; - - DBG (DBG_io, - "gl843_detect_document_end: %d scanned but not read lines\n", - flines); - } - - /* adjust number of bytes to read - * we need to read the final bytes which are word per line * number of last lines - * to have doc leaving feeder */ - lines = - (SANE_UNFIX (dev->model->post_scan) * dev->current_setup.yres) / - MM_PER_INCH + flines; - DBG (DBG_io, "gl843_detect_document_end: adding %d line to flush\n", - lines); - - /* number of bytes to read from scanner to get document out of it after - * end of document dectected by hardware sensor */ - bytes_to_flush = lines * dev->wpl; - - /* if we are already close to end of scan, flushing isn't needed */ - if (bytes_to_flush < read_bytes_left) - { - /* we take all these step to work around an overflow on some plateforms */ - tmp = (int) dev->total_bytes_read; - DBG (DBG_io, "gl843_detect_document_end: tmp=%d\n", tmp); - bytes_remain = (int) dev->total_bytes_to_read; - DBG (DBG_io, "gl843_detect_document_end: bytes_remain=%d\n", - bytes_remain); - bytes_remain = bytes_remain - tmp; - DBG (DBG_io, "gl843_detect_document_end: bytes_remain=%d\n", - bytes_remain); - - /* remaining lines to read by frontend for the current scan */ - if (depth == 1 || dev->settings.scan_mode == SCAN_MODE_LINEART) - { - flines = bytes_remain * 8 / dev->settings.pixels / channels; - } - else - flines = bytes_remain / (depth / 8) - / dev->settings.pixels / channels; - DBG (DBG_io, "gl843_detect_document_end: flines=%d\n", flines); - - if (flines > lines) - { - /* change the value controlling communication with the frontend : - * total bytes to read is current value plus the number of remaining lines - * multiplied by bytes per line */ - sublines = flines - lines; - - if (depth == 1 || dev->settings.scan_mode == SCAN_MODE_LINEART) - sub_bytes = - ((dev->settings.pixels * sublines) / 8 + - (((dev->settings.pixels * sublines) % 8) ? 1 : 0)) * - channels; - else - sub_bytes = - dev->settings.pixels * sublines * channels * (depth / 8); - - dev->total_bytes_to_read -= sub_bytes; - - /* then adjust the physical bytes to read */ - if (read_bytes_left > sub_bytes) - { - dev->read_bytes_left -= sub_bytes; - } - else - { - dev->total_bytes_to_read = dev->total_bytes_read; - dev->read_bytes_left = 0; - } - - DBG (DBG_io, "gl843_detect_document_end: sublines=%d\n", - sublines); - DBG (DBG_io, "gl843_detect_document_end: subbytes=%d\n", - sub_bytes); - DBG (DBG_io, - "gl843_detect_document_end: total_bytes_to_read=%lu\n", - (unsigned long) dev->total_bytes_to_read); - DBG (DBG_io, - "gl843_detect_document_end: read_bytes_left=%d\n", - read_bytes_left); - } - } - else - { - DBG (DBG_io, "gl843_detect_document_end: no flushing needed\n"); - } - } - - DBG (DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - -/** @brief disable XPA slider motor - * toggle gpios to switch disble XPA slider motor - * @param dev device to set up - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl843_xpa_motor_off(Genesys_Device *dev) -{ - uint8_t val; - SANE_Status status=SANE_STATUS_GOOD; - - DBGSTART; - - /* unset GPOADF */ - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - val &= ~REG6B_GPOADF; - RIE (sanei_genesys_write_register (dev, REG6B, val)); - - RIE (sanei_genesys_read_register (dev, REGA8, &val)); - val |= REGA8_GPO27; - RIE (sanei_genesys_write_register (dev, REGA8, val)); - - RIE (sanei_genesys_read_register (dev, REGA9, &val)); - val &= ~REGA9_GPO31; - RIE (sanei_genesys_write_register (dev, REGA9, val)); - - DBGCOMPLETED; - return status; -} - - -/** @brief enable XPA slider motor - * toggle gpios to switch enable XPA slider motor - * @param dev device to set up - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl843_xpa_motor_on(Genesys_Device *dev) -{ - uint8_t val; - SANE_Status status=SANE_STATUS_GOOD; - - DBGSTART; - - /* set MULTFILM et GPOADF */ - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - val |=REG6B_MULTFILM|REG6B_GPOADF; - RIE (sanei_genesys_write_register (dev, REG6B, val)); - - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val &= ~REG6C_GPIO15; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - - /* Motor power ? No move at all without this one */ - RIE (sanei_genesys_read_register (dev, REGA6, &val)); - val |= REGA6_GPIO20; - RIE (sanei_genesys_write_register(dev,REGA6,val)); - - RIE (sanei_genesys_read_register (dev, REGA8, &val)); - val &= ~REGA8_GPO27; - RIE (sanei_genesys_write_register (dev, REGA8, val)); - - RIE (sanei_genesys_read_register (dev, REGA9, &val)); - val |= REGA9_GPO32|REGA9_GPO31; - RIE (sanei_genesys_write_register (dev, REGA9, val)); - - DBGCOMPLETED; - return status; -} - - -/** @brief light XPA lamp - * toggle gpios to switch off regular lamp and light on the - * XPA light - * @param dev device to set up - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl843_xpa_lamp_on(Genesys_Device *dev) -{ - uint8_t val; - SANE_Status status=SANE_STATUS_GOOD; - - DBGSTART; - - /* REGA6 */ - RIE(sanei_genesys_read_register(dev, REGA6, &val)); - - /* cut regular lamp power */ - val &= ~(REGA6_GPIO24|REGA6_GPIO23); - - /* set XPA lamp power */ - val |= REGA6_GPIO22 | REGA6_GPIO21 | REGA6_GPIO19; - - RIE(sanei_genesys_write_register(dev, REGA6, val)); - - RIE(sanei_genesys_read_register(dev, REGA7, &val)); - val|=REGA7_GPOE24; /* lamp 1 off GPOE 24 */ - val|=REGA7_GPOE23; /* lamp 2 off GPOE 23 */ - val|=REGA7_GPOE22; /* full XPA lamp power */ - RIE(sanei_genesys_write_register(dev, REGA7, val)); - - DBGCOMPLETED; - return status; -} - -/* Send the low-level scan command */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl843_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - SANE_Status status; - uint8_t val,r03; - uint16_t dpiset, dpihw; - - DBGSTART; - - /* get back the target dpihw */ - sanei_genesys_get_double (reg, REG_DPISET, &dpiset); - dpihw = sanei_genesys_compute_dpihw (dev, dpiset); - - /* set up GPIO for scan */ - switch(dev->model->gpo_type) - { - /* KV case */ - case GPO_KVSS080: - RIE (sanei_genesys_write_register (dev, REGA9, 0x00)); - RIE (sanei_genesys_write_register (dev, REGA6, 0xf6)); - /* blinking led */ - RIE (sanei_genesys_write_register (dev, 0x7e, 0x04)); - break; - case GPO_G4050: - RIE (sanei_genesys_write_register (dev, REGA7, 0xfe)); - RIE (sanei_genesys_write_register (dev, REGA8, 0x3e)); - RIE (sanei_genesys_write_register (dev, REGA9, 0x06)); - switch (dpihw) - { - case 1200: - case 2400: - case 4800: - RIE (sanei_genesys_write_register (dev, REG6C, 0x60)); - RIE (sanei_genesys_write_register (dev, REGA6, 0x46)); - break; - default: /* 600 dpi case */ - RIE (sanei_genesys_write_register (dev, REG6C, 0x20)); - RIE (sanei_genesys_write_register (dev, REGA6, 0x44)); - } - - /* turn on XPA lamp if XPA is selected and lamp power on*/ - r03 = sanei_genesys_read_reg_from_set (reg, REG03); - if ((r03 & REG03_XPASEL) && (r03 & REG03_LAMPPWR)) - { - RIE(gl843_xpa_lamp_on(dev)); - } - - /* enable XPA lamp motor */ - if (r03 & REG03_XPASEL) - { - RIE(gl843_xpa_motor_on(dev)); - } - - /* blinking led */ - RIE (sanei_genesys_write_register (dev, REG7E, 0x01)); - break; - case GPO_CS4400F: - case GPO_CS8400F: - default: - break; - } - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register - (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* enable scan and motor */ - RIE (sanei_genesys_read_register (dev, REG01, &val)); - val |= REG01_SCAN; - RIE (sanei_genesys_write_register (dev, REG01, val)); - - if (start_motor) - { - RIE (sanei_genesys_write_register (dev, REG0F, 1)); - } - else - { - RIE (sanei_genesys_write_register (dev, REG0F, 0)); - } - - DBGCOMPLETED; - return status; -} - - -/* Send the stop scan command */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl843_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - SANE_Status status; - uint8_t val; - - DBG (DBG_proc, "gl843_end_scan (check_stop = %d)\n", check_stop); - if (reg == NULL) - return SANE_STATUS_INVAL; - - /* post scan gpio */ - RIE(sanei_genesys_write_register(dev,0x7e,0x00)); - - /* turn off XPA lamp if XPA is selected and lamp power on*/ - val = sanei_genesys_read_reg_from_set (reg, REG03); - if (val & (REG03_XPASEL|REG03_LAMPPWR)) - { - sanei_genesys_read_register (dev, REGA6, &val); - - /* switch on regular lamp */ - val |= 0x40; - - /* no XPA lamp power (2 bits for level: __11 ____) */ - val &= ~0x30; - - RIE (sanei_genesys_write_register (dev, REGA6, val)); - } - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl843_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_end_scan: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -/** @brief park XPA lamp - * park the XPA lamp if needed - */ -static SANE_Status gl843_park_xpa_lamp (Genesys_Device * dev) -{ - Genesys_Register_Set local_reg[GENESYS_GL843_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - uint8_t val; - int loop = 0; - - DBGSTART; - - /* copy scan settings */ - memcpy (local_reg, dev->reg, GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* set a huge feedl and reverse direction */ - sanei_genesys_set_triple(local_reg,REG_FEEDL,0xbdcd); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse and no scan */ - r = sanei_genesys_get_address (local_reg, REG02); - r->value |= REG02_MTRREV; - r = sanei_genesys_get_address (local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* write to scanner and start action */ - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL843_MAX_REGS)); - RIE (gl843_xpa_motor_on(dev)); - status = gl843_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to start motor: %s\n",__func__, sane_strstatus (status)); - gl843_stop_action (dev); - /* restore original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL843_MAX_REGS); - return status; - } - - while (loop < 600) /* do not wait longer then 60 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n",__func__, - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io2) - { - sanei_genesys_print_status (val); - } - - if (val & REG41_HOMESNR) /* home sensor */ - { - DBG (DBG_info, "%s: reached home position\n",__func__); - DBG (DBG_proc, "%s: finished\n",__func__); - - /* clear GPOADF to avoid reparking again */ - sanei_genesys_read_register (dev, REG6B, &val); - val &= ~REG6B_GPOADF; - sanei_genesys_write_register (dev, REG6B, val); - - /* disable XPA slider motor */ - gl843_xpa_motor_off(dev); - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* we are not parked here.... should we fail ? */ - DBG (DBG_info, "%s: XPA lamp is not parked\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief Moves the slider to the home (top) position slowly - * */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl843_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg[GENESYS_GL843_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - uint8_t val; - float resolution; - int loop = 0; - - DBG (DBG_proc, "gl843_slow_back_home (wait_until_home = %d)\n", - wait_until_home); - - if (dev->model->gpo_type == GPO_G4050) - { - /* test if we need to park XPA lamp, we check GPOADF */ - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - if(val & REG6B_GPOADF) - { - RIE(gl843_park_xpa_lamp(dev)); - } - } - - /* regular slow back home */ - dev->scanhead_position_in_steps = 0; - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus (status)); - return status; - } - usleep (100000); /* sleep 100 ms */ - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - if (val & HOMESNR) /* is sensor at home? */ - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - memcpy (local_reg, dev->reg, GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - resolution=sanei_genesys_get_lowest_ydpi(dev); - - status = gl843_init_scan_regs (dev, - local_reg, - resolution, - resolution, - 100, - 40000, - 100, - 100, - 8, - 1, - SCAN_MODE_LINEART, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_slow_back_home: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse and no scan */ - r = sanei_genesys_get_address (local_reg, REG02); - r->value |= REG02_MTRREV; - r = sanei_genesys_get_address (local_reg, REG01); - r->value &= ~REG01_SCAN; - - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL843_MAX_REGS)); - - status = gl843_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_slow_back_home: failed to start motor: %s\n", - sane_strstatus (status)); - gl843_stop_action (dev); - /* restore original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL843_MAX_REGS); - return status; - } - - if (wait_until_home) - { - - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io2) - { - sanei_genesys_print_status (val); - } - - if (val & REG41_HOMESNR) /* home sensor */ - { - DBG (DBG_info, "gl843_slow_back_home: reached home position\n"); - DBG (DBG_proc, "gl843_slow_back_home: finished\n"); - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl843_stop_action (dev); - DBG (DBG_error, - "gl843_slow_back_home: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; - } - - DBG (DBG_info, "%s: scanhead is still moving\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl843_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status; - uint8_t *data; - Genesys_Register_Set local_reg[GENESYS_GL843_MAX_REGS]; - int steps; - - int pixels = 600; - int dpi = 300; - - DBG (DBG_proc, "gl843_search_start_position\n"); - - memcpy (local_reg, dev->reg, GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - status = gl843_init_scan_regs (dev, - local_reg, - dpi, - dpi, - 0, - 0, /*we should give a small offset here~60 steps */ - 600, - dev->model->search_lines, - 8, - 1, - SCAN_MODE_GRAY, - 1, /*green */ - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_search_start_position: failed to bulk setup registers: %s\n", - sane_strstatus (status)); - return status; - } - - /* send to scanner */ - status = dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL843_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_search_start_position: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - size = pixels * dev->model->search_lines; - - data = malloc (size); - if (!data) - { - DBG (DBG_error, - "gl843_search_start_position: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - status = gl843_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl843_search_start_position: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl843_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("search_position.pnm", data, 8, 1, pixels, - dev->model->search_lines); - - status = gl843_end_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl843_search_start_position: failed to end scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* update regs to copy ASIC internal state */ - memcpy (dev->reg, local_reg, GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - status = - sanei_genesys_search_reference_point (dev, data, 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl843_search_start_position: failed to set search reference point: %s\n", - sane_strstatus (status)); - return status; - } - - free (data); - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl843_init_regs_for_coarse_calibration (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t channels; - uint8_t cksel; - - DBGSTART; - cksel = (dev->calib_reg[reg_0x18].value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - status = gl843_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - /* XXX STEF XXX dpi instead of pixels !*/ - dev->sensor.optical_res / cksel, - 20, - 16, - channels, - dev->settings.scan_mode, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_init_register_for_coarse_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - gl843_set_motor_power (dev->calib_reg, SANE_FALSE); - - DBG (DBG_info, - "gl843_init_register_for_coarse_calibration: optical sensor res: %d dpi, actual res: %d\n", - dev->sensor.optical_res / cksel, dev->settings.xres); - - status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_init_register_for_coarse_calibration: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move - * */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl843_feed (Genesys_Device * dev, unsigned int steps) -{ - Genesys_Register_Set local_reg[GENESYS_GL843_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - float resolution; - uint8_t val; - - DBGSTART; - - /* prepare local registers */ - memcpy (local_reg, dev->reg, GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - resolution=sanei_genesys_get_lowest_ydpi(dev); - status = gl843_init_scan_regs (dev, - local_reg, - resolution, - resolution, - 0, - steps, - 100, - 3, - 8, - 3, - SCAN_MODE_COLOR, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_FEEDING | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_feed: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); - - /* set up for no scan */ - r = sanei_genesys_get_address (local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* send registers */ - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL843_MAX_REGS)); - - status = gl843_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); - gl843_stop_action (dev); - - /* restore original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL843_MAX_REGS); - return status; - } - - /* wait until feed count reaches the required value, but do not - * exceed 30s */ - do - { - status = sanei_genesys_get_status (dev, &val); - } - while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -/* shading calibration is done at dpihw */ -static SANE_Status -gl843_init_regs_for_shading (Genesys_Device * dev) -{ - SANE_Status status; - int move, resolution, dpihw, factor; - uint16_t strpixel; - - DBGSTART; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - dev->calib_channels = 3; - dev->calib_lines = dev->model->shading_lines; - dpihw=sanei_genesys_compute_dpihw(dev,dev->settings.xres); - factor=dev->sensor.optical_res/dpihw; - resolution=dpihw; - dev->calib_resolution = resolution; - dev->calib_pixels = dev->sensor.sensor_pixels/factor; - - /* distance to move to reach white target */ - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * resolution) / MM_PER_INCH; - - status = gl843_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - move, - dev->calib_pixels, - dev->calib_lines, - 16, - dev->calib_channels, - dev->settings.scan_mode, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_init_registers_for_shading: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - dev->scanhead_position_in_steps += dev->calib_lines + move; - sanei_genesys_get_double(dev->calib_reg,REG_STRPIXEL,&strpixel); - DBG (DBG_info, "%s: STRPIXEL=%d\n", __func__, strpixel); - - status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_init_registers_for_shading: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief set up registers for the actual scan - */ -static SANE_Status -gl843_init_regs_for_scan (Genesys_Device * dev) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status; - - DBG (DBG_info, - "gl843_init_regs_for_scan settings:\nResolution: %ux%uDPI\n" - "Lines : %u\npixels : %u\nStartpos : %.3f/%.3f\nScan mode : %d\n\n", - dev->settings.xres, - dev->settings.yres, - dev->settings.lines, - dev->settings.pixels, - dev->settings.tl_x, - dev->settings.tl_y, - dev->settings.scan_mode); - - /* ensure head is parked in case of calibration */ - gl843_slow_back_home (dev, SANE_TRUE); - - /* channels */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == SCAN_MODE_LINEART) - depth = 1; - - move_dpi = dev->motor.base_ydpi; - - move = SANE_UNFIX (dev->model->y_offset); - move += dev->settings.tl_y; - move = (move * move_dpi) / MM_PER_INCH; - DBG (DBG_info, "gl843_init_regs_for_scan: move=%f steps\n", move); - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - flags = 0; - - /* enable emulated lineart from gray data */ - if(dev->settings.scan_mode == SCAN_MODE_LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - status = gl843_init_scan_regs (dev, - dev->reg, - dev->settings.xres, - dev->settings.yres, - start, - move, - dev->settings.pixels, - dev->settings.lines, - depth, - channels, - dev->settings.scan_mode, - dev->settings.color_filter, - flags); - - if (status != SANE_STATUS_GOOD) - return status; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * This function sends gamma tables to ASIC - */ -static SANE_Status -gl843_send_gamma_table (Genesys_Device * dev) -{ - int size; - int status; - uint8_t *gamma; - int i; - - DBGSTART; - - size = 256; - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - gamma = (uint8_t *) malloc (size * 2 * 3); - if (!gamma) - return SANE_STATUS_NO_MEM; - - /* copy sensor specific's gamma tables */ - for (i = 0; i < size; i++) - { - gamma[i * 2 + size * 0 + 0] = dev->sensor.gamma_table[GENESYS_RED][i] & 0xff; - gamma[i * 2 + size * 0 + 1] = (dev->sensor.gamma_table[GENESYS_RED][i] >> 8) & 0xff; - gamma[i * 2 + size * 2 + 0] = dev->sensor.gamma_table[GENESYS_GREEN][i] & 0xff; - gamma[i * 2 + size * 2 + 1] = (dev->sensor.gamma_table[GENESYS_GREEN][i] >> 8) & 0xff; - gamma[i * 2 + size * 4 + 0] = dev->sensor.gamma_table[GENESYS_BLUE][i] & 0xff; - gamma[i * 2 + size * 4 + 1] = (dev->sensor.gamma_table[GENESYS_BLUE][i] >> 8) & 0xff; - } - - /* send address */ - status = gl843_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "gl843_send_gamma_table: failed to set buffer address: %s\n", - sane_strstatus (status)); - return status; - } - - /* send data */ - status = gl843_bulk_write_data (dev, 0x28, (uint8_t *) gamma, size * 2 * 3); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "gl843_send_gamma_table: failed to send gamma table: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "gl843_send_gamma_table: completed\n"); - free (gamma); - return SANE_STATUS_GOOD; -} - -/* this function does the led calibration by scanning one line of the calibration - area below scanner's top on white strip. - --needs working coarse/gain -*/ -static SANE_Status -gl843_led_calibration (Genesys_Device * dev) -{ - int num_pixels; - int total_size; - int used_res; - uint8_t *line; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels, depth; - int avg[3], avga, avge; - int turn; - char fn[20]; - uint16_t expr, expg, expb; - Genesys_Register_Set *r; - - SANE_Bool acceptable = SANE_FALSE; - - DBG (DBG_proc, "gl843_led_calibration\n"); - - /* offset calibration is always done in color mode */ - channels = 3; - depth = 16; - used_res = dev->sensor.optical_res; - num_pixels = - (dev->sensor.sensor_pixels * used_res) / dev->sensor.optical_res; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, - GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - status = gl843_init_scan_regs (dev, - dev->calib_reg, - used_res, - dev->motor.base_ydpi, - 0, - 0, - num_pixels, - 1, - depth, - channels, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_led_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - RIE (dev->model->cmd_set->bulk_write_register - (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS)); - - - total_size = num_pixels * channels * (depth / 8) * 1; /* colors * bytes_per_color * scan lines */ - - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - */ - - expr = (dev->sensor.regs_0x10_0x1d[0] << 8) | dev->sensor.regs_0x10_0x1d[1]; - expg = (dev->sensor.regs_0x10_0x1d[2] << 8) | dev->sensor.regs_0x10_0x1d[3]; - expb = (dev->sensor.regs_0x10_0x1d[4] << 8) | dev->sensor.regs_0x10_0x1d[5]; - - turn = 0; - - do - { - - dev->sensor.regs_0x10_0x1d[0] = (expr >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[1] = expr & 0xff; - dev->sensor.regs_0x10_0x1d[2] = (expg >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[3] = expg & 0xff; - dev->sensor.regs_0x10_0x1d[4] = (expb >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[5] = expb & 0xff; - - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (dev->calib_reg, 0x10 + i); - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - - RIE (dev->model->cmd_set->bulk_write_register - (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS)); - - DBG (DBG_info, "gl843_led_calibration: starting first line reading\n"); - RIE (gl843_begin_scan (dev, dev->calib_reg, SANE_TRUE)); - RIE (sanei_genesys_read_data_from_scanner (dev, line, total_size)); - - if (DBG_LEVEL >= DBG_data) - { - snprintf (fn, 20, "led_%02d.pnm", turn); - sanei_genesys_write_pnm_file (fn, - line, depth, channels, num_pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG (DBG_info, "gl843_led_calibration: average: " - "%d,%d,%d\n", avg[0], avg[1], avg[2]); - - acceptable = SANE_TRUE; - - if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || - avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || - avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) - acceptable = SANE_FALSE; - - if (!acceptable) - { - avga = (avg[0] + avg[1] + avg[2]) / 3; - expr = (expr * avga) / avg[0]; - expg = (expg * avga) / avg[1]; - expb = (expb * avga) / avg[2]; -/* - keep the resulting exposures below this value. - too long exposure drives the ccd into saturation. - we may fix this by relying on the fact that - we get a striped scan without shading, by means of - statistical calculation -*/ - avge = (expr + expg + expb) / 3; - - /* don't overflow max exposure */ - if (avge > 3000) - { - expr = (expr * 2000) / avge; - expg = (expg * 2000) / avge; - expb = (expb * 2000) / avge; - } - if (avge < 50) - { - expr = (expr * 50) / avge; - expg = (expg * 50) / avge; - expb = (expb * 50) / avge; - } - - } - - RIE (gl843_stop_action (dev)); - - turn++; - - } - while (!acceptable && turn < 100); - - DBG (DBG_info, "gl843_led_calibration: acceptable exposure: %d,%d,%d\n", - expr, expg, expb); - - /* cleanup before return */ - free (line); - - gl843_slow_back_home (dev, SANE_TRUE); - - DBG (DBG_proc, "gl843_led_calibration: completed\n"); - return status; -} - - - -/** - * average dark pixels of a 8 bits scan of a given channel - */ -static int -dark_average_channel (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black, int channel) -{ - unsigned int i, j, k, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average values on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j*channels + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG (DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); - } - DBG (DBG_info, "%s: average = %d\n", __func__, avg[channel]); - return avg[channel]; -} - -/** @brief calibrate AFE offset - * Iterate doing scans at target dpi until AFE offset if correct. One - * color line is scanned at a time. Scanning head doesn't move. - * @param dev device to calibrate - */ -static SANE_Status -gl843_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *first_line, *second_line; - unsigned int channels, bpp; - char title[32]; - int pass, total_size, i, resolution, lines; - int topavg[3], bottomavg[3], avg[3]; - int top[3], bottom[3], black_pixels, pixels, factor, dpihw; - - DBGSTART; - - /* offset calibration is always done in color mode */ - channels = 3; - lines = 8; - bpp = 8; - - /* compute divider factor to compute final pixels number */ - dpihw = sanei_genesys_compute_dpihw (dev, dev->settings.xres); - factor = dev->sensor.optical_res / dpihw; - resolution = dpihw; - pixels = dev->sensor.sensor_pixels / factor; - black_pixels = dev->sensor.black_pixels / factor; - DBG (DBG_io, "gl843_offset_calibration: dpihw =%d\n", dpihw); - DBG (DBG_io, "gl843_offset_calibration: factor =%d\n", factor); - DBG (DBG_io, "gl843_offset_calibration: resolution =%d\n", resolution); - DBG (DBG_io, "gl843_offset_calibration: pixels =%d\n", pixels); - DBG (DBG_io, "gl843_offset_calibration: black_pixels=%d\n", black_pixels); - - status = gl843_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - pixels, - lines, - bpp, - channels, - SCAN_MODE_COLOR, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl843_offset_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - gl843_set_motor_power (dev->calib_reg, SANE_FALSE); - - /* allocate memory for scans */ - total_size = pixels * channels * lines * (bpp / 8); /* colors * bytes_per_color * scan lines */ - - first_line = malloc (total_size); - if (!first_line) - return SANE_STATUS_NO_MEM; - - second_line = malloc (total_size); - if (!second_line) - { - free (first_line); - return SANE_STATUS_NO_MEM; - } - - /* init gain and offset */ - for (i = 0; i < 3; i++) - { - bottom[i] = 10; - dev->frontend.offset[i] = bottom[i]; - dev->frontend.gain[i] = 0; - } - RIEF2 (gl843_set_fe (dev, AFE_SET), first_line, second_line); - - /* scan with obttom AFE settings */ - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl843_offset_calibration: starting first line reading\n"); - RIEF2 (gl843_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, first_line, total_size), first_line, second_line); - if (DBG_LEVEL >= DBG_data) - { - for (i = 0; i < 3; i++) - { - snprintf (title, 20, "offset_%d_%03d.pnm", i, bottom[i]); - sanei_genesys_write_pnm_file (title, first_line, bpp, channels, pixels, lines); - } - } - - for (i = 0; i < 3; i++) - { - bottomavg[i] = dark_average_channel (first_line, pixels, lines, channels, black_pixels, i); - DBG (DBG_io2, "gl843_offset_calibration: bottom avg %d=%d\n", i, bottomavg[i]); - } - - /* now top value */ - for (i = 0; i < 3; i++) - { - top[i] = 255; - dev->frontend.offset[i] = top[i]; - } - RIEF2 (gl843_set_fe (dev, AFE_SET), first_line, second_line); - - /* scan with top AFE values */ - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl843_offset_calibration: starting second line reading\n"); - RIEF2 (gl843_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); - - for (i = 0; i < 3; i++) - { - topavg[i] = dark_average_channel (second_line, pixels, lines, channels, black_pixels, i); - DBG (DBG_io2, "gl843_offset_calibration: top avg %d=%d\n", i, topavg[i]); - } - - pass = 0; - - /* loop until acceptable level */ - while ((pass < 32) - && ((top[0] - bottom[0] > 1) - || (top[1] - bottom[1] > 1) || (top[2] - bottom[2] > 1))) - { - pass++; - - /* settings for new scan */ - for (i = 0; i < 3; i++) - { - if (top[i] - bottom[i] > 1) - { - dev->frontend.offset[i] = (top[i] + bottom[i]) / 2; - } - } - RIEF2 (gl843_set_fe (dev, AFE_SET), first_line, second_line); - - /* scan with no move */ - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl843_offset_calibration: starting second line reading\n"); - RIEF2 (gl843_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); - - if (DBG_LEVEL >= DBG_data) - { - for (i = 0; i < 3; i++) - { - sprintf (title, "offset_%d_%03d.pnm", i, dev->frontend.offset[i]); - sanei_genesys_write_pnm_file (title, second_line, bpp, channels, pixels, lines); - } - } - - for (i = 0; i < 3; i++) - { - avg[i] = dark_average_channel (second_line, pixels, lines, channels, black_pixels, i); - DBG (DBG_info, "gl843_offset_calibration: avg[%d]=%d offset=%d\n", i, avg[i], dev->frontend.offset[i]); - } - - /* compute new boundaries */ - for (i = 0; i < 3; i++) - { - if (topavg[i] >= avg[i]) - { - topavg[i] = avg[i]; - top[i] = dev->frontend.offset[i]; - } - else - { - bottomavg[i] = avg[i]; - bottom[i] = dev->frontend.offset[i]; - } - } - } - DBG (DBG_info, "gl843_offset_calibration: offset=(%d,%d,%d)\n", - dev->frontend.offset[0], - dev->frontend.offset[1], - dev->frontend.offset[2]); - - /* cleanup before return */ - free (first_line); - free (second_line); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* alternative coarse gain calibration - this on uses the settings from offset_calibration and - uses only one scanline - */ -/* - with offset and coarse calibration we only want to get our input range into - a reasonable shape. the fine calibration of the upper and lower bounds will - be done with shading. - */ -static SANE_Status -gl843_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - int pixels, factor, dpihw; - int total_size; - uint8_t *line; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3],coeff; - int val, code, lines; - int resolution; - int bpp; - - DBG (DBG_proc, "gl843_coarse_gain_calibration: dpi = %d\n", dpi); - dpihw=sanei_genesys_compute_dpihw(dev, dpi); - factor=dev->sensor.optical_res/dpihw; - - /* coarse gain calibration is always done in color mode */ - channels = 3; - - /* follow CKSEL */ - if (dev->model->ccd_type == CCD_KVSS080) - { - if(dev->settings.xressensor.optical_res) - { - coeff=0.9; - } - else - { - coeff=1.0; - } - } - else - { - coeff=1.0; - } - resolution=dpihw; - lines=10; - bpp=8; - pixels = dev->sensor.sensor_pixels / factor; - - status = gl843_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - pixels, - lines, - bpp, - channels, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - gl843_set_motor_power (dev->calib_reg, SANE_FALSE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_coarse_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - RIE (dev->model->cmd_set->bulk_write_register - (dev, dev->calib_reg, GENESYS_GL843_MAX_REGS)); - - total_size = pixels * channels * (16/bpp) * lines; - - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - - RIEF (gl843_set_fe(dev, AFE_SET), line); - RIEF (gl843_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, total_size), line); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("coarse.pnm", line, bpp, channels, pixels, lines); - - /* average value on each channel */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = pixels/4; i < (pixels*3/4); i++) - { - if(bpp==16) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * pixels + 1] * 256 + - line[i * 2 + j * 2 * pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - } - else - { - if (dev->model->is_cis) - val = line[i + j * pixels]; - else - val = line[i * channels + j]; - } - - max[j] += val; - } - max[j] = max[j] / (pixels/2); - - gain[j] = ((float) dev->sensor.gain_white_ref*coeff) / max[j]; - - /* turn logical gain value into gain code, checking for overflow */ - code = 283 - 208 / gain[j]; - if (code > 255) - code = 255; - else if (code < 0) - code = 0; - dev->frontend.gain[j] = code; - - DBG (DBG_proc, - "gl843_coarse_gain_calibration: channel %d, max=%d, gain = %f, setting:%d\n", - j, max[j], gain[j], dev->frontend.gain[j]); - } - - if (dev->model->is_cis) - { - if (dev->frontend.gain[0] > dev->frontend.gain[1]) - dev->frontend.gain[0] = dev->frontend.gain[1]; - if (dev->frontend.gain[0] > dev->frontend.gain[2]) - dev->frontend.gain[0] = dev->frontend.gain[2]; - dev->frontend.gain[2] = dev->frontend.gain[1] = dev->frontend.gain[0]; - } - - if (channels == 1) - { - dev->frontend.gain[0] = dev->frontend.gain[1]; - dev->frontend.gain[2] = dev->frontend.gain[1]; - } - - free (line); - - RIE (gl843_stop_action (dev)); - - status=gl843_slow_back_home (dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - -/* - * wait for lamp warmup by scanning the same line until difference - * between 2 scans is below a threshold - */ -static SANE_Status -gl843_init_regs_for_warmup (Genesys_Device * dev, - Genesys_Register_Set * reg, - int *channels, int *total_size) -{ - int num_pixels; - SANE_Status status = SANE_STATUS_GOOD; - int dpihw; - int resolution; - int factor; - - DBGSTART; - if (dev == NULL || reg == NULL || channels == NULL || total_size == NULL) - return SANE_STATUS_INVAL; - - /* setup scan */ - *channels=3; - resolution=600; - dpihw=sanei_genesys_compute_dpihw(dev, resolution); - factor=dev->sensor.optical_res/dpihw; - num_pixels=dev->sensor.sensor_pixels/(factor*2); - *total_size = num_pixels * 3 * 1; - - memcpy (reg, dev->reg, (GENESYS_GL843_MAX_REGS + 1) * sizeof (Genesys_Register_Set)); - status = gl843_init_scan_regs (dev, - reg, - resolution, - resolution, - num_pixels/2, - 0, - num_pixels, - 1, - 8, - *channels, - SCAN_MODE_COLOR, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - gl843_set_motor_power (reg, SANE_FALSE); - RIE (dev->model->cmd_set->bulk_write_register (dev, reg, GENESYS_GL843_MAX_REGS)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * set up GPIO/GPOE for idle state -WRITE GPIO[17-21]= GPIO19 -WRITE GPOE[17-21]= GPOE21 GPOE20 GPOE19 GPOE18 -genesys_write_register(0xa8,0x3e) -GPIO(0xa8)=0x3e - */ -static SANE_Status -gl843_init_gpio (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx; - - DBGSTART; - - RIE (sanei_genesys_write_register (dev, REG6E, dev->gpo.enable[0])); - RIE (sanei_genesys_write_register (dev, REG6F, dev->gpo.enable[1])); - RIE (sanei_genesys_write_register (dev, REG6C, dev->gpo.value[0])); - RIE (sanei_genesys_write_register (dev, REG6D, dev->gpo.value[1])); - - idx=0; - while(dev->model->gpo_type != gpios[idx].gpo_type && gpios[idx].gpo_type!=0) - { - idx++; - } - if (gpios[idx].gpo_type!=0) - { - RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); - RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); - RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); - RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); - } - else - { - status=SANE_STATUS_INVAL; - } - - DBGCOMPLETED; - return status; -} - - -/* * - * initialize ASIC from power on condition - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl843_boot (Genesys_Device * dev, SANE_Bool cold) -{ - SANE_Status status; - uint8_t val; - - DBGSTART; - - if(cold) - { - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - } - - if(dev->usb_mode == 1) - { - val = 0x14; - } - else - { - val = 0x11; - } - RIE (sanei_genesys_write_0x8c (dev, 0x0f, val)); - - /* test CHKVER */ - RIE (sanei_genesys_read_register (dev, REG40, &val)); - if (val & REG40_CHKVER) - { - RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG (DBG_info, - "%s: reported version for genesys chip is 0x%02x\n", __func__, - val); - } - - /* Set default values for registers */ - gl843_init_registers (dev); - - RIE (sanei_genesys_write_register (dev, REG6B, 0x02)); - - /* Write initial registers */ - RIE (dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL843_MAX_REGS)); - - /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ - val = dev->reg[reg_0x0b].value & REG0B_DRAMSEL; - val = (val | REG0B_ENBDRAM); - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg[reg_0x0b].value = val; - /* URB 14 control 0x40 0x0c 0x8c 0x10 len 1 wrote 0xb4 */ - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0xb4)); - - /* CLKSET */ - val = (dev->reg[reg_0x0b].value & ~REG0B_CLKSET) | REG0B_48MHZ; - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg[reg_0x0b].value = val; - - /* prevent further writings by bulk write register */ - dev->reg[reg_0x0b].address = 0x00; - - /* set up end access */ - sanei_genesys_write_register (dev, REGA7, 0x04); - sanei_genesys_write_register (dev, REGA9, 0x00); - - /* set RAM read address */ - RIE (sanei_genesys_write_register (dev, REG29, 0x00)); - RIE (sanei_genesys_write_register (dev, REG2A, 0x00)); - RIE (sanei_genesys_write_register (dev, REG2B, 0x00)); - - /* setup gpio */ - RIE (gl843_init_gpio (dev)); - - gl843_feed (dev, 300); - usleep (100000); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* * - * initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl843_init (Genesys_Device * dev) -{ - SANE_Status status; - - DBG_INIT (); - DBGSTART; - - status=sanei_genesys_asic_init(dev, GENESYS_GL843_MAX_REGS); - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl843_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not lose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); - - switch (s->dev->model->gpo_type) - { - case GPO_KVSS080: - if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) - s->val[OPT_SCAN_SW].b = (val & 0x04) == 0; - break; - case GPO_G4050: - if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) - s->val[OPT_SCAN_SW].b = (val & 0x01) == 0; - if (s->val[OPT_FILE_SW].b == s->last_val[OPT_FILE_SW].b) - s->val[OPT_FILE_SW].b = (val & 0x02) == 0; - if (s->val[OPT_EMAIL_SW].b == s->last_val[OPT_EMAIL_SW].b) - s->val[OPT_EMAIL_SW].b = (val & 0x04) == 0; - if (s->val[OPT_COPY_SW].b == s->last_val[OPT_COPY_SW].b) - s->val[OPT_COPY_SW].b = (val & 0x08) == 0; - break; - case GPO_CS4400F: - case GPO_CS8400F: - default: - break; - } - - return status; -} -#ifndef UNIT_TESTING -static -#endif -/** @brief move sensor to transparency adaptor - * Move sensor to the calibration of the transparency adapator (XPA). - * @param dev device to use - */ -SANE_Status gl843_move_to_ta (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - float resolution; - unsigned int feed; - - DBGSTART; - - resolution=sanei_genesys_get_lowest_ydpi(dev); - feed = 16*(SANE_UNFIX (dev->model->y_offset_calib_ta) * resolution) / MM_PER_INCH; - status = gl843_feed (dev, feed); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to move to XPA calibration area\n", __func__); - return status; - } - - DBGCOMPLETED; - return status; -} - - -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl843_search_strip (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black) -{ - unsigned int pixels, lines, channels; - SANE_Status status; - Genesys_Register_Set local_reg[GENESYS_GL843_MAX_REGS]; - size_t size; - uint8_t *data; - int steps, depth, dpi; - unsigned int pass, count, found, x, y; - char title[80]; - Genesys_Register_Set *r; - - DBG (DBG_proc, "gl843_search_strip %s %s\n", black ? "black" : "white", - forward ? "forward" : "reverse"); - - gl843_set_fe (dev, AFE_SET); - status = gl843_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_search_strip: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - - /* set up for a gray scan at lowest dpi */ - dpi = sanei_genesys_get_lowest_dpi(dev); - channels = 1; - - /* 10 MM */ - /* lines = (10 * dpi) / MM_PER_INCH; */ - /* shading calibation is done with dev->motor.base_ydpi */ - lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; - depth = 8; - pixels = (dev->sensor.sensor_pixels * dpi) / dev->sensor.optical_res; - size = pixels * channels * lines * (depth / 8); - data = malloc (size); - if (!data) - { - DBG (DBG_error, "gl843_search_strip: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - dev->scanhead_position_in_steps = 0; - - memcpy (local_reg, dev->reg, - GENESYS_GL843_MAX_REGS * sizeof (Genesys_Register_Set)); - - status = gl843_init_scan_regs (dev, - local_reg, - dpi, - dpi, - 0, - 0, - pixels, - lines, - depth, - channels, - SCAN_MODE_GRAY, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA); - if (status != SANE_STATUS_GOOD) - { - free(data); - DBG (DBG_error, - "gl843_search_strip: failed to setup for scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* set up for reverse or forward */ - r = sanei_genesys_get_address (local_reg, REG02); - if (forward) - r->value &= ~REG02_MTRREV; - else - r->value |= REG02_MTRREV; - - - status = dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL843_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - free(data); - DBG (DBG_error, - "gl843_search_strip: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl843_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl843_search_strip: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl843_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl843_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, "gl843_search_strip: gl843_stop_action failed\n"); - return status; - } - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file (title, data, depth, channels, pixels, - lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < 20 && !found) - { - status = - dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL843_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl843_search_strip: failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - /* now start scan */ - status = gl843_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl843_search_strip: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl843_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl843_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, "gl843_search_strip: gl843_stop_action failed\n"); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file (title, data, depth, channels, - pixels, lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG (DBG_data, - "gl843_search_strip: strip found forward during pass %d at line %d\n", - pass, y); - } - else - { - DBG (DBG_data, - "gl843_search_strip: pixels=%d, count=%d (%d%%)\n", - pixels, count, (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG (DBG_data, - "gl843_search_strip: strip found backward during pass %d \n", - pass); - } - else - { - DBG (DBG_data, - "gl843_search_strip: pixels=%d, count=%d (%d%%)\n", - pixels, count, (100 * count) / pixels); - } - } - pass++; - } - free (data); - if (found) - { - status = SANE_STATUS_GOOD; - DBG (DBG_info, "gl843_search_strip: %s strip found\n", - black ? "black" : "white"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG (DBG_info, "gl843_search_strip: %s strip not found\n", - black ? "black" : "white"); - } - - DBG (DBG_proc, "gl843_search_strip: completed\n"); - return status; -} - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl843_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) -{ - SANE_Status status; - uint32_t final_size, length, i; - uint8_t *final_data; - uint8_t *buffer; - int count,offset; - unsigned int tgtime; - unsigned int cksel; - Genesys_Register_Set *r; - uint16_t dpiset, strpixel, endpixel, startx, factor; - - DBGSTART; - - offset=0; - length=size; - r = sanei_genesys_get_address (dev->reg, REG01); - if(r->value & REG01_SHDAREA) - { - /* recompute STRPIXEL used shading calibration so we can - * compute offset within data for SHDAREA case */ - r = sanei_genesys_get_address (dev->reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - sanei_genesys_get_double(dev->reg,REG_DPISET,&strpixel); - tgtime=1; - sanei_genesys_get_double(dev->reg,REG_DPISET,&dpiset); - factor=dev->sensor.optical_res/sanei_genesys_compute_dpihw(dev,dpiset); - if (dev->model->ccd_type == CCD_G4050 && dpiset>2400) - { - tgtime=2; - } - - /* start coordinate in optical dpi coordinates */ - startx = ((dev->sensor.dummy_pixel * tgtime)/cksel)/factor; - - /* current scan coordinates */ - sanei_genesys_get_double(dev->reg,REG_STRPIXEL,&strpixel); - sanei_genesys_get_double(dev->reg,REG_ENDPIXEL,&endpixel); - strpixel*=tgtime; - endpixel*=tgtime; - - /* 16 bit words, 2 words per color, 3 color channels */ - offset=(strpixel-startx)*2*2*3; - length=(endpixel-strpixel)*2*2*3; - DBG (DBG_info, "%s: STRPIXEL=%d, ENDPIXEL=%d, startx=%d\n", __func__, strpixel, endpixel, startx); - } - - /* compute and allocate size for final data */ - final_size = ((length+251) / 252) * 256; - DBG (DBG_io, "%s: final shading size=%04x (length=%d)\n", __func__, final_size, length); - final_data = (uint8_t *) malloc (final_size); - if(final_data==NULL) - { - DBG (DBG_error, "%s: failed to allocate memory for shading data\n", __func__); - return SANE_STATUS_NO_MEM; - } - memset(final_data,0x00,final_size); - - /* copy regular shading data to the expected layout */ - buffer = final_data; - count = 0; - - /* loop over calibration data */ - for (i = 0; i < length; i++) - { - buffer[count] = data[offset+i]; - count++; - if ((count % (256*2)) == (252*2)) - { - count += 4*2; - } - } - - /* send data */ - status = sanei_genesys_set_buffer_address (dev, 0); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus (status)); - free(final_data); - return status; - } - - status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, final_data, count); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send shading table: %s\n", __func__, sane_strstatus (status)); - } - - free(final_data); - DBGCOMPLETED; - return status; -} - - -/** the gl843 command set */ -static Genesys_Command_Set gl843_cmd_set = { - "gl843-generic", /* the name of this set */ - - gl843_init, - gl843_init_regs_for_warmup, - gl843_init_regs_for_coarse_calibration, - gl843_init_regs_for_shading, - gl843_init_regs_for_scan, - - gl843_get_filter_bit, - gl843_get_lineart_bit, - gl843_get_bitset_bit, - gl843_get_gain4_bit, - gl843_get_fast_feed_bit, - gl843_test_buffer_empty_bit, - gl843_test_motor_flag_bit, - - gl843_bulk_full_size, - - gl843_set_fe, - gl843_set_powersaving, - gl843_save_power, - - gl843_set_motor_power, - gl843_set_lamp_power, - - gl843_begin_scan, - gl843_end_scan, - - gl843_send_gamma_table, - - gl843_search_start_position, - - gl843_offset_calibration, - gl843_coarse_gain_calibration, - gl843_led_calibration, - - gl843_slow_back_home, - NULL, - - sanei_genesys_bulk_write_register, - gl843_bulk_write_data, - gl843_bulk_read_data, - - gl843_update_hardware_sensors, - - gl843_load_document, - gl843_detect_document_end, - gl843_eject_document, - gl843_search_strip, - - sanei_genesys_is_compatible_calibration, - gl843_move_to_ta, - gl843_send_shading_data, - gl843_calculate_current_setup, - gl843_boot, - NULL -}; - -SANE_Status -sanei_gl843_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl843_cmd_set; - return SANE_STATUS_GOOD; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl843.cc b/backend/genesys_gl843.cc new file mode 100644 index 0000000..a72dc5a --- /dev/null +++ b/backend/genesys_gl843.cc @@ -0,0 +1,4415 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_gl843.h" + +#include +#include + +/**************************************************************************** + Low level function + ****************************************************************************/ + +/* ------------------------------------------------------------------------ */ +/* Read and write RAM, registers and AFE */ +/* ------------------------------------------------------------------------ */ + +/* Set address for writing data */ +static SANE_Status +gl843_set_buffer_address (Genesys_Device * dev, uint32_t addr) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xffff); + + status = sanei_genesys_write_register (dev, 0x5b, ((addr >> 8) & 0xff)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while writing high byte: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = sanei_genesys_write_register (dev, 0x5c, (addr & 0xff)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while writing low byte: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_io, "%s: completed\n", __func__); + + return status; +} + +/** + * writes a block of data to RAM + * @param dev USB device + * @param addr RAM address to write to + * @param size size of the chunk of data + * @param data pointer to the data to write + */ +static SANE_Status +write_data (Genesys_Device * dev, uint32_t addr, uint32_t size, + uint8_t * data) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + status = gl843_set_buffer_address (dev, addr); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while setting address for bulk write data: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* write actual data */ + status = sanei_genesys_bulk_write_data(dev, 0x28, data, size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while writing bulk write data: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* set back address to 0 */ + status = gl843_set_buffer_address (dev, 0); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed setting to default RAM address: %s\n", __func__, + sane_strstatus(status)); + return status; + } + DBGCOMPLETED; + return status; +} + +/**************************************************************************** + Mid level functions + ****************************************************************************/ + +static SANE_Bool +gl843_get_fast_feed_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG02); + if (r && (r->value & REG02_FASTFED)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl843_get_filter_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_FILTER)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl843_get_lineart_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_LINEART)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl843_get_bitset_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_BITSET)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl843_get_gain4_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG06); + if (r && (r->value & REG06_GAIN4)) + return SANE_TRUE; + return SANE_FALSE; +} + +/** + * compute the step multiplier used + */ +static int +gl843_get_step_multiplier (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + int value = 1; + + r = sanei_genesys_get_address (regs, REG9D); + if (r != NULL) + { + switch (r->value & 0x0c) + { + case 0x04: + value = 2; + break; + case 0x08: + value = 4; + break; + default: + value = 1; + } + } + DBG(DBG_io, "%s: step multiplier is %d\n", __func__, value); + return value; +} + +static SANE_Bool +gl843_test_buffer_empty_bit (SANE_Byte val) +{ + if (val & REG41_BUFEMPTY) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl843_test_motor_flag_bit (SANE_Byte val) +{ + if (val & REG41_MOTORENB) + return SANE_TRUE; + return SANE_FALSE; +} + +/** copy sensor specific settings */ +static void +gl843_setup_sensor (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * regs, int dpi,int flags) +{ + (void) dpi; + (void) flags; + + DBGSTART; + + for (const auto& custom_reg : sensor.custom_regs) { + regs->set8(custom_reg.address, custom_reg.value); + } + if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE)) { + regs->set8(0x7d, 0x90); + } + + DBGCOMPLETED; +} + + +/** @brief set all registers to default values . + * This function is called only once at the beginning and + * fills register startup values for registers reused across scans. + * Those that are rarely modified or not modified are written + * individually. + * @param dev device structure holding register set to initialize + */ +static void +gl843_init_registers (Genesys_Device * dev) +{ + // Within this function SENSOR_DEF marker documents that a register is part + // of the sensors definition and the actual value is set in + // gl843_setup_sensor(). + + DBGSTART; + + dev->reg.clear(); + + /* default to KV-SS080 */ + SETREG (0xa2, 0x0f); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0xa2, 0x1f); + } + SETREG (0x01, 0x00); + SETREG (0x02, 0x78); + SETREG (0x03, 0x1f); + SETREG (0x04, 0x10); + + // fine tune upon device description + SETREG (0x05, 0x80); + if (dev->model->model_id == MODEL_HP_SCANJET_G4010 || + dev->model->model_id == MODEL_HP_SCANJET_G4050 || + dev->model->model_id == MODEL_HP_SCANJET_4850C) + { + SETREG (0x05, 0x08); + } + + dev->reg.find_reg(0x05).value &= ~REG05_DPIHW; + switch (sanei_genesys_find_sensor_any(dev).optical_res) + { + case 600: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; + break; + case 1200: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; + break; + case 2400: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; + break; + case 4800: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_4800; + break; + } + + // TODO: on 8600F the windows driver turns off GAIN4 which is recommended + SETREG (0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ + SETREG (0x08, 0x00); + SETREG (0x09, 0x00); + SETREG (0x0a, 0x00); + + // This register controls clock and RAM settings and is further modified in + // gl843_boot + SETREG (0x0b, 0x6a); + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x0b, 0x89); + } + + // EXPR[0:15], EXPG[0:15], EXPB[0:15]: Exposure time settings. + SETREG(0x10, 0x00); // SENSOR_DEF + SETREG(0x11, 0x00); // SENSOR_DEF + SETREG(0x12, 0x00); // SENSOR_DEF + SETREG(0x13, 0x00); // SENSOR_DEF + SETREG(0x14, 0x00); // SENSOR_DEF + SETREG(0x15, 0x00); // SENSOR_DEF + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + dev->reg.set16(REG_EXPR, 0x9c40); + dev->reg.set16(REG_EXPG, 0x9c40); + dev->reg.set16(REG_EXPB, 0x9c40); + } + // CCD signal settings. + SETREG(0x16, 0x33); // SENSOR_DEF + SETREG(0x17, 0x1c); // SENSOR_DEF + SETREG(0x18, 0x10); // SENSOR_DEF + + // EXPDMY[0:7]: Exposure time of dummy lines. + SETREG(0x19, 0x2a); // SENSOR_DEF + + // Various CCD clock settings. + SETREG(0x1a, 0x04); // SENSOR_DEF + SETREG(0x1b, 0x00); // SENSOR_DEF + SETREG(0x1c, 0x20); // SENSOR_DEF + SETREG(0x1d, 0x04); // SENSOR_DEF + + SETREG (0x1e, 0x10); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x1e, 0x20); + } + + SETREG (0x1f, 0x01); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x1f, 0xff); + } + + SETREG (0x20, 0x10); + SETREG (0x21, 0x04); + SETREG (0x22, 0x01); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x22, 0xc8); + } + + SETREG (0x23, 0x01); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x23, 0xc8); + } + + SETREG (0x24, 0x04); + SETREG (0x25, 0x00); + SETREG (0x26, 0x00); + SETREG (0x27, 0x00); + SETREG (0x2c, 0x02); + SETREG (0x2d, 0x58); + // BWHI[0:7]: high level of black and white threshold + SETREG (0x2e, 0x80); + // BWLOW[0:7]: low level of black and white threshold + SETREG (0x2f, 0x80); + SETREG (0x30, 0x00); + SETREG (0x31, 0x14); + SETREG (0x32, 0x27); + SETREG (0x33, 0xec); + + // DUMMY: CCD dummy and optically black pixel count + SETREG (0x34, 0x24); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x34, 0x14); + } + + // MAXWD: If available buffer size is less than 2*MAXWD words, then + // "buffer full" state will be set. + SETREG (0x35, 0x00); + SETREG (0x36, 0xff); + SETREG (0x37, 0xff); + + // LPERIOD: Line period or exposure time for CCD or CIS. + SETREG(0x38, 0x55); // SENSOR_DEF + SETREG(0x39, 0xf0); // SENSOR_DEF + + // FEEDL[0:24]: The number of steps of motor movement. + SETREG(0x3d, 0x00); + SETREG (0x3e, 0x00); + SETREG (0x3f, 0x01); + + // Latch points for high and low bytes of R, G and B channels of AFE. If + // multiple clocks per pixel are consumed, then the setting defines during + // which clock the corresponding value will be read. + // RHI[0:4]: The latch point for high byte of R channel. + // RLOW[0:4]: The latch point for low byte of R channel. + // GHI[0:4]: The latch point for high byte of G channel. + // GLOW[0:4]: The latch point for low byte of G channel. + // BHI[0:4]: The latch point for high byte of B channel. + // BLOW[0:4]: The latch point for low byte of B channel. + SETREG(0x52, 0x01); // SENSOR_DEF + SETREG(0x53, 0x04); // SENSOR_DEF + SETREG(0x54, 0x07); // SENSOR_DEF + SETREG(0x55, 0x0a); // SENSOR_DEF + SETREG(0x56, 0x0d); // SENSOR_DEF + SETREG(0x57, 0x10); // SENSOR_DEF + + // VSMP[0:4]: The position of the image sampling pulse for AFE in cycles. + // VSMPW[0:2]: The length of the image sampling pulse for AFE in cycles. + SETREG(0x58, 0x1b); // SENSOR_DEF + + SETREG(0x59, 0x00); // SENSOR_DEF + SETREG(0x5a, 0x40); // SENSOR_DEF + + // 0x5b-0x5c: GMMADDR[0:15] address for gamma or motor tables download + // SENSOR_DEF + + // DECSEL[0:2]: The number of deceleratino steps after touching home sensor + // STOPTIM[0:4]: The stop duration between change of directions in + // backtracking + SETREG (0x5e, 0x23); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x5e, 0x1f); + } + + // FMOVDEC: The number of deceleration steps in table 5 for auto-go-home + SETREG (0x5f, 0x01); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x5f, 0xf0); + } + + // Z1MOD[0:20] + SETREG (0x60, 0x00); + SETREG (0x61, 0x00); + SETREG (0x62, 0x00); + + // Z2MOD[0:20] + SETREG (0x63, 0x00); + SETREG (0x64, 0x00); + SETREG (0x65, 0x00); + + // STEPSEL[0:1]. Motor movement step mode selection for tables 1-3 in + // scanning mode. + // MTRPWM[0:5]. Motor phase PWM duty cycle setting for tables 1-3 + SETREG (0x67, 0x7f); + // FSTPSEL[0:1]: Motor movement step mode selection for tables 4-5 in + // command mode. + // FASTPWM[5:0]: Motor phase PWM duty cycle setting for tables 4-5 + SETREG (0x68, 0x7f); + + // FSHDEC[0:7]: The number of deceleration steps after scanning is finished + // (table 3) + SETREG (0x69, 0x01); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x69, 64); + } + + // FMOVNO[0:7] The number of acceleration or deceleration steps for fast + // moving (table 4) + SETREG (0x6a, 0x04); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x69, 64); + } + + // GPIO-related register bits + SETREG (0x6b, 0x30); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x6b, 0x72); + } + + // 0x6c, 0x6d, 0x6e, 0x6f are set according to gpio tables. See + // gl843_init_gpio. + + // RSH[0:4]: The position of rising edge of CCD RS signal in cycles + // RSL[0:4]: The position of falling edge of CCD RS signal in cycles + // CPH[0:4]: The position of rising edge of CCD CP signal in cycles. + // CPL[0:4]: The position of falling edge of CCD CP signal in cycles + SETREG(0x70, 0x01); // SENSOR_DEF + SETREG(0x71, 0x03); // SENSOR_DEF + SETREG (0x72, 0x04); + SETREG (0x73, 0x05); + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x70, 0x00); + SETREG(0x71, 0x02); + SETREG(0x72, 0x02); + SETREG(0x73, 0x04); + } + + // CK1MAP[0:17], CK3MAP[0:17], CK4MAP[0:17]: CCD clock bit mapping setting. + SETREG(0x74, 0x00); // SENSOR_DEF + SETREG(0x75, 0x00); // SENSOR_DEF + SETREG(0x76, 0x3c); // SENSOR_DEF + SETREG(0x77, 0x00); // SENSOR_DEF + SETREG(0x78, 0x00); // SENSOR_DEF + SETREG(0x79, 0x9f); // SENSOR_DEF + SETREG(0x7a, 0x00); // SENSOR_DEF + SETREG(0x7b, 0x00); // SENSOR_DEF + SETREG(0x7c, 0x55); // SENSOR_DEF + + // various AFE settings + SETREG(0x7d, 0x00); + + // GPOLED[x]: LED vs GPIO settings + SETREG(0x7e, 0x00); + + // BSMPDLY, VSMPDLY + // LEDCNT[0:1]: Controls led blinking and its period + SETREG (0x7f, 0x00); + + // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for + // moving in various situations. + SETREG (0x80, 0x00); + + if (dev->model->model_id != MODEL_CANON_CANOSCAN_4400F) + { + // NOTE: Historical code. None of the following 6 registers are + // documented in the datasheet. Their default value is 0, so probably it's + // not a bad idea to leave this here. + SETREG (0x81, 0x00); + SETREG (0x82, 0x00); + SETREG (0x83, 0x00); + SETREG (0x84, 0x00); + SETREG (0x85, 0x00); + SETREG (0x86, 0x00); + } + + SETREG (0x87, 0x00); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x87, 0x02); + } + + // MTRPLS[0:7]: The width of the ADF motor trigger signal pulse. + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x94, 0xff); + } + + // 0x95-0x97: SCANLEN[0:19]: Controls when paper jam bit is set in sheetfed + // scanners. + + // ONDUR[0:15]: The duration of PWM ON phase for LAMP control + // OFFDUR[0:15]: The duration of PWM OFF phase for LAMP control + // both of the above are in system clocks + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x98, 0x00); + SETREG(0x99, 0x00); + SETREG(0x9a, 0x00); + SETREG(0x9b, 0x00); + } + + // RMADLY[0:1], MOTLAG, CMODE, STEPTIM, MULDMYLN, IFRS + SETREG(0x9d, 0x04); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0x9d, 0x08); // additionally sets the multiplier for slope tables + } + + + // SEL3INV, TGSTIME[0:2], TGWTIME[0:2] + SETREG (0x9e, 0x00); // SENSOR_DEF + + // RFHSET[0:4]: Refresh time of SDRAM in units of 2us + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0xa2, 0x1f); + } + + // 0xa6-0xa9: controls gpio, see gl843_gpio_init + + // GPOM9, MULSTOP[0-2], NODECEL, TB3TB1, TB5TB2, FIX16CLK. + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0xab, 0x00); + } + + // VRHOME[3:2], VRMOVE[3:2], VRBACK[3:2]: Vref setting of the motor driver IC + // for various situations. + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + SETREG(0xac, 0x00); + } + + if (dev->model->model_id != MODEL_CANON_CANOSCAN_8400F) + { + SETREG (0x0c, 0x00); + SETREG (0x94, 0xff); + SETREG (0xab, 0x50); + } + + if (dev->model->model_id != MODEL_CANON_CANOSCAN_4400F + && dev->model->model_id != MODEL_CANON_CANOSCAN_8400F) + { + SETREG (0xaa, 0x00); + } + + /* G4050 values */ + if (dev->model->model_id == MODEL_HP_SCANJET_G4010 || + dev->model->model_id == MODEL_HP_SCANJET_G4050 || + dev->model->model_id == MODEL_HP_SCANJET_4850C) + { + SETREG (0x03, 0x1d); + SETREG (0x06, 0xd0); /* SCANMOD=110, PWRBIT and no GAIN4 */ + SETREG (0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ + SETREG (0x0a, 0x18); + SETREG (0x0b, 0x69); + + /* CIS exposure is used for XPA lamp movement */ + SETREG (0x10, 0x2c); + SETREG (0x11, 0x09); + SETREG (0x12, 0x22); + SETREG (0x13, 0xb8); + SETREG (0x14, 0x10); + SETREG (0x15, 0xf0); + + SETREG (0x6b, 0xf4); + + SETREG (0x70, 0x00); + SETREG (0x71, 0x02); + SETREG (0x72, 0x00); + SETREG (0x73, 0x00); + + SETREG (0x80, 0x50); + SETREG (0x9d, 0x08); + SETREG (0xab, 0x40); + + /* XXX STEF XXX TODO move to set for scan */ + SETREG (0x98, 0x03); + SETREG (0x99, 0x30); + SETREG (0x9a, 0x01); + SETREG (0x9b, 0x80); + SETREG (0xac, 0x00); + } + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_4400F) + { + SETREG (0x06, 0xf0); /* SCANMOD=111, PWRBIT and no GAIN4 */ + SETREG (0x0b, 0x69); /* 16M only */ + SETREG (0x1e, 0x20); + SETREG (0x22, 0xc8); + SETREG (0x23, 0xc8); + SETREG (0x5e, 0x3f); + SETREG (0x5f, 0xf0); + SETREG (0x6b, 0x72); + SETREG (0x72, 0x01); + SETREG (0x73, 0x03); + SETREG (0x80, 0x0c); + SETREG (0x87, 0x02); /* MCLOCK -> CK4MAP */ + SETREG (0x9d, 0x08); /* STEPTIM=2 */ + SETREG (0xa2, 0x1f); + SETREG (0xab, 0x00); + sanei_genesys_set_double(&dev->reg,REG_EXPR,0x9c40); + sanei_genesys_set_double(&dev->reg,REG_EXPG,0x9c40); + sanei_genesys_set_double(&dev->reg,REG_EXPB,0x9c40); + } + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8400F) + { + SETREG (0x03, 0x1c); + SETREG (0x06, 0xd0); /* SCANMOD=110, PWRBIT and no GAIN4 */ + SETREG (0x0a, 0x10); + SETREG (0x22, 0x50); + SETREG (0x23, 0x50); + SETREG (0x5e, 0x85); + SETREG (0x6b, 0xb1); + SETREG (0x1e, 0xa0); + SETREG (0x72, 0x03); + SETREG (0x73, 0x04); + SETREG (0x7d, 0x20); + SETREG (0x80, 0x28); + SETREG (0x87, 0x02); /* MCLOCK -> CK4MAP */ + SETREG (0x9d, 0x08); /* STEPTIM=2 */ + } + + dev->calib_reg = dev->reg; + + DBGCOMPLETED; +} + +/* Send slope table for motor movement + slope_table in machine byte order + */ +static SANE_Status +gl843_send_slope_table (Genesys_Device * dev, int table_nr, + uint16_t * slope_table, int steps) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + char msg[10000]; + + DBG(DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, table_nr, steps); + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + sprintf (msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) + { + sprintf (msg+strlen(msg), "%d", slope_table[i]); + } + DBG(DBG_io, "%s: %s\n", __func__, msg); + } + + + /* slope table addresses are fixed : 0x4000, 0x4800, 0x5000, 0x5800, 0x6000 */ + /* XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14); */ + status = write_data (dev, 0x4000 + 0x800 * table_nr, steps * 2, table.data()); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: write data failed writing slope table %d (%s)\n", __func__, table_nr, + sane_strstatus(status)); + } + + DBGCOMPLETED; + return status; +} + + +/* Set values of analog frontend */ +static SANE_Status +gl843_set_fe (Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) +{ + (void) sensor; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + int i; + + DBG(DBG_proc, "%s (%s)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == + AFE_POWER_SAVE ? "powersave" : "huh?"); + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + dev->frontend = dev->frontend_initial; + } + + /* check analog frontend type */ + // FIXME: looks like we write to that register with initial data + RIE (sanei_genesys_read_register (dev, REG04, &val)); + if ((val & REG04_FESET) != 0x00) + { + /* for now there is no support for AD fe */ + DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, + dev->reg.find_reg(0x04).value & REG04_FESET); + return SANE_STATUS_UNSUPPORTED; + } + + DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); + + for (i = 1; i <= 3; i++) + { + // FIXME: BUG: we should initialize dev->frontend before first use. Right now it's + // initialized during genesys_coarse_calibration() + if (dev->frontend.regs.empty()) { + status = sanei_genesys_fe_write_data(dev, i, 0x00); + } else { + status = sanei_genesys_fe_write_data(dev, i, dev->frontend.regs.get_value(0x00 + i)); + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing reg[%d] failed: %s\n", __func__, i, sane_strstatus(status)); + return status; + } + } + for (const auto& reg : sensor.custom_fe_regs) { + status = sanei_genesys_fe_write_data(dev, reg.address, reg.value); + if (status != SANE_STATUS_GOOD) { + DBG(DBG_error, "%s: writing reg[%d] failed: %s\n", __func__, i, sane_strstatus(status)); + return status; + } + } + + for (i = 0; i < 3; i++) + { + // FIXME: BUG: see above + if (dev->frontend.regs.empty()) { + status = sanei_genesys_fe_write_data(dev, 0x20 + i, 0x00); + } else { + status = sanei_genesys_fe_write_data(dev, 0x20 + i, dev->frontend.get_offset(i)); + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing offset[%d] failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + + if (dev->model->ccd_type == CCD_KVSS080) + { + for (i = 0; i < 3; i++) + { + // FIXME: BUG: see above + if (dev->frontend.regs.empty()) { + status = sanei_genesys_fe_write_data(dev, 0x24 + i, 0x00); + } else { + status = sanei_genesys_fe_write_data(dev, 0x24 + i, + dev->frontend.regs.get_value(0x24 + i)); + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + } + + for (i = 0; i < 3; i++) + { + // FIXME: BUG: see above + if (dev->frontend.regs.empty()) { + status = sanei_genesys_fe_write_data(dev, 0x28 + i, 0x00); + } else { + status = sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i)); + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: writing gain[%d] failed: %s\n", __func__, i, sane_strstatus(status)); + return status; + } + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +static SANE_Status +gl843_init_motor_regs_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int exposure, + float scan_yres, + int scan_step_type, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + int scan_power_mode, + unsigned int flags) +{ + SANE_Status status = SANE_STATUS_GOOD; + int use_fast_fed, coeff; + unsigned int lincnt; + uint16_t scan_table[1024]; + uint16_t fast_table[1024]; + int scan_steps,fast_steps, fast_step_type; + unsigned int feedl,factor,dist; + GenesysRegister *r; + uint32_t z1, z2; + + DBGSTART; + DBG(DBG_info, "%s : exposure=%d, scan_yres=%g, scan_step_type=%d, scan_lines=%d, scan_dummy=%d, " + "feed_steps=%d, scan_power_mode=%d, flags=%x\n", __func__, exposure, scan_yres, + scan_step_type, scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); + + /* get step multiplier */ + factor = gl843_get_step_multiplier (reg); + + use_fast_fed = 0; + + if((scan_yres>=300 && feed_steps>900) || (flags & MOTOR_FLAG_FEED)) + use_fast_fed=1; + + lincnt=scan_lines; + sanei_genesys_set_triple(reg,REG_LINCNT,lincnt); + DBG(DBG_io, "%s: lincnt=%d\n", __func__, lincnt); + + /* compute register 02 value */ + r = sanei_genesys_get_address (reg, REG02); + r->value = 0x00; + sanei_genesys_set_motor_power(*reg, true); + + if (use_fast_fed) + r->value |= REG02_FASTFED; + else + r->value &= ~REG02_FASTFED; + + /* in case of automatic go home, move until home sensor */ + if (flags & MOTOR_FLAG_AUTO_GO_HOME) + r->value |= REG02_AGOHOME | REG02_NOTHOME; + + /* disable backtracking */ + if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) + ||(scan_yres>=2400) + ||(scan_yres>=sensor.optical_res)) + r->value |= REG02_ACDCDIS; + + /* scan and backtracking slope table */ + sanei_genesys_slope_table(scan_table, + &scan_steps, + scan_yres, + exposure, + dev->motor.base_ydpi, + scan_step_type, + factor, + dev->model->motor_type, + gl843_motors); + RIE(gl843_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); + RIE(gl843_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); + + /* STEPNO */ + r = sanei_genesys_get_address (reg, REG_STEPNO); + r->value = scan_steps; + + /* FSHDEC */ + r = sanei_genesys_get_address (reg, REG_FSHDEC); + r->value = scan_steps; + + /* fast table */ + fast_step_type=0; + if(scan_step_type<=fast_step_type) + { + fast_step_type=scan_step_type; + } + sanei_genesys_slope_table(fast_table, + &fast_steps, + sanei_genesys_get_lowest_ydpi(dev), + exposure, + dev->motor.base_ydpi, + fast_step_type, + factor, + dev->model->motor_type, + gl843_motors); + RIE(gl843_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); + RIE(gl843_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); + RIE(gl843_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); + + /* FASTNO */ + r = sanei_genesys_get_address (reg, REG_FASTNO); + r->value = fast_steps; + + /* FMOVNO */ + r = sanei_genesys_get_address (reg, REG_FMOVNO); + r->value = fast_steps; + + /* substract acceleration distance from feedl */ + feedl=feed_steps; + feedl<<=scan_step_type; + + dist = scan_steps; + if (use_fast_fed) + { + dist += fast_steps*2; + } + DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + /* get sure when don't insane value : XXX STEF XXX in this case we should + * fall back to single table move */ + if(dist600) + { + z1=0; + z2=0; + } + + sanei_genesys_set_triple(reg,REG_Z1MOD,z1); + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + + sanei_genesys_set_triple(reg,REG_Z2MOD,z2); + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + + r = sanei_genesys_get_address (reg, REG1E); + r->value &= 0xf0; /* 0 dummy lines */ + r->value |= scan_dummy; /* dummy lines */ + + r = sanei_genesys_get_address (reg, REG67); + r->value = 0x3f | (scan_step_type << REG67S_STEPSEL); + + r = sanei_genesys_get_address (reg, REG68); + r->value = 0x3f | (scan_step_type << REG68S_FSTPSEL); + + /* steps for STOP table */ + r = sanei_genesys_get_address (reg, REG_FMOVDEC); + r->value = fast_steps; + + /* Vref XXX STEF XXX : optical divider or step type ? */ + r = sanei_genesys_get_address (reg, 0x80); + if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE)) + { + r->value = 0x50; + coeff=sensor.optical_res/sanei_genesys_compute_dpihw(dev, sensor, scan_yres); + if (dev->model->motor_type == MOTOR_KVSS080) + { + if(coeff>=1) + { + r->value |= 0x05; + } + } + else { + switch(coeff) + { + case 4: + r->value |= 0x0a; + break; + case 2: + r->value |= 0x0f; + break; + case 1: + r->value |= 0x0f; + break; + } + } + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** @brief setup optical related registers + * start and pixels are expressed in optical sensor resolution coordinate + * space. + * @param dev device to use + * @param reg registers to set up + * @param exposure exposure time to use + * @param used_res scanning resolution used, may differ from + * scan's one + * @param start logical start pixel coordinate + * @param pixels logical number of pixels to use + * @param channels number of color channles used (1 or 3) + * @param depth bit depth of the scan (1, 8 or 16 bits) + * @param ccd_size_divisor SANE_TRUE specifies how much x coordinates must be shrunk + * @param color_filter to choose the color channel used in gray scans + * @param flags to drive specific settings such no calibration, XPA use ... + * @return SANE_STATUS_GOOD if OK + */ +static SANE_Status +gl843_init_optical_regs_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int exposure, + int used_res, + unsigned int start, + unsigned int pixels, + int channels, + int depth, + unsigned ccd_size_divisor, + ColorFilter color_filter, + int flags) +{ + unsigned int words_per_line; + unsigned int startx, endx, used_pixels; + unsigned int dpiset, dpihw, factor; + unsigned int bytes; + unsigned int tgtime; /**> exposure time multiplier */ + unsigned int cksel; /**> clock per system pixel time in capturing image */ + GenesysRegister *r; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s : exposure=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " + "ccd_size_divisor=%d, flags=%x\n", __func__, exposure, used_res, start, pixels, channels, + depth, ccd_size_divisor, flags); + + /* tgtime */ + tgtime = exposure / 65536 + 1; + DBG(DBG_io2, "%s: tgtime=%d\n", __func__, tgtime); + + /* to manage high resolution device while keeping good + * low resolution scanning speed, we make hardware dpi vary */ + dpihw=sanei_genesys_compute_dpihw(dev, sensor, used_res); + factor=sensor.optical_res/dpihw; + DBG(DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); + + /* sensor parameters */ + gl843_setup_sensor (dev, sensor, reg, dpihw, flags); + + /* resolution is divided according to CKSEL which is known once sensor is set up */ + r = sanei_genesys_get_address (reg, REG18); + cksel= (r->value & REG18_CKSEL)+1; + DBG(DBG_io2, "%s: cksel=%d\n", __func__, cksel); + dpiset = used_res * cksel; + + /* start and end coordinate in optical dpi coordinates */ + startx = (start + sensor.dummy_pixel)/cksel; + + used_pixels=pixels/cksel; + endx = startx + used_pixels; + + /* pixel coordinate factor correction when used dpihw is not maximal one */ + startx/=factor; + endx/=factor; + used_pixels=endx-startx; + + /* in case of stagger we have to start at an odd coordinate */ + if ((flags & OPTICAL_FLAG_STAGGER) + &&((startx & 1)==0)) + { + startx++; + endx++; + } + + status = gl843_set_fe(dev, sensor, AFE_SET); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* enable shading */ + r = sanei_genesys_get_address (reg, REG01); + r->value &= ~REG01_SCAN; + if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + r->value &= ~REG01_DVDSET; + } + else + { + r->value |= REG01_DVDSET; + } + if(dpihw>600) + { + r->value |= REG01_SHDAREA; + } + else + { + r->value &= ~REG01_SHDAREA; + } + + r = sanei_genesys_get_address (reg, REG03); + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + r->value |= REG03_AVEENB; + else { + r->value &= ~REG03_AVEENB; + } + + // FIXME: we probably don't need to set exposure to registers at this point. It was this way + // before a refactor. + sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); + + /* select XPA */ + r->value &= ~REG03_XPASEL; + if (flags & OPTICAL_FLAG_USE_XPA) + { + r->value |= REG03_XPASEL; + } + reg->state.is_xpa_on = flags & OPTICAL_FLAG_USE_XPA; + + /* BW threshold */ + r = sanei_genesys_get_address (reg, REG2E); + r->value = dev->settings.threshold; + r = sanei_genesys_get_address (reg, REG2F); + r->value = dev->settings.threshold; + + /* monochrome / color scan */ + r = sanei_genesys_get_address (reg, REG04); + switch (depth) + { + case 1: + r->value &= ~REG04_BITSET; + r->value |= REG04_LINEART; + break; + case 8: + r->value &= ~(REG04_LINEART | REG04_BITSET); + break; + case 16: + r->value &= ~REG04_LINEART; + r->value |= REG04_BITSET; + break; + } + + r->value &= ~(REG04_FILTER | REG04_AFEMOD); + if (channels == 1) + { + switch (color_filter) + { + case ColorFilter::RED: + r->value |= 0x14; + break; + case ColorFilter::BLUE: + r->value |= 0x1c; + break; + case ColorFilter::GREEN: + r->value |= 0x18; + break; + default: + break; // should not happen + } + } + else + r->value |= 0x10; /* mono */ + + /* register 05 */ + r = sanei_genesys_get_address (reg, REG05); + + /* set up dpihw */ + r->value &= ~REG05_DPIHW; + switch(dpihw) + { + case 600: + r->value |= REG05_DPIHW_600; + break; + case 1200: + r->value |= REG05_DPIHW_1200; + break; + case 2400: + r->value |= REG05_DPIHW_2400; + break; + case 4800: + r->value |= REG05_DPIHW_4800; + break; + } + + /* enable gamma tables */ + if (flags & OPTICAL_FLAG_DISABLE_GAMMA) + r->value &= ~REG05_GMMENB; + else + r->value |= REG05_GMMENB; + + sanei_genesys_set_double(reg, REG_DPISET, dpiset * ccd_size_divisor); + DBG(DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset * ccd_size_divisor); + + sanei_genesys_set_double(reg, REG_STRPIXEL, startx); + sanei_genesys_set_double(reg, REG_ENDPIXEL, endx); + + /* words(16bit) before gamma, conversion to 8 bit or lineart */ + words_per_line = (used_pixels * dpiset) / dpihw; + bytes = depth / 8; + if (depth == 1) + { + words_per_line = (words_per_line >> 3) + ((words_per_line & 7) ? 1 : 0); + } + else + { + words_per_line *= bytes; + } + + dev->wpl = words_per_line; + dev->bpl = words_per_line; + + DBG(DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); + DBG(DBG_io2, "%s: pixels =%d\n", __func__, pixels); + DBG(DBG_io2, "%s: depth =%d\n", __func__, depth); + DBG(DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long) dev->bpl); + DBG(DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); + DBG(DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); + + words_per_line *= channels; + + /* MAXWD is expressed in 2 words unit */ + /* nousedspace = (mem_bank_range * 1024 / 256 -1 ) * 4; */ + sanei_genesys_set_triple(reg,REG_MAXWD,(words_per_line)>>1); + DBG(DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); + + sanei_genesys_set_double(reg,REG_LPERIOD,exposure/tgtime); + DBG(DBG_io2, "%s: exposure used=%d\n", __func__, exposure/tgtime); + + r = sanei_genesys_get_address (reg, REG_DUMMY); + r->value = sensor.dummy_pixel; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +struct ScanSession { + SetupParams params; + + // whether the session setup has been computed via gl843_compute_session() + bool computed = false; + + // whether CCD operates as half-resolution or full resolution at a specific resolution + unsigned ccd_size_divisor = 1; + + // the optical resolution of the scanner. + unsigned optical_resolution = 0; + + // the number of pixels at the optical resolution. + unsigned optical_pixels = 0; + + // the number of bytes in the output of a single line directly from scanner + unsigned optical_line_bytes = 0; + + // the resolution of the output data. + unsigned output_resolution = 0; + + // the number of pixels in output data + unsigned output_pixels = 0; + + // the number of bytes in the output of a single line + unsigned output_line_bytes = 0; + + // the number of lines in the output of the scanner. This must be larger than the user + // requested number due to line staggering and color channel shifting. + unsigned output_line_count = 0; + + // the number of staggered lines (i.e. lines that overlap during scanning due to line being + // thinner than the CCD element) + unsigned num_staggered_lines = 0; + + // the number of lines that color channels shift due to different physical positions of + // different color channels + unsigned max_color_shift_lines = 0; + + void assert_computed() const + { + if (!computed) { + throw std::runtime_error("ScanSession is not computed"); + } + } +}; + +static unsigned align_int_up(unsigned num, unsigned alignment) +{ + unsigned mask = alignment - 1; + if (num & mask) + num = (num & ~mask) + alignment; + return num; +} + +// computes physical parameters for specific scan setup +static void gl843_compute_session(Genesys_Device* dev, ScanSession& s, + const Genesys_Sensor& sensor) +{ + s.params.assert_valid(); + s.ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(s.params.xres); + + s.optical_resolution = sensor.optical_res / s.ccd_size_divisor; + + if (s.params.flags & SCAN_FLAG_USE_OPTICAL_RES) { + s.output_resolution = s.optical_resolution; + } else { + // resolution is choosen from a fixed list and can be used directly + // unless we have ydpi higher than sensor's maximum one + if (s.params.xres > s.optical_resolution) + s.output_resolution = s.optical_resolution; + else + s.output_resolution = s.params.xres; + } + + // compute rounded up number of optical pixels + s.optical_pixels = (s.params.pixels * s.optical_resolution) / s.params.xres; + if (s.optical_pixels * s.params.xres < s.params.pixels * s.optical_resolution) + s.optical_pixels++; + + // ensure the number of optical pixels is divisible by 2. + // In quarter-CCD mode optical_pixels is 4x larger than the actual physical number + s.optical_pixels = align_int_up(s.optical_pixels, 2 * s.ccd_size_divisor); + + s.output_pixels = + (s.optical_pixels * s.output_resolution) / s.optical_resolution; + + // Note: staggering is not applied for calibration. Staggering starts at 2400 dpi + s.num_staggered_lines = 0; + if ((s.params.yres > 1200) && + ((s.params.flags & SCAN_FLAG_IGNORE_LINE_DISTANCE) == 0) && + (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + { + s.num_staggered_lines = (4 * s.params.yres) / dev->motor.base_ydpi; + } + + s.max_color_shift_lines = sanei_genesys_compute_max_shift(dev, s.params.channels, + s.params.yres, s.params.flags); + + s.output_line_count = s.params.lines + s.max_color_shift_lines + s.num_staggered_lines; + + s.optical_line_bytes = (s.optical_pixels * s.params.channels * s.params.depth) / 8; + s.output_line_bytes = (s.output_pixels * s.params.channels * s.params.depth) / 8; + s.computed = true; +} + +/* set up registers for an actual scan + * + * this function sets up the scanner to scan in normal or single line mode + */ +static SANE_Status gl843_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + ScanSession& session) +{ + session.assert_computed(); + + int start; + int move; + unsigned int oflags, mflags; /**> optical and motor flags */ + int exposure; + + int slope_dpi = 0; + int dummy = 0; + int scan_step_type = 1; + int scan_power_mode = 0; + size_t requested_buffer_size, read_buffer_size; + + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, session.params); + + DBG(DBG_info, "%s : stagger=%d lines\n", __func__, session.num_staggered_lines); + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + oflags = 0; + if (session.params.flags & SCAN_FLAG_DISABLE_SHADING) + oflags |= OPTICAL_FLAG_DISABLE_SHADING; + if (session.params.flags & SCAN_FLAG_DISABLE_GAMMA) + oflags |= OPTICAL_FLAG_DISABLE_GAMMA; + if (session.params.flags & SCAN_FLAG_DISABLE_LAMP) + oflags |= OPTICAL_FLAG_DISABLE_LAMP; + if (session.params.flags & SCAN_FLAG_CALIBRATION) + oflags |= OPTICAL_FLAG_DISABLE_DOUBLE; + if (session.num_staggered_lines) + oflags |= OPTICAL_FLAG_STAGGER; + if (session.params.flags & SCAN_FLAG_USE_XPA) + oflags |= OPTICAL_FLAG_USE_XPA; + + + /* compute scan parameters values */ + /* pixels are allways given at full optical resolution */ + /* use detected left margin and fixed value */ + /* start */ + start = session.params.startx; + + dummy = 0; + /* dummy = 1; XXX STEF XXX */ + + /* slope_dpi */ + /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ + if (dev->model->is_cis) + slope_dpi = session.params.yres * session.params.channels; + else + slope_dpi = session.params.yres; + slope_dpi = slope_dpi * (1 + dummy); + + /* scan_step_type */ + exposure = sensor.exposure_lperiod; + if (exposure < 0) { + throw std::runtime_error("Exposure not defined in sensor definition"); + } + scan_step_type = sanei_genesys_compute_step_type(gl843_motors, dev->model->motor_type, exposure); + + DBG(DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); + + /*** optical parameters ***/ + /* in case of dynamic lineart, we use an internal 8 bit gray scan + * to generate 1 lineart data */ + if (session.params.flags & SCAN_FLAG_DYNAMIC_LINEART) { + session.params.depth = 8; + } + + /* no 16 bit gamma for this ASIC */ + if (session.params.depth == 16) + { + session.params.flags |= SCAN_FLAG_DISABLE_GAMMA; + oflags |= OPTICAL_FLAG_DISABLE_GAMMA; + } + + /* now _LOGICAL_ optical values used are known, setup registers */ + status = gl843_init_optical_regs_scan (dev, sensor, + reg, + exposure, + session.output_resolution, + start, + session.optical_pixels, + session.params.channels, + session.params.depth, + session.ccd_size_divisor, + session.params.color_filter, + oflags); + if (status != SANE_STATUS_GOOD) + return status; + + /*** motor parameters ***/ + + /* it seems base_dpi of the G4050 motor is changed above 600 dpi*/ + if (dev->model->motor_type == MOTOR_G4050 && session.params.yres>600) + { + dev->ld_shift_r = (dev->model->ld_shift_r*3800)/dev->motor.base_ydpi; + dev->ld_shift_g = (dev->model->ld_shift_g*3800)/dev->motor.base_ydpi; + dev->ld_shift_b = (dev->model->ld_shift_b*3800)/dev->motor.base_ydpi; + } + else + { + dev->ld_shift_r = dev->model->ld_shift_r; + dev->ld_shift_g = dev->model->ld_shift_g; + dev->ld_shift_b = dev->model->ld_shift_b; + } + + /* add tl_y to base movement */ + move = session.params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + + mflags=0; + if(session.params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) + mflags|=MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; + if(session.params.flags & SCAN_FLAG_FEEDING) + mflags|=MOTOR_FLAG_FEED; + if (session.params.flags & SCAN_FLAG_USE_XPA) + mflags |= MOTOR_FLAG_USE_XPA; + + status = gl843_init_motor_regs_scan (dev, sensor, + reg, + exposure, + slope_dpi, + scan_step_type, + dev->model->is_cis ? session.output_line_count * session.params.channels + : session.output_line_count, + dummy, + move, + scan_power_mode, + mflags); + if (status != SANE_STATUS_GOOD) + return status; + + /* since we don't have sheetfed scanners to handle, + * use huge read buffer */ + /* TODO find the best size according to settings */ + requested_buffer_size = 16 * session.output_line_bytes; + + read_buffer_size = + 2 * requested_buffer_size + + (session.max_color_shift_lines + session.num_staggered_lines) * session.optical_line_bytes; + + dev->read_buffer.clear(); + dev->read_buffer.alloc(read_buffer_size); + + dev->lines_buffer.clear(); + dev->lines_buffer.alloc(read_buffer_size); + + dev->shrink_buffer.clear(); + dev->shrink_buffer.alloc(requested_buffer_size); + + dev->out_buffer.clear(); + dev->out_buffer.alloc((8 * session.params.pixels * session.params.channels * + session.params.depth) / 8); + + dev->read_bytes_left = session.output_line_bytes * session.output_line_count; + + DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); + dev->read_active = SANE_TRUE; + + dev->current_setup.params = session.params; + dev->current_setup.pixels = session.output_pixels; + DBG(DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); + dev->current_setup.lines = session.output_line_count; + dev->current_setup.depth = session.params.depth; + dev->current_setup.channels = session.params.channels; + dev->current_setup.exposure_time = exposure; + dev->current_setup.xres = session.output_resolution; + dev->current_setup.yres = session.params.yres; + dev->current_setup.ccd_size_divisor = session.ccd_size_divisor; + dev->current_setup.stagger = session.num_staggered_lines; + dev->current_setup.max_shift = session.max_color_shift_lines + session.num_staggered_lines; + + dev->total_bytes_read = 0; + if (session.params.depth == 1) { + dev->total_bytes_to_read = ((session.params.pixels * session.params.lines) / 8 + + (((session.params.pixels * session.params.lines) % 8) ? 1 : 0)) * + session.params.channels; + } else { + dev->total_bytes_to_read = session.params.pixels * session.params.lines * + session.params.channels * (session.params.depth / 8); + } + + DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); + + DBG(DBG_proc, "%s: completed\n", __func__); + return SANE_STATUS_GOOD; +} + +static void +gl843_calculate_current_setup(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int depth; + int start; + + int used_res; + int used_pixels; + unsigned int lincnt; + int exposure; + int stagger; + + int max_shift; + + int optical_res; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + /* we have 2 domains for ccd: xres below or above half ccd max dpi */ + unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); + + /* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + /* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + /* start */ + if(dev->settings.scan_method==ScanMethod::TRANSPARENCY) + start = SANE_UNFIX (dev->model->x_offset_ta); + else + start = SANE_UNFIX (dev->model->x_offset); + + start /= ccd_size_divisor; + + start += dev->settings.tl_x; + start = (start * sensor.optical_res) / MM_PER_INCH; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; // not used + params.starty = 0; // not used + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = 0; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + + /* optical_res */ + optical_res = sensor.optical_res / ccd_size_divisor; + + /* stagger */ + if (ccd_size_divisor == 1 && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG(DBG_info, "%s: stagger=%d lines\n", __func__, stagger); + + if (params.xres <= (unsigned) optical_res) { + used_res = params.xres; + } else { + used_res = optical_res; + } + + /* compute scan parameters values */ + /* pixels are allways given at half or full CCD optical resolution */ + /* use detected left margin and fixed value */ + + /* compute correct pixels number */ + used_pixels = (params.pixels * optical_res) / params.xres; + DBG(DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); + + /* exposure */ + exposure = sensor.exposure_lperiod; + if (exposure < 0) { + throw std::runtime_error("Exposure not defined in sensor definition"); + } + DBG(DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); + + /* it seems base_dpi of the G4050 motor is changed above 600 dpi*/ + if (dev->model->motor_type == MOTOR_G4050 && params.yres>600) + { + dev->ld_shift_r = (dev->model->ld_shift_r*3800)/dev->motor.base_ydpi; + dev->ld_shift_g = (dev->model->ld_shift_g*3800)/dev->motor.base_ydpi; + dev->ld_shift_b = (dev->model->ld_shift_b*3800)/dev->motor.base_ydpi; + } + else + { + dev->ld_shift_r = dev->model->ld_shift_r; + dev->ld_shift_g = dev->model->ld_shift_g; + dev->ld_shift_b = dev->model->ld_shift_b; + } + + /* scanned area must be enlarged by max color shift needed */ + max_shift = sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); + + /* lincnt */ + lincnt = params.lines + max_shift + stagger; + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res) / optical_res; + DBG(DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = ccd_size_divisor; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + + DBG(DBG_proc, "%s: completed\n", __func__); +} + +/** + * for fast power saving methods only, like disabling certain amplifiers + * @param dev device to use + * @param enable true to set inot powersaving + * */ +static SANE_Status +gl843_save_power (Genesys_Device * dev, SANE_Bool enable) +{ + uint8_t val; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); + if (dev == NULL) + return SANE_STATUS_INVAL; + + /* switch KV-SS080 lamp off */ + if (dev->model->gpo_type == GPO_KVSS080) + { + RIE(sanei_genesys_read_register (dev, REG6C, &val)); + if(enable) + val &= 0xef; + else + val |= 0x10; + RIE(sanei_genesys_write_register(dev,REG6C,val)); + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl843_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); + if (dev == NULL) + return SANE_STATUS_INVAL; + + DBGCOMPLETED; + return status; +} + +static SANE_Status +gl843_start_action (Genesys_Device * dev) +{ + return sanei_genesys_write_register (dev, 0x0f, 0x01); +} + +static SANE_Status +gl843_stop_action_no_move(Genesys_Device* dev, Genesys_Register_Set* reg) +{ + uint8_t val = sanei_genesys_read_reg_from_set(reg, REG01); + val &= ~REG01_SCAN; + sanei_genesys_set_reg_from_set(reg, REG01, val); + SANE_Status ret = sanei_genesys_write_register(dev, REG01, val); + sanei_genesys_sleep_ms(100); + return ret; +} + +static SANE_Status +gl843_stop_action (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val40, val; + unsigned int loop; + + DBG(DBG_proc, "%s\n", __func__); + + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + val40 = 0; + status = sanei_genesys_read_register (dev, REG40, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + DBG(DBG_proc, "%s: completed\n", __func__); + return status; + } + + /* only stop action if needed */ + if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) + { + DBG(DBG_info, "%s: already stopped\n", __func__); + DBG(DBG_proc, "%s: completed\n", __func__); + return SANE_STATUS_GOOD; + } + + /* ends scan 646 */ + val = dev->reg.get8(REG01); + val &= ~REG01_SCAN; + dev->reg.set8(REG01, val); + status = sanei_genesys_write_register (dev, REG01, val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_sleep_ms(100); + + loop = 10; + while (loop > 0) + { + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + val40 = 0; + status = sanei_genesys_read_register (dev, 0x40, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* if scanner is in command mode, we are done */ + if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) + && !(val & REG41_MOTORENB)) + { + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + sanei_genesys_sleep_ms(100); + loop--; + } + + DBGCOMPLETED; + return SANE_STATUS_IO_ERROR; +} + +static SANE_Status +gl843_get_paper_sensor (Genesys_Device * dev, SANE_Bool * paper_loaded) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + status = sanei_genesys_read_register (dev, REG6D, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read gpio: %s\n", __func__, sane_strstatus(status)); + return status; + } + *paper_loaded = (val & 0x1) == 0; + return SANE_STATUS_GOOD; + + return SANE_STATUS_INVAL; +} + +static SANE_Status +gl843_eject_document (Genesys_Device * dev) +{ + DBG(DBG_proc, "%s: not implemented \n", __func__); + if (dev == NULL) + return SANE_STATUS_INVAL; + return SANE_STATUS_GOOD; +} + + +static SANE_Status +gl843_load_document (Genesys_Device * dev) +{ + DBG(DBG_proc, "%s: not implemented \n", __func__); + if (dev == NULL) + return SANE_STATUS_INVAL; + return SANE_STATUS_GOOD; +} + +/** + * detects end of document and adjust current scan + * to take it into account + * used by sheetfed scanners + */ +static SANE_Status +gl843_detect_document_end (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Bool paper_loaded; + unsigned int scancnt = 0; + int flines, channels, depth, bytes_remain, sublines, + bytes_to_flush, lines, sub_bytes, tmp, read_bytes_left; + DBG(DBG_proc, "%s: begin\n", __func__); + + RIE (gl843_get_paper_sensor (dev, &paper_loaded)); + + /* sheetfed scanner uses home sensor as paper present */ + if ((dev->document == SANE_TRUE) && !paper_loaded) + { + DBG(DBG_info, "%s: no more document\n", __func__); + dev->document = SANE_FALSE; + + channels = dev->current_setup.channels; + depth = dev->current_setup.depth; + read_bytes_left = (int) dev->read_bytes_left; + DBG(DBG_io, "%s: read_bytes_left=%d\n", __func__, read_bytes_left); + + /* get lines read */ + try { + status = sanei_genesys_read_scancnt(dev, &scancnt); + } catch (...) { + flines = 0; + } + if (status != SANE_STATUS_GOOD) + { + flines = 0; + } + else + { + /* compute number of line read */ + tmp = (int) dev->total_bytes_read; + if (depth == 1 || dev->settings.scan_mode == ScanColorMode::LINEART) + flines = tmp * 8 / dev->settings.pixels / channels; + else + flines = tmp / (depth / 8) / dev->settings.pixels / channels; + + /* number of scanned lines, but no read yet */ + flines = scancnt - flines; + + DBG(DBG_io, "%s: %d scanned but not read lines\n", __func__, flines); + } + + /* adjust number of bytes to read + * we need to read the final bytes which are word per line * number of last lines + * to have doc leaving feeder */ + lines = + (SANE_UNFIX (dev->model->post_scan) * dev->current_setup.yres) / + MM_PER_INCH + flines; + DBG(DBG_io, "%s: adding %d line to flush\n", __func__, lines); + + /* number of bytes to read from scanner to get document out of it after + * end of document dectected by hardware sensor */ + bytes_to_flush = lines * dev->wpl; + + /* if we are already close to end of scan, flushing isn't needed */ + if (bytes_to_flush < read_bytes_left) + { + /* we take all these step to work around an overflow on some plateforms */ + tmp = (int) dev->total_bytes_read; + DBG (DBG_io, "%s: tmp=%d\n", __func__, tmp); + bytes_remain = (int) dev->total_bytes_to_read; + DBG(DBG_io, "%s: bytes_remain=%d\n", __func__, bytes_remain); + bytes_remain = bytes_remain - tmp; + DBG(DBG_io, "%s: bytes_remain=%d\n", __func__, bytes_remain); + + /* remaining lines to read by frontend for the current scan */ + if (depth == 1 || dev->settings.scan_mode == ScanColorMode::LINEART) + { + flines = bytes_remain * 8 / dev->settings.pixels / channels; + } + else + flines = bytes_remain / (depth / 8) + / dev->settings.pixels / channels; + DBG(DBG_io, "%s: flines=%d\n", __func__, flines); + + if (flines > lines) + { + /* change the value controlling communication with the frontend : + * total bytes to read is current value plus the number of remaining lines + * multiplied by bytes per line */ + sublines = flines - lines; + + if (depth == 1 || dev->settings.scan_mode == ScanColorMode::LINEART) + sub_bytes = + ((dev->settings.pixels * sublines) / 8 + + (((dev->settings.pixels * sublines) % 8) ? 1 : 0)) * + channels; + else + sub_bytes = + dev->settings.pixels * sublines * channels * (depth / 8); + + dev->total_bytes_to_read -= sub_bytes; + + /* then adjust the physical bytes to read */ + if (read_bytes_left > sub_bytes) + { + dev->read_bytes_left -= sub_bytes; + } + else + { + dev->total_bytes_to_read = dev->total_bytes_read; + dev->read_bytes_left = 0; + } + + DBG(DBG_io, "%s: sublines=%d\n", __func__, sublines); + DBG(DBG_io, "%s: subbytes=%d\n", __func__, sub_bytes); + DBG(DBG_io, "%s: total_bytes_to_read=%lu\n", __func__, + (unsigned long) dev->total_bytes_to_read); + DBG(DBG_io, "%s: read_bytes_left=%d\n", __func__, read_bytes_left); + } + } + else + { + DBG(DBG_io, "%s: no flushing needed\n", __func__); + } + } + + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; +} + +// enables or disables XPA slider motor +static SANE_Status gl843_set_xpa_motor_power(Genesys_Device *dev, bool set) +{ + uint8_t val; + SANE_Status status=SANE_STATUS_GOOD; + + DBGSTART; + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) { + + if (set) { + RIE(sanei_genesys_read_register(dev, REG6C, &val)); + val &= ~REG6C_GPIO14; + if (dev->current_setup.xres >= 2400) { + val |= REG6C_GPIO10; + } + RIE(sanei_genesys_write_register(dev, REG6C, val)); + + RIE(sanei_genesys_read_register(dev, REGA6, &val)); + val |= REGA6_GPIO17; + RIE(sanei_genesys_write_register(dev, REGA6,val)); + } else { + RIE(sanei_genesys_read_register(dev, REG6C, &val)); + val |= REG6C_GPIO14; + val &= ~REG6C_GPIO10; + RIE(sanei_genesys_write_register(dev, REG6C, val)); + + RIE(sanei_genesys_read_register(dev, REGA6, &val)); + val &= ~REGA6_GPIO17; + RIE(sanei_genesys_write_register(dev, REGA6,val)); + } + DBGCOMPLETED; + return status; + } + + if (dev->model->model_id == MODEL_HP_SCANJET_G4050) { + + if (set) { + /* set MULTFILM et GPOADF */ + RIE (sanei_genesys_read_register (dev, REG6B, &val)); + val |=REG6B_MULTFILM|REG6B_GPOADF; + RIE (sanei_genesys_write_register (dev, REG6B, val)); + + RIE (sanei_genesys_read_register (dev, REG6C, &val)); + val &= ~REG6C_GPIO15; + RIE (sanei_genesys_write_register (dev, REG6C, val)); + + /* Motor power ? No move at all without this one */ + RIE (sanei_genesys_read_register (dev, REGA6, &val)); + val |= REGA6_GPIO20; + RIE (sanei_genesys_write_register(dev,REGA6,val)); + + RIE (sanei_genesys_read_register (dev, REGA8, &val)); + val &= ~REGA8_GPO27; + RIE (sanei_genesys_write_register (dev, REGA8, val)); + + RIE (sanei_genesys_read_register (dev, REGA9, &val)); + val |= REGA9_GPO32|REGA9_GPO31; + RIE (sanei_genesys_write_register (dev, REGA9, val)); + } else { + /* unset GPOADF */ + RIE (sanei_genesys_read_register (dev, REG6B, &val)); + val &= ~REG6B_GPOADF; + RIE (sanei_genesys_write_register (dev, REG6B, val)); + + RIE (sanei_genesys_read_register (dev, REGA8, &val)); + val |= REGA8_GPO27; + RIE (sanei_genesys_write_register (dev, REGA8, val)); + + RIE (sanei_genesys_read_register (dev, REGA9, &val)); + val &= ~REGA9_GPO31; + RIE (sanei_genesys_write_register (dev, REGA9, val)); + } + DBGCOMPLETED; + return status; + } + + DBGCOMPLETED; + return status; +} + + +/** @brief light XPA lamp + * toggle gpios to switch off regular lamp and light on the + * XPA light + * @param dev device to set up + */ +static SANE_Status gl843_set_xpa_lamp_power(Genesys_Device *dev, bool set) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val = 0; + DBGSTART; + + if (set) { + RIE(sanei_genesys_read_register(dev, REGA6, &val)); + + // cut regular lamp power + val &= ~(REGA6_GPIO24 | REGA6_GPIO23); + + // set XPA lamp power + val |= REGA6_GPIO22 | REGA6_GPIO21 | REGA6_GPIO19; + + RIE(sanei_genesys_write_register(dev, REGA6, val)); + + RIE(sanei_genesys_read_register(dev, REGA7, &val)); + val|=REGA7_GPOE24; /* lamp 1 off GPOE 24 */ + val|=REGA7_GPOE23; /* lamp 2 off GPOE 23 */ + val|=REGA7_GPOE22; /* full XPA lamp power */ + RIE(sanei_genesys_write_register(dev, REGA7, val)); + } else { + RIE(sanei_genesys_read_register(dev, REGA6, &val)); + + // switch on regular lamp + val |= REGA6_GPIO23; + + // no XPA lamp power (2 bits for level: __11 ____) + val &= ~(REGA6_GPIO22 | REGA6_GPIO21); + + RIE(sanei_genesys_write_register(dev, REGA6, val)); + } + + DBGCOMPLETED; + return status; +} + +/* Send the low-level scan command */ +static SANE_Status +gl843_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SANE_Bool start_motor) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + uint16_t dpiset, dpihw; + + DBGSTART; + + /* get back the target dpihw */ + sanei_genesys_get_double (reg, REG_DPISET, &dpiset); + dpihw = sanei_genesys_compute_dpihw(dev, sensor, dpiset); + + /* set up GPIO for scan */ + switch(dev->model->gpo_type) + { + /* KV case */ + case GPO_KVSS080: + RIE (sanei_genesys_write_register (dev, REGA9, 0x00)); + RIE (sanei_genesys_write_register (dev, REGA6, 0xf6)); + /* blinking led */ + RIE (sanei_genesys_write_register (dev, 0x7e, 0x04)); + break; + case GPO_G4050: + RIE (sanei_genesys_write_register (dev, REGA7, 0xfe)); + RIE (sanei_genesys_write_register (dev, REGA8, 0x3e)); + RIE (sanei_genesys_write_register (dev, REGA9, 0x06)); + switch (dpihw) + { + case 1200: + case 2400: + case 4800: + RIE (sanei_genesys_write_register (dev, REG6C, 0x60)); + RIE (sanei_genesys_write_register (dev, REGA6, 0x46)); + break; + default: /* 600 dpi case */ + RIE (sanei_genesys_write_register (dev, REG6C, 0x20)); + RIE (sanei_genesys_write_register (dev, REGA6, 0x44)); + } + + if (reg->state.is_xpa_on && reg->state.is_lamp_on) { + RIE(gl843_set_xpa_lamp_power(dev, true)); + } + + if (reg->state.is_xpa_on) { + dev->needs_home_ta = SANE_TRUE; + RIE(gl843_set_xpa_motor_power(dev, true)); + } + + /* blinking led */ + RIE (sanei_genesys_write_register (dev, REG7E, 0x01)); + break; + case GPO_CS8600F: + if (reg->state.is_xpa_on) { + dev->needs_home_ta = SANE_TRUE; + RIE(gl843_set_xpa_motor_power(dev, true)); + } + break; + case GPO_CS4400F: + case GPO_CS8400F: + default: + break; + } + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register + (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); + + /* enable scan and motor */ + RIE (sanei_genesys_read_register (dev, REG01, &val)); + val |= REG01_SCAN; + RIE (sanei_genesys_write_register (dev, REG01, val)); + + if (start_motor) + { + RIE (sanei_genesys_write_register (dev, REG0F, 1)); + } + else + { + RIE (sanei_genesys_write_register (dev, REG0F, 0)); + } + + DBGCOMPLETED; + return status; +} + + +/* Send the stop scan command */ +static SANE_Status +gl843_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, + SANE_Bool check_stop) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); + if (reg == NULL) + return SANE_STATUS_INVAL; + + /* post scan gpio */ + RIE(sanei_genesys_write_register(dev,0x7e,0x00)); + + // turn off XPA lamp if needed + // BUG: the if condition below probably shouldn't be enabled when XPA is off + if (reg->state.is_xpa_on || reg->state.is_lamp_on) { + gl843_set_xpa_lamp_power(dev, false); + } + + if (dev->model->is_sheetfed == SANE_TRUE) + { + status = SANE_STATUS_GOOD; + } + else /* flat bed scanners */ + { + status = gl843_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + DBGCOMPLETED; + return status; +} + +/** @brief park XPA lamp + * park the XPA lamp if needed + */ +static SANE_Status gl843_park_xpa_lamp (Genesys_Device * dev) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + uint8_t val; + int loop = 0; + + DBGSTART; + + /* copy scan settings */ + local_reg = dev->reg; + + /* set a huge feedl and reverse direction */ + sanei_genesys_set_triple(&local_reg,REG_FEEDL,0xbdcd); + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); + + /* set up for reverse and no scan */ + r = sanei_genesys_get_address (&local_reg, REG02); + r->value |= REG02_MTRREV; + r = sanei_genesys_get_address (&local_reg, REG01); + r->value &= ~REG01_SCAN; + + /* write to scanner and start action */ + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + RIE(gl843_set_xpa_motor_power(dev, true)); + try { + status = gl843_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl843_stop_action(dev); + } catch (...) {} + try { + // restore original registers + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl843_stop_action (dev); + /* restore original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + while (loop < 600) /* do not wait longer then 60 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io2) + { + sanei_genesys_print_status (val); + } + + if (val & REG41_HOMESNR) /* home sensor */ + { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + + gl843_set_xpa_motor_power(dev, false); + dev->needs_home_ta = SANE_FALSE; + + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + ++loop; + } + + /* we are not parked here.... should we fail ? */ + DBG(DBG_info, "%s: XPA lamp is not parked\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief Moves the slider to the home (top) position slowly + * */ +static SANE_Status +gl843_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + uint8_t val; + float resolution; + int loop = 0; + + DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); + + if (dev->needs_home_ta) { + RIE(gl843_park_xpa_lamp(dev)); + } + + /* regular slow back home */ + dev->scanhead_position_in_steps = 0; + + /* first read gives HOME_SENSOR true */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_sleep_ms(100); + + /* second is reliable */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + if (val & HOMESNR) /* is sensor at home? */ + { + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + local_reg = dev->reg; + resolution=sanei_genesys_get_lowest_ydpi(dev); + + const auto& sensor = sanei_genesys_find_sensor(dev, resolution); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 100; + session.params.starty = 40000; + session.params.pixels = 100; + session.params.lines = 100; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::LINEART; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + gl843_compute_session(dev, session, sensor); + + status = gl843_init_scan_regs(dev, sensor, &local_reg, session); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); + + /* set up for reverse and no scan */ + r = sanei_genesys_get_address(&local_reg, REG02); + r->value |= REG02_MTRREV; + r = sanei_genesys_get_address(&local_reg, REG01); + r->value &= ~REG01_SCAN; + + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + + try { + status = gl843_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl843_stop_action(dev); + } catch (...) {} + try { + // restore original registers + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl843_stop_action (dev); + /* restore original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + if (wait_until_home) + { + + while (loop < 300) /* do not wait longer then 30 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io2) + { + sanei_genesys_print_status (val); + } + + if (val & REG41_HOMESNR) /* home sensor */ + { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + ++loop; + } + + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl843_stop_action (dev); + DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + DBG(DBG_info, "%s: scanhead is still moving\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels + area at 600 dpi from very top of scanner */ +static SANE_Status +gl843_search_start_position (Genesys_Device * dev) +{ + int size; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg; + int steps; + + int pixels = 600; + int dpi = 300; + + DBG(DBG_proc, "%s\n", __func__); + + local_reg = dev->reg; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; // we should give a small offset here - ~60 steps + session.params.pixels = 600; + session.params.lines = dev->model->search_lines; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::GREEN; + session.params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_IGNORE_LINE_DISTANCE | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; + gl843_compute_session(dev, session, sensor); + + status = gl843_init_scan_regs(dev, sensor, &local_reg, session); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk setup registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* send to scanner */ + status = dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + size = dev->read_bytes_left; + + std::vector data(size); + + status = gl843_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + RIE(gl843_stop_action_no_move(dev, &local_reg)); + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl843_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + + status = gl843_end_scan(dev, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + + status = + sanei_genesys_search_reference_point (dev, sensor, data.data(), 0, dpi, pixels, + dev->model->search_lines); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + return SANE_STATUS_GOOD; +} + +/* + * sets up register for coarse gain calibration + * todo: check it for scanners using it */ +static SANE_Status +gl843_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t channels; + uint8_t cksel; + + DBGSTART; + cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ + + /* set line size */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + int flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { + flags |= SCAN_FLAG_USE_XPA; + } + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = sensor.optical_res / cksel; // XXX STEF XXX dpi instead of pixels! + session.params.lines = 20; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + gl843_compute_session(dev, session, sensor); + + status = gl843_init_scan_regs(dev, sensor, ®s, session); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_set_motor_power(regs, false); + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / cksel, dev->settings.xres); + + status = dev->model->cmd_set->bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief moves the slider to steps at motor base dpi + * @param dev device to work on + * @param steps number of steps to move + * */ +static SANE_Status +gl843_feed (Genesys_Device * dev, unsigned int steps) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + float resolution; + uint8_t val; + + DBGSTART; + + /* prepare local registers */ + local_reg = dev->reg; + + resolution=sanei_genesys_get_lowest_ydpi(dev); + + const auto& sensor = sanei_genesys_find_sensor(dev, resolution); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 0; + session.params.starty = steps; + session.params.pixels = 100; + session.params.lines = 3; + session.params.depth = 8; + session.params.channels = 3; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = ColorFilter::RED; + session.params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_FEEDING | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + gl843_compute_session(dev, session, sensor); + + status = gl843_init_scan_regs(dev, sensor, &local_reg, session); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); + + /* set up for no scan */ + r = sanei_genesys_get_address(&local_reg, REG01); + r->value &= ~REG01_SCAN; + + /* send registers */ + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + + try { + status = gl843_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl843_stop_action(dev); + } catch (...) {} + try { + // restore original registers + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl843_stop_action (dev); + + /* restore original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + /* wait until feed count reaches the required value, but do not + * exceed 30s */ + do + { + status = sanei_genesys_get_status (dev, &val); + } + while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); + + // looks like the scanner locks up if we scan immediately after feeding + sanei_genesys_sleep_ms(100); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status gl843_move_to_ta (Genesys_Device * dev); + +/* init registers for shading calibration */ +/* shading calibration is done at dpihw */ +static SANE_Status +gl843_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + int move, resolution, dpihw, factor; + uint16_t strpixel; + + DBGSTART; + + /* initial calibration reg values */ + regs = dev->reg; + + dev->calib_channels = 3; + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) + dev->calib_lines = dev->model->shading_ta_lines; + else + dev->calib_lines = dev->model->shading_lines; + dpihw = sanei_genesys_compute_dpihw_calibration(dev, sensor, dev->settings.xres); + factor=sensor.optical_res/dpihw; + resolution=dpihw; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, + dev->settings.scan_method); + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY && + dev->model->model_id == MODEL_CANON_CANOSCAN_8600F && + dev->settings.xres == 4800) + { + float offset = SANE_UNFIX(dev->model->x_offset_ta); + offset /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); + offset = (offset * calib_sensor.optical_res) / MM_PER_INCH; + + unsigned size = SANE_UNFIX(dev->model->x_size_ta); + size /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); + size = (size * calib_sensor.optical_res) / MM_PER_INCH; + + dev->calib_pixels_offset = offset; + dev->calib_pixels = size; + } + else + { + dev->calib_pixels_offset = 0; + dev->calib_pixels = calib_sensor.sensor_pixels / factor; + } + + dev->calib_resolution = resolution; + + int flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) + { + // note: move_to_ta() function has already been called and the sensor is at the + // transparency adapter + move = 0; // already at dev->model->y_offset_calib_ta implicitly + flags |= SCAN_FLAG_USE_XPA; + } + else + move = SANE_UNFIX(dev->model->y_offset_calib); + + move = (move * resolution) / MM_PER_INCH; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = dev->calib_pixels_offset; + session.params.starty = move; + session.params.pixels = dev->calib_pixels; + session.params.lines = dev->calib_lines; + session.params.depth = 16; + session.params.channels = dev->calib_channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + gl843_compute_session(dev, session, calib_sensor); + + status = gl843_init_scan_regs(dev, calib_sensor, ®s, session); + + // the pixel number may be updated to conform to scanner constraints + dev->calib_pixels = dev->current_setup.pixels; + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + dev->calib_total_bytes_to_read = dev->read_bytes_left; + + dev->scanhead_position_in_steps += dev->calib_lines + move; + sanei_genesys_get_double(®s,REG_STRPIXEL,&strpixel); + DBG(DBG_info, "%s: STRPIXEL=%d\n", __func__, strpixel); + + status = dev->model->cmd_set->bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief set up registers for the actual scan + */ +static SANE_Status +gl843_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int flags; + int depth; + float move; + int move_dpi; + float start; + + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + /* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + /* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + move_dpi = dev->motor.base_ydpi; + + flags = 0; + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) + { + // note: move_to_ta() function has already been called and the sensor is at the + // transparency adapter + move = SANE_UNFIX(dev->model->y_offset_ta) - SANE_UNFIX(dev->model->y_offset_calib_ta); + flags |= SCAN_FLAG_USE_XPA; + } + else + move = SANE_UNFIX(dev->model->y_offset); + + move += dev->settings.tl_y; + move = (move * move_dpi) / MM_PER_INCH; + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* start */ + if(dev->settings.scan_method==ScanMethod::TRANSPARENCY) + start = SANE_UNFIX (dev->model->x_offset_ta); + else + start = SANE_UNFIX (dev->model->x_offset); + + start /= sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); + start += dev->settings.tl_x; + start = (start * sensor.optical_res) / MM_PER_INCH; + + /* enable emulated lineart from gray data */ + if(dev->settings.scan_mode == ScanColorMode::LINEART + && dev->settings.dynamic_lineart) + { + flags |= SCAN_FLAG_DYNAMIC_LINEART; + } + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = start; + session.params.starty = move; + session.params.pixels = dev->settings.pixels; + session.params.lines = dev->settings.lines; + session.params.depth = depth; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + gl843_compute_session(dev, session, sensor); + + status = gl843_init_scan_regs(dev, sensor, &dev->reg, session); + + if (status != SANE_STATUS_GOOD) + return status; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** + * This function sends gamma tables to ASIC + */ +static SANE_Status +gl843_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) +{ + int size; + SANE_Status status = SANE_STATUS_GOOD; + int i; + + DBGSTART; + + size = 256; + + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3); + + std::vector rgamma = get_gamma_table(dev, sensor, GENESYS_RED); + std::vector ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN); + std::vector bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE); + + // copy sensor specific's gamma tables + for (i = 0; i < size; i++) { + gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff; + gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff; + gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff; + gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff; + gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff; + gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff; + } + + /* send address */ + status = gl843_set_buffer_address (dev, 0x0000); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* send data */ + status = sanei_genesys_bulk_write_data(dev, 0x28, gamma.data(), size * 2 * 3); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send gamma table: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: completed\n", __func__); + return SANE_STATUS_GOOD; +} + +/* this function does the led calibration by scanning one line of the calibration + area below scanner's top on white strip. + +-needs working coarse/gain +*/ +static SANE_Status +gl843_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs) +{ + int num_pixels; + int total_size; + int used_res; + int i, j; + SANE_Status status = SANE_STATUS_GOOD; + int val; + int channels, depth; + int avg[3], avga, avge; + int turn; + uint16_t expr, expg, expb; + + SANE_Bool acceptable = SANE_FALSE; + + DBG(DBG_proc, "%s\n", __func__); + + /* offset calibration is always done in color mode */ + channels = 3; + depth = 16; + used_res = sensor.optical_res; + + auto& calib_sensor = sanei_genesys_find_sensor_for_write(dev, used_res, + dev->settings.scan_method); + num_pixels = + (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + ScanSession session; + session.params.xres = used_res; + session.params.yres = dev->motor.base_ydpi; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = depth; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + gl843_compute_session(dev, session, calib_sensor); + + status = gl843_init_scan_regs(dev, calib_sensor, ®s, session); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + + total_size = dev->read_bytes_left; + + std::vector line(total_size); + +/* + we try to get equal bright leds here: + + loop: + average per color + adjust exposure times + */ + + expr = calib_sensor.exposure.red; + expg = calib_sensor.exposure.green; + expb = calib_sensor.exposure.blue; + + turn = 0; + + do + { + + calib_sensor.exposure.red = expr; + calib_sensor.exposure.green = expg; + calib_sensor.exposure.blue = expb; + + sanei_genesys_set_exposure(regs, calib_sensor.exposure); + + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + + DBG(DBG_info, "%s: starting first line reading\n", __func__); + RIE (gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); + RIE (sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); + RIE(gl843_stop_action_no_move(dev, ®s)); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl843_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), depth, channels, num_pixels, 1); + } + + acceptable = SANE_TRUE; + + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + acceptable = SANE_TRUE; + + if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || + avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || + avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) + acceptable = SANE_FALSE; + + if (!acceptable) + { + avga = (avg[0] + avg[1] + avg[2]) / 3; + expr = (expr * avga) / avg[0]; + expg = (expg * avga) / avg[1]; + expb = (expb * avga) / avg[2]; +/* + keep the resulting exposures below this value. + too long exposure drives the ccd into saturation. + we may fix this by relying on the fact that + we get a striped scan without shading, by means of + statistical calculation +*/ + avge = (expr + expg + expb) / 3; + + /* don't overflow max exposure */ + if (avge > 3000) + { + expr = (expr * 2000) / avge; + expg = (expg * 2000) / avge; + expb = (expb * 2000) / avge; + } + if (avge < 50) + { + expr = (expr * 50) / avge; + expg = (expg * 50) / avge; + expb = (expb * 50) / avge; + } + + } + + RIE (gl843_stop_action (dev)); + + turn++; + + } + while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, expr, expg, expb); + + sensor.exposure = calib_sensor.exposure; + + gl843_slow_back_home (dev, SANE_TRUE); + + DBG(DBG_proc, "%s: completed\n", __func__); + return status; +} + + + +/** + * average dark pixels of a 8 bits scan of a given channel + */ +static int +dark_average_channel (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black, int channel) +{ + unsigned int i, j, k, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average values on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + // FIXME: start with the second line because the black pixels often have noise on the first + // line; the cause is probably incorrectly cleaned up previous scan + for (i = 1; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j*channels + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + DBG(DBG_info, "%s: average = %d\n", __func__, avg[channel]); + return avg[channel]; +} + +/** @brief calibrate AFE offset + * Iterate doing scans at target dpi until AFE offset if correct. One + * color line is scanned at a time. Scanning head doesn't move. + * @param dev device to calibrate + */ +static SANE_Status +gl843_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + unsigned int channels, bpp; + int pass, total_size, i, resolution, lines; + int topavg[3], bottomavg[3], avg[3]; + int top[3], bottom[3], black_pixels, pixels, factor, dpihw; + + DBGSTART; + + /* offset calibration is always done in color mode */ + channels = 3; + lines = 8; + bpp = 8; + + /* compute divider factor to compute final pixels number */ + dpihw = sanei_genesys_compute_dpihw_calibration(dev, sensor, dev->settings.xres); + factor = sensor.optical_res / dpihw; + resolution = dpihw; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, + dev->settings.scan_method); + + int target_pixels = calib_sensor.sensor_pixels / factor; + int start_pixel = 0; + black_pixels = calib_sensor.black_pixels / factor; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY && + dev->model->model_id == MODEL_CANON_CANOSCAN_8600F && + dev->settings.xres == 4800) + { + start_pixel = SANE_UNFIX(dev->model->x_offset_ta); + start_pixel /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); + start_pixel = (start_pixel * calib_sensor.optical_res) / MM_PER_INCH; + + target_pixels = SANE_UNFIX(dev->model->x_size_ta); + target_pixels /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); + target_pixels = (target_pixels * calib_sensor.optical_res) / MM_PER_INCH; + } + + int flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) + { + flags |= SCAN_FLAG_USE_XPA; + } + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = start_pixel; + session.params.starty = 0; + session.params.pixels = target_pixels; + session.params.lines = lines; + session.params.depth = bpp; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = ColorFilter::RED; + session.params.flags = flags; + gl843_compute_session(dev, session, calib_sensor); + pixels = session.output_pixels; + + DBG(DBG_io, "%s: dpihw =%d\n", __func__, dpihw); + DBG(DBG_io, "%s: factor =%d\n", __func__, factor); + DBG(DBG_io, "%s: resolution =%d\n", __func__, resolution); + DBG(DBG_io, "%s: pixels =%d\n", __func__, pixels); + DBG(DBG_io, "%s: black_pixels=%d\n", __func__, black_pixels); + status = gl843_init_scan_regs(dev, calib_sensor, ®s, session); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_set_motor_power(regs, false); + + /* allocate memory for scans */ + total_size = dev->read_bytes_left; + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* init gain and offset */ + for (i = 0; i < 3; i++) + { + bottom[i] = 10; + dev->frontend.set_offset(i, bottom[i]); + dev->frontend.set_gain(i, 0); + } + RIE(gl843_set_fe(dev, calib_sensor, AFE_SET)); + + /* scan with obttom AFE settings */ + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting first line reading\n", __func__); + RIE(gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); + RIE(gl843_stop_action_no_move(dev, ®s)); + + if (DBG_LEVEL >= DBG_data) + { + char fn[40]; + snprintf(fn, 40, "gl843_bottom_offset_%03d_%03d_%03d.pnm", + bottom[0], bottom[1], bottom[2]); + sanei_genesys_write_pnm_file(fn, first_line.data(), bpp, channels, pixels, lines); + } + + for (i = 0; i < 3; i++) + { + bottomavg[i] = dark_average_channel(first_line.data(), pixels, lines, channels, black_pixels, i); + DBG(DBG_io2, "%s: bottom avg %d=%d\n", __func__, i, bottomavg[i]); + } + + /* now top value */ + for (i = 0; i < 3; i++) + { + top[i] = 255; + dev->frontend.set_offset(i, top[i]); + } + RIE(gl843_set_fe(dev, calib_sensor, AFE_SET)); + + /* scan with top AFE values */ + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size)); + RIE(gl843_stop_action_no_move(dev, ®s)); + + for (i = 0; i < 3; i++) + { + topavg[i] = dark_average_channel(second_line.data(), pixels, lines, channels, black_pixels, i); + DBG(DBG_io2, "%s: top avg %d=%d\n", __func__, i, topavg[i]); + } + + pass = 0; + + std::vector debug_image; + size_t debug_image_lines = 0; + std::string debug_image_info; + + /* loop until acceptable level */ + while ((pass < 32) + && ((top[0] - bottom[0] > 1) + || (top[1] - bottom[1] > 1) || (top[2] - bottom[2] > 1))) + { + pass++; + + /* settings for new scan */ + for (i = 0; i < 3; i++) + { + if (top[i] - bottom[i] > 1) + { + dev->frontend.set_offset(i, (top[i] + bottom[i]) / 2); + } + } + RIE(gl843_set_fe(dev, calib_sensor, AFE_SET)); + + /* scan with no move */ + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size)); + RIE(gl843_stop_action_no_move(dev, ®s)); + + if (DBG_LEVEL >= DBG_data) + { + char title[100]; + snprintf(title, 100, "lines: %d pixels_per_line: %d offsets[0..2]: %d %d %d\n", + lines, pixels, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + debug_image_info += title; + std::copy(second_line.begin(), second_line.end(), std::back_inserter(debug_image)); + debug_image_lines += lines; + } + + for (i = 0; i < 3; i++) + { + avg[i] = dark_average_channel(second_line.data(), pixels, lines, channels, black_pixels, i); + DBG(DBG_info, "%s: avg[%d]=%d offset=%d\n", __func__, i, avg[i], + dev->frontend.get_offset(i)); + } + + /* compute new boundaries */ + for (i = 0; i < 3; i++) + { + if (topavg[i] >= avg[i]) + { + topavg[i] = avg[i]; + top[i] = dev->frontend.get_offset(i); + } + else + { + bottomavg[i] = avg[i]; + bottom[i] = dev->frontend.get_offset(i); + } + } + } + + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_file("gl843_offset_all_desc.txt", + (uint8_t*) debug_image_info.data(), debug_image_info.size()); + sanei_genesys_write_pnm_file("gl843_offset_all.pnm", + debug_image.data(), bpp, channels, pixels, debug_image_lines); + } + + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/* alternative coarse gain calibration + this on uses the settings from offset_calibration and + uses only one scanline + */ +/* + with offset and coarse calibration we only want to get our input range into + a reasonable shape. the fine calibration of the upper and lower bounds will + be done with shading. + */ +static SANE_Status +gl843_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) +{ + int pixels, factor, dpihw; + int total_size; + int i, j, channels; + SANE_Status status = SANE_STATUS_GOOD; + int max[3]; + float coeff; + int val, lines; + int resolution; + int bpp; + + DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); + dpihw=sanei_genesys_compute_dpihw_calibration(dev, sensor, dpi); + factor=sensor.optical_res/dpihw; + + /* coarse gain calibration is always done in color mode */ + channels = 3; + + /* follow CKSEL */ + if (dev->model->ccd_type == CCD_KVSS080) + { + if(dev->settings.xressettings.scan_method == ScanMethod::TRANSPARENCY) + { + flags |= SCAN_FLAG_USE_XPA; + } + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, + dev->settings.scan_method); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = target_pixels; + session.params.lines = lines; + session.params.depth = bpp; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + gl843_compute_session(dev, session, calib_sensor); + pixels = session.output_pixels; + + try { + status = gl843_init_scan_regs(dev, calib_sensor, ®s, session); + } catch (...) { + try { + sanei_genesys_set_motor_power(regs, false); + } catch (...) {} + throw; + } + + sanei_genesys_set_motor_power(regs, false); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + + total_size = dev->read_bytes_left; + + std::vector line(total_size); + + RIE(gl843_set_fe(dev, calib_sensor, AFE_SET)); + RIE(gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, line.data(), total_size)); + RIE(gl843_stop_action_no_move(dev, ®s)); + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl843_gain.pnm", line.data(), bpp, channels, pixels, lines); + + /* average value on each channel */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + // FIXME: start from the second line because the first line often has artifacts. Probably + // caused by unclean cleanup of previous scans + for (i = pixels/4 + pixels; i < (pixels*3/4) + pixels; i++) + { + if(bpp==16) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * pixels + 1] * 256 + + line[i * 2 + j * 2 * pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + } + else + { + if (dev->model->is_cis) + val = line[i + j * pixels]; + else + val = line[i * channels + j]; + } + + max[j] += val; + } + max[j] = max[j] / (pixels/2); + + /* the flow of data through the frontend ADC is as follows (see e.g. VM8192 datasheet) + input + -> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) -> + -> apply gain (o = i * 208/(283-PGA[7:0]) + -> ADC + + Here we have some input data that was acquired with zero gain (PGA==0). + We want to compute gain such that the output would approach full ADC range (controlled by + gain_white_ref). + + We want to solve the following for {PGA}: + + {input} * 208 / (283 - 0) = {output} + {input} * 208 / (283 - {PGA}) = {target output} + + The solution is the following equation: + + {PGA} = 283 * (1 - {output} / {target output}) + */ + float gain = ((float) max[j] / (calib_sensor.gain_white_ref*coeff)); + int code = 283 * (1 - gain); + if (code > 255) + code = 255; + else if (code < 0) + code = 0; + dev->frontend.set_gain(j, code); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain, + code); + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + if (channels == 1) { + dev->frontend.set_gain(0, dev->frontend.get_gain(1)); + dev->frontend.set_gain(2, dev->frontend.get_gain(1)); + } + + RIE (gl843_stop_action (dev)); + + status=gl843_slow_back_home (dev, SANE_TRUE); + + DBGCOMPLETED; + return status; +} + +/* + * wait for lamp warmup by scanning the same line until difference + * between 2 scans is below a threshold + */ +static SANE_Status +gl843_init_regs_for_warmup (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + int *channels, int *total_size) +{ + int num_pixels; + SANE_Status status = SANE_STATUS_GOOD; + int dpihw; + int resolution; + int factor; + + DBGSTART; + if (dev == NULL || reg == NULL || channels == NULL || total_size == NULL) + return SANE_STATUS_INVAL; + + /* setup scan */ + *channels=3; + resolution=600; + dpihw=sanei_genesys_compute_dpihw_calibration(dev, sensor, resolution); + resolution=dpihw; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, + dev->settings.scan_method); + factor = calib_sensor.optical_res/dpihw; + num_pixels = calib_sensor.sensor_pixels/(factor*2); + *total_size = num_pixels * 3 * 1; + + *reg = dev->reg; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = num_pixels/2; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 8; + session.params.channels = *channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + gl843_compute_session(dev, session, calib_sensor); + + status = gl843_init_scan_regs(dev, calib_sensor, reg, session); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + sanei_genesys_set_motor_power(*reg, false); + RIE(dev->model->cmd_set->bulk_write_register(dev, *reg)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** + * set up GPIO/GPOE for idle state +WRITE GPIO[17-21]= GPIO19 +WRITE GPOE[17-21]= GPOE21 GPOE20 GPOE19 GPOE18 +genesys_write_register(0xa8,0x3e) +GPIO(0xa8)=0x3e + */ +static SANE_Status +gl843_init_gpio (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + int idx; + + DBGSTART; + + RIE (sanei_genesys_write_register (dev, REG6E, dev->gpo.enable[0])); + RIE (sanei_genesys_write_register (dev, REG6F, dev->gpo.enable[1])); + RIE (sanei_genesys_write_register (dev, REG6C, dev->gpo.value[0])); + RIE (sanei_genesys_write_register (dev, REG6D, dev->gpo.value[1])); + + idx=0; + while(dev->model->gpo_type != gpios[idx].gpo_type && gpios[idx].gpo_type!=0) + { + idx++; + } + if (gpios[idx].gpo_type!=0) + { + RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); + RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); + RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); + RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); + } + else + { + status=SANE_STATUS_INVAL; + } + + DBGCOMPLETED; + return status; +} + + +/* * + * initialize ASIC from power on condition + */ +static SANE_Status +gl843_boot (Genesys_Device * dev, SANE_Bool cold) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + DBGSTART; + + if(cold) + { + RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); + RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); + } + + if(dev->usb_mode == 1) + { + val = 0x14; + } + else + { + val = 0x11; + } + RIE (sanei_genesys_write_0x8c (dev, 0x0f, val)); + + /* test CHKVER */ + RIE (sanei_genesys_read_register (dev, REG40, &val)); + if (val & REG40_CHKVER) + { + RIE (sanei_genesys_read_register (dev, 0x00, &val)); + DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); + } + + /* Set default values for registers */ + gl843_init_registers (dev); + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + // turns on vref control for maximum current of the motor driver + RIE(sanei_genesys_write_register (dev, REG6B, 0x72)); + } + else + { + RIE(sanei_genesys_write_register (dev, REG6B, 0x02)); + } + + /* Write initial registers */ + RIE (dev->model->cmd_set->bulk_write_register(dev, dev->reg)); + + // Enable DRAM by setting a rising edge on bit 3 of reg 0x0b + val = dev->reg.find_reg(0x0b).value & REG0B_DRAMSEL; + val = (val | REG0B_ENBDRAM); + RIE (sanei_genesys_write_register (dev, REG0B, val)); + dev->reg.find_reg(0x0b).value = val; + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + RIE (sanei_genesys_write_0x8c (dev, 0x10, 0xc8)); + } + else + { + RIE (sanei_genesys_write_0x8c (dev, 0x10, 0xb4)); + } + + /* CLKSET */ + int clock_freq = REG0B_48MHZ; + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + clock_freq = REG0B_60MHZ; + + val = (dev->reg.find_reg(0x0b).value & ~REG0B_CLKSET) | clock_freq; + + RIE (sanei_genesys_write_register (dev, REG0B, val)); + dev->reg.find_reg(0x0b).value = val; + + /* prevent further writings by bulk write register */ + dev->reg.remove_reg(0x0b); + + if (dev->model->model_id != MODEL_CANON_CANOSCAN_8600F) + { + // set up end access + // FIXME: this is overwritten in gl843_init_gpio + sanei_genesys_write_register(dev, REGA7, 0x04); + sanei_genesys_write_register(dev, REGA9, 0x00); + } + + /* set RAM read address */ + RIE (sanei_genesys_write_register (dev, REG29, 0x00)); + RIE (sanei_genesys_write_register (dev, REG2A, 0x00)); + RIE (sanei_genesys_write_register (dev, REG2B, 0x00)); + + /* setup gpio */ + RIE (gl843_init_gpio (dev)); + + gl843_feed (dev, 300); + sanei_genesys_sleep_ms(100); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* * + * initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +static SANE_Status +gl843_init (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG_INIT (); + DBGSTART; + + status=sanei_genesys_asic_init(dev, 0); + + DBGCOMPLETED; + return status; +} + +static SANE_Status +gl843_update_hardware_sensors (Genesys_Scanner * s) +{ + /* do what is needed to get a new set of events, but try to not lose + any of them. + */ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); + + switch (s->dev->model->gpo_type) + { + case GPO_KVSS080: + s->buttons[BUTTON_SCAN_SW].write((val & 0x04) == 0); + break; + case GPO_G4050: + s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_FILE_SW].write((val & 0x02) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); + s->buttons[BUTTON_COPY_SW].write((val & 0x08) == 0); + break; + case GPO_CS4400F: + case GPO_CS8400F: + default: + break; + } + + return status; +} + +/** @brief move sensor to transparency adaptor + * Move sensor to the calibration of the transparency adapator (XPA). + * @param dev device to use + */ +static SANE_Status +gl843_move_to_ta (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + float resolution; + unsigned int feed; + + DBGSTART; + + resolution=sanei_genesys_get_lowest_ydpi(dev); + feed = 16*(SANE_UNFIX (dev->model->y_offset_calib_ta) * resolution) / MM_PER_INCH; + status = gl843_feed (dev, feed); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to move to XPA calibration area\n", __func__); + return status; + } + + DBGCOMPLETED; + return status; +} + + +/** @brief search for a full width black or white strip. + * This function searches for a black or white stripe across the scanning area. + * When searching backward, the searched area must completely be of the desired + * color since this area will be used for calibration which scans forward. + * @param dev scanner device + * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward + * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip + * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not + */ +static SANE_Status +gl843_search_strip (Genesys_Device * dev, const Genesys_Sensor& sensor, + SANE_Bool forward, SANE_Bool black) +{ + unsigned int pixels, lines, channels; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg; + size_t size; + int steps, depth, dpi; + unsigned int pass, count, found, x, y; + GenesysRegister *r; + + DBG(DBG_proc, "%s %s %s\n", __func__, black ? "black" : "white", forward ? "forward" : "reverse"); + + gl843_set_fe(dev, sensor, AFE_SET); + status = gl843_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* set up for a gray scan at lowest dpi */ + dpi = sanei_genesys_get_lowest_dpi(dev); + channels = 1; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, dpi, dev->settings.scan_method); + + /* 10 MM */ + /* lines = (10 * dpi) / MM_PER_INCH; */ + /* shading calibation is done with dev->motor.base_ydpi */ + lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; + depth = 8; + pixels = (calib_sensor.sensor_pixels * dpi) / calib_sensor.optical_res; + + dev->scanhead_position_in_steps = 0; + + local_reg = dev->reg; + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = lines; + session.params.depth = depth; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::RED; + session.params.flags = SCAN_FLAG_DISABLE_SHADING | SCAN_FLAG_DISABLE_SHADING; + gl843_compute_session(dev, session, calib_sensor); + + status = gl843_init_scan_regs(dev, calib_sensor, &local_reg, session); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + size = dev->read_bytes_left; + std::vector data(size); + + /* set up for reverse or forward */ + r = sanei_genesys_get_address(&local_reg, REG02); + if (forward) + r->value &= ~REG02_MTRREV; + else + r->value |= REG02_MTRREV; + + + status = dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl843_begin_scan(dev, calib_sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl843_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl843_stop_action failed\n", __func__); + return status; + } + + pass = 0; + if (DBG_LEVEL >= DBG_data) + { + char fn[40]; + snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); + sanei_genesys_write_pnm_file(fn, data.data(), depth, channels, pixels, lines); + } + + /* loop until strip is found or maximum pass number done */ + found = 0; + while (pass < 20 && !found) + { + status = + dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* now start scan */ + status = gl843_begin_scan(dev, calib_sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl843_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl843_stop_action failed\n", __func__); + return status; + } + + if (DBG_LEVEL >= DBG_data) + { + char fn[40]; + snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); + sanei_genesys_write_pnm_file(fn, data.data(), depth, channels, pixels, lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (pixels * lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + pass++; + } + if (found) + { + status = SANE_STATUS_GOOD; + DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); + } + else + { + status = SANE_STATUS_UNSUPPORTED; + DBG(DBG_info, "%s: %s strip not found\n", __func__, black ? "black" : "white"); + } + + DBG(DBG_proc, "%s: completed\n", __func__); + return status; +} + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +static SANE_Status +gl843_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, int size) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint32_t final_size, length, i; + uint8_t *buffer; + int count,offset; + unsigned int cksel; + GenesysRegister *r; + uint16_t dpiset, strpixel, endpixel, startx, factor; + + DBGSTART; + + offset=0; + length=size; + r = sanei_genesys_get_address(&dev->reg, REG01); + if(r->value & REG01_SHDAREA) + { + /* recompute STRPIXEL used shading calibration so we can + * compute offset within data for SHDAREA case */ + r = sanei_genesys_get_address(&dev->reg, REG18); + cksel= (r->value & REG18_CKSEL)+1; + sanei_genesys_get_double(&dev->reg,REG_DPISET,&strpixel); + sanei_genesys_get_double(&dev->reg,REG_DPISET,&dpiset); + factor=sensor.optical_res/sanei_genesys_compute_dpihw(dev, sensor, dpiset); + + /* start coordinate in optical dpi coordinates */ + startx = (sensor.dummy_pixel / cksel) / factor; + + /* current scan coordinates */ + sanei_genesys_get_double(&dev->reg,REG_STRPIXEL,&strpixel); + sanei_genesys_get_double(&dev->reg,REG_ENDPIXEL,&endpixel); + + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + int optical_res = sensor.optical_res / dev->current_setup.ccd_size_divisor; + int dpiset_real = dpiset / dev->current_setup.ccd_size_divisor; + int half_ccd_factor = optical_res / + sanei_genesys_compute_dpihw_calibration(dev, sensor, dpiset_real); + strpixel /= half_ccd_factor; + endpixel /= half_ccd_factor; + } + + /* 16 bit words, 2 words per color, 3 color channels */ + offset=(strpixel-startx)*2*2*3; + length=(endpixel-strpixel)*2*2*3; + DBG(DBG_info, "%s: STRPIXEL=%d, ENDPIXEL=%d, startx=%d\n", __func__, strpixel, endpixel, + startx); + } + + /* compute and allocate size for final data */ + final_size = ((length+251) / 252) * 256; + DBG(DBG_io, "%s: final shading size=%04x (length=%d)\n", __func__, final_size, length); + std::vector final_data(final_size, 0); + + /* copy regular shading data to the expected layout */ + buffer = final_data.data(); + count = 0; + + /* loop over calibration data */ + for (i = 0; i < length; i++) + { + buffer[count] = data[offset+i]; + count++; + if ((count % (256*2)) == (252*2)) + { + count += 4*2; + } + } + + /* send data */ + status = sanei_genesys_set_buffer_address (dev, 0); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, final_data.data(), count); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to send shading table: %s\n", __func__, sane_strstatus(status)); + } + + DBGCOMPLETED; + return status; +} + + +/** the gl843 command set */ +static Genesys_Command_Set gl843_cmd_set = { + "gl843-generic", /* the name of this set */ + + [](Genesys_Device* dev) -> bool { (void) dev; return true; }, + + gl843_init, + gl843_init_regs_for_warmup, + gl843_init_regs_for_coarse_calibration, + gl843_init_regs_for_shading, + gl843_init_regs_for_scan, + + gl843_get_filter_bit, + gl843_get_lineart_bit, + gl843_get_bitset_bit, + gl843_get_gain4_bit, + gl843_get_fast_feed_bit, + gl843_test_buffer_empty_bit, + gl843_test_motor_flag_bit, + + gl843_set_fe, + gl843_set_powersaving, + gl843_save_power, + + gl843_begin_scan, + gl843_end_scan, + + gl843_send_gamma_table, + + gl843_search_start_position, + + gl843_offset_calibration, + gl843_coarse_gain_calibration, + gl843_led_calibration, + + NULL, + gl843_slow_back_home, + NULL, + + sanei_genesys_bulk_write_register, + sanei_genesys_bulk_write_data, + sanei_genesys_bulk_read_data, + + gl843_update_hardware_sensors, + + gl843_load_document, + gl843_detect_document_end, + gl843_eject_document, + gl843_search_strip, + + sanei_genesys_is_compatible_calibration, + gl843_move_to_ta, + gl843_send_shading_data, + gl843_calculate_current_setup, + gl843_boot +}; + +SANE_Status +sanei_gl843_init_cmd_set (Genesys_Device * dev) +{ + dev->model->cmd_set = &gl843_cmd_set; + return SANE_STATUS_GOOD; +} diff --git a/backend/genesys_gl843.h b/backend/genesys_gl843.h index 4be46cc..7651cc9 100644 --- a/backend/genesys_gl843.h +++ b/backend/genesys_gl843.h @@ -43,39 +43,6 @@ #include "genesys.h" -#ifdef UNIT_TESTING -SANE_Status gl843_send_slope_table (Genesys_Device * dev, int table_nr, uint16_t * slope_table, int steps); -SANE_Status gl843_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int scan_mode, - int color_filter, - unsigned int flags); -SANE_Status gl843_start_action (Genesys_Device * dev); -SANE_Status gl843_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool start_motor); -SANE_Status gl843_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool check_stop); -SANE_Status gl843_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); -SANE_Status gl843_feed (Genesys_Device * dev, unsigned int steps); -SANE_Status gl843_init (Genesys_Device * dev); -SANE_Status gl843_boot (Genesys_Device * dev, SANE_Bool cold); -SANE_Status gl843_send_shading_data (Genesys_Device * dev, uint8_t * data, int size); -SANE_Status gl843_bulk_write_register (Genesys_Device * dev, Genesys_Register_Set * reg, size_t elems); -SANE_Status gl843_xpa_lamp_on (Genesys_Device * dev); -SANE_Status gl843_xpa_motor_on (Genesys_Device * dev); -SANE_Status gl843_xpa_motor_off (Genesys_Device * dev); -SANE_Status gl843_move_to_ta (Genesys_Device * dev); -#endif - -#define DBGSTART DBG (DBG_proc, "%s start\n", __func__); -#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __func__); - #define REG01 0x01 #define REG01_CISSET 0x80 #define REG01_DOGENB 0x40 @@ -415,154 +382,7 @@ SANE_Status gl843_move_to_ta (Genesys_Device * dev); #define SCAN_FLAG_DISABLE_LAMP 0x040 #define SCAN_FLAG_DYNAMIC_LINEART 0x080 -/** - * writable scanner registers */ -enum -{ - reg_0x01 = 0, - reg_0x02, - reg_0x03, - reg_0x04, - reg_0x05, - reg_0x06, - reg_0x08, - reg_0x09, - reg_0x0a, - reg_0x0b, - reg_0x0c, - reg_0x0f, - reg_0x10, - reg_0x11, - reg_0x12, - reg_0x13, - reg_0x14, - reg_0x15, - reg_0x16, - reg_0x17, - reg_0x18, - reg_0x19, - reg_0x1a, - reg_0x1b, - reg_0x1c, - reg_0x1d, - reg_0x1e, - reg_0x1f, - reg_0x20, - reg_0x21, - reg_0x22, - reg_0x23, - reg_0x24, - reg_0x25, - reg_0x26, - reg_0x27, - reg_0x28, - reg_0x2c, - reg_0x2d, - reg_0x2e, - reg_0x2f, - reg_0x30, - reg_0x31, - reg_0x32, - reg_0x33, - reg_0x34, - reg_0x35, - reg_0x36, - reg_0x37, - reg_0x38, - reg_0x39, - reg_0x3a, - reg_0x3b, - reg_0x3c, - reg_0x3d, - reg_0x3e, - reg_0x3f, - reg_0x51, - reg_0x52, - reg_0x53, - reg_0x54, - reg_0x55, - reg_0x56, - reg_0x57, - reg_0x58, - reg_0x59, - reg_0x5a, - reg_0x5d, - reg_0x5e, - reg_0x5f, - reg_0x60, - reg_0x61, - reg_0x62, - reg_0x63, - reg_0x64, - reg_0x65, - reg_0x67, - reg_0x68, - reg_0x69, - reg_0x6a, - reg_0x6b, - reg_0x70, - reg_0x71, - reg_0x72, - reg_0x73, - reg_0x74, - reg_0x75, - reg_0x76, - reg_0x77, - reg_0x78, - reg_0x79, - reg_0x7a, - reg_0x7b, - reg_0x7c, - reg_0x7d, - reg_0x7e, - reg_0x7f, - reg_0x80, - reg_0x81, - reg_0x82, - reg_0x83, - reg_0x84, - reg_0x85, - reg_0x86, - reg_0x87, - reg_0x88, - reg_0x89, - reg_0x8a, - reg_0x8b, - reg_0x8c, - reg_0x8d, - reg_0x8e, - reg_0x8f, - reg_0x90, - reg_0x91, - reg_0x92, - reg_0x93, - reg_0x94, - reg_0x95, - reg_0x96, - reg_0x97, - reg_0x98, - reg_0x99, - reg_0x9a, - reg_0x9b, - reg_0x9c, - reg_0x9d, - reg_0x9e, - reg_0xa0, - reg_0xa1, - reg_0xa2, - reg_0xa3, - reg_0xa4, - reg_0xa5, - reg_0xaa, - reg_0xab, - reg_0xac, - reg_0xad, - reg_0xae, - reg_0xaf, - GENESYS_GL843_MAX_REGS -}; - -#define SETREG(adr,val) {dev->reg[reg_##adr].address=adr;dev->reg[reg_##adr].value=val;} +#define SETREG(adr,val) { dev->reg.init_reg(adr, val); } typedef struct { @@ -590,84 +410,15 @@ static Gpio_layout gpios[]={ { GPO_CS8400F, 0x00, 0x03, 0x00, 0x02 }, + { + GPO_CS8600F, 0x00, 0xff, 0x00, 0x00, + }, /* end marker */ { 0, 0, 0, 0, 0 }, }; -/** @brief structure for sensor settings - * this structure describes the sensor settings to use for a given - * exposure. - */ -typedef struct { - int sensor_type; /**> sensor id */ - int dpi; /**> maximum dpi for which data are valid */ - int exposure; /**> exposure */ - int ck1map; /**> CK1MAP */ - int ck3map; /**> CK2MAP */ - int ck4map; /**> CK3MAP */ - int segcnt; /**> SEGCNT */ - int tg0cnt; /**> TG0CNT */ - int expdummy; /**> exposure dummy */ - int expr; /**> initial red exposure */ - int expg; /**> initial green exposure */ - int expb; /**> initial blue exposure */ - uint8_t reg0c; /**> register 0x0c value */ - uint8_t reg70; /**> register 0x70 value */ - uint8_t reg71; /**> register 0x71 value */ - uint8_t reg9e; /**> register 0x9e value */ - uint8_t regaa; /**> either undocumented or mapping to somewhere else */ - uint8_t regs_0x10_0x1d[14]; - uint8_t regs_0x52_0x5e[13]; -} Sensor_Profile; - -/** - * database of sensor profiles - */ -static Sensor_Profile xpa_sensors[]={ - {CCD_G4050 , 600, 15624, 0x001c7f, 0x03ffff, 0x03ffff, 5168, 0, 0x2a, 0, 0, 0, 0x00, 0x00, 0x02, 0x00, 0x00, - {0x2c, 0x09, 0x22, 0xb8, 0x10, 0xf0, 0x33, 0x4c, 0x01, 0x2a, 0x30, 0x00, 0x00, 0x08} , - {0x0e, 0x11, 0x02, 0x05, 0x08, 0x0b, 0x6b, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x6f}, - }, -}; -static Sensor_Profile sensors[]={ - /* 0c 70 71 9e aa*/ - {CCD_KVSS080, 600, 8000, 0x000000, 0x00ffff, 0x03ffff, 5168, 0, 0x2a, 0, 0, 0, 0x00, 0x01, 0x03, 0x00, 0x00, - /* 10 11 12 13 14 15 16 17 18 19 1a 1b 1c 1d */ - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x1c, 0x00, 0x2a, 0x2c, 0x00, 0x20, 0x04} , - /* 52 53 54 55 56 57 58 59 5a 5b 5c 5d 5e */ - {0x0c, 0x0f, 0x00, 0x03, 0x06, 0x09, 0x6b, 0x00, 0xc0, 0x00, 0x00, 0x00, 0x23}, - }, - - {CCD_G4050 , 600, 8016, 0x0001ff, 0x03ffff, 0x03ffff, 5168, 0, 0x2a, 0, 0, 0, 0x00, 0x00, 0x02, 0x00, 0x00, - {0x2c, 0x09, 0x22, 0xb8, 0x10, 0xf0, 0x33, 0x0c, 0x00, 0x2a, 0x30, 0x00, 0x00, 0x08} , - {0x0b, 0x0e, 0x11, 0x02, 0x05, 0x08, 0x63, 0x00, 0x40, 0x00, 0x00, 0x00, 0x63}, - }, - - {CCD_G4050 , 1200, 56064, 0x0fffff, 0x0001ff, 0x0001ff, 5168, 0, 0x2a, 0, 0, 0, 0x20, 0x08, 0x0c, 0xc0, 0x05, - {0x2c, 0x09, 0x22, 0xb8, 0x10, 0xf0, 0x3b, 0x0c, 0x10, 0x2a, 0x38, 0x10, 0x00, 0x08} , - {0x02, 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x1b, 0x00, 0x40, 0x00, 0x00, 0x00, 0x63}, - }, - - {CCD_G4050 , 2400, 56064, 0x0fffff, 0x000000, 0x000000, 5168, 0, 0x2a, 0, 0, 0, 0x20, 0x08, 0x0a, 0xc0, 0x05, - {0x2c, 0x09, 0x22, 0xb8, 0x10, 0xf0, 0x3b, 0x0c, 0x10, 0x2a, 0x38, 0x10, 0xc0, 0x08} , - {0x02, 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x1b, 0x00, 0x40, 0x00, 0x00, 0x00, 0x63}, - }, - - {CCD_G4050 , 4800, 42752, 0x0fffff, 0x000000, 0x000000, 5168, 0, 0x2a, 0, 0, 0, 0x21, 0x08, 0x0a, 0xc0, 0x07, - {0x2c, 0x09, 0x22, 0xb8, 0x10, 0xf0, 0x3b, 0x0c, 0x10, 0x2a, 0x38, 0x10, 0xc1, 0x08} , - {0x02, 0x05, 0x08, 0x0b, 0x0e, 0x11, 0x1b, 0x00, 0x40, 0x00, 0x00, 0x00, 0x63}, - }, - {CCD_CS4400F, 600, 11640, 0xf838, 0xfc00, 0x92a4, 5168, 0, 0x2a, 0x9c40, 0x9c40, 0x9c40, 0x00, 0x00, 0x02, 0x2d, 0x00, - {0x9c, 0x40, 0x9c, 0x40, 0x9c, 0x40, 0x13, 0x0a, 0x10, 0x2a, 0x30, 0x00, 0x00, 0x6b}, - {0x0a, 0x0d, 0x00, 0x03, 0x06, 0x08, 0x5b, 0x00, 0x40, 0x00, 0x00, 0x00, 0x3f}, - }, - {CCD_CS8400F, 600, 7200, 0x0e3f, 0x0000, 0x1b6db, 5168, 0, 0x2a, 0x0, 0x0, 0x0, 0x00, 0x01, 0x02, 0x00, 0x00, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x0c, 0x13, 0x2a, 0x30, 0x00, 0x00, 0x84}, - {0x0d, 0x10, 0x01, 0x04, 0x07, 0x0a, 0x6b, 0x00, 0x40, 0x00, 0x00, 0x00, 0x85}, - } -}; static uint32_t kvss080[]={44444, 34188, 32520, 29630, 26666, 24242, 22222, 19048, 16666, 15686, 14814, 14034, 12402, 11110, 8888, 7618, 6666, 5926, 5228, 4678, 4172, 3682, 3336, 3074, 2866, 2702, 2566, 2450, 2352, 2266, 2188, 2118, 2056, 2002, 1950, 1904, 1860, 1820, 1784, 1748, 1716, 1684, 1656, 1628, 1600, 1576, 1552, 1528, 1506, 1486, 1466, 1446, 1428, 1410, 1394, 1376, 1360, 1346, 1330, 1316, 1302, 1288, 1276, 1264, 1250, 1238, 1228, 1216, 1206, 1194, 1184, 1174, 1164, 1154, 1146, 1136, 1128, 1120, 1110, 1102, 1094, 1088, 1080, 1072, 1064, 1058, 1050, 1044, 1038, 1030, 1024, 1018, 1012, 1006, 1000, 994, 988, 984, 978, 972, 968, 962, 958, 952, 948, 942, 938, 934, 928, 924, 920, 916, 912, 908, 904, 900, 896, 892, 888, 884, 882, 878, 874, 870, 868, 864, 860, 858, 854, 850, 848, 844, 842, 838, 836, 832, 830, 826, 824, 822, 820, 816, 814, 812, 808, 806, 804, 802, 800, 796, 794, 792, 790, 788, 786, 784, 782, 778, 776, 774, 772, 770, 768, 766, 764, 762, 760, 758, 756, 754, 752, 750, 750, 748, 746, 744, 742, 740, 738, 736, 734, 734, 732, 730, 728, 726, 724, 724, 722, 720, 718, 716, 716, 714, 712, 710, 710, 708, 706, 704, 704, 702, 700, 698, 698, 696, 694, 694, 692, 690, 690, 688, 686, 686, 684, 682, 682, 680, 678, 678, 676, 674, 674, 672, 672, 670, 668, 668, 666, 666, 664, 662, 662, 660, 660, 658, 656, 656, 654, 654, 652, 652, 650, 650, 648, 646, 646, 644, 644, 642, 642, 640, 640, 638, 638, 636, 636, 636, 634, 634, 632, 632, 630, 630, 628, 628, 626, 626, 624, 624, 624, 622, 622, 620, 620, 618, 618, 618, 616, 616, 614, 614, 612, 612, 612, 610, 610, 608, 608, 608, 606, 606, 606, 604, 604, 602, 602, 602, 600, 600, 600, 598, 598, 596, 596, 596, 594, 594, 594, 592, 592, 592, 590, 590, 590, 588, 588, 588, 586, 586, 586, 584, 584, 584, 582, 582, 582, 590, 590, 590, 588, 588, 588, 586, 586, 586, 584, 584, 584, 582, 582, 582, 580, 580, 580, 578, 578, 578, 576, 576, 576, 576, 574, 574, 574, 572, 572, 572, 570, 570, 570, 568, 568, 568, 568, 566, 566, 566, 564, 564, 564, 562, 562, 562, 562, 560, 560, 560, 558, 558, 558, 558, 556, 556, 556, 554, 554, 554, 552, 552, 552, 552, 550, 550, 550, 548, 548, 548, 548, 546, 546, 546, 546, 544, 544, 544, 542, 542, 542, 542, 540, 540, 540, 538, 538, 538, 538, 536, 536, 536, 536, 534, 534, 534, 534, 532, 532, 532, 530, 530, 530, 530, 528, 528, 528, 528, 526, 526, 526, 526, 524, 524, 524, 524, 522, 522, 522, 522, 520, 520, 520, 520, 518, 518, 518, 516, 516, 516, 516, 514, 514, 514, 514, 514, 512, 512, 512, 512, 510, 510, 510, 510, 508, 508, 508, 508, 506, 506, 506, 506, 504, 504, 504, 504, 502, 502, 502, 502, 500, 500, 500, 500, 0}; static uint32_t g4050_fast[]={7842,5898,4384,4258,4152,4052,3956,3864,3786,3714,3632,3564,3498,3444,3384,3324,3276,3228,3174,3128,3086,3044,3002,2968,2930,2892,2860,2824,2794,2760,2732,2704,2676,2650,2618,2594,2568,2548,2524,2500,2478,2454,2436,2414,2392,2376,2354,2338,2318,2302,2282,2266,2252,2232,2218,2202,2188,2174,2160,2142,2128,2116,2102,2088,2076,2062,2054,2040,2028,2020,2014,2008,2004,2002,2002,2002,1946,1882,1826,1770,1716,1662,1612,1568,1526,1488,1454,1422,1390,1362,1336,1310,1288,1264,1242,1222,1204,1184,1166,1150,1134,1118,1104,1090,1076,1064,1050,1038,1026,1016,1004,994,984,972,964,954,944,936,928,920,910,902,896,888,880,874,866,860,854,848,840,834,828,822,816,812,806,800,796,790,784,780,776,770,766,760,756,752,748,744,740,736,732,728,724,720,716,712,708,704,702,698,694,690,688,684,682,678,674,672,668,666,662,660,656,654,650,648,646,644,640,638,636,632,630,628,624,622,620,618,616,614,610,608,606,604,602,600,598,596,594,592,590,588,586,584,582,580,578,576,574,572,570,568,566,564,564,562,560,558,556,554,552,552,550,548,546,546,544,542,540,538,538,536,534,532,532,530,528,528,526,524,522,522,520,518,518,516,514,514,512,512,510,508,508,506,504,504,502,502,500,498,498,496,496,494,494,492,490,490,488,488,486,486,484,484,482,480,480,478,478,476,476,474,474,472,472,470,470,468,468,468,466,466,464,464,462,462,460,460,458,458,456,456,456,454,454,452,452,450,450,450,448,448,446,446,444,444,444,442,442,440,440,440,438,438,438,436,436,434,434,434,432,432,432,430,430,428,428,428,426,426,426,424,424,424,422,422,422,420,420,420,418,418,418,416,416,416,414,414,414,412,412,412,410,410,410,408,408,408,406,406,406,404,404,404,404,402,402,402,400,400,400,400,398,398,398,396,396,396,396,394,394,394,392,392,392,392,390,390,390,388,388,388,388,386,386,386,386,384,384,384,384,382,382,382,382,380,380,380,380,378,378,378,378,376,376,376,376,376,374,374,374,374,374,372,372,372,372,372,370,370,370,370,370,368,368,368,368,368,366,366,366,366,366,364,364,364,364,364,364,362,362,362,362,362,360,360,360,360,360,360,358,358,358,358,358,358,356,356,356,356,356,356,354,354,354,354,354,352,352,352,352,352,352,350,350,350,350,350,350,350,348,348,348,348,348,348,346,346,346,346,346,346,344,344,344,344,344,344,344,342,342,342,342,342,342,340,340,340,340,340,340,340,338,338,338,338,338,338,338,336,336,336,336,336,336,336,334,334,334,334,334,334,334,332,332,332,332,332,332,332,332,330,330,330,330,330,330,330,328,328,328,328,328,328,328,328,326,326,326,326,326,326,326,324,324,324,324,324,324,324,324,322,322,322,322,322,322,322,322,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320, 0}; @@ -676,12 +427,35 @@ static uint32_t g4050_max[]={42752,42752,42752,42752,42752,42752,42752,42752, 41 static uint32_t g4050_xpa[]={9422,5978,4736,4028,3560,3220,2914,2756,2588,2448,2328,2224,2132,2052,1978,1914,1854,1800,1752,1706,1664,1626,1588,1554,1522,1492,1464,1438,1412,1388,1366,1344,1324,1304,1284,1268,1250,1232,1218,1202,1188,1172,1160,1146,1134,1120,1110,1098,1086,1076,1066,1056,1046,1036,1026,1018,1008,1000,992,984,976,968,960,952,946,938,932,924,918,912,906,898,892,888,882,876,870,864,860,854,848,844,838,834,828,824,820,814,810,806,802,798,794,790,786,782,778,774,770,766,762,758,754,752,748,744,740,738,734,730,728,724,722,718,716,712,710,706,704,700,698,696,692,690,686,684,682,678,676,674,672,668,666,664,662,660,656,654,652,650,648,646,644,642,638,636,634,632,630,628,626,624,622,620,618,616,614,612,612,610,608,606,604,602,600,598,596,594,594,592,590,588,586,584,584,582,580,578,576,576,574,572,570,570,568,566,564,564,562,560,560,558,556,554,554,552,550,550,548,546,546,544,542,542,540,540,538,536,536,534,532,532,530,530,528,526,526,524,524,522,522,520,518,518,516,516,514,514,512,512,510,508,508,506,506,504,504,502,502,500,500,498,498,496,496,494,494,492,492,492,490,490,488,488,486,486,484,484,482,482,480,480,480,478,478,476,476,474,474,474,472,472,470,470,468,468,468,466,466,464,464,464,462,462,462,460,460,458,458,458,456,456,454,454,454,452,452,452,450,450,450,448,448,446,446,446,444,444,444,442,442,442,440,440,440,438,438,438,436,436,436,434,434,434,432,432,432,430,430,430,430,428,428,428,426,426,426,424,424,424,424,422,422,422,420,420,420,418,418,418,418,416,416,416,414,414,414,414,412,412,412,412,410,410,410,408,408,408,408,406,406,406,406,404,404,404,404,402,402,402,402,400,400,400,400,398,398,398,398,396,396,396,396,394,394,394,394,392,392,392,392,392,390,390,390,390,388,388,388,388,386,386,386,386,386,384,384,384,384,384,382,382,382,382,380,380,380,380,380,378,378,378,378,378,376,376,376,376,376,374,374,374,374,374,372,372,372,372,372,370,370,370,370,370,368,368,368,368,368,366,366,366,366,366,364,364,364,364,364,364,362,362,362,362,362,360,360,360,360,360,360,358,358,358,358,358,358,356,356,356,356,356,354,354,354,354,354,354,352,352,352,352,352,352,350,350,350,350,350,350,350,348,348,348,348,348,348,346,346,346,346,346,346,344,344,344,344,344,344,344,342,342,342,342,342,342,340,340,340,340,340,340,340,338,338,338,338,338,338,338,336,336,336,336,336,336,336,334,334,334,334,334,334,334,332,332,332,332,332,332,332,330,330,330,330,330,330,330,330,328,328,328,328,328,328,328,326,326,326,326,326,326,326,326,324,324,324,324,324,324,324,324,322,322,322,322,322,322,322,322,320,320,320,320,320,320,320,320,318,318,318,318,318,318,318,318,318,316,316,316,316,316,316,316,316,314,314,314,314,314,314,314,314,314,312,312,312,312,312,312,312,312,312,310,310,310,310,310,310,310,310,310,308,308,308,308,308,308,308,308,308,306,306,306,306,306,306,306,306,306,306,304,304,304,304,304,304,304,304,304,302,302,302,302,302,302,302,302,302,302,300,300,300,300,300,300,300,300,300,300,298,298,298,298,298,298,298,298,298,298,298,296,296,296,296,296,296,296,296,296,296,294,294,294,294,294,294,294,294,294,294,294,292,292,292,292,292,292,292,292,292,292,292,290,290,290,290,290,290,290,290,290,290,290,288,288,288,288,288,288,288,288,288,288,288,288,286,286,286,286,286,286,286,286,286,286,286,286,284,284,284,284,284,284,284,284,284,284,284,284,282,282,282,282,282,282,282,282,282,282,282,282,280,280,280,280,280,280,280,280,280,280,280,280,280,278,278,278,278,278,278,278,278,278,278,278,278,278,276,276,276,276,276,276,276,276,276,276,276,276,276,274,274,274,274,274,274,274,274,274,274,274,274,274,274,272,272,272,272,272,272,272,272,272,272,272,272,272,272,270,270,270,270,270,270,270,270,270,270,270,270,270,270,268,268,268,268,268,268,268,268,268,268,268,268,268,268,268,266,266,266,266,266,266,266,266,266,266,266,266,266,266,266,264,264,264,264,264,264,264,264,264,264,264,264,264,264,264,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,260,260,260,260,260,260,260,260,260,260,260,260,260,260,260,260,258,258,258,258,258,258,258,258,258,258,258,258,258,258,258,258,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,0}; static uint32_t cs4400f_fast[]={49152, 49152, 31144, 23652, 19538, 16822, 14908, 13442, 12288, 11356, 10590, 9922, 9362, 8886, 8456, 8064, 7728, 7418, 7148, 6882, 6664, 6446, 6252, 6060, 5890, 5740, 5586, 5450, 5322, 5198, 5080, 4968, 4868, 4766, 4674, 4584, 4500, 4418, 4338, 4262, 4194, 4122, 4058, 3996, 3932, 3874, 3816, 3766, 3712, 3662, 3610, 3566, 3518, 3474, 3430, 3388, 3350, 3310, 3272, 3236, 3200, 3164, 3130, 3096, 3062, 3032, 3000, 2972, 2942, 2914, 2884, 2858, 2832, 2806, 2780, 2756, 2732, 2708, 2686, 2662, 2640, 2618, 2596, 2576, 2554, 2536, 2516, 2496, 2478, 2458, 2440, 2422, 2404, 2388, 2370, 2354, 2338, 2320, 2306, 2290, 2276, 2258, 2244, 2230, 2216, 2202, 2188, 2174, 2162, 2148, 2134, 2122, 2108, 2096, 2084, 2072, 2060, 2048, 2036, 2026, 2014, 2002, 1992, 1982, 1970, 1960, 1950, 1940, 1928, 1920, 1908, 1900, 1890, 1880, 1872, 1862, 1852, 1844, 1834, 1826, 1818, 1808, 1800, 1792, 1784, 1776, 1768, 1760, 1752, 1742, 1736, 1728, 1720, 1712, 1704, 1698, 1690, 1684, 1676, 1670, 1662, 1656, 1648, 1642, 1634, 1628, 1622, 1616, 1608, 1602, 1596, 1590, 1584, 1578, 1572, 1566, 1560, 1554, 1548, 1542, 1536, 1532, 1526, 1520, 1514, 1508, 1504, 1498, 1492, 1488, 1482, 1478, 1472, 1466, 1462, 1456, 1452, 1446, 1442, 1438, 1432, 1428, 1424, 1418, 1414, 1410, 1404, 1400, 1396, 1390, 1386, 1382, 1378, 1374, 1370, 1364, 1360, 1356, 1352, 1348, 1344, 1340, 1336, 1332, 1328, 1324, 1320, 1316, 1312, 1308, 1304, 1302, 1298, 1294, 1290, 1286, 1282, 1278, 1276, 1272, 1268, 1264, 1262, 1258, 1254, 1250, 1248, 1244, 1240, 1238, 1234, 1230, 1228, 1224, 1222, 1218, 1214, 1212, 1208, 1206, 1202, 1200, 1196, 1194, 1190, 1186, 1184, 1182, 1178, 1176, 1172, 1170, 1166, 1164, 1162, 1158, 1156, 1152, 1150, 1148, 1144, 1142, 1138, 1136, 1134, 1130, 1128, 1126, 1122, 1120, 1118, 1116, 1112, 1110, 1108, 1106, 1102, 1100, 1098, 1096, 1092, 1090, 1088, 1086, 1082, 1080, 1078, 1076, 1074, 1072, 1068, 1066, 1064, 1062, 1060, 1058, 1056, 1054, 1052, 1048, 1046, 1044, 1042, 1040, 1038, 1036, 1034, 1032, 1030, 1028, 1026, 1024, 1022, 1020, 1018, 1016, 1014, 1012, 1010, 1008, 1006, 1004, 1002, 1000, 998, 996, 994, 992, 990, 988, 986, 984, 982, 980, 978, 976, 974, 972, 972, 970, 968, 966, 964, 962, 960, 958, 956, 956, 954, 952, 950, 948, 946, 944, 944, 942, 940, 938, 936, 934, 934, 932, 930, 928, 926, 926, 924, 922, 920, 918, 918, 916, 914, 912, 912, 910, 908, 906, 904, 904, 902, 900, 898, 898, 896, 894, 892, 892, 890, 888, 888, 886, 884, 882, 882, 880, 878, 878, 876, 874, 874, 872, 870, 868, 868, 866, 864, 864, 862, 860, 860, 858, 856, 856, 854, 852, 852, 850, 848, 848, 846, 846, 844, 842, 842, 840, 838, 838, 836, 834, 834, 832, 832, 830, 828, 828, 826, 826, 824, 822, 822, 820, 820, 818, 816, 816, 814, 814, 812, 812, 810, 808, 808, 806, 806, 804, 802, 802, 800, 800, 798, 798, 796, 796, 794, 792, 792, 790, 790, 788, 788, 786, 786, 784, 784, 782, 782, 780, 780, 778, 778, 776, 774, 774, 772, 772, 770, 770, 768, 768, 766, 766, 764, 764, 762, 762, 760, 760, 758, 758, 758, 756, 756, 754, 754, 752, 752, 750, 750, 748, 748, 746, 746, 744, 744, 742, 742, 740, 740, 738, 738, 738, 736, 736, 734, 734, 732, 732, 730, 730, 730, 728, 728, 726, 726, 724, 724, 722, 722, 722, 720, 720, 718, 718, 718, 716, 716, 714, 714, 712, 712, 712, 710, 710, 708, 708, 708, 706, 706, 704, 704, 702, 702, 702, 700, 700, 698, 698, 698, 696, 696, 694, 694, 694, 692, 692, 692, 690, 690, 688, 688, 688, 686, 686, 684, 684, 684, 682, 682, 682, 680, 680, 680, 678, 678, 676, 676, 676, 674, 674, 674, 672, 672, 670, 670, 670, 668, 668, 668, 666, 666, 666, 664, 664, 664, 662, 662, 660, 660, 660, 658, 658, 658, 656, 656, 656, 654, 654, 654, 652, 652, 652, 650, 650, 650, 648, 648, 648, 646, 646, 646, 644, 644, 644, 642, 642, 642, 640, 640, 640, 640, 638, 638, 638, 636, 636, 636, 634, 634, 634, 632, 632, 632, 630, 630, 630, 630, 628, 628, 628, 626, 626, 626, 624, 624, 624, 624, 622, 622, 622, 620, 620, 620, 618, 618, 618, 618, 616, 616, 616, 614, 614, 614, 614, 612, 612, 612, 610, 610, 610, 610, 608, 608, 608, 606, 606, 606, 606, 604, 604, 604, 604, 602, 602, 602, 600, 600, 600, 600, 598, 598, 598, 598, 596, 596, 596, 594, 594, 594, 594, 592, 592, 592, 592, 590, 590, 590, 590, 588, 588, 588, 586, 586, 586, 586, 584, 584, 584, 584, 582, 582, 582, 582, 580, 580, 580, 580, 578, 578, 578, 578, 576, 576, 576, 576, 574, 574, 574, 574, 574, 572, 572, 572, 572, 570, 570, 570, 570, 568, 568, 568, 568, 566, 566, 566, 566, 564, 564, 564, 564, 564, 562, 562, 562, 562, 560, 560, 560, 560, 558, 558, 558, 558, 558, 556, 556, 556, 556, 554, 554, 554, 554, 554, 552, 552, 552, 552, 550, 550, 550, 550, 550, 548, 548, 548, 548, 546, 546, 546, 546, 546, 544, 544, 544, 544, 544, 542, 542, 542, 542, 540, 540, 540, 540, 540, 538, 538, 538, 538, 538, 536, 536, 536, 536, 536, 534, 534, 534, 534, 534, 532, 532, 532, 532, 532, 530, 530, 530, 530, 530, 528, 528, 528, 528, 528, 526, 526, 526, 526, 526, 524, 524, 524, 524, 524, 522, 522, 522, 522, 522, 520, 520, 520, 520, 520, 520, 518, 518, 518, 518, 518, 516, 516, 516, 516, 516, 514, 514, 514, 514, 514, 514, 512, 512, 512, 512, 512, 510, 510, 510, 510, 510, 510, 508, 508, 508, 508, 508, 506, 506, 506, 506, 506, 506, 504, 504, 504, 504, 504, 502, 502, 502, 502, 502, 502, 500, 500, 500, 500, 500, 500, 498, 498, 498, 498, 498, 498, 496, 496, 496, 496, 496, 496, 494, 494, 494, 494, 494, 494, 492, 492, 492, 492, 492, 492, 490, 490, 490, 490, 490, 490, 488, 488, 488, 488, 488, 488, 486, 486, 486, 486, 486, 486, 484, 484, 484, 484, 484, 484, 484, 0, 0, 0, 0, 0}; static uint32_t cs8400f_fast[]={8743, 8205, 7017, 6201, 4938, 4016, 3371, 2966, 2682, 2469, 2296, 2159, 2041, 1942, 1857, 1782, 1716, 1656, 1602, 1554, 1510, 1470, 1432, 1398, 1366, 1336, 1309, 1282, 1258, 1235, 1213, 1193, 1173, 1154, 1137, 1120, 1104, 1089, 1074, 1060, 1047, 1034, 1022, 1010, 998, 987, 976, 966, 956, 946, 937, 928, 919, 911, 902, 894, 887, 879, 872, 864, 858, 851, 844, 838, 832, 825, 819, 814, 808, 802, 797, 792, 786, 781, 776, 771, 766, 762, 757, 753, 748, 744, 740, 736, 731, 728, 724, 720, 716, 712, 709, 705, 701, 698, 695, 691, 688, 685, 682, 679, 675, 672, 669, 666, 664, 661, 658, 655, 652, 650, 647, 644, 642, 639, 637, 634, 632, 629, 627, 625, 622, 620, 618, 616, 613, 611, 609, 607, 605, 603, 601, 599, 597, 595, 593, 591, 589, 587, 585, 583, 581, 580, 578, 576, 574, 573, 571, 569, 567, 566, 564, 563, 561, 559, 558, 556, 555, 553, 552, 550, 549, 547, 546, 544, 543, 542, 540, 539, 537, 536, 535, 533, 532, 531, 529, 528, 527, 526, 524, 523, 522, 521, 519, 518, 517, 516, 515, 514, 512, 511, 510, 509, 508, 507, 506, 505, 504, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 488, 487, 486, 485, 484, 483, 482, 481, 480, 479, 478, 477, 477, 476, 475, 474, 473, 472, 472, 471, 470, 469, 468, 467, 467, 466, 465, 464, 464, 463, 462, 461, 460, 460, 459, 458, 457, 457, 456, 455, 454, 454, 453, 452, 452, 451, 450, 449, 449, 448, 448, 447, 446, 446, 445, 444, 444, 443, 442, 442, 441, 440, 440, 439, 438, 438, 437, 437, 436, 435, 435, 434, 434, 433, 432, 432, 431, 431, 430, 429, 429, 428, 428, 427, 427, 426, 425, 425, 424, 424, 423, 423, 422, 422, 421, 421, 420, 420, 419, 419, 418, 417, 417, 416, 416, 416, 415, 414, 414, 414, 413, 412, 412, 412, 411, 411, 410, 410, 409, 409, 408, 408, 407, 407, 406, 406, 406, 405, 405, 404, 404, 403, 403, 402, 402, 402, 401, 401, 400, 400, 399, 399, 398, 398, 398, 397, 397, 396, 396, 396, 395, 395, 394, 394, 394, 393, 393, 392, 392, 392, 391, 391, 391, 390, 390, 389, 389, 389, 388, 388, 387, 387, 387, 386, 386, 385, 385, 385, 384, 384, 384, 383, 383, 383, 382, 382, 382, 381, 381, 381, 380, 380, 380, 379, 379, 379, 378, 378, 378, 377, 377, 377, 376, 376, 376, 375, 375, 375, 374, 374, 374, 373, 373, 373, 372, 372, 372, 371, 371, 371, 370, 370, 370, 370, 369, 369, 369, 368, 368, 368, 368, 367, 367, 367, 367, 366, 366, 366, 365, 365, 365, 365, 364, 364, 364, 363, 363, 363, 363, 362, 362, 362, 362, 361, 361, 361, 360, 360, 360, 360, 359, 359, 359, 358, 358, 358, 358, 357, 357, 357, 356, 356, 356, 356, 355, 355, 355, 355, 354, 354, 354, 354, 354, 353, 353, 353, 353, 352, 352, 352, 352, 352, 351, 351, 351, 351, 350, 350, 350, 350, 350, 349, 349, 349, 349, 348, 348, 348, 348, 348, 347, 347, 347, 347, 346, 346, 346, 346, 346, 345, 345, 345, 345, 344, 344, 344, 344, 344, 343, 343, 343, 343, 342, 342, 342, 342, 342, 341, 341, 341, 341, 340, 340, 340, 340, 340, 339, 339, 339, 339, 338, 338, 338, 338, 338, 337, 337, 337, 337, 337, 337, 336, 336, 336, 336, 336, 336, 335, 335, 335, 335, 335, 335, 334, 334, 334, 334, 334, 334, 333, 333, 333, 333, 333, 333, 332, 332, 332, 332, 332, 332, 331, 331, 331, 331, 331, 331, 330, 330, 330, 330, 330, 330, 329, 329, 329, 329, 329, 329, 328, 328, 328, 328, 328, 328, 327, 327, 327, 327, 327, 327, 326, 326, 326, 326, 326, 326, 325, 325, 325, 325, 325, 325, 324, 324, 324, 324, 324, 324, 323, 323, 323, 323, 323, 323, 322, 322, 322, 322, 322, 322, 321, 321, 321, 321, 321, 321, 320, 320, 320, 320, 320, 320, 319, 319, 319, 319, 319, 319, 318, 318, 318, 318, 318, 318, 317, 317, 317, 317, 317, 317, 316, 316, 316, 316, 316, 316, 315, 315, 315, 315, 315, 315, 314, 314, 314, 314, 314, 314, 313, 313, 313, 313, 313, 313, 312, 312, 312, 312, 312, 312, 311, 311, 311, 311, 311, 311, 310, 310, 310, 310, 310, 310, 309, 309, 309, 309, 309, 309, 308, 308, 308, 308, 308, 308, 307, 307, 307, 307, 307, 307, 306, 306, 306, 306, 306, 306, 305, 305, 305, 305, 305, 305, 304, 304, 304, 304, 304, 304, 303, 303, 303, 303, 303, 303, 302, 302, 302, 302, 302, 302, 302, 301, 301, 301, 301, 301, 301, 301, 301, 301, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 0, 0, 0, 0, 0 }; +static uint32_t motor_speeds_cs8600f[] = { + 54612, 54612, 34604, 26280, 21708, 18688, 16564, 14936, 13652, 12616, + 11768, 11024, 10400, 9872, 9392, 8960, 8584, 8240, 7940, 7648, + 7404, 7160, 6948, 6732, 6544, 6376, 6208, 6056, 5912, 5776, + 5644, 5520, 5408, 5292, 5192, 5092, 5000, 4908, 4820, 4736, + 4660, 4580, 4508, 4440, 4368, 4304, 4240, 4184, 4124, 4068, + 4012, 3960, 3908, 3860, 3808, 3764, 3720, 3676, 3636, 3592, + 3552, 3516, 3476, 3440, 3400, 3368, 3332, 3300, 3268, 3236, + 3204, 3176, 3148, 3116, 3088, 3060, 3036, 3008, 2984, 2956, + 2932, 2908, 2884, 2860, 2836, 2816, 2796, 2772, 2752, 2732, + 2708, 2692, 2672, 2652, 2632, 2616, 2596, 2576, 2560, 2544, + 2528, 2508, 2492, 2476, 2460, 2444, 2432, 2416, 2400, 2384, + 2372, 2356, 2344, 2328, 2316, 2304, 2288, 2276, 2260, 2252, + 2236, 2224, 2212, 2200, 2188, 2176, 2164, 2156, 2144, 2132, + 2120, 2108, 2100, 2088, 2080, 2068, 2056, 2048, 2036, 2028, + 2020, 2008, 2000, 1988, 1980, 1972, 1964, 1952, 1944, 1936, + 1928, 1920, 1912, 1900, 1892, 1884, 1876, 1868, 1860, 1856, + 1848, 1840, 1832, 1824, 1816, 1808, 1800, 1796, 1788, 1780, + 1772, 1764, 1760, 1752, 1744, 1740, 1732, 1724, 1720, 1712, + 1708, 1700, 1692, 1688, 1680, 1676, 1668, 1664, 1656, 1652, + 1644, 1640, 1636, 1628, 1624, 1616, 1612, 1608, 1600, 1596, + 1592, 1584, 1580, 1576, 1568, 1564, 1560, 1556, 1548, 1544, + 1540, 1536, 1528, 1524, 1520, 1516, 1512, 1508, 1500, 0 +}; /** * database of motor profiles */ -/* *INDENT-OFF* */ static Motor_Profile gl843_motors[]={ /* KV-SS080 */ {MOTOR_KVSS080, 8000, 1, kvss080}, @@ -693,8 +467,6 @@ static Motor_Profile gl843_motors[]={ {MOTOR_G4050, 56064, 1, g4050_high}, /* CS8400F */ {MOTOR_CS8400F, 7200, 0, cs8400f_fast}, - {0, 0, 0, NULL}, + { MOTOR_CS8600F, 0x59d8, 2, motor_speeds_cs8600f }, // FIXME: if the exposure is lower then we'll select another motor + { 0, 0, 0, NULL }, }; -/* *INDENT-ON* */ - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl846.c b/backend/genesys_gl846.c deleted file mode 100644 index 0716c17..0000000 --- a/backend/genesys_gl846.c +++ /dev/null @@ -1,3711 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2012-2013 Stéphane Voltz - - - 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. -*/ - -/** @file - * - * This file handles GL846 and GL845 ASICs since they are really close to each other. - */ -#undef BACKEND_NAME -#define BACKEND_NAME genesys_gl846 - -#include "genesys_gl846.h" - -/**************************************************************************** - Low level function - ****************************************************************************/ - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - - -/** @brief read scanned data - * Read in 0xeff0 maximum sized blocks. This read is done in 2 - * parts if not multple of 512. First read is rounded to a multiple of 512 bytes, last read fetches the - * remainder. Read addr is always 0x10000000 with the memory layout setup. - * @param dev device to read data from - * @param addr address within ASIC memory space, unused but kept for API - * @param data pointer where to store the read data - * @param len size to read - */ -static SANE_Status -gl846_bulk_read_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size, target, read, done; - uint8_t outdata[8]; - uint8_t *buffer; - - DBG (DBG_io, "gl846_bulk_read_data: requesting %lu bytes at addr=0x%02x\n", (u_long) len, addr); - - if (len == 0) - return SANE_STATUS_GOOD; - - target = len; - buffer = data; - - /* loop until computed data size is read */ - while (target) - { - if (target > 0xeff0) - { - size = 0xeff0; - } - else - { - size = target; - } - - /* hard coded 0x10000000 addr */ - outdata[0] = 0; - outdata[1] = 0; - outdata[2] = 0; - outdata[3] = 0x10; - - /* data size to transfer */ - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, 0x00, sizeof (outdata), - outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s failed while writing command: %s\n", - __func__, sane_strstatus (status)); - return status; - } - - /* blocks must be multiple of 512 but not last block */ - read = size; - if (read >= 512) - { - read /= 512; - read *= 512; - } - - DBG (DBG_io2, - "gl846_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) read); - status = sanei_usb_read_bulk (dev->dn, buffer, &read); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - done=read; - DBG (DBG_io2, "gl846_bulk_read_data: %lu bytes of data read\n", (u_long) done); - - /* read less than 512 bytes remainder */ - if (read < size) - { - read = size - read; - DBG (DBG_io2, - "gl846_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) read); - status = sanei_usb_read_bulk (dev->dn, buffer+done, &read); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - done=read; - DBG (DBG_io2, "gl846_bulk_read_data: %lu bytes of data read\n", (u_long) done); - } - - DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __func__, - (u_long) size, (u_long) (target - size)); - - target -= size; - buffer += size; - } - - if (DBG_LEVEL >= DBG_data && dev->binary!=NULL) - { - fwrite(data, len, 1, dev->binary); - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl846_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_get_filter_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_get_lineart_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_get_bitset_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_get_gain4_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** - * compute the step multiplier used - */ -static int -gl846_get_step_multiplier (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - int value = 1; - - r = sanei_genesys_get_address (regs, 0x9d); - if (r != NULL) - { - value = (r->value & 0x0f)>>1; - value = 1 << value; - } - DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); - return value; -} - -/** @brief sensor profile - * search for the database of motor profiles and get the best one. Each - * profile is at a specific dpihw. Use LiDE 110 table by default. - * @param sensor_type sensor id - * @param dpi hardware dpi for the scan - * @return a pointer to a Sensor_Profile struct - */ -static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi) -{ - unsigned int i; - int idx; - - i=0; - idx=-1; - while(i=dpi - && sensors[i].dpimodel->ccd_type, xres); - return sensor->exposure; -} - - -/** @brief sensor specific settings -*/ -static void -gl846_setup_sensor (Genesys_Device * dev, Genesys_Register_Set * regs, int dpi) -{ - Genesys_Register_Set *r; - Sensor_Profile *sensor; - int dpihw, i; - uint16_t exp; - - DBGSTART; - dpihw=sanei_genesys_compute_dpihw(dev,dpi); - - for (i = 0x06; i < 0x0e; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - if (r) - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - - for (i = 0; i < 9; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - if (r) - r->value = dev->sensor.regs_0x52_0x5e[i]; - } - - /* set EXPDUMMY and CKxMAP */ - dpihw=sanei_genesys_compute_dpihw(dev,dpi); - sensor=get_sensor_profile(dev->model->ccd_type, dpihw); - - sanei_genesys_set_reg_from_set(regs,REG_EXPDMY,(uint8_t)((sensor->expdummy) & 0xff)); - - /* if no calibration has been done, set default values for exposures */ - exp=dev->sensor.regs_0x10_0x1d[0]*256+dev->sensor.regs_0x10_0x1d[1]; - if(exp==0) - { - exp=sensor->expr; - } - sanei_genesys_set_double(regs,REG_EXPR,exp); - - exp=dev->sensor.regs_0x10_0x1d[2]*256+dev->sensor.regs_0x10_0x1d[3]; - if(exp==0) - { - exp=sensor->expg; - } - sanei_genesys_set_double(regs,REG_EXPG,exp); - - exp=dev->sensor.regs_0x10_0x1d[4]*256+dev->sensor.regs_0x10_0x1d[5]; - if(exp==0) - { - exp=sensor->expb; - } - sanei_genesys_set_double(regs,REG_EXPB,exp); - - sanei_genesys_set_triple(regs,REG_CK1MAP,sensor->ck1map); - sanei_genesys_set_triple(regs,REG_CK3MAP,sensor->ck3map); - sanei_genesys_set_triple(regs,REG_CK4MAP,sensor->ck4map); - - /* order of the sub-segments */ - dev->order=sensor->order; - - r = sanei_genesys_get_address (regs, 0x17); - r->value = sensor->r17; - - DBGCOMPLETED; -} - - -/* returns the max register bulk size */ -static int -gl846_bulk_full_size (void) -{ - return GENESYS_GL846_MAX_REGS; -} - -/** @brief set all registers to default values . - * This function is called only once at the beginning and - * fills register startup values for registers reused across scans. - * Those that are rarely modified or not modified are written - * individually. - * @param dev device structure holding register set to initialize - */ -static void -gl846_init_registers (Genesys_Device * dev) -{ - DBGSTART; - - memset (dev->reg, 0, - GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - - SETREG (0x01,0x60); - SETREG (0x02,0x38); - SETREG (0x03,0x03); - SETREG (0x04,0x22); - SETREG (0x05,0x60); - SETREG (0x06,0x10); - SETREG (0x08,0x60); - SETREG (0x09,0x00); - SETREG (0x0a,0x00); - SETREG (0x0b,0x8b); - SETREG (0x0c,0x00); - SETREG (0x0d,0x00); - SETREG (0x10,0x00); - SETREG (0x11,0x00); - SETREG (0x12,0x00); - SETREG (0x13,0x00); - SETREG (0x14,0x00); - SETREG (0x15,0x00); - SETREG (0x16,0xbb); - SETREG (0x17,0x13); - SETREG (0x18,0x10); - SETREG (0x19,0x2a); - SETREG (0x1a,0x34); - SETREG (0x1b,0x00); - SETREG (0x1c,0x20); - SETREG (0x1d,0x06); - SETREG (0x1e,0xf0); - SETREG (0x1f,0x01); - SETREG (0x20,0x03); - SETREG (0x21,0x10); - SETREG (0x22,0x60); - SETREG (0x23,0x60); - SETREG (0x24,0x60); - SETREG (0x25,0x00); - SETREG (0x26,0x00); - SETREG (0x27,0x00); - SETREG (0x2c,0x00); - SETREG (0x2d,0x00); - SETREG (0x2e,0x80); - SETREG (0x2f,0x80); - SETREG (0x30,0x00); - SETREG (0x31,0x00); - SETREG (0x32,0x00); - SETREG (0x33,0x00); - SETREG (0x34,0x1f); - SETREG (0x35,0x00); - SETREG (0x36,0x40); - SETREG (0x37,0x00); - SETREG (0x38,0x2a); - SETREG (0x39,0xf8); - SETREG (0x3d,0x00); - SETREG (0x3e,0x00); - SETREG (0x3f,0x01); - SETREG (0x52,0x02); - SETREG (0x53,0x04); - SETREG (0x54,0x06); - SETREG (0x55,0x08); - SETREG (0x56,0x0a); - SETREG (0x57,0x00); - SETREG (0x58,0x59); - SETREG (0x59,0x31); - SETREG (0x5a,0x40); - SETREG (0x5e,0x1f); - SETREG (0x5f,0x01); - SETREG (0x60,0x00); - SETREG (0x61,0x00); - SETREG (0x62,0x00); - SETREG (0x63,0x00); - SETREG (0x64,0x00); - SETREG (0x65,0x00); - SETREG (0x67,0x7f); - SETREG (0x68,0x7f); - SETREG (0x69,0x01); - SETREG (0x6a,0x01); - SETREG (0x70,0x01); - SETREG (0x71,0x00); - SETREG (0x72,0x02); - SETREG (0x73,0x01); - SETREG (0x74,0x00); - SETREG (0x75,0x00); - SETREG (0x76,0x00); - SETREG (0x77,0x00); - SETREG (0x78,0x00); - SETREG (0x79,0x3f); - SETREG (0x7a,0x00); - SETREG (0x7b,0x09); - SETREG (0x7c,0x99); - SETREG (0x7d,0x20); - SETREG (0x7f,0x05); - SETREG (0x80,0x4f); - SETREG (0x87,0x02); - SETREG (0x94,0xff); - SETREG (0x9d,0x04); - SETREG (0x9e,0x00); - SETREG (0xa1,0xe0); - SETREG (0xa2,0x1f); - SETREG (0xab,0xc0); - SETREG (0xbb,0x00); - SETREG (0xbc,0x0f); - SETREG (0xdb,0xff); - SETREG (0xfe,0x08); - SETREG (0xff,0x02); - SETREG (0x98,0x20); - SETREG (0x99,0x00); - SETREG (0x9a,0x90); - SETREG (0x9b,0x00); - SETREG (0xf8,0x05); - - /* fine tune upon device description */ - dev->reg[reg_0x05].value &= ~REG05_DPIHW; - switch (dev->sensor.optical_res) - { - case 600: - dev->reg[reg_0x05].value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg[reg_0x05].value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg[reg_0x05].value |= REG05_DPIHW_2400; - break; - case 4800: - dev->reg[reg_0x05].value |= REG05_DPIHW_4800; - break; - } - - /* initalize calibration reg */ - memcpy (dev->calib_reg, dev->reg, - GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - - DBGCOMPLETED; -} - -/**@brief send slope table for motor movement - * Send slope_table in machine byte order - * @param dev device to send slope table - * @param table_nr index of the slope table in ASIC memory - * Must be in the [0-4] range. - * @param slope_table pointer to 16 bit values array of the slope table - * @param steps number of elements in the slope table - */ -static SANE_Status -gl846_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - SANE_Status status; - uint8_t *table; - int i; - char msg[10000]; - - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, - table_nr, steps); - - /* sanity check */ - if(table_nr<0 || table_nr>4) - { - DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); - return SANE_STATUS_INVAL; - } - - table = (uint8_t *) malloc (steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), "%d", slope_table[i]); - } - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - /* slope table addresses are fixed */ - status = sanei_genesys_write_ahb (dev->dn, dev->usb_mode, 0x10000000 + 0x4000 * table_nr, steps * 2, table); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: write to AHB failed writing slope table %d (%s)\n", - __func__, table_nr, sane_strstatus (status)); - } - - free (table); - DBGCOMPLETED; - return status; -} - -/** - * Set register values of Analog Device type frontend - * */ -static SANE_Status -gl846_set_adi_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - uint16_t val; - uint8_t val8; - - DBGSTART; - - /* wait for FE to be ready */ - status = sanei_genesys_get_status (dev, &val8); - while (val8 & REG41_FEBUSY) - { - usleep (10000); - status = sanei_genesys_get_status (dev, &val8); - }; - - if (set == AFE_INIT) - { - DBG (DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - - /* sets to default values */ - sanei_genesys_init_fe (dev); - } - - /* write them to analog frontend */ - val = dev->frontend.reg[0]; - status = sanei_genesys_fe_write_data (dev, 0x00, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, - sane_strstatus (status)); - return status; - } - val = dev->frontend.reg[1]; - status = sanei_genesys_fe_write_data (dev, 0x01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg1: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - for (i = 0; i < 3; i++) - { - val = dev->frontend.gain[i]; - status = sanei_genesys_fe_write_data (dev, 0x02 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write gain %d: %s\n", __func__, i, - sane_strstatus (status)); - return status; - } - } - for (i = 0; i < 3; i++) - { - val = dev->frontend.offset[i]; - status = sanei_genesys_fe_write_data (dev, 0x05 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write offset %d: %s\n", __func__, i, - sane_strstatus (status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl846_homsnr_gpio(Genesys_Device *dev) -{ -uint8_t val; -SANE_Status status=SANE_STATUS_GOOD; - - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val |= 0x41; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - - return status; -} - -/* Set values of analog frontend */ -static SANE_Status -gl846_set_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status; - - DBG(DBG_proc, "gl846_set_fe (%s)\n", - set == AFE_INIT ? "init" : set == AFE_SET ? "set" : - set == AFE_POWER_SAVE ? "powersave" : "huh?"); - - /* route to specific analog frontend setup */ - switch (dev->reg[reg_0x04].value & REG04_FESET) - { - case 0x02: /* ADI FE */ - status = gl846_set_adi_fe(dev, set); - break; - default: - DBG(DBG_proc, "gl846_set_fe(): unsupported frontend type %d\n", - dev->reg[reg_0x04].value & REG04_FESET); - status = SANE_STATUS_UNSUPPORTED; - } - - DBGCOMPLETED; - return status; -} - - -/** @brief set up motor related register for scan - */ -static SANE_Status -gl846_init_motor_regs_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - int scan_power_mode, - unsigned int flags) -{ - SANE_Status status; - int use_fast_fed; - unsigned int fast_dpi; - uint16_t scan_table[SLOPE_TABLE_SIZE]; - uint16_t fast_table[SLOPE_TABLE_SIZE]; - int scan_steps, fast_steps, factor; - unsigned int feedl, dist; - Genesys_Register_Set *r; - uint32_t z1, z2; - unsigned int min_restep = 0x20; - uint8_t val; - int fast_step_type; - unsigned int ccdlmt,tgtime; - - DBGSTART; - DBG (DBG_proc, "gl846_init_motor_regs_scan : scan_exposure_time=%d, " - "scan_yres=%g, scan_step_type=%d, scan_lines=%d, scan_dummy=%d, " - "feed_steps=%d, scan_power_mode=%d, flags=%x\n", - scan_exposure_time, - scan_yres, - scan_step_type, - scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); - - /* get step multiplier */ - factor = gl846_get_step_multiplier (reg); - - use_fast_fed=0; - /* no fast fed since feed works well */ - if(dev->settings.yres==4444 && feed_steps>100 - && ((flags & MOTOR_FLAG_FEED)==0)) - { - use_fast_fed=1; - } - DBG (DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); - - sanei_genesys_set_triple(reg, REG_LINCNT, scan_lines); - DBG (DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); - - /* compute register 02 value */ - r = sanei_genesys_get_address (reg, REG02); - r->value = 0x00; - r->value |= REG02_MTRPWR; - - if (use_fast_fed) - r->value |= REG02_FASTFED; - else - r->value &= ~REG02_FASTFED; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= REG02_AGOHOME | REG02_NOTHOME; - - if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - ||(scan_yres>=dev->sensor.optical_res)) - { - r->value |= REG02_ACDCDIS; - } - - /* scan and backtracking slope table */ - sanei_genesys_slope_table(scan_table, - &scan_steps, - scan_yres, - scan_exposure_time, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - gl846_motors); - RIE(gl846_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); - RIE(gl846_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); - - /* fast table */ - fast_dpi=sanei_genesys_get_lowest_ydpi(dev); - fast_step_type=scan_step_type; - if(scan_step_type>=2) - { - fast_step_type=2; - } - - sanei_genesys_slope_table(fast_table, - &fast_steps, - fast_dpi, - scan_exposure_time, - dev->motor.base_ydpi, - fast_step_type, - factor, - dev->model->motor_type, - gl846_motors); - - /* manual override of high start value */ - fast_table[0]=fast_table[1]; - - RIE(gl846_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); - RIE(gl846_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); - RIE(gl846_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); - - /* correct move distance by acceleration and deceleration amounts */ - feedl=feed_steps; - if (use_fast_fed) - { - feedl<<=fast_step_type; - dist=(scan_steps+2*fast_steps)*factor; - /* TODO read and decode REGAB */ - r = sanei_genesys_get_address (reg, 0x5e); - dist += (r->value & 31); - /* FEDCNT */ - r = sanei_genesys_get_address (reg, REG_FEDCNT); - dist += r->value; - } - else - { - feedl<<=scan_step_type; - dist=scan_steps*factor; - if (flags & MOTOR_FLAG_FEED) - dist *=2; - } - DBG (DBG_io2, "%s: scan steps=%d\n", __func__, scan_steps); - DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); - - /* check for overflow */ - if(distvalue & REG0C_CCDLMT)+1; - - r = sanei_genesys_get_address (reg, REG1C); - tgtime=1<<(r->value & REG1C_TGTIME); - - /* hi res motor speed GPIO */ - /* - RIE (sanei_genesys_read_register (dev, REG6C, &effective)); - */ - - /* if quarter step, bipolar Vref2 */ - /* XXX STEF XXX GPIO - if (scan_step_type > 1) - { - if (scan_step_type < 3) - { - val = effective & ~REG6C_GPIO13; - } - else - { - val = effective | REG6C_GPIO13; - } - } - else - { - val = effective; - } - RIE (sanei_genesys_write_register (dev, REG6C, val)); - */ - - /* effective scan */ - /* - RIE (sanei_genesys_read_register (dev, REG6C, &effective)); - val = effective | REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - */ - - if(dev->model->gpo_type==GPO_IMG101) - { - if(scan_yres==sanei_genesys_compute_dpihw(dev,scan_yres)) - { - val=1; - } - else - { - val=0; - } - RIE (sanei_genesys_write_register (dev, REG7E, val)); - } - - min_restep=scan_steps/2-1; - if (min_restep < 1) - min_restep = 1; - r = sanei_genesys_get_address (reg, REG_FWDSTEP); - r->value = min_restep; - r = sanei_genesys_get_address (reg, REG_BWDSTEP); - r->value = min_restep; - - sanei_genesys_calculate_zmode2(use_fast_fed, - scan_exposure_time*ccdlmt*tgtime, - scan_table, - scan_steps*factor, - feedl, - min_restep*factor, - &z1, - &z2); - - DBG (DBG_info, "gl846_init_motor_regs_scan: z1 = %d\n", z1); - sanei_genesys_set_triple(reg, REG60, z1 | (scan_step_type << (16+REG60S_STEPSEL))); - - DBG (DBG_info, "gl846_init_motor_regs_scan: z2 = %d\n", z2); - sanei_genesys_set_triple(reg, REG63, z2 | (scan_step_type << (16+REG63S_FSTPSEL))); - - r = sanei_genesys_get_address (reg, 0x1e); - r->value &= 0xf0; /* 0 dummy lines */ - r->value |= scan_dummy; /* dummy lines */ - - r = sanei_genesys_get_address (reg, REG67); - r->value = 0x7f; - - r = sanei_genesys_get_address (reg, REG68); - r->value = 0x7f; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FSHDEC); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FMOVNO); - r->value = fast_steps; - - r = sanei_genesys_get_address (reg, REG_FMOVDEC); - r->value = fast_steps; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** @brief set up registers related to sensor - * Set up the following registers - 0x01 - 0x03 - 0x10-0x015 R/G/B exposures - 0x19 EXPDMY - 0x2e BWHI - 0x2f BWLO - 0x04 - 0x87 - 0x05 - 0x2c,0x2d DPISET - 0x30,0x31 STRPIXEL - 0x32,0x33 ENDPIXEL - 0x35,0x36,0x37 MAXWD [25:2] (>>2) - 0x38,0x39 LPERIOD - 0x34 DUMMY - */ -static SANE_Status -gl846_init_optical_regs_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int exposure_time, - int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, int color_filter, int flags) -{ - unsigned int words_per_line; - unsigned int startx, endx, used_pixels; - unsigned int dpiset, dpihw,segnb,cksel,factor; - unsigned int bytes; - Genesys_Register_Set *r; - SANE_Status status; - Sensor_Profile *sensor; - - DBG (DBG_proc, "gl846_init_optical_regs_scan : exposure_time=%d, " - "used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", exposure_time, - used_res, start, pixels, channels, depth, half_ccd, flags); - - /* resolution is divided according to CKSEL */ - r = sanei_genesys_get_address (reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); - - /* to manage high resolution device while keeping good - * low resolution scanning speed, we make hardware dpi vary */ - dpihw=sanei_genesys_compute_dpihw(dev, used_res * cksel); - factor=dev->sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); - - /* sensor parameters */ - sensor=get_sensor_profile(dev->model->ccd_type, dpihw); - gl846_setup_sensor (dev, reg, dpihw); - dpiset = used_res * cksel; - - /* start and end coordinate in optical dpi coordinates */ - startx = start/cksel+dev->sensor.CCD_start_xoffset; - used_pixels=pixels/cksel; - - /* end of sensor window */ - endx = startx + used_pixels; - - /* sensors are built from 600 dpi segments for LiDE 100/200 - * and 1200 dpi for the 700F */ - if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR) - { - segnb=dpihw/600; - } - else - { - segnb=1; - } - - /* compute pixel coordinate in the given dpihw space, - * taking segments into account */ - startx/=factor*segnb; - endx/=factor*segnb; - dev->len=endx-startx; - dev->dist=0; - dev->skip=0; - - /* in cas of multi-segments sensor, we have to add the witdh - * of the sensor crossed by the scan area */ - if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR && segnb>1) - { - dev->dist = sensor->segcnt; - } - - /* use a segcnt rounded to next even number */ - endx += ((dev->dist+1)&0xfffe)*(segnb-1); - used_pixels=endx-startx; - - status = gl846_set_fe (dev, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_init_optical_regs_scan: failed to set frontend: %s\n", - sane_strstatus (status)); - return status; - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, REG01); - r->value &= ~REG01_SCAN; - r->value |= REG01_SHDAREA; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - r->value &= ~REG01_DVDSET; - } - else - { - r->value |= REG01_DVDSET; - } - - r = sanei_genesys_get_address (reg, REG03); - r->value &= ~REG03_AVEENB; - - if (flags & OPTICAL_FLAG_DISABLE_LAMP) - r->value &= ~REG03_LAMPPWR; - else - r->value |= REG03_LAMPPWR; - - /* BW threshold */ - r = sanei_genesys_get_address (reg, 0x2e); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, 0x2f); - r->value = dev->settings.threshold; - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, REG04); - switch (depth) - { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - r->value &= ~(REG04_FILTER | REG04_AFEMOD); - if (channels == 1) - { - switch (color_filter) - { - case 0: - r->value |= 0x24; /* red filter */ - break; - case 2: - r->value |= 0x2c; /* blue filter */ - break; - default: - r->value |= 0x28; /* green filter */ - break; - } - } - else - r->value |= 0x20; /* mono */ - - /* register 05 */ - r = sanei_genesys_get_address (reg, REG05); - - /* set up dpihw */ - r->value &= ~REG05_DPIHW; - switch(dpihw) - { - case 600: - r->value |= REG05_DPIHW_600; - break; - case 1200: - r->value |= REG05_DPIHW_1200; - break; - case 2400: - r->value |= REG05_DPIHW_2400; - break; - case 4800: - r->value |= REG05_DPIHW_4800; - break; - } - - /* enable gamma tables */ - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - /* CIS scanners can do true gray by setting LEDADD */ - /* we set up LEDADD only when asked */ - if (dev->model->is_cis == SANE_TRUE) - { - r = sanei_genesys_get_address (reg, 0x87); - r->value &= ~REG87_LEDADD; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG87_LEDADD; - } - /* RGB weighting - r = sanei_genesys_get_address (reg, 0x01); - r->value &= ~REG01_TRUEGRAY; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG01_TRUEGRAY; - }*/ - } - - /* words(16bit) before gamma, conversion to 8 bit or lineart*/ - words_per_line = (used_pixels * dpiset) / dpihw; - bytes=depth/8; - if (depth == 1) - { - words_per_line = (words_per_line+7)/8 ; - dev->len = (dev->len >> 3) + ((dev->len & 7) ? 1 : 0); - dev->dist = (dev->dist >> 3) + ((dev->dist & 7) ? 1 : 0); - } - else - { - words_per_line *= bytes; - dev->dist *= bytes; - dev->len *= bytes; - } - - dev->bpl = words_per_line; - dev->cur=0; - dev->segnb=segnb; - dev->line_interp = 0; - - sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); - - sanei_genesys_set_double(reg,REG_STRPIXEL,startx); - sanei_genesys_set_double(reg,REG_ENDPIXEL,endx); - DBG (DBG_io2, "%s: startx=%d\n", __func__, startx); - DBG (DBG_io2, "%s: endx =%d\n", __func__, endx); - - DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->segnb =%lu\n", __func__, (unsigned long)dev->segnb); - - words_per_line *= channels; - dev->wpl = words_per_line; - - if(dev->oe_buffer.buffer!=NULL) - { - sanei_genesys_buffer_free (&(dev->oe_buffer)); - } - RIE (sanei_genesys_buffer_alloc (&(dev->oe_buffer), dev->wpl)); - - /* MAXWD is expressed in 4 words unit */ - sanei_genesys_set_triple(reg, REG_MAXWD, (words_per_line >> 2)); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); - - sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); - DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); - - r = sanei_genesys_get_address (reg, 0x34); - r->value = dev->sensor.dummy_pixel; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl846_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int color_filter, - unsigned int flags) -{ - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; - unsigned int oflags; /**> optical flags */ - unsigned int mflags; /**> motor flags */ - int exposure_time; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int scan_power_mode = 0; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - SANE_Status status; - - DBG (DBG_info, - "gl846_init_scan_regs settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g/%g\n" - "Depth/Channels: %u/%u\n" - "Flags : %x\n\n", - xres, yres, lines, pixels, startx, starty, depth, channels, flags); - - /* we may have 2 domains for ccd: xres below or above half ccd max dpi */ - if (dev->sensor.optical_res < 2 * xres || - !(dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)) - { - half_ccd = SANE_FALSE; - } - else - { - half_ccd = SANE_TRUE; - } - - /* optical_res */ - optical_res = dev->sensor.optical_res; - if (half_ccd) - optical_res /= 2; - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "gl846_init_scan_regs : stagger=%d lines\n", stagger); - - /* used_res */ - if (flags & SCAN_FLAG_USE_OPTICAL_RES) - { - used_res = optical_res; - } - else - { - /* resolution is choosen from a list */ - used_res = xres; - } - - /* compute scan parameters values */ - /* pixels are allways given at full optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - /* add x coordinates */ - start = startx; - - if (stagger > 0) - start |= 1; - - /* compute correct pixels number */ - /* pixels */ - used_pixels = (pixels * optical_res) / xres; - - /* round up pixels number if needed */ - if (used_pixels * xres < pixels * optical_res) - used_pixels++; - - dummy = 3-channels; - -/* slope_dpi */ -/* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = yres * channels; - else - slope_dpi = yres; - - slope_dpi = slope_dpi * (1 + dummy); - - exposure_time = gl846_compute_exposure (dev, used_res); - scan_step_type = sanei_genesys_compute_step_type(gl846_motors, dev->model->motor_type, exposure_time); - - DBG (DBG_info, "gl846_init_scan_regs : exposure_time=%d pixels\n", exposure_time); - DBG (DBG_info, "gl846_init_scan_regs : scan_step_type=%d\n", scan_step_type); - -/*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if ((flags & SCAN_FLAG_DYNAMIC_LINEART) && (dev->settings.scan_mode == SCAN_MODE_LINEART)) - { - depth = 8; - } - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - oflags = 0; - if(flags & SCAN_FLAG_DISABLE_SHADING) - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - if(flags & SCAN_FLAG_DISABLE_GAMMA) - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - if(flags & SCAN_FLAG_DISABLE_LAMP) - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - - if (dev->model->is_cis && dev->settings.true_gray) - { - oflags |= OPTICAL_FLAG_ENABLE_LEDADD; - } - - status = gl846_init_optical_regs_scan (dev, - reg, - exposure_time, - used_res, - start, - used_pixels, - channels, - depth, - half_ccd, - color_filter, - oflags); - - if (status != SANE_STATUS_GOOD) - return status; - -/*** motor parameters ***/ - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,flags); - - /* lincnt */ - lincnt = lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = starty; - DBG (DBG_info, "gl846_init_scan_regs: move=%d steps\n", move); - - mflags=0; - if(flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) - mflags |= MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; - if(flags & SCAN_FLAG_FEEDING) - mflags |= MOTOR_FLAG_FEED; - - status = gl846_init_motor_regs_scan (dev, - reg, - exposure_time, - slope_dpi, - scan_step_type, - dev->model->is_cis ? lincnt * - channels : lincnt, dummy, move, - scan_power_mode, - mflags); - - if (status != SANE_STATUS_GOOD) - return status; - - - /*** prepares data reordering ***/ - -/* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * channels * depth) / 8; - - requested_buffer_size = 8 * bytes_per_line; - /* we must use a round number of bytes_per_line */ - /* XXX STEF XXX - if (requested_buffer_size > BULKIN_MAXSIZE) - requested_buffer_size = - (BULKIN_MAXSIZE / bytes_per_line) * bytes_per_line; - */ - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * channels * depth) / 8; - - RIE (sanei_genesys_buffer_free (&(dev->read_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->read_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->lines_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->lines_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->shrink_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->shrink_buffer), - requested_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->out_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->out_buffer), - (8 * dev->settings.pixels * channels * - depth) / 8)); - - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG (DBG_info, - "gl846_init_scan_regs: physical bytes to read = %lu\n", - (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - -/* TODO: should this be done elsewhere? */ - /* scan bytes to send to the frontend */ - /* theory : - target_size = - (dev->settings.pixels * dev->settings.lines * channels * depth) / 8; - but it suffers from integer overflow so we do the following: - - 1 bit color images store color data byte-wise, eg byte 0 contains - 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains - 8 bits of blue. - This does not fix the overflow, though. - 644mp*16 = 10gp, leading to an overflow - -- pierre - */ - - dev->total_bytes_read = 0; - if (depth == 1) - dev->total_bytes_to_read = - ((dev->settings.pixels * dev->settings.lines) / 8 + - (((dev->settings.pixels * dev->settings.lines) % 8) ? 1 : 0)) * - channels; - else - dev->total_bytes_to_read = - dev->settings.pixels * dev->settings.lines * channels * (depth / 8); - - DBG (DBG_info, "gl846_init_scan_regs: total bytes to send = %lu\n", - (u_long) dev->total_bytes_to_read); -/* END TODO */ - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl846_calculate_current_setup (Genesys_Device * dev) -{ - int channels; - int depth; - int start; - - float xres; /*dpi */ - float yres; /*dpi */ - float startx; /*optical_res, from dummy_pixel+1 */ - float pixels; - float lines; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure_time; - int stagger; - - int slope_dpi; - int dummy = 0; - int max_shift; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - - DBG (DBG_info, - "gl846_calculate_current_setup settings:\n" - "Resolution: %uDPI\n" - "Lines : %u\n" - "PPL : %u\n" - "Startpos : %.3f/%.3f\n" - "Scan mode : %d\n\n", - dev->settings.yres, dev->settings.lines, dev->settings.pixels, - dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); - - /* channels */ - if (dev->settings.scan_mode == 4) /* single pass color */ - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == 0) - depth = 1; - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - - xres = dev->settings.xres; /*dpi */ - yres = dev->settings.yres; /*dpi */ - startx = start; /*optical_res, from dummy_pixel+1 */ - pixels = dev->settings.pixels; - lines = dev->settings.lines; - - DBG (DBG_info, - "gl846_calculate_current_setup settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g\n" - "Depth/Channels: %u/%u\n\n", - xres, yres, lines, pixels, startx, depth, channels); - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if ((dev->sensor.optical_res < 2 * xres) || - !(dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)) - { - half_ccd = SANE_FALSE; - } - else - { - half_ccd = SANE_TRUE; - } - - /* optical_res */ - optical_res = dev->sensor.optical_res; - - /* stagger */ - if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "gl846_calculate_current_setup: stagger=%d lines\n", - stagger); - - /* resolution is choosen from a fixed list */ - used_res = xres; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - - /* compute correct pixels number */ - used_pixels = (pixels * optical_res) / used_res; - dummy = 3-channels; - - /* slope_dpi */ - /* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = yres * channels; - else - slope_dpi = yres; - - slope_dpi = slope_dpi * (1 + dummy); - - exposure_time = gl846_compute_exposure (dev, used_res); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); - - /* lincnt */ - lincnt = lines + max_shift + stagger; - - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static void -gl846_set_motor_power (Genesys_Register_Set * regs, SANE_Bool set) -{ - - DBG (DBG_proc, "gl846_set_motor_power\n"); - - if (set) - { - sanei_genesys_set_reg_from_set (regs, REG02, - sanei_genesys_read_reg_from_set (regs, - REG02) - | REG02_MTRPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, REG02, - sanei_genesys_read_reg_from_set (regs, - REG02) - & ~REG02_MTRPWR); - } -} - -static void -gl846_set_lamp_power (Genesys_Device __sane_unused__ * dev, - Genesys_Register_Set * regs, SANE_Bool set) -{ - if (set) - { - sanei_genesys_set_reg_from_set (regs, REG03, - sanei_genesys_read_reg_from_set (regs, REG03) - | REG03_LAMPPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, REG03, - sanei_genesys_read_reg_from_set (regs, REG03) - & ~REG03_LAMPPWR); - } -} - -/*for fast power saving methods only, like disabling certain amplifiers*/ -static SANE_Status -gl846_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - DBG (DBG_proc, "gl846_save_power: enable = %d\n", enable); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl846_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - DBG (DBG_proc, "gl846_set_powersaving (delay = %d)\n", delay); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl846_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl846_stop_action (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val40, val; - unsigned int loop; - - DBGSTART; - - /* post scan gpio : without that HOMSNR is unreliable */ - gl846_homsnr_gpio(dev); - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBG (DBG_info, "%s: already stopped\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* ends scan */ - val = sanei_genesys_read_reg_from_set (dev->reg, REG01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set (dev->reg, REG01, val); - status = sanei_genesys_write_register (dev, REG01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write register 01: %s\n", __func__, - sane_strstatus (status)); - return status; - } - usleep (100 * 1000); - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) - && !(val & REG41_MOTORENB)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - usleep (100 * 1000); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - -/* Send the low-level scan command */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl846_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - SANE_Status status; - uint8_t val; - Genesys_Register_Set *r; - - DBGSTART; - - /* XXX STEF XXX SCAN GPIO */ - /* - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - RIE (sanei_genesys_write_register (dev, REG6C, val)); - */ - - val = REG0D_CLRLNCNT; - RIE (sanei_genesys_write_register (dev, REG0D, val)); - val = REG0D_CLRMCNT; - RIE (sanei_genesys_write_register (dev, REG0D, val)); - - RIE (sanei_genesys_read_register (dev, REG01, &val)); - val |= REG01_SCAN; - RIE (sanei_genesys_write_register (dev, REG01, val)); - r = sanei_genesys_get_address (reg, REG01); - r->value = val; - - if (start_motor) - { - RIE (sanei_genesys_write_register (dev, REG0F, 1)); - } - else - { - RIE (sanei_genesys_write_register (dev, REG0F, 0)); - } - - DBGCOMPLETED; - - return status; -} - - -/* Send the stop scan command */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl846_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - SANE_Status status; - - DBG (DBG_proc, "gl846_end_scan (check_stop = %d)\n", check_stop); - if (reg == NULL) - return SANE_STATUS_INVAL; - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl846_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_end_scan: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -/* Moves the slider to the home (top) postion slowly */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl846_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg[GENESYS_GL846_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - float resolution; - uint8_t val; - int loop = 0; - int scan_mode; - - DBG (DBG_proc, "gl846_slow_back_home (wait_until_home = %d)\n", - wait_until_home); - - if(dev->usb_mode<0) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* post scan gpio : without that HOMSNR is unreliable */ - gl846_homsnr_gpio(dev); - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - usleep (100000); /* sleep 100 ms */ - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - /* is sensor at home? */ - if (val & HOMESNR) - { - DBG (DBG_info, "%s: already at home, completed\n", __func__); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - memcpy (local_reg, dev->reg, GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - - resolution=sanei_genesys_get_lowest_ydpi(dev); - - /* TODO add scan_mode to the API */ - scan_mode= dev->settings.scan_mode; - dev->settings.scan_mode=SCAN_MODE_LINEART; - status = gl846_init_scan_regs (dev, - local_reg, - resolution, - resolution, - 100, - 30000, - 100, - 100, - 8, - 1, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_slow_back_home: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - dev->settings.scan_mode=scan_mode; - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse */ - r = sanei_genesys_get_address (local_reg, REG02); - r->value |= REG02_MTRREV; - - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL846_MAX_REGS)); - - status = gl846_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_slow_back_home: failed to start motor: %s\n", - sane_strstatus (status)); - gl846_stop_action (dev); - /* send original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL846_MAX_REGS); - return status; - } - - /* post scan gpio : without that HOMSNR is unreliable */ - gl846_homsnr_gpio(dev); - - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - - if (val & HOMESNR) /* home sensor */ - { - DBG (DBG_info, "gl846_slow_back_home: reached home position\n"); - gl846_stop_action (dev); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl846_stop_action (dev); - DBG (DBG_error, - "gl846_slow_back_home: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; - } - - DBG (DBG_info, "gl846_slow_back_home: scanhead is still moving\n"); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl846_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status; - uint8_t *data; - Genesys_Register_Set local_reg[GENESYS_GL846_MAX_REGS]; - int steps; - - int pixels = 600; - int dpi = 300; - - DBG (DBG_proc, "gl846_search_start_position\n"); - - memcpy (local_reg, dev->reg, - GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - status = gl846_init_scan_regs (dev, local_reg, dpi, dpi, 0, 0, /*we should give a small offset here~60 steps */ - 600, dev->model->search_lines, 8, 1, 1, /*green */ - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_search_start_position: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* send to scanner */ - status = dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL846_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_search_start_position: failed to bulk write registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - size = pixels * dev->model->search_lines; - - data = malloc (size); - if (!data) - { - DBG (DBG_error, - "gl846_search_start_position: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - status = gl846_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl846_search_start_position: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl846_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("search_position.pnm", data, 8, 1, pixels, - dev->model->search_lines); - - status = gl846_end_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl846_search_start_position: failed to end scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* update regs to copy ASIC internal state */ - memcpy (dev->reg, local_reg, - GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - -/*TODO: find out where sanei_genesys_search_reference_point - stores information, and use that correctly*/ - status = - sanei_genesys_search_reference_point (dev, data, 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl846_search_start_position: failed to set search reference point: %s\n", - sane_strstatus (status)); - return status; - } - - free (data); - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl846_init_regs_for_coarse_calibration (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t channels; - uint8_t cksel; - - DBG (DBG_proc, "gl846_init_regs_for_coarse_calibration\n"); - - - cksel = (dev->calib_reg[reg_0x18].value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - status = gl846_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - dev->sensor.optical_res / cksel, - 20, - 16, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_init_register_for_coarse_calibration: Failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_info, - "gl846_init_register_for_coarse_calibration: optical sensor res: %d dpi, actual res: %d\n", - dev->sensor.optical_res / cksel, dev->settings.xres); - - status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL846_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_init_register_for_coarse_calibration: Failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move in base_dpi line count - * */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl846_feed (Genesys_Device * dev, unsigned int steps) -{ - Genesys_Register_Set local_reg[GENESYS_GL846_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - float resolution; - uint8_t val; - - DBGSTART; - DBG (DBG_io, "%s: steps=%d\n", __func__, steps); - - /* prepare local registers */ - memcpy (local_reg, dev->reg, GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - - resolution=sanei_genesys_get_lowest_ydpi(dev); - status = gl846_init_scan_regs (dev, - local_reg, - resolution, - resolution, - 0, - steps, - 100, - 3, - 8, - 3, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_FEEDING | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_feed: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* set exposure to zero */ - sanei_genesys_set_triple(local_reg,REG_EXPR,0); - sanei_genesys_set_triple(local_reg,REG_EXPG,0); - sanei_genesys_set_triple(local_reg,REG_EXPB,0); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); - - /* set up for no scan */ - r = sanei_genesys_get_address (local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* send registers */ - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL846_MAX_REGS)); - - status = gl846_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); - gl846_stop_action (dev); - - /* restore original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL846_MAX_REGS); - return status; - } - - /* wait until feed count reaches the required value, but do not - * exceed 30s */ - do - { - status = sanei_genesys_get_status (dev, &val); - } - while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); - - /* then stop scanning */ - RIE(gl846_stop_action (dev)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -static SANE_Status -gl846_init_regs_for_shading (Genesys_Device * dev) -{ - SANE_Status status; - float move; - - DBGSTART; - dev->calib_channels = 3; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - - dev->calib_resolution = sanei_genesys_compute_dpihw(dev,dev->settings.xres); - dev->calib_lines = dev->model->shading_lines; - if(dev->calib_resolution==4800) - dev->calib_lines *= 2; - dev->calib_pixels = (dev->sensor.sensor_pixels*dev->calib_resolution)/dev->sensor.optical_res; - DBG (DBG_io, "%s: calib_lines = %d\n", __func__, (unsigned int)dev->calib_lines); - DBG (DBG_io, "%s: calib_pixels = %d\n", __func__, (unsigned int)dev->calib_pixels); - - /* this is aworkaround insufficent distance for slope - * motor acceleration TODO special motor slope for shading */ - move=1; - if(dev->calib_resolution<1200) - { - move=40; - } - - status = gl846_init_scan_regs (dev, - dev->calib_reg, - dev->calib_resolution, - dev->calib_resolution, - 0, - move, - dev->calib_pixels, - dev->calib_lines, - 16, - dev->calib_channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL846_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); - return status; - } - - /* we use GENESYS_FLAG_SHADING_REPARK */ - dev->scanhead_position_in_steps = 0; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief set up registers for the actual scan - */ -static SANE_Status -gl846_init_regs_for_scan (Genesys_Device * dev) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status; - - DBG (DBG_info, - "gl846_init_regs_for_scan settings:\nResolution: %uDPI\n" - "Lines : %u\nPPL : %u\nStartpos : %.3f/%.3f\nScan mode : %d\n\n", - dev->settings.yres, dev->settings.lines, dev->settings.pixels, - dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); - - /* channels */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == SCAN_MODE_LINEART) - depth = 1; - - - /* steps to move to reach scanning area: - - first we move to physical start of scanning - either by a fixed steps amount from the black strip - or by a fixed amount from parking position, - minus the steps done during shading calibration - - then we move by the needed offset whitin physical - scanning area - - assumption: steps are expressed at maximum motor resolution - - we need: - SANE_Fixed y_offset; - SANE_Fixed y_size; - SANE_Fixed y_offset_calib; - mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ - - /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is - relative from origin, else, it is from parking position */ - - move_dpi = dev->motor.base_ydpi; - - move = SANE_UNFIX (dev->model->y_offset); - move += dev->settings.tl_y; - move = (move * move_dpi) / MM_PER_INCH; - move -= dev->scanhead_position_in_steps; - DBG (DBG_info, "%s: move=%f steps\n",__func__, move); - - /* fast move to scan area */ - /* we don't move fast the whole distance since it would involve - * computing acceleration/deceleration distance for scan - * resolution. So leave a remainder for it so scan makes the final - * move tuning */ - if(channels*dev->settings.yres>=600 && move>700) - { - status = gl846_feed (dev, move-500); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to move to scan area\n",__func__); - return status; - } - move=500; - } - - DBG (DBG_info, "gl846_init_regs_for_scan: move=%f steps\n", move); - DBG (DBG_info, "%s: move=%f steps\n", __func__, move); - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - flags = 0; - - /* emulated lineart from gray data is required for now */ - if(dev->settings.scan_mode == SCAN_MODE_LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - /* backtracking isn't handled well, so don't enable it */ - flags |= SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; - - status = gl846_init_scan_regs (dev, - dev->reg, - dev->settings.xres, - dev->settings.yres, - start, - move, - dev->settings.pixels, - dev->settings.lines, - depth, - channels, - dev->settings.color_filter, - flags); - - if (status != SANE_STATUS_GOOD) - return status; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -static SANE_Status -gl846_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t addr, length, i, x, factor, pixels; - uint32_t dpiset, dpihw, strpixel, endpixel; - uint16_t tempo; - uint32_t lines, channels; - uint8_t val,*buffer,*ptr,*src; - - DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); - - /* shading data is plit in 3 (up to 5 with IR) areas - write(0x10014000,0x00000dd8) - URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x.... - write(0x1003e000,0x00000dd8) - write(0x10068000,0x00000dd8) - */ - length = (uint32_t) (size / 3); - sanei_genesys_get_double(dev->reg,REG_STRPIXEL,&tempo); - strpixel=tempo; - sanei_genesys_get_double(dev->reg,REG_ENDPIXEL,&tempo); - endpixel=tempo; - - /* compute deletion factor */ - sanei_genesys_get_double(dev->reg,REG_DPISET,&tempo); - dpiset=tempo; - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n",__func__,strpixel,endpixel,endpixel-strpixel,dpiset); - dpihw=sanei_genesys_compute_dpihw(dev,dpiset); - factor=dpihw/dpiset; - DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); - - if(DBG_LEVEL>=DBG_data) - { - dev->binary=fopen("binary.pnm","wb"); - sanei_genesys_get_triple(dev->reg, REG_LINCNT, &lines); - channels=dev->current_setup.channels; - if(dev->binary!=NULL) - { - fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); - } - } - - pixels=endpixel-strpixel; - - /* since we're using SHDAREA, substract startx coordinate from shading */ - strpixel-=((dev->sensor.CCD_start_xoffset*600)/dev->sensor.optical_res); - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; - pixels*=2*2; - - /* allocate temporary buffer */ - buffer=(uint8_t *)malloc(pixels); - memset(buffer,0,pixels); - DBG( DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n",__func__,pixels,pixels); - - /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address - * is 8192*reg value */ - - /* write actual color channel data */ - for(i=0;i<3;i++) - { - /* build up actual shading data by copying the part from the full width one - * to the one corresponding to SHDAREA */ - ptr=buffer; - - /* iterate on both sensor segment */ - for(x=0;xdn, dev->usb_mode, addr, pixels, buffer); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl846_send_shading_data; write to AHB failed (%s)\n", - sane_strstatus (status)); - free(buffer); - return status; - } - } - - free(buffer); - DBGCOMPLETED; - - return status; -} - -/** @brief calibrates led exposure - * Calibrate exposure by scanning a white area until the used exposure gives - * data white enough. - * @param dev device to calibrate - */ -static SANE_Status -gl846_led_calibration (Genesys_Device * dev) -{ - int num_pixels; - int total_size; - int used_res; - uint8_t *line; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels, depth; - int avg[3], top[3], bottom[3]; - int turn; - char fn[20]; - uint16_t exp[3]; - Sensor_Profile *sensor; - float move; - SANE_Bool acceptable; - - DBGSTART; - - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; - if(move>20) - { - RIE(gl846_feed (dev, move)); - } - DBG (DBG_io, "%s: move=%f steps\n", __func__, move); - - /* offset calibration is always done in color mode */ - channels = 3; - depth=16; - used_res=sanei_genesys_compute_dpihw(dev,dev->settings.xres); - sensor=get_sensor_profile(dev->model->ccd_type, used_res); - num_pixels = (dev->sensor.sensor_pixels*used_res)/dev->sensor.optical_res; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* set up for the calibration scan */ - status = gl846_init_scan_regs (dev, - dev->calib_reg, - used_res, - used_res, - 0, - 0, - num_pixels, - 1, - depth, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - - /* initial loop values and boundaries */ - exp[0]=sensor->expr; - exp[1]=sensor->expg; - exp[2]=sensor->expb; - - bottom[0]=29000; - bottom[1]=29000; - bottom[2]=29000; - - top[0]=41000; - top[1]=51000; - top[2]=51000; - - turn = 0; - - /* no move during led calibration */ - gl846_set_motor_power (dev->calib_reg, SANE_FALSE); - do - { - /* set up exposure */ - sanei_genesys_set_double(dev->calib_reg,REG_EXPR,exp[0]); - sanei_genesys_set_double(dev->calib_reg,REG_EXPG,exp[1]); - sanei_genesys_set_double(dev->calib_reg,REG_EXPB,exp[2]); - - /* write registers and scan data */ - RIEF (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL846_MAX_REGS), line); - - DBG (DBG_info, "gl846_led_calibration: starting line reading\n"); - RIEF (gl846_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, total_size), line); - - /* stop scanning */ - RIEF (gl846_stop_action (dev), line); - - if (DBG_LEVEL >= DBG_data) - { - snprintf (fn, 20, "led_%02d.pnm", turn); - sanei_genesys_write_pnm_file (fn, line, depth, channels, num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG (DBG_info, "gl846_led_calibration: average: %d,%d,%d\n", avg[0], avg[1], avg[2]); - - /* check if exposure gives average within the boundaries */ - acceptable = SANE_TRUE; - for(i=0;i<3;i++) - { - if(avg[i]top[i]) - { - exp[i]=(exp[i]*top[i])/avg[i]; - acceptable = SANE_FALSE; - } - } - - turn++; - } - while (!acceptable && turn < 100); - - DBG (DBG_info, "gl846_led_calibration: acceptable exposure: %d,%d,%d\n", exp[0], exp[1], exp[2]); - - /* set these values as final ones for scan */ - sanei_genesys_set_double(dev->reg,REG_EXPR,exp[0]); - sanei_genesys_set_double(dev->reg,REG_EXPG,exp[1]); - sanei_genesys_set_double(dev->reg,REG_EXPB,exp[2]); - - /* store in this struct since it is the one used by cache calibration */ - dev->sensor.regs_0x10_0x1d[0] = (exp[0] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[1] = exp[0] & 0xff; - dev->sensor.regs_0x10_0x1d[2] = (exp[1] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[3] = exp[1] & 0xff; - dev->sensor.regs_0x10_0x1d[4] = (exp[2] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[5] = exp[2] & 0xff; - - /* cleanup before return */ - free (line); - - /* go back home */ - if(move>20) - { - status=gl846_slow_back_home (dev, SANE_TRUE); - } - - DBGCOMPLETED; - return status; -} - -/** - * set up GPIO/GPOE for idle state - */ -static SANE_Status -gl846_init_gpio (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx=0; - - DBGSTART; - - /* search GPIO profile */ - while(gpios[idx].sensor_id!=0 && dev->model->gpo_type!=gpios[idx].sensor_id) - { - idx++; - } - if(gpios[idx].sensor_id==0) - { - DBG (DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __func__, dev->model->ccd_type); - return SANE_STATUS_INVAL; - } - - RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); - RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); - - RIE (sanei_genesys_write_register (dev, REG6B, gpios[idx].r6b)); - RIE (sanei_genesys_write_register (dev, REG6C, gpios[idx].r6c)); - RIE (sanei_genesys_write_register (dev, REG6D, gpios[idx].r6d)); - RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); - RIE (sanei_genesys_write_register (dev, REG6F, gpios[idx].r6f)); - - RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); - RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); - - DBGCOMPLETED; - return status; -} - -/** - * set memory layout by filling values in dedicated registers - */ -static SANE_Status -gl846_init_memory_layout (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx = 0, i; - uint8_t val; - - DBGSTART - - /* point to per model memory layout */ - idx = 0; - while(layouts[idx].model!=NULL && strcmp(dev->model->name,layouts[idx].model)!=0) - { - if(strcmp(dev->model->name,layouts[idx].model)!=0) - idx++; - } - if(layouts[idx].model==NULL) - { - DBG(DBG_error, "%s: failed to find memory layout for model %s!\n", __func__, dev->model->name); - return SANE_STATUS_INVAL; - } - - /* CLKSET and DRAMSEL */ - val = layouts[idx].dramsel; - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg[reg_0x0b].value = val; - - /* prevent further writings by bulk write register */ - dev->reg[reg_0x0b].address = 0x00; - - /* setup base address for shading and scanned data. */ - for(i=0;i<10;i++) - { - sanei_genesys_write_register (dev, 0xe0+i, layouts[idx].rx[i]); - } - - DBGCOMPLETED; - return status; -} - -/* * - * initialize ASIC from power on condition - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl846_boot (Genesys_Device * dev, SANE_Bool cold) -{ - SANE_Status status; - uint8_t val; - - DBGSTART; - - /* reset ASIC if cold boot */ - if(cold) - { - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - } - - if(dev->usb_mode == 1) - { - val = 0x14; - } - else - { - val = 0x11; - } - RIE (sanei_genesys_write_0x8c (dev, 0x0f, val)); - - /* test CHKVER */ - RIE (sanei_genesys_read_register (dev, REG40, &val)); - if (val & REG40_CHKVER) - { - RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG (DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); - } - - /* Set default values for registers */ - gl846_init_registers (dev); - - /* Write initial registers */ - RIE (dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL846_MAX_REGS)); - - /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ - val = dev->reg[reg_0x0b].value & REG0B_DRAMSEL; - val = (val | REG0B_ENBDRAM); - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg[reg_0x0b].value = val; - - /* CIS_LINE */ - if (dev->model->is_cis) - { - SETREG (0x08, REG08_CIS_LINE); - RIE (sanei_genesys_write_register (dev, 0x08, dev->reg[reg_0x08].value)); - } - - /* set up clocks */ - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0e)); - RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); - - /* setup gpio */ - RIE (gl846_init_gpio (dev)); - - /* setup internal memory layout */ - RIE (gl846_init_memory_layout (dev)); - - SETREG (0xf8, 0x05); - RIE (sanei_genesys_write_register (dev, 0xf8, dev->reg[reg_0xf8].value)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl846_init (Genesys_Device * dev) -{ - SANE_Status status; - - DBG_INIT (); - DBGSTART; - - status=sanei_genesys_asic_init(dev, GENESYS_GL846_MAX_REGS); - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl846_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not lose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - uint8_t scan, file, email, copy; - switch(s->dev->model->gpo_type) - { - default: - scan=0x01; - file=0x02; - email=0x04; - copy=0x08; - } - RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); - - if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) - s->val[OPT_SCAN_SW].b = (val & scan) == 0; - if (s->val[OPT_FILE_SW].b == s->last_val[OPT_FILE_SW].b) - s->val[OPT_FILE_SW].b = (val & file) == 0; - if (s->val[OPT_EMAIL_SW].b == s->last_val[OPT_EMAIL_SW].b) - s->val[OPT_EMAIL_SW].b = (val & email) == 0; - if (s->val[OPT_COPY_SW].b == s->last_val[OPT_COPY_SW].b) - s->val[OPT_COPY_SW].b = (val & copy) == 0; - - return status; -} - -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl846_search_strip (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black) -{ - unsigned int pixels, lines, channels; - SANE_Status status; - Genesys_Register_Set local_reg[GENESYS_GL846_MAX_REGS]; - size_t size; - uint8_t *data; - int steps, depth, dpi; - unsigned int pass, count, found, x, y; - char title[80]; - Genesys_Register_Set *r; - - DBG (DBG_proc, "gl846_search_strip %s %s\n", black ? "black" : "white", - forward ? "forward" : "reverse"); - - status = gl846_set_fe (dev, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_search_strip: gl846_set_fe() failed: %s\n", - sane_strstatus(status)); - return status; - } - - status = gl846_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_search_strip: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - - /* set up for a gray scan at lowest dpi */ - dpi = 9600; - for (x = 0; x < MAX_RESOLUTIONS; x++) - { - if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) - dpi = dev->model->xdpi_values[x]; - } - channels = 1; - /* 10 MM */ - /* lines = (10 * dpi) / MM_PER_INCH; */ - /* shading calibation is done with dev->motor.base_ydpi */ - lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; - depth = 8; - pixels = (dev->sensor.sensor_pixels * dpi) / dev->sensor.optical_res; - size = pixels * channels * lines * (depth / 8); - data = malloc (size); - if (!data) - { - DBG (DBG_error, "gl846_search_strip: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - dev->scanhead_position_in_steps = 0; - - memcpy (local_reg, dev->reg, - GENESYS_GL846_MAX_REGS * sizeof (Genesys_Register_Set)); - - status = gl846_init_scan_regs (dev, - local_reg, - dpi, - dpi, - 0, - 0, - pixels, - lines, - depth, - channels, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA); - if (status != SANE_STATUS_GOOD) - { - free(data); - DBG (DBG_error, - "gl846_search_strip: failed to setup for scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* set up for reverse or forward */ - r = sanei_genesys_get_address (local_reg, REG02); - if (forward) - r->value &= ~REG02_MTRREV; - else - r->value |= REG02_MTRREV; - - - status = dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL846_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - free(data); - DBG (DBG_error, - "gl846_search_strip: Failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl846_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl846_search_strip: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl846_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl846_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, "gl846_search_strip: gl846_stop_action failed\n"); - return status; - } - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file (title, data, depth, channels, pixels, - lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < 20 && !found) - { - status = dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL846_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_search_strip: Failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - /* now start scan */ - status = gl846_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl846_search_strip: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl846_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl846_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, "gl846_search_strip: gl846_stop_action failed\n"); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file (title, data, depth, channels, - pixels, lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG (DBG_data, - "gl846_search_strip: strip found forward during pass %d at line %d\n", - pass, y); - } - else - { - DBG (DBG_data, - "gl846_search_strip: pixels=%d, count=%d (%d%%)\n", - pixels, count, (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG (DBG_data, - "gl846_search_strip: strip found backward during pass %d \n", - pass); - } - else - { - DBG (DBG_data, - "gl846_search_strip: pixels=%d, count=%d (%d%%)\n", - pixels, count, (100 * count) / pixels); - } - } - pass++; - } - free (data); - if (found) - { - status = SANE_STATUS_GOOD; - DBG (DBG_info, "gl846_search_strip: %s strip found\n", - black ? "black" : "white"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG (DBG_info, "gl846_search_strip: %s strip not found\n", - black ? "black" : "white"); - } - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a 8 bits scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black) -{ - unsigned int i, j, k, average, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average value on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG (DBG_info, "dark_average: avg[%d] = %d\n", k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG (DBG_info, "dark_average: average = %d\n", average); - return average; -} - -static SANE_Status -gl846_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *first_line, *second_line, reg04; - unsigned int channels, bpp; - char title[32]; - int pass = 0, avg, total_size; - int topavg, bottomavg, resolution, lines; - int top, bottom, black_pixels, pixels; - - DBGSTART; - - /* no gain nor offset for AKM AFE */ - RIE (sanei_genesys_read_register (dev, REG04, ®04)); - if ((reg04 & REG04_FESET) == 0x02) - { - DBGCOMPLETED; - return status; - } - - /* offset calibration is always done in color mode */ - channels = 3; - resolution=dev->sensor.optical_res; - dev->calib_pixels = dev->sensor.sensor_pixels; - lines=1; - bpp=8; - pixels= (dev->sensor.sensor_pixels*resolution) / dev->sensor.optical_res; - black_pixels = (dev->sensor.black_pixels * resolution) / dev->sensor.optical_res; - DBG (DBG_io2, "gl846_offset_calibration: black_pixels=%d\n", black_pixels); - - status = gl846_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - pixels, - lines, - bpp, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_offset_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - gl846_set_motor_power (dev->calib_reg, SANE_FALSE); - - /* allocate memory for scans */ - total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ - - first_line = malloc (total_size); - if (!first_line) - return SANE_STATUS_NO_MEM; - - second_line = malloc (total_size); - if (!second_line) - { - free (first_line); - return SANE_STATUS_NO_MEM; - } - - /* init gain */ - dev->frontend.gain[0] = 0; - dev->frontend.gain[1] = 0; - dev->frontend.gain[2] = 0; - - /* scan with no move */ - bottom = 10; - dev->frontend.offset[0] = bottom; - dev->frontend.offset[1] = bottom; - dev->frontend.offset[2] = bottom; - - RIEF2 (gl846_set_fe(dev, AFE_SET), first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL846_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl846_offset_calibration: starting first line reading\n"); - RIEF2 (gl846_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, first_line, total_size), first_line, second_line); - if (DBG_LEVEL >= DBG_data) - { - snprintf(title,20,"offset%03d.pnm",bottom); - sanei_genesys_write_pnm_file (title, first_line, bpp, channels, pixels, lines); - } - - bottomavg = dark_average (first_line, pixels, lines, channels, black_pixels); - DBG (DBG_io2, "gl846_offset_calibration: bottom avg=%d\n", bottomavg); - - /* now top value */ - top = 255; - dev->frontend.offset[0] = top; - dev->frontend.offset[1] = top; - dev->frontend.offset[2] = top; - RIEF2 (gl846_set_fe(dev, AFE_SET), first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL846_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl846_offset_calibration: starting second line reading\n"); - RIEF2 (gl846_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); - - topavg = dark_average (second_line, pixels, lines, channels, black_pixels); - DBG (DBG_io2, "gl846_offset_calibration: top avg=%d\n", topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.offset[0] = (top + bottom) / 2; - dev->frontend.offset[1] = (top + bottom) / 2; - dev->frontend.offset[2] = (top + bottom) / 2; - - /* scan with no move */ - RIEF2 (gl846_set_fe(dev, AFE_SET), first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL846_MAX_REGS), first_line, second_line); - DBG (DBG_info, "gl846_offset_calibration: starting second line reading\n"); - RIEF2 (gl846_begin_scan (dev, dev->calib_reg, SANE_TRUE), first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size), first_line, second_line); - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", dev->frontend.offset[1]); - sanei_genesys_write_pnm_file (title, second_line, bpp, channels, pixels, lines); - } - - avg = dark_average (second_line, pixels, lines, channels, black_pixels); - DBG (DBG_info, "gl846_offset_calibration: avg=%d offset=%d\n", avg, - dev->frontend.offset[1]); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.offset[1]; - } - else - { - bottomavg = avg; - bottom = dev->frontend.offset[1]; - } - } - DBG (DBG_info, "gl846_offset_calibration: offset=(%d,%d,%d)\n", dev->frontend.offset[0], dev->frontend.offset[1], dev->frontend.offset[2]); - - /* cleanup before return */ - free (first_line); - free (second_line); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl846_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - int pixels; - int total_size; - uint8_t *line, reg04; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3],coeff; - int val, code, lines; - int resolution; - int bpp; - - DBG (DBG_proc, "gl846_coarse_gain_calibration: dpi = %d\n", dpi); - - /* no gain nor offset for AKM AFE */ - RIE (sanei_genesys_read_register (dev, REG04, ®04)); - if ((reg04 & REG04_FESET) == 0x02) - { - DBGCOMPLETED; - return status; - } - - /* coarse gain calibration is always done in color mode */ - channels = 3; - - /* follow CKSEL */ - if(dev->settings.xressensor.optical_res) - { - coeff=0.9; - /*resolution=dev->sensor.optical_res/2;*/ - resolution=dev->sensor.optical_res; - } - else - { - resolution=dev->sensor.optical_res; - coeff=1.0; - } - lines=10; - bpp=8; - pixels = (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - - status = gl846_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - pixels, - lines, - bpp, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - gl846_set_motor_power (dev->calib_reg, SANE_FALSE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl846_coarse_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - RIE (dev->model->cmd_set->bulk_write_register - (dev, dev->calib_reg, GENESYS_GL846_MAX_REGS)); - - total_size = pixels * channels * (16/bpp) * lines; - - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - - RIEF (gl846_set_fe(dev, AFE_SET), line); - RIEF (gl846_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, total_size), line); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("coarse.pnm", line, bpp, channels, pixels, lines); - - /* average value on each channel */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = pixels/4; i < (pixels*3/4); i++) - { - if (dev->model->is_cis) - val = line[i + j * pixels]; - else - val = line[i * channels + j]; - - max[j] += val; - } - max[j] = max[j] / (pixels/2); - - gain[j] = ((float) dev->sensor.gain_white_ref*coeff) / max[j]; - - /* turn logical gain value into gain code, checking for overflow */ - code = 283 - 208 / gain[j]; - if (code > 255) - code = 255; - else if (code < 0) - code = 0; - dev->frontend.gain[j] = code; - - DBG (DBG_proc, - "gl846_coarse_gain_calibration: channel %d, max=%d, gain = %f, setting:%d\n", - j, max[j], gain[j], dev->frontend.gain[j]); - } - - if (dev->model->is_cis) - { - if (dev->frontend.gain[0] > dev->frontend.gain[1]) - dev->frontend.gain[0] = dev->frontend.gain[1]; - if (dev->frontend.gain[0] > dev->frontend.gain[2]) - dev->frontend.gain[0] = dev->frontend.gain[2]; - dev->frontend.gain[2] = dev->frontend.gain[1] = dev->frontend.gain[0]; - } - - free (line); - - RIE (gl846_stop_action (dev)); - - status=gl846_slow_back_home (dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - - -/** the gl846 command set */ -static Genesys_Command_Set gl846_cmd_set = { - "gl846-generic", /* the name of this set */ - - gl846_init, - NULL, - gl846_init_regs_for_coarse_calibration, - gl846_init_regs_for_shading, - gl846_init_regs_for_scan, - - gl846_get_filter_bit, - gl846_get_lineart_bit, - gl846_get_bitset_bit, - gl846_get_gain4_bit, - gl846_get_fast_feed_bit, - gl846_test_buffer_empty_bit, - gl846_test_motor_flag_bit, - - gl846_bulk_full_size, - - gl846_set_fe, - gl846_set_powersaving, - gl846_save_power, - - gl846_set_motor_power, - gl846_set_lamp_power, - - gl846_begin_scan, - gl846_end_scan, - - sanei_genesys_send_gamma_table, - - gl846_search_start_position, - - gl846_offset_calibration, - gl846_coarse_gain_calibration, - gl846_led_calibration, - - gl846_slow_back_home, - NULL, - - sanei_genesys_bulk_write_register, - NULL, - gl846_bulk_read_data, - - gl846_update_hardware_sensors, - - NULL, - NULL, - NULL, - gl846_search_strip, - - sanei_genesys_is_compatible_calibration, - NULL, - gl846_send_shading_data, - gl846_calculate_current_setup, - gl846_boot, - NULL -}; - -SANE_Status -sanei_gl846_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl846_cmd_set; - return SANE_STATUS_GOOD; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl846.cc b/backend/genesys_gl846.cc new file mode 100644 index 0000000..c5294b8 --- /dev/null +++ b/backend/genesys_gl846.cc @@ -0,0 +1,3393 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2012-2013 Stéphane Voltz + + + 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. +*/ + +/** @file + * + * This file handles GL846 and GL845 ASICs since they are really close to each other. + */ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_gl846.h" + +#include + +/**************************************************************************** + Mid level functions + ****************************************************************************/ + +static SANE_Bool +gl846_get_fast_feed_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG02); + if (r && (r->value & REG02_FASTFED)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl846_get_filter_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_FILTER)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl846_get_lineart_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_LINEART)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl846_get_bitset_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_BITSET)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl846_get_gain4_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x06); + if (r && (r->value & REG06_GAIN4)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl846_test_buffer_empty_bit (SANE_Byte val) +{ + if (val & REG41_BUFEMPTY) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl846_test_motor_flag_bit (SANE_Byte val) +{ + if (val & REG41_MOTORENB) + return SANE_TRUE; + return SANE_FALSE; +} + +/** + * compute the step multiplier used + */ +static int +gl846_get_step_multiplier (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + int value = 1; + + r = sanei_genesys_get_address (regs, 0x9d); + if (r != NULL) + { + value = (r->value & 0x0f)>>1; + value = 1 << value; + } + DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); + return value; +} + +/** @brief sensor profile + * search for the database of motor profiles and get the best one. Each + * profile is at a specific dpihw. Use LiDE 110 table by default. + * @param sensor_type sensor id + * @param dpi hardware dpi for the scan + * @return a pointer to a Sensor_Profile struct + */ +static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi) +{ + unsigned int i; + int idx; + + i=0; + idx=-1; + while(i=dpi + && sensors[i].dpimodel->ccd_type, xres); + return sensor_profile->exposure; +} + + +/** @brief sensor specific settings +*/ +static void gl846_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * regs, int dpi) +{ + GenesysRegister *r; + int dpihw; + uint16_t exp; + + DBGSTART; + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpi); + + for (uint16_t addr = 0x16; addr < 0x1e; addr++) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + for (uint16_t addr = 0x52; addr < 0x52 + 9; addr++) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + /* set EXPDUMMY and CKxMAP */ + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpi); + Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw); + + sanei_genesys_set_reg_from_set(regs,REG_EXPDMY,(uint8_t)((sensor_profile->expdummy) & 0xff)); + + /* if no calibration has been done, set default values for exposures */ + exp = sensor.exposure.red; + if(exp==0) + { + exp=sensor_profile->expr; + } + sanei_genesys_set_double(regs,REG_EXPR,exp); + + exp = sensor.exposure.green; + if(exp==0) + { + exp=sensor_profile->expg; + } + sanei_genesys_set_double(regs,REG_EXPG,exp); + + exp = sensor.exposure.blue; + if(exp==0) + { + exp=sensor_profile->expb; + } + sanei_genesys_set_double(regs,REG_EXPB,exp); + + sanei_genesys_set_triple(regs,REG_CK1MAP,sensor_profile->ck1map); + sanei_genesys_set_triple(regs,REG_CK3MAP,sensor_profile->ck3map); + sanei_genesys_set_triple(regs,REG_CK4MAP,sensor_profile->ck4map); + + /* order of the sub-segments */ + dev->order=sensor_profile->order; + + r = sanei_genesys_get_address (regs, 0x17); + r->value = sensor_profile->r17; + + DBGCOMPLETED; +} + + +/** @brief set all registers to default values . + * This function is called only once at the beginning and + * fills register startup values for registers reused across scans. + * Those that are rarely modified or not modified are written + * individually. + * @param dev device structure holding register set to initialize + */ +static void +gl846_init_registers (Genesys_Device * dev) +{ + DBGSTART; + + dev->reg.clear(); + + SETREG (0x01,0x60); + SETREG (0x02,0x38); + SETREG (0x03,0x03); + SETREG (0x04,0x22); + SETREG (0x05,0x60); + SETREG (0x06,0x10); + SETREG (0x08,0x60); + SETREG (0x09,0x00); + SETREG (0x0a,0x00); + SETREG (0x0b,0x8b); + SETREG (0x0c,0x00); + SETREG (0x0d,0x00); + SETREG (0x10,0x00); + SETREG (0x11,0x00); + SETREG (0x12,0x00); + SETREG (0x13,0x00); + SETREG (0x14,0x00); + SETREG (0x15,0x00); + SETREG (0x16,0xbb); + SETREG (0x17,0x13); + SETREG (0x18,0x10); + SETREG (0x19,0x2a); + SETREG (0x1a,0x34); + SETREG (0x1b,0x00); + SETREG (0x1c,0x20); + SETREG (0x1d,0x06); + SETREG (0x1e,0xf0); + SETREG (0x1f,0x01); + SETREG (0x20,0x03); + SETREG (0x21,0x10); + SETREG (0x22,0x60); + SETREG (0x23,0x60); + SETREG (0x24,0x60); + SETREG (0x25,0x00); + SETREG (0x26,0x00); + SETREG (0x27,0x00); + SETREG (0x2c,0x00); + SETREG (0x2d,0x00); + SETREG (0x2e,0x80); + SETREG (0x2f,0x80); + SETREG (0x30,0x00); + SETREG (0x31,0x00); + SETREG (0x32,0x00); + SETREG (0x33,0x00); + SETREG (0x34,0x1f); + SETREG (0x35,0x00); + SETREG (0x36,0x40); + SETREG (0x37,0x00); + SETREG (0x38,0x2a); + SETREG (0x39,0xf8); + SETREG (0x3d,0x00); + SETREG (0x3e,0x00); + SETREG (0x3f,0x01); + SETREG (0x52,0x02); + SETREG (0x53,0x04); + SETREG (0x54,0x06); + SETREG (0x55,0x08); + SETREG (0x56,0x0a); + SETREG (0x57,0x00); + SETREG (0x58,0x59); + SETREG (0x59,0x31); + SETREG (0x5a,0x40); + SETREG (0x5e,0x1f); + SETREG (0x5f,0x01); + SETREG (0x60,0x00); + SETREG (0x61,0x00); + SETREG (0x62,0x00); + SETREG (0x63,0x00); + SETREG (0x64,0x00); + SETREG (0x65,0x00); + SETREG (0x67,0x7f); + SETREG (0x68,0x7f); + SETREG (0x69,0x01); + SETREG (0x6a,0x01); + SETREG (0x70,0x01); + SETREG (0x71,0x00); + SETREG (0x72,0x02); + SETREG (0x73,0x01); + SETREG (0x74,0x00); + SETREG (0x75,0x00); + SETREG (0x76,0x00); + SETREG (0x77,0x00); + SETREG (0x78,0x00); + SETREG (0x79,0x3f); + SETREG (0x7a,0x00); + SETREG (0x7b,0x09); + SETREG (0x7c,0x99); + SETREG (0x7d,0x20); + SETREG (0x7f,0x05); + SETREG (0x80,0x4f); + SETREG (0x87,0x02); + SETREG (0x94,0xff); + SETREG (0x9d,0x04); + SETREG (0x9e,0x00); + SETREG (0xa1,0xe0); + SETREG (0xa2,0x1f); + SETREG (0xab,0xc0); + SETREG (0xbb,0x00); + SETREG (0xbc,0x0f); + SETREG (0xdb,0xff); + SETREG (0xfe,0x08); + SETREG (0xff,0x02); + SETREG (0x98,0x20); + SETREG (0x99,0x00); + SETREG (0x9a,0x90); + SETREG (0x9b,0x00); + SETREG (0xf8,0x05); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + /* fine tune upon device description */ + dev->reg.find_reg(0x05).value &= ~REG05_DPIHW; + switch (sensor.optical_res) + { + case 600: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; + break; + case 1200: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; + break; + case 2400: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; + break; + case 4800: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_4800; + break; + } + + /* initalize calibration reg */ + dev->calib_reg = dev->reg; + + DBGCOMPLETED; +} + +/**@brief send slope table for motor movement + * Send slope_table in machine byte order + * @param dev device to send slope table + * @param table_nr index of the slope table in ASIC memory + * Must be in the [0-4] range. + * @param slope_table pointer to 16 bit values array of the slope table + * @param steps number of elements in the slope table + */ +static SANE_Status +gl846_send_slope_table (Genesys_Device * dev, int table_nr, + uint16_t * slope_table, int steps) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + char msg[10000]; + + DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, + table_nr, steps); + + /* sanity check */ + if(table_nr<0 || table_nr>4) + { + DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); + return SANE_STATUS_INVAL; + } + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + sprintf (msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) + { + sprintf (msg+strlen(msg), "%d", slope_table[i]); + } + DBG (DBG_io, "%s: %s\n", __func__, msg); + } + + /* slope table addresses are fixed */ + status = sanei_genesys_write_ahb(dev, 0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: write to AHB failed writing slope table %d (%s)\n", __func__, table_nr, + sane_strstatus(status)); + } + + DBGCOMPLETED; + return status; +} + +/** + * Set register values of Analog Device type frontend + * */ +static SANE_Status +gl846_set_adi_fe (Genesys_Device * dev, uint8_t set) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + uint8_t val8; + + DBGSTART; + + /* wait for FE to be ready */ + status = sanei_genesys_get_status (dev, &val8); + while (val8 & REG41_FEBUSY) + { + sanei_genesys_sleep_ms(10); + status = sanei_genesys_get_status (dev, &val8); + }; + + if (set == AFE_INIT) + { + DBG (DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + dev->frontend = dev->frontend_initial; + } + + /* write them to analog frontend */ + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, + sane_strstatus (status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to write reg1: %s\n", __func__, + sane_strstatus (status)); + return status; + } + + for (i = 0; i < 3; i++) + { + status = sanei_genesys_fe_write_data(dev, 0x02 + i, dev->frontend.get_gain(i)); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to write gain %d: %s\n", __func__, i, + sane_strstatus (status)); + return status; + } + } + for (i = 0; i < 3; i++) + { + status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.get_offset(i)); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to write offset %d: %s\n", __func__, i, + sane_strstatus (status)); + return status; + } + } + + DBGCOMPLETED; + return status; +} + +static SANE_Status +gl846_homsnr_gpio(Genesys_Device *dev) +{ +uint8_t val; +SANE_Status status=SANE_STATUS_GOOD; + + RIE (sanei_genesys_read_register (dev, REG6C, &val)); + val |= 0x41; + RIE (sanei_genesys_write_register (dev, REG6C, val)); + + return status; +} + +/* Set values of analog frontend */ +static SANE_Status +gl846_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) +{ + (void) sensor; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (%s)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : + set == AFE_POWER_SAVE ? "powersave" : "huh?"); + + /* route to specific analog frontend setup */ + switch (dev->reg.find_reg(0x04).value & REG04_FESET) + { + case 0x02: /* ADI FE */ + status = gl846_set_adi_fe(dev, set); + break; + default: + DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, + dev->reg.find_reg(0x04).value & REG04_FESET); + status = SANE_STATUS_UNSUPPORTED; + } + + DBGCOMPLETED; + return status; +} + + +/** @brief set up motor related register for scan + */ +static SANE_Status +gl846_init_motor_regs_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int scan_exposure_time, + float scan_yres, + int scan_step_type, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + int scan_power_mode, + unsigned int flags) +{ + SANE_Status status = SANE_STATUS_GOOD; + int use_fast_fed; + unsigned int fast_dpi; + uint16_t scan_table[SLOPE_TABLE_SIZE]; + uint16_t fast_table[SLOPE_TABLE_SIZE]; + int scan_steps, fast_steps, factor; + unsigned int feedl, dist; + GenesysRegister *r; + uint32_t z1, z2; + unsigned int min_restep = 0x20; + uint8_t val; + int fast_step_type; + unsigned int ccdlmt,tgtime; + + DBGSTART; + DBG(DBG_proc, "%s : scan_exposure_time=%d, scan_yres=%g, scan_step_type=%d, scan_lines=%d, " + "scan_dummy=%d, feed_steps=%d, scan_power_mode=%d, flags=%x\n", __func__, scan_exposure_time, + scan_yres, scan_step_type, scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); + + /* get step multiplier */ + factor = gl846_get_step_multiplier (reg); + + use_fast_fed=0; + /* no fast fed since feed works well */ + if(dev->settings.yres==4444 && feed_steps>100 + && ((flags & MOTOR_FLAG_FEED)==0)) + { + use_fast_fed=1; + } + DBG (DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); + + sanei_genesys_set_triple(reg, REG_LINCNT, scan_lines); + DBG (DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); + + /* compute register 02 value */ + r = sanei_genesys_get_address (reg, REG02); + r->value = 0x00; + sanei_genesys_set_motor_power(*reg, true); + + if (use_fast_fed) + r->value |= REG02_FASTFED; + else + r->value &= ~REG02_FASTFED; + + if (flags & MOTOR_FLAG_AUTO_GO_HOME) + r->value |= REG02_AGOHOME | REG02_NOTHOME; + + if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) + ||(scan_yres>=sensor.optical_res)) + { + r->value |= REG02_ACDCDIS; + } + + /* scan and backtracking slope table */ + sanei_genesys_slope_table(scan_table, + &scan_steps, + scan_yres, + scan_exposure_time, + dev->motor.base_ydpi, + scan_step_type, + factor, + dev->model->motor_type, + gl846_motors); + RIE(gl846_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); + RIE(gl846_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); + + /* fast table */ + fast_dpi=sanei_genesys_get_lowest_ydpi(dev); + fast_step_type=scan_step_type; + if(scan_step_type>=2) + { + fast_step_type=2; + } + + sanei_genesys_slope_table(fast_table, + &fast_steps, + fast_dpi, + scan_exposure_time, + dev->motor.base_ydpi, + fast_step_type, + factor, + dev->model->motor_type, + gl846_motors); + + /* manual override of high start value */ + fast_table[0]=fast_table[1]; + + RIE(gl846_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); + RIE(gl846_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); + RIE(gl846_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); + + /* correct move distance by acceleration and deceleration amounts */ + feedl=feed_steps; + if (use_fast_fed) + { + feedl<<=fast_step_type; + dist=(scan_steps+2*fast_steps)*factor; + /* TODO read and decode REGAB */ + r = sanei_genesys_get_address (reg, 0x5e); + dist += (r->value & 31); + /* FEDCNT */ + r = sanei_genesys_get_address (reg, REG_FEDCNT); + dist += r->value; + } + else + { + feedl<<=scan_step_type; + dist=scan_steps*factor; + if (flags & MOTOR_FLAG_FEED) + dist *=2; + } + DBG (DBG_io2, "%s: scan steps=%d\n", __func__, scan_steps); + DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + /* check for overflow */ + if(distvalue & REG0C_CCDLMT)+1; + + r = sanei_genesys_get_address (reg, REG1C); + tgtime=1<<(r->value & REG1C_TGTIME); + + /* hi res motor speed GPIO */ + /* + RIE (sanei_genesys_read_register (dev, REG6C, &effective)); + */ + + /* if quarter step, bipolar Vref2 */ + /* XXX STEF XXX GPIO + if (scan_step_type > 1) + { + if (scan_step_type < 3) + { + val = effective & ~REG6C_GPIO13; + } + else + { + val = effective | REG6C_GPIO13; + } + } + else + { + val = effective; + } + RIE (sanei_genesys_write_register (dev, REG6C, val)); + */ + + /* effective scan */ + /* + RIE (sanei_genesys_read_register (dev, REG6C, &effective)); + val = effective | REG6C_GPIO10; + RIE (sanei_genesys_write_register (dev, REG6C, val)); + */ + + if(dev->model->gpo_type==GPO_IMG101) + { + if(scan_yres==sanei_genesys_compute_dpihw(dev, sensor,scan_yres)) + { + val=1; + } + else + { + val=0; + } + RIE (sanei_genesys_write_register (dev, REG7E, val)); + } + + min_restep=scan_steps/2-1; + if (min_restep < 1) + min_restep = 1; + r = sanei_genesys_get_address (reg, REG_FWDSTEP); + r->value = min_restep; + r = sanei_genesys_get_address (reg, REG_BWDSTEP); + r->value = min_restep; + + sanei_genesys_calculate_zmode2(use_fast_fed, + scan_exposure_time*ccdlmt*tgtime, + scan_table, + scan_steps*factor, + feedl, + min_restep*factor, + &z1, + &z2); + + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + sanei_genesys_set_triple(reg, REG60, z1 | (scan_step_type << (16+REG60S_STEPSEL))); + + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + sanei_genesys_set_triple(reg, REG63, z2 | (scan_step_type << (16+REG63S_FSTPSEL))); + + r = sanei_genesys_get_address (reg, 0x1e); + r->value &= 0xf0; /* 0 dummy lines */ + r->value |= scan_dummy; /* dummy lines */ + + r = sanei_genesys_get_address (reg, REG67); + r->value = 0x7f; + + r = sanei_genesys_get_address (reg, REG68); + r->value = 0x7f; + + r = sanei_genesys_get_address (reg, REG_STEPNO); + r->value = scan_steps; + + r = sanei_genesys_get_address (reg, REG_FASTNO); + r->value = scan_steps; + + r = sanei_genesys_get_address (reg, REG_FSHDEC); + r->value = scan_steps; + + r = sanei_genesys_get_address (reg, REG_FMOVNO); + r->value = fast_steps; + + r = sanei_genesys_get_address (reg, REG_FMOVDEC); + r->value = fast_steps; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** @brief set up registers related to sensor + * Set up the following registers + 0x01 + 0x03 + 0x10-0x015 R/G/B exposures + 0x19 EXPDMY + 0x2e BWHI + 0x2f BWLO + 0x04 + 0x87 + 0x05 + 0x2c,0x2d DPISET + 0x30,0x31 STRPIXEL + 0x32,0x33 ENDPIXEL + 0x35,0x36,0x37 MAXWD [25:2] (>>2) + 0x38,0x39 LPERIOD + 0x34 DUMMY + */ +static SANE_Status +gl846_init_optical_regs_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int exposure_time, + int used_res, + unsigned int start, + unsigned int pixels, + int channels, + int depth, + SANE_Bool half_ccd, ColorFilter color_filter, int flags) +{ + unsigned int words_per_line; + unsigned int startx, endx, used_pixels; + unsigned int dpiset, dpihw,segnb,cksel,factor; + unsigned int bytes; + GenesysRegister *r; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s : exposure_time=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " + "half_ccd=%d, flags=%x\n", __func__, exposure_time, used_res, start, pixels, channels, depth, + half_ccd, flags); + + /* resolution is divided according to CKSEL */ + r = sanei_genesys_get_address (reg, REG18); + cksel= (r->value & REG18_CKSEL)+1; + DBG(DBG_io2, "%s: cksel=%d\n", __func__, cksel); + + /* to manage high resolution device while keeping good + * low resolution scanning speed, we make hardware dpi vary */ + dpihw=sanei_genesys_compute_dpihw(dev, sensor, used_res * cksel); + factor=sensor.optical_res/dpihw; + DBG(DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); + + /* sensor parameters */ + Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw); + gl846_setup_sensor(dev, sensor, reg, dpihw); + dpiset = used_res * cksel; + + /* start and end coordinate in optical dpi coordinates */ + startx = start/cksel+sensor.CCD_start_xoffset; + used_pixels=pixels/cksel; + + /* end of sensor window */ + endx = startx + used_pixels; + + /* sensors are built from 600 dpi segments for LiDE 100/200 + * and 1200 dpi for the 700F */ + if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR) + { + segnb=dpihw/600; + } + else + { + segnb=1; + } + + /* compute pixel coordinate in the given dpihw space, + * taking segments into account */ + startx/=factor*segnb; + endx/=factor*segnb; + dev->len=endx-startx; + dev->dist=0; + dev->skip=0; + + /* in cas of multi-segments sensor, we have to add the witdh + * of the sensor crossed by the scan area */ + if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR && segnb>1) + { + dev->dist = sensor_profile->segcnt; + } + + /* use a segcnt rounded to next even number */ + endx += ((dev->dist+1)&0xfffe)*(segnb-1); + used_pixels=endx-startx; + + status = gl846_set_fe(dev, sensor, AFE_SET); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* enable shading */ + r = sanei_genesys_get_address (reg, REG01); + r->value &= ~REG01_SCAN; + r->value |= REG01_SHDAREA; + if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + r->value &= ~REG01_DVDSET; + } + else + { + r->value |= REG01_DVDSET; + } + + r = sanei_genesys_get_address (reg, REG03); + r->value &= ~REG03_AVEENB; + + sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); + + /* BW threshold */ + r = sanei_genesys_get_address (reg, 0x2e); + r->value = dev->settings.threshold; + r = sanei_genesys_get_address (reg, 0x2f); + r->value = dev->settings.threshold; + + /* monochrome / color scan */ + r = sanei_genesys_get_address (reg, REG04); + switch (depth) + { + case 1: + r->value &= ~REG04_BITSET; + r->value |= REG04_LINEART; + break; + case 8: + r->value &= ~(REG04_LINEART | REG04_BITSET); + break; + case 16: + r->value &= ~REG04_LINEART; + r->value |= REG04_BITSET; + break; + } + + r->value &= ~(REG04_FILTER | REG04_AFEMOD); + if (channels == 1) + { + switch (color_filter) + { + case ColorFilter::RED: + r->value |= 0x24; + break; + case ColorFilter::BLUE: + r->value |= 0x2c; + break; + case ColorFilter::GREEN: + r->value |= 0x28; + break; + default: + break; // should not happen + } + } + else + r->value |= 0x20; /* mono */ + + /* register 05 */ + r = sanei_genesys_get_address (reg, REG05); + + /* set up dpihw */ + r->value &= ~REG05_DPIHW; + switch(dpihw) + { + case 600: + r->value |= REG05_DPIHW_600; + break; + case 1200: + r->value |= REG05_DPIHW_1200; + break; + case 2400: + r->value |= REG05_DPIHW_2400; + break; + case 4800: + r->value |= REG05_DPIHW_4800; + break; + } + + /* enable gamma tables */ + if (flags & OPTICAL_FLAG_DISABLE_GAMMA) + r->value &= ~REG05_GMMENB; + else + r->value |= REG05_GMMENB; + + /* CIS scanners can do true gray by setting LEDADD */ + /* we set up LEDADD only when asked */ + if (dev->model->is_cis == SANE_TRUE) + { + r = sanei_genesys_get_address (reg, 0x87); + r->value &= ~REG87_LEDADD; + if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) + { + r->value |= REG87_LEDADD; + } + /* RGB weighting + r = sanei_genesys_get_address (reg, 0x01); + r->value &= ~REG01_TRUEGRAY; + if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) + { + r->value |= REG01_TRUEGRAY; + }*/ + } + + /* words(16bit) before gamma, conversion to 8 bit or lineart*/ + words_per_line = (used_pixels * dpiset) / dpihw; + bytes=depth/8; + if (depth == 1) + { + words_per_line = (words_per_line+7)/8 ; + dev->len = (dev->len >> 3) + ((dev->len & 7) ? 1 : 0); + dev->dist = (dev->dist >> 3) + ((dev->dist & 7) ? 1 : 0); + } + else + { + words_per_line *= bytes; + dev->dist *= bytes; + dev->len *= bytes; + } + + dev->bpl = words_per_line; + dev->cur=0; + dev->segnb=segnb; + dev->line_interp = 0; + + sanei_genesys_set_double(reg,REG_DPISET,dpiset); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); + + sanei_genesys_set_double(reg,REG_STRPIXEL,startx); + sanei_genesys_set_double(reg,REG_ENDPIXEL,endx); + DBG (DBG_io2, "%s: startx=%d\n", __func__, startx); + DBG (DBG_io2, "%s: endx =%d\n", __func__, endx); + + DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); + DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); + DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); + DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); + DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); + DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); + DBG (DBG_io2, "%s: dev->segnb =%lu\n", __func__, (unsigned long)dev->segnb); + + words_per_line *= channels; + dev->wpl = words_per_line; + + dev->oe_buffer.clear(); + dev->oe_buffer.alloc(dev->wpl); + + /* MAXWD is expressed in 4 words unit */ + sanei_genesys_set_triple(reg, REG_MAXWD, (words_per_line >> 2)); + DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); + + sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); + DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); + + r = sanei_genesys_get_address (reg, 0x34); + r->value = sensor.dummy_pixel; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* set up registers for an actual scan + * + * this function sets up the scanner to scan in normal or single line mode + */ +static SANE_Status +gl846_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SetupParams& params) +{ + params.assert_valid(); + + int used_res; + int start, used_pixels; + int bytes_per_line; + int move; + unsigned int lincnt; + unsigned int oflags; /**> optical flags */ + unsigned int mflags; /**> motor flags */ + int exposure_time; + int stagger; + + int slope_dpi = 0; + int dummy = 0; + int scan_step_type = 1; + int scan_power_mode = 0; + int max_shift; + size_t requested_buffer_size, read_buffer_size; + + SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ + int optical_res; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + + /* we may have 2 domains for ccd: xres below or above half ccd max dpi */ + if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) + { + half_ccd = SANE_TRUE; + } + else + { + half_ccd = SANE_FALSE; + } + + /* optical_res */ + optical_res = sensor.optical_res; + if (half_ccd) + optical_res /= 2; + + /* stagger */ + if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG(DBG_info, "%s : stagger=%d lines\n", __func__, stagger); + + /* used_res */ + if (params.flags & SCAN_FLAG_USE_OPTICAL_RES) + { + used_res = optical_res; + } + else + { + /* resolution is choosen from a list */ + used_res = params.xres; + } + + /* compute scan parameters values */ + /* pixels are allways given at full optical resolution */ + /* use detected left margin and fixed value */ + /* start */ + /* add x coordinates */ + start = params.startx; + + if (stagger > 0) + start |= 1; + + /* compute correct pixels number */ + /* pixels */ + used_pixels = (params.pixels * optical_res) / params.xres; + + /* round up pixels number if needed */ + if (used_pixels * params.xres < params.pixels * optical_res) + used_pixels++; + + dummy = 3-params.channels; + +/* slope_dpi */ +/* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) + slope_dpi = params.yres * params.channels; + else + slope_dpi = params.yres; + + slope_dpi = slope_dpi * (1 + dummy); + + exposure_time = gl846_compute_exposure (dev, used_res); + scan_step_type = sanei_genesys_compute_step_type(gl846_motors, dev->model->motor_type, exposure_time); + + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); + +/*** optical parameters ***/ + /* in case of dynamic lineart, we use an internal 8 bit gray scan + * to generate 1 lineart data */ + if (params.flags & SCAN_FLAG_DYNAMIC_LINEART) { + params.depth = 8; + } + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + oflags = 0; + if(params.flags & SCAN_FLAG_DISABLE_SHADING) + oflags |= OPTICAL_FLAG_DISABLE_SHADING; + if(params.flags & SCAN_FLAG_DISABLE_GAMMA) + oflags |= OPTICAL_FLAG_DISABLE_GAMMA; + if(params.flags & SCAN_FLAG_DISABLE_LAMP) + oflags |= OPTICAL_FLAG_DISABLE_LAMP; + + if (dev->model->is_cis && dev->settings.true_gray) + { + oflags |= OPTICAL_FLAG_ENABLE_LEDADD; + } + + status = gl846_init_optical_regs_scan (dev, sensor, + reg, + exposure_time, + used_res, + start, + used_pixels, + params.channels, + params.depth, + half_ccd, + params.color_filter, + oflags); + + if (status != SANE_STATUS_GOOD) + return status; + +/*** motor parameters ***/ + + /* max_shift */ + max_shift=sanei_genesys_compute_max_shift(dev,params.channels,params.yres,params.flags); + + /* lincnt */ + lincnt = params.lines + max_shift + stagger; + + /* add tl_y to base movement */ + move = params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + mflags=0; + if(params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) + mflags |= MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; + if(params.flags & SCAN_FLAG_FEEDING) + mflags |= MOTOR_FLAG_FEED; + + status = gl846_init_motor_regs_scan (dev, sensor, + reg, + exposure_time, + slope_dpi, + scan_step_type, + dev->model->is_cis ? lincnt * + params.channels : lincnt, dummy, move, + scan_power_mode, + mflags); + + if (status != SANE_STATUS_GOOD) + return status; + + + /*** prepares data reordering ***/ + +/* words_per_line */ + bytes_per_line = (used_pixels * used_res) / optical_res; + bytes_per_line = (bytes_per_line * params.channels * params.depth) / 8; + + requested_buffer_size = 8 * bytes_per_line; + + read_buffer_size = + 2 * requested_buffer_size + + ((max_shift + stagger) * used_pixels * params.channels * params.depth) / 8; + + dev->read_buffer.clear(); + dev->read_buffer.alloc(read_buffer_size); + + dev->lines_buffer.clear(); + dev->lines_buffer.alloc(read_buffer_size); + + dev->shrink_buffer.clear(); + dev->shrink_buffer.alloc(requested_buffer_size); + + dev->out_buffer.clear(); + dev->out_buffer.alloc((8 * params.pixels * params.channels * params.depth) / 8); + + dev->read_bytes_left = bytes_per_line * lincnt; + + DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); + dev->read_active = SANE_TRUE; + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res) / optical_res; + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure_time; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + +/* TODO: should this be done elsewhere? */ + /* scan bytes to send to the frontend */ + /* theory : + target_size = + (params.pixels * params.lines * channels * depth) / 8; + but it suffers from integer overflow so we do the following: + + 1 bit color images store color data byte-wise, eg byte 0 contains + 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains + 8 bits of blue. + This does not fix the overflow, though. + 644mp*16 = 10gp, leading to an overflow + -- pierre + */ + + dev->total_bytes_read = 0; + if (params.depth == 1) + dev->total_bytes_to_read = + ((params.pixels * params.lines) / 8 + + (((params.pixels * params.lines) % 8) ? 1 : 0)) * + params.channels; + else + dev->total_bytes_to_read = + params.pixels * params.lines * params.channels * (params.depth / 8); + + DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); +/* END TODO */ + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static void +gl846_calculate_current_setup(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int depth; + int start; + + int used_res; + int used_pixels; + unsigned int lincnt; + int exposure_time; + int stagger; + + int slope_dpi; + int dummy = 0; + int max_shift; + + SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ + int optical_res; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + /* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + /* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + /* start */ + start = SANE_UNFIX (dev->model->x_offset); + start += dev->settings.tl_x; + start = (start * sensor.optical_res) / MM_PER_INCH; + + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; // not used + params.starty = 0; // not used + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = 0; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + +/* half_ccd */ + /* we have 2 domains for ccd: xres below or above half ccd max dpi */ + if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) { + half_ccd = SANE_TRUE; + } else { + half_ccd = SANE_FALSE; + } + + /* optical_res */ + optical_res = sensor.optical_res; + + /* stagger */ + if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG(DBG_info, "%s: stagger=%d lines\n", __func__, stagger); + + /* resolution is choosen from a fixed list */ + used_res = params.xres; + + /* compute scan parameters values */ + /* pixels are allways given at half or full CCD optical resolution */ + /* use detected left margin and fixed value */ + + /* compute correct pixels number */ + used_pixels = (params.pixels * optical_res) / used_res; + dummy = 3 - params.channels; + + /* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) { + slope_dpi = params.yres * params.channels; + } else { + slope_dpi = params.yres; + } + + slope_dpi = slope_dpi * (1 + dummy); + + exposure_time = gl846_compute_exposure (dev, used_res); + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + + max_shift = sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); + + /* lincnt */ + lincnt = params.lines + max_shift + stagger; + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res) / optical_res; + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure_time; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + + DBGCOMPLETED; +} + +/*for fast power saving methods only, like disabling certain amplifiers*/ +static SANE_Status +gl846_save_power (Genesys_Device * dev, SANE_Bool enable) +{ + DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); + if (dev == NULL) + return SANE_STATUS_INVAL; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl846_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) +{ + DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); + if (dev == NULL) + return SANE_STATUS_INVAL; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl846_start_action (Genesys_Device * dev) +{ + return sanei_genesys_write_register (dev, 0x0f, 0x01); +} + +static SANE_Status +gl846_stop_action (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val40, val; + unsigned int loop; + + DBGSTART; + + /* post scan gpio : without that HOMSNR is unreliable */ + gl846_homsnr_gpio(dev); + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + status = sanei_genesys_read_register (dev, REG40, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* only stop action if needed */ + if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) + { + DBG(DBG_info, "%s: already stopped\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + /* ends scan */ + val = dev->reg.get8(REG01); + val &= ~REG01_SCAN; + dev->reg.set8(REG01, val); + status = sanei_genesys_write_register (dev, REG01, val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_sleep_ms(100); + + loop = 10; + while (loop > 0) + { + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + status = sanei_genesys_read_register (dev, REG40, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* if scanner is in command mode, we are done */ + if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) + && !(val & REG41_MOTORENB)) + { + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + sanei_genesys_sleep_ms(100); + loop--; + } + + DBGCOMPLETED; + return SANE_STATUS_IO_ERROR; +} + +/* Send the low-level scan command */ +static SANE_Status +gl846_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SANE_Bool start_motor) +{ + (void) sensor; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + GenesysRegister *r; + + DBGSTART; + + /* XXX STEF XXX SCAN GPIO */ + /* + RIE (sanei_genesys_read_register (dev, REG6C, &val)); + RIE (sanei_genesys_write_register (dev, REG6C, val)); + */ + + val = REG0D_CLRLNCNT; + RIE (sanei_genesys_write_register (dev, REG0D, val)); + val = REG0D_CLRMCNT; + RIE (sanei_genesys_write_register (dev, REG0D, val)); + + RIE (sanei_genesys_read_register (dev, REG01, &val)); + val |= REG01_SCAN; + RIE (sanei_genesys_write_register (dev, REG01, val)); + r = sanei_genesys_get_address (reg, REG01); + r->value = val; + + if (start_motor) + { + RIE (sanei_genesys_write_register (dev, REG0F, 1)); + } + else + { + RIE (sanei_genesys_write_register (dev, REG0F, 0)); + } + + DBGCOMPLETED; + + return status; +} + + +/* Send the stop scan command */ +static SANE_Status +gl846_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, + SANE_Bool check_stop) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); + if (reg == NULL) + return SANE_STATUS_INVAL; + + if (dev->model->is_sheetfed == SANE_TRUE) + { + status = SANE_STATUS_GOOD; + } + else /* flat bed scanners */ + { + status = gl846_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + DBGCOMPLETED; + return status; +} + +/* Moves the slider to the home (top) postion slowly */ +static SANE_Status +gl846_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + float resolution; + uint8_t val; + int loop = 0; + ScanColorMode scan_mode; + + DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); + + /* post scan gpio : without that HOMSNR is unreliable */ + gl846_homsnr_gpio(dev); + + /* first read gives HOME_SENSOR true */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + sanei_genesys_sleep_ms(100); + + /* second is reliable */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + /* is sensor at home? */ + if (val & HOMESNR) + { + DBG(DBG_info, "%s: already at home, completed\n", __func__); + dev->scanhead_position_in_steps = 0; + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + local_reg = dev->reg; + + resolution=sanei_genesys_get_lowest_ydpi(dev); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + /* TODO add scan_mode to the API */ + scan_mode= dev->settings.scan_mode; + dev->settings.scan_mode = ScanColorMode::LINEART; + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 100; + params.starty = 30000; + params.pixels = 100; + params.lines = 100; + params.depth = 8; + params.channels = 1; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::RED; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl846_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + dev->settings.scan_mode=scan_mode; + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); + + /* set up for reverse */ + r = sanei_genesys_get_address(&local_reg, REG02); + r->value |= REG02_MTRREV; + + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + + try { + status = gl846_start_action(dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl846_stop_action(dev); + } catch (...) {} + try { + // restore original registers + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl846_stop_action (dev); + /* send original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + /* post scan gpio : without that HOMSNR is unreliable */ + gl846_homsnr_gpio(dev); + + if (wait_until_home) + { + while (loop < 300) /* do not wait longer then 30 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + if (val & HOMESNR) /* home sensor */ + { + DBG(DBG_info, "%s: reached home position\n", __func__); + gl846_stop_action (dev); + dev->scanhead_position_in_steps = 0; + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + ++loop; + } + + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl846_stop_action (dev); + DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + DBG(DBG_info, "%s: scanhead is still moving\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels + area at 600 dpi from very top of scanner */ +static SANE_Status +gl846_search_start_position (Genesys_Device * dev) +{ + int size; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg; + int steps; + + int pixels = 600; + int dpi = 300; + + DBG(DBG_proc, "%s\n", __func__); + + local_reg = dev->reg; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); + + SetupParams params; + params.xres = dpi; + params.yres = dpi; + params.startx = 0; + params.starty = 0; /*we should give a small offset here~60 steps */ + params.pixels = 600; + params.lines = dev->model->search_lines; + params.depth = 8; + params.channels = 1; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::GREEN; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl846_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* send to scanner */ + status = dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + size = pixels * dev->model->search_lines; + + std::vector data(size); + + status = gl846_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl846_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + + status = gl846_end_scan (dev, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + +/*TODO: find out where sanei_genesys_search_reference_point + stores information, and use that correctly*/ + status = + sanei_genesys_search_reference_point (dev, sensor, data.data(), 0, dpi, pixels, + dev->model->search_lines); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + return SANE_STATUS_GOOD; +} + +/* + * sets up register for coarse gain calibration + * todo: check it for scanners using it */ +static SANE_Status +gl846_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t channels; + uint8_t cksel; + + DBG(DBG_proc, "%s\n", __func__); + + + cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ + + /* set line size */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else { + channels = 1; + } + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = 0; + params.starty = 0; + params.pixels = sensor.optical_res / cksel; + params.lines = 20; + params.depth = 16; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl846_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / cksel, dev->settings.xres); + + status = dev->model->cmd_set->bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief moves the slider to steps at motor base dpi + * @param dev device to work on + * @param steps number of steps to move in base_dpi line count + * */ +static SANE_Status +gl846_feed (Genesys_Device * dev, unsigned int steps) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + float resolution; + uint8_t val; + + DBGSTART; + DBG(DBG_io, "%s: steps=%d\n", __func__, steps); + + /* prepare local registers */ + local_reg = dev->reg; + + resolution=sanei_genesys_get_lowest_ydpi(dev); + const auto& sensor = sanei_genesys_find_sensor(dev, resolution); + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 0; + params.starty = steps; + params.pixels = 100; + params.lines = 3; + params.depth = 8; + params.channels = 3; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_FEEDING | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl846_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* set exposure to zero */ + sanei_genesys_set_triple(&local_reg,REG_EXPR,0); + sanei_genesys_set_triple(&local_reg,REG_EXPG,0); + sanei_genesys_set_triple(&local_reg,REG_EXPB,0); + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); + + /* set up for no scan */ + r = sanei_genesys_get_address(&local_reg, REG01); + r->value &= ~REG01_SCAN; + + /* send registers */ + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + + try { + status = gl846_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl846_stop_action(dev); + } catch (...) {} + try { + // restore original registers + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl846_stop_action (dev); + + /* restore original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + /* wait until feed count reaches the required value, but do not + * exceed 30s */ + do + { + status = sanei_genesys_get_status (dev, &val); + } + while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); + + /* then stop scanning */ + RIE(gl846_stop_action (dev)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/* init registers for shading calibration */ +static SANE_Status +gl846_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + float move; + + DBGSTART; + dev->calib_channels = 3; + + /* initial calibration reg values */ + regs = dev->reg; + + dev->calib_resolution = sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); + dev->calib_total_bytes_to_read = 0; + dev->calib_lines = dev->model->shading_lines; + if(dev->calib_resolution==4800) + dev->calib_lines *= 2; + dev->calib_pixels = (sensor.sensor_pixels*dev->calib_resolution)/sensor.optical_res; + DBG(DBG_io, "%s: calib_lines = %d\n", __func__, (unsigned int)dev->calib_lines); + DBG(DBG_io, "%s: calib_pixels = %d\n", __func__, (unsigned int)dev->calib_pixels); + + /* this is aworkaround insufficent distance for slope + * motor acceleration TODO special motor slope for shading */ + move=1; + if(dev->calib_resolution<1200) + { + move=40; + } + + SetupParams params; + params.xres = dev->calib_resolution; + params.yres = dev->calib_resolution; + params.startx = 0; + params.starty = move; + params.pixels = dev->calib_pixels; + params.lines = dev->calib_lines; + params.depth = 16; + params.channels = dev->calib_channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl846_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = dev->model->cmd_set->bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* we use GENESYS_FLAG_SHADING_REPARK */ + dev->scanhead_position_in_steps = 0; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief set up registers for the actual scan + */ +static SANE_Status +gl846_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int flags; + int depth; + float move; + int move_dpi; + float start; + + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + /* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + /* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + + /* steps to move to reach scanning area: + - first we move to physical start of scanning + either by a fixed steps amount from the black strip + or by a fixed amount from parking position, + minus the steps done during shading calibration + - then we move by the needed offset whitin physical + scanning area + + assumption: steps are expressed at maximum motor resolution + + we need: + SANE_Fixed y_offset; + SANE_Fixed y_size; + SANE_Fixed y_offset_calib; + mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ + + /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is + relative from origin, else, it is from parking position */ + + move_dpi = dev->motor.base_ydpi; + + move = SANE_UNFIX (dev->model->y_offset); + move += dev->settings.tl_y; + move = (move * move_dpi) / MM_PER_INCH; + move -= dev->scanhead_position_in_steps; + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* fast move to scan area */ + /* we don't move fast the whole distance since it would involve + * computing acceleration/deceleration distance for scan + * resolution. So leave a remainder for it so scan makes the final + * move tuning */ + if(channels*dev->settings.yres>=600 && move>700) + { + status = gl846_feed (dev, move-500); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to move to scan area\n", __func__); + return status; + } + move=500; + } + + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* start */ + start = SANE_UNFIX (dev->model->x_offset); + start += dev->settings.tl_x; + start = (start * sensor.optical_res) / MM_PER_INCH; + + flags = 0; + + /* emulated lineart from gray data is required for now */ + if(dev->settings.scan_mode == ScanColorMode::LINEART + && dev->settings.dynamic_lineart) + { + flags |= SCAN_FLAG_DYNAMIC_LINEART; + } + + /* backtracking isn't handled well, so don't enable it */ + flags |= SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; + params.starty = move; + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = flags; + + status = gl846_init_scan_regs(dev, sensor, &dev->reg, params); + + if (status != SANE_STATUS_GOOD) + return status; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +static SANE_Status +gl846_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, int size) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint32_t addr, length, i, x, factor, pixels; + uint32_t dpiset, dpihw, strpixel, endpixel; + uint16_t tempo; + uint32_t lines, channels; + uint8_t val,*ptr,*src; + + DBGSTART; + DBG(DBG_io2, "%s: writing %d bytes of shading data\n", __func__, size); + + /* shading data is plit in 3 (up to 5 with IR) areas + write(0x10014000,0x00000dd8) + URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x.... + write(0x1003e000,0x00000dd8) + write(0x10068000,0x00000dd8) + */ + length = (uint32_t) (size / 3); + sanei_genesys_get_double(&dev->reg,REG_STRPIXEL,&tempo); + strpixel=tempo; + sanei_genesys_get_double(&dev->reg,REG_ENDPIXEL,&tempo); + endpixel=tempo; + + /* compute deletion factor */ + sanei_genesys_get_double(&dev->reg,REG_DPISET,&tempo); + dpiset=tempo; + DBG(DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n", __func__, strpixel, endpixel, + endpixel-strpixel, dpiset); + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpiset); + factor=dpihw/dpiset; + DBG(DBG_io2, "%s: factor=%d\n", __func__, factor); + + if(DBG_LEVEL>=DBG_data) + { + dev->binary=fopen("binary.pnm","wb"); + sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &lines); + channels=dev->current_setup.channels; + if(dev->binary!=NULL) + { + fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); + } + } + + pixels=endpixel-strpixel; + + /* since we're using SHDAREA, substract startx coordinate from shading */ + strpixel-=((sensor.CCD_start_xoffset*600)/sensor.optical_res); + + /* turn pixel value into bytes 2x16 bits words */ + strpixel*=2*2; + pixels*=2*2; + + std::vector buffer(pixels, 0); + + DBG(DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n", __func__, pixels, pixels); + + /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address + * is 8192*reg value */ + + /* write actual color channel data */ + for(i=0;i<3;i++) + { + /* build up actual shading data by copying the part from the full width one + * to the one corresponding to SHDAREA */ + ptr = buffer.data(); + + /* iterate on both sensor segment */ + for(x=0;xmodel->y_offset_calib); + move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; + if(move>20) + { + RIE(gl846_feed (dev, move)); + } + DBG(DBG_io, "%s: move=%f steps\n", __func__, move); + + /* offset calibration is always done in color mode */ + channels = 3; + depth=16; + used_res=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); + Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, used_res); + num_pixels = (sensor.sensor_pixels*used_res)/sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + SetupParams params; + params.xres = used_res; + params.yres = used_res; + params.startx = 0; + params.starty = 0; + params.pixels = num_pixels; + params.lines = 1; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl846_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ + std::vector line(total_size); + + /* initial loop values and boundaries */ + exp[0]=sensor_profile->expr; + exp[1]=sensor_profile->expg; + exp[2]=sensor_profile->expb; + + bottom[0]=29000; + bottom[1]=29000; + bottom[2]=29000; + + top[0]=41000; + top[1]=51000; + top[2]=51000; + + turn = 0; + + /* no move during led calibration */ + sanei_genesys_set_motor_power(regs, false); + do + { + /* set up exposure */ + sanei_genesys_set_double(®s,REG_EXPR,exp[0]); + sanei_genesys_set_double(®s,REG_EXPG,exp[1]); + sanei_genesys_set_double(®s,REG_EXPB,exp[2]); + + /* write registers and scan data */ + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + + DBG(DBG_info, "%s: starting line reading\n", __func__); + RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); + + /* stop scanning */ + RIE(gl846_stop_action(dev)); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl846_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), depth, channels, num_pixels, 1); + } + + /* compute average */ + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + /* check if exposure gives average within the boundaries */ + acceptable = SANE_TRUE; + for(i=0;i<3;i++) + { + if(avg[i]top[i]) + { + exp[i]=(exp[i]*top[i])/avg[i]; + acceptable = SANE_FALSE; + } + } + + turn++; + } + while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); + + /* set these values as final ones for scan */ + sanei_genesys_set_double(&dev->reg,REG_EXPR,exp[0]); + sanei_genesys_set_double(&dev->reg,REG_EXPG,exp[1]); + sanei_genesys_set_double(&dev->reg,REG_EXPB,exp[2]); + + /* store in this struct since it is the one used by cache calibration */ + sensor.exposure.red = exp[0]; + sensor.exposure.green = exp[1]; + sensor.exposure.blue = exp[2]; + + /* go back home */ + if(move>20) + { + status=gl846_slow_back_home (dev, SANE_TRUE); + } + + DBGCOMPLETED; + return status; +} + +/** + * set up GPIO/GPOE for idle state + */ +static SANE_Status +gl846_init_gpio (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + int idx=0; + + DBGSTART; + + /* search GPIO profile */ + while(gpios[idx].sensor_id!=0 && dev->model->gpo_type!=gpios[idx].sensor_id) + { + idx++; + } + if(gpios[idx].sensor_id==0) + { + DBG(DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __func__, + dev->model->ccd_type); + return SANE_STATUS_INVAL; + } + + RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); + RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); + + RIE (sanei_genesys_write_register (dev, REG6B, gpios[idx].r6b)); + RIE (sanei_genesys_write_register (dev, REG6C, gpios[idx].r6c)); + RIE (sanei_genesys_write_register (dev, REG6D, gpios[idx].r6d)); + RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); + RIE (sanei_genesys_write_register (dev, REG6F, gpios[idx].r6f)); + + RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); + RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); + + DBGCOMPLETED; + return status; +} + +/** + * set memory layout by filling values in dedicated registers + */ +static SANE_Status +gl846_init_memory_layout (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + int idx = 0, i; + uint8_t val; + + DBGSTART + + /* point to per model memory layout */ + idx = 0; + while(layouts[idx].model!=NULL && strcmp(dev->model->name,layouts[idx].model)!=0) + { + if(strcmp(dev->model->name,layouts[idx].model)!=0) + idx++; + } + if(layouts[idx].model==NULL) + { + DBG(DBG_error, "%s: failed to find memory layout for model %s!\n", __func__, dev->model->name); + return SANE_STATUS_INVAL; + } + + /* CLKSET and DRAMSEL */ + val = layouts[idx].dramsel; + RIE (sanei_genesys_write_register (dev, REG0B, val)); + dev->reg.find_reg(0x0b).value = val; + + /* prevent further writings by bulk write register */ + dev->reg.remove_reg(0x0b); + + /* setup base address for shading and scanned data. */ + for(i=0;i<10;i++) + { + sanei_genesys_write_register (dev, 0xe0+i, layouts[idx].rx[i]); + } + + DBGCOMPLETED; + return status; +} + +/* * + * initialize ASIC from power on condition + */ +static SANE_Status +gl846_boot (Genesys_Device * dev, SANE_Bool cold) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + DBGSTART; + + /* reset ASIC if cold boot */ + if(cold) + { + RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); + RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); + } + + if(dev->usb_mode == 1) + { + val = 0x14; + } + else + { + val = 0x11; + } + RIE (sanei_genesys_write_0x8c (dev, 0x0f, val)); + + /* test CHKVER */ + RIE (sanei_genesys_read_register (dev, REG40, &val)); + if (val & REG40_CHKVER) + { + RIE (sanei_genesys_read_register (dev, 0x00, &val)); + DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); + } + + /* Set default values for registers */ + gl846_init_registers (dev); + + /* Write initial registers */ + RIE (dev->model->cmd_set->bulk_write_register(dev, dev->reg)); + + /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ + val = dev->reg.find_reg(0x0b).value & REG0B_DRAMSEL; + val = (val | REG0B_ENBDRAM); + RIE (sanei_genesys_write_register (dev, REG0B, val)); + dev->reg.find_reg(0x0b).value = val; + + /* CIS_LINE */ + if (dev->model->is_cis) + { + SETREG (0x08, REG08_CIS_LINE); + RIE (sanei_genesys_write_register (dev, 0x08, dev->reg.find_reg(0x08).value)); + } + + /* set up clocks */ + RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0e)); + RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); + + /* setup gpio */ + RIE (gl846_init_gpio (dev)); + + /* setup internal memory layout */ + RIE (gl846_init_memory_layout (dev)); + + SETREG (0xf8, 0x05); + RIE (sanei_genesys_write_register (dev, 0xf8, dev->reg.find_reg(0xf8).value)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** + * initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +static SANE_Status gl846_init(Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG_INIT (); + DBGSTART; + + status=sanei_genesys_asic_init(dev, 0); + + DBGCOMPLETED; + return status; +} + +static SANE_Status +gl846_update_hardware_sensors (Genesys_Scanner * s) +{ + /* do what is needed to get a new set of events, but try to not lose + any of them. + */ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + uint8_t scan, file, email, copy; + switch(s->dev->model->gpo_type) + { + default: + scan=0x01; + file=0x02; + email=0x04; + copy=0x08; + } + RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); + + s->buttons[BUTTON_SCAN_SW].write((val & scan) == 0); + s->buttons[BUTTON_FILE_SW].write((val & file) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & email) == 0); + s->buttons[BUTTON_COPY_SW].write((val & copy) == 0); + + return status; +} + +/** @brief search for a full width black or white strip. + * This function searches for a black or white stripe across the scanning area. + * When searching backward, the searched area must completely be of the desired + * color since this area will be used for calibration which scans forward. + * @param dev scanner device + * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward + * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip + * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not + */ +static SANE_Status +gl846_search_strip(Genesys_Device * dev, const Genesys_Sensor& sensor, + SANE_Bool forward, SANE_Bool black) +{ + unsigned int pixels, lines, channels; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg; + size_t size; + int steps, depth, dpi; + unsigned int pass, count, found, x, y; + char title[80]; + GenesysRegister *r; + + DBG(DBG_proc, "%s %s %s\n", __func__, black ? "black" : "white", forward ? "forward" : "reverse"); + + status = gl846_set_fe(dev, sensor, AFE_SET); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl846_set_fe() failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl846_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* set up for a gray scan at lowest dpi */ + dpi = 9600; + for (x = 0; x < MAX_RESOLUTIONS; x++) + { + if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) + dpi = dev->model->xdpi_values[x]; + } + channels = 1; + /* 10 MM */ + /* lines = (10 * dpi) / MM_PER_INCH; */ + /* shading calibation is done with dev->motor.base_ydpi */ + lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; + depth = 8; + pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; + size = pixels * channels * lines * (depth / 8); + std::vector data(size); + + dev->scanhead_position_in_steps = 0; + + local_reg = dev->reg; + + SetupParams params; + params.xres = dpi; + params.yres = dpi; + params.startx = 0; + params.starty = 0; + params.pixels = pixels; + params.lines = lines; + params.depth = depth; + params.channels = channels; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::RED; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA; + + status = gl846_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* set up for reverse or forward */ + r = sanei_genesys_get_address (&local_reg, REG02); + if (forward) + r->value &= ~REG02_MTRREV; + else + r->value |= REG02_MTRREV; + + + status = dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl846_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl846_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl846_stop_action failed\n", __func__); + return status; + } + + pass = 0; + if (DBG_LEVEL >= DBG_data) + { + sprintf(title, "gl846_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); + sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); + } + + /* loop until strip is found or maximum pass number done */ + found = 0; + while (pass < 20 && !found) + { + status = dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* now start scan */ + status = gl846_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl846_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl846_stop_action failed\n", __func__); + return status; + } + + if (DBG_LEVEL >= DBG_data) + { + sprintf(title, "gl846_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); + sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (pixels * lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + pass++; + } + + if (found) + { + status = SANE_STATUS_GOOD; + DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); + } + else + { + status = SANE_STATUS_UNSUPPORTED; + DBG(DBG_info, "%s: %s strip not found\n", __func__, black ? "black" : "white"); + } + + DBGCOMPLETED; + return status; +} + +/** + * average dark pixels of a 8 bits scan + */ +static int +dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black) +{ + unsigned int i, j, k, average, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average value on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + for (i = 0; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + average = 0; + for (i = 0; i < channels; i++) + average += avg[i]; + average /= channels; + DBG(DBG_info, "%s: average = %d\n", __func__, average); + return average; +} + +static SANE_Status +gl846_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t reg04; + unsigned int channels, bpp; + int pass = 0, avg, total_size; + int topavg, bottomavg, resolution, lines; + int top, bottom, black_pixels, pixels; + + DBGSTART; + + /* no gain nor offset for AKM AFE */ + RIE (sanei_genesys_read_register (dev, REG04, ®04)); + if ((reg04 & REG04_FESET) == 0x02) + { + DBGCOMPLETED; + return status; + } + + /* offset calibration is always done in color mode */ + channels = 3; + resolution=sensor.optical_res; + dev->calib_pixels = sensor.sensor_pixels; + lines=1; + bpp=8; + pixels= (sensor.sensor_pixels*resolution) / sensor.optical_res; + black_pixels = (sensor.black_pixels * resolution) / sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 0; + params.starty = 0; + params.pixels = pixels; + params.lines = lines; + params.depth = bpp; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl846_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_set_motor_power(regs, false); + + /* allocate memory for scans */ + total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* init gain */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* scan with no move */ + bottom = 10; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + + RIE(gl846_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting first line reading\n", __func__); + RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, first_line.data(), total_size)); + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl846_offset%03d.pnm", bottom); + sanei_genesys_write_pnm_file(fn, first_line.data(), bpp, channels, pixels, lines); + } + + bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); + + /* now top value */ + top = 255; + dev->frontend.set_offset(0, top); + dev->frontend.set_offset(1, top); + dev->frontend.set_offset(2, top); + RIE(gl846_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); + + topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); + + /* loop until acceptable level */ + while ((pass < 32) && (top - bottom > 1)) + { + pass++; + + /* settings for new scan */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + /* scan with no move */ + RIE(gl846_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl846_offset%03d.pnm", dev->frontend.get_offset(1)); + sanei_genesys_write_pnm_file(fn, second_line.data(), bpp, channels, pixels, lines); + } + + avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); + + /* compute new boundaries */ + if (topavg == avg) + { + topavg = avg; + top = dev->frontend.get_offset(1); + } + else + { + bottomavg = avg; + bottom = dev->frontend.get_offset(1); + } + } + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl846_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) +{ + int pixels; + int total_size; + uint8_t reg04; + int i, j, channels; + SANE_Status status = SANE_STATUS_GOOD; + int max[3]; + float gain[3],coeff; + int val, code, lines; + int resolution; + int bpp; + + DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); + + /* no gain nor offset for AKM AFE */ + RIE (sanei_genesys_read_register (dev, REG04, ®04)); + if ((reg04 & REG04_FESET) == 0x02) + { + DBGCOMPLETED; + return status; + } + + /* coarse gain calibration is always done in color mode */ + channels = 3; + + /* follow CKSEL */ + if(dev->settings.xressettings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + try { + status = gl846_init_scan_regs(dev, sensor, ®s, params); + } catch (...) { + try { + sanei_genesys_set_motor_power(regs, false); + } catch (...) {} + throw; + } + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + RIE (dev->model->cmd_set->bulk_write_register(dev, regs)); + + total_size = pixels * channels * (16/bpp) * lines; + + std::vector line(total_size); + + RIE(gl846_set_fe(dev, sensor, AFE_SET)); + RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl846_gain.pnm", line.data(), bpp, channels, pixels, lines); + + /* average value on each channel */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + for (i = pixels/4; i < (pixels*3/4); i++) + { + if (dev->model->is_cis) + val = line[i + j * pixels]; + else + val = line[i * channels + j]; + + max[j] += val; + } + max[j] = max[j] / (pixels/2); + + gain[j] = ((float) sensor.gain_white_ref*coeff) / max[j]; + + /* turn logical gain value into gain code, checking for overflow */ + code = 283 - 208 / gain[j]; + if (code > 255) + code = 255; + else if (code < 0) + code = 0; + dev->frontend.set_gain(j, code); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], + dev->frontend.get_gain(j)); + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + RIE (gl846_stop_action (dev)); + + status=gl846_slow_back_home (dev, SANE_TRUE); + + DBGCOMPLETED; + return status; +} + + +/** the gl846 command set */ +static Genesys_Command_Set gl846_cmd_set = { + "gl846-generic", /* the name of this set */ + + nullptr, + + gl846_init, + NULL, + gl846_init_regs_for_coarse_calibration, + gl846_init_regs_for_shading, + gl846_init_regs_for_scan, + + gl846_get_filter_bit, + gl846_get_lineart_bit, + gl846_get_bitset_bit, + gl846_get_gain4_bit, + gl846_get_fast_feed_bit, + gl846_test_buffer_empty_bit, + gl846_test_motor_flag_bit, + + gl846_set_fe, + gl846_set_powersaving, + gl846_save_power, + + gl846_begin_scan, + gl846_end_scan, + + sanei_genesys_send_gamma_table, + + gl846_search_start_position, + + gl846_offset_calibration, + gl846_coarse_gain_calibration, + gl846_led_calibration, + + NULL, + gl846_slow_back_home, + NULL, + + sanei_genesys_bulk_write_register, + NULL, + sanei_genesys_bulk_read_data, + + gl846_update_hardware_sensors, + + NULL, + NULL, + NULL, + gl846_search_strip, + + sanei_genesys_is_compatible_calibration, + NULL, + gl846_send_shading_data, + gl846_calculate_current_setup, + gl846_boot +}; + +SANE_Status +sanei_gl846_init_cmd_set (Genesys_Device * dev) +{ + dev->model->cmd_set = &gl846_cmd_set; + return SANE_STATUS_GOOD; +} diff --git a/backend/genesys_gl846.h b/backend/genesys_gl846.h index e1dc711..797c605 100644 --- a/backend/genesys_gl846.h +++ b/backend/genesys_gl846.h @@ -335,239 +335,39 @@ #define REGF8_SMAXSEL 4 #define REGF8_MINSEL 0x0f -/** - * writable scanner registers */ -enum -{ - reg_0x01 = 0, - reg_0x02, - reg_0x03, - reg_0x04, - reg_0x05, - reg_0x06, - reg_0x08, - reg_0x09, - reg_0x0a, - reg_0x0b, - reg_0x0c, - reg_0x0d, - reg_0x0e, - reg_0x0f, - reg_0x10, - reg_0x11, - reg_0x12, - reg_0x13, - reg_0x14, - reg_0x15, - reg_0x16, - reg_0x17, - reg_0x18, - reg_0x19, - reg_0x1a, - reg_0x1b, - reg_0x1c, - reg_0x1d, - reg_0x1e, - reg_0x1f, - reg_0x20, - reg_0x21, - reg_0x22, - reg_0x23, - reg_0x24, - reg_0x25, - reg_0x26, - reg_0x27, - reg_0x2c, - reg_0x2d, - reg_0x2e, - reg_0x2f, - reg_0x30, - reg_0x31, - reg_0x32, - reg_0x33, - reg_0x34, - reg_0x35, - reg_0x36, - reg_0x37, - reg_0x38, - reg_0x39, - reg_0x3a, - reg_0x3b, - reg_0x3d, - reg_0x3e, - reg_0x3f, - reg_0x51, - reg_0x52, - reg_0x53, - reg_0x54, - reg_0x55, - reg_0x56, - reg_0x57, - reg_0x58, - reg_0x59, - reg_0x5a, - reg_0x5e, - reg_0x5f, - reg_0x60, - reg_0x61, - reg_0x62, - reg_0x63, - reg_0x64, - reg_0x65, - reg_0x67, - reg_0x68, - reg_0x69, - reg_0x6a, - reg_0x6b, - reg_0x6c, - reg_0x6d, - reg_0x6e, - reg_0x6f, - reg_0x70, - reg_0x71, - reg_0x72, - reg_0x73, - reg_0x74, - reg_0x75, - reg_0x76, - reg_0x77, - reg_0x78, - reg_0x79, - reg_0x7a, - reg_0x7b, - reg_0x7c, - reg_0x7d, - reg_0x7e, - reg_0x7f, - reg_0x80, - reg_0x87, - reg_0x94, - reg_0x98, - reg_0x99, - reg_0x9a, - reg_0x9b, - reg_0x9d, - reg_0x9e, - reg_0xa1, - reg_0xa2, - reg_0xa3, - reg_0xa4, - reg_0xa5, - reg_0xa6, - reg_0xa7, - reg_0xa8, - reg_0xa9, - reg_0xab, - reg_0xbb, - reg_0xbc, - reg_0xbd, - reg_0xbe, - reg_0xc5, - reg_0xc6, - reg_0xc7, - reg_0xc8, - reg_0xc9, - reg_0xca, - reg_0xd0, - reg_0xd1, - reg_0xd2, - reg_0xdb, - reg_0xe0, - reg_0xe1, - reg_0xe2, - reg_0xe3, - reg_0xe4, - reg_0xe5, - reg_0xe6, - reg_0xe7, - reg_0xe8, - reg_0xe9, - reg_0xea, - reg_0xeb, - reg_0xec, - reg_0xed, - reg_0xee, - reg_0xef, - reg_0xf0, - reg_0xf1, - reg_0xf2, - reg_0xf3, - reg_0xf4, - reg_0xf5, - reg_0xf6, - reg_0xf7, - reg_0xf8, - reg_0xfe, - reg_0xff, - GENESYS_GL846_MAX_REGS -}; - -#define SETREG(adr,val) {dev->reg[reg_##adr].address=adr;dev->reg[reg_##adr].value=val;} +#define SETREG(adr,val) { dev->reg.init_reg(adr, val); } /** set up registers for an actual scan * * this function sets up the scanner to scan in normal or single line mode */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl846_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int color_filter, - unsigned int flags); +static SANE_Status gl846_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, SetupParams& params); /* Send the low-level scan command */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl846_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool start_motor); +static SANE_Status gl846_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, SANE_Bool start_motor); /* Send the stop scan command */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl846_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool check_stop); +static SANE_Status gl846_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool check_stop); -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl846_init (Genesys_Device * dev); +static SANE_Status gl846_init (Genesys_Device * dev); /** @brief moves the slider to steps at motor base dpi * @param dev device to work on * @param steps number of steps to move * */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status +static SANE_Status gl846_feed (Genesys_Device * dev, unsigned int steps); -#ifndef UNIT_TESTING -static -#endif -SANE_Status +static SANE_Status gl846_stop_action (Genesys_Device * dev); -#ifndef UNIT_TESTING -static -#endif -SANE_Status +static SANE_Status gl846_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); -#ifndef UNIT_TESTING -static -#endif -SANE_Status +static SANE_Status gl846_boot (Genesys_Device * dev, SANE_Bool cold); @@ -594,7 +394,7 @@ static Gpio_Profile gpios[]={ typedef struct { - char *model; + const char *model; uint8_t dramsel; /* shading data address */ uint8_t rd0; @@ -667,8 +467,6 @@ typedef struct { uint8_t r17; /**> TG width */ } Sensor_Profile; -/* *INDENT-OFF* */ - /** * order of the scanned pixel */ @@ -681,7 +479,6 @@ static Sensor_Profile sensors[]={ {CCD_IMG101, 1200, 11000, 60, 159, 85, 5136, 255, 0, 0, 0, order_01 , 0x13}, {CCD_PLUSTEK3800, 1200, 11000, 60, 159, 85, 5136, 255, 0, 0, 0, order_01 , 0x13}, }; -/* *INDENT-ON* */ /* base motor slopes in full step unit */ /* target=((exposure * dpi) / base_dpi)>>step_type; */ @@ -691,7 +488,6 @@ static uint32_t img101_high[] = {22000, 22000, 22000, 18450, 15974, 14284, 13054 * database of motor profiles */ -/* *INDENT-OFF* */ static Motor_Profile gl846_motors[]={ /* Image Formula 101 */ {MOTOR_IMG101, 11000, HALF_STEP , img101_high}, @@ -700,6 +496,3 @@ static Motor_Profile gl846_motors[]={ /* end of database entry */ {0, 0, 0, NULL}, }; -/* *INDENT-ON* */ - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl847.c b/backend/genesys_gl847.c deleted file mode 100644 index a3b35a2..0000000 --- a/backend/genesys_gl847.c +++ /dev/null @@ -1,3824 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2013 Stéphane Voltz - - - 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. -*/ - -#undef BACKEND_NAME -#define BACKEND_NAME genesys_gl847 - -#include "genesys_gl847.h" - -/**************************************************************************** - Low level function - ****************************************************************************/ - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - - -/** @brief read scanned data - * Read in 0xeff0 maximum sized blocks. This read is done in 2 - * parts if not multple of 512. First read is rounded to a multiple of 512 bytes, last read fetches the - * remainder. Read addr is always 0x10000000 with the memory layout setup. - * @param dev device to read data from - * @param addr address within ASIC memory space, unused but kept for API - * @param data pointer where to store the read data - * @param len size to read - */ -static SANE_Status -gl847_bulk_read_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status; - size_t size, target, read, done; - uint8_t outdata[8]; - uint8_t *buffer; - - DBG (DBG_io, "gl847_bulk_read_data: requesting %lu bytes at addr=0x%02x\n", (u_long) len, addr); - - if (len == 0) - return SANE_STATUS_GOOD; - - target = len; - buffer = data; - - /* loop until computed data size is read */ - while (target) - { - if (target > 0xeff0) - { - size = 0xeff0; - } - else - { - size = target; - } - - /* hard coded 0x10000000 addr */ - outdata[0] = 0; - outdata[1] = 0; - outdata[2] = 0; - outdata[3] = 0x10; - - /* data size to transfer */ - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_BUFFER, 0x00, sizeof (outdata), - outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s failed while writing command: %s\n", - __func__, sane_strstatus (status)); - return status; - } - - /* blocks must be multiple of 512 but not last block */ - read = size; - if (read >= 512) - { - read /= 512; - read *= 512; - } - - DBG (DBG_io2, - "gl847_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) read); - status = sanei_usb_read_bulk (dev->dn, buffer, &read); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - done=read; - DBG (DBG_io2, "gl847_bulk_read_data: %lu bytes of data read\n", (u_long) done); - - /* read less than 512 bytes remainder */ - if (read < size) - { - read = size - read; - DBG (DBG_io2, - "gl847_bulk_read_data: trying to read %lu bytes of data\n", - (u_long) read); - status = sanei_usb_read_bulk (dev->dn, buffer+done, &read); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_bulk_read_data failed while reading bulk data: %s\n", - sane_strstatus (status)); - return status; - } - done=read; - DBG (DBG_io2, "gl847_bulk_read_data: %lu bytes of data read\n", (u_long) done); - } - - DBG (DBG_io2, "%s: read %lu bytes, %lu remaining\n", __func__, - (u_long) size, (u_long) (target - size)); - - target -= size; - buffer += size; - } - - if (DBG_LEVEL >= DBG_data && dev->binary!=NULL) - { - fwrite(data, len, 1, dev->binary); - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl847_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_get_filter_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_get_lineart_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_get_bitset_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_get_gain4_bit (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** - * compute the step multiplier used - */ -static int -gl847_get_step_multiplier (Genesys_Register_Set * regs) -{ - Genesys_Register_Set *r = NULL; - int value = 1; - - r = sanei_genesys_get_address (regs, 0x9d); - if (r != NULL) - { - value = (r->value & 0x0f)>>1; - value = 1 << value; - } - DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); - return value; -} - -/** @brief sensor profile - * search for the database of motor profiles and get the best one. Each - * profile is at a specific dpihw. Use LiDE 110 table by default. - * @param sensor_type sensor id - * @param dpi hardware dpi for the scan - * @return a pointer to a Sensor_Profile struct - */ -static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi) -{ - unsigned int i; - int idx; - - i=0; - idx=-1; - while(i=dpi - && sensors[i].dpimodel->ccd_type, xres); - return sensor->exposure; -} - - -/** @brief sensor specific settings -*/ -static void -gl847_setup_sensor (Genesys_Device * dev, Genesys_Register_Set * regs, int dpi) -{ - Genesys_Register_Set *r; - Sensor_Profile *sensor; - int dpihw, i; - uint16_t exp; - - DBGSTART; - dpihw=sanei_genesys_compute_dpihw(dev,dpi); - - for (i = 0x06; i < 0x0e; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - if (r) - r->value = dev->sensor.regs_0x10_0x1d[i]; - } - - for (i = 0; i < 9; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - if (r) - r->value = dev->sensor.regs_0x52_0x5e[i]; - } - - /* set EXPDUMMY and CKxMAP */ - dpihw=sanei_genesys_compute_dpihw(dev,dpi); - sensor=get_sensor_profile(dev->model->ccd_type, dpihw); - - sanei_genesys_set_reg_from_set(regs,REG_EXPDMY,(uint8_t)((sensor->expdummy) & 0xff)); - - /* if no calibration has been done, set default values for exposures */ - exp=dev->sensor.regs_0x10_0x1d[0]*256+dev->sensor.regs_0x10_0x1d[1]; - if(exp==0) - { - exp=sensor->expr; - } - sanei_genesys_set_double(regs,REG_EXPR,exp); - - exp=dev->sensor.regs_0x10_0x1d[2]*256+dev->sensor.regs_0x10_0x1d[3]; - if(exp==0) - { - exp=sensor->expg; - } - sanei_genesys_set_double(regs,REG_EXPG,exp); - - exp=dev->sensor.regs_0x10_0x1d[4]*256+dev->sensor.regs_0x10_0x1d[5]; - if(exp==0) - { - exp=sensor->expb; - } - sanei_genesys_set_double(regs,REG_EXPB,exp); - - sanei_genesys_set_triple(regs,REG_CK1MAP,sensor->ck1map); - sanei_genesys_set_triple(regs,REG_CK3MAP,sensor->ck3map); - sanei_genesys_set_triple(regs,REG_CK4MAP,sensor->ck4map); - - /* order of the sub-segments */ - dev->order=sensor->order; - - r = sanei_genesys_get_address (regs, 0x17); - r->value = sensor->r17; - - DBGCOMPLETED; -} - - -/* returns the max register bulk size */ -static int -gl847_bulk_full_size (void) -{ - return GENESYS_GL847_MAX_REGS; -} - -/** @brief set all registers to default values . - * This function is called only once at the beginning and - * fills register startup values for registers reused across scans. - * Those that are rarely modified or not modified are written - * individually. - * @param dev device structure holding register set to initialize - */ -static void -gl847_init_registers (Genesys_Device * dev) -{ - int lide700=0; - uint8_t val; - - DBGSTART; - /* 700F class needs some different initial settings */ - if (strcmp (dev->model->name, "canon-lide-700f") == 0) - { - lide700 = 1; - } - - memset (dev->reg, 0, - GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - - SETREG (0x01, 0x82); - SETREG (0x02, 0x18); - SETREG (0x03, 0x50); - SETREG (0x04, 0x12); - SETREG (0x05, 0x80); - SETREG (0x06, 0x50); /* FASTMODE + POWERBIT */ - SETREG (0x08, 0x10); - SETREG (0x09, 0x01); - SETREG (0x0a, 0x00); - SETREG (0x0b, 0x01); - SETREG (0x0c, 0x02); - - /* LED exposures */ - SETREG (0x10, 0x00); - SETREG (0x11, 0x00); - SETREG (0x12, 0x00); - SETREG (0x13, 0x00); - SETREG (0x14, 0x00); - SETREG (0x15, 0x00); - - SETREG (0x16, 0x10); - SETREG (0x17, 0x08); - SETREG (0x18, 0x00); - - /* EXPDMY */ - SETREG (0x19, 0x50); - - SETREG (0x1a, 0x34); - SETREG (0x1b, 0x00); - SETREG (0x1c, 0x02); - SETREG (0x1d, 0x04); - SETREG (0x1e, 0x10); - SETREG (0x1f, 0x04); - SETREG (0x20, 0x02); - SETREG (0x21, 0x10); - SETREG (0x22, 0x7f); - SETREG (0x23, 0x7f); - SETREG (0x24, 0x10); - SETREG (0x25, 0x00); - SETREG (0x26, 0x00); - SETREG (0x27, 0x00); - SETREG (0x2c, 0x09); - SETREG (0x2d, 0x60); - SETREG (0x2e, 0x80); - SETREG (0x2f, 0x80); - SETREG (0x30, 0x00); - SETREG (0x31, 0x10); - SETREG (0x32, 0x15); - SETREG (0x33, 0x0e); - SETREG (0x34, 0x40); - SETREG (0x35, 0x00); - SETREG (0x36, 0x2a); - SETREG (0x37, 0x30); - SETREG (0x38, 0x2a); - SETREG (0x39, 0xf8); - SETREG (0x3d, 0x00); - SETREG (0x3e, 0x00); - SETREG (0x3f, 0x00); - SETREG (0x52, 0x03); - SETREG (0x53, 0x07); - SETREG (0x54, 0x00); - SETREG (0x55, 0x00); - SETREG (0x56, 0x00); - SETREG (0x57, 0x00); - SETREG (0x58, 0x2a); - SETREG (0x59, 0xe1); - SETREG (0x5a, 0x55); - SETREG (0x5e, 0x41); - SETREG (0x5f, 0x40); - SETREG (0x60, 0x00); - SETREG (0x61, 0x21); - SETREG (0x62, 0x40); - SETREG (0x63, 0x00); - SETREG (0x64, 0x21); - SETREG (0x65, 0x40); - SETREG (0x67, 0x80); - SETREG (0x68, 0x80); - SETREG (0x69, 0x20); - SETREG (0x6a, 0x20); - - /* CK1MAP */ - SETREG (0x74, 0x00); - SETREG (0x75, 0x00); - SETREG (0x76, 0x3c); - - /* CK3MAP */ - SETREG (0x77, 0x00); - SETREG (0x78, 0x00); - SETREG (0x79, 0x9f); - - /* CK4MAP */ - SETREG (0x7a, 0x00); - SETREG (0x7b, 0x00); - SETREG (0x7c, 0x55); - - SETREG (0x7d, 0x00); - - /* NOTE: autoconf is a non working option */ - SETREG (0x87, 0x02); - SETREG (0x9d, 0x06); - SETREG (0xa2, 0x0f); - SETREG (0xbd, 0x18); - SETREG (0xfe, 0x08); - - /* gamma[0] and gamma[256] values */ - SETREG (0xbe, 0x00); - SETREG (0xc5, 0x00); - SETREG (0xc6, 0x00); - SETREG (0xc7, 0x00); - SETREG (0xc8, 0x00); - SETREG (0xc9, 0x00); - SETREG (0xca, 0x00); - - /* LiDE 700 fixups */ - if(lide700) - { - SETREG (0x5f, 0x04); - SETREG (0x7d, 0x80); - - /* we write to these registers only once */ - val=0; - sanei_genesys_write_register (dev, REG7E, val); - sanei_genesys_write_register (dev, REG9E, val); - sanei_genesys_write_register (dev, REG9F, val); - sanei_genesys_write_register (dev, REGAB, val); - } - - /* fine tune upon device description */ - dev->reg[reg_0x05].value &= ~REG05_DPIHW; - switch (dev->sensor.optical_res) - { - case 600: - dev->reg[reg_0x05].value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg[reg_0x05].value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg[reg_0x05].value |= REG05_DPIHW_2400; - break; - case 4800: - dev->reg[reg_0x05].value |= REG05_DPIHW_4800; - break; - } - - /* initalize calibration reg */ - memcpy (dev->calib_reg, dev->reg, - GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - - DBGCOMPLETED; -} - -/**@brief send slope table for motor movement - * Send slope_table in machine byte order - * @param dev device to send slope table - * @param table_nr index of the slope table in ASIC memory - * Must be in the [0-4] range. - * @param slope_table pointer to 16 bit values array of the slope table - * @param steps number of elements in the slope table - */ -static SANE_Status -gl847_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - SANE_Status status; - uint8_t *table; - int i; - char msg[10000]; - - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, - table_nr, steps); - - /* sanity check */ - if(table_nr<0 || table_nr>4) - { - DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); - return SANE_STATUS_INVAL; - } - - table = (uint8_t *) malloc (steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), "%d", slope_table[i]); - } - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - /* slope table addresses are fixed */ - status = - sanei_genesys_write_ahb (dev->dn, dev->usb_mode, 0x10000000 + 0x4000 * table_nr, steps * 2, table); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: write to AHB failed writing slope table %d (%s)\n", - __func__, table_nr, sane_strstatus (status)); - } - - free (table); - DBGCOMPLETED; - return status; -} - -/** - * Set register values of Analog Device type frontend - * */ -static SANE_Status -gl847_set_ad_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - uint16_t val; - uint8_t val8; - - DBGSTART; - - /* wait for FE to be ready */ - status = sanei_genesys_get_status (dev, &val8); - while (val8 & REG41_FEBUSY); - { - usleep (10000); - status = sanei_genesys_get_status (dev, &val8); - }; - - if (set == AFE_INIT) - { - DBG (DBG_proc, "gl847_set_ad_fe(): setting DAC %u\n", - dev->model->dac_type); - - /* sets to default values */ - sanei_genesys_init_fe (dev); - } - - /* reset DAC */ - status = sanei_genesys_fe_write_data (dev, 0x00, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl847_set_ad_fe: failed to write reg0: %s\n", - sane_strstatus (status)); - return status; - } - - /* write them to analog frontend */ - val = dev->frontend.reg[0]; - status = sanei_genesys_fe_write_data (dev, 0x00, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl847_set_ad_fe: failed to write reg0: %s\n", - sane_strstatus (status)); - return status; - } - val = dev->frontend.reg[1]; - status = sanei_genesys_fe_write_data (dev, 0x01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl847_set_ad_fe: failed to write reg1: %s\n", - sane_strstatus (status)); - return status; - } - - for (i = 0; i < 3; i++) - { - val = dev->frontend.gain[i]; - status = sanei_genesys_fe_write_data (dev, 0x02 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_set_ad_fe: failed to write gain %d: %s\n", i, - sane_strstatus (status)); - return status; - } - } - for (i = 0; i < 3; i++) - { - val = dev->frontend.offset[i]; - status = sanei_genesys_fe_write_data (dev, 0x05 + i, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_set_ad_fe: failed to write offset %d: %s\n", i, - sane_strstatus (status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl847_homsnr_gpio(Genesys_Device *dev) -{ -uint8_t val; -SANE_Status status=SANE_STATUS_GOOD; - - if (dev->model->gpo_type == GPO_CANONLIDE700) - { - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val &= ~REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - } - else - { - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val |= REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - } - return status; -} - -/* Set values of analog frontend */ -static SANE_Status -gl847_set_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status; - uint8_t val; - - DBG (DBG_proc, "gl847_set_fe (%s)\n", - set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?"); - - RIE (sanei_genesys_read_register (dev, REG04, &val)); - - /* route to AD devices */ - if ((val & REG04_FESET) == 0x02) - { - return gl847_set_ad_fe (dev, set); - } - - /* for now there is no support yet for wolfson fe */ - DBG (DBG_proc, "gl847_set_fe(): unsupported frontend type %d\n", - dev->reg[reg_0x04].value & REG04_FESET); - - DBGCOMPLETED; - return SANE_STATUS_UNSUPPORTED; -} - - -/** @brief set up motor related register for scan - */ -static SANE_Status -gl847_init_motor_regs_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - int scan_power_mode, - unsigned int flags) -{ - SANE_Status status; - int use_fast_fed; - unsigned int fast_dpi; - uint16_t scan_table[SLOPE_TABLE_SIZE]; - uint16_t fast_table[SLOPE_TABLE_SIZE]; - int scan_steps, fast_steps, factor; - unsigned int feedl, dist; - Genesys_Register_Set *r; - uint32_t z1, z2; - unsigned int min_restep = 0x20; - uint8_t val, effective; - int fast_step_type; - unsigned int ccdlmt,tgtime; - - DBGSTART; - DBG (DBG_proc, "gl847_init_motor_regs_scan : scan_exposure_time=%d, " - "scan_yres=%g, scan_step_type=%d, scan_lines=%d, scan_dummy=%d, " - "feed_steps=%d, scan_power_mode=%d, flags=%x\n", - scan_exposure_time, - scan_yres, - scan_step_type, - scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); - - /* get step multiplier */ - factor = gl847_get_step_multiplier (reg); - - use_fast_fed=0; - /* no fast fed since feed works well */ - if(dev->settings.yres==4444 && feed_steps>100 - && ((flags & MOTOR_FLAG_FEED)==0)) - { - use_fast_fed=1; - } - DBG (DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); - - sanei_genesys_set_triple(reg, REG_LINCNT, scan_lines); - DBG (DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); - - /* compute register 02 value */ - r = sanei_genesys_get_address (reg, REG02); - r->value = 0x00; - r->value |= REG02_MTRPWR; - - if (use_fast_fed) - r->value |= REG02_FASTFED; - else - r->value &= ~REG02_FASTFED; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= REG02_AGOHOME | REG02_NOTHOME; - - if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - ||(scan_yres>=dev->sensor.optical_res)) - { - r->value |= REG02_ACDCDIS; - } - - /* scan and backtracking slope table */ - sanei_genesys_slope_table(scan_table, - &scan_steps, - scan_yres, - scan_exposure_time, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - gl847_motors); - RIE(gl847_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); - RIE(gl847_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); - - /* fast table */ - fast_dpi=sanei_genesys_get_lowest_ydpi(dev); - fast_step_type=scan_step_type; - if(scan_step_type>=2) - { - fast_step_type=2; - } - - sanei_genesys_slope_table(fast_table, - &fast_steps, - fast_dpi, - scan_exposure_time, - dev->motor.base_ydpi, - fast_step_type, - factor, - dev->model->motor_type, - gl847_motors); - - /* manual override of high start value */ - fast_table[0]=fast_table[1]; - - RIE(gl847_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); - RIE(gl847_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); - RIE(gl847_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); - - /* correct move distance by acceleration and deceleration amounts */ - feedl=feed_steps; - if (use_fast_fed) - { - feedl<<=fast_step_type; - dist=(scan_steps+2*fast_steps)*factor; - /* TODO read and decode REGAB */ - r = sanei_genesys_get_address (reg, 0x5e); - dist += (r->value & 31); - /* FEDCNT */ - r = sanei_genesys_get_address (reg, REG_FEDCNT); - dist += r->value; - } - else - { - feedl<<=scan_step_type; - dist=scan_steps*factor; - if (flags & MOTOR_FLAG_FEED) - dist *=2; - } - DBG (DBG_io2, "%s: scan steps=%d\n", __func__, scan_steps); - DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); - - /* check for overflow */ - if(distvalue & REG0C_CCDLMT)+1; - - r = sanei_genesys_get_address (reg, REG1C); - tgtime=1<<(r->value & REG1C_TGTIME); - - /* hi res motor speed GPIO */ - RIE (sanei_genesys_read_register (dev, REG6C, &effective)); - - /* if quarter step, bipolar Vref2 */ - if (scan_step_type > 1) - { - if (scan_step_type < 3) - { - val = effective & ~REG6C_GPIO13; - } - else - { - val = effective | REG6C_GPIO13; - } - } - else - { - val = effective; - } - RIE (sanei_genesys_write_register (dev, REG6C, val)); - - /* effective scan */ - RIE (sanei_genesys_read_register (dev, REG6C, &effective)); - val = effective | REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - - min_restep=scan_steps/2-1; - if (min_restep < 1) - min_restep = 1; - r = sanei_genesys_get_address (reg, REG_FWDSTEP); - r->value = min_restep; - r = sanei_genesys_get_address (reg, REG_BWDSTEP); - r->value = min_restep; - - sanei_genesys_calculate_zmode2(use_fast_fed, - scan_exposure_time*ccdlmt*tgtime, - scan_table, - scan_steps*factor, - feedl, - min_restep*factor, - &z1, - &z2); - - DBG (DBG_info, "gl847_init_motor_regs_scan: z1 = %d\n", z1); - sanei_genesys_set_triple(reg, REG60, z1 | (scan_step_type << (16+REG60S_STEPSEL))); - - DBG (DBG_info, "gl847_init_motor_regs_scan: z2 = %d\n", z2); - sanei_genesys_set_triple(reg, REG63, z2 | (scan_step_type << (16+REG63S_FSTPSEL))); - - r = sanei_genesys_get_address (reg, 0x1e); - r->value &= 0xf0; /* 0 dummy lines */ - r->value |= scan_dummy; /* dummy lines */ - - r = sanei_genesys_get_address (reg, REG67); - r->value = REG67_MTRPWM; - - r = sanei_genesys_get_address (reg, REG68); - r->value = REG68_FASTPWM; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FSHDEC); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FMOVNO); - r->value = fast_steps; - - r = sanei_genesys_get_address (reg, REG_FMOVDEC); - r->value = fast_steps; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** @brief set up registers related to sensor - * Set up the following registers - 0x01 - 0x03 - 0x10-0x015 R/G/B exposures - 0x19 EXPDMY - 0x2e BWHI - 0x2f BWLO - 0x04 - 0x87 - 0x05 - 0x2c,0x2d DPISET - 0x30,0x31 STRPIXEL - 0x32,0x33 ENDPIXEL - 0x35,0x36,0x37 MAXWD [25:2] (>>2) - 0x38,0x39 LPERIOD - 0x34 DUMMY - */ -static SANE_Status -gl847_init_optical_regs_scan (Genesys_Device * dev, - Genesys_Register_Set * reg, - unsigned int exposure_time, - int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, int color_filter, int flags) -{ - unsigned int words_per_line; - unsigned int startx, endx, used_pixels; - unsigned int dpiset, dpihw,segnb,cksel,factor; - unsigned int bytes; - Genesys_Register_Set *r; - SANE_Status status; - Sensor_Profile *sensor; - - DBG (DBG_proc, "gl847_init_optical_regs_scan : exposure_time=%d, " - "used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", exposure_time, - used_res, start, pixels, channels, depth, half_ccd, flags); - - /* resolution is divided according to CKSEL */ - r = sanei_genesys_get_address (reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); - - /* to manage high resolution device while keeping good - * low resolution scanning speed, we make hardware dpi vary */ - dpihw=sanei_genesys_compute_dpihw(dev, used_res * cksel); - factor=dev->sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); - - /* sensor parameters */ - sensor=get_sensor_profile(dev->model->ccd_type, dpihw); - gl847_setup_sensor (dev, reg, dpihw); - dpiset = used_res * cksel; - - /* start and end coordinate in optical dpi coordinates */ - startx = start/cksel+dev->sensor.CCD_start_xoffset; - used_pixels=pixels/cksel; - - /* end of sensor window */ - endx = startx + used_pixels; - - /* sensors are built from 600 dpi segments for LiDE 100/200 - * and 1200 dpi for the 700F */ - if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR) - { - segnb=dpihw/600; - } - else - { - segnb=1; - } - - /* compute pixel coordinate in the given dpihw space, - * taking segments into account */ - startx/=factor*segnb; - endx/=factor*segnb; - dev->len=endx-startx; - dev->dist=0; - dev->skip=0; - - /* in cas of multi-segments sensor, we have to add the witdh - * of the sensor crossed by the scan area */ - if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR && segnb>1) - { - dev->dist = sensor->segcnt; - } - - /* use a segcnt rounded to next even number */ - endx += ((dev->dist+1)&0xfffe)*(segnb-1); - used_pixels=endx-startx; - - status = gl847_set_fe (dev, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_init_optical_regs_scan: failed to set frontend: %s\n", - sane_strstatus (status)); - return status; - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, REG01); - r->value &= ~REG01_SCAN; - r->value |= REG01_SHDAREA; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - r->value &= ~REG01_DVDSET; - } - else - { - r->value |= REG01_DVDSET; - } - - r = sanei_genesys_get_address (reg, REG03); - r->value &= ~REG03_AVEENB; - - if (flags & OPTICAL_FLAG_DISABLE_LAMP) - r->value &= ~REG03_LAMPPWR; - else - r->value |= REG03_LAMPPWR; - - /* BW threshold */ - r = sanei_genesys_get_address (reg, 0x2e); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, 0x2f); - r->value = dev->settings.threshold; - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, REG04); - switch (depth) - { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - r->value &= ~(REG04_FILTER | REG04_AFEMOD); - if (channels == 1) - { - switch (color_filter) - { - case 0: - r->value |= 0x14; /* red filter */ - break; - case 2: - r->value |= 0x1c; /* blue filter */ - break; - default: - r->value |= 0x18; /* green filter */ - break; - } - } - else - r->value |= 0x10; /* mono */ - - /* register 05 */ - r = sanei_genesys_get_address (reg, REG05); - - /* set up dpihw */ - r->value &= ~REG05_DPIHW; - switch(dpihw) - { - case 600: - r->value |= REG05_DPIHW_600; - break; - case 1200: - r->value |= REG05_DPIHW_1200; - break; - case 2400: - r->value |= REG05_DPIHW_2400; - break; - case 4800: - r->value |= REG05_DPIHW_4800; - break; - } - - /* enable gamma tables */ - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - /* CIS scanners can do true gray by setting LEDADD */ - /* we set up LEDADD only when asked */ - if (dev->model->is_cis == SANE_TRUE) - { - r = sanei_genesys_get_address (reg, 0x87); - r->value &= ~REG87_LEDADD; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG87_LEDADD; - } - /* RGB weighting - r = sanei_genesys_get_address (reg, 0x01); - r->value &= ~REG01_TRUEGRAY; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG01_TRUEGRAY; - }*/ - } - - /* words(16bit) before gamma, conversion to 8 bit or lineart*/ - words_per_line = (used_pixels * dpiset) / dpihw; - bytes=depth/8; - if (depth == 1) - { - words_per_line = (words_per_line+7)/8 ; - dev->len = (dev->len >> 3) + ((dev->len & 7) ? 1 : 0); - dev->dist = (dev->dist >> 3) + ((dev->dist & 7) ? 1 : 0); - } - else - { - words_per_line *= bytes; - dev->dist *= bytes; - dev->len *= bytes; - } - - dev->bpl = words_per_line; - dev->cur=0; - dev->segnb=segnb; - dev->line_interp = 0; - - sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); - - sanei_genesys_set_double(reg,REG_STRPIXEL,startx); - sanei_genesys_set_double(reg,REG_ENDPIXEL,endx); - DBG (DBG_io2, "%s: startx=%d\n", __func__, startx); - DBG (DBG_io2, "%s: endx =%d\n", __func__, endx); - - DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->segnb =%lu\n", __func__, (unsigned long)dev->segnb); - - words_per_line *= channels; - dev->wpl = words_per_line; - - if(dev->oe_buffer.buffer!=NULL) - { - sanei_genesys_buffer_free (&(dev->oe_buffer)); - } - RIE (sanei_genesys_buffer_alloc (&(dev->oe_buffer), dev->wpl)); - - /* MAXWD is expressed in 4 words unit */ - sanei_genesys_set_triple(reg, REG_MAXWD, (words_per_line >> 2)); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); - - sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); - DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); - - r = sanei_genesys_get_address (reg, 0x34); - r->value = dev->sensor.dummy_pixel; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl847_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int color_filter, - unsigned int flags) -{ - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; - unsigned int oflags; /**> optical flags */ - unsigned int mflags; /**> motor flags */ - int exposure_time; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int scan_power_mode = 0; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - SANE_Status status; - - DBG (DBG_info, - "gl847_init_scan_regs settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g/%g\n" - "Depth/Channels: %u/%u\n" - "Flags : %x\n\n", - xres, yres, lines, pixels, startx, starty, depth, channels, flags); - - /* we may have 2 domains for ccd: xres below or above half ccd max dpi */ - if (dev->sensor.optical_res < 2 * xres || - !(dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)) - { - half_ccd = SANE_FALSE; - } - else - { - half_ccd = SANE_TRUE; - } - - /* optical_res */ - optical_res = dev->sensor.optical_res; - if (half_ccd) - optical_res /= 2; - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "gl847_init_scan_regs : stagger=%d lines\n", stagger); - - /* used_res */ - if (flags & SCAN_FLAG_USE_OPTICAL_RES) - { - used_res = optical_res; - } - else - { - /* resolution is choosen from a list */ - used_res = xres; - } - - /* compute scan parameters values */ - /* pixels are allways given at full optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - /* add x coordinates */ - start = startx; - - if (stagger > 0) - start |= 1; - - /* compute correct pixels number */ - /* pixels */ - used_pixels = (pixels * optical_res) / xres; - - /* round up pixels number if needed */ - if (used_pixels * xres < pixels * optical_res) - used_pixels++; - - dummy = 3-channels; - -/* slope_dpi */ -/* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = yres * channels; - else - slope_dpi = yres; - - slope_dpi = slope_dpi * (1 + dummy); - - exposure_time = gl847_compute_exposure (dev, used_res); - scan_step_type = sanei_genesys_compute_step_type(gl847_motors, dev->model->motor_type, exposure_time); - - DBG (DBG_info, "gl847_init_scan_regs : exposure_time=%d pixels\n", exposure_time); - DBG (DBG_info, "gl847_init_scan_regs : scan_step_type=%d\n", scan_step_type); - -/*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if ((flags & SCAN_FLAG_DYNAMIC_LINEART) && (dev->settings.scan_mode == SCAN_MODE_LINEART)) - { - depth = 8; - } - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - oflags = 0; - if(flags & SCAN_FLAG_DISABLE_SHADING) - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - if(flags & SCAN_FLAG_DISABLE_GAMMA) - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - if(flags & SCAN_FLAG_DISABLE_LAMP) - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - - if (dev->model->is_cis && dev->settings.true_gray) - { - oflags |= OPTICAL_FLAG_ENABLE_LEDADD; - } - - status = gl847_init_optical_regs_scan (dev, - reg, - exposure_time, - used_res, - start, - used_pixels, - channels, - depth, - half_ccd, - color_filter, - oflags); - - if (status != SANE_STATUS_GOOD) - return status; - -/*** motor parameters ***/ - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,flags); - - /* lincnt */ - lincnt = lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = starty; - DBG (DBG_info, "gl847_init_scan_regs: move=%d steps\n", move); - - mflags=0; - if(flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) - mflags |= MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; - if(flags & SCAN_FLAG_FEEDING) - mflags |= MOTOR_FLAG_FEED; - - status = gl847_init_motor_regs_scan (dev, - reg, - exposure_time, - slope_dpi, - scan_step_type, - dev->model->is_cis ? lincnt * - channels : lincnt, dummy, move, - scan_power_mode, - mflags); - - if (status != SANE_STATUS_GOOD) - return status; - - - /*** prepares data reordering ***/ - -/* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * channels * depth) / 8; - - requested_buffer_size = 8 * bytes_per_line; - /* we must use a round number of bytes_per_line */ - /* XXX STEF XXX - if (requested_buffer_size > BULKIN_MAXSIZE) - requested_buffer_size = - (BULKIN_MAXSIZE / bytes_per_line) * bytes_per_line; - */ - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * channels * depth) / 8; - - RIE (sanei_genesys_buffer_free (&(dev->read_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->read_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->lines_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->lines_buffer), read_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->shrink_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->shrink_buffer), - requested_buffer_size)); - - RIE (sanei_genesys_buffer_free (&(dev->out_buffer))); - RIE (sanei_genesys_buffer_alloc (&(dev->out_buffer), - (8 * dev->settings.pixels * channels * - depth) / 8)); - - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG (DBG_info, - "gl847_init_scan_regs: physical bytes to read = %lu\n", - (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - -/* TODO: should this be done elsewhere? */ - /* scan bytes to send to the frontend */ - /* theory : - target_size = - (dev->settings.pixels * dev->settings.lines * channels * depth) / 8; - but it suffers from integer overflow so we do the following: - - 1 bit color images store color data byte-wise, eg byte 0 contains - 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains - 8 bits of blue. - This does not fix the overflow, though. - 644mp*16 = 10gp, leading to an overflow - -- pierre - */ - - dev->total_bytes_read = 0; - if (depth == 1) - dev->total_bytes_to_read = - ((dev->settings.pixels * dev->settings.lines) / 8 + - (((dev->settings.pixels * dev->settings.lines) % 8) ? 1 : 0)) * - channels; - else - dev->total_bytes_to_read = - dev->settings.pixels * dev->settings.lines * channels * (depth / 8); - - DBG (DBG_info, "gl847_init_scan_regs: total bytes to send = %lu\n", - (u_long) dev->total_bytes_to_read); -/* END TODO */ - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl847_calculate_current_setup (Genesys_Device * dev) -{ - int channels; - int depth; - int start; - - float xres; /*dpi */ - float yres; /*dpi */ - float startx; /*optical_res, from dummy_pixel+1 */ - float pixels; - float lines; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure_time; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int max_shift; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - - DBG (DBG_info, - "gl847_calculate_current_setup settings:\n" - "Resolution: %uDPI\n" - "Lines : %u\n" - "PPL : %u\n" - "Startpos : %.3f/%.3f\n" - "Scan mode : %d\n\n", - dev->settings.yres, dev->settings.lines, dev->settings.pixels, - dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); - - /* channels */ - if (dev->settings.scan_mode == 4) /* single pass color */ - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == 0) - depth = 1; - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - - xres = dev->settings.xres; /*dpi */ - yres = dev->settings.yres; /*dpi */ - startx = start; /*optical_res, from dummy_pixel+1 */ - pixels = dev->settings.pixels; - lines = dev->settings.lines; - - DBG (DBG_info, - "gl847_calculate_current_setup settings:\n" - "Resolution : %gDPI/%gDPI\n" - "Lines : %g\n" - "PPL : %g\n" - "Startpos : %g\n" - "Depth/Channels: %u/%u\n\n", - xres, yres, lines, pixels, startx, depth, channels); - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if ((dev->sensor.optical_res < 2 * xres) || - !(dev->model->flags & GENESYS_FLAG_HALF_CCD_MODE)) - { - half_ccd = SANE_FALSE; - } - else - { - half_ccd = SANE_TRUE; - } - - /* optical_res */ - optical_res = dev->sensor.optical_res; - - /* stagger */ - if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) - stagger = (4 * yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "gl847_calculate_current_setup: stagger=%d lines\n", - stagger); - - /* resolution is choosen from a fixed list */ - used_res = xres; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - - /* compute correct pixels number */ - used_pixels = (pixels * optical_res) / used_res; - dummy = 3-channels; - - /* slope_dpi */ - /* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = yres * channels; - else - slope_dpi = yres; - - slope_dpi = slope_dpi * (1 + dummy); - - exposure_time = gl847_compute_exposure (dev, used_res); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,channels,yres,0); - - /* lincnt */ - lincnt = lines + max_shift + stagger; - - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = depth; - dev->current_setup.channels = channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = yres; - dev->current_setup.half_ccd = half_ccd; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static void -gl847_set_motor_power (Genesys_Register_Set * regs, SANE_Bool set) -{ - - DBG (DBG_proc, "gl847_set_motor_power\n"); - - if (set) - { - sanei_genesys_set_reg_from_set (regs, REG02, - sanei_genesys_read_reg_from_set (regs, - REG02) - | REG02_MTRPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, REG02, - sanei_genesys_read_reg_from_set (regs, - REG02) - & ~REG02_MTRPWR); - } -} - -static void -gl847_set_lamp_power (Genesys_Device __sane_unused__ * dev, - Genesys_Register_Set * regs, SANE_Bool set) -{ - if (set) - { - sanei_genesys_set_reg_from_set (regs, REG03, - sanei_genesys_read_reg_from_set (regs, REG03) - | REG03_LAMPPWR); - } - else - { - sanei_genesys_set_reg_from_set (regs, REG03, - sanei_genesys_read_reg_from_set (regs, REG03) - & ~REG03_LAMPPWR); - } -} - -/*for fast power saving methods only, like disabling certain amplifiers*/ -static SANE_Status -gl847_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - DBG (DBG_proc, "gl847_save_power: enable = %d\n", enable); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl847_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - DBG (DBG_proc, "gl847_set_powersaving (delay = %d)\n", delay); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl847_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl847_stop_action (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val40, val; - unsigned int loop; - - DBGSTART; - - /* post scan gpio : without that HOMSNR is unreliable */ - gl847_homsnr_gpio(dev); - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBG (DBG_info, "%s: already stopped\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* ends scan */ - val = sanei_genesys_read_reg_from_set (dev->reg, REG01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set (dev->reg, REG01, val); - status = sanei_genesys_write_register (dev, REG01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write register 01: %s\n", __func__, - sane_strstatus (status)); - return status; - } - usleep (100 * 1000); - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) - && !(val & REG41_MOTORENB)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - usleep (100 * 1000); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - -/* Send the low-level scan command */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl847_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - SANE_Status status; - uint8_t val; - Genesys_Register_Set *r; - - DBGSTART; - - /* clear GPIO 10 */ - if (dev->model->gpo_type != GPO_CANONLIDE700) - { - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val &= ~REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - } - - val = REG0D_CLRLNCNT; - RIE (sanei_genesys_write_register (dev, REG0D, val)); - val = REG0D_CLRMCNT; - RIE (sanei_genesys_write_register (dev, REG0D, val)); - - RIE (sanei_genesys_read_register (dev, REG01, &val)); - val |= REG01_SCAN; - RIE (sanei_genesys_write_register (dev, REG01, val)); - r = sanei_genesys_get_address (reg, REG01); - r->value = val; - - if (start_motor) - { - RIE (sanei_genesys_write_register (dev, REG0F, 1)); - } - else - { - RIE (sanei_genesys_write_register (dev, REG0F, 0)); - } - - DBGCOMPLETED; - - return status; -} - - -/* Send the stop scan command */ -#ifndef UNIT_TESTING -static -#endif - SANE_Status -gl847_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - SANE_Status status; - - DBG (DBG_proc, "gl847_end_scan (check_stop = %d)\n", check_stop); - if (reg == NULL) - return SANE_STATUS_INVAL; - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl847_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_end_scan: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -/** rewind scan - * Move back by the same amount of distance than previous scan. - * @param dev device to rewind - * @returns SANE_STATUS_GOOD on success - */ -GENESYS_STATIC -SANE_Status gl847_rewind(Genesys_Device * dev) -{ - SANE_Status status; - uint8_t byte; - - DBGSTART; - - /* set motor reverse */ - RIE (sanei_genesys_read_register (dev, 0x02, &byte)); - byte |= 0x04; - RIE (sanei_genesys_write_register(dev, 0x02, byte)); - - /* and start scan, then wait completion */ - RIE (gl847_begin_scan (dev, dev->reg, SANE_TRUE)); - do - { - usleep(100*1000); - RIE (sanei_genesys_read_register (dev, REG40, &byte)); - } - while(byte & REG40_MOTMFLG); - RIE (gl847_end_scan (dev, dev->reg, SANE_TRUE)); - - /* restore direction */ - RIE (sanei_genesys_read_register (dev, 0x02, &byte)); - byte &= 0xfb; - RIE (sanei_genesys_write_register(dev, 0x02, byte)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** Park head - * Moves the slider to the home (top) position slowly - * @param dev device to park - * @param wait_until_home true to make the function waiting for head - * to be home before returning, if fals returne immediately - * @returns SANE_STATUS_GOO on success */ -GENESYS_STATIC -SANE_Status -gl847_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg[GENESYS_GL847_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - float resolution; - uint8_t val; - int loop = 0; - int scan_mode; - - DBG (DBG_proc, "gl847_slow_back_home (wait_until_home = %d)\n", - wait_until_home); - - /* post scan gpio : without that HOMSNR is unreliable */ - gl847_homsnr_gpio(dev); - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - usleep (100000); /* sleep 100 ms */ - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - /* is sensor at home? */ - if (val & HOMESNR) - { - DBG (DBG_info, "%s: already at home, completed\n", __func__); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - memcpy (local_reg, dev->reg, GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - - resolution=sanei_genesys_get_lowest_ydpi(dev); - - /* TODO add scan_mode to the API */ - scan_mode= dev->settings.scan_mode; - dev->settings.scan_mode=SCAN_MODE_LINEART; - status = gl847_init_scan_regs (dev, - local_reg, - resolution, - resolution, - 100, - 30000, - 100, - 100, - 8, - 1, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_slow_back_home: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - dev->settings.scan_mode=scan_mode; - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse */ - r = sanei_genesys_get_address (local_reg, REG02); - r->value |= REG02_MTRREV; - - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL847_MAX_REGS)); - - status = gl847_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_slow_back_home: failed to start motor: %s\n", - sane_strstatus (status)); - gl847_stop_action (dev); - /* send original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL847_MAX_REGS); - return status; - } - - /* post scan gpio : without that HOMSNR is unreliable */ - gl847_homsnr_gpio(dev); - - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_slow_back_home: failed to read home sensor: %s\n", - sane_strstatus (status)); - return status; - } - - if (val & HOMESNR) /* home sensor */ - { - DBG (DBG_info, "gl847_slow_back_home: reached home position\n"); - gl847_stop_action (dev); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - usleep (100000); /* sleep 100 ms */ - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl847_stop_action (dev); - DBG (DBG_error, - "gl847_slow_back_home: timeout while waiting for scanhead to go home\n"); - return SANE_STATUS_IO_ERROR; - } - - DBG (DBG_info, "gl847_slow_back_home: scanhead is still moving\n"); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl847_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status; - uint8_t *data; - Genesys_Register_Set local_reg[GENESYS_GL847_MAX_REGS]; - int steps; - - int pixels = 600; - int dpi = 300; - - DBG (DBG_proc, "gl847_search_start_position\n"); - - memcpy (local_reg, dev->reg, - GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - status = gl847_init_scan_regs (dev, local_reg, dpi, dpi, 0, 0, /*we should give a small offset here~60 steps */ - 600, dev->model->search_lines, 8, 1, 1, /*green */ - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_search_start_position: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* send to scanner */ - status = dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL847_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_search_start_position: failed to bulk write registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - size = pixels * dev->model->search_lines; - - data = malloc (size); - if (!data) - { - DBG (DBG_error, - "gl847_search_start_position: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - - status = gl847_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl847_search_start_position: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl847_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("search_position.pnm", data, 8, 1, pixels, - dev->model->search_lines); - - status = gl847_end_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl847_search_start_position: failed to end scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* update regs to copy ASIC internal state */ - memcpy (dev->reg, local_reg, - GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - -/*TODO: find out where sanei_genesys_search_reference_point - stores information, and use that correctly*/ - status = - sanei_genesys_search_reference_point (dev, data, 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl847_search_start_position: failed to set search reference point: %s\n", - sane_strstatus (status)); - return status; - } - - free (data); - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl847_init_regs_for_coarse_calibration (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t channels; - uint8_t cksel; - - DBG (DBG_proc, "gl847_init_regs_for_coarse_calibration\n"); - - - cksel = (dev->calib_reg[reg_0x18].value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - status = gl847_init_scan_regs (dev, - dev->calib_reg, - dev->settings.xres, - dev->settings.yres, - 0, - 0, - dev->sensor.optical_res / cksel, - 20, - 16, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_init_register_for_coarse_calibration: Failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_info, - "gl847_init_register_for_coarse_calibration: optical sensor res: %d dpi, actual res: %d\n", - dev->sensor.optical_res / cksel, dev->settings.xres); - - status = - dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL847_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_init_register_for_coarse_calibration: Failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move in base_dpi line count - * */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status -gl847_feed (Genesys_Device * dev, unsigned int steps) -{ - Genesys_Register_Set local_reg[GENESYS_GL847_MAX_REGS]; - SANE_Status status; - Genesys_Register_Set *r; - float resolution; - uint8_t val; - - DBGSTART; - DBG (DBG_io, "%s: steps=%d\n", __func__, steps); - - /* prepare local registers */ - memcpy (local_reg, dev->reg, GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - - resolution=sanei_genesys_get_lowest_ydpi(dev); - status = gl847_init_scan_regs (dev, - local_reg, - resolution, - resolution, - 0, - steps, - 100, - 3, - 8, - 3, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_FEEDING | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_feed: failed to set up registers: %s\n", - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* set exposure to zero */ - sanei_genesys_set_triple(local_reg,REG_EXPR,0); - sanei_genesys_set_triple(local_reg,REG_EXPG,0); - sanei_genesys_set_triple(local_reg,REG_EXPB,0); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); - - /* set up for no scan */ - r = sanei_genesys_get_address (local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* send registers */ - RIE (dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL847_MAX_REGS)); - - status = gl847_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); - gl847_stop_action (dev); - - /* restore original registers */ - dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL847_MAX_REGS); - return status; - } - - /* wait until feed count reaches the required value, but do not - * exceed 30s */ - do - { - status = sanei_genesys_get_status (dev, &val); - } - while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); - - /* then stop scanning */ - RIE(gl847_stop_action (dev)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -static SANE_Status -gl847_init_regs_for_shading (Genesys_Device * dev) -{ - SANE_Status status; - float move; - - DBGSTART; - dev->calib_channels = 3; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - - dev->calib_resolution = sanei_genesys_compute_dpihw(dev,dev->settings.xres); - dev->calib_lines = dev->model->shading_lines; - if(dev->calib_resolution==4800) - dev->calib_lines *= 2; - dev->calib_pixels = (dev->sensor.sensor_pixels*dev->calib_resolution)/dev->sensor.optical_res; - DBG (DBG_io, "%s: calib_lines = %d\n", __func__, (int)dev->calib_lines); - DBG (DBG_io, "%s: calib_pixels = %d\n", __func__, (int)dev->calib_pixels); - - /* this is aworkaround insufficent distance for slope - * motor acceleration TODO special motor slope for shading */ - move=1; - if(dev->calib_resolution<1200) - { - move=40; - } - - status = gl847_init_scan_regs (dev, - dev->calib_reg, - dev->calib_resolution, - dev->calib_resolution, - 0, - move, - dev->calib_pixels, - dev->calib_lines, - 16, - dev->calib_channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - status = dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL847_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus (status)); - return status; - } - - /* we use GENESYS_FLAG_SHADING_REPARK */ - dev->scanhead_position_in_steps = 0; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief set up registers for the actual scan - */ -static SANE_Status -gl847_init_regs_for_scan (Genesys_Device * dev) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status; - - DBG (DBG_info, - "gl847_init_regs_for_scan settings:\nResolution: %uDPI\n" - "Lines : %u\nPPL : %u\nStartpos : %.3f/%.3f\nScan mode : %d\n\n", - dev->settings.yres, dev->settings.lines, dev->settings.pixels, - dev->settings.tl_x, dev->settings.tl_y, dev->settings.scan_mode); - - /* channels */ - if (dev->settings.scan_mode == SCAN_MODE_COLOR) /* single pass color */ - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == SCAN_MODE_LINEART) - depth = 1; - - - /* steps to move to reach scanning area: - - first we move to physical start of scanning - either by a fixed steps amount from the black strip - or by a fixed amount from parking position, - minus the steps done during shading calibration - - then we move by the needed offset whitin physical - scanning area - - assumption: steps are expressed at maximum motor resolution - - we need: - SANE_Fixed y_offset; - SANE_Fixed y_size; - SANE_Fixed y_offset_calib; - mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ - - /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is - relative from origin, else, it is from parking position */ - - move_dpi = dev->motor.base_ydpi; - - move = SANE_UNFIX (dev->model->y_offset); - move += dev->settings.tl_y; - move = (move * move_dpi) / MM_PER_INCH; - move -= dev->scanhead_position_in_steps; - DBG (DBG_info, "%s: move=%f steps\n",__func__, move); - - /* fast move to scan area */ - /* we don't move fast the whole distance since it would involve - * computing acceleration/deceleration distance for scan - * resolution. So leave a remainder for it so scan makes the final - * move tuning */ - if(channels*dev->settings.yres>=600 && move>700) - { - status = gl847_feed (dev, move-500); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to move to scan area\n",__func__); - return status; - } - move=500; - } - - DBG (DBG_info, "gl124_init_regs_for_scan: move=%f steps\n", move); - DBG (DBG_info, "%s: move=%f steps\n", __func__, move); - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * dev->sensor.optical_res) / MM_PER_INCH; - - flags = 0; - - /* emulated lineart from gray data is required for now */ - if(dev->settings.scan_mode == SCAN_MODE_LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - /* backtracking isn't handled well, so don't enable it */ - flags |= SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; - - status = gl847_init_scan_regs (dev, - dev->reg, - dev->settings.xres, - dev->settings.yres, - start, - move, - dev->settings.pixels, - dev->settings.lines, - depth, - channels, - dev->settings.color_filter, - flags); - - if (status != SANE_STATUS_GOOD) - return status; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -static SANE_Status -gl847_send_shading_data (Genesys_Device * dev, uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t addr, length, i, x, factor, pixels; - uint32_t dpiset, dpihw, strpixel, endpixel; - uint16_t tempo; - uint32_t lines, channels; - uint8_t val,*buffer,*ptr,*src; - - DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); - - /* shading data is plit in 3 (up to 5 with IR) areas - write(0x10014000,0x00000dd8) - URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x.... - write(0x1003e000,0x00000dd8) - write(0x10068000,0x00000dd8) - */ - length = (uint32_t) (size / 3); - sanei_genesys_get_double(dev->reg,REG_STRPIXEL,&tempo); - strpixel=tempo; - sanei_genesys_get_double(dev->reg,REG_ENDPIXEL,&tempo); - endpixel=tempo; - - /* compute deletion factor */ - sanei_genesys_get_double(dev->reg,REG_DPISET,&tempo); - dpiset=tempo; - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n",__func__,strpixel,endpixel,endpixel-strpixel,dpiset); - dpihw=sanei_genesys_compute_dpihw(dev,dpiset); - factor=dpihw/dpiset; - DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); - - if(DBG_LEVEL>=DBG_data) - { - dev->binary=fopen("binary.pnm","wb"); - sanei_genesys_get_triple(dev->reg, REG_LINCNT, &lines); - channels=dev->current_setup.channels; - if(dev->binary!=NULL) - { - fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); - } - } - - pixels=endpixel-strpixel; - - /* since we're using SHDAREA, substract startx coordinate from shading */ - strpixel-=((dev->sensor.CCD_start_xoffset*600)/dev->sensor.optical_res); - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; - pixels*=2*2; - - /* allocate temporary buffer */ - buffer=(uint8_t *)malloc(pixels); - memset(buffer,0,pixels); - DBG( DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n",__func__,pixels,pixels); - - /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address - * is 8192*reg value */ - - /* write actual color channel data */ - for(i=0;i<3;i++) - { - /* build up actual shading data by copying the part from the full width one - * to the one corresponding to SHDAREA */ - ptr=buffer; - - /* iterate on both sensor segment */ - for(x=0;xdn, dev->usb_mode, addr, pixels, buffer); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "gl847_send_shading_data; write to AHB failed (%s)\n", - sane_strstatus (status)); - return status; - } - } - - free(buffer); - DBGCOMPLETED; - - return status; -} - -/** @brief calibrates led exposure - * Calibrate exposure by scanning a white area until the used exposure gives - * data white enough. - * @param dev device to calibrate - */ -static SANE_Status -gl847_led_calibration (Genesys_Device * dev) -{ - int num_pixels; - int total_size; - int used_res; - uint8_t *line; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels, depth; - int avg[3], top[3], bottom[3]; - int turn; - char fn[20]; - uint16_t exp[3]; - Sensor_Profile *sensor; - float move; - SANE_Bool acceptable; - - DBGSTART; - - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; - if(move>20) - { - RIE(gl847_feed (dev, move)); - } - DBG (DBG_io, "%s: move=%f steps\n", __func__, move); - - /* offset calibration is always done in color mode */ - channels = 3; - depth=16; - used_res=sanei_genesys_compute_dpihw(dev,dev->settings.xres); - sensor=get_sensor_profile(dev->model->ccd_type, used_res); - num_pixels = (dev->sensor.sensor_pixels*used_res)/dev->sensor.optical_res; - - /* initial calibration reg values */ - memcpy (dev->calib_reg, dev->reg, GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - - /* set up for the calibration scan */ - status = gl847_init_scan_regs (dev, - dev->calib_reg, - used_res, - used_res, - 0, - 0, - num_pixels, - 1, - depth, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - - /* initial loop values and boundaries */ - exp[0]=sensor->expr; - exp[1]=sensor->expg; - exp[2]=sensor->expb; - - bottom[0]=29000; - bottom[1]=29000; - bottom[2]=29000; - - top[0]=41000; - top[1]=51000; - top[2]=51000; - - turn = 0; - - /* no move during led calibration */ - gl847_set_motor_power (dev->calib_reg, SANE_FALSE); - do - { - /* set up exposure */ - sanei_genesys_set_double(dev->calib_reg,REG_EXPR,exp[0]); - sanei_genesys_set_double(dev->calib_reg,REG_EXPG,exp[1]); - sanei_genesys_set_double(dev->calib_reg,REG_EXPB,exp[2]); - - /* write registers and scan data */ - RIEF (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL847_MAX_REGS), line); - - DBG (DBG_info, "gl847_led_calibration: starting line reading\n"); - RIEF (gl847_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, total_size), line); - - /* stop scanning */ - RIEF (gl847_stop_action (dev), line); - - if (DBG_LEVEL >= DBG_data) - { - snprintf (fn, 20, "led_%02d.pnm", turn); - sanei_genesys_write_pnm_file (fn, line, depth, channels, num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG (DBG_info, "gl847_led_calibration: average: %d,%d,%d\n", avg[0], avg[1], avg[2]); - - /* check if exposure gives average within the boundaries */ - acceptable = SANE_TRUE; - for(i=0;i<3;i++) - { - if(avg[i]top[i]) - { - exp[i]=(exp[i]*top[i])/avg[i]; - acceptable = SANE_FALSE; - } - } - - turn++; - } - while (!acceptable && turn < 100); - - DBG (DBG_info, "gl847_led_calibration: acceptable exposure: %d,%d,%d\n", exp[0], exp[1], exp[2]); - - /* set these values as final ones for scan */ - sanei_genesys_set_double(dev->reg,REG_EXPR,exp[0]); - sanei_genesys_set_double(dev->reg,REG_EXPG,exp[1]); - sanei_genesys_set_double(dev->reg,REG_EXPB,exp[2]); - - /* store in this struct since it is the one used by cache calibration */ - dev->sensor.regs_0x10_0x1d[0] = (exp[0] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[1] = exp[0] & 0xff; - dev->sensor.regs_0x10_0x1d[2] = (exp[1] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[3] = exp[1] & 0xff; - dev->sensor.regs_0x10_0x1d[4] = (exp[2] >> 8) & 0xff; - dev->sensor.regs_0x10_0x1d[5] = exp[2] & 0xff; - - /* cleanup before return */ - free (line); - - /* go back home */ - if(move>20) - { - status=gl847_slow_back_home (dev, SANE_TRUE); - } - - DBGCOMPLETED; - return status; -} - -/** - * set up GPIO/GPOE for idle state - */ -static SANE_Status -gl847_init_gpio (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx=0; - - DBGSTART; - - /* search GPIO profile */ - while(gpios[idx].sensor_id!=0 && dev->model->gpo_type!=gpios[idx].sensor_id) - { - idx++; - } - if(gpios[idx].sensor_id==0) - { - DBG (DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __func__, dev->model->ccd_type); - return SANE_STATUS_INVAL; - } - - RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); - RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); - - RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); - RIE (sanei_genesys_write_register (dev, REG6C, 0x00)); - - RIE (sanei_genesys_write_register (dev, REG6B, gpios[idx].r6b)); - RIE (sanei_genesys_write_register (dev, REG6C, gpios[idx].r6c)); - RIE (sanei_genesys_write_register (dev, REG6D, gpios[idx].r6d)); - RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); - RIE (sanei_genesys_write_register (dev, REG6F, gpios[idx].r6f)); - - RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); - RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); - - DBGCOMPLETED; - return status; -} - -/** - * set memory layout by filling values in dedicated registers - */ -static SANE_Status -gl847_init_memory_layout (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx = 0; - uint8_t val; - - DBG (DBG_proc, "gl847_init_memory_layout\n"); - - /* point to per model memory layout */ - idx = 0; - if (strcmp (dev->model->name, "canon-lide-100") == 0) - { - idx = 0; - } - if (strcmp (dev->model->name, "canon-lide-200") == 0) - { - idx = 1; - } - if (strcmp (dev->model->name, "canon-5600f") == 0) - { - idx = 2; - } - if (strcmp (dev->model->name, "canon-lide-700f") == 0) - { - idx = 3; - } - - /* CLKSET nd DRAMSEL */ - val = layouts[idx].dramsel; - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg[reg_0x0b].value = val; - - /* prevent further writings by bulk write register */ - dev->reg[reg_0x0b].address = 0x00; - - /* setup base address for shading data. */ - /* values must be multiplied by 8192=0x4000 to give address on AHB */ - /* R-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd0, layouts[idx].rd0); - /* G-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd1, layouts[idx].rd1); - /* B-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd2, layouts[idx].rd2); - - /* setup base address for scanned data. */ - /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ - /* R-Channel ODD image buffer 0x0124->0x92000 */ - /* size for each buffer is 0x16d*1k word */ - sanei_genesys_write_register (dev, 0xe0, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xe1, layouts[idx].re1); - /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ - sanei_genesys_write_register (dev, 0xe2, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xe3, layouts[idx].re3); - - /* R-Channel EVEN image buffer 0x0292 */ - sanei_genesys_write_register (dev, 0xe4, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xe5, layouts[idx].re5); - /* R-Channel EVEN image buffer end-address 0x03ff*/ - sanei_genesys_write_register (dev, 0xe6, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xe7, layouts[idx].re7); - - /* same for green, since CIS, same addresses */ - sanei_genesys_write_register (dev, 0xe8, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xe9, layouts[idx].re1); - sanei_genesys_write_register (dev, 0xea, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xeb, layouts[idx].re3); - sanei_genesys_write_register (dev, 0xec, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xed, layouts[idx].re5); - sanei_genesys_write_register (dev, 0xee, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xef, layouts[idx].re7); - -/* same for blue, since CIS, same addresses */ - sanei_genesys_write_register (dev, 0xf0, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xf1, layouts[idx].re1); - sanei_genesys_write_register (dev, 0xf2, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xf3, layouts[idx].re3); - sanei_genesys_write_register (dev, 0xf4, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xf5, layouts[idx].re5); - sanei_genesys_write_register (dev, 0xf6, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xf7, layouts[idx].re7); - - DBGCOMPLETED; - return status; -} - -/* * - * initialize ASIC from power on condition - */ -static SANE_Status -gl847_boot (Genesys_Device * dev, SANE_Bool cold) -{ - SANE_Status status; - uint8_t val; - - DBGSTART; - - /* reset ASIC if cold boot */ - if(cold) - { - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - } - - /* test CHKVER */ - RIE (sanei_genesys_read_register (dev, REG40, &val)); - if (val & REG40_CHKVER) - { - RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG (DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); - } - - /* Set default values for registers */ - gl847_init_registers (dev); - - /* Write initial registers */ - RIE (dev->model->cmd_set->bulk_write_register (dev, dev->reg, GENESYS_GL847_MAX_REGS)); - - /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ - val = dev->reg[reg_0x0b].value & REG0B_DRAMSEL; - val = (val | REG0B_ENBDRAM); - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg[reg_0x0b].value = val; - - /* CIS_LINE */ - SETREG (0x08, REG08_CIS_LINE); - RIE (sanei_genesys_write_register (dev, 0x08, dev->reg[reg_0x08].value)); - - /* set up end access */ - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0b)); - RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); - - /* setup gpio */ - RIE (gl847_init_gpio (dev)); - - /* setup internal memory layout */ - RIE (gl847_init_memory_layout (dev)); - - SETREG (0xf8, 0x01); - RIE (sanei_genesys_write_register (dev, 0xf8, dev->reg[reg_0xf8].value)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl847_init (Genesys_Device * dev) -{ - SANE_Status status; - - DBG_INIT (); - DBGSTART; - - status=sanei_genesys_asic_init(dev, GENESYS_GL847_MAX_REGS); - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl847_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not lose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - uint8_t scan, file, email, copy; - switch(s->dev->model->gpo_type) - { - case GPO_CANONLIDE700: - scan=0x04; - file=0x02; - email=0x01; - copy=0x08; - break; - default: - scan=0x01; - file=0x02; - email=0x04; - copy=0x08; - } - RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); - - if (s->val[OPT_SCAN_SW].b == s->last_val[OPT_SCAN_SW].b) - s->val[OPT_SCAN_SW].b = (val & scan) == 0; - if (s->val[OPT_FILE_SW].b == s->last_val[OPT_FILE_SW].b) - s->val[OPT_FILE_SW].b = (val & file) == 0; - if (s->val[OPT_EMAIL_SW].b == s->last_val[OPT_EMAIL_SW].b) - s->val[OPT_EMAIL_SW].b = (val & email) == 0; - if (s->val[OPT_COPY_SW].b == s->last_val[OPT_COPY_SW].b) - s->val[OPT_COPY_SW].b = (val & copy) == 0; - - return status; -} - -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl847_search_strip (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black) -{ - unsigned int pixels, lines, channels; - SANE_Status status; - Genesys_Register_Set local_reg[GENESYS_GL847_MAX_REGS]; - size_t size; - uint8_t *data; - int steps, depth, dpi; - unsigned int pass, count, found, x, y; - char title[80]; - Genesys_Register_Set *r; - - DBG (DBG_proc, "gl847_search_strip %s %s\n", black ? "black" : "white", - forward ? "forward" : "reverse"); - - gl847_set_fe (dev, AFE_SET); - status = gl847_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_search_strip: failed to stop: %s\n", - sane_strstatus (status)); - return status; - } - - /* set up for a gray scan at lowest dpi */ - dpi = 9600; - for (x = 0; x < MAX_RESOLUTIONS; x++) - { - if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) - dpi = dev->model->xdpi_values[x]; - } - channels = 1; - /* 10 MM */ - /* lines = (10 * dpi) / MM_PER_INCH; */ - /* shading calibation is done with dev->motor.base_ydpi */ - lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; - depth = 8; - pixels = (dev->sensor.sensor_pixels * dpi) / dev->sensor.optical_res; - size = pixels * channels * lines * (depth / 8); - data = malloc (size); - if (!data) - { - DBG (DBG_error, "gl847_search_strip: failed to allocate memory\n"); - return SANE_STATUS_NO_MEM; - } - dev->scanhead_position_in_steps = 0; - - memcpy (local_reg, dev->reg, - GENESYS_GL847_MAX_REGS * sizeof (Genesys_Register_Set)); - - status = gl847_init_scan_regs (dev, - local_reg, - dpi, - dpi, - 0, - 0, - pixels, - lines, - depth, - channels, - 0, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA); - if (status != SANE_STATUS_GOOD) - { - free(data); - DBG (DBG_error, - "gl847_search_strip: failed to setup for scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* set up for reverse or forward */ - r = sanei_genesys_get_address (local_reg, REG02); - if (forward) - r->value &= ~REG02_MTRREV; - else - r->value |= REG02_MTRREV; - - - status = dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL847_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - free(data); - DBG (DBG_error, - "gl847_search_strip: Failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl847_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl847_search_strip: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl847_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl847_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, "gl847_search_strip: gl847_stop_action failed\n"); - return status; - } - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file (title, data, depth, channels, pixels, - lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < 20 && !found) - { - status = - dev->model->cmd_set->bulk_write_register (dev, local_reg, GENESYS_GL847_MAX_REGS); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_search_strip: Failed to bulk write registers: %s\n", - sane_strstatus (status)); - return status; - } - - /* now start scan */ - status = gl847_begin_scan (dev, local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl847_search_strip: failed to begin scan: %s\n", - sane_strstatus (status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data, size); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, - "gl847_search_start_position: failed to read data: %s\n", - sane_strstatus (status)); - return status; - } - - status = gl847_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - free (data); - DBG (DBG_error, "gl847_search_strip: gl847_stop_action failed\n"); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file (title, data, depth, channels, - pixels, lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG (DBG_data, - "gl847_search_strip: strip found forward during pass %d at line %d\n", - pass, y); - } - else - { - DBG (DBG_data, - "gl847_search_strip: pixels=%d, count=%d (%d%%)\n", - pixels, count, (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG (DBG_data, - "gl847_search_strip: strip found backward during pass %d \n", - pass); - } - else - { - DBG (DBG_data, - "gl847_search_strip: pixels=%d, count=%d (%d%%)\n", - pixels, count, (100 * count) / pixels); - } - } - pass++; - } - free (data); - if (found) - { - status = SANE_STATUS_GOOD; - DBG (DBG_info, "gl847_search_strip: %s strip found\n", - black ? "black" : "white"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG (DBG_info, "gl847_search_strip: %s strip not found\n", - black ? "black" : "white"); - } - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a 8 bits scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black) -{ - unsigned int i, j, k, average, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average value on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG (DBG_info, "dark_average: avg[%d] = %d\n", k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG (DBG_info, "dark_average: average = %d\n", average); - return average; -} - -static SANE_Status -gl847_offset_calibration (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *first_line, *second_line, reg04; - unsigned int channels, bpp; - char title[32]; - int pass = 0, avg, total_size; - int topavg, bottomavg, resolution, lines; - int top, bottom, black_pixels, pixels; - - DBGSTART; - - /* no gain nor offset for AKM AFE */ - RIE (sanei_genesys_read_register (dev, REG04, ®04)); - if ((reg04 & REG04_FESET) == 0x02) - { - DBGCOMPLETED; - return status; - } - - /* offset calibration is always done in color mode */ - channels = 3; - resolution=dev->sensor.optical_res; - dev->calib_pixels = dev->sensor.sensor_pixels; - lines=1; - bpp=8; - pixels= (dev->sensor.sensor_pixels*resolution) / dev->sensor.optical_res; - black_pixels = (dev->sensor.black_pixels * resolution) / dev->sensor.optical_res; - DBG (DBG_io2, "gl847_offset_calibration: black_pixels=%d\n", black_pixels); - - status = gl847_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - pixels, - lines, - bpp, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_offset_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - gl847_set_motor_power (dev->calib_reg, SANE_FALSE); - - /* allocate memory for scans */ - total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ - - first_line = malloc (total_size); - if (!first_line) - return SANE_STATUS_NO_MEM; - - second_line = malloc (total_size); - if (!second_line) - { - free (first_line); - return SANE_STATUS_NO_MEM; - } - - /* init gain */ - dev->frontend.gain[0] = 0; - dev->frontend.gain[1] = 0; - dev->frontend.gain[2] = 0; - - /* scan with no move */ - bottom = 10; - dev->frontend.offset[0] = bottom; - dev->frontend.offset[1] = bottom; - dev->frontend.offset[2] = bottom; - - RIEF2 (gl847_set_fe(dev, AFE_SET),first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL847_MAX_REGS),first_line, second_line); - DBG (DBG_info, "gl847_offset_calibration: starting first line reading\n"); - RIEF2 (gl847_begin_scan (dev, dev->calib_reg, SANE_TRUE),first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, first_line, total_size),first_line, second_line); - if (DBG_LEVEL >= DBG_data) - { - snprintf(title,20,"offset%03d.pnm",bottom); - sanei_genesys_write_pnm_file (title, first_line, bpp, channels, pixels, lines); - } - - bottomavg = dark_average (first_line, pixels, lines, channels, black_pixels); - DBG (DBG_io2, "gl847_offset_calibration: bottom avg=%d\n", bottomavg); - - /* now top value */ - top = 255; - dev->frontend.offset[0] = top; - dev->frontend.offset[1] = top; - dev->frontend.offset[2] = top; - RIEF2 (gl847_set_fe(dev, AFE_SET),first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL847_MAX_REGS),first_line, second_line); - DBG (DBG_info, "gl847_offset_calibration: starting second line reading\n"); - RIEF2 (gl847_begin_scan (dev, dev->calib_reg, SANE_TRUE),first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size),first_line, second_line); - - topavg = dark_average (second_line, pixels, lines, channels, black_pixels); - DBG (DBG_io2, "gl847_offset_calibration: top avg=%d\n", topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.offset[0] = (top + bottom) / 2; - dev->frontend.offset[1] = (top + bottom) / 2; - dev->frontend.offset[2] = (top + bottom) / 2; - - /* scan with no move */ - RIEF2 (gl847_set_fe(dev, AFE_SET),first_line, second_line); - RIEF2 (dev->model->cmd_set->bulk_write_register (dev, dev->calib_reg, GENESYS_GL847_MAX_REGS),first_line, second_line); - DBG (DBG_info, "gl847_offset_calibration: starting second line reading\n"); - RIEF2 (gl847_begin_scan (dev, dev->calib_reg, SANE_TRUE),first_line, second_line); - RIEF2 (sanei_genesys_read_data_from_scanner (dev, second_line, total_size),first_line, second_line); - - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "offset%03d.pnm", dev->frontend.offset[1]); - sanei_genesys_write_pnm_file (title, second_line, bpp, channels, pixels, lines); - } - - avg = dark_average (second_line, pixels, lines, channels, black_pixels); - DBG (DBG_info, "gl847_offset_calibration: avg=%d offset=%d\n", avg, - dev->frontend.offset[1]); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.offset[1]; - } - else - { - bottomavg = avg; - bottom = dev->frontend.offset[1]; - } - } - DBG (DBG_info, "gl847_offset_calibration: offset=(%d,%d,%d)\n", dev->frontend.offset[0], dev->frontend.offset[1], dev->frontend.offset[2]); - - /* cleanup before return */ - free (first_line); - free (second_line); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl847_coarse_gain_calibration (Genesys_Device * dev, int dpi) -{ - int pixels; - int total_size; - uint8_t *line, reg04; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3],coeff; - int val, code, lines; - int resolution; - int bpp; - - DBG (DBG_proc, "gl847_coarse_gain_calibration: dpi = %d\n", dpi); - - /* no gain nor offset for AKM AFE */ - RIE (sanei_genesys_read_register (dev, REG04, ®04)); - if ((reg04 & REG04_FESET) == 0x02) - { - DBGCOMPLETED; - return status; - } - - /* coarse gain calibration is always done in color mode */ - channels = 3; - - /* follow CKSEL */ - if(dev->settings.xressensor.optical_res) - { - coeff=0.9; - /*resolution=dev->sensor.optical_res/2; */ - resolution=dev->sensor.optical_res; - } - else - { - resolution=dev->sensor.optical_res; - coeff=1.0; - } - lines=10; - bpp=8; - pixels = (dev->sensor.sensor_pixels * resolution) / dev->sensor.optical_res; - - status = gl847_init_scan_regs (dev, - dev->calib_reg, - resolution, - resolution, - 0, - 0, - pixels, - lines, - bpp, - channels, - dev->settings.color_filter, - SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE); - gl847_set_motor_power (dev->calib_reg, SANE_FALSE); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "gl847_coarse_calibration: failed to setup scan: %s\n", - sane_strstatus (status)); - return status; - } - - RIE (dev->model->cmd_set->bulk_write_register - (dev, dev->calib_reg, GENESYS_GL847_MAX_REGS)); - - total_size = pixels * channels * (16/bpp) * lines; - - line = malloc (total_size); - if (!line) - return SANE_STATUS_NO_MEM; - - RIEF (gl847_set_fe(dev, AFE_SET), line); - RIEF (gl847_begin_scan (dev, dev->calib_reg, SANE_TRUE), line); - RIEF (sanei_genesys_read_data_from_scanner (dev, line, total_size), line); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file ("coarse.pnm", line, bpp, channels, pixels, lines); - - /* average value on each channel */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = pixels/4; i < (pixels*3/4); i++) - { - if(bpp==16) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * pixels + 1] * 256 + - line[i * 2 + j * 2 * pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - } - else - { - if (dev->model->is_cis) - val = line[i + j * pixels]; - else - val = line[i * channels + j]; - } - - max[j] += val; - } - max[j] = max[j] / (pixels/2); - - gain[j] = ((float) dev->sensor.gain_white_ref*coeff) / max[j]; - - /* turn logical gain value into gain code, checking for overflow */ - code = 283 - 208 / gain[j]; - if (code > 255) - code = 255; - else if (code < 0) - code = 0; - dev->frontend.gain[j] = code; - - DBG (DBG_proc, - "gl847_coarse_gain_calibration: channel %d, max=%d, gain = %f, setting:%d\n", - j, max[j], gain[j], dev->frontend.gain[j]); - } - - if (dev->model->is_cis) - { - if (dev->frontend.gain[0] > dev->frontend.gain[1]) - dev->frontend.gain[0] = dev->frontend.gain[1]; - if (dev->frontend.gain[0] > dev->frontend.gain[2]) - dev->frontend.gain[0] = dev->frontend.gain[2]; - dev->frontend.gain[2] = dev->frontend.gain[1] = dev->frontend.gain[0]; - } - - if (channels == 1) - { - dev->frontend.gain[0] = dev->frontend.gain[1]; - dev->frontend.gain[2] = dev->frontend.gain[1]; - } - - free (line); - - RIE (gl847_stop_action (dev)); - - status=gl847_slow_back_home (dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - - -/** the gl847 command set */ -static Genesys_Command_Set gl847_cmd_set = { - "gl847-generic", /* the name of this set */ - - gl847_init, - NULL, /*gl847_init_regs_for_warmup*/ - gl847_init_regs_for_coarse_calibration, - gl847_init_regs_for_shading, - gl847_init_regs_for_scan, - - gl847_get_filter_bit, - gl847_get_lineart_bit, - gl847_get_bitset_bit, - gl847_get_gain4_bit, - gl847_get_fast_feed_bit, - gl847_test_buffer_empty_bit, - gl847_test_motor_flag_bit, - - gl847_bulk_full_size, - - gl847_set_fe, - gl847_set_powersaving, - gl847_save_power, - - gl847_set_motor_power, - gl847_set_lamp_power, - - gl847_begin_scan, - gl847_end_scan, - - sanei_genesys_send_gamma_table, - - gl847_search_start_position, - - gl847_offset_calibration, - gl847_coarse_gain_calibration, - gl847_led_calibration, - - gl847_slow_back_home, - gl847_rewind, - - sanei_genesys_bulk_write_register, - NULL, - gl847_bulk_read_data, - - gl847_update_hardware_sensors, - - NULL, /* no known gl847 sheetfed scanner */ - NULL, /* no known gl847 sheetfed scanner */ - NULL, /* no known gl847 sheetfed scanner */ - gl847_search_strip, - - sanei_genesys_is_compatible_calibration, - NULL, - gl847_send_shading_data, - gl847_calculate_current_setup, - gl847_boot, - NULL -}; - -SANE_Status -sanei_gl847_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl847_cmd_set; - return SANE_STATUS_GOOD; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_gl847.cc b/backend/genesys_gl847.cc new file mode 100644 index 0000000..b5748a5 --- /dev/null +++ b/backend/genesys_gl847.cc @@ -0,0 +1,3517 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_gl847.h" + +#include + +/**************************************************************************** + Mid level functions + ****************************************************************************/ + +static SANE_Bool +gl847_get_fast_feed_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG02); + if (r && (r->value & REG02_FASTFED)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl847_get_filter_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_FILTER)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl847_get_lineart_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_LINEART)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl847_get_bitset_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, REG04); + if (r && (r->value & REG04_BITSET)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl847_get_gain4_bit (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + + r = sanei_genesys_get_address (regs, 0x06); + if (r && (r->value & REG06_GAIN4)) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl847_test_buffer_empty_bit (SANE_Byte val) +{ + if (val & REG41_BUFEMPTY) + return SANE_TRUE; + return SANE_FALSE; +} + +static SANE_Bool +gl847_test_motor_flag_bit (SANE_Byte val) +{ + if (val & REG41_MOTORENB) + return SANE_TRUE; + return SANE_FALSE; +} + +/** + * compute the step multiplier used + */ +static int +gl847_get_step_multiplier (Genesys_Register_Set * regs) +{ + GenesysRegister *r = NULL; + int value = 1; + + r = sanei_genesys_get_address (regs, 0x9d); + if (r != NULL) + { + value = (r->value & 0x0f)>>1; + value = 1 << value; + } + DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); + return value; +} + +/** @brief sensor profile + * search for the database of motor profiles and get the best one. Each + * profile is at a specific dpihw. Use LiDE 110 table by default. + * @param sensor_type sensor id + * @param dpi hardware dpi for the scan + * @return a pointer to a Sensor_Profile struct + */ +static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi) +{ + unsigned int i; + int idx; + + i=0; + idx=-1; + while(i=dpi + && sensors[i].dpimodel->ccd_type, xres); + return sensor_profile->exposure; +} + + +/** @brief sensor specific settings +*/ +static void gl847_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * regs, int dpi) +{ + GenesysRegister *r; + int dpihw; + uint16_t exp; + + DBGSTART; + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpi); + + for (uint16_t addr = 0x16; addr < 0x1e; addr++) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + for (uint16_t addr = 0x52; addr < 0x52 + 9; addr++) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + /* set EXPDUMMY and CKxMAP */ + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpi); + Sensor_Profile* sensor_profile=get_sensor_profile(dev->model->ccd_type, dpihw); + + sanei_genesys_set_reg_from_set(regs,REG_EXPDMY,(uint8_t)((sensor_profile->expdummy) & 0xff)); + + /* if no calibration has been done, set default values for exposures */ + exp = sensor.exposure.red; + if(exp==0) + { + exp=sensor_profile->expr; + } + sanei_genesys_set_double(regs,REG_EXPR,exp); + + exp = sensor.exposure.green; + if(exp==0) + { + exp=sensor_profile->expg; + } + sanei_genesys_set_double(regs,REG_EXPG,exp); + + exp = sensor.exposure.blue; + if(exp==0) + { + exp=sensor_profile->expb; + } + sanei_genesys_set_double(regs,REG_EXPB,exp); + + sanei_genesys_set_triple(regs,REG_CK1MAP,sensor_profile->ck1map); + sanei_genesys_set_triple(regs,REG_CK3MAP,sensor_profile->ck3map); + sanei_genesys_set_triple(regs,REG_CK4MAP,sensor_profile->ck4map); + + /* order of the sub-segments */ + dev->order=sensor_profile->order; + + r = sanei_genesys_get_address (regs, 0x17); + r->value = sensor_profile->r17; + + DBGCOMPLETED; +} + + +/** @brief set all registers to default values . + * This function is called only once at the beginning and + * fills register startup values for registers reused across scans. + * Those that are rarely modified or not modified are written + * individually. + * @param dev device structure holding register set to initialize + */ +static void +gl847_init_registers (Genesys_Device * dev) +{ + int lide700=0; + uint8_t val; + + DBGSTART; + /* 700F class needs some different initial settings */ + if (dev->model->model_id == MODEL_CANON_LIDE_700F) + { + lide700 = 1; + } + + dev->reg.clear(); + + SETREG (0x01, 0x82); + SETREG (0x02, 0x18); + SETREG (0x03, 0x50); + SETREG (0x04, 0x12); + SETREG (0x05, 0x80); + SETREG (0x06, 0x50); /* FASTMODE + POWERBIT */ + SETREG (0x08, 0x10); + SETREG (0x09, 0x01); + SETREG (0x0a, 0x00); + SETREG (0x0b, 0x01); + SETREG (0x0c, 0x02); + + /* LED exposures */ + SETREG (0x10, 0x00); + SETREG (0x11, 0x00); + SETREG (0x12, 0x00); + SETREG (0x13, 0x00); + SETREG (0x14, 0x00); + SETREG (0x15, 0x00); + + SETREG (0x16, 0x10); + SETREG (0x17, 0x08); + SETREG (0x18, 0x00); + + /* EXPDMY */ + SETREG (0x19, 0x50); + + SETREG (0x1a, 0x34); + SETREG (0x1b, 0x00); + SETREG (0x1c, 0x02); + SETREG (0x1d, 0x04); + SETREG (0x1e, 0x10); + SETREG (0x1f, 0x04); + SETREG (0x20, 0x02); + SETREG (0x21, 0x10); + SETREG (0x22, 0x7f); + SETREG (0x23, 0x7f); + SETREG (0x24, 0x10); + SETREG (0x25, 0x00); + SETREG (0x26, 0x00); + SETREG (0x27, 0x00); + SETREG (0x2c, 0x09); + SETREG (0x2d, 0x60); + SETREG (0x2e, 0x80); + SETREG (0x2f, 0x80); + SETREG (0x30, 0x00); + SETREG (0x31, 0x10); + SETREG (0x32, 0x15); + SETREG (0x33, 0x0e); + SETREG (0x34, 0x40); + SETREG (0x35, 0x00); + SETREG (0x36, 0x2a); + SETREG (0x37, 0x30); + SETREG (0x38, 0x2a); + SETREG (0x39, 0xf8); + SETREG (0x3d, 0x00); + SETREG (0x3e, 0x00); + SETREG (0x3f, 0x00); + SETREG (0x52, 0x03); + SETREG (0x53, 0x07); + SETREG (0x54, 0x00); + SETREG (0x55, 0x00); + SETREG (0x56, 0x00); + SETREG (0x57, 0x00); + SETREG (0x58, 0x2a); + SETREG (0x59, 0xe1); + SETREG (0x5a, 0x55); + SETREG (0x5e, 0x41); + SETREG (0x5f, 0x40); + SETREG (0x60, 0x00); + SETREG (0x61, 0x21); + SETREG (0x62, 0x40); + SETREG (0x63, 0x00); + SETREG (0x64, 0x21); + SETREG (0x65, 0x40); + SETREG (0x67, 0x80); + SETREG (0x68, 0x80); + SETREG (0x69, 0x20); + SETREG (0x6a, 0x20); + + /* CK1MAP */ + SETREG (0x74, 0x00); + SETREG (0x75, 0x00); + SETREG (0x76, 0x3c); + + /* CK3MAP */ + SETREG (0x77, 0x00); + SETREG (0x78, 0x00); + SETREG (0x79, 0x9f); + + /* CK4MAP */ + SETREG (0x7a, 0x00); + SETREG (0x7b, 0x00); + SETREG (0x7c, 0x55); + + SETREG (0x7d, 0x00); + + /* NOTE: autoconf is a non working option */ + SETREG (0x87, 0x02); + SETREG (0x9d, 0x06); + SETREG (0xa2, 0x0f); + SETREG (0xbd, 0x18); + SETREG (0xfe, 0x08); + + /* gamma[0] and gamma[256] values */ + SETREG (0xbe, 0x00); + SETREG (0xc5, 0x00); + SETREG (0xc6, 0x00); + SETREG (0xc7, 0x00); + SETREG (0xc8, 0x00); + SETREG (0xc9, 0x00); + SETREG (0xca, 0x00); + + /* LiDE 700 fixups */ + if(lide700) + { + SETREG (0x5f, 0x04); + SETREG (0x7d, 0x80); + + /* we write to these registers only once */ + val=0; + sanei_genesys_write_register (dev, REG7E, val); + sanei_genesys_write_register (dev, REG9E, val); + sanei_genesys_write_register (dev, REG9F, val); + sanei_genesys_write_register (dev, REGAB, val); + } + + /* fine tune upon device description */ + dev->reg.find_reg(0x05).value &= ~REG05_DPIHW; + switch (sanei_genesys_find_sensor_any(dev).optical_res) + { + case 600: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; + break; + case 1200: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; + break; + case 2400: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; + break; + case 4800: + dev->reg.find_reg(0x05).value |= REG05_DPIHW_4800; + break; + } + + /* initalize calibration reg */ + dev->calib_reg = dev->reg; + + DBGCOMPLETED; +} + +/**@brief send slope table for motor movement + * Send slope_table in machine byte order + * @param dev device to send slope table + * @param table_nr index of the slope table in ASIC memory + * Must be in the [0-4] range. + * @param slope_table pointer to 16 bit values array of the slope table + * @param steps number of elements in the slope table + */ +static SANE_Status +gl847_send_slope_table (Genesys_Device * dev, int table_nr, + uint16_t * slope_table, int steps) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + char msg[10000]; + + DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, + table_nr, steps); + + /* sanity check */ + if(table_nr<0 || table_nr>4) + { + DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); + return SANE_STATUS_INVAL; + } + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + sprintf (msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) + { + sprintf (msg+strlen(msg), "%d", slope_table[i]); + } + DBG (DBG_io, "%s: %s\n", __func__, msg); + } + + /* slope table addresses are fixed */ + status = sanei_genesys_write_ahb(dev, 0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: write to AHB failed writing slope table %d (%s)\n", __func__, table_nr, + sane_strstatus(status)); + } + + DBGCOMPLETED; + return status; +} + +/** + * Set register values of Analog Device type frontend + * */ +static SANE_Status +gl847_set_ad_fe (Genesys_Device * dev, uint8_t set) +{ + SANE_Status status = SANE_STATUS_GOOD; + int i; + uint8_t val8; + + DBGSTART; + + /* wait for FE to be ready */ + status = sanei_genesys_get_status (dev, &val8); + while (val8 & REG41_FEBUSY) + { + sanei_genesys_sleep_ms(10); + status = sanei_genesys_get_status (dev, &val8); + }; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); + + dev->frontend = dev->frontend_initial; + } + + /* reset DAC */ + status = sanei_genesys_fe_write_data (dev, 0x00, 0x80); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* write them to analog frontend */ + status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status)); + return status; + } + status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write reg1: %s\n", __func__, sane_strstatus(status)); + return status; + } + + for (i = 0; i < 3; i++) + { + status = sanei_genesys_fe_write_data(dev, 0x02 + i, dev->frontend.get_gain(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write gain %d: %s\n", __func__, i, sane_strstatus(status)); + return status; + } + } + for (i = 0; i < 3; i++) + { + status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.get_offset(i)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write offset %d: %s\n", __func__, i, + sane_strstatus(status)); + return status; + } + } + + DBGCOMPLETED; + return status; +} + +static SANE_Status +gl847_homsnr_gpio(Genesys_Device *dev) +{ +uint8_t val; +SANE_Status status=SANE_STATUS_GOOD; + + if (dev->model->gpo_type == GPO_CANONLIDE700) + { + RIE (sanei_genesys_read_register (dev, REG6C, &val)); + val &= ~REG6C_GPIO10; + RIE (sanei_genesys_write_register (dev, REG6C, val)); + } + else + { + RIE (sanei_genesys_read_register (dev, REG6C, &val)); + val |= REG6C_GPIO10; + RIE (sanei_genesys_write_register (dev, REG6C, val)); + } + return status; +} + +/* Set values of analog frontend */ +static SANE_Status +gl847_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) +{ + (void) sensor; + + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + DBG(DBG_proc, "%s (%s)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == + AFE_POWER_SAVE ? "powersave" : "huh?"); + + RIE (sanei_genesys_read_register (dev, REG04, &val)); + + /* route to AD devices */ + if ((val & REG04_FESET) == 0x02) + { + return gl847_set_ad_fe (dev, set); + } + + /* for now there is no support yet for wolfson fe */ + DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, + dev->reg.find_reg(0x04).value & REG04_FESET); + + DBGCOMPLETED; + return SANE_STATUS_UNSUPPORTED; +} + + +/** @brief set up motor related register for scan + */ +static SANE_Status +gl847_init_motor_regs_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int scan_exposure_time, + float scan_yres, + int scan_step_type, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + int scan_power_mode, + unsigned int flags) +{ + SANE_Status status = SANE_STATUS_GOOD; + int use_fast_fed; + unsigned int fast_dpi; + uint16_t scan_table[SLOPE_TABLE_SIZE]; + uint16_t fast_table[SLOPE_TABLE_SIZE]; + int scan_steps, fast_steps, factor; + unsigned int feedl, dist; + GenesysRegister *r; + uint32_t z1, z2; + unsigned int min_restep = 0x20; + uint8_t val, effective; + int fast_step_type; + unsigned int ccdlmt,tgtime; + + DBGSTART; + DBG(DBG_proc, "%s : scan_exposure_time=%d, can_yres=%g, scan_step_type=%d, scan_lines=%d, " + "scan_dummy=%d, feed_steps=%d, scan_power_mode=%d, flags=%x\n", __func__, scan_exposure_time, + scan_yres, scan_step_type, scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); + + /* get step multiplier */ + factor = gl847_get_step_multiplier (reg); + + use_fast_fed=0; + /* no fast fed since feed works well */ + if(dev->settings.yres==4444 && feed_steps>100 + && ((flags & MOTOR_FLAG_FEED)==0)) + { + use_fast_fed=1; + } + DBG(DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); + + sanei_genesys_set_triple(reg, REG_LINCNT, scan_lines); + DBG(DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); + + /* compute register 02 value */ + r = sanei_genesys_get_address (reg, REG02); + r->value = 0x00; + sanei_genesys_set_motor_power(*reg, true); + + if (use_fast_fed) + r->value |= REG02_FASTFED; + else + r->value &= ~REG02_FASTFED; + + if (flags & MOTOR_FLAG_AUTO_GO_HOME) + r->value |= REG02_AGOHOME | REG02_NOTHOME; + + if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) + ||(scan_yres>=sensor.optical_res)) + { + r->value |= REG02_ACDCDIS; + } + + /* scan and backtracking slope table */ + sanei_genesys_slope_table(scan_table, + &scan_steps, + scan_yres, + scan_exposure_time, + dev->motor.base_ydpi, + scan_step_type, + factor, + dev->model->motor_type, + gl847_motors); + RIE(gl847_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); + RIE(gl847_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); + + /* fast table */ + fast_dpi=sanei_genesys_get_lowest_ydpi(dev); + fast_step_type=scan_step_type; + if(scan_step_type>=2) + { + fast_step_type=2; + } + + sanei_genesys_slope_table(fast_table, + &fast_steps, + fast_dpi, + scan_exposure_time, + dev->motor.base_ydpi, + fast_step_type, + factor, + dev->model->motor_type, + gl847_motors); + + /* manual override of high start value */ + fast_table[0]=fast_table[1]; + + RIE(gl847_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); + RIE(gl847_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); + RIE(gl847_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); + + /* correct move distance by acceleration and deceleration amounts */ + feedl=feed_steps; + if (use_fast_fed) + { + feedl<<=fast_step_type; + dist=(scan_steps+2*fast_steps)*factor; + /* TODO read and decode REGAB */ + r = sanei_genesys_get_address (reg, 0x5e); + dist += (r->value & 31); + /* FEDCNT */ + r = sanei_genesys_get_address (reg, REG_FEDCNT); + dist += r->value; + } + else + { + feedl<<=scan_step_type; + dist=scan_steps*factor; + if (flags & MOTOR_FLAG_FEED) + dist *=2; + } + DBG(DBG_io2, "%s: scan steps=%d\n", __func__, scan_steps); + DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + /* check for overflow */ + if(distvalue & REG0C_CCDLMT)+1; + + r = sanei_genesys_get_address (reg, REG1C); + tgtime=1<<(r->value & REG1C_TGTIME); + + /* hi res motor speed GPIO */ + RIE (sanei_genesys_read_register (dev, REG6C, &effective)); + + /* if quarter step, bipolar Vref2 */ + if (scan_step_type > 1) + { + if (scan_step_type < 3) + { + val = effective & ~REG6C_GPIO13; + } + else + { + val = effective | REG6C_GPIO13; + } + } + else + { + val = effective; + } + RIE (sanei_genesys_write_register (dev, REG6C, val)); + + /* effective scan */ + RIE (sanei_genesys_read_register (dev, REG6C, &effective)); + val = effective | REG6C_GPIO10; + RIE (sanei_genesys_write_register (dev, REG6C, val)); + + min_restep=scan_steps/2-1; + if (min_restep < 1) + min_restep = 1; + r = sanei_genesys_get_address (reg, REG_FWDSTEP); + r->value = min_restep; + r = sanei_genesys_get_address (reg, REG_BWDSTEP); + r->value = min_restep; + + sanei_genesys_calculate_zmode2(use_fast_fed, + scan_exposure_time*ccdlmt*tgtime, + scan_table, + scan_steps*factor, + feedl, + min_restep*factor, + &z1, + &z2); + + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + sanei_genesys_set_triple(reg, REG60, z1 | (scan_step_type << (16+REG60S_STEPSEL))); + + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + sanei_genesys_set_triple(reg, REG63, z2 | (scan_step_type << (16+REG63S_FSTPSEL))); + + r = sanei_genesys_get_address (reg, 0x1e); + r->value &= 0xf0; /* 0 dummy lines */ + r->value |= scan_dummy; /* dummy lines */ + + r = sanei_genesys_get_address (reg, REG67); + r->value = REG67_MTRPWM; + + r = sanei_genesys_get_address (reg, REG68); + r->value = REG68_FASTPWM; + + r = sanei_genesys_get_address (reg, REG_STEPNO); + r->value = scan_steps; + + r = sanei_genesys_get_address (reg, REG_FASTNO); + r->value = scan_steps; + + r = sanei_genesys_get_address (reg, REG_FSHDEC); + r->value = scan_steps; + + r = sanei_genesys_get_address (reg, REG_FMOVNO); + r->value = fast_steps; + + r = sanei_genesys_get_address (reg, REG_FMOVDEC); + r->value = fast_steps; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** @brief set up registers related to sensor + * Set up the following registers + 0x01 + 0x03 + 0x10-0x015 R/G/B exposures + 0x19 EXPDMY + 0x2e BWHI + 0x2f BWLO + 0x04 + 0x87 + 0x05 + 0x2c,0x2d DPISET + 0x30,0x31 STRPIXEL + 0x32,0x33 ENDPIXEL + 0x35,0x36,0x37 MAXWD [25:2] (>>2) + 0x38,0x39 LPERIOD + 0x34 DUMMY + */ +static SANE_Status +gl847_init_optical_regs_scan (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, + unsigned int exposure_time, + int used_res, + unsigned int start, + unsigned int pixels, + int channels, + int depth, + SANE_Bool half_ccd, ColorFilter color_filter, int flags) +{ + unsigned int words_per_line; + unsigned int startx, endx, used_pixels; + unsigned int dpiset, dpihw,segnb,cksel,factor; + unsigned int bytes; + GenesysRegister *r; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s : exposure_time=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " + "half_ccd=%d, flags=%x\n", __func__, exposure_time, used_res, start, pixels, channels, depth, + half_ccd, flags); + + /* resolution is divided according to CKSEL */ + r = sanei_genesys_get_address (reg, REG18); + cksel= (r->value & REG18_CKSEL)+1; + DBG(DBG_io2, "%s: cksel=%d\n", __func__, cksel); + + /* to manage high resolution device while keeping good + * low resolution scanning speed, we make hardware dpi vary */ + dpihw=sanei_genesys_compute_dpihw(dev, sensor, used_res * cksel); + factor=sensor.optical_res/dpihw; + DBG(DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); + + /* sensor parameters */ + Sensor_Profile* sensor_profile=get_sensor_profile(dev->model->ccd_type, dpihw); + gl847_setup_sensor(dev, sensor, reg, dpihw); + dpiset = used_res * cksel; + + /* start and end coordinate in optical dpi coordinates */ + startx = start/cksel+sensor.CCD_start_xoffset; + used_pixels=pixels/cksel; + + /* end of sensor window */ + endx = startx + used_pixels; + + /* sensors are built from 600 dpi segments for LiDE 100/200 + * and 1200 dpi for the 700F */ + if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR) + { + segnb=dpihw/600; + } + else + { + segnb=1; + } + + /* compute pixel coordinate in the given dpihw space, + * taking segments into account */ + startx/=factor*segnb; + endx/=factor*segnb; + dev->len=endx-startx; + dev->dist=0; + dev->skip=0; + + /* in cas of multi-segments sensor, we have to add the witdh + * of the sensor crossed by the scan area */ + if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR && segnb>1) + { + dev->dist = sensor_profile->segcnt; + } + + /* use a segcnt rounded to next even number */ + endx += ((dev->dist+1)&0xfffe)*(segnb-1); + used_pixels=endx-startx; + + status = gl847_set_fe(dev, sensor, AFE_SET); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* enable shading */ + r = sanei_genesys_get_address (reg, REG01); + r->value &= ~REG01_SCAN; + r->value |= REG01_SHDAREA; + if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + r->value &= ~REG01_DVDSET; + } + else + { + r->value |= REG01_DVDSET; + } + + r = sanei_genesys_get_address (reg, REG03); + r->value &= ~REG03_AVEENB; + + sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); + + /* BW threshold */ + r = sanei_genesys_get_address (reg, 0x2e); + r->value = dev->settings.threshold; + r = sanei_genesys_get_address (reg, 0x2f); + r->value = dev->settings.threshold; + + /* monochrome / color scan */ + r = sanei_genesys_get_address (reg, REG04); + switch (depth) + { + case 1: + r->value &= ~REG04_BITSET; + r->value |= REG04_LINEART; + break; + case 8: + r->value &= ~(REG04_LINEART | REG04_BITSET); + break; + case 16: + r->value &= ~REG04_LINEART; + r->value |= REG04_BITSET; + break; + } + + r->value &= ~(REG04_FILTER | REG04_AFEMOD); + if (channels == 1) + { + switch (color_filter) + { + + case ColorFilter::RED: + r->value |= 0x14; + break; + case ColorFilter::BLUE: + r->value |= 0x1c; + break; + case ColorFilter::GREEN: + r->value |= 0x18; + break; + default: + break; // should not happen + } + } + else + r->value |= 0x10; /* mono */ + + /* register 05 */ + r = sanei_genesys_get_address (reg, REG05); + + /* set up dpihw */ + r->value &= ~REG05_DPIHW; + switch(dpihw) + { + case 600: + r->value |= REG05_DPIHW_600; + break; + case 1200: + r->value |= REG05_DPIHW_1200; + break; + case 2400: + r->value |= REG05_DPIHW_2400; + break; + case 4800: + r->value |= REG05_DPIHW_4800; + break; + } + + /* enable gamma tables */ + if (flags & OPTICAL_FLAG_DISABLE_GAMMA) + r->value &= ~REG05_GMMENB; + else + r->value |= REG05_GMMENB; + + /* CIS scanners can do true gray by setting LEDADD */ + /* we set up LEDADD only when asked */ + if (dev->model->is_cis == SANE_TRUE) + { + r = sanei_genesys_get_address (reg, 0x87); + r->value &= ~REG87_LEDADD; + if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) + { + r->value |= REG87_LEDADD; + } + /* RGB weighting + r = sanei_genesys_get_address (reg, 0x01); + r->value &= ~REG01_TRUEGRAY; + if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) + { + r->value |= REG01_TRUEGRAY; + }*/ + } + + /* words(16bit) before gamma, conversion to 8 bit or lineart*/ + words_per_line = (used_pixels * dpiset) / dpihw; + bytes=depth/8; + if (depth == 1) + { + words_per_line = (words_per_line+7)/8 ; + dev->len = (dev->len >> 3) + ((dev->len & 7) ? 1 : 0); + dev->dist = (dev->dist >> 3) + ((dev->dist & 7) ? 1 : 0); + } + else + { + words_per_line *= bytes; + dev->dist *= bytes; + dev->len *= bytes; + } + + dev->bpl = words_per_line; + dev->cur=0; + dev->segnb=segnb; + dev->line_interp = 0; + + sanei_genesys_set_double(reg,REG_DPISET,dpiset); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); + + sanei_genesys_set_double(reg,REG_STRPIXEL,startx); + sanei_genesys_set_double(reg,REG_ENDPIXEL,endx); + DBG (DBG_io2, "%s: startx=%d\n", __func__, startx); + DBG (DBG_io2, "%s: endx =%d\n", __func__, endx); + + DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); + DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); + DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); + DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); + DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); + DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); + DBG (DBG_io2, "%s: dev->segnb =%lu\n", __func__, (unsigned long)dev->segnb); + + words_per_line *= channels; + dev->wpl = words_per_line; + + dev->oe_buffer.clear(); + dev->oe_buffer.alloc(dev->wpl); + + /* MAXWD is expressed in 4 words unit */ + sanei_genesys_set_triple(reg, REG_MAXWD, (words_per_line >> 2)); + DBG(DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); + + sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); + DBG(DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); + + r = sanei_genesys_get_address (reg, 0x34); + r->value = sensor.dummy_pixel; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* set up registers for an actual scan + * + * this function sets up the scanner to scan in normal or single line mode + */ +static SANE_Status +gl847_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SetupParams& params) + +{ + params.assert_valid(); + + int used_res; + int start, used_pixels; + int bytes_per_line; + int move; + unsigned int lincnt; + unsigned int oflags; /**> optical flags */ + unsigned int mflags; /**> motor flags */ + int exposure_time; + int stagger; + + int slope_dpi = 0; + int dummy = 0; + int scan_step_type = 1; + int scan_power_mode = 0; + int max_shift; + size_t requested_buffer_size, read_buffer_size; + + SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ + int optical_res; + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + + /* we may have 2 domains for ccd: xres below or above half ccd max dpi */ + if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) + { + half_ccd = SANE_TRUE; + } + else + { + half_ccd = SANE_FALSE; + } + + /* optical_res */ + optical_res = sensor.optical_res; + if (half_ccd) + optical_res /= 2; + + /* stagger */ + if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG(DBG_info, "%s : stagger=%d lines\n", __func__, stagger); + + /* used_res */ + if (params.flags & SCAN_FLAG_USE_OPTICAL_RES) + { + used_res = optical_res; + } + else + { + /* resolution is choosen from a list */ + used_res = params.xres; + } + + /* compute scan parameters values */ + /* pixels are allways given at full optical resolution */ + /* use detected left margin and fixed value */ + /* start */ + /* add x coordinates */ + start = params.startx; + + if (stagger > 0) + start |= 1; + + /* compute correct pixels number */ + /* pixels */ + used_pixels = (params.pixels * optical_res) / params.xres; + + /* round up pixels number if needed */ + if (used_pixels * params.xres < params.pixels * optical_res) + used_pixels++; + + dummy = 3-params.channels; + +/* slope_dpi */ +/* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) + slope_dpi = params.yres * params.channels; + else + slope_dpi = params.yres; + + slope_dpi = slope_dpi * (1 + dummy); + + exposure_time = gl847_compute_exposure (dev, used_res); + scan_step_type = sanei_genesys_compute_step_type(gl847_motors, dev->model->motor_type, exposure_time); + + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); + +/*** optical parameters ***/ + /* in case of dynamic lineart, we use an internal 8 bit gray scan + * to generate 1 lineart data */ + if (params.flags & SCAN_FLAG_DYNAMIC_LINEART) { + params.depth = 8; + } + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + oflags = 0; + if(params.flags & SCAN_FLAG_DISABLE_SHADING) + oflags |= OPTICAL_FLAG_DISABLE_SHADING; + if(params.flags & SCAN_FLAG_DISABLE_GAMMA) + oflags |= OPTICAL_FLAG_DISABLE_GAMMA; + if(params.flags & SCAN_FLAG_DISABLE_LAMP) + oflags |= OPTICAL_FLAG_DISABLE_LAMP; + + if (dev->model->is_cis && dev->settings.true_gray) + { + oflags |= OPTICAL_FLAG_ENABLE_LEDADD; + } + + status = gl847_init_optical_regs_scan (dev, sensor, + reg, + exposure_time, + used_res, + start, + used_pixels, + params.channels, + params.depth, + half_ccd, + params.color_filter, + oflags); + + if (status != SANE_STATUS_GOOD) + return status; + +/*** motor parameters ***/ + + /* max_shift */ + max_shift=sanei_genesys_compute_max_shift(dev,params.channels,params.yres,params.flags); + + /* lincnt */ + lincnt = params.lines + max_shift + stagger; + + /* add tl_y to base movement */ + move = params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + mflags=0; + if(params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) + mflags |= MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; + if(params.flags & SCAN_FLAG_FEEDING) + mflags |= MOTOR_FLAG_FEED; + + status = gl847_init_motor_regs_scan (dev, sensor, + reg, + exposure_time, + slope_dpi, + scan_step_type, + dev->model->is_cis ? lincnt * + params.channels : lincnt, dummy, move, + scan_power_mode, + mflags); + + if (status != SANE_STATUS_GOOD) + return status; + + + /*** prepares data reordering ***/ + +/* words_per_line */ + bytes_per_line = (used_pixels * used_res) / optical_res; + bytes_per_line = (bytes_per_line * params.channels * params.depth) / 8; + + requested_buffer_size = 8 * bytes_per_line; + + read_buffer_size = + 2 * requested_buffer_size + + ((max_shift + stagger) * used_pixels * params.channels * params.depth) / 8; + + dev->read_buffer.clear(); + dev->read_buffer.alloc(read_buffer_size); + + dev->lines_buffer.clear(); + dev->lines_buffer.alloc(read_buffer_size); + + dev->shrink_buffer.clear(); + dev->shrink_buffer.alloc(requested_buffer_size); + + dev->out_buffer.clear(); + dev->out_buffer.alloc((8 * params.pixels * params.channels * params.depth) / 8); + + dev->read_bytes_left = bytes_per_line * lincnt; + + DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); + dev->read_active = SANE_TRUE; + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res) / optical_res; + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure_time; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + +/* TODO: should this be done elsewhere? */ + /* scan bytes to send to the frontend */ + /* theory : + target_size = + (params.pixels * params.lines * channels * depth) / 8; + but it suffers from integer overflow so we do the following: + + 1 bit color images store color data byte-wise, eg byte 0 contains + 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains + 8 bits of blue. + This does not fix the overflow, though. + 644mp*16 = 10gp, leading to an overflow + -- pierre + */ + + dev->total_bytes_read = 0; + if (params.depth == 1) + dev->total_bytes_to_read = + ((params.pixels * params.lines) / 8 + + (((params.pixels * params.lines) % 8) ? 1 : 0)) * + params.channels; + else + dev->total_bytes_to_read = + params.pixels * params.lines * params.channels * (params.depth / 8); + + DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); +/* END TODO */ + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static void +gl847_calculate_current_setup(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int depth; + int start; + + int used_res; + int used_pixels; + unsigned int lincnt; + int exposure_time; + int stagger; + + int slope_dpi = 0; + int dummy = 0; + int max_shift; + + SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ + int optical_res; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + /* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + /* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + /* start */ + start = SANE_UNFIX (dev->model->x_offset); + start += dev->settings.tl_x; + start = (start * sensor.optical_res) / MM_PER_INCH; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; // not used + params.starty = 0; // not used + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = 0; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, params); + +/* half_ccd */ + /* we have 2 domains for ccd: xres below or above half ccd max dpi */ + if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) { + half_ccd = SANE_TRUE; + } else { + half_ccd = SANE_FALSE; + } + + /* optical_res */ + optical_res = sensor.optical_res; + + /* stagger */ + if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) + stagger = (4 * params.yres) / dev->motor.base_ydpi; + else + stagger = 0; + DBG(DBG_info, "%s: stagger=%d lines\n", __func__, stagger); + + /* resolution is choosen from a fixed list */ + used_res = params.xres; + + /* compute scan parameters values */ + /* pixels are allways given at half or full CCD optical resolution */ + /* use detected left margin and fixed value */ + + /* compute correct pixels number */ + used_pixels = (params.pixels * optical_res) / used_res; + dummy = 3 - params.channels; + + /* slope_dpi */ + /* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) { + slope_dpi = params.yres * params.channels; + } else { + slope_dpi = params.yres; + } + + slope_dpi = slope_dpi * (1 + dummy); + + exposure_time = gl847_compute_exposure (dev, used_res); + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + + /* max_shift */ + max_shift = sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); + + /* lincnt */ + lincnt = params.lines + max_shift + stagger; + + dev->current_setup.params = params; + dev->current_setup.pixels = (used_pixels * used_res) / optical_res; + dev->current_setup.lines = lincnt; + dev->current_setup.depth = params.depth; + dev->current_setup.channels = params.channels; + dev->current_setup.exposure_time = exposure_time; + dev->current_setup.xres = used_res; + dev->current_setup.yres = params.yres; + dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; + dev->current_setup.stagger = stagger; + dev->current_setup.max_shift = max_shift + stagger; + + DBGCOMPLETED; +} + +/*for fast power saving methods only, like disabling certain amplifiers*/ +static SANE_Status +gl847_save_power (Genesys_Device * dev, SANE_Bool enable) +{ + DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); + if (dev == NULL) + return SANE_STATUS_INVAL; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl847_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) +{ + DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); + if (dev == NULL) + return SANE_STATUS_INVAL; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl847_start_action (Genesys_Device * dev) +{ + return sanei_genesys_write_register (dev, 0x0f, 0x01); +} + +static SANE_Status +gl847_stop_action (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val40, val; + unsigned int loop; + + DBGSTART; + + /* post scan gpio : without that HOMSNR is unreliable */ + gl847_homsnr_gpio(dev); + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + status = sanei_genesys_read_register (dev, REG40, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* only stop action if needed */ + if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) + { + DBG(DBG_info, "%s: already stopped\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + /* ends scan */ + val = dev->reg.get8(REG01); + val &= ~REG01_SCAN; + sanei_genesys_set_reg_from_set(&dev->reg, REG01, val); + status = sanei_genesys_write_register (dev, REG01, val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_sleep_ms(100); + + loop = 10; + while (loop > 0) + { + status = sanei_genesys_get_status (dev, &val); + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + status = sanei_genesys_read_register (dev, REG40, &val40); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* if scanner is in command mode, we are done */ + if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) + && !(val & REG41_MOTORENB)) + { + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + sanei_genesys_sleep_ms(100); + loop--; + } + + DBGCOMPLETED; + return SANE_STATUS_IO_ERROR; +} + +/* Send the low-level scan command */ +static SANE_Status +gl847_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, + SANE_Bool start_motor) +{ + (void) sensor; + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + GenesysRegister *r; + + DBGSTART; + + /* clear GPIO 10 */ + if (dev->model->gpo_type != GPO_CANONLIDE700) + { + RIE (sanei_genesys_read_register (dev, REG6C, &val)); + val &= ~REG6C_GPIO10; + RIE (sanei_genesys_write_register (dev, REG6C, val)); + } + + val = REG0D_CLRLNCNT; + RIE (sanei_genesys_write_register (dev, REG0D, val)); + val = REG0D_CLRMCNT; + RIE (sanei_genesys_write_register (dev, REG0D, val)); + + RIE (sanei_genesys_read_register (dev, REG01, &val)); + val |= REG01_SCAN; + RIE (sanei_genesys_write_register (dev, REG01, val)); + r = sanei_genesys_get_address (reg, REG01); + r->value = val; + + if (start_motor) + { + RIE (sanei_genesys_write_register (dev, REG0F, 1)); + } + else + { + RIE (sanei_genesys_write_register (dev, REG0F, 0)); + } + + DBGCOMPLETED; + + return status; +} + + +/* Send the stop scan command */ +static SANE_Status +gl847_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, + SANE_Bool check_stop) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); + if (reg == NULL) + return SANE_STATUS_INVAL; + + if (dev->model->is_sheetfed == SANE_TRUE) + { + status = SANE_STATUS_GOOD; + } + else /* flat bed scanners */ + { + status = gl847_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + } + + DBGCOMPLETED; + return status; +} + +/** rewind scan + * Move back by the same amount of distance than previous scan. + * @param dev device to rewind + * @returns SANE_STATUS_GOOD on success + */ +#if 0 /* disabled to fix #7 */ +static +SANE_Status gl847_rewind(Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t byte; + + DBGSTART; + + /* set motor reverse */ + RIE (sanei_genesys_read_register (dev, 0x02, &byte)); + byte |= 0x04; + RIE (sanei_genesys_write_register(dev, 0x02, byte)); + + /* and start scan, then wait completion */ + RIE (gl847_begin_scan (dev, dev->reg, SANE_TRUE)); + do + { + sanei_genesys_sleep_ms(100); + RIE (sanei_genesys_read_register (dev, REG40, &byte)); + } + while(byte & REG40_MOTMFLG); + RIE (gl847_end_scan (dev, dev->reg, SANE_TRUE)); + + /* restore direction */ + RIE (sanei_genesys_read_register (dev, 0x02, &byte)); + byte &= 0xfb; + RIE (sanei_genesys_write_register(dev, 0x02, byte)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} +#endif + +/** Park head + * Moves the slider to the home (top) position slowly + * @param dev device to park + * @param wait_until_home true to make the function waiting for head + * to be home before returning, if fals returne immediately + * @returns SANE_STATUS_GOO on success */ +static +SANE_Status +gl847_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + float resolution; + uint8_t val; + int loop = 0; + ScanColorMode scan_mode; + + DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); + + /* post scan gpio : without that HOMSNR is unreliable */ + gl847_homsnr_gpio(dev); + + /* first read gives HOME_SENSOR true */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + sanei_genesys_sleep_ms(100); + + /* second is reliable */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); + return status; + } + if (DBG_LEVEL >= DBG_io) + { + sanei_genesys_print_status (val); + } + + /* is sensor at home? */ + if (val & HOMESNR) + { + DBG(DBG_info, "%s: already at home, completed\n", __func__); + dev->scanhead_position_in_steps = 0; + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + + local_reg = dev->reg; + + resolution=sanei_genesys_get_lowest_ydpi(dev); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + /* TODO add scan_mode to the API */ + scan_mode = dev->settings.scan_mode; + dev->settings.scan_mode = ScanColorMode::LINEART; + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 100; + params.starty = 30000; + params.pixels = 100; + params.lines = 100; + params.depth = 8; + params.channels = 1; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::RED; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl847_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + dev->settings.scan_mode = scan_mode; + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); + + /* set up for reverse */ + r = sanei_genesys_get_address (&local_reg, REG02); + r->value |= REG02_MTRREV; + + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + + try { + status = gl847_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl847_stop_action(dev); + } catch (...) {} + try { + // restore original registers + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl847_stop_action (dev); + /* send original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + /* post scan gpio : without that HOMSNR is unreliable */ + gl847_homsnr_gpio(dev); + + if (wait_until_home) + { + while (loop < 300) /* do not wait longer then 30 seconds */ + { + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + if (val & HOMESNR) /* home sensor */ + { + DBG(DBG_info, "%s: reached home position\n", __func__); + gl847_stop_action (dev); + dev->scanhead_position_in_steps = 0; + DBGCOMPLETED; + return SANE_STATUS_GOOD; + } + sanei_genesys_sleep_ms(100); + ++loop; + } + + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl847_stop_action (dev); + DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + DBG(DBG_info, "%s: scanhead is still moving\n", __func__); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels + area at 600 dpi from very top of scanner */ +static SANE_Status +gl847_search_start_position (Genesys_Device * dev) +{ + int size; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg; + int steps; + + int pixels = 600; + int dpi = 300; + + DBG(DBG_proc, "%s\n", __func__); + + local_reg = dev->reg; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); + + SetupParams params; + params.xres = dpi; + params.yres = dpi; + params.startx = 0; + params.starty = 0; /*we should give a small offset here~60 steps */ + params.pixels = 600; + params.lines = dev->model->search_lines; + params.depth = 8; + params.channels = 1; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::GREEN; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl847_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* send to scanner */ + status = dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + size = pixels * dev->model->search_lines; + + std::vector data(size); + + status = gl847_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl847_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + + status = gl847_end_scan(dev, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + +/*TODO: find out where sanei_genesys_search_reference_point + stores information, and use that correctly*/ + status = + sanei_genesys_search_reference_point(dev, sensor, data.data(), 0, dpi, pixels, + dev->model->search_lines); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + return SANE_STATUS_GOOD; +} + +/* + * sets up register for coarse gain calibration + * todo: check it for scanners using it */ +static SANE_Status +gl847_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t channels; + uint8_t cksel; + + DBG(DBG_proc, "%s\n", __func__); + + + cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ + + /* set line size */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else { + channels = 1; + } + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = 0; + params.starty = 0; + params.pixels = sensor.optical_res / cksel; + params.lines = 20; + params.depth = 16; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl847_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / cksel, dev->settings.xres); + + status = + dev->model->cmd_set->bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief moves the slider to steps at motor base dpi + * @param dev device to work on + * @param steps number of steps to move in base_dpi line count + * */ +static SANE_Status +gl847_feed (Genesys_Device * dev, unsigned int steps) +{ + Genesys_Register_Set local_reg; + SANE_Status status = SANE_STATUS_GOOD; + GenesysRegister *r; + float resolution; + uint8_t val; + + DBGSTART; + DBG(DBG_io, "%s: steps=%d\n", __func__, steps); + + local_reg = dev->reg; + + resolution=sanei_genesys_get_lowest_ydpi(dev); + const auto& sensor = sanei_genesys_find_sensor(dev, resolution); + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 0; + params.starty = steps; + params.pixels = 100; + params.lines = 3; + params.depth = 8; + params.channels = 3; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_FEEDING | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl847_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); + DBGCOMPLETED; + return status; + } + + /* set exposure to zero */ + sanei_genesys_set_triple(&local_reg,REG_EXPR,0); + sanei_genesys_set_triple(&local_reg,REG_EXPG,0); + sanei_genesys_set_triple(&local_reg,REG_EXPB,0); + + /* clear scan and feed count */ + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); + RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); + + /* set up for no scan */ + r = sanei_genesys_get_address(&local_reg, REG01); + r->value &= ~REG01_SCAN; + + /* send registers */ + RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); + + try { + status = gl847_start_action (dev); + } catch (...) { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + try { + gl847_stop_action(dev); + } catch (...) {} + try { + // restore original registers + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + } catch (...) {} + throw; + } + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); + gl847_stop_action (dev); + + /* restore original registers */ + dev->model->cmd_set->bulk_write_register(dev, dev->reg); + return status; + } + + /* wait until feed count reaches the required value, but do not + * exceed 30s */ + do + { + status = sanei_genesys_get_status (dev, &val); + } + while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); + + /* then stop scanning */ + RIE(gl847_stop_action (dev)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/* init registers for shading calibration */ +static SANE_Status +gl847_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + float move; + + DBGSTART; + dev->calib_channels = 3; + + /* initial calibration reg values */ + regs = dev->reg; + + dev->calib_resolution = sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); + dev->calib_total_bytes_to_read = 0; + dev->calib_lines = dev->model->shading_lines; + if(dev->calib_resolution==4800) + dev->calib_lines *= 2; + dev->calib_pixels = (sensor.sensor_pixels*dev->calib_resolution)/sensor.optical_res; + DBG(DBG_io, "%s: calib_lines = %d\n", __func__, (int)dev->calib_lines); + DBG(DBG_io, "%s: calib_pixels = %d\n", __func__, (int)dev->calib_pixels); + + /* this is aworkaround insufficent distance for slope + * motor acceleration TODO special motor slope for shading */ + move=1; + if(dev->calib_resolution<1200) + { + move=40; + } + + SetupParams params; + params.xres = dev->calib_resolution; + params.yres = dev->calib_resolution; + params.startx = 0; + params.starty = move; + params.pixels = dev->calib_pixels; + params.lines = dev->calib_lines; + params.depth = 16; + params.channels = dev->calib_channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl847_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = dev->model->cmd_set->bulk_write_register(dev, regs); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* we use GENESYS_FLAG_SHADING_REPARK */ + dev->scanhead_position_in_steps = 0; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** @brief set up registers for the actual scan + */ +static SANE_Status +gl847_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int channels; + int flags; + int depth; + float move; + int move_dpi; + float start; + + SANE_Status status = SANE_STATUS_GOOD; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, dev->settings); + + /* channels */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + channels = 3; + else + channels = 1; + + /* depth */ + depth = dev->settings.depth; + if (dev->settings.scan_mode == ScanColorMode::LINEART) + depth = 1; + + + /* steps to move to reach scanning area: + - first we move to physical start of scanning + either by a fixed steps amount from the black strip + or by a fixed amount from parking position, + minus the steps done during shading calibration + - then we move by the needed offset whitin physical + scanning area + + assumption: steps are expressed at maximum motor resolution + + we need: + SANE_Fixed y_offset; + SANE_Fixed y_size; + SANE_Fixed y_offset_calib; + mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ + + /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is + relative from origin, else, it is from parking position */ + + move_dpi = dev->motor.base_ydpi; + + move = SANE_UNFIX (dev->model->y_offset); + move += dev->settings.tl_y; + move = (move * move_dpi) / MM_PER_INCH; + move -= dev->scanhead_position_in_steps; + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* fast move to scan area */ + /* we don't move fast the whole distance since it would involve + * computing acceleration/deceleration distance for scan + * resolution. So leave a remainder for it so scan makes the final + * move tuning */ + if(channels*dev->settings.yres>=600 && move>700) + { + status = gl847_feed (dev, move-500); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to move to scan area\n", __func__); + return status; + } + move=500; + } + + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* start */ + start = SANE_UNFIX (dev->model->x_offset); + start += dev->settings.tl_x; + start = (start * sensor.optical_res) / MM_PER_INCH; + + flags = 0; + + /* emulated lineart from gray data is required for now */ + if(dev->settings.scan_mode == ScanColorMode::LINEART + && dev->settings.dynamic_lineart) + { + flags |= SCAN_FLAG_DYNAMIC_LINEART; + } + + /* backtracking isn't handled well, so don't enable it */ + flags |= SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; + + SetupParams params; + params.xres = dev->settings.xres; + params.yres = dev->settings.yres; + params.startx = start; + params.starty = move; + params.pixels = dev->settings.pixels; + params.lines = dev->settings.lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = dev->settings.scan_mode; + params.color_filter = dev->settings.color_filter; + params.flags = flags; + + status = gl847_init_scan_regs(dev, sensor, &dev->reg, params); + + if (status != SANE_STATUS_GOOD) + return status; + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +static SANE_Status +gl847_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, int size) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint32_t addr, length, i, x, factor, pixels; + uint32_t dpiset, dpihw, strpixel, endpixel; + uint16_t tempo; + uint32_t lines, channels; + uint8_t val,*ptr,*src; + + DBGSTART; + DBG(DBG_io2, "%s: writing %d bytes of shading data\n", __func__, size); + + /* shading data is plit in 3 (up to 5 with IR) areas + write(0x10014000,0x00000dd8) + URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x.... + write(0x1003e000,0x00000dd8) + write(0x10068000,0x00000dd8) + */ + length = (uint32_t) (size / 3); + sanei_genesys_get_double(&dev->reg,REG_STRPIXEL,&tempo); + strpixel=tempo; + sanei_genesys_get_double(&dev->reg,REG_ENDPIXEL,&tempo); + endpixel=tempo; + + /* compute deletion factor */ + sanei_genesys_get_double(&dev->reg,REG_DPISET,&tempo); + dpiset=tempo; + DBG(DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n", __func__, strpixel, endpixel, + endpixel-strpixel, dpiset); + dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpiset); + factor=dpihw/dpiset; + DBG(DBG_io2, "%s: factor=%d\n", __func__, factor); + + if(DBG_LEVEL>=DBG_data) + { + dev->binary=fopen("binary.pnm","wb"); + sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &lines); + channels=dev->current_setup.channels; + if(dev->binary!=NULL) + { + fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); + } + } + + pixels=endpixel-strpixel; + + /* since we're using SHDAREA, substract startx coordinate from shading */ + strpixel-=((sensor.CCD_start_xoffset*600)/sensor.optical_res); + + /* turn pixel value into bytes 2x16 bits words */ + strpixel*=2*2; + pixels*=2*2; + + std::vector buffer(pixels, 0); + + DBG(DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n", __func__, pixels, pixels); + + /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address + * is 8192*reg value */ + + /* write actual color channel data */ + for(i=0;i<3;i++) + { + /* build up actual shading data by copying the part from the full width one + * to the one corresponding to SHDAREA */ + ptr = buffer.data(); + + /* iterate on both sensor segment */ + for(x=0;xmodel->y_offset_calib); + move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; + if(move>20) + { + RIE(gl847_feed (dev, move)); + } + DBG(DBG_io, "%s: move=%f steps\n", __func__, move); + + /* offset calibration is always done in color mode */ + channels = 3; + depth=16; + used_res=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); + Sensor_Profile* sensor_profile=get_sensor_profile(dev->model->ccd_type, used_res); + num_pixels = (sensor.sensor_pixels*used_res)/sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + SetupParams params; + params.xres = used_res; + params.yres = used_res; + params.startx = 0; + params.starty = 0; + params.pixels = num_pixels; + params.lines = 1; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl847_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ + std::vector line(total_size); + + /* initial loop values and boundaries */ + exp[0]=sensor_profile->expr; + exp[1]=sensor_profile->expg; + exp[2]=sensor_profile->expb; + + bottom[0]=29000; + bottom[1]=29000; + bottom[2]=29000; + + top[0]=41000; + top[1]=51000; + top[2]=51000; + + turn = 0; + + /* no move during led calibration */ + sanei_genesys_set_motor_power(regs, false); + do + { + /* set up exposure */ + sanei_genesys_set_double(®s,REG_EXPR,exp[0]); + sanei_genesys_set_double(®s,REG_EXPG,exp[1]); + sanei_genesys_set_double(®s,REG_EXPB,exp[2]); + + /* write registers and scan data */ + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + + DBG(DBG_info, "%s: starting line reading\n", __func__); + RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); + + /* stop scanning */ + RIE(gl847_stop_action (dev)); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl847_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), depth, channels, num_pixels, 1); + } + + /* compute average */ + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + /* check if exposure gives average within the boundaries */ + acceptable = SANE_TRUE; + for(i=0;i<3;i++) + { + if(avg[i]top[i]) + { + exp[i]=(exp[i]*top[i])/avg[i]; + acceptable = SANE_FALSE; + } + } + + turn++; + } + while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); + + /* set these values as final ones for scan */ + sanei_genesys_set_double(&dev->reg,REG_EXPR,exp[0]); + sanei_genesys_set_double(&dev->reg,REG_EXPG,exp[1]); + sanei_genesys_set_double(&dev->reg,REG_EXPB,exp[2]); + + /* store in this struct since it is the one used by cache calibration */ + sensor.exposure.red = exp[0]; + sensor.exposure.green = exp[1]; + sensor.exposure.blue = exp[2]; + + /* go back home */ + if(move>20) + { + status=gl847_slow_back_home (dev, SANE_TRUE); + } + + DBGCOMPLETED; + return status; +} + +/** + * set up GPIO/GPOE for idle state + */ +static SANE_Status +gl847_init_gpio (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + int idx=0; + + DBGSTART; + + /* search GPIO profile */ + while(gpios[idx].sensor_id!=0 && dev->model->gpo_type!=gpios[idx].sensor_id) + { + idx++; + } + if(gpios[idx].sensor_id==0) + { + DBG(DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __func__, + dev->model->ccd_type); + return SANE_STATUS_INVAL; + } + + RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); + RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); + + RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); + RIE (sanei_genesys_write_register (dev, REG6C, 0x00)); + + RIE (sanei_genesys_write_register (dev, REG6B, gpios[idx].r6b)); + RIE (sanei_genesys_write_register (dev, REG6C, gpios[idx].r6c)); + RIE (sanei_genesys_write_register (dev, REG6D, gpios[idx].r6d)); + RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); + RIE (sanei_genesys_write_register (dev, REG6F, gpios[idx].r6f)); + + RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); + RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); + + DBGCOMPLETED; + return status; +} + +/** + * set memory layout by filling values in dedicated registers + */ +static SANE_Status +gl847_init_memory_layout (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + int idx = 0; + uint8_t val; + + DBG(DBG_proc, "%s\n" , __func__); + + /* point to per model memory layout */ + idx = 0; + if (dev->model->model_id == MODEL_CANON_LIDE_100) + { + idx = 0; + } + if (dev->model->model_id == MODEL_CANON_LIDE_200) + { + idx = 1; + } + if (dev->model->model_id == MODEL_CANON_CANOSCAN_5600F) + { + idx = 2; + } + if (dev->model->model_id == MODEL_CANON_LIDE_700F) + { + idx = 3; + } + + /* CLKSET nd DRAMSEL */ + val = layouts[idx].dramsel; + RIE (sanei_genesys_write_register (dev, REG0B, val)); + dev->reg.find_reg(0x0b).value = val; + + /* prevent further writings by bulk write register */ + dev->reg.remove_reg(0x0b); + + /* setup base address for shading data. */ + /* values must be multiplied by 8192=0x4000 to give address on AHB */ + /* R-Channel shading bank0 address setting for CIS */ + sanei_genesys_write_register (dev, 0xd0, layouts[idx].rd0); + /* G-Channel shading bank0 address setting for CIS */ + sanei_genesys_write_register (dev, 0xd1, layouts[idx].rd1); + /* B-Channel shading bank0 address setting for CIS */ + sanei_genesys_write_register (dev, 0xd2, layouts[idx].rd2); + + /* setup base address for scanned data. */ + /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ + /* R-Channel ODD image buffer 0x0124->0x92000 */ + /* size for each buffer is 0x16d*1k word */ + sanei_genesys_write_register (dev, 0xe0, layouts[idx].re0); + sanei_genesys_write_register (dev, 0xe1, layouts[idx].re1); + /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ + sanei_genesys_write_register (dev, 0xe2, layouts[idx].re2); + sanei_genesys_write_register (dev, 0xe3, layouts[idx].re3); + + /* R-Channel EVEN image buffer 0x0292 */ + sanei_genesys_write_register (dev, 0xe4, layouts[idx].re4); + sanei_genesys_write_register (dev, 0xe5, layouts[idx].re5); + /* R-Channel EVEN image buffer end-address 0x03ff*/ + sanei_genesys_write_register (dev, 0xe6, layouts[idx].re6); + sanei_genesys_write_register (dev, 0xe7, layouts[idx].re7); + + /* same for green, since CIS, same addresses */ + sanei_genesys_write_register (dev, 0xe8, layouts[idx].re0); + sanei_genesys_write_register (dev, 0xe9, layouts[idx].re1); + sanei_genesys_write_register (dev, 0xea, layouts[idx].re2); + sanei_genesys_write_register (dev, 0xeb, layouts[idx].re3); + sanei_genesys_write_register (dev, 0xec, layouts[idx].re4); + sanei_genesys_write_register (dev, 0xed, layouts[idx].re5); + sanei_genesys_write_register (dev, 0xee, layouts[idx].re6); + sanei_genesys_write_register (dev, 0xef, layouts[idx].re7); + +/* same for blue, since CIS, same addresses */ + sanei_genesys_write_register (dev, 0xf0, layouts[idx].re0); + sanei_genesys_write_register (dev, 0xf1, layouts[idx].re1); + sanei_genesys_write_register (dev, 0xf2, layouts[idx].re2); + sanei_genesys_write_register (dev, 0xf3, layouts[idx].re3); + sanei_genesys_write_register (dev, 0xf4, layouts[idx].re4); + sanei_genesys_write_register (dev, 0xf5, layouts[idx].re5); + sanei_genesys_write_register (dev, 0xf6, layouts[idx].re6); + sanei_genesys_write_register (dev, 0xf7, layouts[idx].re7); + + DBGCOMPLETED; + return status; +} + +/* * + * initialize ASIC from power on condition + */ +static SANE_Status +gl847_boot (Genesys_Device * dev, SANE_Bool cold) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + + DBGSTART; + + /* reset ASIC if cold boot */ + if(cold) + { + RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); + RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); + } + + /* test CHKVER */ + RIE (sanei_genesys_read_register (dev, REG40, &val)); + if (val & REG40_CHKVER) + { + RIE (sanei_genesys_read_register (dev, 0x00, &val)); + DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); + } + + /* Set default values for registers */ + gl847_init_registers (dev); + + /* Write initial registers */ + RIE (dev->model->cmd_set->bulk_write_register(dev, dev->reg)); + + /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ + val = dev->reg.find_reg(0x0b).value & REG0B_DRAMSEL; + val = (val | REG0B_ENBDRAM); + RIE (sanei_genesys_write_register (dev, REG0B, val)); + dev->reg.find_reg(0x0b).value = val; + + /* CIS_LINE */ + SETREG (0x08, REG08_CIS_LINE); + RIE (sanei_genesys_write_register (dev, 0x08, dev->reg.find_reg(0x08).value)); + + /* set up end access */ + RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0b)); + RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); + + /* setup gpio */ + RIE (gl847_init_gpio (dev)); + + /* setup internal memory layout */ + RIE (gl847_init_memory_layout (dev)); + + SETREG (0xf8, 0x01); + RIE (sanei_genesys_write_register (dev, 0xf8, dev->reg.find_reg(0xf8).value)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** + * initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +static SANE_Status gl847_init (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + + DBG_INIT (); + DBGSTART; + + status=sanei_genesys_asic_init(dev, 0); + + DBGCOMPLETED; + return status; +} + +static SANE_Status +gl847_update_hardware_sensors (Genesys_Scanner * s) +{ + /* do what is needed to get a new set of events, but try to not lose + any of them. + */ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + uint8_t scan, file, email, copy; + switch(s->dev->model->gpo_type) + { + case GPO_CANONLIDE700: + scan=0x04; + file=0x02; + email=0x01; + copy=0x08; + break; + default: + scan=0x01; + file=0x02; + email=0x04; + copy=0x08; + } + RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); + + s->buttons[BUTTON_SCAN_SW].write((val & scan) == 0); + s->buttons[BUTTON_FILE_SW].write((val & file) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & email) == 0); + s->buttons[BUTTON_COPY_SW].write((val & copy) == 0); + + return status; +} + +/** @brief search for a full width black or white strip. + * This function searches for a black or white stripe across the scanning area. + * When searching backward, the searched area must completely be of the desired + * color since this area will be used for calibration which scans forward. + * @param dev scanner device + * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward + * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip + * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not + */ +static SANE_Status +gl847_search_strip (Genesys_Device * dev, const Genesys_Sensor& sensor, + SANE_Bool forward, SANE_Bool black) +{ + unsigned int pixels, lines, channels; + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set local_reg; + size_t size; + int steps, depth, dpi; + unsigned int pass, count, found, x, y; + char title[80]; + GenesysRegister *r; + + DBG(DBG_proc, "%s %s %s\n", __func__, black ? "black" : "white", forward ? "forward" : "reverse"); + + gl847_set_fe(dev, sensor, AFE_SET); + status = gl847_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* set up for a gray scan at lowest dpi */ + dpi = 9600; + for (x = 0; x < MAX_RESOLUTIONS; x++) + { + if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) + dpi = dev->model->xdpi_values[x]; + } + channels = 1; + /* 10 MM */ + /* lines = (10 * dpi) / MM_PER_INCH; */ + /* shading calibation is done with dev->motor.base_ydpi */ + lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; + depth = 8; + pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; + size = pixels * channels * lines * (depth / 8); + std::vector data(size); + dev->scanhead_position_in_steps = 0; + + local_reg = dev->reg; + + SetupParams params; + params.xres = dpi; + params.yres = dpi; + params.startx = 0; + params.starty = 0; + params.pixels = pixels; + params.lines = lines; + params.depth = depth; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::GRAY; + params.color_filter = ColorFilter::RED; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA; + + status = gl847_init_scan_regs(dev, sensor, &local_reg, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* set up for reverse or forward */ + r = sanei_genesys_get_address(&local_reg, REG02); + if (forward) + r->value &= ~REG02_MTRREV; + else + r->value |= REG02_MTRREV; + + + status = dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl847_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl847_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl847_stop_action failed\n", __func__); + return status; + } + + pass = 0; + if (DBG_LEVEL >= DBG_data) + { + sprintf(title, "gl847_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); + sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); + } + + /* loop until strip is found or maximum pass number done */ + found = 0; + while (pass < 20 && !found) + { + status = + dev->model->cmd_set->bulk_write_register(dev, local_reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* now start scan */ + status = gl847_begin_scan(dev, sensor, &local_reg, SANE_TRUE); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + /* waits for valid data */ + do + sanei_genesys_test_buffer_empty (dev, &steps); + while (steps); + + /* now we're on target, we can read data */ + status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); + return status; + } + + status = gl847_stop_action (dev); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: gl847_stop_action failed\n", __func__); + return status; + } + + if (DBG_LEVEL >= DBG_data) + { + sprintf(title, "gl847_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); + sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (pixels * lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + pass++; + } + + if (found) + { + status = SANE_STATUS_GOOD; + DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); + } + else + { + status = SANE_STATUS_UNSUPPORTED; + DBG(DBG_info, "%s: %s strip not found\n", __func__, black ? "black" : "white"); + } + + DBGCOMPLETED; + return status; +} + +/** + * average dark pixels of a 8 bits scan + */ +static int +dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black) +{ + unsigned int i, j, k, average, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average value on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + for (i = 0; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + average = 0; + for (i = 0; i < channels; i++) + average += avg[i]; + average /= channels; + DBG(DBG_info, "%s: average = %d\n", __func__, average); + return average; +} + +static SANE_Status +gl847_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t reg04; + unsigned int channels, bpp; + int pass = 0, avg, total_size; + int topavg, bottomavg, resolution, lines; + int top, bottom, black_pixels, pixels; + + DBGSTART; + + /* no gain nor offset for AKM AFE */ + RIE (sanei_genesys_read_register (dev, REG04, ®04)); + if ((reg04 & REG04_FESET) == 0x02) + { + DBGCOMPLETED; + return status; + } + + /* offset calibration is always done in color mode */ + channels = 3; + resolution=sensor.optical_res; + dev->calib_pixels = sensor.sensor_pixels; + lines=1; + bpp=8; + pixels= (sensor.sensor_pixels*resolution) / sensor.optical_res; + black_pixels = (sensor.black_pixels * resolution) / sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + SetupParams params; + params.xres = resolution; + params.yres = resolution; + params.startx = 0; + params.starty = 0; + params.pixels = pixels; + params.lines = lines; + params.depth = bpp; + params.channels = channels; + params.scan_method = dev->settings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + status = gl847_init_scan_regs(dev, sensor, ®s, params); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + sanei_genesys_set_motor_power(regs, false); + + /* allocate memory for scans */ + total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* init gain */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* scan with no move */ + bottom = 10; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + + RIE(gl847_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting first line reading\n", __func__); + RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl847_offset%03d.pnm", bottom); + sanei_genesys_write_pnm_file(fn, first_line.data(), bpp, channels, pixels, lines); + } + + bottomavg = dark_average (first_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); + + /* now top value */ + top = 255; + dev->frontend.set_offset(0, top); + dev->frontend.set_offset(1, top); + dev->frontend.set_offset(2, top); + RIE(gl847_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); + + topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); + + /* loop until acceptable level */ + while ((pass < 32) && (top - bottom > 1)) + { + pass++; + + /* settings for new scan */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + /* scan with no move */ + RIE(gl847_set_fe(dev, sensor, AFE_SET)); + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + snprintf(fn, 30, "gl847_offset%03d.pnm", dev->frontend.get_offset(1)); + sanei_genesys_write_pnm_file(fn, second_line.data(), bpp, channels, pixels, lines); + } + + avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); + + /* compute new boundaries */ + if (topavg == avg) + { + topavg = avg; + top = dev->frontend.get_offset(1); + } + else + { + bottomavg = avg; + bottom = dev->frontend.get_offset(1); + } + } + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +static SANE_Status +gl847_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) +{ + int pixels; + int total_size; + uint8_t reg04; + int i, j, channels; + SANE_Status status = SANE_STATUS_GOOD; + int max[3]; + float gain[3],coeff; + int val, code, lines; + int resolution; + int bpp; + + DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); + + /* no gain nor offset for AKM AFE */ + RIE (sanei_genesys_read_register (dev, REG04, ®04)); + if ((reg04 & REG04_FESET) == 0x02) + { + DBGCOMPLETED; + return status; + } + + /* coarse gain calibration is always done in color mode */ + channels = 3; + + /* follow CKSEL */ + if(dev->settings.xressettings.scan_method; + params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + params.color_filter = dev->settings.color_filter; + params.flags = SCAN_FLAG_DISABLE_SHADING | + SCAN_FLAG_DISABLE_GAMMA | + SCAN_FLAG_SINGLE_LINE | + SCAN_FLAG_IGNORE_LINE_DISTANCE; + + try { + status = gl847_init_scan_regs(dev, sensor, ®s, params); + } catch (...) { + try { + sanei_genesys_set_motor_power(regs, false); + } catch (...) {} + throw; + } + + sanei_genesys_set_motor_power(regs, false); + + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); + return status; + } + + RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); + + total_size = pixels * channels * (16/bpp) * lines; + + std::vector line(total_size); + + RIE(gl847_set_fe(dev, sensor, AFE_SET)); + RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); + RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl847_gain.pnm", line.data(), bpp, channels, pixels, lines); + + /* average value on each channel */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + for (i = pixels/4; i < (pixels*3/4); i++) + { + if(bpp==16) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * pixels + 1] * 256 + + line[i * 2 + j * 2 * pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + } + else + { + if (dev->model->is_cis) + val = line[i + j * pixels]; + else + val = line[i * channels + j]; + } + + max[j] += val; + } + max[j] = max[j] / (pixels/2); + + gain[j] = ((float) sensor.gain_white_ref*coeff) / max[j]; + + /* turn logical gain value into gain code, checking for overflow */ + code = 283 - 208 / gain[j]; + if (code > 255) + code = 255; + else if (code < 0) + code = 0; + dev->frontend.set_gain(j, code); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], + dev->frontend.get_gain(j)); + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + if (channels == 1) { + dev->frontend.set_gain(0, dev->frontend.get_gain(1)); + dev->frontend.set_gain(2, dev->frontend.get_gain(1)); + } + + RIE (gl847_stop_action (dev)); + + status=gl847_slow_back_home (dev, SANE_TRUE); + + DBGCOMPLETED; + return status; +} + + +/** the gl847 command set */ +static Genesys_Command_Set gl847_cmd_set = { + "gl847-generic", /* the name of this set */ + + nullptr, + + gl847_init, + NULL, /*gl847_init_regs_for_warmup*/ + gl847_init_regs_for_coarse_calibration, + gl847_init_regs_for_shading, + gl847_init_regs_for_scan, + + gl847_get_filter_bit, + gl847_get_lineart_bit, + gl847_get_bitset_bit, + gl847_get_gain4_bit, + gl847_get_fast_feed_bit, + gl847_test_buffer_empty_bit, + gl847_test_motor_flag_bit, + + gl847_set_fe, + gl847_set_powersaving, + gl847_save_power, + + gl847_begin_scan, + gl847_end_scan, + + sanei_genesys_send_gamma_table, + + gl847_search_start_position, + + gl847_offset_calibration, + gl847_coarse_gain_calibration, + gl847_led_calibration, + + NULL, + gl847_slow_back_home, + NULL, /* disable gl847_rewind, see #7 */ + + sanei_genesys_bulk_write_register, + NULL, + sanei_genesys_bulk_read_data, + + gl847_update_hardware_sensors, + + NULL, /* no known gl847 sheetfed scanner */ + NULL, /* no known gl847 sheetfed scanner */ + NULL, /* no known gl847 sheetfed scanner */ + gl847_search_strip, + + sanei_genesys_is_compatible_calibration, + NULL, + gl847_send_shading_data, + gl847_calculate_current_setup, + gl847_boot +}; + +SANE_Status +sanei_gl847_init_cmd_set (Genesys_Device * dev) +{ + dev->model->cmd_set = &gl847_cmd_set; + return SANE_STATUS_GOOD; +} diff --git a/backend/genesys_gl847.h b/backend/genesys_gl847.h index 1da2065..7af9c36 100644 --- a/backend/genesys_gl847.h +++ b/backend/genesys_gl847.h @@ -43,12 +43,6 @@ #include "genesys.h" - -#ifdef UNIT_TESTING -SANE_Status gl847_stop_action (Genesys_Device * dev); -SANE_Status gl847_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); -#endif - #define REG01 0x01 #define REG01_CISSET 0x80 #define REG01_DOGENB 0x40 @@ -326,201 +320,29 @@ SANE_Status gl847_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_hom #define REG_CK3MAP 0x77 #define REG_CK4MAP 0x7a -/** - * writable scanner registers */ -enum -{ - reg_0x01 = 0, - reg_0x02, - reg_0x03, - reg_0x04, - reg_0x05, - reg_0x06, - reg_0x08, - reg_0x09, - reg_0x0a, - reg_0x0b, - reg_0x0c, - reg_0x0d, - reg_0x0e, - reg_0x0f, - reg_0x10, - reg_0x11, - reg_0x12, - reg_0x13, - reg_0x14, - reg_0x15, - reg_0x16, - reg_0x17, - reg_0x18, - reg_0x19, - reg_0x1a, - reg_0x1b, - reg_0x1c, - reg_0x1d, - reg_0x1e, - reg_0x1f, - reg_0x20, - reg_0x21, - reg_0x22, - reg_0x23, - reg_0x24, - reg_0x25, - reg_0x26, - reg_0x27, - reg_0x2c, - reg_0x2d, - reg_0x2e, - reg_0x2f, - reg_0x30, - reg_0x31, - reg_0x32, - reg_0x33, - reg_0x34, - reg_0x35, - reg_0x36, - reg_0x37, - reg_0x38, - reg_0x39, - reg_0x3a, - reg_0x3b, - reg_0x3d, - reg_0x3e, - reg_0x3f, - reg_0x51, - reg_0x52, - reg_0x53, - reg_0x54, - reg_0x55, - reg_0x56, - reg_0x57, - reg_0x58, - reg_0x59, - reg_0x5a, - reg_0x5e, - reg_0x5f, - reg_0x60, - reg_0x61, - reg_0x62, - reg_0x63, - reg_0x64, - reg_0x65, - reg_0x67, - reg_0x68, - reg_0x69, - reg_0x6a, - reg_0x6b, - reg_0x6c, - reg_0x6d, - reg_0x6e, - reg_0x6f, - reg_0x74, - reg_0x75, - reg_0x76, - reg_0x77, - reg_0x78, - reg_0x79, - reg_0x7a, - reg_0x7b, - reg_0x7c, - reg_0x7d, - reg_0x87, - reg_0x9d, - reg_0xa2, - reg_0xa3, - reg_0xa4, - reg_0xa5, - reg_0xa6, - reg_0xa7, - reg_0xa8, - reg_0xa9, - reg_0xbd, - reg_0xbe, - reg_0xc5, - reg_0xc6, - reg_0xc7, - reg_0xc8, - reg_0xc9, - reg_0xca, - reg_0xd0, - reg_0xd1, - reg_0xd2, - reg_0xe0, - reg_0xe1, - reg_0xe2, - reg_0xe3, - reg_0xe4, - reg_0xe5, - reg_0xe6, - reg_0xe7, - reg_0xe8, - reg_0xe9, - reg_0xea, - reg_0xeb, - reg_0xec, - reg_0xed, - reg_0xee, - reg_0xef, - reg_0xf0, - reg_0xf1, - reg_0xf2, - reg_0xf3, - reg_0xf4, - reg_0xf5, - reg_0xf6, - reg_0xf7, - reg_0xf8, - reg_0xfe, - GENESYS_GL847_MAX_REGS -}; - -#define SETREG(adr,val) {dev->reg[reg_##adr].address=adr;dev->reg[reg_##adr].value=val;} +#define SETREG(adr,val) { dev->reg.init_reg(adr, val); } /** set up registers for an actual scan * * this function sets up the scanner to scan in normal or single line mode */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl847_init_scan_regs (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, /*dpi */ - float yres, /*dpi */ - float startx, /*optical_res, from dummy_pixel+1 */ - float starty, /*base_ydpi, from home! */ - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int color_filter, - unsigned int flags); +static SANE_Status gl847_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, SetupParams& params); /* Send the low-level scan command */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl847_begin_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool start_motor); +static SANE_Status gl847_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * reg, SANE_Bool start_motor); /* Send the stop scan command */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl847_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool check_stop); +static SANE_Status gl847_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool check_stop); -#ifndef UNIT_TESTING -static -#endif -SANE_Status gl847_init (Genesys_Device * dev); +static SANE_Status gl847_init (Genesys_Device * dev); /** @brief moves the slider to steps at motor base dpi * @param dev device to work on * @param steps number of steps to move * */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status +static SANE_Status gl847_feed (Genesys_Device * dev, unsigned int steps); typedef struct @@ -606,8 +428,6 @@ typedef struct { uint8_t r17; /**> TG width */ } Sensor_Profile; -/* *INDENT-OFF* */ - static size_t order_01[]={0,1}; static size_t order_0213[]={0,2,1,3}; static size_t order_0246[]={0,2,4,6,1,3,5,7}; @@ -643,7 +463,6 @@ static Sensor_Profile sensors[]={ {CIS_CANONLIDE700, 2400, 10576, 135, 249, 85, 5187, 255, 2798, 1558, 972, new_order , 0x08}, {CIS_CANONLIDE700, 4800, 10576, 135, 249, 85, 5187, 255, 2798, 1558, 972, order_0145, 0x06}, }; -/* *INDENT-ON* */ /* base motor sopes in full step unit */ /* target=((exposure * dpi) / base_dpi)>>step_type; */ @@ -663,7 +482,6 @@ static uint32_t lide200_max[] = { 124992, 124992, 124992, 124992, 124992, 124992 * database of motor profiles */ -/* *INDENT-OFF* */ static Motor_Profile gl847_motors[]={ /* LiDE 100 */ {MOTOR_CANONLIDE100, 2848, HALF_STEP , lide200_base}, @@ -690,6 +508,3 @@ static Motor_Profile gl847_motors[]={ /* end of database entry */ {0, 0, 0, NULL}, }; -/* *INDENT-ON* */ - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_low.c b/backend/genesys_low.c deleted file mode 100644 index 4cbd75d..0000000 --- a/backend/genesys_low.c +++ /dev/null @@ -1,2010 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2013 Stéphane Voltz - - - 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. -*/ -#undef BACKEND_NAME -#define BACKEND_NAME genesys_low - -#include "genesys_low.h" - -/* ------------------------------------------------------------------------ */ -/* functions calling ASIC specific functions */ -/* ------------------------------------------------------------------------ */ - -/** - * setup the hardware dependent functions - */ -SANE_Status -sanei_genesys_init_cmd_set (Genesys_Device * dev) -{ - DBG_INIT (); - switch (dev->model->asic_type) - { - case GENESYS_GL646: - return sanei_gl646_init_cmd_set (dev); - case GENESYS_GL841: - return sanei_gl841_init_cmd_set (dev); - case GENESYS_GL843: - return sanei_gl843_init_cmd_set (dev); - case GENESYS_GL845: /* since only a few reg bits differs - we handle both together */ - case GENESYS_GL846: - return sanei_gl846_init_cmd_set (dev); - case GENESYS_GL847: - return sanei_gl847_init_cmd_set (dev); - case GENESYS_GL124: - return sanei_gl124_init_cmd_set (dev); - default: - return SANE_STATUS_INVAL; - } -} - -/* ------------------------------------------------------------------------ */ -/* General IO and debugging functions */ -/* ------------------------------------------------------------------------ */ - -/* Write data to a pnm file (e.g. calibration). For debugging only */ -/* data is RGB or grey, with little endian byte order */ -SANE_Status -sanei_genesys_write_pnm_file (char *filename, uint8_t * data, int depth, - int channels, int pixels_per_line, int lines) -{ - FILE *out; - int count; - - DBG (DBG_info, - "sanei_genesys_write_pnm_file: depth=%d, channels=%d, ppl=%d, lines=%d\n", - depth, channels, pixels_per_line, lines); - - out = fopen (filename, "w"); - if (!out) - { - DBG (DBG_error, - "sanei_genesys_write_pnm_file: could nor open %s for writing: %s\n", - filename, strerror (errno)); - return SANE_STATUS_INVAL; - } - if(depth==1) - { - fprintf (out, "P4\n%d\n%d\n", pixels_per_line, lines); - } - else - { - fprintf (out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', - pixels_per_line, lines, (int) pow (2, depth) - 1); - } - if (channels == 3) - { - for (count = 0; count < (pixels_per_line * lines * 3); count++) - { - if (depth == 16) - fputc (*(data + 1), out); - fputc (*(data++), out); - if (depth == 16) - data++; - } - } - else - { - if (depth==1) - { - pixels_per_line/=8; - } - for (count = 0; count < (pixels_per_line * lines); count++) - { - switch (depth) - { - case 8: - fputc (*(data + count), out); - break; - case 16: - fputc (*(data + 1), out); - fputc (*(data), out); - data += 2; - break; - default: - fputc(data[count], out); - break; - } - } - } - fclose (out); - - DBG (DBG_proc, "sanei_genesys_write_pnm_file: finished\n"); - return SANE_STATUS_GOOD; -} - -/* the following 2 functions are used to handle registers in a - way that doesn't depend on the actual ASIC type */ - -/* Reads a register from a register set */ -SANE_Byte -sanei_genesys_read_reg_from_set (Genesys_Register_Set * reg, - uint16_t address) -{ - SANE_Int i; - - for (i = 0; i < GENESYS_MAX_REGS && reg[i].address; i++) - { - if (reg[i].address == address) - { - return reg[i].value; - } - } - return 0; -} - -/* Reads a register from a register set */ -void -sanei_genesys_set_reg_from_set (Genesys_Register_Set * reg, uint16_t address, - SANE_Byte value) -{ - SANE_Int i; - - for (i = 0; i < GENESYS_MAX_REGS && reg[i].address; i++) - { - if (reg[i].address == address) - { - reg[i].value = value; - break; - } - } -} - - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - -/** @brief write to one high (addr >= 0x100) register - * write to a register which address is higher than 0xff. - * @param dev opened device to write to - * @param reg LSB of register address - * @param val value to write - */ -SANE_Status -sanei_genesys_write_hregister (Genesys_Device * dev, uint16_t reg, uint8_t val) -{ - SANE_Status status; - uint8_t buffer[2]; - - buffer[0]=reg & 0xff; - buffer[1]=val; - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - 0x100 | VALUE_SET_REGISTER, INDEX, 2, buffer); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sanei_genesys_write_hregister (0x%02x, 0x%02x): failed : %s\n", reg, val, sane_strstatus (status)); - return status; - } - - DBG (DBG_io, "sanei_genesys_write_hregister (0x%02x, 0x%02x) completed\n", - reg, val); - - return status; -} - -/** @brief read from one high (addr >= 0x100) register - * Read to a register which address is higher than 0xff. Second byte is check to detect - * physical link errors. - * @param dev opened device to read from - * @param reg LSB of register address - * @param val value to write - */ -SANE_Status -sanei_genesys_read_hregister (Genesys_Device * dev, uint16_t reg, uint8_t * val) -{ - SANE_Status status; - SANE_Byte value[2]; - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_IN, REQUEST_BUFFER, - 0x100 | VALUE_GET_REGISTER, 0x22+((reg & 0xff)<<8), 2, value); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_read_hregister (0x%02x): failed while reading register: %s\n", - reg, sane_strstatus (status)); - return status; - } - *val=value[0]; - DBG( DBG_io2, "sanei_genesys_read_hregister(0x%02x)=0x%02x\n",reg,*val); - - /* check usb link status */ - if((value[1] & 0xff) != 0x55) - { - DBG (DBG_error,"sanei_genesys_read_hregister: invalid read, scanner unplugged ?\n"); - status=SANE_STATUS_IO_ERROR; - } - return status; -} - -/** - * Write to one GL847 ASIC register -URB 10 control 0x40 0x04 0x83 0x00 len 2 wrote 0xa6 0x04 - */ -static SANE_Status -sanei_genesys_write_gl847_register (Genesys_Device * dev, uint8_t reg, uint8_t val) -{ - SANE_Status status; - uint8_t buffer[2]; - - buffer[0]=reg; - buffer[1]=val; - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, - VALUE_SET_REGISTER, INDEX, 2, buffer); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sanei_genesys_write_gl847_register (0x%02x, 0x%02x): failed : %s\n", reg, val, sane_strstatus (status)); - return status; - } - - DBG (DBG_io, "sanei_genesys_write_gl847_register (0x%02x, 0x%02x) completed\n", - reg, val); - - return status; -} - -/** - * Write to one ASIC register - */ -SANE_Status -sanei_genesys_write_register (Genesys_Device * dev, uint16_t reg, uint8_t val) -{ - SANE_Status status; - SANE_Byte reg8; - -#ifdef UNIT_TESTING - if(dev->usb_mode<0) - { - return SANE_STATUS_GOOD; - } -#endif - - /* 16 bit register address space */ - if(reg>255) - { - return sanei_genesys_write_hregister(dev, reg, val); - } - - /* route to gl847 function if needed */ - if(dev->model->asic_type==GENESYS_GL847 - || dev->model->asic_type==GENESYS_GL845 - || dev->model->asic_type==GENESYS_GL846 - || dev->model->asic_type==GENESYS_GL124) - { - return sanei_genesys_write_gl847_register(dev, reg, val); - } - - reg8=reg & 0xff; - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, ®8); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_write_register (0x%02x, 0x%02x): failed while setting register: %s\n", - reg, val, sane_strstatus (status)); - return status; - } - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_WRITE_REGISTER, INDEX, 1, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_write_register (0x%02x, 0x%02x): failed while writing register value: %s\n", - reg, val, sane_strstatus (status)); - return status; - } - - DBG (DBG_io, "sanei_genesys_write_register (0x%02x, 0x%02x) completed\n", - reg, val); - - return status; -} - -/** - * @brief write command to 0x8c endpoint - * Write a value to 0x8c end point (end access), for USB firmware related operations - * Known values are 0x0f, 0x11 for USB 2.0 data transfer and 0x0f,0x14 for USB1.1 - * @param dev device to write to - * @param index index of the command - * @param val value to write - */ -SANE_Status -sanei_genesys_write_0x8c (Genesys_Device * dev, uint8_t index, uint8_t val) -{ - SANE_Status status; - -#ifdef UNIT_TESTING - if(dev->usb_mode<0) - { - return SANE_STATUS_GOOD; - } -#endif - - DBG (DBG_io, "sanei_genesys_write_0x8c: 0x%02x,0x%02x\n", index, val); - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_BUF_ENDACCESS, index, 1, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_write_0x8c: failed %s\n", sane_strstatus (status)); - } - return status; -} - -/* read reg 0x41: - * URB 164 control 0xc0 0x04 0x8e 0x4122 len 2 read 0xfc 0x55 - */ -static SANE_Status -sanei_genesys_read_gl847_register (Genesys_Device * dev, uint16_t reg, uint8_t * val) -{ - SANE_Status status; - SANE_Byte value[2]; - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_IN, REQUEST_BUFFER, - VALUE_GET_REGISTER, 0x22+(reg<<8), 2, value); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_read_gl847_register (0x%02x): failed while setting register: %s\n", - reg, sane_strstatus (status)); - return status; - } - *val=value[0]; - DBG( DBG_io2, "sanei_genesys_read_gl847_register(0x%02x)=0x%02x\n",reg,*val); - - /* check usb link status */ - if((value[1] & 0xff) != 0x55) - { - DBG (DBG_error,"sanei_genesys_read_gl847_register: invalid read, scanner unplugged ?\n"); - status=SANE_STATUS_IO_ERROR; - } - return status; -} - -/* Read from one register */ -SANE_Status -sanei_genesys_read_register (Genesys_Device * dev, uint16_t reg, uint8_t * val) -{ - SANE_Status status; - SANE_Byte reg8; - -#ifdef UNIT_TESTING - if(dev->usb_mode<0) - { - *val=0; - return SANE_STATUS_GOOD; - } -#endif - - /* 16 bit register address space */ - if(reg>255) - { - return sanei_genesys_read_hregister(dev, reg, val); - } - - /* route to gl847 function if needed */ - if(dev->model->asic_type==GENESYS_GL847 - || dev->model->asic_type==GENESYS_GL845 - || dev->model->asic_type==GENESYS_GL846 - || dev->model->asic_type==GENESYS_GL124) - return sanei_genesys_read_gl847_register(dev, reg, val); - - /* 8 bit register address space */ - reg8=(SANE_Byte)(reg& 0Xff); - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_OUT, REQUEST_REGISTER, - VALUE_SET_REGISTER, INDEX, 1, ®8); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_read_register (0x%02x, 0x%02x): failed while setting register: %s\n", - reg, *val, sane_strstatus (status)); - return status; - } - - *val = 0; - - status = - sanei_usb_control_msg (dev->dn, REQUEST_TYPE_IN, REQUEST_REGISTER, - VALUE_READ_REGISTER, INDEX, 1, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_read_register (0x%02x, 0x%02x): failed while reading register value: %s\n", - reg, *val, sane_strstatus (status)); - return status; - } - - DBG (DBG_io, "sanei_genesys_read_register (0x%02x, 0x%02x) completed\n", - reg, *val); - - return status; -} - -/* Set address for writing data */ -SANE_Status -sanei_genesys_set_buffer_address (Genesys_Device * dev, uint32_t addr) -{ - SANE_Status status; - - if(dev->model->asic_type==GENESYS_GL847 - || dev->model->asic_type==GENESYS_GL845 - || dev->model->asic_type==GENESYS_GL846 - || dev->model->asic_type==GENESYS_GL124) - { - DBG (DBG_warn, - "sanei_genesys_set_buffer_address: shouldn't be used for GL846+ ASICs\n"); - return SANE_STATUS_GOOD; - } - - DBG (DBG_io, - "sanei_genesys_set_buffer_address: setting address to 0x%05x\n", - addr & 0xfffffff0); - - addr = addr >> 4; - - status = sanei_genesys_write_register (dev, 0x2b, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_set_buffer_address: failed while writing low byte: %s\n", - sane_strstatus (status)); - return status; - } - - addr = addr >> 8; - status = sanei_genesys_write_register (dev, 0x2a, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_set_buffer_address: failed while writing high byte: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io, "sanei_genesys_set_buffer_address: completed\n"); - - return status; -} - -/**@brief read data from analog frontend (AFE) - * @param dev device owning the AFE - * @param addr register address to read - * @param data placeholder for the result - * @return SANE_STATUS_GOOD is OK, else the error code - */ -SANE_Status -sanei_genesys_fe_read_data (Genesys_Device * dev, uint8_t addr, - uint16_t *data) -{ - SANE_Status status; - uint8_t value; - Genesys_Register_Set reg[1]; - - - DBG (DBG_proc, "sanei_genesys_fe_read_data: start\n"); - - reg[0].address = 0x50; - reg[0].value = addr; - - /* set up read address */ - status = dev->model->cmd_set->bulk_write_register (dev, reg, 1); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_fe_read_data: failed while bulk writing registers: %s\n", - sane_strstatus (status)); - return status; - } - - /* read data */ - RIE (sanei_genesys_read_register (dev, 0x46, &value)); - *data=256*value; - RIE (sanei_genesys_read_register (dev, 0x47, &value)); - *data+=value; - - DBG (DBG_io, "sanei_genesys_fe_read_data (0x%02x, 0x%04x)\n", addr, *data); - DBG (DBG_proc, "sanei_genesys_fe_read_data: completed\n"); - - return status; -} - -/*@brief write data to analog frontend - * writes data to analog frontend to set it up accordingly - * to the sensor settings (exposure, timings, color, bit depth, ...) - * @param dev devie owning the AFE to write to - * @param addr AFE rister address - * @param data value to write to AFE register - **/ -SANE_Status -sanei_genesys_fe_write_data (Genesys_Device * dev, uint8_t addr, - uint16_t data) -{ - SANE_Status status; - Genesys_Register_Set reg[3]; - -#ifdef UNIT_TESTING - if(dev->usb_mode<0) - { - return SANE_STATUS_GOOD; - } -#endif - - DBG (DBG_io, "sanei_genesys_fe_write_data (0x%02x, 0x%04x)\n", addr, data); - - reg[0].address = 0x51; - reg[0].value = addr; - reg[1].address = 0x3a; - reg[1].value = (data / 256) & 0xff; - reg[2].address = 0x3b; - reg[2].value = data & 0xff; - if (dev->model->asic_type == GENESYS_GL124) - { - reg[1].address = 0x5d; - reg[2].address = 0x5e; - } - - status = dev->model->cmd_set->bulk_write_register (dev, reg, 3); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_fe_write_data: failed while bulk writing registers: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_io, "sanei_genesys_fe_write_data: completed\n"); - - return status; -} - -/* ------------------------------------------------------------------------ */ -/* Medium level functions */ -/* ------------------------------------------------------------------------ */ - -/** read the status register - */ -SANE_Status -sanei_genesys_get_status (Genesys_Device * dev, uint8_t * status) -{ -#ifdef UNIT_TESTING - if(dev->usb_mode<0) - { - *status=0; - return SANE_STATUS_GOOD; - } -#endif - - if(dev->model->asic_type==GENESYS_GL124) - return sanei_genesys_read_hregister(dev, 0x101, status); - return sanei_genesys_read_register (dev, 0x41, status); -} - -/** - * decodes and prints content of status register - * @param val value read from status register - */ -void sanei_genesys_print_status (uint8_t val) -{ - char msg[80]; - - sprintf (msg, "%s%s%s%s%s%s%s%s", - val & PWRBIT ? "PWRBIT " : "", - val & BUFEMPTY ? "BUFEMPTY " : "", - val & FEEDFSH ? "FEEDFSH " : "", - val & SCANFSH ? "SCANFSH " : "", - val & HOMESNR ? "HOMESNR " : "", - val & LAMPSTS ? "LAMPSTS " : "", - val & FEBUSY ? "FEBUSY " : "", - val & MOTORENB ? "MOTORENB" : ""); - DBG (DBG_info, "status=%s\n", msg); -} - -#if 0 -/* returns pixels per line from register set */ -/*candidate for moving into chip specific files?*/ -static int -genesys_pixels_per_line (Genesys_Register_Set * reg) -{ - int pixels_per_line; - - pixels_per_line = - sanei_genesys_read_reg_from_set (reg, - 0x32) * 256 + - sanei_genesys_read_reg_from_set (reg, 0x33); - pixels_per_line -= - (sanei_genesys_read_reg_from_set (reg, 0x30) * 256 + - sanei_genesys_read_reg_from_set (reg, 0x31)); - - return pixels_per_line; -} - -/* returns dpiset from register set */ -/*candidate for moving into chip specific files?*/ -static int -genesys_dpiset (Genesys_Register_Set * reg) -{ - int dpiset; - - dpiset = - sanei_genesys_read_reg_from_set (reg, - 0x2c) * 256 + - sanei_genesys_read_reg_from_set (reg, 0x2d); - - return dpiset; -} -#endif - -/** read the number of valid words in scanner's RAM - * ie registers 42-43-44 - */ -/*candidate for moving into chip specific files?*/ -SANE_Status -sanei_genesys_read_valid_words (Genesys_Device * dev, unsigned int *words) -{ - SANE_Status status; - uint8_t value; - - DBGSTART; - switch (dev->model->asic_type) - { - case GENESYS_GL124: - RIE (sanei_genesys_read_hregister (dev, 0x102, &value)); - *words = (value & 0x03); - RIE (sanei_genesys_read_hregister (dev, 0x103, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_hregister (dev, 0x104, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_hregister (dev, 0x105, &value)); - *words = *words * 256 + value; - break; - - case GENESYS_GL845: - case GENESYS_GL846: - RIE (sanei_genesys_read_register (dev, 0x42, &value)); - *words = (value & 0x02); - RIE (sanei_genesys_read_register (dev, 0x43, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_register (dev, 0x44, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_register (dev, 0x45, &value)); - *words = *words * 256 + value; - break; - - case GENESYS_GL847: - RIE (sanei_genesys_read_register (dev, 0x42, &value)); - *words = (value & 0x03); - RIE (sanei_genesys_read_register (dev, 0x43, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_register (dev, 0x44, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_register (dev, 0x45, &value)); - *words = *words * 256 + value; - break; - - default: - RIE (sanei_genesys_read_register (dev, 0x44, &value)); - *words = value; - RIE (sanei_genesys_read_register (dev, 0x43, &value)); - *words += (value * 256); - RIE (sanei_genesys_read_register (dev, 0x42, &value)); - if (dev->model->asic_type == GENESYS_GL646) - *words += ((value & 0x03) * 256 * 256); - else - *words += ((value & 0x0f) * 256 * 256); - } - - DBG (DBG_proc, "%s: %d words\n", __func__, *words); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** read the number of lines scanned - * ie registers 4b-4c-4d - */ -SANE_Status -sanei_genesys_read_scancnt (Genesys_Device * dev, unsigned int *words) -{ - SANE_Status status; - uint8_t value; - - DBG (DBG_proc, "sanei_genesys_read_scancnt: start\n"); - - if (dev->model->asic_type == GENESYS_GL124) - { - RIE (sanei_genesys_read_hregister (dev, 0x10b, &value)); - *words = (value & 0x0f) << 16; - RIE (sanei_genesys_read_hregister (dev, 0x10c, &value)); - *words += (value << 8); - RIE (sanei_genesys_read_hregister (dev, 0x10d, &value)); - *words += value; - } - else - { - RIE (sanei_genesys_read_register (dev, 0x4d, &value)); - *words = value; - RIE (sanei_genesys_read_register (dev, 0x4c, &value)); - *words += (value * 256); - RIE (sanei_genesys_read_register (dev, 0x4b, &value)); - if (dev->model->asic_type == GENESYS_GL646) - *words += ((value & 0x03) * 256 * 256); - else - *words += ((value & 0x0f) * 256 * 256); - } - - DBG (DBG_proc, "sanei_genesys_read_scancnt: %d lines\n", *words); - return SANE_STATUS_GOOD; -} - -/** - * Find register in set - * @param regs register set to search - * @param addr addres of the searched register - * @return a Genesys_Register_Set pointer corresponding to the required - * address in ASIC space. Or NULL if not found. - */ -Genesys_Register_Set * -sanei_genesys_get_address (Genesys_Register_Set * regs, uint16_t addr) -{ - int i; - for (i = 0; i < GENESYS_MAX_REGS; i++) - { - if (regs[i].address == addr) - return ®s[i]; - } - DBG (DBG_error, "sanei_genesys_get_address: failed to find address for register 0x%02x, crash expected !\n",addr); - return NULL; -} - -/** - * set a 16 bit value in the given register set. - * @param regs register set where to set values - * @param addr address of the first register index to set - * @param value value to set - * @return SANE_STATUS_INVAL if the index doesn't exist in register set - */ -SANE_Status -sanei_genesys_set_double(Genesys_Register_Set *regs, uint16_t addr, uint16_t value) -{ - Genesys_Register_Set *r; - - /* high byte */ - r = sanei_genesys_get_address (regs, addr); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - r->value = HIBYTE (value); - - /* low byte */ - r = sanei_genesys_get_address (regs, addr+1); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - r->value = LOBYTE (value); - - return SANE_STATUS_GOOD; -} - -/** - * set a 24 bit value in the given register set. - * @param regs register set where to set values - * @param addr address of the first register index to set - * @param value value to set - * @return SANE_STATUS_INVAL if the index doesn't exist in register set - */ -SANE_Status -sanei_genesys_set_triple(Genesys_Register_Set *regs, uint16_t addr, uint32_t value) -{ - Genesys_Register_Set *r; - - /* low byte of highword */ - r = sanei_genesys_get_address (regs, addr); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - r->value = LOBYTE (HIWORD(value)); - - /* high byte of low word */ - r = sanei_genesys_get_address (regs, addr+1); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - r->value = HIBYTE (LOWORD(value)); - - /* low byte of low word */ - r = sanei_genesys_get_address (regs, addr+2); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - r->value = LOBYTE (LOWORD(value)); - - return SANE_STATUS_GOOD; -} - -/** - * get a 16 bit value in the given register set. - * @param regs register set where to read values - * @param addr address of the first register index to read - * @param value value to set - * @return SANE_STATUS_INVAL if the index doesn't exist in register set - */ -SANE_Status -sanei_genesys_get_double(Genesys_Register_Set *regs, uint16_t addr, uint16_t *value) -{ - Genesys_Register_Set *r; - uint16_t result=0; - - /* high byte */ - r = sanei_genesys_get_address (regs, addr); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - result=r->value<<8; - - /* low byte */ - r = sanei_genesys_get_address (regs, addr+1); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - result+=r->value; - - *value=result; - return SANE_STATUS_GOOD; -} - -/** - * get a 24 bit value in the given register set. - * @param regs register set where to read values - * @param addr address of the first register index to read - * @param value value to set - * @return SANE_STATUS_INVAL if the index doesn't exist in register set - */ -SANE_Status -sanei_genesys_get_triple(Genesys_Register_Set *regs, uint16_t addr, uint32_t *value) -{ - Genesys_Register_Set *r; - uint32_t result=0; - - /* low byte of highword */ - r = sanei_genesys_get_address (regs, addr); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - result=r->value<<16; - - /* high byte of low word */ - r = sanei_genesys_get_address (regs, addr+1); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - result+=(r->value<<8); - - /* low byte of low word */ - r = sanei_genesys_get_address (regs, addr+2); - if(r==NULL) - { - return SANE_STATUS_INVAL; - } - result+=r->value; - - *value=result; - return SANE_STATUS_GOOD; -} - -/** @brief Check if the scanner's internal data buffer is empty - * @param *dev device to test for data - * @param *empty return value - * @return empty will be set to SANE_TRUE if there is no scanned data. - **/ -SANE_Status -sanei_genesys_test_buffer_empty (Genesys_Device * dev, SANE_Bool * empty) -{ - uint8_t val = 0; - SANE_Status status; - - usleep(1000); - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_test_buffer_empty: failed to read buffer status: %s\n", - sane_strstatus (status)); - return status; - } - - if (dev->model->cmd_set->test_buffer_empty_bit (val)) - { - /* fix timing issue on USB3 (or just may be too fast) hardware - * spotted by John S. Weber - */ - usleep(1000); - DBG (DBG_io2, "sanei_genesys_test_buffer_empty: buffer is empty\n"); - *empty = SANE_TRUE; - return SANE_STATUS_GOOD; - } - - *empty = SANE_FALSE; - - DBG (DBG_io, "sanei_genesys_test_buffer_empty: buffer is filled\n"); - return SANE_STATUS_GOOD; -} - - -/* Read data (e.g scanned image) from scan buffer */ -SANE_Status -sanei_genesys_read_data_from_scanner (Genesys_Device * dev, uint8_t * data, - size_t size) -{ - SANE_Status status; - int time_count = 0; - unsigned int words = 0; - - DBG (DBG_proc, "sanei_genesys_read_data_from_scanner (size = %lu bytes)\n", - (u_long) size); - - if (size & 1) - DBG (DBG_info, - "WARNING sanei_genesys_read_data_from_scanner: odd number of bytes\n"); - - /* wait until buffer not empty for up to 5 seconds */ - do - { - status = sanei_genesys_read_valid_words (dev, &words); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_read_data_from_scanner: checking for empty buffer failed: %s\n", - sane_strstatus (status)); - return status; - } - if (words == 0) - { - usleep (10000); /* wait 10 msec */ - time_count++; - } - } - while ((time_count < 2500*2) && (words == 0)); - - if (words == 0) /* timeout, buffer does not get filled */ - { - DBG (DBG_error, - "sanei_genesys_read_data_from_scanner: timeout, buffer does not get filled\n"); - return SANE_STATUS_IO_ERROR; - } - - status = dev->model->cmd_set->bulk_read_data (dev, 0x45, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_read_data_from_scanner: reading bulk data failed: %s\n", - sane_strstatus (status)); - return status; - } - - DBG (DBG_proc, "sanei_genesys_read_data_from_scanner: completed\n"); - return SANE_STATUS_GOOD; -} -SANE_Status -sanei_genesys_read_feed_steps (Genesys_Device * dev, unsigned int *steps) -{ - SANE_Status status; - uint8_t value; - - DBG (DBG_proc, "sanei_genesys_read_feed_steps\n"); - - if (dev->model->asic_type == GENESYS_GL124) - { - RIE (sanei_genesys_read_hregister (dev, 0x108, &value)); - *steps = (value & 0x1f) << 16; - RIE (sanei_genesys_read_hregister (dev, 0x109, &value)); - *steps += (value << 8); - RIE (sanei_genesys_read_hregister (dev, 0x10a, &value)); - *steps += value; - } - else - { - RIE (sanei_genesys_read_register (dev, 0x4a, &value)); - *steps = value; - RIE (sanei_genesys_read_register (dev, 0x49, &value)); - *steps += (value * 256); - RIE (sanei_genesys_read_register (dev, 0x48, &value)); - if (dev->model->asic_type == GENESYS_GL646) - *steps += ((value & 0x03) * 256 * 256); - else if (dev->model->asic_type == GENESYS_GL841) - *steps += ((value & 0x0f) * 256 * 256); - else - *steps += ((value & 0x1f) * 256 * 256); - } - - DBG (DBG_proc, "sanei_genesys_read_feed_steps: %d steps\n", *steps); - return SANE_STATUS_GOOD; -} - - -/** - * Write to many registers at once - * Note: sequential call to write register, no effective - * bulk write implemented. - * @param dev device to write to - * @param reg pointer to an array of registers - * @param elems size of the array - */ -SANE_Status -sanei_genesys_bulk_write_register (Genesys_Device * dev, - Genesys_Register_Set * reg, - size_t elems) -{ - SANE_Status status = SANE_STATUS_GOOD; - size_t i; - - for (i = 0; i < elems && status == SANE_STATUS_GOOD; i++) - { - if (reg[i].address != 0) - { - status = - sanei_genesys_write_register (dev, reg[i].address, reg[i].value); - } - } - - DBG (DBG_io, "%s: wrote %lu registers\n", __func__, (u_long) elems); - return status; -} - - - -/** - * writes a block of data to AHB - * @param dn USB device index - * @param usb_mode usb mode : -1, fake usb, 1 usb 1.1, 2 usb 2.0 - * @param addr AHB address to write to - * @param size size of the chunk of data - * @param data pointer to the data to write - */ -SANE_Status -sanei_genesys_write_ahb (SANE_Int dn, int usb_mode, uint32_t addr, uint32_t size, uint8_t * data) -{ - uint8_t outdata[8]; - size_t written,blksize; - SANE_Status status = SANE_STATUS_GOOD; - int i; - char msg[100]="AHB="; - - outdata[0] = addr & 0xff; - outdata[1] = ((addr >> 8) & 0xff); - outdata[2] = ((addr >> 16) & 0xff); - outdata[3] = ((addr >> 24) & 0xff); - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - if (DBG_LEVEL >= DBG_io) - { - for (i = 0; i < 8; i++) - { - sprintf (msg+strlen(msg), " 0x%02x", outdata[i]); - } - DBG (DBG_io, "%s: write(0x%08x,0x%08x)\n", __func__, addr,size); - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - /* no effective write if fake USB */ - if(usb_mode<0) - { - DBGCOMPLETED; - return status; - } - - /* write addr and size for AHB */ - status = - sanei_usb_control_msg (dn, REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, - 0x01, 8, outdata); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "sanei_genesys_write_ahb: failed while setting addr and size: %s\n", - sane_strstatus (status)); - return status; - } - - /* write actual data */ - written = 0; - do - { - if (size - written > BULKOUT_MAXSIZE) - { - blksize = BULKOUT_MAXSIZE; - } - else - { - blksize = size - written; - } - status = sanei_usb_write_bulk (dn, data + written, &blksize); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "sanei_genesys_write_ahb: failed while writing bulk data: %s\n", - sane_strstatus (status)); - return status; - } - written += blksize; - } - while (written < size); - - return status; -} - -/** @brief generates gamma buffer to transfer - * Generates gamma table buffer to send to ASIC. Applies - * contrast and brightness if set. - * @param dev device to set up - * @param bits number of bits used by gamma - * @param max value for gamma - * @param size of the gamma table - * @param gamma allocated gamma buffer to fill - * @returns SANE_STATUS_GOOD or SANE_STATUS_NO_MEM - */ -SANE_Status sanei_genesys_generate_gamma_buffer(Genesys_Device * dev, - int bits, - int max, - int size, - uint8_t *gamma) -{ - int i; - uint16_t value, *lut=NULL; - - if(dev->settings.contrast!=0 || dev->settings.brightness!=0) - { - lut=(uint16_t *)malloc(65536*2); - if(lut==NULL) - { - free(gamma); - return SANE_STATUS_NO_MEM; - } - sanei_genesys_load_lut((unsigned char *)lut, - bits, - bits, - 0, - max, - dev->settings.contrast, - dev->settings.brightness); - for (i = 0; i < size; i++) - { - value=dev->sensor.gamma_table[GENESYS_RED][i]; - value=lut[value]; - gamma[i * 2 + size * 0 + 0] = value & 0xff; - gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff; - - value=dev->sensor.gamma_table[GENESYS_GREEN][i]; - value=lut[value]; - gamma[i * 2 + size * 2 + 0] = value & 0xff; - gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff; - - value=dev->sensor.gamma_table[GENESYS_BLUE][i]; - value=lut[value]; - gamma[i * 2 + size * 4 + 0] = value & 0xff; - gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff; - } - } - else - { - for (i = 0; i < size; i++) - { - value=dev->sensor.gamma_table[GENESYS_RED][i]; - gamma[i * 2 + size * 0 + 0] = value & 0xff; - gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff; - - value=dev->sensor.gamma_table[GENESYS_GREEN][i]; - gamma[i * 2 + size * 2 + 0] = value & 0xff; - gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff; - - value=dev->sensor.gamma_table[GENESYS_BLUE][i]; - gamma[i * 2 + size * 4 + 0] = value & 0xff; - gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff; - } - } - - - if(lut!=NULL) - { - free(lut); - } - - return SANE_STATUS_GOOD; -} - - -/** @brief send gamma table to scanner - * This function sends generic gamma table (ie ones built with - * provided gamma) or the user defined one if provided by - * fontend. Used by gl846+ ASICs - * @param dev device to write to - */ -SANE_Status -sanei_genesys_send_gamma_table (Genesys_Device * dev) -{ - int size; - int i; - uint8_t *gamma, val; - SANE_Status status; - - DBGSTART; - - size = 256 + 1; - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - gamma = (uint8_t *) malloc (size * 2 * 3); - if (!gamma) - { - return SANE_STATUS_NO_MEM; - } - memset(gamma, 255, size*3*2); - - RIE(sanei_genesys_generate_gamma_buffer(dev, 16, 65535, size, gamma)); - - /* loop sending gamma tables NOTE: 0x01000000 not 0x10000000 */ - for (i = 0; i < 3; i++) - { - /* clear corresponding GMM_N bit */ - RIEF (sanei_genesys_read_register (dev, 0xbd, &val), gamma); - val &= ~(0x01 << i); - RIEF (sanei_genesys_write_register (dev, 0xbd, val), gamma); - - /* clear corresponding GMM_F bit */ - RIEF (sanei_genesys_read_register (dev, 0xbe, &val), gamma); - val &= ~(0x01 << i); - RIEF (sanei_genesys_write_register (dev, 0xbe, val), gamma); - - /* set GMM_Z */ - RIEF (sanei_genesys_write_register (dev, 0xc5+2*i, gamma[size*2*i+1]), gamma); - RIEF (sanei_genesys_write_register (dev, 0xc6+2*i, gamma[size*2*i]), gamma); - - status = sanei_genesys_write_ahb (dev->dn, dev->usb_mode, 0x01000000 + 0x200 * i, (size-1) * 2, gamma + i * size * 2+2); - if (status != SANE_STATUS_GOOD) - { - free (gamma); - DBG (DBG_error, - "%s: write to AHB failed writing table %d (%s)\n", __func__, - i, sane_strstatus (status)); - } - } - - free (gamma); - DBGCOMPLETED; - return status; -} - -/** @brief initialize device - * Initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home. Designed for gl846+ ASICs. - * Detects cold boot (ie first boot since device plugged) in this case - * an extensice setup up is done at hardware level. - * - * @param dev device to initialize - * @param max_regs umber of maximum used registers - * @return SANE_STATUS_GOOD in case of success - */ -SANE_Status -sanei_genesys_asic_init (Genesys_Device * dev, int max_regs) -{ - SANE_Status status; - uint8_t val; - SANE_Bool cold = SANE_TRUE; - int size; /**< size of the device's gamma table */ - int i; - - DBGSTART; - - /* URB 16 control 0xc0 0x0c 0x8e 0x0b len 1 read 0x00 */ - if(dev->usb_mode>=0) - { - status = sanei_usb_control_msg (dev->dn, REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_GET_REGISTER, 0x00, 1, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: request register failed %s\n", __func__, - sane_strstatus (status)); - return status; - } - DBG (DBG_io2, "%s: value=0x%02x\n", __func__, val); - DBG (DBG_info, "%s: device is %s\n", __func__, (val & 0x08) ? "USB 1.0" : "USB2.0"); - if (val & 0x08) - { - dev->usb_mode = 1; - } - else - { - dev->usb_mode = 2; - } - } - - /* setup gamma tables */ - size = 256; - for(i=0;i<3;i++) - { - FREE_IFNOT_NULL (dev->sensor.gamma_table[i]); - dev->sensor.gamma_table[i] = (uint16_t *) malloc (2 * size); - if (dev->sensor.gamma_table[i] == NULL) - { - DBG (DBG_error, "%s: could not allocate memory for gamma table %d\n", - __func__, i); - return SANE_STATUS_NO_MEM; - } - sanei_genesys_create_gamma_table (dev->sensor.gamma_table[i], - size, - 65535, - 65535, - dev->sensor.gamma[i]); - } - - /* check if the device has already been initialized and powered up - * we read register 6 and check PWRBIT, if reset scanner has been - * freshly powered up. This bit will be set to later so that following - * reads can detect power down/up cycle*/ - RIE (sanei_genesys_read_register (dev, 0x06, &val)); - /* test for POWER bit */ - if (val & 0x10) - { - cold = SANE_FALSE; - } - DBG (DBG_info, "%s: device is %s\n", __func__, cold ? "cold" : "warm"); - - /* don't do anything if backend is initialized and hardware hasn't been - * replug */ - if (dev->already_initialized && !cold) - { - DBG (DBG_info, "%s: already initialized, nothing to do\n", __func__); - return SANE_STATUS_GOOD; - } - - /* set up hardware and registers */ - RIE (dev->model->cmd_set->asic_boot (dev, cold)); - - /* now hardware part is OK, set up device struct */ - FREE_IFNOT_NULL (dev->white_average_data); - FREE_IFNOT_NULL (dev->dark_average_data); - - dev->settings.color_filter = 0; - - /* duplicate initial values into calibration registers */ - memcpy (dev->calib_reg, dev->reg, max_regs * sizeof (Genesys_Register_Set)); - - /* Set analog frontend */ - RIE (dev->model->cmd_set->set_fe (dev, AFE_INIT)); - - dev->oe_buffer.buffer = NULL; - dev->already_initialized = SANE_TRUE; - - /* Move to home if needed */ - RIE (dev->model->cmd_set->slow_back_home (dev, SANE_TRUE)); - dev->scanhead_position_in_steps = 0; - - /* Set powersaving (default = 15 minutes) */ - RIE (dev->model->cmd_set->set_powersaving (dev, 15)); - - DBGCOMPLETED; - return status; -} - -/** - * Wait for the scanning head to park - */ -SANE_Status -sanei_genesys_wait_for_home (Genesys_Device * dev) -{ - SANE_Status status; - uint8_t val; - int loop; - int max=300; - - DBGSTART; - - /* clear the parking status whatever the outcome of the function */ - dev->parking=SANE_FALSE; - - /* read initial status, if head isn't at home and motor is on - * we are parking, so we wait. - * gl847/gl124 need 2 reads for reliable results */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - return status; - } - usleep (10000); - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* if at home, return */ - if(val & HOMESNR) - { - DBG (DBG_info, - "%s: already at home\n", __func__); - return status; - } - - /* loop for 30 s max, polling home sensor */ - loop = 0; - do - { - /* wait 100 ms */ - usleep (100000); - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io2) - { - sanei_genesys_print_status (val); - } - ++loop; - } - while (loop < max && !(val & HOMESNR) && status == SANE_STATUS_GOOD); - - /* if after the timeout, head is still not parked, error out */ - if(loop >= max && !(val & HOMESNR) && status == SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to reach park position %ds\n", __func__, max/10); - return SANE_STATUS_IO_ERROR; - } - - DBGCOMPLETED; - return status; -} - -/**@brief compute hardware sensor dpi to use - * compute the sensor hardware dpi based on target resolution. - * A lower dpihw enable faster scans. - * @param dev device used for the scan - * @param xres x resolution of the scan - * @return the hardware dpi to use - */ -int sanei_genesys_compute_dpihw(Genesys_Device *dev, int xres) -{ - /* some scanners use alxways hardware dpi for sensor */ - if (dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE) - { - return dev->sensor.optical_res; - } - - /* can't be below 600 dpi */ - if (xres <= 600) - { - return 600; - } - if (xres <= dev->sensor.optical_res / 4) - { - return dev->sensor.optical_res / 4; - } - if (xres <= dev->sensor.optical_res / 2) - { - return dev->sensor.optical_res / 2; - } - return dev->sensor.optical_res; -} - -/** @brief motor profile - * search for the database of motor profiles and get the best one. Each - * profile is at full step and at a reference exposure. Use first entry - * by default. - * @param motors motor profile database - * @param motor_type motor id - * @param exposure exposure time - * @return a pointer to a Motor_Profile struct - */ -Motor_Profile *sanei_genesys_get_motor_profile(Motor_Profile *motors, int motor_type, int exposure) -{ - unsigned int i; - int idx; - - i=0; - idx=-1; - while(motors[i].exposure!=0) - { - /* exact match */ - if(motors[i].motor_type==motor_type && motors[i].exposure==exposure) - { - return &(motors[i]); - } - - /* closest match */ - if(motors[i].motor_type==motor_type) - { - /* if profile exposure is higher than the required one, - * the entry is a candidate for the closest match */ - if(motors[i].exposure>=exposure) - { - if(idx<0) - { - /* no match found yet */ - idx=i; - } - else - { - /* test for better match */ - if(motors[i].exposurestep_type; -} - -/** @brief generate slope table - * Generate the slope table to use for the scan using a reference slope - * table. - * @param slope pointer to the slope table to fill - * @param steps pointer to return used step number - * @param dpi desired motor resolution - * @param exposure exposure used - * @param base_dpi base resolution of the motor - * @param step_type step type used for scan - * @param factor shrink factor for the slope - * @param motor_type motor id - * @param motors motor profile database - */ -int sanei_genesys_slope_table(uint16_t *slope, - int *steps, - int dpi, - int exposure, - int base_dpi, - int step_type, - int factor, - int motor_type, - Motor_Profile *motors) -{ -int sum, i; -uint16_t target,current; -Motor_Profile *profile; - - /* required speed */ - target=((exposure * dpi) / base_dpi)>>step_type; - DBG (DBG_io2, "%s: exposure=%d, dpi=%d, target=%d\n", __func__, exposure, dpi, target); - - /* fill result with target speed */ - for(i=0;itable[0]; - - /* loop on profile copying and apply step type */ - while(profile->table[i]!=0 && current>=target) - { - slope[i]=current; - sum+=slope[i]; - i++; - current=profile->table[i]>>step_type; - } - - /* ensure last step is required speed in case profile doesn't contain it */ - if(current!=0 && currenttable[i]==0 && DBG_LEVEL >= DBG_warn && current>target) - { - DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too low ?\n",__func__,target); - } - if(i<3 && DBG_LEVEL >= DBG_warn) - { - DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too high ?\n",__func__,target); - } - - /* align on factor */ - while(i%factor!=0) - { - slope[i+1]=slope[i]; - sum+=slope[i]; - i++; - } - - /* ensure minimal slope size */ - while(i<2*factor) - { - slope[i+1]=slope[i]; - sum+=slope[i]; - i++; - } - - /* return used steps and acceleration sum */ - *steps=i/factor; - return sum; -} - -/** @brief returns the lowest possible ydpi for the device - * Parses device entry to find lowest motor dpi. - * @param dev device description - * @return lowest motor resolution - */ -int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev) -{ - int min=20000; - int i=0; - - while(dev->model->ydpi_values[i]!=0) - { - if(dev->model->ydpi_values[i]model->ydpi_values[i]; - } - i++; - } - return min; -} - -/** @brief returns the lowest possible dpi for the device - * Parses device entry to find lowest motor or sensor dpi. - * @param dev device description - * @return lowest motor resolution - */ -int sanei_genesys_get_lowest_dpi(Genesys_Device *dev) -{ - int min=20000; - int i=0; - - while(dev->model->ydpi_values[i]!=0) - { - if(dev->model->ydpi_values[i]model->ydpi_values[i]; - } - i++; - } - i=0; - while(dev->model->xdpi_values[i]!=0) - { - if(dev->model->xdpi_values[i]model->xdpi_values[i]; - } - i++; - } - return min; -} - -/** @brief check is a cache entry may be used - * Compares current settings with the cache entry and return - * SANE_TRUE if they are compatible. - * A calibration cache is compatible if color mode and x dpi match the user - * requested scan. In the case of CIS scanners, dpi isn't a criteria. - * flatbed cache entries are considred too old and then expires if they - * are older than the expiration time option, forcing calibration at least once - * then given time. */ -SANE_Status -sanei_genesys_is_compatible_calibration (Genesys_Device * dev, - Genesys_Calibration_Cache * cache, - int for_overwrite) -{ -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - int compatible = 1, resolution; - SANE_Status status; - - DBGSTART; - - if(dev->model->cmd_set->calculate_current_setup==NULL) - { - DBG (DBG_proc, "%s: no calculate_setup, non compatible cache\n", __func__); - return SANE_STATUS_UNSUPPORTED; - } - - status = dev->model->cmd_set->calculate_current_setup (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to calculate current setup: %s\n", __func__, - sane_strstatus (status)); - return status; - } - dev->current_setup.scan_method = dev->settings.scan_method; - - DBG (DBG_proc, "%s: checking\n", __func__); - - /* a calibration cache is compatible if color mode and x dpi match the user - * requested scan. In the case of CIS scanners, dpi isn't a criteria */ - if (dev->model->is_cis == SANE_FALSE) - { - resolution = dev->settings.xres; - if(resolution>dev->sensor.optical_res) - { - resolution=dev->sensor.optical_res; - } - compatible = (resolution == ((int) cache->used_setup.xres)); - } - else - { - resolution=sanei_genesys_compute_dpihw(dev,dev->settings.xres); - compatible = (resolution == ((int) sanei_genesys_compute_dpihw(dev,cache->used_setup.xres))); - } - DBG (DBG_io, "%s: after resolution check current compatible=%d\n", __func__, compatible); - if (dev->current_setup.half_ccd != cache->used_setup.half_ccd) - { - DBG (DBG_io, "%s: half_ccd=%d, used=%d\n", __func__, - dev->current_setup.half_ccd, cache->used_setup.half_ccd); - compatible = 0; - } - if (dev->current_setup.scan_method != cache->used_setup.scan_method) - { - DBG (DBG_io, "%s: current method=%d, used=%d\n", __func__, - dev->current_setup.scan_method, cache->used_setup.scan_method); - compatible = 0; - } - if (!compatible) - { - DBG (DBG_proc, "%s: completed, non compatible cache\n", __func__); - return SANE_STATUS_UNSUPPORTED; - } - - /* a cache entry expires after afetr expiration time for non sheetfed scanners */ - /* this is not taken into account when overwriting cache entries */ -#ifdef HAVE_SYS_TIME_H - if(for_overwrite == SANE_FALSE && dev->settings.expiration_time >=0) - { - gettimeofday (&time, NULL); - if ((time.tv_sec - cache->last_calibration > dev->settings.expiration_time*60) - && (dev->model->is_sheetfed == SANE_FALSE) - && (dev->settings.scan_method == SCAN_METHOD_FLATBED)) - { - DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __func__); - return SANE_STATUS_UNSUPPORTED; - } - } -#endif - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** @brief compute maximum line distance shift - * compute maximum line distance shift for the motor and sensor - * combination. Line distance shift is the distance between different - * color component of CCD sensors. Since these components aren't at - * the same physical place, they scan diffrent lines. Software must - * take this into account to accurately mix color data. - * @param dev device session to compute max_shift for - * @param channels number of color channels for the scan - * @param yres motor resolution used for the scan - * @param flags scan flags - * @return 0 or line distance shift - */ -int sanei_genesys_compute_max_shift(Genesys_Device *dev, - int channels, - int yres, - int flags) -{ - int max_shift; - - max_shift=0; - if (channels > 1 && !(flags & SCAN_FLAG_IGNORE_LINE_DISTANCE)) - { - max_shift = dev->ld_shift_r; - if (dev->ld_shift_b > max_shift) - max_shift = dev->ld_shift_b; - if (dev->ld_shift_g > max_shift) - max_shift = dev->ld_shift_g; - max_shift = (max_shift * yres) / dev->motor.base_ydpi; - } - return max_shift; -} - -/** @brief build lookup table for digital enhancements - * 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. - * @param lut pointer where to store the generated lut - * @param in_bits number of bits for in values - * @param out_bits number of bits of out values - * @param out_min minimal out value - * @param out_max maximal out value - * @param slope slope of the generated data - * @param offset offset of the generated data - */ -SANE_Status -sanei_genesys_load_lut (unsigned char * lut, - int in_bits, - int out_bits, - int out_min, - int out_max, - int slope, - int offset) -{ - SANE_Status ret = SANE_STATUS_GOOD; - int i, j; - double shift, rise; - int max_in_val = (1 << in_bits) - 1; - int max_out_val = (1 << out_bits) - 1; - uint8_t *lut_p8 = lut; - uint16_t *lut_p16 = (uint16_t *) lut; - - DBGSTART; - - /* slope is converted to rise per unit run: - * first [-127,127] to [-.999,.999] - * then to [-PI/4,PI/4] then [0,PI/2] - * 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 / 128 * M_PI_4 + M_PI_4) * 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; - - /* cap data to required range */ - if (j < out_min) - { - j = out_min; - } - else if (j > out_max) - { - j = out_max; - } - - /* copy result according to bit depth */ - if (out_bits <= 8) - { - *lut_p8 = j; - lut_p8++; - } - else - { - *lut_p16 = j; - lut_p16++; - } - } - - DBGCOMPLETED; - return ret; -} - -/* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc new file mode 100644 index 0000000..097375f --- /dev/null +++ b/backend/genesys_low.cc @@ -0,0 +1,2059 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_low.h" +#include "assert.h" + +#include + + +Genesys_Device::~Genesys_Device() +{ + clear(); + + if (file_name != nullptr) + free(file_name); +} + +void Genesys_Device::clear() +{ + read_buffer.clear(); + lines_buffer.clear(); + shrink_buffer.clear(); + out_buffer.clear(); + binarize_buffer.clear(); + local_buffer.clear(); + + calib_file.clear(); + + calibration_cache.clear(); + + white_average_data.clear(); + dark_average_data.clear(); +} + +/* ------------------------------------------------------------------------ */ +/* functions calling ASIC specific functions */ +/* ------------------------------------------------------------------------ */ + +/** + * setup the hardware dependent functions + */ +SANE_Status +sanei_genesys_init_cmd_set (Genesys_Device * dev) +{ + DBG_INIT (); + switch (dev->model->asic_type) + { + case GENESYS_GL646: + return sanei_gl646_init_cmd_set (dev); + case GENESYS_GL841: + return sanei_gl841_init_cmd_set (dev); + case GENESYS_GL843: + return sanei_gl843_init_cmd_set (dev); + case GENESYS_GL845: /* since only a few reg bits differs + we handle both together */ + case GENESYS_GL846: + return sanei_gl846_init_cmd_set (dev); + case GENESYS_GL847: + return sanei_gl847_init_cmd_set (dev); + case GENESYS_GL124: + return sanei_gl124_init_cmd_set (dev); + default: + return SANE_STATUS_INVAL; + } +} + +/* ------------------------------------------------------------------------ */ +/* General IO and debugging functions */ +/* ------------------------------------------------------------------------ */ + +SANE_Status sanei_genesys_write_file(const char *filename, uint8_t * data, size_t length) +{ + FILE *out; + + out = fopen (filename, "w"); + if (!out) { + DBG(DBG_error, "%s: could nor open %s for writing: %s\n", __func__, filename, + strerror(errno)); + return SANE_STATUS_INVAL; + } + fwrite(data, 1, length, out); + fclose(out); + + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; +} + +/* Write data to a pnm file (e.g. calibration). For debugging only */ +/* data is RGB or grey, with little endian byte order */ +SANE_Status +sanei_genesys_write_pnm_file (const char *filename, uint8_t * data, int depth, + int channels, int pixels_per_line, int lines) +{ + FILE *out; + int count; + + DBG(DBG_info, "%s: depth=%d, channels=%d, ppl=%d, lines=%d\n", __func__,depth, channels, + pixels_per_line, lines); + + out = fopen (filename, "w"); + if (!out) + { + DBG(DBG_error, "%s: could nor open %s for writing: %s\n", __func__, filename, + strerror(errno)); + return SANE_STATUS_INVAL; + } + if(depth==1) + { + fprintf (out, "P4\n%d\n%d\n", pixels_per_line, lines); + } + else + { + fprintf (out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', + pixels_per_line, lines, (int) pow (2, depth) - 1); + } + if (channels == 3) + { + for (count = 0; count < (pixels_per_line * lines * 3); count++) + { + if (depth == 16) + fputc (*(data + 1), out); + fputc (*(data++), out); + if (depth == 16) + data++; + } + } + else + { + if (depth==1) + { + pixels_per_line/=8; + } + for (count = 0; count < (pixels_per_line * lines); count++) + { + switch (depth) + { + case 8: + fputc (*(data + count), out); + break; + case 16: + fputc (*(data + 1), out); + fputc (*(data), out); + data += 2; + break; + default: + fputc(data[count], out); + break; + } + } + } + fclose (out); + + DBG(DBG_proc, "%s: finished\n", __func__); + return SANE_STATUS_GOOD; +} + +/* ------------------------------------------------------------------------ */ +/* Read and write RAM, registers and AFE */ +/* ------------------------------------------------------------------------ */ + +extern unsigned sanei_genesys_get_bulk_max_size(Genesys_Device * dev) +{ + /* Genesys supports 0xFE00 maximum size in general, wheraus GL646 supports + 0xFFC0. We use 0xF000 because that's the packet limit in the Linux usbmon + USB capture stack. By default it limits packet size to b_size / 5 where + b_size is the size of the ring buffer. By default it's 300*1024, so the + packet is limited 61440 without any visibility to acquiring software. + */ + if (dev->model->asic_type == GENESYS_GL124 || + dev->model->asic_type == GENESYS_GL846 || + dev->model->asic_type == GENESYS_GL847) { + return 0xeff0; + } + return 0xf000; +} + +void sanei_genesys_bulk_read_data_send_header(Genesys_Device* dev, size_t len) +{ + DBG_HELPER(dbg); + + uint8_t outdata[8]; + if (dev->model->asic_type == GENESYS_GL124 || + dev->model->asic_type == GENESYS_GL846 || + dev->model->asic_type == GENESYS_GL847) + { + // hard coded 0x10000000 address + outdata[0] = 0; + outdata[1] = 0; + outdata[2] = 0; + outdata[3] = 0x10; + } else if (dev->model->asic_type == GENESYS_GL841 || + dev->model->asic_type == GENESYS_GL843) { + outdata[0] = BULK_IN; + outdata[1] = BULK_RAM; + outdata[2] = VALUE_BUFFER & 0xff; + outdata[3] = (VALUE_BUFFER >> 8) & 0xff; + } else { + outdata[0] = BULK_IN; + outdata[1] = BULK_RAM; + outdata[2] = 0x00; + outdata[3] = 0x00; + } + + /* data size to transfer */ + outdata[4] = (len & 0xff); + outdata[5] = ((len >> 8) & 0xff); + outdata[6] = ((len >> 16) & 0xff); + outdata[7] = ((len >> 24) & 0xff); + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, + sizeof(outdata), outdata); +} + +SANE_Status sanei_genesys_bulk_read_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, + size_t len) +{ + DBG_HELPER(dbg); + + // currently supported: GL646, GL841, GL843, GL846, GL847, GL124 + size_t size, target; + uint8_t *buffer; + + unsigned is_addr_used = 1; + unsigned has_header_before_each_chunk = 0; + if (dev->model->asic_type == GENESYS_GL124 || + dev->model->asic_type == GENESYS_GL846 || + dev->model->asic_type == GENESYS_GL847) + { + is_addr_used = 0; + has_header_before_each_chunk = 1; + } + + if (is_addr_used) { + DBG(DBG_io, "%s: requesting %lu bytes from 0x%02x addr\n", __func__, (u_long) len, addr); + } else { + DBG(DBG_io, "%s: requesting %lu bytes\n", __func__, (u_long) len); + } + + if (len == 0) + return SANE_STATUS_GOOD; + + if (is_addr_used) { + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, 0x00, + 1, &addr); + } + + target = len; + buffer = data; + + size_t max_in_size = sanei_genesys_get_bulk_max_size(dev); + + if (!has_header_before_each_chunk) { + sanei_genesys_bulk_read_data_send_header(dev, len); + } + + // loop until computed data size is read + while (target) { + if (target > max_in_size) { + size = max_in_size; + } else { + size = target; + } + + if (has_header_before_each_chunk) { + sanei_genesys_bulk_read_data_send_header(dev, size); + } + + DBG(DBG_io2, "%s: trying to read %lu bytes of data\n", __func__, (u_long) size); + + dev->usb_dev.bulk_read(data, &size); + + DBG(DBG_io2, "%s: read %lu bytes, %lu remaining\n", __func__, + (u_long) size, (u_long) (target - size)); + + target -= size; + data += size; + } + + if (DBG_LEVEL >= DBG_data && dev->binary!=NULL) { + fwrite(buffer, len, 1, dev->binary); + } + + return SANE_STATUS_GOOD; +} + +SANE_Status sanei_genesys_bulk_write_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, + size_t len) +{ + DBG_HELPER(dbg); + + // supported: GL646, GL841, GL843 + size_t size; + uint8_t outdata[8]; + + DBG(DBG_io, "%s writing %lu bytes\n", __func__, (u_long) len); + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, &addr); + + + size_t max_out_size = sanei_genesys_get_bulk_max_size(dev); + + while (len) { + if (len > max_out_size) + size = max_out_size; + else + size = len; + + if (dev->model->asic_type == GENESYS_GL841) { + outdata[0] = BULK_OUT; + outdata[1] = BULK_RAM; + outdata[2] = VALUE_BUFFER & 0xff; + outdata[3] = (VALUE_BUFFER >> 8) & 0xff; + } else { + outdata[0] = BULK_OUT; + outdata[1] = BULK_RAM; + outdata[2] = 0x00; + outdata[3] = 0x00; + } + + outdata[4] = (size & 0xff); + outdata[5] = ((size >> 8) & 0xff); + outdata[6] = ((size >> 16) & 0xff); + outdata[7] = ((size >> 24) & 0xff); + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, + sizeof(outdata), outdata); + + dev->usb_dev.bulk_write(data, &size); + + DBG(DBG_io2, "%s: wrote %lu bytes, %lu remaining\n", __func__, (u_long) size, + (u_long) (len - size)); + + len -= size; + data += size; + } + + return SANE_STATUS_GOOD; +} + +/** @brief write to one high (addr >= 0x100) register + * write to a register which address is higher than 0xff. + * @param dev opened device to write to + * @param reg LSB of register address + * @param val value to write + */ +SANE_Status +sanei_genesys_write_hregister (Genesys_Device * dev, uint16_t reg, uint8_t val) +{ + DBG_HELPER(dbg); + + uint8_t buffer[2]; + + buffer[0]=reg & 0xff; + buffer[1]=val; + + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, 0x100 | VALUE_SET_REGISTER, INDEX, + 2, buffer); + + DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); + + return SANE_STATUS_GOOD; +} + +/** @brief read from one high (addr >= 0x100) register + * Read to a register which address is higher than 0xff. Second byte is check to detect + * physical link errors. + * @param dev opened device to read from + * @param reg LSB of register address + * @param val value to write + */ +SANE_Status +sanei_genesys_read_hregister (Genesys_Device * dev, uint16_t reg, uint8_t * val) +{ + DBG_HELPER(dbg); + + SANE_Byte value[2]; + + dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, 0x100 | VALUE_GET_REGISTER, + 0x22+((reg & 0xff)<<8), 2, value); + + *val=value[0]; + DBG(DBG_io2, "%s(0x%02x)=0x%02x\n", __func__, reg, *val); + + /* check usb link status */ + if((value[1] & 0xff) != 0x55) + { + DBG(DBG_error,"%s: invalid read, scanner unplugged ?\n", __func__); + return SANE_STATUS_IO_ERROR; + } + return SANE_STATUS_GOOD; +} + +/** + * Write to one GL847 ASIC register +URB 10 control 0x40 0x04 0x83 0x00 len 2 wrote 0xa6 0x04 + */ +static SANE_Status +sanei_genesys_write_gl847_register (Genesys_Device * dev, uint8_t reg, uint8_t val) +{ + DBG_HELPER(dbg); + + uint8_t buffer[2]; + + buffer[0]=reg; + buffer[1]=val; + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER, INDEX, + 2, buffer); + + DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); + + return SANE_STATUS_GOOD; +} + +/** + * Write to one ASIC register + */ +SANE_Status +sanei_genesys_write_register (Genesys_Device * dev, uint16_t reg, uint8_t val) +{ + DBG_HELPER(dbg); + + SANE_Byte reg8; + + /* 16 bit register address space */ + if(reg>255) + { + return sanei_genesys_write_hregister(dev, reg, val); + } + + /* route to gl847 function if needed */ + if(dev->model->asic_type==GENESYS_GL847 + || dev->model->asic_type==GENESYS_GL845 + || dev->model->asic_type==GENESYS_GL846 + || dev->model->asic_type==GENESYS_GL124) + { + return sanei_genesys_write_gl847_register(dev, reg, val); + } + + reg8=reg & 0xff; + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, ®8); + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_WRITE_REGISTER, INDEX, + 1, &val); + + DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); + + return SANE_STATUS_GOOD; +} + +/** + * @brief write command to 0x8c endpoint + * Write a value to 0x8c end point (end access), for USB firmware related operations + * Known values are 0x0f, 0x11 for USB 2.0 data transfer and 0x0f,0x14 for USB1.1 + * @param dev device to write to + * @param index index of the command + * @param val value to write + */ +SANE_Status +sanei_genesys_write_0x8c(Genesys_Device * dev, uint8_t index, uint8_t val) +{ + DBG_HELPER_ARGS(dbg, "0x%02x,0x%02x", index, val); + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_BUF_ENDACCESS, index, + 1, &val); + return SANE_STATUS_GOOD; +} + +/* read reg 0x41: + * URB 164 control 0xc0 0x04 0x8e 0x4122 len 2 read 0xfc 0x55 + */ +static SANE_Status +sanei_genesys_read_gl847_register (Genesys_Device * dev, uint16_t reg, uint8_t * val) +{ + DBG_HELPER(dbg); + SANE_Status status = SANE_STATUS_GOOD; + SANE_Byte value[2]; + + dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, VALUE_GET_REGISTER, 0x22+(reg<<8), + 2, value); + + *val=value[0]; + DBG(DBG_io2, "%s(0x%02x)=0x%02x\n", __func__, reg, *val); + + /* check usb link status */ + if((value[1] & 0xff) != 0x55) + { + DBG(DBG_error,"%s: invalid read, scanner unplugged ?\n", __func__); + status=SANE_STATUS_IO_ERROR; + } + return status; +} + +/* Read from one register */ +SANE_Status +sanei_genesys_read_register (Genesys_Device * dev, uint16_t reg, uint8_t * val) +{ + DBG_HELPER(dbg); + + SANE_Byte reg8; + + /* 16 bit register address space */ + if(reg>255) + { + return sanei_genesys_read_hregister(dev, reg, val); + } + + /* route to gl847 function if needed */ + if(dev->model->asic_type==GENESYS_GL847 + || dev->model->asic_type==GENESYS_GL845 + || dev->model->asic_type==GENESYS_GL846 + || dev->model->asic_type==GENESYS_GL124) + return sanei_genesys_read_gl847_register(dev, reg, val); + + /* 8 bit register address space */ + reg8=(SANE_Byte)(reg& 0Xff); + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, ®8); + + *val = 0; + + dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_READ_REGISTER, INDEX, + 1, val); + + DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, *val); + + return SANE_STATUS_GOOD; +} + +/* Set address for writing data */ +SANE_Status +sanei_genesys_set_buffer_address (Genesys_Device * dev, uint32_t addr) +{ + SANE_Status status = SANE_STATUS_GOOD; + + if(dev->model->asic_type==GENESYS_GL847 + || dev->model->asic_type==GENESYS_GL845 + || dev->model->asic_type==GENESYS_GL846 + || dev->model->asic_type==GENESYS_GL124) + { + DBG(DBG_warn, "%s: shouldn't be used for GL846+ ASICs\n", __func__); + return SANE_STATUS_GOOD; + } + + DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xfffffff0); + + addr = addr >> 4; + + status = sanei_genesys_write_register (dev, 0x2b, (addr & 0xff)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while writing low byte: %s\n", __func__, sane_strstatus(status)); + return status; + } + + addr = addr >> 8; + status = sanei_genesys_write_register (dev, 0x2a, (addr & 0xff)); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while writing high byte: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_io, "%s: completed\n", __func__); + + return status; +} + +/**@brief read data from analog frontend (AFE) + * @param dev device owning the AFE + * @param addr register address to read + * @param data placeholder for the result + * @return SANE_STATUS_GOOD is OK, else the error code + */ +SANE_Status +sanei_genesys_fe_read_data (Genesys_Device * dev, uint8_t addr, + uint16_t *data) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t value; + Genesys_Register_Set reg; + + + DBG(DBG_proc, "%s: start\n", __func__); + + reg.init_reg(0x50, addr); + + /* set up read address */ + status = dev->model->cmd_set->bulk_write_register(dev, reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while bulk writing registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + /* read data */ + RIE (sanei_genesys_read_register (dev, 0x46, &value)); + *data=256*value; + RIE (sanei_genesys_read_register (dev, 0x47, &value)); + *data+=value; + + DBG(DBG_io, "%s (0x%02x, 0x%04x)\n", __func__, addr, *data); + DBG(DBG_proc, "%s: completed\n", __func__); + + return status; +} + +/*@brief write data to analog frontend + * writes data to analog frontend to set it up accordingly + * to the sensor settings (exposure, timings, color, bit depth, ...) + * @param dev devie owning the AFE to write to + * @param addr AFE rister address + * @param data value to write to AFE register + **/ +SANE_Status +sanei_genesys_fe_write_data (Genesys_Device * dev, uint8_t addr, + uint16_t data) +{ + SANE_Status status = SANE_STATUS_GOOD; + Genesys_Register_Set reg(Genesys_Register_Set::SEQUENTIAL); + + DBG(DBG_io, "%s (0x%02x, 0x%04x)\n", __func__, addr, data); + + reg.init_reg(0x51, addr); + if (dev->model->asic_type == GENESYS_GL124) { + reg.init_reg(0x5d, (data / 256) & 0xff); + reg.init_reg(0x5e, data & 0xff); + } else { + reg.init_reg(0x3a, (data / 256) & 0xff); + reg.init_reg(0x3b, data & 0xff); + } + + status = dev->model->cmd_set->bulk_write_register(dev, reg); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed while bulk writing registers: %s\n", __func__, + sane_strstatus(status)); + return status; + } + + DBG(DBG_io, "%s: completed\n", __func__); + + return status; +} + +/* ------------------------------------------------------------------------ */ +/* Medium level functions */ +/* ------------------------------------------------------------------------ */ + +/** read the status register + */ +SANE_Status +sanei_genesys_get_status (Genesys_Device * dev, uint8_t * status) +{ + if(dev->model->asic_type==GENESYS_GL124) + return sanei_genesys_read_hregister(dev, 0x101, status); + return sanei_genesys_read_register (dev, 0x41, status); +} + +/** + * decodes and prints content of status register + * @param val value read from status register + */ +void sanei_genesys_print_status (uint8_t val) +{ + char msg[80]; + + sprintf (msg, "%s%s%s%s%s%s%s%s", + val & PWRBIT ? "PWRBIT " : "", + val & BUFEMPTY ? "BUFEMPTY " : "", + val & FEEDFSH ? "FEEDFSH " : "", + val & SCANFSH ? "SCANFSH " : "", + val & HOMESNR ? "HOMESNR " : "", + val & LAMPSTS ? "LAMPSTS " : "", + val & FEBUSY ? "FEBUSY " : "", + val & MOTORENB ? "MOTORENB" : ""); + DBG(DBG_info, "status=%s\n", msg); +} + +#if 0 +/* returns pixels per line from register set */ +/*candidate for moving into chip specific files?*/ +static int +genesys_pixels_per_line (Genesys_Register_Set * reg) +{ + int pixels_per_line; + + pixels_per_line = + sanei_genesys_read_reg_from_set (reg, + 0x32) * 256 + + sanei_genesys_read_reg_from_set (reg, 0x33); + pixels_per_line -= + (sanei_genesys_read_reg_from_set (reg, 0x30) * 256 + + sanei_genesys_read_reg_from_set (reg, 0x31)); + + return pixels_per_line; +} + +/* returns dpiset from register set */ +/*candidate for moving into chip specific files?*/ +static int +genesys_dpiset (Genesys_Register_Set * reg) +{ + int dpiset; + + dpiset = + sanei_genesys_read_reg_from_set (reg, + 0x2c) * 256 + + sanei_genesys_read_reg_from_set (reg, 0x2d); + + return dpiset; +} +#endif + +/** read the number of valid words in scanner's RAM + * ie registers 42-43-44 + */ +/*candidate for moving into chip specific files?*/ +SANE_Status +sanei_genesys_read_valid_words (Genesys_Device * dev, unsigned int *words) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t value; + + DBGSTART; + switch (dev->model->asic_type) + { + case GENESYS_GL124: + RIE (sanei_genesys_read_hregister (dev, 0x102, &value)); + *words = (value & 0x03); + RIE (sanei_genesys_read_hregister (dev, 0x103, &value)); + *words = *words * 256 + value; + RIE (sanei_genesys_read_hregister (dev, 0x104, &value)); + *words = *words * 256 + value; + RIE (sanei_genesys_read_hregister (dev, 0x105, &value)); + *words = *words * 256 + value; + break; + + case GENESYS_GL845: + case GENESYS_GL846: + RIE (sanei_genesys_read_register (dev, 0x42, &value)); + *words = (value & 0x02); + RIE (sanei_genesys_read_register (dev, 0x43, &value)); + *words = *words * 256 + value; + RIE (sanei_genesys_read_register (dev, 0x44, &value)); + *words = *words * 256 + value; + RIE (sanei_genesys_read_register (dev, 0x45, &value)); + *words = *words * 256 + value; + break; + + case GENESYS_GL847: + RIE (sanei_genesys_read_register (dev, 0x42, &value)); + *words = (value & 0x03); + RIE (sanei_genesys_read_register (dev, 0x43, &value)); + *words = *words * 256 + value; + RIE (sanei_genesys_read_register (dev, 0x44, &value)); + *words = *words * 256 + value; + RIE (sanei_genesys_read_register (dev, 0x45, &value)); + *words = *words * 256 + value; + break; + + default: + RIE (sanei_genesys_read_register (dev, 0x44, &value)); + *words = value; + RIE (sanei_genesys_read_register (dev, 0x43, &value)); + *words += (value * 256); + RIE (sanei_genesys_read_register (dev, 0x42, &value)); + if (dev->model->asic_type == GENESYS_GL646) + *words += ((value & 0x03) * 256 * 256); + else + *words += ((value & 0x0f) * 256 * 256); + } + + DBG(DBG_proc, "%s: %d words\n", __func__, *words); + DBGCOMPLETED; + return SANE_STATUS_GOOD; +} + +/** read the number of lines scanned + * ie registers 4b-4c-4d + */ +SANE_Status +sanei_genesys_read_scancnt (Genesys_Device * dev, unsigned int *words) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t value; + + DBG(DBG_proc, "%s: start\n", __func__); + + if (dev->model->asic_type == GENESYS_GL124) + { + RIE (sanei_genesys_read_hregister (dev, 0x10b, &value)); + *words = (value & 0x0f) << 16; + RIE (sanei_genesys_read_hregister (dev, 0x10c, &value)); + *words += (value << 8); + RIE (sanei_genesys_read_hregister (dev, 0x10d, &value)); + *words += value; + } + else + { + RIE (sanei_genesys_read_register (dev, 0x4d, &value)); + *words = value; + RIE (sanei_genesys_read_register (dev, 0x4c, &value)); + *words += (value * 256); + RIE (sanei_genesys_read_register (dev, 0x4b, &value)); + if (dev->model->asic_type == GENESYS_GL646) + *words += ((value & 0x03) * 256 * 256); + else + *words += ((value & 0x0f) * 256 * 256); + } + + DBG(DBG_proc, "%s: %d lines\n", __func__, *words); + return SANE_STATUS_GOOD; +} + +/** @brief Check if the scanner's internal data buffer is empty + * @param *dev device to test for data + * @param *empty return value + * @return empty will be set to SANE_TRUE if there is no scanned data. + **/ +SANE_Status +sanei_genesys_test_buffer_empty (Genesys_Device * dev, SANE_Bool * empty) +{ + uint8_t val = 0; + SANE_Status status = SANE_STATUS_GOOD; + + sanei_genesys_sleep_ms(1); + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: failed to read buffer status: %s\n", __func__, sane_strstatus(status)); + return status; + } + + if (dev->model->cmd_set->test_buffer_empty_bit (val)) + { + /* fix timing issue on USB3 (or just may be too fast) hardware + * spotted by John S. Weber + */ + sanei_genesys_sleep_ms(1); + DBG(DBG_io2, "%s: buffer is empty\n", __func__); + *empty = SANE_TRUE; + return SANE_STATUS_GOOD; + } + + *empty = SANE_FALSE; + + DBG(DBG_io, "%s: buffer is filled\n", __func__); + return SANE_STATUS_GOOD; +} + + +/* Read data (e.g scanned image) from scan buffer */ +SANE_Status +sanei_genesys_read_data_from_scanner (Genesys_Device * dev, uint8_t * data, + size_t size) +{ + SANE_Status status = SANE_STATUS_GOOD; + int time_count = 0; + unsigned int words = 0; + + DBG(DBG_proc, "%s (size = %lu bytes)\n", __func__, (u_long) size); + + if (size & 1) + DBG(DBG_info, "WARNING %s: odd number of bytes\n", __func__); + + /* wait until buffer not empty for up to 5 seconds */ + do + { + status = sanei_genesys_read_valid_words (dev, &words); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: checking for empty buffer failed: %s\n", __func__, + sane_strstatus(status)); + return status; + } + if (words == 0) + { + sanei_genesys_sleep_ms(10); + time_count++; + } + } + while ((time_count < 2500*2) && (words == 0)); + + if (words == 0) /* timeout, buffer does not get filled */ + { + DBG(DBG_error, "%s: timeout, buffer does not get filled\n", __func__); + return SANE_STATUS_IO_ERROR; + } + + status = dev->model->cmd_set->bulk_read_data (dev, 0x45, data, size); + if (status != SANE_STATUS_GOOD) + { + DBG(DBG_error, "%s: reading bulk data failed: %s\n", __func__, sane_strstatus(status)); + return status; + } + + DBG(DBG_proc, "%s: completed\n", __func__); + return SANE_STATUS_GOOD; +} +SANE_Status +sanei_genesys_read_feed_steps (Genesys_Device * dev, unsigned int *steps) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t value; + + DBG(DBG_proc, "%s\n", __func__); + + if (dev->model->asic_type == GENESYS_GL124) + { + RIE (sanei_genesys_read_hregister (dev, 0x108, &value)); + *steps = (value & 0x1f) << 16; + RIE (sanei_genesys_read_hregister (dev, 0x109, &value)); + *steps += (value << 8); + RIE (sanei_genesys_read_hregister (dev, 0x10a, &value)); + *steps += value; + } + else + { + RIE (sanei_genesys_read_register (dev, 0x4a, &value)); + *steps = value; + RIE (sanei_genesys_read_register (dev, 0x49, &value)); + *steps += (value * 256); + RIE (sanei_genesys_read_register (dev, 0x48, &value)); + if (dev->model->asic_type == GENESYS_GL646) + *steps += ((value & 0x03) * 256 * 256); + else if (dev->model->asic_type == GENESYS_GL841) + *steps += ((value & 0x0f) * 256 * 256); + else + *steps += ((value & 0x1f) * 256 * 256); + } + + DBG(DBG_proc, "%s: %d steps\n", __func__, *steps); + return SANE_STATUS_GOOD; +} + +void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, bool set) +{ + static const uint8_t REG03_LAMPPWR = 0x10; + + if (set) { + regs.find_reg(0x03).value |= REG03_LAMPPWR; + + if (dev->model->asic_type == GENESYS_GL841) { + sanei_genesys_set_exposure(regs, sanei_genesys_fixup_exposure(sensor.exposure)); + regs.set8(0x19, 0x50); + } + + if (dev->model->asic_type == GENESYS_GL843) { + sanei_genesys_set_exposure(regs, sensor.exposure); + } + } else { + regs.find_reg(0x03).value &= ~REG03_LAMPPWR; + + if (dev->model->asic_type == GENESYS_GL841) { + sanei_genesys_set_exposure(regs, {0x0101, 0x0101, 0x0101}); + regs.set8(0x19, 0xff); + } + + if (dev->model->asic_type == GENESYS_GL843) { + if (dev->model->model_id != MODEL_CANON_CANOSCAN_8600F) { + // BUG: datasheet says we shouldn't set exposure to zero + sanei_genesys_set_exposure(regs, {0, 0, 0}); + } + } + } + regs.state.is_lamp_on = set; +} + +void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set) +{ + static const uint8_t REG02_MTRPWR = 0x10; + + if (set) { + regs.find_reg(0x02).value |= REG02_MTRPWR; + } else { + regs.find_reg(0x02).value &= ~REG02_MTRPWR; + } +} + +/** + * Write to many registers at once + * Note: sequential call to write register, no effective + * bulk write implemented. + * @param dev device to write to + * @param reg pointer to an array of registers + * @param elems size of the array + */ +SANE_Status sanei_genesys_bulk_write_register(Genesys_Device * dev, Genesys_Register_Set& reg) +{ + DBG_HELPER(dbg); + + SANE_Status status = SANE_STATUS_GOOD; + + if (dev->model->asic_type == GENESYS_GL646 || + dev->model->asic_type == GENESYS_GL841) + { + uint8_t outdata[8]; + std::vector buffer; + buffer.reserve(reg.size() * 2); + + /* copy registers and values in data buffer */ + for (const auto& r : reg) { + buffer.push_back(r.address); + buffer.push_back(r.value); + } + + DBG(DBG_io, "%s (elems= %lu, size = %lu)\n", __func__, (u_long) reg.size(), + (u_long) buffer.size()); + + if (dev->model->asic_type == GENESYS_GL646) { + outdata[0] = BULK_OUT; + outdata[1] = BULK_REGISTER; + outdata[2] = 0x00; + outdata[3] = 0x00; + outdata[4] = (buffer.size() & 0xff); + outdata[5] = ((buffer.size() >> 8) & 0xff); + outdata[6] = ((buffer.size() >> 16) & 0xff); + outdata[7] = ((buffer.size() >> 24) & 0xff); + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, INDEX, + sizeof(outdata), outdata); + + size_t write_size = buffer.size(); + + dev->usb_dev.bulk_write(buffer.data(), &write_size); + } else { + for (size_t i = 0; i < reg.size();) { + size_t c = reg.size() - i; + if (c > 32) /*32 is max on GL841. checked that.*/ + c = 32; + + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER, + INDEX, c * 2, buffer.data() + i * 2); + + i += c; + } + } + } else { + for (const auto& r : reg) { + status = sanei_genesys_write_register (dev, r.address, r.value); + if (status != SANE_STATUS_GOOD) + return status; + } + } + + DBG (DBG_io, "%s: wrote %lu registers\n", __func__, (u_long) reg.size()); + return status; +} + + + +/** + * writes a block of data to AHB + * @param dn USB device index + * @param usb_mode usb mode : 1 usb 1.1, 2 usb 2.0 + * @param addr AHB address to write to + * @param size size of the chunk of data + * @param data pointer to the data to write + */ +SANE_Status +sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t size, uint8_t * data) +{ + DBG_HELPER(dbg); + + uint8_t outdata[8]; + size_t written,blksize; + SANE_Status status = SANE_STATUS_GOOD; + int i; + char msg[100]="AHB="; + + outdata[0] = addr & 0xff; + outdata[1] = ((addr >> 8) & 0xff); + outdata[2] = ((addr >> 16) & 0xff); + outdata[3] = ((addr >> 24) & 0xff); + outdata[4] = (size & 0xff); + outdata[5] = ((size >> 8) & 0xff); + outdata[6] = ((size >> 16) & 0xff); + outdata[7] = ((size >> 24) & 0xff); + + if (DBG_LEVEL >= DBG_io) + { + for (i = 0; i < 8; i++) + { + sprintf (msg+strlen(msg), " 0x%02x", outdata[i]); + } + DBG (DBG_io, "%s: write(0x%08x,0x%08x)\n", __func__, addr,size); + DBG (DBG_io, "%s: %s\n", __func__, msg); + } + + // write addr and size for AHB + dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x01, 8, outdata); + + size_t max_out_size = sanei_genesys_get_bulk_max_size(dev); + + /* write actual data */ + written = 0; + do + { + if (size - written > max_out_size) + { + blksize = max_out_size; + } + else + { + blksize = size - written; + } + dev->usb_dev.bulk_write(data + written, &blksize); + + written += blksize; + } + while (written < size); + + return status; +} + + +std::vector get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, + int color) +{ + if (!dev->gamma_override_tables[color].empty()) { + return dev->gamma_override_tables[color]; + } else { + std::vector ret; + sanei_genesys_create_default_gamma_table(dev, ret, sensor.gamma[color]); + return ret; + } +} + +/** @brief generates gamma buffer to transfer + * Generates gamma table buffer to send to ASIC. Applies + * contrast and brightness if set. + * @param dev device to set up + * @param bits number of bits used by gamma + * @param max value for gamma + * @param size of the gamma table + * @param gamma allocated gamma buffer to fill + * @returns SANE_STATUS_GOOD or SANE_STATUS_NO_MEM + */ +SANE_Status sanei_genesys_generate_gamma_buffer(Genesys_Device * dev, + const Genesys_Sensor& sensor, + int bits, + int max, + int size, + uint8_t *gamma) +{ + std::vector rgamma = get_gamma_table(dev, sensor, GENESYS_RED); + std::vector ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN); + std::vector bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE); + + if(dev->settings.contrast!=0 || dev->settings.brightness!=0) + { + std::vector lut(65536); + sanei_genesys_load_lut((unsigned char *)lut.data(), + bits, + bits, + 0, + max, + dev->settings.contrast, + dev->settings.brightness); + for (int i = 0; i < size; i++) + { + uint16_t value=rgamma[i]; + value=lut[value]; + gamma[i * 2 + size * 0 + 0] = value & 0xff; + gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff; + + value=ggamma[i]; + value=lut[value]; + gamma[i * 2 + size * 2 + 0] = value & 0xff; + gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff; + + value=bgamma[i]; + value=lut[value]; + gamma[i * 2 + size * 4 + 0] = value & 0xff; + gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff; + } + } + else + { + for (int i = 0; i < size; i++) + { + uint16_t value=rgamma[i]; + gamma[i * 2 + size * 0 + 0] = value & 0xff; + gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff; + + value=ggamma[i]; + gamma[i * 2 + size * 2 + 0] = value & 0xff; + gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff; + + value=bgamma[i]; + gamma[i * 2 + size * 4 + 0] = value & 0xff; + gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff; + } + } + + return SANE_STATUS_GOOD; +} + + +/** @brief send gamma table to scanner + * This function sends generic gamma table (ie ones built with + * provided gamma) or the user defined one if provided by + * fontend. Used by gl846+ ASICs + * @param dev device to write to + */ +SANE_Status +sanei_genesys_send_gamma_table(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int size; + int i; + uint8_t val; + SANE_Status status = SANE_STATUS_GOOD; + + DBGSTART; + + size = 256 + 1; + + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3, 255); + + RIE(sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data())); + + /* loop sending gamma tables NOTE: 0x01000000 not 0x10000000 */ + for (i = 0; i < 3; i++) + { + /* clear corresponding GMM_N bit */ + RIE(sanei_genesys_read_register(dev, 0xbd, &val)); + val &= ~(0x01 << i); + RIE(sanei_genesys_write_register(dev, 0xbd, val)); + + /* clear corresponding GMM_F bit */ + RIE(sanei_genesys_read_register(dev, 0xbe, &val)); + val &= ~(0x01 << i); + RIE(sanei_genesys_write_register(dev, 0xbe, val)); + + // FIXME: currently the last word of each gamma table is not initialied, so to work around + // unstable data, just set it to 0 which is the most likely value of uninitialized memory + // (proper value is probably 0xff) + gamma[size * 2 * i + size * 2 - 2] = 0; + gamma[size * 2 * i + size * 2 - 1] = 0; + + /* set GMM_Z */ + RIE(sanei_genesys_write_register (dev, 0xc5+2*i, gamma[size*2*i+1])); + RIE(sanei_genesys_write_register (dev, 0xc6+2*i, gamma[size*2*i])); + + status = sanei_genesys_write_ahb(dev, 0x01000000 + 0x200 * i, (size-1) * 2, gamma.data() + i * size * 2+2); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: write to AHB failed writing table %d (%s)\n", __func__, + i, sane_strstatus (status)); + break; + } + } + + DBGCOMPLETED; + return status; +} + +/** @brief initialize device + * Initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home. Designed for gl846+ ASICs. + * Detects cold boot (ie first boot since device plugged) in this case + * an extensice setup up is done at hardware level. + * + * @param dev device to initialize + * @param max_regs umber of maximum used registers + * @return SANE_STATUS_GOOD in case of success + */ +SANE_Status +sanei_genesys_asic_init(Genesys_Device* dev, int /*max_regs*/) +{ + DBG_HELPER(dbg); + + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + SANE_Bool cold = SANE_TRUE; + + DBGSTART; + + // URB 16 control 0xc0 0x0c 0x8e 0x0b len 1 read 0x00 */ + dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_GET_REGISTER, 0x00, 1, &val); + + DBG (DBG_io2, "%s: value=0x%02x\n", __func__, val); + DBG (DBG_info, "%s: device is %s\n", __func__, (val & 0x08) ? "USB 1.0" : "USB2.0"); + if (val & 0x08) + { + dev->usb_mode = 1; + } + else + { + dev->usb_mode = 2; + } + + /* check if the device has already been initialized and powered up + * we read register 6 and check PWRBIT, if reset scanner has been + * freshly powered up. This bit will be set to later so that following + * reads can detect power down/up cycle*/ + RIE (sanei_genesys_read_register (dev, 0x06, &val)); + /* test for POWER bit */ + if (val & 0x10) + { + cold = SANE_FALSE; + } + DBG (DBG_info, "%s: device is %s\n", __func__, cold ? "cold" : "warm"); + + /* don't do anything if backend is initialized and hardware hasn't been + * replug */ + if (dev->already_initialized && !cold) + { + DBG (DBG_info, "%s: already initialized, nothing to do\n", __func__); + return SANE_STATUS_GOOD; + } + + /* set up hardware and registers */ + RIE (dev->model->cmd_set->asic_boot (dev, cold)); + + /* now hardware part is OK, set up device struct */ + dev->white_average_data.clear(); + dev->dark_average_data.clear(); + + dev->settings.color_filter = ColorFilter::RED; + + /* duplicate initial values into calibration registers */ + dev->calib_reg = dev->reg; + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + /* Set analog frontend */ + RIE (dev->model->cmd_set->set_fe(dev, sensor, AFE_INIT)); + + dev->already_initialized = SANE_TRUE; + + /* Move to home if needed */ + RIE (dev->model->cmd_set->slow_back_home (dev, SANE_TRUE)); + dev->scanhead_position_in_steps = 0; + + /* Set powersaving (default = 15 minutes) */ + RIE (dev->model->cmd_set->set_powersaving (dev, 15)); + + return status; +} + +/** + * Wait for the scanning head to park + */ +SANE_Status +sanei_genesys_wait_for_home (Genesys_Device * dev) +{ + SANE_Status status = SANE_STATUS_GOOD; + uint8_t val; + int loop; + int max=300; + + DBGSTART; + + /* clear the parking status whatever the outcome of the function */ + dev->parking=SANE_FALSE; + + /* read initial status, if head isn't at home and motor is on + * we are parking, so we wait. + * gl847/gl124 need 2 reads for reliable results */ + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus (status)); + return status; + } + sanei_genesys_sleep_ms(10); + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus (status)); + return status; + } + + /* if at home, return */ + if(val & HOMESNR) + { + DBG (DBG_info, + "%s: already at home\n", __func__); + return status; + } + + /* loop for 30 s max, polling home sensor */ + loop = 0; + do + { + sanei_genesys_sleep_ms(100); + status = sanei_genesys_get_status (dev, &val); + if (status != SANE_STATUS_GOOD) + { + DBG (DBG_error, + "%s: failed to read home sensor: %s\n", __func__, + sane_strstatus (status)); + return status; + } + if (DBG_LEVEL >= DBG_io2) + { + sanei_genesys_print_status (val); + } + ++loop; + } + while (loop < max && !(val & HOMESNR) && status == SANE_STATUS_GOOD); + + /* if after the timeout, head is still not parked, error out */ + if(loop >= max && !(val & HOMESNR) && status == SANE_STATUS_GOOD) + { + DBG (DBG_error, "%s: failed to reach park position %ds\n", __func__, max/10); + return SANE_STATUS_IO_ERROR; + } + + DBGCOMPLETED; + return status; +} + +/**@brief compute hardware sensor dpi to use + * compute the sensor hardware dpi based on target resolution. + * A lower dpihw enable faster scans. + * @param dev device used for the scan + * @param xres x resolution of the scan + * @return the hardware dpi to use + */ +int sanei_genesys_compute_dpihw(Genesys_Device *dev, const Genesys_Sensor& sensor, int xres) +{ + /* some scanners use always hardware dpi for sensor */ + if (dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE) + { + return sensor.optical_res; + } + + /* can't be below 600 dpi */ + if (xres <= 600) + { + return 600; + } + if (xres <= sensor.optical_res / 4) + { + return sensor.optical_res / 4; + } + if (xres <= sensor.optical_res / 2) + { + return sensor.optical_res / 2; + } + return sensor.optical_res; +} + +// sanei_genesys_compute_dpihw returns the dpihw that is written to register. +// However the number of pixels depends on half_ccd mode +int sanei_genesys_compute_dpihw_calibration(Genesys_Device *dev, const Genesys_Sensor& sensor, + int xres) +{ + if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) + { + // real resolution is half of the "official" resolution - half_ccd mode + int hwres = sensor.optical_res / sensor.get_ccd_size_divisor_for_dpi(xres); + + if (xres <= hwres / 4) + { + return hwres / 4; + } + if (xres <= hwres / 2) + { + return hwres / 2; + } + return hwres; + } + + return sanei_genesys_compute_dpihw(dev, sensor, xres); +} + +/** @brief motor profile + * search for the database of motor profiles and get the best one. Each + * profile is at full step and at a reference exposure. Use first entry + * by default. + * @param motors motor profile database + * @param motor_type motor id + * @param exposure exposure time + * @return a pointer to a Motor_Profile struct + */ +Motor_Profile *sanei_genesys_get_motor_profile(Motor_Profile *motors, int motor_type, int exposure) +{ + unsigned int i; + int idx; + + i=0; + idx=-1; + while(motors[i].exposure!=0) + { + /* exact match */ + if(motors[i].motor_type==motor_type && motors[i].exposure==exposure) + { + return &(motors[i]); + } + + /* closest match */ + if(motors[i].motor_type==motor_type) + { + /* if profile exposure is higher than the required one, + * the entry is a candidate for the closest match */ + if(motors[i].exposure>=exposure) + { + if(idx<0) + { + /* no match found yet */ + idx=i; + } + else + { + /* test for better match */ + if(motors[i].exposurestep_type; +} + +/** @brief generate slope table + * Generate the slope table to use for the scan using a reference slope + * table. + * @param slope pointer to the slope table to fill + * @param steps pointer to return used step number + * @param dpi desired motor resolution + * @param exposure exposure used + * @param base_dpi base resolution of the motor + * @param step_type step type used for scan + * @param factor shrink factor for the slope + * @param motor_type motor id + * @param motors motor profile database + */ +int sanei_genesys_slope_table(uint16_t *slope, + int *steps, + int dpi, + int exposure, + int base_dpi, + int step_type, + int factor, + int motor_type, + Motor_Profile *motors) +{ +int sum, i; +uint16_t target,current; +Motor_Profile *profile; + + /* required speed */ + target=((exposure * dpi) / base_dpi)>>step_type; + DBG (DBG_io2, "%s: exposure=%d, dpi=%d, target=%d\n", __func__, exposure, dpi, target); + + /* fill result with target speed */ + for(i=0;itable[0]; + + /* loop on profile copying and apply step type */ + while(profile->table[i]!=0 && current>=target) + { + slope[i]=current; + sum+=slope[i]; + i++; + current=profile->table[i]>>step_type; + } + + /* ensure last step is required speed in case profile doesn't contain it */ + if(current!=0 && currenttable[i]==0 && DBG_LEVEL >= DBG_warn && current>target) + { + DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too low ?\n",__func__,target); + } + if(i<3 && DBG_LEVEL >= DBG_warn) + { + DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too high ?\n",__func__,target); + } + + /* align on factor */ + while(i%factor!=0) + { + slope[i+1]=slope[i]; + sum+=slope[i]; + i++; + } + + /* ensure minimal slope size */ + while(i<2*factor) + { + slope[i+1]=slope[i]; + sum+=slope[i]; + i++; + } + + // return used steps and taken time + *steps=i/factor; + return sum; +} + +/** @brief returns the lowest possible ydpi for the device + * Parses device entry to find lowest motor dpi. + * @param dev device description + * @return lowest motor resolution + */ +int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev) +{ + int min=20000; + int i=0; + + while(dev->model->ydpi_values[i]!=0) + { + if(dev->model->ydpi_values[i]model->ydpi_values[i]; + } + i++; + } + return min; +} + +/** @brief returns the lowest possible dpi for the device + * Parses device entry to find lowest motor or sensor dpi. + * @param dev device description + * @return lowest motor resolution + */ +int sanei_genesys_get_lowest_dpi(Genesys_Device *dev) +{ + int min=20000; + int i=0; + + while(dev->model->ydpi_values[i]!=0) + { + if(dev->model->ydpi_values[i]model->ydpi_values[i]; + } + i++; + } + i=0; + while(dev->model->xdpi_values[i]!=0) + { + if(dev->model->xdpi_values[i]model->xdpi_values[i]; + } + i++; + } + return min; +} + +/** @brief check is a cache entry may be used + * Compares current settings with the cache entry and return + * SANE_TRUE if they are compatible. + * A calibration cache is compatible if color mode and x dpi match the user + * requested scan. In the case of CIS scanners, dpi isn't a criteria. + * flatbed cache entries are considred too old and then expires if they + * are older than the expiration time option, forcing calibration at least once + * then given time. */ +bool sanei_genesys_is_compatible_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Calibration_Cache * cache, int for_overwrite) +{ +#ifdef HAVE_SYS_TIME_H + struct timeval time; +#endif + int compatible = 1, resolution; + + DBGSTART; + + if(dev->model->cmd_set->calculate_current_setup==NULL) + { + DBG (DBG_proc, "%s: no calculate_setup, non compatible cache\n", __func__); + return false; + } + + dev->model->cmd_set->calculate_current_setup(dev, sensor); + + DBG (DBG_proc, "%s: checking\n", __func__); + + /* a calibration cache is compatible if color mode and x dpi match the user + * requested scan. In the case of CIS scanners, dpi isn't a criteria */ + if (dev->model->is_cis == SANE_FALSE) + { + resolution = dev->settings.xres; + if(resolution>sensor.optical_res) + { + resolution=sensor.optical_res; + } + compatible = (resolution == ((int) cache->used_setup.xres)); + } + else + { + resolution=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); + compatible = (resolution == ((int) sanei_genesys_compute_dpihw(dev, sensor,cache->used_setup.xres))); + } + DBG (DBG_io, "%s: after resolution check current compatible=%d\n", __func__, compatible); + if (dev->current_setup.ccd_size_divisor != cache->used_setup.ccd_size_divisor) + { + DBG (DBG_io, "%s: half_ccd=%d, used=%d\n", __func__, + dev->current_setup.ccd_size_divisor, cache->used_setup.ccd_size_divisor); + compatible = 0; + } + if (dev->current_setup.params.scan_method != cache->used_setup.params.scan_method) + { + DBG (DBG_io, "%s: current method=%d, used=%d\n", __func__, + static_cast(dev->current_setup.params.scan_method), + static_cast(cache->used_setup.params.scan_method)); + compatible = 0; + } + if (!compatible) + { + DBG (DBG_proc, "%s: completed, non compatible cache\n", __func__); + return false; + } + + /* a cache entry expires after afetr expiration time for non sheetfed scanners */ + /* this is not taken into account when overwriting cache entries */ +#ifdef HAVE_SYS_TIME_H + if(for_overwrite == SANE_FALSE && dev->settings.expiration_time >=0) + { + gettimeofday (&time, NULL); + if ((time.tv_sec - cache->last_calibration > dev->settings.expiration_time*60) + && (dev->model->is_sheetfed == SANE_FALSE) + && (dev->settings.scan_method == ScanMethod::FLATBED)) + { + DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __func__); + return false; + } + } +#endif + + DBGCOMPLETED; + return true; +} + + +/** @brief compute maximum line distance shift + * compute maximum line distance shift for the motor and sensor + * combination. Line distance shift is the distance between different + * color component of CCD sensors. Since these components aren't at + * the same physical place, they scan diffrent lines. Software must + * take this into account to accurately mix color data. + * @param dev device session to compute max_shift for + * @param channels number of color channels for the scan + * @param yres motor resolution used for the scan + * @param flags scan flags + * @return 0 or line distance shift + */ +int sanei_genesys_compute_max_shift(Genesys_Device *dev, + int channels, + int yres, + int flags) +{ + int max_shift; + + max_shift=0; + if (channels > 1 && !(flags & SCAN_FLAG_IGNORE_LINE_DISTANCE)) + { + max_shift = dev->ld_shift_r; + if (dev->ld_shift_b > max_shift) + max_shift = dev->ld_shift_b; + if (dev->ld_shift_g > max_shift) + max_shift = dev->ld_shift_g; + max_shift = (max_shift * yres) / dev->motor.base_ydpi; + } + return max_shift; +} + +/** @brief build lookup table for digital enhancements + * 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. + * @param lut pointer where to store the generated lut + * @param in_bits number of bits for in values + * @param out_bits number of bits of out values + * @param out_min minimal out value + * @param out_max maximal out value + * @param slope slope of the generated data + * @param offset offset of the generated data + */ +SANE_Status +sanei_genesys_load_lut (unsigned char * lut, + int in_bits, + int out_bits, + int out_min, + int out_max, + int slope, + int offset) +{ + SANE_Status ret = SANE_STATUS_GOOD; + int i, j; + double shift, rise; + int max_in_val = (1 << in_bits) - 1; + int max_out_val = (1 << out_bits) - 1; + uint8_t *lut_p8 = lut; + uint16_t *lut_p16 = (uint16_t *) lut; + + DBGSTART; + + /* slope is converted to rise per unit run: + * first [-127,127] to [-.999,.999] + * then to [-PI/4,PI/4] then [0,PI/2] + * 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 / 128 * M_PI_4 + M_PI_4) * 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; + + /* cap data to required range */ + if (j < out_min) + { + j = out_min; + } + else if (j > out_max) + { + j = out_max; + } + + /* copy result according to bit depth */ + if (out_bits <= 8) + { + *lut_p8 = j; + lut_p8++; + } + else + { + *lut_p16 = j; + lut_p16++; + } + } + + DBGCOMPLETED; + return ret; +} + +void sanei_genesys_usleep(unsigned int useconds) +{ + usleep(useconds); +} + +void sanei_genesys_sleep_ms(unsigned int milliseconds) +{ + sanei_genesys_usleep(milliseconds * 1000); +} + +static std::unique_ptr>> s_functions_run_at_backend_exit; + +void add_function_to_run_at_backend_exit(std::function function) +{ + if (!s_functions_run_at_backend_exit) + s_functions_run_at_backend_exit.reset(new std::vector>()); + s_functions_run_at_backend_exit->push_back(std::move(function)); +} + +void run_functions_at_backend_exit() +{ + for (auto it = s_functions_run_at_backend_exit->rbegin(); + it != s_functions_run_at_backend_exit->rend(); ++it) + { + (*it)(); + } + s_functions_run_at_backend_exit.release(); +} + +void debug_dump(unsigned level, const Genesys_Settings& settings) +{ + DBG(level, "settings:\n" + "Resolution X/Y : %u / %u dpi\n" + "Lines : %u\n" + "Pixels per line : %u\n" + "Depth : %u\n" + "Start position X/Y : %.3f/%.3f\n" + "Scan mode : %d\n\n", + settings.xres, settings.yres, + settings.lines, settings.pixels, settings.depth, + settings.tl_x, settings.tl_y, + static_cast(settings.scan_mode)); +} + +void debug_dump(unsigned level, const SetupParams& params) +{ + DBG(level, "settings:\n" + "Resolution X/Y : %u / %u dpi\n" + "Lines : %u\n" + "Pixels per line : %u\n" + "Depth : %u\n" + "Channels : %u\n" + "Start position X/Y : %g / %g\n" + "Scan mode : %d\n" + "Color filter : %d\n" + "Flags : %x\n", + params.xres, params.yres, + params.lines, params.pixels, + params.depth, params.channels, + params.startx, params.starty, + static_cast(params.scan_mode), + static_cast(params.color_filter), + params.flags); +} + +void debug_dump(unsigned level, const Genesys_Current_Setup& setup) +{ + DBG(level, "current_setup:\n" + "Pixels: %d\n" + "Lines: %d\n" + "Depth: %d\n" + "Channels: %d\n" + "exposure_time: %d\n" + "Resolution X/Y: %g %g\n" + "ccd_size_divisor: %d\n" + "stagger: %d\n" + "max_shift: %d\n", + setup.pixels, + setup.lines, + setup.depth, + setup.channels, + setup.exposure_time, + setup.xres, setup.yres, + setup.ccd_size_divisor, + setup.stagger, + setup.max_shift); +} diff --git a/backend/genesys_low.h b/backend/genesys_low.h index 56627b4..e750808 100644 --- a/backend/genesys_low.h +++ b/backend/genesys_low.h @@ -1,4 +1,4 @@ -/* sane - Scanner Access Now Easy. +/* sane - Scanner Access Now Easy. Copyright (C) 2003 Oliver Rauch Copyright (C) 2003, 2004 Henning Meier-Geinitz @@ -81,56 +81,20 @@ #include "../include/_stdint.h" -#ifndef UNIT_TESTING -#define GENESYS_STATIC static -#else -#define GENESYS_STATIC -#endif - -#define DBG_error0 0 /* errors/warnings printed even with devuglevel 0 */ -#define DBG_error 1 /* fatal errors */ -#define DBG_init 2 /* initialization and scanning time messages */ -#define DBG_warn 3 /* warnings and non-fatal errors */ -#define DBG_info 4 /* informational messages */ -#define DBG_proc 5 /* starting/finishing functions */ -#define DBG_io 6 /* io functions */ -#define DBG_io2 7 /* io functions that are called very often */ -#define DBG_data 8 /* log image data */ - -/** - * call a function and return on error - */ -#define RIE(function) \ - do { status = function; \ - if (status != SANE_STATUS_GOOD) \ - { \ - DBG(DBG_error, "%s: %s\n", __func__, sane_strstatus (status)); \ - return status; \ - } \ - } while (SANE_FALSE) - -#define RIEF(function, mem) \ - do { status = function; \ - if (status != SANE_STATUS_GOOD) \ - { \ - free(mem); \ - DBG(DBG_error, "%s: %s\n", __func__, sane_strstatus (status)); \ - return status; \ - } \ - } while (SANE_FALSE) - -#define RIEF2(function, mem1, mem2) \ - do { status = function; \ - if (status != SANE_STATUS_GOOD) \ - { \ - free(mem1); \ - free(mem2); \ - return status; \ - } \ - } while (SANE_FALSE) - -#define DBGSTART DBG (DBG_proc, "%s start\n", __func__); -#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __func__); +#include "genesys_error.h" +#include "genesys_sanei.h" +#include "genesys_serialize.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #define FREE_IFNOT_NULL(x) if(x!=NULL) { free(x); x=NULL;} @@ -163,11 +127,12 @@ #define GENESYS_FLAG_DARK_WHITE_CALIBRATION (1 << 12) /**< yet another calibration method. does white and dark shading in one run, depending on a black and a white strip*/ #define GENESYS_FLAG_CUSTOM_GAMMA (1 << 13) /**< allow custom gamma tables */ #define GENESYS_FLAG_NO_CALIBRATION (1 << 14) /**< allow scanners to use skip the calibration, needed for sheetfed scanners */ -#define GENESYS_FLAG_HALF_CCD_MODE (1 << 15) /**< scanner has setting for half ccd mode */ #define GENESYS_FLAG_SIS_SENSOR (1 << 16) /**< handling of multi-segments sensors in software */ #define GENESYS_FLAG_SHADING_NO_MOVE (1 << 17) /**< scanner doesn't move sensor during shading calibration */ #define GENESYS_FLAG_SHADING_REPARK (1 << 18) /**< repark head between shading scans */ #define GENESYS_FLAG_FULL_HWDPI_MODE (1 << 19) /**< scanner always use maximum hw dpi to setup the sensor */ +// scanner has infrared transparency scanning capability +#define GENESYS_FLAG_HAS_UTA_INFRARED (1 << 20) #define GENESYS_HAS_NO_BUTTONS 0 /**< scanner has no supported button */ #define GENESYS_HAS_SCAN_SW (1 << 0) /**< scanner has SCAN button */ @@ -207,9 +172,6 @@ #define BULK_RAM 0x00 #define BULK_REGISTER 0x11 -#define BULKIN_MAXSIZE 0xFE00 -#define GL646_BULKIN_MAXSIZE 0xFFC0 -#define GL646_BULKIN_MINSIZE 0x0800 #define BULKOUT_MAXSIZE 0xF000 /* AFE values */ @@ -236,77 +198,619 @@ #define FEBUSY 0x02 #define MOTORENB 0x01 -typedef struct Genesys_Register_Set +#define GENESYS_MAX_REGS 256 + +enum class ScanMethod : unsigned { + // normal scan method + FLATBED = 0, + // scan using transparency adaptor + TRANSPARENCY = 1, + // scan using transparency adaptor via infrared channel + TRANSPARENCY_INFRARED = 2 +}; + +inline void serialize(std::istream& str, ScanMethod& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, ScanMethod& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +enum class ScanColorMode : unsigned { + LINEART = 0, + HALFTONE, + GRAY, + COLOR_SINGLE_PASS +}; + +inline void serialize(std::istream& str, ScanColorMode& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, ScanColorMode& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +enum class ColorFilter : unsigned { + RED = 0, + GREEN, + BLUE, + NONE +}; + +inline void serialize(std::istream& str, ColorFilter& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, ColorFilter& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +struct GenesysRegister { + uint16_t address = 0; + uint8_t value = 0; +}; + +inline bool operator<(const GenesysRegister& lhs, const GenesysRegister& rhs) +{ + return lhs.address < rhs.address; +} + +struct GenesysRegisterSetState { + bool is_lamp_on = false; + bool is_xpa_on = false; +}; + +class Genesys_Register_Set { +public: + using container = std::vector; + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; + + // FIXME: this shouldn't live here, but in a separate struct that contains Genesys_Register_Set + GenesysRegisterSetState state; + + enum Options { + SEQUENTIAL = 1 + }; + + Genesys_Register_Set() + { + registers_.reserve(GENESYS_MAX_REGS); + } + + // by default the register set is sorted by address. In certain cases it's importand to send + // the registers in certain order: use the SEQUENTIAL option for that + Genesys_Register_Set(Options opts) : Genesys_Register_Set() + { + if ((opts & SEQUENTIAL) == SEQUENTIAL) { + sorted_ = false; + } + } + + void init_reg(uint16_t address, uint8_t default_value) + { + if (find_reg_index(address) >= 0) { + set8(address, default_value); + return; + } + GenesysRegister reg; + reg.address = address; + reg.value = default_value; + registers_.push_back(reg); + if (sorted_) + std::sort(registers_.begin(), registers_.end()); + } + + void remove_reg(uint16_t address) + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + registers_.erase(registers_.begin() + i); + } + + GenesysRegister& find_reg(uint16_t address) + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + return registers_[i]; + } + + const GenesysRegister& find_reg(uint16_t address) const + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + return registers_[i]; + } + + GenesysRegister* find_reg_address(uint16_t address) + { + return &find_reg(address); + } + + const GenesysRegister* find_reg_address(uint16_t address) const + { + return &find_reg(address); + } + + void set8(uint16_t address, uint8_t value) + { + find_reg(address).value = value; + } + + void set8_mask(uint16_t address, uint8_t value, uint8_t mask) + { + auto& reg = find_reg(address); + reg.value = (reg.value & ~mask) | value; + } + + void set16(uint16_t address, uint16_t value) + { + find_reg(address).value = (value >> 8) & 0xff; + find_reg(address + 1).value = value & 0xff; + } + + void set24(uint16_t address, uint32_t value) + { + find_reg(address).value = (value >> 16) & 0xff; + find_reg(address + 1).value = (value >> 8) & 0xff; + find_reg(address + 2).value = value & 0xff; + } + + uint8_t get8(uint16_t address) const + { + return find_reg(address).value; + } + + uint16_t get16(uint16_t address) const + { + return (find_reg(address).value << 8) | find_reg(address + 1).value; + } + + uint32_t get24(uint16_t address) const + { + return (find_reg(address).value << 16) | + (find_reg(address + 1).value << 8) | + find_reg(address + 2).value; + } + + void clear() { registers_.clear(); } + size_t size() const { return registers_.size(); } + + iterator begin() { return registers_.begin(); } + const_iterator begin() const { return registers_.begin(); } + + iterator end() { return registers_.end(); } + const_iterator end() const { return registers_.end(); } + +private: + int find_reg_index(uint16_t address) const + { + if (!sorted_) { + for (size_t i = 0; i < registers_.size(); i++) { + if (registers_[i].address == address) { + return i; + } + } + return -1; + } + + GenesysRegister search; + search.address = address; + auto it = std::lower_bound(registers_.begin(), registers_.end(), search); + if (it == registers_.end()) + return -1; + if (it->address != address) + return -1; + return std::distance(registers_.begin(), it); + } + + // registers are stored in a sorted vector + bool sorted_ = true; + std::vector registers_; +}; + +template +struct AssignableArray : public std::array { + AssignableArray() = default; + AssignableArray(const AssignableArray&) = default; + AssignableArray& operator=(const AssignableArray&) = default; + + AssignableArray& operator=(std::initializer_list init) + { + if (init.size() != std::array::size()) + throw std::runtime_error("An array of incorrect size assigned"); + std::copy(init.begin(), init.end(), std::array::begin()); + return *this; + } +}; + +struct GenesysRegisterSetting { + GenesysRegisterSetting() = default; + + GenesysRegisterSetting(uint16_t p_address, uint8_t p_value) : + address(p_address), value(p_value) + {} + + GenesysRegisterSetting(uint16_t p_address, uint8_t p_value, uint8_t p_mask) : + address(p_address), value(p_value), mask(p_mask) + {} + + uint16_t address = 0; + uint8_t value = 0; + uint8_t mask = 0xff; + + bool operator==(const GenesysRegisterSetting& other) const + { + return address == other.address && value == other.value && mask == other.mask; + } +}; + +template +void serialize(Stream& str, GenesysRegisterSetting& reg) +{ + serialize(str, reg.address); + serialize(str, reg.value); + serialize(str, reg.mask); +} + +class GenesysRegisterSettingSet { +public: + using container = std::vector; + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; + + GenesysRegisterSettingSet() = default; + GenesysRegisterSettingSet(std::initializer_list ilist) : regs_(ilist) {} + + iterator begin() { return regs_.begin(); } + const_iterator begin() const { return regs_.begin(); } + iterator end() { return regs_.end(); } + const_iterator end() const { return regs_.end(); } + + GenesysRegisterSetting& operator[](size_t i) { return regs_[i]; } + const GenesysRegisterSetting& operator[](size_t i) const { return regs_[i]; } + + size_t size() const { return regs_.size(); } + bool empty() const { return regs_.empty(); } + void clear() { regs_.clear(); } + + void push_back(GenesysRegisterSetting reg) { regs_.push_back(reg); } + + void merge(const GenesysRegisterSettingSet& other) + { + for (const auto& reg : other) { + set_value(reg.address, reg.value); + } + } + + uint8_t get_value(uint16_t address) const + { + for (const auto& reg : regs_) { + if (reg.address == address) + return reg.value; + } + throw std::runtime_error("Unknown register"); + } + + void set_value(uint16_t address, uint8_t value) + { + for (auto& reg : regs_) { + if (reg.address == address) { + reg.value = value; + return; + } + } + push_back(GenesysRegisterSetting(address, value)); + } + + friend void serialize(std::istream& str, GenesysRegisterSettingSet& reg); + friend void serialize(std::ostream& str, GenesysRegisterSettingSet& reg); + + bool operator==(const GenesysRegisterSettingSet& other) const + { + return regs_ == other.regs_; + } + +private: + std::vector regs_; +}; + +inline void serialize(std::istream& str, GenesysRegisterSettingSet& reg) +{ + reg.clear(); + const size_t max_register_address = + 1 << (sizeof(GenesysRegisterSetting::address) * CHAR_BIT); + serialize(str, reg.regs_, max_register_address); +} + +inline void serialize(std::ostream& str, GenesysRegisterSettingSet& reg) +{ + serialize(str, reg.regs_); +} + +struct GenesysFrontendLayout { - uint16_t address; - uint8_t value; -} Genesys_Register_Set; + std::array offset_addr = {}; + std::array gain_addr = {}; + + bool operator==(const GenesysFrontendLayout& other) const + { + return offset_addr == other.offset_addr && gain_addr == other.gain_addr; + } +}; /** @brief Data structure to set up analog frontend. - * The analog frontend converts analog value from image sensor to - * digital value. It has its own control registers which are set up - * with this structure. The values are written using sanei_genesys_fe_write_data. - * The actual register addresses they map to depends on the frontend used. - * @see sanei_genesys_fe_write_data + The analog frontend converts analog value from image sensor to digital value. It has its own + control registers which are set up with this structure. The values are written using + sanei_genesys_fe_write_data. */ -typedef struct +struct Genesys_Frontend { - uint8_t fe_id; /**< id of the frontend description */ - uint8_t reg[4]; /**< values to set up frontend control register, they - usually map to analog register 0x00 to 0x03 */ - uint8_t sign[3]; /**< sets the sign of the digital value */ - uint8_t offset[3]; /**< offset correction to apply to signal, most often - maps to frontend register 0x20-0x22 */ - uint8_t gain[3]; /**< amplification to apply to signal, most often - maps to frontend register 0x28-0x2a */ - uint8_t reg2[3]; /**< extra control registers */ -} Genesys_Frontend; - -typedef struct + Genesys_Frontend() = default; + + // id of the frontend description + uint8_t fe_id = 0; + + // all registers of the frontend + GenesysRegisterSettingSet regs; + + // extra control registers + std::array reg2 = {}; + + GenesysFrontendLayout layout; + + void set_offset(unsigned which, uint8_t value) + { + regs.set_value(layout.offset_addr[which], value); + } + + void set_gain(unsigned which, uint8_t value) + { + regs.set_value(layout.gain_addr[which], value); + } + + uint8_t get_offset(unsigned which) const + { + return regs.get_value(layout.offset_addr[which]); + } + + uint8_t get_gain(unsigned which) const + { + return regs.get_value(layout.gain_addr[which]); + } + + bool operator==(const Genesys_Frontend& other) const + { + return fe_id == other.fe_id && + regs == other.regs && + reg2 == other.reg2 && + layout == other.layout; + } +}; + +template +void serialize(Stream& str, Genesys_Frontend& x) { - uint8_t sensor_id; /**< id of the sensor description */ - int optical_res; - int black_pixels; - int dummy_pixel; /* value of dummy register. */ - int CCD_start_xoffset; /* last pixel of CCD margin at optical resolution */ - int sensor_pixels; /* total pixels used by the sensor */ - int fau_gain_white_ref; /* TA CCD target code (reference gain) */ - int gain_white_ref; /* CCD target code (reference gain) */ - uint8_t regs_0x08_0x0b[4]; - uint8_t regs_0x10_0x1d[14]; - uint8_t regs_0x52_0x5e[13]; - float gamma[3]; /**< red, green and blue gamma coefficient for default gamma tables */ - uint16_t *gamma_table[3]; /**< sensor specific gamma tables */ -} Genesys_Sensor; - -typedef struct + serialize(str, x.fe_id); + serialize_newline(str); + serialize(str, x.regs); + serialize_newline(str); + serialize(str, x.reg2); + serialize_newline(str); + serialize(str, x.layout.offset_addr); + serialize(str, x.layout.gain_addr); +} + +struct SensorExposure { + uint16_t red, green, blue; +}; + +struct Genesys_Sensor { + + Genesys_Sensor() = default; + ~Genesys_Sensor() = default; + + // id of the sensor description + uint8_t sensor_id = 0; + int optical_res = 0; + + // the minimum and maximum resolution this sensor is usable at. -1 means that the resolution + // can be any. + int min_resolution = -1; + int max_resolution = -1; + + // the scan method used with the sensor + ScanMethod method = ScanMethod::FLATBED; + + // CCD may present itself as half or quarter-size CCD on certain resolutions + int ccd_size_divisor = 1; + + int black_pixels = 0; + // value of the dummy register + int dummy_pixel = 0; + // last pixel of CCD margin at optical resolution + int CCD_start_xoffset = 0; + // total pixels used by the sensor + int sensor_pixels = 0; + // TA CCD target code (reference gain) + int fau_gain_white_ref = 0; + // CCD target code (reference gain) + int gain_white_ref = 0; + + // red, green and blue initial exposure values + SensorExposure exposure; + + int exposure_lperiod = -1; + + GenesysRegisterSettingSet custom_regs; + GenesysRegisterSettingSet custom_fe_regs; + + // red, green and blue gamma coefficient for default gamma tables + AssignableArray gamma; + + int get_ccd_size_divisor_for_dpi(int xres) const + { + if (ccd_size_divisor >= 4 && xres * 4 <= optical_res) { + return 4; + } + if (ccd_size_divisor >= 2 && xres * 2 <= optical_res) { + return 2; + } + return 1; + } + + bool operator==(const Genesys_Sensor& other) const + { + return sensor_id == other.sensor_id && + optical_res == other.optical_res && + min_resolution == other.min_resolution && + max_resolution == other.max_resolution && + method == other.method && + ccd_size_divisor == other.ccd_size_divisor && + black_pixels == other.black_pixels && + dummy_pixel == other.dummy_pixel && + CCD_start_xoffset == other.CCD_start_xoffset && + sensor_pixels == other.sensor_pixels && + fau_gain_white_ref == other.fau_gain_white_ref && + gain_white_ref == other.gain_white_ref && + exposure.blue == other.exposure.blue && + exposure.green == other.exposure.green && + exposure.red == other.exposure.red && + exposure_lperiod == other.exposure_lperiod && + custom_regs == other.custom_regs && + custom_fe_regs == other.custom_fe_regs && + gamma == other.gamma; + } +}; + +template +void serialize(Stream& str, Genesys_Sensor& x) { - uint8_t gpo_id; /**< id of the gpo description */ - uint8_t value[2]; /**< registers 0x6c and 0x6d on gl843 */ - uint8_t enable[2]; /**< registers 0x6e and 0x6F on gl843 */ -} Genesys_Gpo; + serialize(str, x.sensor_id); + serialize(str, x.optical_res); + serialize(str, x.min_resolution); + serialize(str, x.max_resolution); + serialize(str, x.method); + serialize(str, x.ccd_size_divisor); + serialize(str, x.black_pixels); + serialize(str, x.dummy_pixel); + serialize(str, x.CCD_start_xoffset); + serialize(str, x.sensor_pixels); + serialize(str, x.fau_gain_white_ref); + serialize(str, x.gain_white_ref); + serialize_newline(str); + serialize(str, x.exposure.blue); + serialize(str, x.exposure.green); + serialize(str, x.exposure.red); + serialize(str, x.exposure_lperiod); + serialize_newline(str); + serialize(str, x.custom_regs); + serialize_newline(str); + serialize(str, x.custom_fe_regs); + serialize_newline(str); + serialize(str, x.gamma); +} -typedef struct +struct Genesys_Gpo { - SANE_Int maximum_start_speed; /* maximum speed allowed when accelerating from standstill. Unit: pixeltime/step */ - SANE_Int maximum_speed; /* maximum speed allowed. Unit: pixeltime/step */ - SANE_Int minimum_steps; /* number of steps used for default curve */ - float g; /* power for non-linear acceleration curves. */ -/* vs*(1-i^g)+ve*(i^g) where - vs = start speed, ve = end speed, - i = 0.0 for first entry and i = 1.0 for last entry in default table*/ -} Genesys_Motor_Slope; + Genesys_Gpo() = default; + + Genesys_Gpo(uint8_t id, const std::array& v, const std::array& e) + { + gpo_id = id; + value[0] = v[0]; + value[1] = v[1]; + enable[0] = e[0]; + enable[1] = e[1]; + } + // Genesys_Gpo + uint8_t gpo_id = 0; -typedef struct + // registers 0x6c and 0x6d on GL841, GL842, GL843, GL846, GL848 and possibly others + uint8_t value[2] = { 0, 0 }; + + // registers 0x6e and 0x6f on GL841, GL842, GL843, GL846, GL848 and possibly others + uint8_t enable[2] = { 0, 0 }; +}; + +struct Genesys_Motor_Slope +{ + Genesys_Motor_Slope() = default; + Genesys_Motor_Slope(int p_maximum_start_speed, int p_maximum_speed, int p_minimum_steps, + float p_g) : + maximum_start_speed(p_maximum_start_speed), + maximum_speed(p_maximum_speed), + minimum_steps(p_minimum_steps), + g(p_g) + {} + + // maximum speed allowed when accelerating from standstill. Unit: pixeltime/step + int maximum_start_speed = 0; + // maximum speed allowed. Unit: pixeltime/step + int maximum_speed = 0; + // number of steps used for default curve + int minimum_steps = 0; + + /* power for non-linear acceleration curves. + vs*(1-i^g)+ve*(i^g) where + vs = start speed, ve = end speed, + i = 0.0 for first entry and i = 1.0 for last entry in default table + */ + float g = 0; +}; + + +struct Genesys_Motor { - uint8_t motor_id; /**< id of the motor description */ - SANE_Int base_ydpi; /* motor base steps. Unit: 1/" */ - SANE_Int optical_ydpi; /* maximum resolution in y-direction. Unit: 1/" */ - SANE_Int max_step_type; /* maximum step type. 0-2 */ - SANE_Int power_mode_count; /* number of power modes*/ - Genesys_Motor_Slope slopes[2][3]; /* slopes to derive individual slopes from */ -} Genesys_Motor; + Genesys_Motor() = default; + Genesys_Motor(uint8_t p_motor_id, int p_base_ydpi, int p_optical_ydpi, int p_max_step_type, + int p_power_mode_count, + const std::vector>& p_slopes) : + motor_id(p_motor_id), + base_ydpi(p_base_ydpi), + optical_ydpi(p_optical_ydpi), + max_step_type(p_max_step_type), + power_mode_count(p_power_mode_count), + slopes(p_slopes) + {} + + // id of the motor description + uint8_t motor_id = 0; + // motor base steps. Unit: 1/inch + int base_ydpi = 0; + // maximum resolution in y-direction. Unit: 1/inch + int optical_ydpi = 0; + // maximum step type. 0-2 + int max_step_type = 0; + // number of power modes + int power_mode_count = 0; + // slopes to derive individual slopes from + std::vector> slopes; +}; typedef enum Genesys_Color_Order { @@ -329,116 +833,175 @@ Genesys_Color_Order; #define GENESYS_GL123 123 #define GENESYS_GL124 124 -#define GENESYS_MAX_REGS 256 +enum Genesys_Model_Type +{ + MODEL_UMAX_ASTRA_4500 = 0, + MODEL_CANON_LIDE_50, + MODEL_PANASONIC_KV_SS080, + MODEL_HP_SCANJET_4850C, + MODEL_HP_SCANJET_G4010, + MODEL_HP_SCANJET_G4050, + MODEL_CANON_CANOSCAN_4400F, + MODEL_CANON_CANOSCAN_8400F, + MODEL_CANON_CANOSCAN_8600F, + MODEL_CANON_LIDE_100, + MODEL_CANON_LIDE_110, + MODEL_CANON_LIDE_120, + MODEL_CANON_LIDE_210, + MODEL_CANON_LIDE_220, + MODEL_CANON_CANOSCAN_5600F, + MODEL_CANON_LIDE_700F, + MODEL_CANON_LIDE_200, + MODEL_CANON_LIDE_60, + MODEL_CANON_LIDE_80, + MODEL_HP_SCANJET_2300C, + MODEL_HP_SCANJET_2400C, + MODEL_VISIONEER_STROBE_XP200, + MODEL_HP_SCANJET_3670C, + MODEL_PLUSTEK_OPTICPRO_ST12, + MODEL_PLUSTEK_OPTICPRO_ST24, + MODEL_MEDION_MD5345, + MODEL_VISIONEER_STROBE_XP300, + MODEL_SYSCAN_DOCKETPORT_665, + MODEL_VISIONEER_ROADWARRIOR, + MODEL_SYSCAN_DOCKETPORT_465, + MODEL_VISIONEER_STROBE_XP100_REVISION3, + MODEL_PENTAX_DSMOBILE_600, + MODEL_SYSCAN_DOCKETPORT_467, + MODEL_SYSCAN_DOCKETPORT_685, + MODEL_SYSCAN_DOCKETPORT_485, + MODEL_DCT_DOCKETPORT_487, + MODEL_VISIONEER_7100, + MODEL_XEROX_2400, + MODEL_XEROX_TRAVELSCANNER_100, + MODEL_PLUSTEK_OPTICPRO_3600, + MODEL_HP_SCANJET_N6310, + MODEL_PLUSTEK_OPTICBOOK_3800, + MODEL_CANON_IMAGE_FORMULA_101 +}; -#define DAC_WOLFSON_UMAX 0 -#define DAC_WOLFSON_ST12 1 -#define DAC_WOLFSON_ST24 2 -#define DAC_WOLFSON_5345 3 -#define DAC_WOLFSON_HP2400 4 -#define DAC_WOLFSON_HP2300 5 -#define DAC_CANONLIDE35 6 -#define DAC_AD_XP200 7 /* Analog Device frontend */ -#define DAC_WOLFSON_XP300 8 -#define DAC_WOLFSON_HP3670 9 -#define DAC_WOLFSON_DSM600 10 -#define DAC_CANONLIDE200 11 -#define DAC_KVSS080 12 -#define DAC_G4050 13 -#define DAC_CANONLIDE110 14 -#define DAC_PLUSTEK_3600 15 -#define DAC_CANONLIDE700 16 -#define DAC_CS8400F 17 -#define DAC_IMG101 18 -#define DAC_PLUSTEK3800 19 -#define DAC_CANONLIDE80 20 -#define DAC_CANONLIDE120 21 - -#define CCD_UMAX 0 -#define CCD_ST12 1 /* SONY ILX548: 5340 Pixel ??? */ -#define CCD_ST24 2 /* SONY ILX569: 10680 Pixel ??? */ -#define CCD_5345 3 -#define CCD_HP2400 4 -#define CCD_HP2300 5 -#define CCD_CANONLIDE35 6 -#define CIS_XP200 7 /* CIS sensor for Strobe XP200 */ - /* 8 is unused currently */ -#define CCD_HP3670 9 -#define CCD_DP665 10 -#define CCD_ROADWARRIOR 11 -#define CCD_DSMOBILE600 12 -#define CCD_XP300 13 -#define CCD_DP685 14 -#define CIS_CANONLIDE200 15 -#define CIS_CANONLIDE100 16 -#define CCD_KVSS080 17 -#define CCD_G4050 18 -#define CIS_CANONLIDE110 19 -#define CCD_PLUSTEK_3600 20 -#define CCD_HP_N6310 21 -#define CIS_CANONLIDE700 22 -#define CCD_CS4400F 23 -#define CCD_CS8400F 24 -#define CCD_IMG101 25 -#define CCD_PLUSTEK3800 26 -#define CIS_CANONLIDE210 27 -#define CIS_CANONLIDE80 28 -#define CIS_CANONLIDE220 29 -#define CIS_CANONLIDE120 30 - -#define GPO_UMAX 0 -#define GPO_ST12 1 -#define GPO_ST24 2 -#define GPO_5345 3 -#define GPO_HP2400 4 -#define GPO_HP2300 5 -#define GPO_CANONLIDE35 6 -#define GPO_XP200 7 -#define GPO_XP300 8 -#define GPO_HP3670 9 -#define GPO_DP665 10 -#define GPO_DP685 11 -#define GPO_CANONLIDE200 12 -#define GPO_KVSS080 13 -#define GPO_G4050 14 -#define GPO_CANONLIDE110 15 -#define GPO_PLUSTEK_3600 16 -#define GPO_CANONLIDE210 17 -#define GPO_HP_N6310 18 -#define GPO_CANONLIDE700 19 -#define GPO_CS4400F 20 -#define GPO_CS8400F 21 -#define GPO_IMG101 22 -#define GPO_PLUSTEK3800 23 -#define GPO_CANONLIDE80 24 -#define GPO_CANONLIDE120 25 - -#define MOTOR_UMAX 0 -#define MOTOR_5345 1 -#define MOTOR_ST24 2 -#define MOTOR_HP2400 3 -#define MOTOR_HP2300 4 -#define MOTOR_CANONLIDE35 5 -#define MOTOR_XP200 6 -#define MOTOR_XP300 7 -#define MOTOR_HP3670 9 -#define MOTOR_DP665 10 -#define MOTOR_ROADWARRIOR 11 -#define MOTOR_DSMOBILE_600 12 -#define MOTOR_CANONLIDE200 13 -#define MOTOR_CANONLIDE100 14 -#define MOTOR_KVSS080 15 -#define MOTOR_G4050 16 -#define MOTOR_CANONLIDE110 17 -#define MOTOR_PLUSTEK_3600 18 -#define MOTOR_CANONLIDE700 19 -#define MOTOR_CS8400F 20 -#define MOTOR_IMG101 21 -#define MOTOR_PLUSTEK3800 22 -#define MOTOR_CANONLIDE210 23 -#define MOTOR_CANONLIDE80 24 -#define MOTOR_CANONLIDE120 25 +enum Genesys_Dac_Type +{ + DAC_WOLFSON_UMAX = 0, + DAC_WOLFSON_ST12, + DAC_WOLFSON_ST24, + DAC_WOLFSON_5345, + DAC_WOLFSON_HP2400, + DAC_WOLFSON_HP2300, + DAC_CANONLIDE35, + DAC_AD_XP200, + DAC_WOLFSON_XP300, + DAC_WOLFSON_HP3670, + DAC_WOLFSON_DSM600, + DAC_CANONLIDE200, + DAC_KVSS080, + DAC_G4050, + DAC_CANONLIDE110, + DAC_PLUSTEK_3600, + DAC_CANONLIDE700, + DAC_CS8400F, + DAC_CS8600F, + DAC_IMG101, + DAC_PLUSTEK3800, + DAC_CANONLIDE80, + DAC_CANONLIDE120 +}; + +enum Genesys_Sensor_Type +{ + CCD_UMAX = 0, + CCD_ST12, // SONY ILX548: 5340 Pixel ??? + CCD_ST24, // SONY ILX569: 10680 Pixel ??? + CCD_5345, + CCD_HP2400, + CCD_HP2300, + CCD_CANONLIDE35, + CIS_XP200, // CIS sensor for Strobe XP200, + CCD_HP3670, + CCD_DP665, + CCD_ROADWARRIOR, + CCD_DSMOBILE600, + CCD_XP300, + CCD_DP685, + CIS_CANONLIDE200, + CIS_CANONLIDE100, + CCD_KVSS080, + CCD_G4050, + CIS_CANONLIDE110, + CCD_PLUSTEK_3600, + CCD_HP_N6310, + CIS_CANONLIDE700, + CCD_CS4400F, + CCD_CS8400F, + CCD_CS8600F, + CCD_IMG101, + CCD_PLUSTEK3800, + CIS_CANONLIDE210, + CIS_CANONLIDE80, + CIS_CANONLIDE220, + CIS_CANONLIDE120, +}; +enum Genesys_Gpo_Type +{ + GPO_UMAX, + GPO_ST12, + GPO_ST24, + GPO_5345, + GPO_HP2400, + GPO_HP2300, + GPO_CANONLIDE35, + GPO_XP200, + GPO_XP300, + GPO_HP3670, + GPO_DP665, + GPO_DP685, + GPO_CANONLIDE200, + GPO_KVSS080, + GPO_G4050, + GPO_CANONLIDE110, + GPO_PLUSTEK_3600, + GPO_CANONLIDE210, + GPO_HP_N6310, + GPO_CANONLIDE700, + GPO_CS4400F, + GPO_CS8400F, + GPO_CS8600F, + GPO_IMG101, + GPO_PLUSTEK3800, + GPO_CANONLIDE80, + GPO_CANONLIDE120 +}; + +enum Genesys_Motor_Type +{ + MOTOR_UMAX = 0, + MOTOR_5345, + MOTOR_ST24, + MOTOR_HP2400, + MOTOR_HP2300, + MOTOR_CANONLIDE35, + MOTOR_XP200, + MOTOR_XP300, + MOTOR_HP3670, + MOTOR_DP665, + MOTOR_ROADWARRIOR, + MOTOR_DSMOBILE_600, + MOTOR_CANONLIDE200, + MOTOR_CANONLIDE100, + MOTOR_KVSS080, + MOTOR_G4050, + MOTOR_CANONLIDE110, + MOTOR_PLUSTEK_3600, + MOTOR_CANONLIDE700, + MOTOR_CS8400F, + MOTOR_CS8600F, + MOTOR_IMG101, + MOTOR_PLUSTEK3800, + MOTOR_CANONLIDE210, + MOTOR_CANONLIDE80, + MOTOR_CANONLIDE120 +}; /* Forward typedefs */ typedef struct Genesys_Device Genesys_Device; @@ -462,15 +1025,21 @@ typedef struct Genesys_Command_Set /*@} */ + bool (*needs_home_before_init_regs_for_scan) (Genesys_Device* dev); + /** For ASIC initialization */ SANE_Status (*init) (Genesys_Device * dev); SANE_Status (*init_regs_for_warmup) (Genesys_Device * dev, + const Genesys_Sensor& sensor, Genesys_Register_Set * regs, int *channels, int *total_size); - SANE_Status (*init_regs_for_coarse_calibration) (Genesys_Device * dev); - SANE_Status (*init_regs_for_shading) (Genesys_Device * dev); - SANE_Status (*init_regs_for_scan) (Genesys_Device * dev); + SANE_Status (*init_regs_for_coarse_calibration) (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs); + SANE_Status (*init_regs_for_shading) (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs); + SANE_Status (*init_regs_for_scan) (Genesys_Device * dev, const Genesys_Sensor& sensor); SANE_Bool (*get_filter_bit) (Genesys_Register_Set * reg); SANE_Bool (*get_lineart_bit) (Genesys_Register_Set * reg); @@ -481,18 +1050,12 @@ typedef struct Genesys_Command_Set SANE_Bool (*test_buffer_empty_bit) (SANE_Byte val); SANE_Bool (*test_motor_flag_bit) (SANE_Byte val); - int (*bulk_full_size) (void); - - SANE_Status (*set_fe) (Genesys_Device * dev, uint8_t set); + SANE_Status (*set_fe) (Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set); SANE_Status (*set_powersaving) (Genesys_Device * dev, int delay); SANE_Status (*save_power) (Genesys_Device * dev, SANE_Bool enable); - void (*set_motor_power) (Genesys_Register_Set * regs, SANE_Bool set); - void (*set_lamp_power) (Genesys_Device * dev, - Genesys_Register_Set * regs, - SANE_Bool set); - SANE_Status (*begin_scan) (Genesys_Device * dev, + const Genesys_Sensor& sensor, Genesys_Register_Set * regs, SANE_Bool start_motor); SANE_Status (*end_scan) (Genesys_Device * dev, @@ -502,32 +1065,31 @@ typedef struct Genesys_Command_Set /** * Send gamma tables to ASIC */ - SANE_Status (*send_gamma_table) (Genesys_Device * dev); + SANE_Status (*send_gamma_table) (Genesys_Device * dev, const Genesys_Sensor& sensor); SANE_Status (*search_start_position) (Genesys_Device * dev); - SANE_Status (*offset_calibration) (Genesys_Device * dev); - SANE_Status (*coarse_gain_calibration) (Genesys_Device * dev, int dpi); - SANE_Status (*led_calibration) (Genesys_Device * dev); - + SANE_Status (*offset_calibration) (Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs); + SANE_Status (*coarse_gain_calibration) (Genesys_Device * dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi); + SANE_Status (*led_calibration) (Genesys_Device * dev, Genesys_Sensor& sensor, + Genesys_Register_Set& regs); + + void (*wait_for_motor_stop) (Genesys_Device* dev); SANE_Status (*slow_back_home) (Genesys_Device * dev, SANE_Bool wait_until_home); SANE_Status (*rewind) (Genesys_Device * dev); SANE_Status (*bulk_write_register) (Genesys_Device * dev, - Genesys_Register_Set * reg, - size_t elems); + Genesys_Register_Set& regs); + SANE_Status (*bulk_write_data) (Genesys_Device * dev, uint8_t addr, uint8_t * data, size_t len); SANE_Status (*bulk_read_data) (Genesys_Device * dev, uint8_t addr, uint8_t * data, size_t len); - /* Updates hardware sensor information in Genesys_Scanner.val[]. - If possible, just get information for given option. - The sensor state in Genesys_Scanner.val[] should be merged with the - new sensor state, using the information that was last read by the frontend - in Genesys_Scanner.last_val[], in such a way that a button up/down - relative to Genesys_Scanner.last_val[] is not lost. - */ + // Updates hardware sensor information in Genesys_Scanner.val[]. SANE_Status (*update_hardware_sensors) (struct Genesys_Scanner * s); /* functions for sheetfed scanners */ @@ -548,12 +1110,11 @@ typedef struct Genesys_Command_Set /** * search for an black or white area in forward or reverse * direction */ - SANE_Status (*search_strip) (Genesys_Device * dev, SANE_Bool forward, SANE_Bool black); + SANE_Status (*search_strip) (Genesys_Device * dev, const Genesys_Sensor& sensor, + SANE_Bool forward, SANE_Bool black); - SANE_Status (*is_compatible_calibration) ( - Genesys_Device * dev, - Genesys_Calibration_Cache *cache, - SANE_Bool for_overwrite); + bool (*is_compatible_calibration) (Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Calibration_Cache* cache, SANE_Bool for_overwrite); /* functions for transparency adapter */ /** @@ -564,36 +1125,17 @@ typedef struct Genesys_Command_Set /** * write shading data calibration to ASIC */ - SANE_Status (*send_shading_data) (Genesys_Device * dev, uint8_t * data, int size); + SANE_Status (*send_shading_data) (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * data, int size); - /** - * calculate current scan setup - */ - SANE_Status (*calculate_current_setup) (Genesys_Device * dev); + // calculate current scan setup + void (*calculate_current_setup) (Genesys_Device * dev, const Genesys_Sensor& sensor); /** * cold boot init function */ SANE_Status (*asic_boot) (Genesys_Device * dev, SANE_Bool cold); - /** - * Scan register setting interface - */ - SANE_Status (*init_scan_regs) (Genesys_Device * dev, - Genesys_Register_Set * reg, - float xres, - float yres, - float startx, - float starty, - float pixels, - float lines, - unsigned int depth, - unsigned int channels, - int scan_method, - int scan_mode, - int color_filter, - unsigned int flags); - } Genesys_Command_Set; /** @brief structure to describe a scanner model @@ -605,6 +1147,7 @@ typedef struct Genesys_Model SANE_String_Const name; SANE_String_Const vendor; SANE_String_Const model; + SANE_Int model_id; SANE_Int asic_type; /* ASIC type gl646 or gl841 */ Genesys_Command_Set *cmd_set; /* pointers to low level functions */ @@ -653,108 +1196,277 @@ typedef struct Genesys_Model SANE_Word buttons; /* Button flags, described existing buttons for the model */ /*@} */ SANE_Int shading_lines; /* how many lines are used for shading calibration */ + SANE_Int shading_ta_lines; // how many lines are used for shading calibration in TA mode SANE_Int search_lines; /* how many lines are used to search start position */ } Genesys_Model; -#define SCAN_METHOD_FLATBED 0 /**< normal scan method */ -#define SCAN_METHOD_TRANSPARENCY 2 /**< scan using transparency adaptor */ -#define SCAN_METHOD_NEGATIVE 0x88 /**< scan using negative adaptor */ +struct Genesys_Settings +{ + ScanMethod scan_method = ScanMethod::FLATBED; + ScanColorMode scan_mode = ScanColorMode::LINEART; -#define SCAN_MODE_LINEART 0 /**< lineart scan mode */ -#define SCAN_MODE_HALFTONE 1 /**< halftone scan mode */ -#define SCAN_MODE_GRAY 2 /**< gray scan mode */ -#define SCAN_MODE_COLOR 4 /**< color scan mode */ + // horizontal dpi + int xres = 0; + // vertical dpi + int yres = 0; -typedef struct -{ - int scan_method; /* todo: change >=2: Transparency, 0x88: negative film */ - int scan_mode; /* todo: change 0,1 = lineart, halftone; 2 = gray, 3 = 3pass color, 4=single pass color */ - int xres; /**< horizontal dpi */ - int yres; /**< vertical dpi */ + //x start on scan table in mm + double tl_x = 0; + // y start on scan table in mm + double tl_y = 0; - double tl_x; /* x start on scan table in mm */ - double tl_y; /* y start on scan table in mm */ + // number of lines at scan resolution + unsigned int lines = 0; + // number of pixels at scan resolution + unsigned int pixels = 0; - unsigned int lines; /**< number of lines at scan resolution */ - unsigned int pixels; /**< number of pixels at scan resolution */ + // bit depth of the scan + unsigned int depth = 0; - unsigned int depth;/* bit depth of the scan */ + ColorFilter color_filter = ColorFilter::NONE; - /* todo : remove these fields ? */ - int exposure_time; + // true if scan is true gray, false if monochrome scan + int true_gray = 0; - unsigned int color_filter; + // lineart threshold + int threshold = 0; - /**< true if scan is true gray, false if monochrome scan */ - int true_gray; + // lineart threshold curve for dynamic rasterization + int threshold_curve = 0; - /**< lineart threshold */ - int threshold; + // Disable interpolation for xres::max(); + + // resolution in x direction + unsigned xres = NOT_SET; + // resolution in y direction + unsigned yres = NOT_SET; + // start pixel in X direction, from dummy_pixel + 1 + float startx = -1; + // start pixel in Y direction, counted according to base_ydpi + float starty = -1; + // the number of pixels in X direction + unsigned pixels = NOT_SET; + // the number of pixels in Y direction + unsigned lines = NOT_SET; + // the depth of the scan in bits. Allowed are 1, 8, 16 + unsigned depth = NOT_SET; + // the number of channels + unsigned channels = NOT_SET; + + ScanMethod scan_method = static_cast(NOT_SET); + + ScanColorMode scan_mode = static_cast(NOT_SET); + + ColorFilter color_filter = static_cast(NOT_SET); + + unsigned flags = NOT_SET; + + void assert_valid() const + { + if (xres == NOT_SET || yres == NOT_SET || startx < 0 || starty < 0 || + pixels == NOT_SET || lines == NOT_SET ||depth == NOT_SET || channels == NOT_SET || + scan_method == static_cast(NOT_SET) || + scan_mode == static_cast(NOT_SET) || + color_filter == static_cast(NOT_SET) || + flags == NOT_SET) + { + throw std::runtime_error("SetupParams are not valid"); + } + } + + bool operator==(const SetupParams& other) const + { + return xres == other.xres && + yres == other.yres && + startx == other.startx && + starty == other.starty && + pixels == other.pixels && + lines == other.lines && + depth == other.depth && + channels == other.channels && + scan_method == other.scan_method && + scan_mode == other.scan_mode && + color_filter == other.color_filter && + flags == other.flags; + } +}; - /**< value for brightness enhancement in the [-100..100] range */ - int brightness; - - /**< cahe entries expiration time */ - int expiration_time; -} Genesys_Settings; +template +void serialize(Stream& str, SetupParams& x) +{ + serialize(str, x.xres); + serialize(str, x.yres); + serialize(str, x.startx); + serialize(str, x.starty); + serialize(str, x.pixels); + serialize(str, x.lines); + serialize(str, x.depth); + serialize(str, x.channels); + serialize(str, x.scan_method); + serialize(str, x.scan_mode); + serialize(str, x.color_filter); + serialize(str, x.flags); +} -typedef struct Genesys_Current_Setup +struct Genesys_Current_Setup { - int pixels; /* pixel count expected from scanner */ - int lines; /* line count expected from scanner */ - int depth; /* depth expected from scanner */ - int channels; /* channel count expected from scanner */ - int scan_method; /* scanning method: flatbed or XPA */ - int exposure_time; /* used exposure time */ - float xres; /* used xres */ - float yres; /* used yres*/ - SANE_Bool half_ccd; /* half ccd mode */ - SANE_Int stagger; - SANE_Int max_shift; /* max shift of any ccd component, including staggered pixels*/ -} Genesys_Current_Setup; - -typedef struct Genesys_Buffer + // params used for this setup + SetupParams params; + + // pixel count expected from scanner + int pixels = 0; + // line count expected from scanner + int lines = 0; + // depth expected from scanner + int depth = 0; + // channel count expected from scanner + int channels = 0; + + // used exposure time + int exposure_time = 0; + // used xres + float xres = 0; + // used yres + float yres = 0; + // half ccd mode + unsigned ccd_size_divisor = 1; + SANE_Int stagger = 0; + // max shift of any ccd component, including staggered pixels + SANE_Int max_shift = 0; + + bool operator==(const Genesys_Current_Setup& other) const + { + return params == other.params && + pixels == other.pixels && + lines == other.lines && + depth == other.depth && + channels == other.channels && + exposure_time == other.exposure_time && + xres == other.xres && + yres == other.yres && + ccd_size_divisor == other.ccd_size_divisor && + stagger == other.stagger && + max_shift == other.max_shift; + } +}; + +template +void serialize(Stream& str, Genesys_Current_Setup& x) { - SANE_Byte *buffer; - size_t size; - size_t pos; /* current position in read buffer */ - size_t avail; /* data bytes currently in buffer */ -} Genesys_Buffer; + serialize(str, x.params); + serialize_newline(str); + serialize(str, x.pixels); + serialize(str, x.lines); + serialize(str, x.depth); + serialize(str, x.channels); + serialize(str, x.exposure_time); + serialize(str, x.xres); + serialize(str, x.yres); + serialize(str, x.ccd_size_divisor); + serialize(str, x.stagger); + serialize(str, x.max_shift); +} -struct Genesys_Calibration_Cache +struct Genesys_Buffer { - Genesys_Current_Setup used_setup;/* used to check if entry is compatible */ - time_t last_calibration; + Genesys_Buffer() = default; - Genesys_Frontend frontend; - Genesys_Sensor sensor; + size_t size() const { return buffer_.size(); } + size_t avail() const { return avail_; } + size_t pos() const { return pos_; } - size_t calib_pixels; - size_t calib_channels; - size_t average_size; - uint8_t *white_average_data; - uint8_t *dark_average_data; + // TODO: refactor code that uses this function to no longer use it + void set_pos(size_t pos) { pos_ = pos; } - struct Genesys_Calibration_Cache *next; + void alloc(size_t size); + void clear(); + + void reset(); + + uint8_t* get_write_pos(size_t size); + uint8_t* get_read_pos(); // TODO: mark as const + + void produce(size_t size); + void consume(size_t size); + +private: + std::vector buffer_; + // current position in read buffer + size_t pos_ = 0; + // data bytes currently in buffer + size_t avail_ = 0; }; +struct Genesys_Calibration_Cache +{ + Genesys_Calibration_Cache() = default; + ~Genesys_Calibration_Cache() = default; + + // used to check if entry is compatible + Genesys_Current_Setup used_setup; + time_t last_calibration = 0; + + Genesys_Frontend frontend; + Genesys_Sensor sensor; + + size_t calib_pixels = 0; + size_t calib_channels = 0; + size_t average_size = 0; + std::vector white_average_data; + std::vector dark_average_data; + + bool operator==(const Genesys_Calibration_Cache& other) const + { + return used_setup == other.used_setup && + last_calibration == other.last_calibration && + frontend == other.frontend && + sensor == other.sensor && + calib_pixels == other.calib_pixels && + calib_channels == other.calib_channels && + average_size == other.average_size && + white_average_data == other.white_average_data && + dark_average_data == other.dark_average_data; + } +}; + +template +void serialize(Stream& str, Genesys_Calibration_Cache& x) +{ + serialize(str, x.used_setup); + serialize_newline(str); + serialize(str, x.last_calibration); + serialize_newline(str); + serialize(str, x.frontend); + serialize_newline(str); + serialize(str, x.sensor); + serialize_newline(str); + serialize(str, x.calib_pixels); + serialize(str, x.calib_channels); + serialize(str, x.average_size); + serialize_newline(str); + serialize(str, x.white_average_data); + serialize_newline(str); + serialize(str, x.dark_average_data); +} + /** * Describes the current device status for the backend * session. This should be more accurately called @@ -762,86 +1474,140 @@ struct Genesys_Calibration_Cache */ struct Genesys_Device { - SANE_Int dn; - SANE_Word vendorId; /**< USB vendor identifier */ - SANE_Word productId; /**< USB product identifier */ - SANE_Int usb_mode; /**< USB mode: 1 for USB 1.1, 2 for USB 2.0, - 0 unset and -1 for fake USB device */ - SANE_String file_name; - SANE_String calib_file; - Genesys_Model *model; - - Genesys_Register_Set reg[256]; - Genesys_Register_Set calib_reg[256]; - Genesys_Settings settings; - Genesys_Frontend frontend; - Genesys_Sensor sensor; - Genesys_Gpo gpo; - Genesys_Motor motor; - uint16_t slope_table0[256]; - uint16_t slope_table1[256]; - uint8_t control[6]; - time_t init_date; - - size_t average_size; - size_t calib_pixels; /**< number of pixels used during shading calibration */ - size_t calib_lines; /**< number of lines used during shading calibration */ - size_t calib_channels; - size_t calib_resolution; - uint8_t *white_average_data; - uint8_t *dark_average_data; - uint16_t dark[3]; - - SANE_Bool already_initialized; - SANE_Int scanhead_position_in_steps; - SANE_Int lamp_off_time; - - SANE_Bool read_active; - SANE_Bool parking; /**< signal wether the park command has been issued */ - SANE_Bool document; /**< for sheetfed scanner's, is TRUE when there - is a document in the scanner */ - - Genesys_Buffer read_buffer; - Genesys_Buffer lines_buffer; - Genesys_Buffer shrink_buffer; - Genesys_Buffer out_buffer; - Genesys_Buffer binarize_buffer; /**< buffer for digital lineart from gray data */ - Genesys_Buffer local_buffer; /**< local buffer for gray data during dynamix lineart */ - - size_t read_bytes_left; /**< bytes to read from scanner */ - - size_t total_bytes_read; /**< total bytes read sent to frontend */ - size_t total_bytes_to_read; /**< total bytes read to be sent to frontend */ - size_t wpl; /**< asic's word per line */ - - Genesys_Current_Setup current_setup; /* contains the real used values */ - - /**< look up table used in dynamic rasterization */ - unsigned char lineart_lut[256]; - - Genesys_Calibration_Cache *calibration_cache; - - struct Genesys_Device *next; - - SANE_Int ld_shift_r; /**< used red line-distance shift*/ - SANE_Int ld_shift_g; /**< used green line-distance shift*/ - SANE_Int ld_shift_b; /**< used blue line-distance shift*/ - int segnb; /**< number of segments composing the sensor */ - int line_interp; /**< number of lines used in line interpolation */ - int line_count; /**< number of scan lines used during scan */ - size_t bpl; /**< bytes per full scan widthline */ - size_t dist; /**< bytes distance between an odd and an even pixel */ - size_t len; /**< number of even pixels */ - size_t cur; /**< current pixel position within sub window */ - size_t skip; /**< number of bytes to skip at start of line */ - size_t *order; /**< array describing the order of the sub-segments of the sensor */ - Genesys_Buffer oe_buffer; /**< buffer to handle even/odd data */ - - SANE_Bool buffer_image; /**< when true the scanned picture is first buffered - * to allow software image enhancements */ - SANE_Byte *img_buffer; /**< image buffer where the scanned picture is stored */ - - FILE *binary; /**< binary logger file */ + Genesys_Device() = default; + ~Genesys_Device(); + + using Calibration = std::vector; + + // frees commonly used data + void clear(); + + UsbDevice usb_dev; + SANE_Word vendorId = 0; /**< USB vendor identifier */ + SANE_Word productId = 0; /**< USB product identifier */ + + // USB mode: + // 0: not set + // 1: USB 1.1 + // 2: USB 2.0 + SANE_Int usb_mode = 0; + + SANE_String file_name = nullptr; + std::string calib_file; + + // if enabled, no calibration data will be loaded or saved to files + SANE_Int force_calibration = 0; + Genesys_Model *model = nullptr; + + Genesys_Register_Set reg; + Genesys_Register_Set calib_reg; + Genesys_Settings settings; + Genesys_Frontend frontend, frontend_initial; + Genesys_Gpo gpo; + Genesys_Motor motor; + uint8_t control[6] = {}; + time_t init_date = 0; + + size_t average_size = 0; + // number of pixels used during shading calibration + size_t calib_pixels = 0; + // number of lines used during shading calibration + size_t calib_lines = 0; + size_t calib_channels = 0; + size_t calib_resolution = 0; + // bytes to read from USB when calibrating. If 0, this is not set + size_t calib_total_bytes_to_read = 0; + // certain scanners support much higher resolution when scanning transparency, but we can't + // read whole width of the scanner as a single line at that resolution. Thus for stuff like + // calibration we want to read only the possible calibration area. + size_t calib_pixels_offset = 0; + + // gamma overrides. If a respective array is not empty then it means that the gamma for that + // color is overridden. + std::vector gamma_override_tables[3]; + + std::vector white_average_data; + std::vector dark_average_data; + uint16_t dark[3] = {}; + + SANE_Bool already_initialized = 0; + SANE_Int scanhead_position_in_steps = 0; + SANE_Int lamp_off_time = 0; + + SANE_Bool read_active = 0; + // signal wether the park command has been issued + SANE_Bool parking = 0; + + // for sheetfed scanner's, is TRUE when there is a document in the scanner + SANE_Bool document = 0; + + SANE_Bool needs_home_ta = 0; + + Genesys_Buffer read_buffer; + Genesys_Buffer lines_buffer; + Genesys_Buffer shrink_buffer; + Genesys_Buffer out_buffer; + + // buffer for digital lineart from gray data + Genesys_Buffer binarize_buffer = {}; + // local buffer for gray data during dynamix lineart + Genesys_Buffer local_buffer = {}; + + // bytes to read from scanner + size_t read_bytes_left = 0; + + // total bytes read sent to frontend + size_t total_bytes_read = 0; + // total bytes read to be sent to frontend + size_t total_bytes_to_read = 0; + // asic's word per line + size_t wpl = 0; + + // contains the real used values + Genesys_Current_Setup current_setup; + + // look up table used in dynamic rasterization + unsigned char lineart_lut[256] = {}; + + Calibration calibration_cache; + + // used red line-distance shift + SANE_Int ld_shift_r = 0; + // used green line-distance shift + SANE_Int ld_shift_g = 0; + // used blue line-distance shift + SANE_Int ld_shift_b = 0; + // number of segments composing the sensor + int segnb = 0; + // number of lines used in line interpolation + int line_interp = 0; + // number of scan lines used during scan + int line_count = 0; + // bytes per full scan widthline + size_t bpl = 0; + // bytes distance between an odd and an even pixel + size_t dist = 0; + // number of even pixels + size_t len = 0; + // current pixel position within sub window + size_t cur = 0; + // number of bytes to skip at start of line + size_t skip = 0; + + // array describing the order of the sub-segments of the sensor + size_t* order = nullptr; + + // buffer to handle even/odd data + Genesys_Buffer oe_buffer = {}; + + // when true the scanned picture is first buffered to allow software image enhancements + SANE_Bool buffer_image = 0; + + // image buffer where the scanned picture is stored + std::vector img_buffer; + + // binary logger file + FILE *binary = nullptr; }; typedef struct Genesys_USB_Device_Entry @@ -858,7 +1624,7 @@ typedef struct { int motor_type; /**< motor id */ int exposure; /**< exposure for the slope table */ int step_type; /**< default step type for given exposure */ - uint32_t *table; /**< 0 terminated slope table at full step */ + uint32_t *table; // 0-terminated slope table at full step (i.e. step_type == 0) } Motor_Profile; #define FULL_STEP 0 @@ -908,13 +1674,26 @@ typedef struct { /* common functions needed by low level specific functions */ /*--------------------------------------------------------------------------*/ -extern Genesys_Register_Set *sanei_genesys_get_address (Genesys_Register_Set * regs, uint16_t addr); +inline GenesysRegister* sanei_genesys_get_address(Genesys_Register_Set* regs, uint16_t addr) +{ + auto* ret = regs->find_reg_address(addr); + if (ret == nullptr) { + DBG(DBG_error, "%s: failed to find address for register 0x%02x, crash expected !\n", + __func__, addr); + } + return ret; +} -extern SANE_Byte -sanei_genesys_read_reg_from_set (Genesys_Register_Set * regs, uint16_t address); +inline uint8_t sanei_genesys_read_reg_from_set(Genesys_Register_Set* regs, uint16_t address) +{ + return regs->get8(address); +} -extern void -sanei_genesys_set_reg_from_set (Genesys_Register_Set * regs, uint16_t address, SANE_Byte value); +inline void sanei_genesys_set_reg_from_set(Genesys_Register_Set* regs, uint16_t address, + uint8_t value) +{ + regs->set8(address, value); +} extern SANE_Status sanei_genesys_init_cmd_set (Genesys_Device * dev); @@ -931,25 +1710,38 @@ extern SANE_Status sanei_genesys_write_hregister (Genesys_Device * dev, uint16_t reg, uint8_t val); extern SANE_Status -sanei_genesys_bulk_write_register (Genesys_Device * dev, - Genesys_Register_Set * reg, - size_t elems); +sanei_genesys_bulk_write_register(Genesys_Device * dev, + Genesys_Register_Set& regs); extern SANE_Status sanei_genesys_write_0x8c (Genesys_Device * dev, uint8_t index, uint8_t val); +extern unsigned sanei_genesys_get_bulk_max_size(Genesys_Device * dev); + +extern SANE_Status sanei_genesys_bulk_read_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, + size_t len); + +extern SANE_Status sanei_genesys_bulk_write_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, + size_t len); + extern SANE_Status sanei_genesys_get_status (Genesys_Device * dev, uint8_t * status); extern void sanei_genesys_print_status (uint8_t val); extern SANE_Status -sanei_genesys_write_ahb (SANE_Int dn, int usb_mode, uint32_t addr, uint32_t size, uint8_t * data); - -extern void sanei_genesys_init_fe (Genesys_Device * dev); +sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t size, uint8_t * data); extern void sanei_genesys_init_structs (Genesys_Device * dev); +const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev); +Genesys_Sensor& sanei_genesys_find_sensor_any_for_write(Genesys_Device* dev); +const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, int dpi, + ScanMethod scan_method = ScanMethod::FLATBED); +Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, int dpi, + ScanMethod scan_method = ScanMethod::FLATBED); + extern SANE_Status -sanei_genesys_init_shading_data (Genesys_Device * dev, int pixels_per_line); +sanei_genesys_init_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, + int pixels_per_line); extern SANE_Status sanei_genesys_read_valid_words (Genesys_Device * dev, unsigned int *steps); @@ -960,6 +1752,11 @@ extern SANE_Status sanei_genesys_read_scancnt (Genesys_Device * dev, extern SANE_Status sanei_genesys_read_feed_steps (Genesys_Device * dev, unsigned int *steps); +void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, bool set); + +void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set); + extern void sanei_genesys_calculate_zmode2 (SANE_Bool two_table, uint32_t exposure_time, @@ -1026,24 +1823,28 @@ sanei_genesys_create_slope_table3 (Genesys_Device * dev, unsigned int *final_exposure, int power_mode); -extern void -sanei_genesys_create_gamma_table (uint16_t * gamma_table, int size, - float maximum, float gamma_max, - float gamma); +void sanei_genesys_create_default_gamma_table(Genesys_Device* dev, + std::vector& gamma_table, float gamma); + +std::vector get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, + int color); -extern SANE_Status sanei_genesys_send_gamma_table (Genesys_Device * dev); +SANE_Status sanei_genesys_send_gamma_table(Genesys_Device * dev, const Genesys_Sensor& sensor); extern SANE_Status sanei_genesys_start_motor (Genesys_Device * dev); extern SANE_Status sanei_genesys_stop_motor (Genesys_Device * dev); extern SANE_Status -sanei_genesys_search_reference_point (Genesys_Device * dev, uint8_t * data, - int start_pixel, int dpi, int width, - int height); +sanei_genesys_search_reference_point(Genesys_Device * dev, Genesys_Sensor& sensor, + uint8_t * data, + int start_pixel, int dpi, int width, + int height); + +extern SANE_Status sanei_genesys_write_file(const char *filename, uint8_t* data, size_t length); extern SANE_Status -sanei_genesys_write_pnm_file (char *filename, uint8_t * data, int depth, +sanei_genesys_write_pnm_file (const char *filename, uint8_t * data, int depth, int channels, int pixels_per_line, int lines); extern SANE_Status @@ -1053,35 +1854,54 @@ extern SANE_Status sanei_genesys_read_data_from_scanner (Genesys_Device * dev, uint8_t * data, size_t size); -extern SANE_Status -sanei_genesys_buffer_alloc(Genesys_Buffer * buf, size_t size); - -extern SANE_Status -sanei_genesys_buffer_free(Genesys_Buffer * buf); - -extern SANE_Byte * -sanei_genesys_buffer_get_write_pos(Genesys_Buffer * buf, size_t size); - -extern SANE_Byte * -sanei_genesys_buffer_get_read_pos(Genesys_Buffer * buf); +inline void sanei_genesys_set_double(Genesys_Register_Set* regs, uint16_t addr, uint16_t value) +{ + regs->set16(addr, value); +} -extern SANE_Status -sanei_genesys_buffer_produce(Genesys_Buffer * buf, size_t size); +inline void sanei_genesys_set_triple(Genesys_Register_Set* regs, uint16_t addr, uint32_t value) +{ + regs->set24(addr, value); +} -extern SANE_Status -sanei_genesys_buffer_consume(Genesys_Buffer * buf, size_t size); +inline void sanei_genesys_get_double(Genesys_Register_Set* regs, uint16_t addr, uint16_t* value) +{ + *value = regs->get16(addr); +} -extern SANE_Status -sanei_genesys_set_double(Genesys_Register_Set *regs, uint16_t addr, uint16_t value); +inline void sanei_genesys_get_triple(Genesys_Register_Set* regs, uint16_t addr, uint32_t* value) +{ + *value = regs->get24(addr); +} -extern SANE_Status -sanei_genesys_set_triple(Genesys_Register_Set *regs, uint16_t addr, uint32_t value); +inline void sanei_genesys_set_exposure(Genesys_Register_Set& regs, const SensorExposure& exposure) +{ + regs.set8(0x10, (exposure.red >> 8) & 0xff); + regs.set8(0x11, exposure.red & 0xff); + regs.set8(0x12, (exposure.green >> 8) & 0xff); + regs.set8(0x13, exposure.green & 0xff); + regs.set8(0x14, (exposure.blue >> 8) & 0xff); + regs.set8(0x15, exposure.blue & 0xff); +} -extern SANE_Status -sanei_genesys_get_double(Genesys_Register_Set *regs, uint16_t addr, uint16_t *value); +inline uint16_t sanei_genesys_fixup_exposure_value(uint16_t value) +{ + if ((value & 0xff00) == 0) { + value |= 0x100; + } + if ((value & 0x00ff) == 0) { + value |= 0x1; + } + return value; +} -extern SANE_Status -sanei_genesys_get_triple(Genesys_Register_Set *regs, uint16_t addr, uint32_t *value); +inline SensorExposure sanei_genesys_fixup_exposure(SensorExposure exposure) +{ + exposure.red = sanei_genesys_fixup_exposure_value(exposure.red); + exposure.green = sanei_genesys_fixup_exposure_value(exposure.green); + exposure.blue = sanei_genesys_fixup_exposure_value(exposure.blue); + return exposure; +} extern SANE_Status sanei_genesys_wait_for_home(Genesys_Device *dev); @@ -1089,8 +1909,10 @@ sanei_genesys_wait_for_home(Genesys_Device *dev); extern SANE_Status sanei_genesys_asic_init(Genesys_Device *dev, SANE_Bool cold); -extern -int sanei_genesys_compute_dpihw(Genesys_Device *dev, int xres); +int sanei_genesys_compute_dpihw(Genesys_Device *dev, const Genesys_Sensor& sensor, int xres); + +int sanei_genesys_compute_dpihw_calibration(Genesys_Device *dev, const Genesys_Sensor& sensor, + int xres); extern Motor_Profile *sanei_genesys_get_motor_profile(Motor_Profile *motors, int motor_type, int exposure); @@ -1119,15 +1941,8 @@ int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev); extern int sanei_genesys_get_lowest_dpi(Genesys_Device *dev); -/** - * reads previously cached calibration data - * from file - */ -extern SANE_Status -sanei_genesys_read_calibration (Genesys_Device * dev); - -extern SANE_Status -sanei_genesys_is_compatible_calibration (Genesys_Device * dev, +extern bool +sanei_genesys_is_compatible_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Calibration_Cache * cache, int for_overwrite); @@ -1160,78 +1975,12 @@ sanei_genesys_load_lut (unsigned char * lut, extern SANE_Status sanei_genesys_generate_gamma_buffer(Genesys_Device * dev, + const Genesys_Sensor& sensor, int bits, int max, int size, uint8_t *gamma); -#ifdef UNIT_TESTING -SANE_Status -genesys_send_offset_and_shading (Genesys_Device * dev, - uint8_t * data, - int size); - -void -genesys_average_data (uint8_t * average_data, - uint8_t * calibration_data, - uint32_t lines, - uint32_t pixel_components_per_line); - -void -compute_averaged_planar (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int words_per_color, - unsigned int channels, - unsigned int o, - unsigned int coeff, - unsigned int target_bright, - unsigned int target_dark); - - -void -compute_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int channels, - unsigned int cmat[3], - int offset, - unsigned int coeff, - unsigned int target); - -void -compute_planar_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int factor, - unsigned int pixels_per_line, - unsigned int words_per_color, - unsigned int channels, - unsigned int cmat[3], - unsigned int offset, - unsigned int coeff, - unsigned int target); - -void -compute_shifted_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int channels, - unsigned int cmat[3], - int offset, - unsigned int coeff, - unsigned int target_dark, - unsigned int target_bright, - unsigned int patch_size); /* contigous extent */ - -SANE_Status -probe_genesys_devices (void); - -SANE_Status genesys_flatbed_calibration (Genesys_Device *dev); - -SANE_Status genesys_send_shading_coefficient (Genesys_Device *dev); -#endif - - /*---------------------------------------------------------------------------*/ /* ASIC specific functions declarations */ /*---------------------------------------------------------------------------*/ @@ -1242,4 +1991,52 @@ extern SANE_Status sanei_gl846_init_cmd_set (Genesys_Device * dev); extern SANE_Status sanei_gl847_init_cmd_set (Genesys_Device * dev); extern SANE_Status sanei_gl124_init_cmd_set (Genesys_Device * dev); +// same as usleep, except that it does nothing if testing mode is enabled +extern void sanei_genesys_usleep(unsigned int useconds); + +// same as sanei_genesys_usleep just that the duration is in milliseconds +extern void sanei_genesys_sleep_ms(unsigned int milliseconds); + +void add_function_to_run_at_backend_exit(std::function function); + +// calls functions added via add_function_to_run_at_backend_exit() in reverse order of being +// added. +void run_functions_at_backend_exit(); + +template +class StaticInit { +public: + StaticInit() = default; + StaticInit(const StaticInit&) = delete; + StaticInit& operator=(const StaticInit&) = delete; + + template + void init(Args&& ... args) + { + ptr_ = std::unique_ptr(new T(std::forward(args)...)); + add_function_to_run_at_backend_exit([this](){ deinit(); }); + } + + void deinit() + { + ptr_.release(); + } + + const T* operator->() const { return ptr_.get(); } + T* operator->() { return ptr_.get(); } + const T& operator*() const { return *ptr_.get(); } + T& operator*() { return *ptr_.get(); } + +private: + std::unique_ptr ptr_; +}; + +extern StaticInit> s_sensors; +void genesys_init_sensor_tables(); +void genesys_init_frontend_tables(); + +void debug_dump(unsigned level, const Genesys_Settings& settings); +void debug_dump(unsigned level, const SetupParams& params); +void debug_dump(unsigned level, const Genesys_Current_Setup& setup); + #endif /* not GENESYS_LOW_H */ diff --git a/backend/genesys_sanei.cc b/backend/genesys_sanei.cc new file mode 100644 index 0000000..5b5b40a --- /dev/null +++ b/backend/genesys_sanei.cc @@ -0,0 +1,140 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "genesys_sanei.h" + +UsbDevice::~UsbDevice() +{ + if (is_open()) { + DBG(DBG_error, "UsbDevice not closed; closing automatically"); + close(); + } +} + +void UsbDevice::open(const char* dev_name) +{ + DBG_HELPER(dbg); + + if (is_open()) { + throw SaneException("device already open"); + } + int device_num = 0; + + dbg.status("open device"); + TIE(sanei_usb_open(dev_name, &device_num)); + + name_ = dev_name; + device_num_ = device_num; + is_open_ = true; +} + +void UsbDevice::clear_halt() +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_clear_halt(device_num_)); +} + +void UsbDevice::reset() +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_reset(device_num_)); +} + +void UsbDevice::close() +{ + DBG_HELPER(dbg); + assert_is_open(); + + // we can't do much if closing fails, so we close the device on our side regardless of the + // function succeeds + int device_num = device_num_; + + set_not_open(); + sanei_usb_close(device_num); +} + +void UsbDevice::get_vendor_product(int& vendor, int& product) +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_get_vendor_product(device_num_, &vendor, &product)); +} + +void UsbDevice::control_msg(int rtype, int reg, int value, int index, int length, uint8_t* data) +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_control_msg(device_num_, rtype, reg, value, index, length, data)); +} + +void UsbDevice::bulk_read(uint8_t* buffer, size_t* size) +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_read_bulk(device_num_, buffer, size)); +} + +void UsbDevice::bulk_write(const uint8_t* buffer, size_t* size) +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_write_bulk(device_num_, buffer, size)); +} + +void UsbDevice::assert_is_open() const +{ + if (!is_open()) { + throw SaneException("device not open"); + } +} + +void UsbDevice::set_not_open() +{ + device_num_ = 0; + is_open_ = false; + name_ = ""; +} diff --git a/backend/genesys_sanei.h b/backend/genesys_sanei.h new file mode 100644 index 0000000..0e41600 --- /dev/null +++ b/backend/genesys_sanei.h @@ -0,0 +1,97 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_SANEI_H +#define BACKEND_GENESYS_SANEI_H + +#include "genesys_error.h" +#include "../include/sane/sanei_usb.h" + +#include +#include + +class UsbDevice { +public: + UsbDevice() = default; + UsbDevice(const UsbDevice& other) = delete; + UsbDevice& operator=(const UsbDevice&) = delete; + + UsbDevice(UsbDevice&& other) : + name_(other.name_), + is_open_(other.is_open_), + device_num_(other.device_num_) + { + other.set_not_open(); + } + + ~UsbDevice(); + + bool is_open() const { return is_open_; } + + int device_number() const { return device_num_; } + + const std::string& name() const { return name_; } + + void open(const char* dev_name); + + void clear_halt(); + void reset(); + void close(); + + void get_vendor_product(int& vendor, int& product); + + void control_msg(int rtype, int reg, int value, int index, int length, uint8_t* data); + void bulk_read(uint8_t* buffer, size_t* size); + void bulk_write(const uint8_t* buffer, size_t* size); + +private: + + void assert_is_open() const; + void set_not_open(); + + std::string name_; + bool is_open_ = false; + int device_num_ = 0; +}; + +#endif // BACKEND_GENESYS_SANEI_H diff --git a/backend/genesys_serialize.cc b/backend/genesys_serialize.cc new file mode 100644 index 0000000..e69de29 diff --git a/backend/genesys_serialize.h b/backend/genesys_serialize.h new file mode 100644 index 0000000..481e872 --- /dev/null +++ b/backend/genesys_serialize.h @@ -0,0 +1,144 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_SERIALIZE_H +#define BACKEND_GENESYS_SERIALIZE_H + +#include "genesys_error.h" +#include +#include +#include +#include +#include + +// it would be best to use something like boost.serialization + +inline void serialize_newline(std::ostream& str) { str << '\n'; } +inline void serialize_newline(std::istream& str) { (void) str; } + +inline void serialize(std::ostream& str, char x) { str << static_cast(x) << " "; } +inline void serialize(std::istream& str, char& x) { int v; str >> v; x = v; } +inline void serialize(std::ostream& str, unsigned char x) { str << static_cast(x) << " "; } +inline void serialize(std::istream& str, unsigned char& x) { unsigned v; str >> v; x = v; } +inline void serialize(std::ostream& str, signed char x) { str << static_cast(x) << " "; } +inline void serialize(std::istream& str, signed char& x) { int v; str >> v; x = v; } +inline void serialize(std::ostream& str, short x) { str << x << " "; } +inline void serialize(std::istream& str, short& x) { str >> x; } +inline void serialize(std::ostream& str, unsigned short x) { str << x << " "; } +inline void serialize(std::istream& str, unsigned short& x) { str >> x; } +inline void serialize(std::ostream& str, int x) { str << x << " "; } +inline void serialize(std::istream& str, int& x) { str >> x; } +inline void serialize(std::ostream& str, unsigned int x) { str << x << " "; } +inline void serialize(std::istream& str, unsigned int& x) { str >> x; } +inline void serialize(std::ostream& str, long x) { str << x << " "; } +inline void serialize(std::istream& str, long& x) { str >> x; } +inline void serialize(std::ostream& str, unsigned long x) { str << x << " "; } +inline void serialize(std::istream& str, unsigned long& x) { str >> x; } +inline void serialize(std::ostream& str, long long x) { str << x << " "; } +inline void serialize(std::istream& str, long long& x) { str >> x; } +inline void serialize(std::ostream& str, unsigned long long x) { str << x << " "; } +inline void serialize(std::istream& str, unsigned long long& x) { str >> x; } +inline void serialize(std::ostream& str, float x) { str << x << " "; } +inline void serialize(std::istream& str, float& x) { str >> x; } +inline void serialize(std::ostream& str, double x) { str << x << " "; } +inline void serialize(std::istream& str, double& x) { str >> x; } +inline void serialize(std::ostream& str, const std::string& x) { str << x << " "; } +inline void serialize(std::istream& str, std::string& x) { str >> x; } + +template +void serialize(std::ostream& str, std::vector& x) +{ + serialize(str, x.size()); + serialize_newline(str); + + for (auto& item : x) { + serialize(str, item); + serialize_newline(str); + } +} + +template +void serialize(std::istream& str, std::vector& x, + size_t max_size = std::numeric_limits::max()) +{ + size_t new_size; + serialize(str, new_size); + + if (new_size > max_size) { + throw SaneException("Too large std::vector to deserialize"); + } + x.reserve(new_size); + for (size_t i = 0; i < new_size; ++i) { + T item; + serialize(str, item); + x.push_back(item); + } +} + +template +void serialize(std::ostream& str, std::array& x) +{ + serialize(str, x.size()); + serialize_newline(str); + + for (auto& item : x) { + serialize(str, item); + serialize_newline(str); + } +} + +template +void serialize(std::istream& str, std::array& x) +{ + size_t new_size; + serialize(str, new_size); + + if (new_size > Size) { + throw SaneException("Incorrect std::array size to deserialize"); + } + for (auto& item : x) { + serialize(str, item); + } +} + +#endif diff --git a/backend/gphoto2.c b/backend/gphoto2.c index c8af306..973257c 100644 --- a/backend/gphoto2.c +++ b/backend/gphoto2.c @@ -1,28 +1,28 @@ /* Please note! Although intended to support multiple camera types * it's been tested with only cameras I have access to: the Kodak DC240 - * and the Directory Browse "camera." I'm very interested - * in learning what it would take to support more cameras. In + * and the Directory Browse "camera." I'm very interested + * in learning what it would take to support more cameras. In * particular, the current incarnation will only support cameras * that directly generate jpeg files. - * + * * Please report sucesses or failures using this backend! - * + * * However, having said that, I've already found it to be quite useful * even in its current form - one reason is that gphoto2 provides access - * to the camera via USB which is not supported by the regular DC240 + * to the camera via USB which is not supported by the regular DC240 * backend and is dramatically faster than the serial port. */ /*************************************************************************** * _S_A_N_E - Scanner Access Now Easy. - gphoto2.c + gphoto2.c 03/12/01 - Peter Fales Based on the dc210 driver, (C) 1998 Brian J. Murrell (which is based on dc25 driver (C) 1998 by Peter Fales) - + This file (C) 2001 by Peter Fales This file is part of the SANE package. @@ -61,14 +61,14 @@ 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. + If you do not wish that, delete this exception notice. *************************************************************************** - This file implements a SANE backend for digital cameras + This file implements a SANE backend for digital cameras supported by the gphoto2 libraries. - - THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! + + THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! (feedback to: gphoto2-devel@fales-lorenz.net) @@ -96,7 +96,7 @@ #include "../include/sane/sanei_backend.h" /* PSF 1/12/02 - gphoto2.h does a #include of config.h. We don't have - * config.h by that name (we call it sane/config.h), so the #undef of + * config.h by that name (we call it sane/config.h), so the #undef of * HAVE_CONFIG_H will cause it to skip that. */ #undef HAVE_CONFIG_H @@ -349,7 +349,7 @@ static const SANE_Device *devlist[] = { dev + 0, 0 }; -/* +/* * debug_func - called for gphoto2 debugging output (if enabled) */ static void @@ -397,9 +397,9 @@ init_gphoto2 (void) { /* * We get here if re-initializing the camera: either because - * the user clicked the "re-establish" button, or we need to - * recalculate the number of photos after taking a picture. - * We must release the old camera before starting over. + * the user clicked the "re-establish" button, or we need to + * recalculate the number of photos after taking a picture. + * We must release the old camera before starting over. */ CHECK_RET (gp_camera_unref (camera)); } @@ -455,14 +455,14 @@ init_gphoto2 (void) * knows that and will complain if we try to set the speed for * ports other than serial ones. Because we are paranoid here and * check every single error message returned by gphoto2, we need - * to make sure that we have a serial port. + * to make sure that we have a serial port. */ if (Cam_data.speed && !strncmp (Cam_data.port, "serial:", 7)) { - /* + /* * Not sure why we need this hack. The API keeps opening/closing * the port, and that seems to confuse the camera. Holding - * the port open seems to fix it. + * the port open seems to fix it. */ if ((hack_fd = open (Cam_data.port + 7, O_RDONLY)) < 0) { @@ -514,7 +514,7 @@ init_gphoto2 (void) } /* - * close_gphoto2() - Shutdown camera interface + * close_gphoto2() - Shutdown camera interface */ static void close_gphoto2 (void) @@ -565,7 +565,7 @@ get_info (void) } /* If we've already got a folder_list, free it up before starting - * the new one + * the new one */ if (folder_list != NULL) { @@ -613,8 +613,8 @@ get_info (void) } -/* - * erase() - erase file from camera corresponding to +/* + * erase() - erase file from camera corresponding to * current picture number. Does not update any of the other * backend data structures. */ @@ -689,7 +689,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize /* Earlier versions why would try to keep going with compiled in * defaults if the config file is missing. But, now we have so * options and combinations of options, that success without a config - * file is unlikely. So, give and return failure + * file is unlikely. So, give and return failure */ DBG (0, "warning: %s: missing config file '%s'\n" "If you aren't using gphoto2, you should disable it in dll.conf.\n" @@ -794,7 +794,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize /* Special case: Force port to special value for the * "Directory Browse" camera - overriding anything in * the config file - or more likely when not specified - * in the config file. + * in the config file. */ if (strcmp (Cam_data.camera_name, "Directory Browse") == 0) @@ -1086,14 +1086,14 @@ sane_control_option (SANE_Handle handle, SANE_Int option, else Cam_data.current_picture_number = Cam_data.pic_taken; - /* + /* * Setting a new image number could change image size (if * we supported that - which we hope to do someday! */ myinfo |= SANE_INFO_RELOAD_PARAMS; - /* get the image's resolution, unless the camera has no - * pictures yet + /* get the image's resolution, unless the camera has no + * pictures yet */ if (Cam_data.pic_taken != 0) { @@ -1141,7 +1141,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (gphoto2_opt_snap) { /* activate the resolution setting */ -/* Until we figure out how to do this +/* Until we figure out how to do this sod[GPHOTO2_OPT_LOWRES].cap &= ~SANE_CAP_INACTIVE; */ /* and de-activate the image number selector */ @@ -1151,7 +1151,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { /* deactivate the resolution setting */ sod[GPHOTO2_OPT_LOWRES].cap |= SANE_CAP_INACTIVE; - /* and activate the image number selector, if there are + /* and activate the image number selector, if there are * pictures available */ if (Cam_data.current_picture_number) { @@ -1405,7 +1405,7 @@ sane_start (SANE_Handle handle) if (gphoto2_opt_snap) { /* - * Don't allow picture unless there is room in the + * Don't allow picture unless there is room in the * camera. */ if (Cam_data.pic_left == 0) @@ -1458,7 +1458,7 @@ sane_start (SANE_Handle handle) if ( converter_init (handle) != SANE_STATUS_GOOD ) return SANE_STATUS_INVAL; - /* Check if a linebuffer has been allocated. If we had one + /* Check if a linebuffer has been allocated. If we had one * previously, free it up and allocate one for (possibly) new * size. parms.bytes_per_line is set by converter_init() */ @@ -1588,7 +1588,7 @@ sane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * get_pictures_info - load information about all pictures currently in * camera: Mainly the mapping of picture number * to picture name. We'ld like to get other - * information such as image size, but the API + * information such as image size, but the API * doesn't provide any support for that. */ static PictureInfo * @@ -1684,7 +1684,7 @@ snap_pic (void) return SANE_STATUS_INVAL; } - /* + /* * This is needed when the camera has no files and the first picture * is taken. I guess it's because a folder needs to be created and * the filesystem doesn't know about it. @@ -1699,9 +1699,9 @@ snap_pic (void) /* Can't just increment picture count, because if the camera has * zero pictures we may not know the folder name. Start over * with get_info and get_pictures_info. (We didn't have the call - * to init_gphoto2() here before, but that was causing us to not + * to init_gphoto2() here before, but that was causing us to not * see the new image - need to use a biggger hammer to get it to - * re-read the camera directory + * re-read the camera directory */ if (init_gphoto2 () != SANE_STATUS_GOOD) @@ -1772,7 +1772,7 @@ read_dir (SANE_String dir, SANE_Bool read_files) /* * read_info - read the info block from camera for the specified file - * NOT YET SUPPORTED - If it were we could use it to do things + * NOT YET SUPPORTED - If it were we could use it to do things * like update the image size parameters displayed by the GUI */ static SANE_Int @@ -1789,7 +1789,7 @@ read_info (SANE_String_Const fname) } /* - * set_res - set picture size depending on resolution settings + * set_res - set picture size depending on resolution settings */ static void set_res (SANE_Int __sane_unused__ lowres) @@ -1809,8 +1809,8 @@ set_res (SANE_Int __sane_unused__ lowres) } /* - * converter_do_scan_complete_cleanup - do everything that needs to be - * once a "scan" has been completed: Unref the file, Erase the image, + * converter_do_scan_complete_cleanup - do everything that needs to be + * once a "scan" has been completed: Unref the file, Erase the image, * and increment image number to point to next picture. */ static SANE_Status @@ -1902,17 +1902,17 @@ converter_do_scan_complete_cleanup (void) } /* - * converter_fill_buffer - Fill line buffer with next input line from image. - * Currently assumes jpeg, but this is where we would put the switch + * converter_fill_buffer - Fill line buffer with next input line from image. + * Currently assumes jpeg, but this is where we would put the switch * to handle other image types. */ static SANE_Int converter_fill_buffer (void) { -/* +/* * FIXME: Current implementation reads one scan line at a time. Part - * of the reason for this is in the original code is to give the frontend + * of the reason for this is in the original code is to give the frontend * a chance to update * the progress marker periodically. Since the gphoto2 * driver sucks in the whole image before decoding it, perhaps we could * come up with a simpler implementation. @@ -1927,8 +1927,8 @@ converter_fill_buffer (void) } /* - * converter_scan_complete - Check if all the data for the image has been read. - * Currently assumes jpeg, but this is where we would put the + * converter_scan_complete - Check if all the data for the image has been read. + * Currently assumes jpeg, but this is where we would put the * switch to handle other image types. */ static SANE_Bool @@ -1946,7 +1946,7 @@ converter_scan_complete (void) /* * converter_init - Initialize image conversion data. - * Currently assumes jpeg, but this is where we would put the + * Currently assumes jpeg, but this is where we would put the * switch to handle other image types. */ static SANE_Status diff --git a/backend/gphoto2.conf.in b/backend/gphoto2.conf.in index f5a660a..646fa76 100644 --- a/backend/gphoto2.conf.in +++ b/backend/gphoto2.conf.in @@ -1,23 +1,23 @@ # Interface port where the camera is connected -# This should be one of the values returned by "gphoto2 --list-ports", +# This should be one of the values returned by "gphoto2 --list-ports", # such # as serial:/dev/ttyS6 or usb: port=serial:/dev/ttyd1 -# Port speed. This should be one of the values returned by +# Port speed. This should be one of the values returned by # "gphoto2 --abilities" speed=115200 -# Name of camera. This should be one of the values returned by +# Name of camera. This should be one of the values returned by # "gphoto2 --list-cameras" camera=Kodak DC240 -# Prints some extra information during the init phase. +# Prints some extra information during the init phase. dumpinquiry -# The resolution should be the maximum resolution supported by the +# The resolution should be the maximum resolution supported by the # camera. It's not really used for much, since the actual size will be # reported by the camera when the download starts. But it may be useful -# for the frontend to have a clue prior to the download. (e.g. it +# for the frontend to have a clue prior to the download. (e.g. it # may want to create an image window, or report the maximum file size. # Width x Height. resolution=1280x960 @@ -27,6 +27,6 @@ thumb_resolution=160x120 # top-level (fixed) folder directory in camera. Backend assumes # that there is one variable directory under this (e.g. 100DC240) -# which will be read from the camera, and all the images in the -# camera are under that. +# which will be read from the camera, and all the images in the +# camera are under that. topfolder=/DCIM diff --git a/backend/gphoto2.h b/backend/gphoto2.h index 60591cf..b792875 100644 --- a/backend/gphoto2.h +++ b/backend/gphoto2.h @@ -47,12 +47,12 @@ 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. + If you do not wish that, delete this exception notice. *************************************************************************** This file implements a SANE backend for the Kodak DC-240 - digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! + digital camera. THIS IS EXTREMELY ALPHA CODE! USE AT YOUR OWN RISK!! (feedback to: gphoto2-devel@fales-lorenz.net) diff --git a/backend/gt68xx.c b/backend/gt68xx.c index 13efe91..fb3bfb4 100644 --- a/backend/gt68xx.c +++ b/backend/gt68xx.c @@ -2,46 +2,46 @@ Copyright (C) 2002 Sergey Vlasov Copyright (C) 2002 - 2007 Henning Geinitz - Copyright (C) 2009 Stéphane Voltz for sheetfed + Copyright (C) 2009 Stéphane Voltz for sheetfed calibration code. 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. + If you do not wish that, delete this exception notice. */ /* @@ -162,13 +162,6 @@ static SANE_Range y_range = { SANE_FIX (0.0) /* quantization */ }; - -static const SANE_Range offset_range = { - -63, /* minimum */ - 63, /* maximum */ - 1 /* quantization */ -}; - static SANE_Range gamma_range = { SANE_FIX (0.01), /* minimum */ SANE_FIX (5.0), /* maximum */ @@ -756,7 +749,7 @@ init_options (GT68xx_Scanner * s) s->opt[OPT_SENSOR_GROUP].desc = SANE_DESC_SENSORS; s->opt[OPT_SENSOR_GROUP].type = SANE_TYPE_GROUP; s->opt[OPT_SENSOR_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - + /* calibration needed */ s->opt[OPT_NEED_CALIBRATION_SW].name = "need-calibration"; s->opt[OPT_NEED_CALIBRATION_SW].title = SANE_I18N ("Need calibration"); @@ -1487,7 +1480,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) DBG (0, "WARNING: Your scanner is not fully supported or at least \n"); DBG (0, " had only limited testing. Please be careful and \n"); DBG (0, " report any failure/success to \n"); - DBG (0, " sane-devel@lists.alioth.debian.org. Please provide as many\n"); + DBG (0, " sane-devel@alioth-lists.debian.net. Please provide as many\n"); DBG (0, " details as possible, e.g. the exact name of your\n"); DBG (0, " scanner and what does (not) work.\n"); } @@ -1502,7 +1495,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) DBG (0, " the scanner immediately if you hear unusual noise. \n"); DBG (0, " Please report any success to \n"); - DBG (0, " sane-devel@lists.alioth.debian.org. Please provide as many\n"); + DBG (0, " sane-devel@alioth-lists.debian.net. Please provide as many\n"); DBG (0, " details as possible, e.g. the exact name of your\n"); DBG (0, " scanner, ids, settings etc.\n"); @@ -1616,7 +1609,7 @@ sane_close (SANE_Handle handle) gt68xx_device_lamp_control (s->dev, SANE_FALSE, SANE_FALSE); dev = s->dev; - + free (s->val[OPT_MODE].s); free (s->val[OPT_GRAY_MODE_COLOR].s); free (s->val[OPT_SOURCE].s); @@ -1624,7 +1617,7 @@ sane_close (SANE_Handle handle) free ((void *)(size_t)s->opt[OPT_RESOLUTION].constraint.word_list); gt68xx_scanner_free (s); - + gt68xx_device_fix_descriptor (dev); gt68xx_device_deactivate (dev); @@ -1859,7 +1852,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, status = gt68xx_sheetfed_scanner_calibrate (s); myinfo |= SANE_INFO_RELOAD_OPTIONS; break; - + case OPT_CLEAR_CALIBRATION: gt68xx_clear_calibration (s); myinfo |= SANE_INFO_RELOAD_OPTIONS; @@ -2045,14 +2038,14 @@ sane_start (SANE_Handle handle) { /* compute scan parameters */ scan_request.calculate = SANE_TRUE; - gt68xx_device_setup_scan (s->dev, &scan_request, SA_SCAN, &scan_params); + gt68xx_device_setup_scan (s->dev, &scan_request, SA_SCAN, &scan_params); /* restore settings from calibration stored */ memcpy(s->dev->afe,&(s->afe_params), sizeof(GT68xx_AFE_Parameters)); RIE (gt68xx_assign_calibration (s, scan_params)); scan_request.calculate = SANE_FALSE; } - + /* send scan request to the scanner */ RIE (gt68xx_scanner_start_scan (s, &scan_request, &scan_params)); @@ -2331,7 +2324,7 @@ sane_cancel (SANE_Handle handle) if (s->dev->model->flags & GT68XX_FLAG_SHEET_FED) { gt68xx_device_paperfeed (s->dev); - } + } else { sanei_usb_set_timeout (SHORT_TIMEOUT); diff --git a/backend/gt68xx.conf.in b/backend/gt68xx.conf.in index 4affdcc..e9a9706 100644 --- a/backend/gt68xx.conf.in +++ b/backend/gt68xx.conf.in @@ -6,8 +6,8 @@ # Manual configuration is necessary for some scanners. Please uncomment the # override line and optinally the vendor and product lines that apply to your -# scanner. For some scanners it's also necessary to change the name of the -# firmware file. +# scanner. For some scanners it's also necessary to change the name of the +# firmware file. ############################################################################# # For testing scanners that are not yet supported by this backend add the @@ -43,32 +43,32 @@ usb 0x05d8 0x4002 #override "mustek-scanexpress-2400-usb" # Artec Ultima 2000: -#override "artec-ultima-2000" +#override "artec-ultima-2000" #firmware "ePlus2k.usb" # Artec Ultima 2000e+: -#override "artec-ultima-2000" +#override "artec-ultima-2000" #firmware "ePlus2k.usb" #vendor "Artec" #model "Ultima 2000e+" # Boeder SmartScan Slim Edition: -#override "artec-ultima-2000" +#override "artec-ultima-2000" #vendor "Boeder" #model "SmartScan Slim Edition" # Medion/Lifetec/Tevion/Cytron MD/LT 9385: -#override "artec-ultima-2000" +#override "artec-ultima-2000" #vendor "Medion" #model "MD/LT 9385" # Medion/Lifetec/Tevion/Cytron MD 9458: -#override "artec-ultima-2000" +#override "artec-ultima-2000" #vendor "Medion" #model "MD 9458" # Trust Flat Scan USB 19200: -#override "artec-ultima-2000" +#override "artec-ultima-2000" #vendor "Trust" #model "Flat Scan USB 19200" @@ -196,6 +196,11 @@ usb 0x07b3 0x045f # Autodetect NeatReceipts Mobile Scanner usb 0x07b3 0x0462 +############################################################################## +# Autodetect Plustek OpticSlim 500 Plus +usb 0x07b3 0x046e +override "plustek-opticslim-500plus" + ############################################################################## # Autodetect Plustek OpticSlim 1200 usb 0x07b3 0x0413 diff --git a/backend/gt68xx.h b/backend/gt68xx.h index 20f8c6c..96ad418 100644 --- a/backend/gt68xx.h +++ b/backend/gt68xx.h @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002 Sergey Vlasov - + 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. + If you do not wish that, delete this exception notice. */ #ifndef GT68XX_H diff --git a/backend/gt68xx_devices.c b/backend/gt68xx_devices.c index 1239190..2df24f6 100644 --- a/backend/gt68xx_devices.c +++ b/backend/gt68xx_devices.c @@ -2,44 +2,44 @@ Copyright (C) 2002 Sergey Vlasov Copyright (C) 2002 - 2007 Henning Geinitz - + 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. + If you do not wish that, delete this exception notice. */ /* Scanner-specific data */ @@ -406,7 +406,7 @@ static GT68xx_Model mustek_2448taplus_model = { SANE_FALSE, /* Is this a CIS scanner? */ GT68XX_FLAG_NO_STOP /* Which flags are needed for this scanner? */ - /* Based on data from Jakub Dvo?ák . */ + /* Based on data from Jakub Dvořák . */ }; static GT68xx_Model mustek_1200ta_model = { @@ -805,6 +805,54 @@ static GT68xx_Model artec_ultima2000_model = { /* Setup for Cytron TCM MD 9385 */ }; +static GT68xx_Model plustek_opticslim500plus_model = { + "plustek-opticslim-500plus", /* Name */ + "Plustek", /* Device vendor string */ + "OpticSlim 500 Plus", /* Device model name */ + "cis3R5B1.fw", /* Name of the firmware file */ + SANE_FALSE, /* Dynamic allocation flag */ + + &mustek_gt6816_command_set, /* Command set used by this scanner */ + + 600, /* maximum optical sensor resolution */ + 1200, /* maximum motor resolution */ + 600, /* base x-res used to calculate geometry */ + 600, /* base y-res used to calculate geometry */ + 1200, /* if ydpi is equal or higher, disable backtracking */ + SANE_FALSE, /* Use base_ydpi for all resolutions */ + + {600, 300, 150, 75, 50, 0}, /* possible x-resolutions */ + {1200, 600, 300, 150, 75, 50, 0},/* possible y-resolutions */ + {16, 8, 0}, /* possible depths in gray mode */ + {16, 8, 0}, /* possible depths in color mode */ + + SANE_FIX (1.0), /* Start of scan area in mm (x) */ + SANE_FIX (9.5), /* Start of scan area in mm (y) */ + SANE_FIX (218.0), /* Size of scan area in mm (x) */ + SANE_FIX (142.0), /* Size of scan area in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in mm (y) */ + SANE_FIX (0.0), /* Start of black mark in mm (x) */ + + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ + SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ + SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ + + SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ + + 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ + 0, /* CCD distcance for CCD with 6 lines) */ + + COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ + {0x32, 0x02, 0x26, 0x07, 0x26, 0x09}, /* Default offset/gain */ + {0x127, 0x127, 0x127}, /* Default exposure parameters */ + SANE_FIX (1.5), /* Default gamma value */ + + SANE_TRUE, /* Is this a CIS scanner? */ + GT68XX_FLAG_NO_CALIBRATE /* Which flags are needed for this scanner? */ +}; + static GT68xx_Model mustek_2400cu_model = { "mustek-bearpaw-2400-cu", /* Name */ "Mustek", /* Device vendor string */ @@ -1930,6 +1978,7 @@ static GT68xx_USB_Device_Entry gt68xx_usb_device_list[] = { {0x07b3, 0x040b, &plustek_ops12_model}, {0x07b3, 0x040e, &plustek_ops24_model}, {0x07b3, 0x0412, &plustek_opticslim_m12_model}, + {0x07b3, 0x046e, &plustek_opticslim500plus_model}, {0x07b3, 0x0413, &plustek_opticslim1200_model}, {0x07b3, 0x0422, &plustek_opticslim2400_model}, {0x07b3, 0x045f, &iriscan_express_2_model}, diff --git a/backend/gt68xx_generic.c b/backend/gt68xx_generic.c index f5e5bb6..9fd8006 100644 --- a/backend/gt68xx_generic.c +++ b/backend/gt68xx_generic.c @@ -2,44 +2,44 @@ Copyright (C) 2002 Sergey Vlasov Copyright (C) 2005-2007 Henning Geinitz - + 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. + If you do not wish that, delete this exception notice. */ /** @file @@ -112,7 +112,7 @@ gt68xx_generic_fix_gain (SANE_Int gain) gain += 12; else if (gain > 51) gain = 63; - + return gain; } @@ -330,7 +330,7 @@ gt68xx_generic_setup_scan (GT68xx_Device * dev, request->mbs = SANE_TRUE; } } - + } else { @@ -571,7 +571,7 @@ gt68xx_generic_setup_scan (GT68xx_Device * dev, motor_mode_2 = (request->lamp ? 0 : 1) << 0; motor_mode_2 |= (line_mode ? 0 : 1) << 2; - if ((action != SA_SCAN) + if ((action != SA_SCAN) && (strcmp (dev->model->command_set->name, "mustek-gt6816") == 0)) motor_mode_2 |= 1 << 3; @@ -657,11 +657,11 @@ gt68xx_generic_move_paper (GT68xx_Device * dev, if (ydpi > model->base_ydpi) ydpi = base_ydpi; - + pixel_y0 = SANE_UNFIX ((request->y0 + model->y_offset)) * ydpi / MM_PER_INCH + 0.5; abs_y0 = pixel_y0 * base_ydpi / ydpi; - + DBG (6, "gt68xx_generic_move_paper: base_ydpi=%d\n", base_ydpi); DBG (6, "gt68xx_generic_move_paper: ydpi=%d\n", ydpi); DBG (6, "gt68xx_generic_move_paper: abs_y0=%d\n", abs_y0); diff --git a/backend/gt68xx_generic.h b/backend/gt68xx_generic.h index 01ecff9..2008974 100644 --- a/backend/gt68xx_generic.h +++ b/backend/gt68xx_generic.h @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002 Sergey Vlasov - + 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. + If you do not wish that, delete this exception notice. */ #ifndef GT68XX_GENERIC_H diff --git a/backend/gt68xx_gt6801.c b/backend/gt68xx_gt6801.c index d61729c..c0a6288 100644 --- a/backend/gt68xx_gt6801.c +++ b/backend/gt68xx_gt6801.c @@ -3,44 +3,44 @@ Copyright (C) 2002 Sergey Vlasov GT6801 support by Andreas Nowack Copyright (C) 2002-2007 Henning Geinitz - + 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. + If you do not wish that, delete this exception notice. */ /** @file @@ -143,7 +143,7 @@ gt6801_download_firmware (GT68xx_Device * dev, * For GT6816 this was: * if (memcmp (block, check_buf, block_size) != 0) ... * Apparently the GT6801 does something different... - * + * * hmg: For my BP 1200 CU the result is 00 09 so maybe only the 0 is * relevant? */ diff --git a/backend/gt68xx_gt6801.h b/backend/gt68xx_gt6801.h index 750ce39..d6d1ceb 100644 --- a/backend/gt68xx_gt6801.h +++ b/backend/gt68xx_gt6801.h @@ -2,44 +2,44 @@ Copyright (C) 2002 Sergey Vlasov GT6801 support by Andreas Nowack - + 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. + If you do not wish that, delete this exception notice. */ #ifndef GT68XX_GT6801_H diff --git a/backend/gt68xx_gt6816.c b/backend/gt68xx_gt6816.c index 045194a..a7880bd 100644 --- a/backend/gt68xx_gt6816.c +++ b/backend/gt68xx_gt6816.c @@ -2,44 +2,44 @@ Copyright (C) 2002 Sergey Vlasov Copyright (C) 2002-2007 Henning Geinitz - + 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. + If you do not wish that, delete this exception notice. */ /** @file diff --git a/backend/gt68xx_gt6816.h b/backend/gt68xx_gt6816.h index 7b72071..f941811 100644 --- a/backend/gt68xx_gt6816.h +++ b/backend/gt68xx_gt6816.h @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002 Sergey Vlasov - + 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. + If you do not wish that, delete this exception notice. */ #ifndef GT68XX_GT6816_H diff --git a/backend/gt68xx_high.c b/backend/gt68xx_high.c index 25885b0..782b4f3 100644 --- a/backend/gt68xx_high.c +++ b/backend/gt68xx_high.c @@ -3,46 +3,46 @@ Copyright (C) 2002 Sergey Vlasov AFE offset/gain setting by David Stevenson Copyright (C) 2002 - 2007 Henning Geinitz - Copyright (C) 2009 Stéphane Voltz for sheetfed + Copyright (C) 2009 Stéphane Voltz for sheetfed calibration code. 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. + If you do not wish that, delete this exception notice. */ #include "gt68xx_high.h" @@ -560,7 +560,7 @@ gt68xx_scanner_start_scan_extended (GT68xx_Scanner * scanner, return status; } - if (scanner->dev->model->is_cis + if (scanner->dev->model->is_cis && !((scanner->dev->model->flags & GT68XX_FLAG_SHEET_FED) && scanner->calibrated == SANE_FALSE)) { status = @@ -1016,7 +1016,7 @@ struct GT68xx_Afe_Values /** Calculate average black and maximum white * * This function is used for CCD scanners. The black mark to the left ist used - * for the calculation of average black. The remaining calibration strip + * for the calculation of average black. The remaining calibration strip * is used for searching the segment whose white average is the highest. * * @param values AFE values @@ -1189,7 +1189,7 @@ finish: /* Wait for lamp to give stable brightness */ static SANE_Status -gt68xx_wait_lamp_stable (GT68xx_Scanner * scanner, +gt68xx_wait_lamp_stable (GT68xx_Scanner * scanner, GT68xx_Scan_Parameters * params, GT68xx_Scan_Request *request, unsigned int *buffer_pointers[3], @@ -1848,6 +1848,11 @@ gt68xx_afe_cis_auto (GT68xx_Scanner * scanner) DBG (5, "gt68xx_afe_cis_auto: start\n"); + if (scanner->dev->model->flags & GT68XX_FLAG_NO_CALIBRATE) + { + return SANE_STATUS_GOOD; + } + memset (&old_afe, 255, sizeof (old_afe)); /* Start with the preset exposure settings */ @@ -2006,7 +2011,7 @@ gt68xx_calibrator_create_copy (GT68xx_Calibrator ** calibrator, return status; } - + static SANE_Status gt68xx_sheetfed_move_to_scan_area (GT68xx_Scanner * scanner, GT68xx_Scan_Request * request) @@ -2032,8 +2037,8 @@ gt68xx_sheetfed_move_to_scan_area (GT68xx_Scanner * scanner, * target (which may be a blank page). It first move to a white area then * does afe and exposure calibration. Then it scans white lines to get data * for shading correction. - * @param scanner structure describing the frontend session and the device - * @return SANE_STATUS_GOOD is everything goes right, SANE_STATUS_INVAL + * @param scanner structure describing the frontend session and the device + * @return SANE_STATUS_GOOD is everything goes right, SANE_STATUS_INVAL * otherwise. */ static SANE_Status @@ -2349,10 +2354,10 @@ gt68xx_sheetfed_scanner_calibrate (GT68xx_Scanner * scanner) /** @brief assign calibration for scan * This function creates the calibrators and set up afe for the requested - * scan. It uses calibration data that has been created by + * scan. It uses calibration data that has been created by * gt68xx_sheetfed_scanner_calibrate. - * @param scanner structure describing the frontend session and the device - * @return SANE_STATUS_GOOD is everything goes right, SANE_STATUS_INVAL + * @param scanner structure describing the frontend session and the device + * @return SANE_STATUS_GOOD is everything goes right, SANE_STATUS_INVAL * otherwise. */ static SANE_Status diff --git a/backend/gt68xx_high.h b/backend/gt68xx_high.h index d830e96..da4ab6a 100644 --- a/backend/gt68xx_high.h +++ b/backend/gt68xx_high.h @@ -2,44 +2,44 @@ Copyright (C) 2002 Sergey Vlasov Copyright (C) 2002-2007 Henning Geinitz - + 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. + If you do not wish that, delete this exception notice. */ #ifndef GT68XX_HIGH_H @@ -77,11 +77,11 @@ struct GT68xx_Calibrator /** Calibration data for a given resolution */ struct GT68xx_Calibration -{ +{ SANE_Int dpi; /**< optical horizontal dpi used to build the calibration data */ SANE_Int pixel_x0; /**< x start position used at calibration time */ - + GT68xx_Calibrator *gray; /**< Calibrator for grayscale data */ GT68xx_Calibrator *red; /**< Calibrator for the red channel */ GT68xx_Calibrator *green; /**< Calibrator for the green channel */ diff --git a/backend/gt68xx_low.c b/backend/gt68xx_low.c index 6060c45..3ea4590 100644 --- a/backend/gt68xx_low.c +++ b/backend/gt68xx_low.c @@ -2,44 +2,44 @@ Copyright (C) 2002 Sergey Vlasov Copyright (C) 2002 - 2007 Henning Geinitz - + 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. + If you do not wish that, delete this exception notice. */ /** @file @@ -1023,7 +1023,7 @@ gt68xx_device_get_id (GT68xx_Device * dev) return SANE_STATUS_UNSUPPORTED; } -static void +static void gt68xx_device_fix_descriptor (GT68xx_Device * dev) { SANE_Byte data[8]; diff --git a/backend/gt68xx_low.h b/backend/gt68xx_low.h index 0743230..89bd365 100644 --- a/backend/gt68xx_low.h +++ b/backend/gt68xx_low.h @@ -2,44 +2,44 @@ Copyright (C) 2002 Sergey Vlasov Copyright (C) 2002 - 2007 Henning Geinitz - + 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. + If you do not wish that, delete this exception notice. */ #ifndef GT68XX_LOW_H @@ -112,6 +112,9 @@ #define GT68XX_FLAG_SHEET_FED (1 << 12) /* we have a sheet fed scanner */ #define GT68XX_FLAG_HAS_CALIBRATE (1 << 13) /* for sheet fed scanners that be calibrated with an calibration sheet */ +#define GT68XX_FLAG_NO_CALIBRATE (1 << 14) /* don't calibrate, because calibration is broken */ + + /* Forward typedefs */ typedef struct GT68xx_USB_Device_Entry GT68xx_USB_Device_Entry; @@ -162,7 +165,7 @@ struct GT68xx_USB_Device_Entry /** List of all supported devices. * - * This is an array of GT68xx_USB_Device_Entry structures which describe + * This is an array of GT68xx_USB_Device_Entry structures which describe * USB devices supported by this backend. The array is terminated by an * entry with model = NULL. * @@ -319,7 +322,7 @@ struct GT68xx_Command_Set SANE_Status (*lamp_control) (GT68xx_Device * dev, SANE_Bool fb_lamp, SANE_Bool ta_lamp); - /** Check whether the scanner carriage is still moving. + /** Check whether the scanner carriage is still moving. * * @param dev Device object. * @param moving Returned state of the scanner: @@ -400,7 +403,7 @@ struct GT68xx_Command_Set /** Detect if a document is inserted in the feeder * * @param dev Device object. - * @param present + * @param present */ SANE_Status (*document_present) (GT68xx_Device * dev, SANE_Bool *present); @@ -564,7 +567,7 @@ struct GT68xx_Scan_Request * * These parameters describe a low-level scan request; many such requests are * executed during calibration, and they need to have parameters separate from - * the main request (GT68xx_Scan_Request). + * the main request (GT68xx_Scan_Request). */ struct GT68xx_Scan_Parameters { @@ -883,7 +886,7 @@ static SANE_Status gt68xx_device_lamp_control (GT68xx_Device * dev, SANE_Bool fb_lamp, SANE_Bool ta_lamp); -/** Check whether the scanner carriage is still moving. +/** Check whether the scanner carriage is still moving. * * @param dev Device object. * @param moving Returned state of the scanner: @@ -1067,7 +1070,7 @@ static SANE_Status gt68xx_device_read_finish (GT68xx_Device * dev); * * @param res Result packet from the last command * @param command Command - * + * * @return * - #SANE_STATUS_GOOD - success. * - #SANE_STATUS_IO_ERROR - the command wasn't successful @@ -1076,7 +1079,7 @@ static SANE_Status gt68xx_device_check_result (GT68xx_Packet res, SANE_Byte command); -static SANE_Status +static SANE_Status gt68xx_device_get_id (GT68xx_Device * dev); /** Read the device descriptor of the scanner. @@ -1088,7 +1091,7 @@ gt68xx_device_get_id (GT68xx_Device * dev); * * @param dev device */ -static void +static void gt68xx_device_fix_descriptor (GT68xx_Device * dev); #endif /* not GT68XX_LOW_H */ diff --git a/backend/gt68xx_mid.c b/backend/gt68xx_mid.c index 1301139..0d5cbe4 100644 --- a/backend/gt68xx_mid.c +++ b/backend/gt68xx_mid.c @@ -2,44 +2,44 @@ Copyright (C) 2002 Sergey Vlasov Copyright (C) 2002-2007 Henning Geinitz - + 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. + If you do not wish that, delete this exception notice. */ #include "gt68xx_mid.h" diff --git a/backend/gt68xx_mid.h b/backend/gt68xx_mid.h index 4ba6c4c..2bbaac2 100644 --- a/backend/gt68xx_mid.h +++ b/backend/gt68xx_mid.h @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002 Sergey Vlasov - + 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. + If you do not wish that, delete this exception notice. */ #ifndef GT68XX_MID_H diff --git a/backend/gt68xx_shm_channel.c b/backend/gt68xx_shm_channel.c index bca7425..496a959 100644 --- a/backend/gt68xx_shm_channel.c +++ b/backend/gt68xx_shm_channel.c @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002 Sergey Vlasov - + 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. + If you do not wish that, delete this exception notice. */ /** @file diff --git a/backend/gt68xx_shm_channel.h b/backend/gt68xx_shm_channel.h index c6cfdff..54b5eca 100644 --- a/backend/gt68xx_shm_channel.h +++ b/backend/gt68xx_shm_channel.h @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002 Sergey Vlasov - + 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. + If you do not wish that, delete this exception notice. */ #ifndef GT68XX_SHM_CHANNEL_H diff --git a/backend/hp-device.c b/backend/hp-device.c index 6a50f84..30e7a79 100644 --- a/backend/hp-device.c +++ b/backend/hp-device.c @@ -471,4 +471,3 @@ sanei_hp_device_sanedevice (HpDevice this) { return &this->sanedev; } - diff --git a/backend/hp-handle.c b/backend/hp-handle.c index ec8adbc..63e9fcb 100644 --- a/backend/hp-handle.c +++ b/backend/hp-handle.c @@ -227,16 +227,9 @@ hp_handle_stopScan (HpHandle this) { int info; DBG(3, "hp_handle_stopScan: killing child (%ld)\n", (long) this->reader_pid); - if (this->child_forked) - { - kill(this->reader_pid, SIGTERM); - waitpid(this->reader_pid, &info, 0); - } - else - { - sanei_thread_kill (this->reader_pid); - sanei_thread_waitpid(this->reader_pid, &info); - } + sanei_thread_kill (this->reader_pid); + sanei_thread_waitpid(this->reader_pid, &info); + DBG(1, "hp_handle_stopScan: child %s = %d\n", WIFEXITED(info) ? "exited, status" : "signalled, signal", WIFEXITED(info) ? WEXITSTATUS(info) : WTERMSIG(info)); @@ -746,10 +739,7 @@ sanei_hp_handle_cancel (HpHandle this) { DBG(3,"sanei_hp_handle_cancel: send SIGTERM to child (%ld)\n", (long) this->reader_pid); - if (this->child_forked) - kill(this->reader_pid, SIGTERM); - else - sanei_thread_kill(this->reader_pid); + sanei_thread_kill(this->reader_pid); } } diff --git a/backend/hp-option.c b/backend/hp-option.c index ba799b7..f4d23f8 100644 --- a/backend/hp-option.c +++ b/backend/hp-option.c @@ -851,16 +851,19 @@ _probe_resolution (_HpOption this, HpScsi scsi, HpOptSet __sane_unused__ optset, if ( (sanei_hp_device_probe (&compat, scsi) == SANE_STATUS_GOOD) && (compat & HP_COMPAT_PS) ) - {int val, mi, ma; + { + int val, mi, ma; - if ( (sanei_hp_scl_inquire(scsi, SCL_MEDIA, &val, &mi, &ma) + if ( (sanei_hp_scl_inquire(scsi, SCL_MEDIA, &val, &mi, &ma) == SANE_STATUS_GOOD) - && ((val == HP_MEDIA_SLIDE) || (val == HP_MEDIA_NEGATIVE)) ) - quant = 300; - minval = (minval+quant-1)/quant; - minval *= quant; - maxval = (maxval+quant-1)/quant; - maxval *= quant; + && ((val == HP_MEDIA_SLIDE) || (val == HP_MEDIA_NEGATIVE)) ) + { + quant = 300; + minval = (minval+quant-1)/quant; + minval *= quant; + maxval = (maxval+quant-1)/quant; + maxval *= quant; + } } DBG(5, "_probe_resolution: set range %d..%d, quant=%d\n",minval,maxval,quant); @@ -2431,7 +2434,7 @@ _program_scan_type (HpOption this, HpScsi scsi, HpOptSet optset, HpData data) sanei_hp_scl_set(scsi, SCL_TONE_MAP, -1); /* Select tone map */ } } - + return SANE_STATUS_GOOD; } diff --git a/backend/hp-scl.c b/backend/hp-scl.c index f1813c7..a7376e6 100644 --- a/backend/hp-scl.c +++ b/backend/hp-scl.c @@ -553,7 +553,7 @@ hp_scsi_close (HpScsi this, int completely) DBG(3, "scsi_close: not closing. Keep open\n"); return; } - + } assert(this->fd >= 0); diff --git a/backend/hp.README b/backend/hp.README index 756ddca..0727221 100644 --- a/backend/hp.README +++ b/backend/hp.README @@ -51,7 +51,7 @@ to xhp just to get a better acceptance. Test support of commands to be independant from inquired model number. - + Wed Mar 28 10:00:00 UT+1 1998 Bring it on its way to the SANE-project. Geoffrey accepted to add diff --git a/backend/hp.c b/backend/hp.c index f00b82d..f6a3637 100644 --- a/backend/hp.c +++ b/backend/hp.c @@ -73,7 +73,7 @@ static char *hp_backend_revision = "$Revision$"; Revision 1.17 2003/10/06 19:54:07 kig-guest Bug #300248: correct "Negatives" to "Negative" in option description - + V 1.04, 24-Jul-2003, PK (peter@kirchgessner.net) - Add internationalization diff --git a/backend/hp3500.c b/backend/hp3500.c index 26fe071..fc2c6b5 100644 --- a/backend/hp3500.c +++ b/backend/hp3500.c @@ -253,7 +253,7 @@ static const SANE_Device **devlist = 0; /** * Called by SANE initially. - * + * * From the SANE spec: * This function must be called before any other SANE function can be * called. The behavior of a SANE backend is undefined if this @@ -287,7 +287,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /** * Called by SANE to find out about supported devices. - * + * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a @@ -300,7 +300,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. - * + * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and @@ -452,7 +452,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /** * Gets or sets an option value. - * + * * From the SANE spec: * This function is used to set or inquire the current value of option * number n of the device represented by handle h. The manner in which @@ -463,7 +463,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) * area pointed to by v must be big enough to hold the entire option * value (determined by member size in the corresponding option * descriptor). - * + * * The only exception to this rule is that when setting the value of a * string option, the string pointed to by argument v may be shorter * since the backend will stop reading the option value upon @@ -751,7 +751,7 @@ sane_start (SANE_Handle handle) * completion of that request. Outside of that window, the returned * values are best-effort estimates of what the parameters will be * when sane_start() gets invoked. - * + * * Calling this function before a scan has actually started allows, * for example, to get an estimate of how big the scanned image will * be. The parameters passed to this function are the handle h of the @@ -788,12 +788,12 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) /** * Called by SANE to read data. - * + * * In this implementation, sane_read does nothing much besides reading * data from a pipe and handing it back. On the other end of the pipe * there's the reader process which gets data from the scanner and * stuffs it into the pipe. - * + * * From the SANE spec: * This function is used to read image data from the device * represented by handle h. Argument buf is a pointer to a memory @@ -801,7 +801,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) * returned is stored in *len. A backend must set this to zero when * the call fails (i.e., when a status other than SANE_STATUS_GOOD is * returned). - * + * * When the call succeeds, the number of bytes returned can be * anywhere in the range from 0 to maxlen bytes. */ @@ -846,26 +846,26 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, /** - * Cancels a scan. + * Cancels a scan. * * It has been said on the mailing list that sane_cancel is a bit of a * misnomer because it is routinely called to signal the end of a * batch - quoting David Mosberger-Tang: - * + * * > In other words, the idea is to have sane_start() be called, and * > collect as many images as the frontend wants (which could in turn * > consist of multiple frames each as indicated by frame-type) and - * > when the frontend is done, it should call sane_cancel(). + * > when the frontend is done, it should call sane_cancel(). * > Sometimes it's better to think of sane_cancel() as "sane_stop()" * > but that name would have had some misleading connotations as * > well, that's why we stuck with "cancel". - * + * * The current consensus regarding duplex and ADF scans seems to be * the following call sequence: sane_start; sane_read (repeat until * EOF); sane_start; sane_read... and then call sane_cancel if the * batch is at an end. I.e. do not call sane_cancel during the run but * as soon as you get a SANE_STATUS_NO_DOCS. - * + * * From the SANE spec: * This function is used to immediately or as quickly as possible * cancel the currently pending operation of the device represented by @@ -892,7 +892,7 @@ sane_cancel (SANE_Handle h) /** * Ends use of the scanner. - * + * * From the SANE spec: * This function terminates the association between the device handle * passed in argument h and the device it represents. If the device is @@ -910,7 +910,7 @@ sane_close (SANE_Handle handle) /** * Terminates the backend. - * + * * From the SANE spec: * This function must be called to terminate use of a backend. The * function will first close all device handles that still might be @@ -1134,7 +1134,7 @@ do_cancel (struct hp3500_data *scanner) sanei_thread_waitpid (scanner->reader_pid, &exit_status); } - scanner->reader_pid = -1; + sanei_thread_invalidate (scanner->reader_pid); } if (scanner->pipe_r >= 0) { @@ -1149,7 +1149,7 @@ calculateDerivedValues (struct hp3500_data *scanner) DBG (12, "calculateDerivedValues\n"); - /* Convert the SANE_FIXED values for the scan area into 1/1200 inch + /* Convert the SANE_FIXED values for the scan area into 1/1200 inch * scanner units */ scanner->fullres_pixels.left = @@ -3139,7 +3139,7 @@ rts8801_fullscan (unsigned x, tg_setting = resparms[rmres].tg; rt_set_ccd_shift_clock_multiplier (regs, tg_info[tg_setting].tg_cph0p); rt_set_ccd_clock_reset_interval (regs, tg_info[tg_setting].tg_crsp); - rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp); + rt_set_ccd_clamp_clock_multiplier (regs, tg_info[tg_setting].tg_cclpp); rt_set_one_register (0xc6, 0); rt_set_one_register (0xc6, 0); @@ -3386,7 +3386,7 @@ rts8801_scan (unsigned x, iCalibY = (resolution == 25) ? 1 : 2; iCalibTarget = 550; - + rt_turn_off_lamp(); for (i = 0; i < 6; ++i) @@ -3394,7 +3394,7 @@ rts8801_scan (unsigned x, aiBestOffset[i] = 0xbf; aiPassed[i] = 0; } - + do { DBG (30, "Initial calibration pass commences\n"); @@ -3405,7 +3405,7 @@ rts8801_scan (unsigned x, calib_info[i * 3] = aiBestOffset[i]; calib_info[i * 3 + 1] = aiBestOffset[i + 3]; } - + cd.buffer = calibbuf; cd.space = sizeof (calibbuf); DBG (30, "Commencing scan for initial calibration pass\n"); @@ -3453,7 +3453,7 @@ rts8801_scan (unsigned x, calib_info[i * 3 + 2] = 1; aiPassed[i] = 0; } - + do { struct dcalibdata dcdt; @@ -3782,12 +3782,14 @@ writefunc (struct hp3500_write_info *winfo, int bytes, char *data) return write (winfo->scanner->pipe_w, data, bytes) == bytes; } +#ifdef _POSIX_SOURCE static void sigtermHandler (int signal) { signal = signal; /* get rid of compiler warning */ cancelled_scan = 1; } +#endif static int reader_process (void *pv) diff --git a/backend/hp3900.conf.in b/backend/hp3900.conf.in index 2de0001..0b0262b 100644 --- a/backend/hp3900.conf.in +++ b/backend/hp3900.conf.in @@ -28,4 +28,3 @@ usb 0x06dc 0x0020 # BenQ 5550 usb 0x04a5 0x2211 - diff --git a/backend/hp3900_config.c b/backend/hp3900_config.c index 3c0ed77..830243b 100644 --- a/backend/hp3900_config.c +++ b/backend/hp3900_config.c @@ -243,7 +243,7 @@ enum fcsec6 CALIBOFFSET2ON, OFFSETTUNESTEP2, OFFSETBOUNDARYRATIO2, OFFSETAVGRATIO2, - + OFFSETEVEN2R, OFFSETEVEN2G, OFFSETEVEN2B, OFFSETODD2R, OFFSETODD2G, OFFSETODD2B, @@ -5622,7 +5622,7 @@ static int fitcalibrate_get(int section, int option, int defvalue) case SCANINFO: rst = fc_scaninfo_get(option, defvalue); break; } - + return rst; } diff --git a/backend/hp3900_debug.c b/backend/hp3900_debug.c index eb7d45c..b8cd8f1 100644 --- a/backend/hp3900_debug.c +++ b/backend/hp3900_debug.c @@ -764,7 +764,7 @@ dbg_buffer (SANE_Int level, char *title, SANE_Byte * buffer, SANE_Int size, bzero (&text, sizeof (text)); } data = _B0 (buffer[cont]); - text[col] = (data > 31) ? data : '·'; + text[col] = (data > 31) ? data : '·'; snprintf (sdata, 80, "%02x ", data); sline = strcat (sline, sdata); col++; diff --git a/backend/hp3900_rts8822.c b/backend/hp3900_rts8822.c index 9c8deaa..bbd1e38 100644 --- a/backend/hp3900_rts8822.c +++ b/backend/hp3900_rts8822.c @@ -1774,7 +1774,7 @@ SetScanParams (struct st_device *dev, SANE_Byte * Regs, 8)) ? hwdcfg->compression : FALSE; if ((arrangeline2 == FIX_BY_HARD) || (mycolormode == CM_LINEART)) - arrangeline2 = mycolormode; /*¿? */ + arrangeline2 = mycolormode; /*¿? */ else if ((mycolormode == CM_GRAY) && (hwdcfg->highresolution == FALSE)) arrangeline2 = 0; @@ -2372,7 +2372,7 @@ IsScannerLinked (struct st_device *dev) lamp = FLB_LAMP; - /* Comprobar si es la primera conexión con el escaner */ + /* Comprobar si es la primera conexión con el escaner */ if (Read_Word (dev->usb_handle, 0xe829, &var2) == OK) { SANE_Int firstconnection; @@ -2385,7 +2385,7 @@ IsScannerLinked (struct st_device *dev) if (firstconnection == TRUE) { - /* primera conexión */ + /* primera conexión */ SANE_Byte flb_lamp, tma_lamp; flb_lamp = 0; @@ -7049,7 +7049,7 @@ Triplet_Colour_LRes (SANE_Int Width, SANE_Byte * Buffer, */ /* Esta funcion une los tres canales de color en un triplete - Inicialmente cada color está separado en 3 buffers apuntados + Inicialmente cada color está separado en 3 buffers apuntados por pChannel1 ,2 y 3 */ SANE_Int Value; @@ -7591,11 +7591,11 @@ Read_Block (struct st_device *dev, SANE_Int buffer_size, SANE_Byte * buffer, /* scan2: 04F0155C 01 08 00 02 03 00 58 02 ..X -04F01564 58 02 58 02 C5 00 00 00 XXÅ... -04F0156C B4 07 00 00 8B 01 00 00 ´..‹.. -04F01574 10 06 00 00 EC 13 00 00 ..ì.. -04F0157C B2 07 00 00 B4 07 00 00 ²..´.. -04F01584 CF 08 00 00 Ï.. +04F01564 58 02 58 02 C5 00 00 00 XXÃ…... +04F0156C B4 07 00 00 8B 01 00 00 ´..‹.. +04F01574 10 06 00 00 EC 13 00 00 ..ì.. +04F0157C B2 07 00 00 B4 07 00 00 ²..´.. +04F01584 CF 08 00 00 Ã.. arrangeline2 = 1 */ @@ -8329,7 +8329,7 @@ if (Calib_test(dev, Regs, &myCalib, &scancfg) == OK ) } else { - /*5e7c *//* entra aquí */ + /*5e7c *//* entra aquí */ if ((scancfg.resolution_y / 10) > scancfg.coord.top) runb1 = 0; } @@ -9209,7 +9209,7 @@ RTS_Setup (struct st_device *dev, SANE_Byte * Regs, if (scancfg->colormode == CM_LINEART) data_bitset (&Regs[0x60b], 0x0c, 0); - /* disable gamma correction ¿? */ + /* disable gamma correction ¿? */ data_bitset (&Regs[0x1d0], 0x40, 0); } @@ -13902,7 +13902,7 @@ Constrains_Check (struct st_device *dev, SANE_Int Resolution, SANE_Int scantype, struct st_coords *mycoords) { /* - Constrains: + Constrains: 100 dpi 850 x 1170 | 164 x 327 300 dpi 2550 x 3510 600 dpi 5100 x 7020 diff --git a/backend/hp4200.c b/backend/hp4200.c index 589157d..d4d4f64 100644 --- a/backend/hp4200.c +++ b/backend/hp4200.c @@ -5,24 +5,24 @@ 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. + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Developers: - Adrian Perez Jorge (APJ) - + Adrian Perez Jorge (APJ) - Creator of the original HP4200C backend code. adrianpj@easynews.com - - Andrew John Lewis (AJL) - + + Andrew John Lewis (AJL) - lewi0235@tc.umn.edu Arnar Mar Hrafnkelsson (AMH) - @@ -43,7 +43,7 @@ TODO: image size and the scanner-to-host bandwidth. - improve image quality. - fix problem concerning mangled images - + */ #define BUILD 2 @@ -1498,7 +1498,7 @@ do_fine_calibration (HP4200_Scanner * s, struct coarse_t *coarse) int i; for (i = 0; i < 12; i++) { - memset (registro[i], 0, 5460 * 3); + memset (registro[i], 0, 5460 * 3 * sizeof(registro[0])); } } @@ -1884,7 +1884,7 @@ prepare_for_a_scan (HP4200_Scanner * s) calculated horizontal dpi code */ hdpi_div = hdpi_mapping[hdpi_code]; - /* image_width is set to the correct number of pixels by calling + /* image_width is set to the correct number of pixels by calling fxn. This might be the reason we can't do high res full width scans though...not sure. */ /*s->user_parms.image_width /= 4; */ diff --git a/backend/hp4200.h b/backend/hp4200.h index 13c0d7f..1547847 100644 --- a/backend/hp4200.h +++ b/backend/hp4200.h @@ -5,15 +5,15 @@ 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. + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef _HP4200_H diff --git a/backend/hp5400.c b/backend/hp5400.c index cfa2dc9..58d01f8 100644 --- a/backend/hp5400.c +++ b/backend/hp5400.c @@ -4,21 +4,21 @@ This file was initially copied from the hp3300 testools and adjusted to suit. Original copyright notice follows: - + Copyright (C) 2001 Bertrik Sikken (bertrik@zonnet.nl) 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. @@ -81,5 +81,3 @@ #include "hp5400_internal.c" #include "hp5400_sane.c" #include "hp5400_sanei.c" - - diff --git a/backend/hp5400_debug.c b/backend/hp5400_debug.c index 0460e8b..ad2e4fb 100644 --- a/backend/hp5400_debug.c +++ b/backend/hp5400_debug.c @@ -69,5 +69,3 @@ void hp5400_dbg_start() { #include "../include/sane/sanei_debug.h" #endif - - diff --git a/backend/hp5400_internal.c b/backend/hp5400_internal.c index 65a434f..34bf55d 100644 --- a/backend/hp5400_internal.c +++ b/backend/hp5400_internal.c @@ -212,10 +212,10 @@ SetCalibration (int iHandle, int numPixels, unsigned int *low_vals[3], { char cmd[8]; /* unsigned char cmd[8]; */ /* should fix the compilation warning - but I don't have a scanner right now + but I don't have a scanner right now to check that the fix does not break calibration */ - + int i, j, k; struct CalPixel { @@ -413,7 +413,7 @@ CircBufferGetLine (int iHandle, TDataPipe * p, void *pabLine) int i; int maxoff = 0; char* buftmp = (char*) (p->buffer); - + /* HP5400_DBG(DBG_MSG, "CircBufferGetLine:\n"); */ if (p->roff > maxoff) @@ -1018,7 +1018,7 @@ InitScan (enum ScanType scantype, TScanParams * pParams, struct ScanRequest req; struct ScanResponse res; int ret; - + memset(&req, 0, sizeof(req)); req.x1 = 0x08; @@ -1089,7 +1089,7 @@ InitScan2 (enum ScanType scantype, struct ScanRequest *req, req->offx = htons (0x09F8); if (htons (req->offy) > 0x0DB6) req->offy = htons (0x0DB6); - /* These tests are meaningless as htons() returns unsigned + /* These tests are meaningless as htons() returns unsigned if( htons( req->offx ) < 0 ) req->offx = 0; if( htons( req->offy ) < 0 ) req->offy = 0; */ diff --git a/backend/hp5400_sanei.c b/backend/hp5400_sanei.c index 1396cb1..10c90ef 100644 --- a/backend/hp5400_sanei.c +++ b/backend/hp5400_sanei.c @@ -133,7 +133,7 @@ hp5400_open (const char *filename) sane_strstatus (status)); return -1; } - + status = sanei_usb_get_vendor_product (fd, &iVendor, &iProduct); if (status != SANE_STATUS_GOOD) { @@ -313,7 +313,7 @@ hp5400_bulk_read_block (int iHandle, int iCmd, void *cmd, int cmdlen, _UsbWriteControl (fd, iCmd, 0, cmd, cmdlen); res = len; sanei_usb_read_bulk (fd, (SANE_Byte *) buffer, &res); - HP5400_DBG (DBG_MSG, "Read block returned %lu when reading %d\n", + HP5400_DBG (DBG_MSG, "Read block returned %lu when reading %d\n", (u_long) res, len); return res; } @@ -384,4 +384,3 @@ hp5400_isOn (int iHandle) return 0; /* is off */ } #endif - diff --git a/backend/hp5400_xfer.h b/backend/hp5400_xfer.h index e3e823d..b3a1cc6 100644 --- a/backend/hp5400_xfer.h +++ b/backend/hp5400_xfer.h @@ -47,7 +47,7 @@ If you do not wish that, delete this exception notice. Transport layer for communication with HP5400/5470 scanner. - + Add support for bulk transport of data - 19/02/2003 Martijn */ diff --git a/backend/hp5590.c b/backend/hp5590.c index fabf40a..b206406 100644 --- a/backend/hp5590.c +++ b/backend/hp5590.c @@ -1,6 +1,8 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2007 Ilia Sotnikov HP ScanJet 4570c support by Markham Thomas + ADF page detection and high DPI fixes by Bernard Badeer + scanbd integration by Damiano Scaramuzza and Bernard Badeer This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -59,47 +61,161 @@ #include "../include/sane/saneopts.h" #include "hp5590_cmds.c" #include "hp5590_low.c" +#include "../include/sane/sanei_net.h" /* Debug levels */ -#define DBG_err 0 -#define DBG_proc 10 -#define DBG_verbose 20 +#define DBG_err 0 +#define DBG_proc 10 +#define DBG_verbose 20 +#define DBG_details 30 #define hp5590_assert(exp) if(!(exp)) { \ - DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ - return SANE_STATUS_INVAL; \ + DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ + return SANE_STATUS_INVAL; \ } #define hp5590_assert_void_return(exp) if(!(exp)) { \ - DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ - return; \ + DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ + return; \ } +#define MY_MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define MY_MAX(a, b) (((a) > (b)) ? (a) : (b)) + /* #define HAS_WORKING_COLOR_48 */ -#define BUILD 7 -#define USB_TIMEOUT 30 * 1000 +#define BUILD 8 +#define USB_TIMEOUT 30 * 1000 static SANE_Word res_list[] = { 6, 100, 200, 300, 600, 1200, 2400 }; -#define SANE_VALUE_SCAN_SOURCE_FLATBED SANE_I18N("Flatbed") -#define SANE_VALUE_SCAN_SOURCE_ADF SANE_I18N("ADF") -#define SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX SANE_I18N("ADF Duplex") -#define SANE_VALUE_SCAN_SOURCE_TMA_SLIDES SANE_I18N("TMA Slides") -#define SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES SANE_I18N("TMA Negatives") +#define SANE_VALUE_SCAN_SOURCE_FLATBED SANE_I18N("Flatbed") +#define SANE_VALUE_SCAN_SOURCE_ADF SANE_I18N("ADF") +#define SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX SANE_I18N("ADF Duplex") +#define SANE_VALUE_SCAN_SOURCE_TMA_SLIDES SANE_I18N("TMA Slides") +#define SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES SANE_I18N("TMA Negatives") +static SANE_String_Const +sources_list[] = { + SANE_VALUE_SCAN_SOURCE_FLATBED, + SANE_VALUE_SCAN_SOURCE_ADF, + SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, + SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, + SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, + NULL +}; + +#define SANE_VALUE_SCAN_MODE_COLOR_24 SANE_VALUE_SCAN_MODE_COLOR +#define SANE_VALUE_SCAN_MODE_COLOR_48 SANE_I18N("Color (48 bits)") +#define HAS_WORKING_COLOR_48 1 + +#define SANE_NAME_LAMP_TIMEOUT "extend-lamp-timeout" +#define SANE_TITLE_LAMP_TIMEOUT SANE_I18N("Extend lamp timeout") +#define SANE_DESC_LAMP_TIMEOUT SANE_I18N("Extends lamp timeout (from 15 minutes to 1 hour)") +#define SANE_NAME_WAIT_FOR_BUTTON "wait-for-button" +#define SANE_TITLE_WAIT_FOR_BUTTON SANE_I18N("Wait for button") +#define SANE_DESC_WAIT_FOR_BUTTON SANE_I18N("Waits for button before scanning") +#define SANE_NAME_BUTTON_PRESSED "button-pressed" +#define SANE_TITLE_BUTTON_PRESSED SANE_I18N("Last button pressed") +#define SANE_DESC_BUTTON_PRESSED SANE_I18N("Get ID of last button pressed (read only)") +#define SANE_NAME_LCD_COUNTER "counter-value" +#define SANE_TITLE_LCD_COUNTER SANE_I18N("LCD counter") +#define SANE_DESC_LCD_COUNTER SANE_I18N("Get value of LCD counter (read only)") +#define SANE_NAME_COLOR_LED "color-led" +#define SANE_TITLE_COLOR_LED SANE_I18N("Color LED indicator") +#define SANE_DESC_COLOR_LED SANE_I18N("Get value of LED indicator (read only)") +#define SANE_NAME_DOC_IN_ADF "doc-in-adf" +#define SANE_TITLE_DOC_IN_ADF SANE_I18N("Document available in ADF") +#define SANE_DESC_DOC_IN_ADF SANE_I18N("Get state of document-available indicator in ADF (read only)") +#define SANE_NAME_OVERWRITE_EOP_PIXEL "hide-eop-pixel" +#define SANE_TITLE_OVERWRITE_EOP_PIXEL SANE_I18N("Hide end-of-page pixel") +#define SANE_DESC_OVERWRITE_EOP_PIXEL SANE_I18N("Hide end-of-page indicator pixels and overwrite with neighbor pixels") +#define SANE_NAME_TRAILING_LINES_MODE "trailing-lines-mode" +#define SANE_TITLE_TRAILING_LINES_MODE SANE_I18N("Filling mode of trailing lines after scan data (ADF)") +#define SANE_DESC_TRAILING_LINES_MODE SANE_I18N("raw = raw scan data, last = repeat last scan line, raster = b/w raster, "\ + "white = white color, black = black color, color = RGB or gray color value") +#define SANE_NAME_TRAILING_LINES_COLOR "trailing-lines-color" +#define SANE_TITLE_TRAILING_LINES_COLOR SANE_I18N("RGB or gray color value for filling mode 'color'") +#define SANE_DESC_TRAILING_LINES_COLOR SANE_I18N("Color value for trailing lines filling mode 'color'. "\ + "RGB color as r*65536+256*g+b or gray value (default=violet or gray)") + +#define BUTTON_PRESSED_VALUE_COUNT 11 +#define BUTTON_PRESSED_VALUE_NONE_KEY "none" +#define BUTTON_PRESSED_VALUE_POWER_KEY "power" +#define BUTTON_PRESSED_VALUE_SCAN_KEY "scan" +#define BUTTON_PRESSED_VALUE_COLLECT_KEY "collect" +#define BUTTON_PRESSED_VALUE_FILE_KEY "file" +#define BUTTON_PRESSED_VALUE_EMAIL_KEY "email" +#define BUTTON_PRESSED_VALUE_COPY_KEY "copy" +#define BUTTON_PRESSED_VALUE_UP_KEY "up" +#define BUTTON_PRESSED_VALUE_DOWN_KEY "down" +#define BUTTON_PRESSED_VALUE_MODE_KEY "mode" +#define BUTTON_PRESSED_VALUE_CANCEL_KEY "cancel" +#define BUTTON_PRESSED_VALUE_MAX_KEY_LEN 32 +static SANE_String_Const +buttonstate_list[] = { + BUTTON_PRESSED_VALUE_NONE_KEY, + BUTTON_PRESSED_VALUE_POWER_KEY, + BUTTON_PRESSED_VALUE_SCAN_KEY, + BUTTON_PRESSED_VALUE_COLLECT_KEY, + BUTTON_PRESSED_VALUE_FILE_KEY, + BUTTON_PRESSED_VALUE_EMAIL_KEY, + BUTTON_PRESSED_VALUE_COPY_KEY, + BUTTON_PRESSED_VALUE_UP_KEY, + BUTTON_PRESSED_VALUE_DOWN_KEY, + BUTTON_PRESSED_VALUE_MODE_KEY, + BUTTON_PRESSED_VALUE_CANCEL_KEY, + NULL +}; + +#define COLOR_LED_VALUE_COUNT 2 +#define COLOR_LED_VALUE_COLOR_KEY "color" +#define COLOR_LED_VALUE_BLACKWHITE_KEY "black_white" +#define COLOR_LED_VALUE_MAX_KEY_LEN 32 +static SANE_String_Const +colorledstate_list[] = { + COLOR_LED_VALUE_COLOR_KEY, + COLOR_LED_VALUE_BLACKWHITE_KEY, + NULL +}; -#define SANE_VALUE_SCAN_MODE_COLOR_24 SANE_VALUE_SCAN_MODE_COLOR -#define SANE_VALUE_SCAN_MODE_COLOR_48 SANE_I18N("Color (48 bits)") +#define LCD_COUNTER_VALUE_MIN 1 +#define LCD_COUNTER_VALUE_MAX 99 +#define LCD_COUNTER_VALUE_QUANT 1 +static SANE_Range +lcd_counter_range = { + LCD_COUNTER_VALUE_MIN, + LCD_COUNTER_VALUE_MAX, + LCD_COUNTER_VALUE_QUANT +}; -#define SANE_NAME_LAMP_TIMEOUT "extend-lamp-timeout" -#define SANE_TITLE_LAMP_TIMEOUT SANE_I18N("Extend lamp timeout") -#define SANE_DESC_LAMP_TIMEOUT SANE_I18N("Extends lamp timeout (from 15 minutes to 1 hour)") -#define SANE_NAME_WAIT_FOR_BUTTON "wait-for-button" -#define SANE_TITLE_WAIT_FOR_BUTTON SANE_I18N("Wait for button") -#define SANE_DESC_WAIT_FOR_BUTTON SANE_I18N("Waits for button before scanning") +#define TRAILING_LINES_MODE_RAW 0 +#define TRAILING_LINES_MODE_LAST 1 +#define TRAILING_LINES_MODE_RASTER 2 +#define TRAILING_LINES_MODE_WHITE 3 +#define TRAILING_LINES_MODE_BLACK 4 +#define TRAILING_LINES_MODE_COLOR 5 +#define TRAILING_LINES_MODE_VALUE_COUNT 6 + +#define TRAILING_LINES_MODE_RAW_KEY "raw" +#define TRAILING_LINES_MODE_LAST_KEY "last" +#define TRAILING_LINES_MODE_RASTER_KEY "raster" +#define TRAILING_LINES_MODE_WHITE_KEY "white" +#define TRAILING_LINES_MODE_BLACK_KEY "black" +#define TRAILING_LINES_MODE_COLOR_KEY "color" +#define TRAILING_LINES_MODE_MAX_KEY_LEN 24 +static SANE_String_Const +trailingmode_list[] = { + TRAILING_LINES_MODE_RAW_KEY, + TRAILING_LINES_MODE_LAST_KEY, + TRAILING_LINES_MODE_RASTER_KEY, + TRAILING_LINES_MODE_WHITE_KEY, + TRAILING_LINES_MODE_BLACK_KEY, + TRAILING_LINES_MODE_COLOR_KEY, + NULL +}; -#define MAX_SCAN_SOURCE_VALUE_LEN 24 -#define MAX_SCAN_MODE_VALUE_LEN 24 +#define MAX_SCAN_SOURCE_VALUE_LEN 24 +#define MAX_SCAN_MODE_VALUE_LEN 24 static SANE_Range range_x, range_y, range_qual; @@ -126,29 +242,51 @@ enum hp5590_opt_idx { HP5590_OPT_RESOLUTION, HP5590_OPT_LAMP_TIMEOUT, HP5590_OPT_WAIT_FOR_BUTTON, + HP5590_OPT_BUTTON_PRESSED, + HP5590_OPT_COLOR_LED, + HP5590_OPT_LCD_COUNTER, + HP5590_OPT_DOC_IN_ADF, HP5590_OPT_PREVIEW, + HP5590_OPT_OVERWRITE_EOP_PIXEL, + HP5590_OPT_TRAILING_LINES_MODE, + HP5590_OPT_TRAILING_LINES_COLOR, HP5590_OPT_LAST }; struct hp5590_scanner { - struct scanner_info *info; - enum proto_flags proto_flags; - SANE_Device sane; - SANE_Int dn; - float br_x, br_y, tl_x, tl_y; - unsigned int dpi; - enum color_depths depth; - enum scan_sources source; - SANE_Bool extend_lamp_timeout; - SANE_Bool wait_for_button; - SANE_Bool preview; - unsigned int quality; - SANE_Option_Descriptor *opts; - struct hp5590_scanner *next; - unsigned int image_size; - SANE_Int transferred_image_size; - void *bulk_read_state; - SANE_Bool scanning; + struct scanner_info *info; + enum proto_flags proto_flags; + SANE_Device sane; + SANE_Int dn; + float br_x, br_y, tl_x, tl_y; + unsigned int dpi; + enum color_depths depth; + enum scan_sources source; + SANE_Bool extend_lamp_timeout; + SANE_Bool wait_for_button; + SANE_Bool preview; + unsigned int quality; + SANE_Option_Descriptor *opts; + struct hp5590_scanner *next; + unsigned long long image_size; + unsigned long long transferred_image_size; + void *bulk_read_state; + SANE_Bool scanning; + SANE_Bool overwrite_eop_pixel; + SANE_Byte *eop_last_line_data; + unsigned int eop_last_line_data_rpos; + SANE_Int eop_trailing_lines_mode; + SANE_Int eop_trailing_lines_color; + SANE_Byte *adf_next_page_lines_data; + unsigned int adf_next_page_lines_data_size; + unsigned int adf_next_page_lines_data_rpos; + unsigned int adf_next_page_lines_data_wpos; + SANE_Byte *one_line_read_buffer; + unsigned int one_line_read_buffer_rpos; + SANE_Byte *color_shift_line_buffer1; + unsigned int color_shift_buffered_lines1; + SANE_Byte *color_shift_line_buffer2; + unsigned int color_shift_buffered_lines2; }; static @@ -157,19 +295,19 @@ struct hp5590_scanner *scanners_list; /******************************************************************************/ static SANE_Status calc_image_params (struct hp5590_scanner *scanner, - unsigned int *pixel_bits, - unsigned int *pixels_per_line, - unsigned int *bytes_per_line, - unsigned int *lines, - unsigned int *image_size) + unsigned int *pixel_bits, + unsigned int *pixels_per_line, + unsigned int *bytes_per_line, + unsigned int *lines, + unsigned long long *image_size) { - unsigned int _pixel_bits; - SANE_Status ret; - unsigned int _pixels_per_line; - unsigned int _bytes_per_line; - unsigned int _lines; - unsigned int _image_size; - float var; + unsigned int _pixel_bits; + SANE_Status ret; + unsigned int _pixels_per_line; + unsigned int _bytes_per_line; + unsigned int _lines; + unsigned int _image_size; + float var; DBG (DBG_proc, "%s\n", __func__); @@ -195,7 +333,7 @@ calc_image_params (struct hp5590_scanner *scanner, if (var > _bytes_per_line) _bytes_per_line++; - _image_size = _lines * _bytes_per_line; + _image_size = (unsigned long long) _lines * _bytes_per_line; DBG (DBG_verbose, "%s: pixel_bits: %u, pixels_per_line: %u, " "bytes_per_line: %u, lines: %u, image_size: %u\n", @@ -219,18 +357,18 @@ calc_image_params (struct hp5590_scanner *scanner, return SANE_STATUS_GOOD; } - + /******************************************************************************/ static SANE_Status attach_usb_device (SANE_String_Const devname, - enum hp_scanner_types hp_scanner_type) + enum hp_scanner_types hp_scanner_type) { - struct scanner_info *info; - struct hp5590_scanner *scanner, *ptr; - unsigned int max_count, count; - SANE_Int dn; - SANE_Status ret; - const struct hp5590_model *hp5590_model; + struct scanner_info *info; + struct hp5590_scanner *scanner, *ptr; + unsigned int max_count, count; + SANE_Int dn; + SANE_Status ret; + const struct hp5590_model *hp5590_model; DBG (DBG_proc, "%s: Opening USB device\n", __func__); if (sanei_usb_open (devname, &dn) != SANE_STATUS_GOOD) @@ -242,7 +380,7 @@ attach_usb_device (SANE_String_Const devname, return ret; if (hp5590_init_scanner (dn, hp5590_model->proto_flags, - &info, hp_scanner_type) != 0) + &info, hp_scanner_type) != 0) return SANE_STATUS_IO_ERROR; DBG (1, "%s: found HP%s scanner at '%s'\n", @@ -250,13 +388,13 @@ attach_usb_device (SANE_String_Const devname, DBG (DBG_verbose, "%s: Reading max scan count\n", __func__); if (hp5590_read_max_scan_count (dn, hp5590_model->proto_flags, - &max_count) != 0) + &max_count) != 0) return SANE_STATUS_IO_ERROR; DBG (DBG_verbose, "%s: Max Scanning count %u\n", __func__, max_count); DBG (DBG_verbose, "%s: Reading scan count\n", __func__); if (hp5590_read_scan_count (dn, hp5590_model->proto_flags, - &count) != 0) + &count) != 0) return SANE_STATUS_IO_ERROR; DBG (DBG_verbose, "%s: Scanning count %u\n", __func__, count); @@ -282,6 +420,18 @@ attach_usb_device (SANE_String_Const devname, scanner->info = info; scanner->bulk_read_state = NULL; scanner->opts = NULL; + scanner->eop_last_line_data = NULL; + scanner->eop_last_line_data_rpos = 0; + scanner->adf_next_page_lines_data = NULL; + scanner->adf_next_page_lines_data_size = 0; + scanner->adf_next_page_lines_data_rpos = 0; + scanner->adf_next_page_lines_data_wpos = 0; + scanner->one_line_read_buffer = NULL; + scanner->one_line_read_buffer_rpos = 0; + scanner->color_shift_line_buffer1 = NULL; + scanner->color_shift_buffered_lines1 = 0; + scanner->color_shift_line_buffer2 = NULL; + scanner->color_shift_buffered_lines2 = 0; if (!scanners_list) scanners_list = scanner; @@ -326,11 +476,11 @@ attach_hp7650 (SANE_String_Const devname) SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize) { - SANE_Status ret; - SANE_Word vendor_id, product_id; - + SANE_Status ret; + SANE_Word vendor_id, product_id; + DBG_INIT(); - + DBG (1, "SANE backed for HP ScanJet 4500C/4570C/5500C/5550C/5590/7650 %u.%u.%u\n", SANE_CURRENT_MAJOR, V_MINOR, BUILD); DBG (1, "(c) Ilia Sotnikov \n"); @@ -389,7 +539,34 @@ void sane_exit (void) for (ptr = scanners_list; ptr; ptr = pnext) { if (ptr->opts != NULL) - free (ptr->opts); + free (ptr->opts); + if (ptr->eop_last_line_data != NULL) { + free (ptr->eop_last_line_data); + ptr->eop_last_line_data = NULL; + ptr->eop_last_line_data_rpos = 0; + } + if (ptr->adf_next_page_lines_data != NULL) { + free (ptr->adf_next_page_lines_data); + ptr->adf_next_page_lines_data = NULL; + ptr->adf_next_page_lines_data_size = 0; + ptr->adf_next_page_lines_data_wpos = 0; + ptr->adf_next_page_lines_data_rpos = 0; + } + if (ptr->one_line_read_buffer != NULL) { + free (ptr->one_line_read_buffer); + ptr->one_line_read_buffer = NULL; + ptr->one_line_read_buffer_rpos = 0; + } + if (ptr->color_shift_line_buffer1 != NULL) { + free (ptr->color_shift_line_buffer1); + ptr->color_shift_line_buffer1 = NULL; + ptr->color_shift_buffered_lines1 = 0; + } + if (ptr->color_shift_line_buffer2 != NULL) { + free (ptr->color_shift_line_buffer2); + ptr->color_shift_line_buffer2 = NULL; + ptr->color_shift_buffered_lines2 = 0; + } pnext = ptr->next; free (ptr); } @@ -428,11 +605,8 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) SANE_Status sane_open (SANE_String_Const devicename, SANE_Handle * handle) { - struct hp5590_scanner *ptr; - SANE_Option_Descriptor *opts; - unsigned int available_sources; - SANE_String_Const *sources_list; - unsigned int source_idx; + struct hp5590_scanner *ptr; + SANE_Option_Descriptor *opts; DBG (DBG_proc, "%s: device name: %s\n", __func__, devicename); @@ -444,19 +618,31 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) ptr = scanners_list; } else { for (ptr = scanners_list; - ptr && strcmp (ptr->sane.name, devicename) != 0; - ptr = ptr->next); + ptr && strcmp (ptr->sane.name, devicename) != 0; + ptr = ptr->next); } if (!ptr) return SANE_STATUS_INVAL; + /* DS: Without this after the first scan (and sane_close) + * it was impossible to use again the read_buttons usb routine. + * Function sane_close puts dn = -1. Now sane_open needs to open + * the usb communication again. + */ + if (ptr->dn < 0) { + DBG (DBG_proc, "%s: Reopening USB device\n", __func__); + if (sanei_usb_open (ptr->sane.name, &ptr->dn) != SANE_STATUS_GOOD) + return SANE_STATUS_IO_ERROR; + DBG (DBG_proc, "%s: USB device reopened\n", __func__); + } + ptr->tl_x = 0; ptr->tl_y = 0; ptr->br_x = ptr->info->max_size_x; ptr->br_y = ptr->info->max_size_y; ptr->dpi = res_list[1]; - ptr->depth = DEPTH_BW; + ptr->depth = DEPTH_BW; ptr->source = SOURCE_FLATBED; ptr->extend_lamp_timeout = SANE_FALSE; ptr->wait_for_button = SANE_FALSE; @@ -464,6 +650,9 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) ptr->quality = 4; ptr->image_size = 0; ptr->scanning = SANE_FALSE; + ptr->overwrite_eop_pixel = SANE_TRUE; + ptr->eop_trailing_lines_mode = TRAILING_LINES_MODE_LAST; + ptr->eop_trailing_lines_color = 0x7f007f; *handle = ptr; @@ -542,29 +731,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) opts[HP5590_OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; opts[HP5590_OPT_MODE].constraint.string_list = mode_list; - available_sources = 1; /* Flatbed is always available */ - if (ptr->info->features & FEATURE_ADF) - available_sources += 2; - if (ptr->info->features & FEATURE_TMA) - available_sources += 2; - available_sources++; /* Count terminating NULL */ - sources_list = malloc (available_sources * sizeof (SANE_String_Const)); - if (!sources_list) - return SANE_STATUS_NO_MEM; - source_idx = 0; - sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_FLATBED; - if (ptr->info->features & FEATURE_ADF) - { - sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_ADF; - sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX; - } - if (ptr->info->features & FEATURE_TMA) - { - sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_TMA_SLIDES; - sources_list[source_idx++] = SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES; - } - sources_list[source_idx] = NULL; - + /* Show all features, check on feature in command line evaluation. */ opts[HP5590_OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; opts[HP5590_OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; opts[HP5590_OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; @@ -605,6 +772,46 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) opts[HP5590_OPT_WAIT_FOR_BUTTON].constraint_type = SANE_CONSTRAINT_NONE; opts[HP5590_OPT_WAIT_FOR_BUTTON].constraint.string_list = NULL; + opts[HP5590_OPT_BUTTON_PRESSED].name = SANE_NAME_BUTTON_PRESSED; + opts[HP5590_OPT_BUTTON_PRESSED].title = SANE_TITLE_BUTTON_PRESSED; + opts[HP5590_OPT_BUTTON_PRESSED].desc = SANE_DESC_BUTTON_PRESSED; + opts[HP5590_OPT_BUTTON_PRESSED].type = SANE_TYPE_STRING; + opts[HP5590_OPT_BUTTON_PRESSED].unit = SANE_UNIT_NONE; + opts[HP5590_OPT_BUTTON_PRESSED].size = BUTTON_PRESSED_VALUE_MAX_KEY_LEN; + opts[HP5590_OPT_BUTTON_PRESSED].cap = SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT; + opts[HP5590_OPT_BUTTON_PRESSED].constraint_type = SANE_CONSTRAINT_STRING_LIST; + opts[HP5590_OPT_BUTTON_PRESSED].constraint.string_list = buttonstate_list; + + opts[HP5590_OPT_COLOR_LED].name = SANE_NAME_COLOR_LED; + opts[HP5590_OPT_COLOR_LED].title = SANE_TITLE_COLOR_LED; + opts[HP5590_OPT_COLOR_LED].desc = SANE_DESC_COLOR_LED; + opts[HP5590_OPT_COLOR_LED].type = SANE_TYPE_STRING; + opts[HP5590_OPT_COLOR_LED].unit = SANE_UNIT_NONE; + opts[HP5590_OPT_COLOR_LED].size = COLOR_LED_VALUE_MAX_KEY_LEN; + opts[HP5590_OPT_COLOR_LED].cap = SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT; + opts[HP5590_OPT_COLOR_LED].constraint_type = SANE_CONSTRAINT_STRING_LIST; + opts[HP5590_OPT_COLOR_LED].constraint.string_list = colorledstate_list; + + opts[HP5590_OPT_LCD_COUNTER].name = SANE_NAME_LCD_COUNTER; + opts[HP5590_OPT_LCD_COUNTER].title = SANE_TITLE_LCD_COUNTER; + opts[HP5590_OPT_LCD_COUNTER].desc = SANE_DESC_LCD_COUNTER; + opts[HP5590_OPT_LCD_COUNTER].type = SANE_TYPE_INT; + opts[HP5590_OPT_LCD_COUNTER].unit = SANE_UNIT_NONE; + opts[HP5590_OPT_LCD_COUNTER].size = sizeof(SANE_Int); + opts[HP5590_OPT_LCD_COUNTER].cap = SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT; + opts[HP5590_OPT_LCD_COUNTER].constraint_type = SANE_CONSTRAINT_RANGE; + opts[HP5590_OPT_LCD_COUNTER].constraint.range = &lcd_counter_range; + + opts[HP5590_OPT_DOC_IN_ADF].name = SANE_NAME_DOC_IN_ADF; + opts[HP5590_OPT_DOC_IN_ADF].title = SANE_TITLE_DOC_IN_ADF; + opts[HP5590_OPT_DOC_IN_ADF].desc = SANE_DESC_DOC_IN_ADF; + opts[HP5590_OPT_DOC_IN_ADF].type = SANE_TYPE_BOOL; + opts[HP5590_OPT_DOC_IN_ADF].unit = SANE_UNIT_NONE; + opts[HP5590_OPT_DOC_IN_ADF].size = sizeof(SANE_Bool); + opts[HP5590_OPT_DOC_IN_ADF].cap = SANE_CAP_HARD_SELECT | SANE_CAP_SOFT_DETECT; + opts[HP5590_OPT_DOC_IN_ADF].constraint_type = SANE_CONSTRAINT_NONE; + opts[HP5590_OPT_DOC_IN_ADF].constraint.range = NULL; + opts[HP5590_OPT_PREVIEW].name = SANE_NAME_PREVIEW; opts[HP5590_OPT_PREVIEW].title = SANE_TITLE_PREVIEW; opts[HP5590_OPT_PREVIEW].desc = SANE_DESC_PREVIEW; @@ -615,6 +822,36 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) opts[HP5590_OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE; opts[HP5590_OPT_PREVIEW].constraint.string_list = NULL; + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].name = SANE_NAME_OVERWRITE_EOP_PIXEL; + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].title = SANE_TITLE_OVERWRITE_EOP_PIXEL; + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].desc = SANE_DESC_OVERWRITE_EOP_PIXEL; + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].type = SANE_TYPE_BOOL; + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].unit = SANE_UNIT_NONE; + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].size = sizeof(SANE_Bool); + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].constraint_type = SANE_CONSTRAINT_NONE; + opts[HP5590_OPT_OVERWRITE_EOP_PIXEL].constraint.string_list = NULL; + + opts[HP5590_OPT_TRAILING_LINES_MODE].name = SANE_NAME_TRAILING_LINES_MODE; + opts[HP5590_OPT_TRAILING_LINES_MODE].title = SANE_TITLE_TRAILING_LINES_MODE; + opts[HP5590_OPT_TRAILING_LINES_MODE].desc = SANE_DESC_TRAILING_LINES_MODE; + opts[HP5590_OPT_TRAILING_LINES_MODE].type = SANE_TYPE_STRING; + opts[HP5590_OPT_TRAILING_LINES_MODE].unit = SANE_UNIT_NONE; + opts[HP5590_OPT_TRAILING_LINES_MODE].size = TRAILING_LINES_MODE_MAX_KEY_LEN; + opts[HP5590_OPT_TRAILING_LINES_MODE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + opts[HP5590_OPT_TRAILING_LINES_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + opts[HP5590_OPT_TRAILING_LINES_MODE].constraint.string_list = trailingmode_list; + + opts[HP5590_OPT_TRAILING_LINES_COLOR].name = SANE_NAME_TRAILING_LINES_COLOR; + opts[HP5590_OPT_TRAILING_LINES_COLOR].title = SANE_TITLE_TRAILING_LINES_COLOR; + opts[HP5590_OPT_TRAILING_LINES_COLOR].desc = SANE_DESC_TRAILING_LINES_COLOR; + opts[HP5590_OPT_TRAILING_LINES_COLOR].type = SANE_TYPE_INT; + opts[HP5590_OPT_TRAILING_LINES_COLOR].unit = SANE_UNIT_NONE; + opts[HP5590_OPT_TRAILING_LINES_COLOR].size = sizeof(SANE_Int); + opts[HP5590_OPT_TRAILING_LINES_COLOR].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + opts[HP5590_OPT_TRAILING_LINES_COLOR].constraint_type = SANE_CONSTRAINT_NONE; + opts[HP5590_OPT_TRAILING_LINES_COLOR].constraint.string_list = NULL; + ptr->opts = opts; return SANE_STATUS_GOOD; @@ -646,285 +883,541 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) return &scanner->opts[option]; } +/*************************************DS:Support function read buttons status */ +SANE_Status +read_button_pressed(SANE_Handle handle, enum button_status * button_pressed) +{ + struct hp5590_scanner * scanner = handle; + *button_pressed = BUTTON_NONE; + enum button_status status = BUTTON_NONE; + DBG (DBG_verbose, "%s: Checking button status (device_number = %u) (device_name = %s)\n", __func__, scanner->dn, scanner->sane.name); + SANE_Status ret = hp5590_read_buttons (scanner->dn, scanner->proto_flags, &status); + if (ret != SANE_STATUS_GOOD) + { + DBG (DBG_proc, "%s: Error reading button status (%u)\n", __func__, ret); + return ret; + } + DBG (DBG_verbose, "%s: Button pressed = %d\n", __func__, status); + *button_pressed = status; + return SANE_STATUS_GOOD; +} + +/******************************************************************************/ +SANE_Status +read_lcd_and_led_values(SANE_Handle handle, + SANE_Int * lcd_counter, + enum color_led_status * color_led) +{ + struct hp5590_scanner * scanner = handle; + *lcd_counter = 1; + *color_led = LED_COLOR; + DBG (DBG_verbose, "%s: Reading LCD and LED values (device_number = %u) (device_name = %s)\n", + __func__, scanner->dn, scanner->sane.name); + SANE_Status ret = hp5590_read_lcd_and_led (scanner->dn, scanner->proto_flags, lcd_counter, color_led); + if (ret != SANE_STATUS_GOOD) + { + DBG (DBG_proc, "%s: Error reading LCD and LED values (%u)\n", __func__, ret); + return ret; + } + DBG (DBG_verbose, "%s: LCD = %d, LED = %s\n", __func__, *lcd_counter, + *color_led == LED_BLACKWHITE ? COLOR_LED_VALUE_BLACKWHITE_KEY : COLOR_LED_VALUE_COLOR_KEY); + return SANE_STATUS_GOOD; +} + +/******************************************************************************/ +SANE_Status +read_doc_in_adf_value(SANE_Handle handle, + SANE_Bool * doc_in_adf) +{ + struct hp5590_scanner * scanner = handle; + DBG (DBG_verbose, "%s: Reading state of document-available in ADF (device_number = %u) (device_name = %s)\n", + __func__, scanner->dn, scanner->sane.name); + SANE_Status ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags); + if (ret == SANE_STATUS_GOOD) + *doc_in_adf = SANE_TRUE; + else if (ret == SANE_STATUS_NO_DOCS) + *doc_in_adf = SANE_FALSE; + else + { + DBG (DBG_proc, "%s: Error reading state of document-available in ADF (%u)\n", __func__, ret); + return ret; + } + DBG (DBG_verbose, "%s: doc_in_adf = %s\n", __func__, *doc_in_adf == SANE_FALSE ? "false" : "true"); + return SANE_STATUS_GOOD; +} + /******************************************************************************/ SANE_Status sane_control_option (SANE_Handle handle, SANE_Int option, - SANE_Action action, void *value, + SANE_Action action, void *value, SANE_Int * info) { - struct hp5590_scanner *scanner = handle; - + struct hp5590_scanner *scanner = handle; + if (!value) return SANE_STATUS_INVAL; if (!handle) return SANE_STATUS_INVAL; - + if (option >= HP5590_OPT_LAST) return SANE_STATUS_INVAL; if (action == SANE_ACTION_GET_VALUE) { if (option == HP5590_OPT_NUM) - { - DBG(3, "%s: get total number of options - %u\n", __func__, HP5590_OPT_LAST); - *((SANE_Int *) value) = HP5590_OPT_LAST; - return SANE_STATUS_GOOD; - } - + { + DBG(3, "%s: get total number of options - %u\n", __func__, HP5590_OPT_LAST); + *((SANE_Int *) value) = HP5590_OPT_LAST; + return SANE_STATUS_GOOD; + } + if (!scanner->opts) - return SANE_STATUS_INVAL; - + return SANE_STATUS_INVAL; + DBG (DBG_proc, "%s: get option '%s' value\n", __func__, scanner->opts[option].name); if (option == HP5590_OPT_BR_X) - { - *(SANE_Fixed *) value = SANE_FIX (scanner->br_x * 25.4); - } + { + *(SANE_Fixed *) value = SANE_FIX (scanner->br_x * 25.4); + } if (option == HP5590_OPT_BR_Y) - { - *(SANE_Fixed *) value = SANE_FIX (scanner->br_y * 25.4); - } + { + *(SANE_Fixed *) value = SANE_FIX (scanner->br_y * 25.4); + } if (option == HP5590_OPT_TL_X) - { - *(SANE_Fixed *) value = SANE_FIX ((scanner->tl_x) * 25.4); - } + { + *(SANE_Fixed *) value = SANE_FIX ((scanner->tl_x) * 25.4); + } if (option == HP5590_OPT_TL_Y) - { - *(SANE_Fixed *) value = SANE_FIX (scanner->tl_y * 25.4); - } + { + *(SANE_Fixed *) value = SANE_FIX (scanner->tl_y * 25.4); + } if (option == HP5590_OPT_MODE) - { - switch (scanner->depth) { - case DEPTH_BW: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_MODE_LINEART, strlen (SANE_VALUE_SCAN_MODE_LINEART)); - break; - case DEPTH_GRAY: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_MODE_GRAY, strlen (SANE_VALUE_SCAN_MODE_GRAY)); - break; - case DEPTH_COLOR_24: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_24, strlen (SANE_VALUE_SCAN_MODE_COLOR_24)); - break; - case DEPTH_COLOR_48: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_48, strlen (SANE_VALUE_SCAN_MODE_COLOR_48)); - break; - default: - return SANE_STATUS_INVAL; - } - } + { + switch (scanner->depth) { + case DEPTH_BW: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_MODE_LINEART, strlen (SANE_VALUE_SCAN_MODE_LINEART)); + break; + case DEPTH_GRAY: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_MODE_GRAY, strlen (SANE_VALUE_SCAN_MODE_GRAY)); + break; + case DEPTH_COLOR_24: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_24, strlen (SANE_VALUE_SCAN_MODE_COLOR_24)); + break; + case DEPTH_COLOR_48: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_MODE_COLOR_48, strlen (SANE_VALUE_SCAN_MODE_COLOR_48)); + break; + default: + return SANE_STATUS_INVAL; + } + } if (option == HP5590_OPT_SOURCE) - { - switch (scanner->source) { - case SOURCE_FLATBED: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_SOURCE_FLATBED, strlen (SANE_VALUE_SCAN_SOURCE_FLATBED)); - break; - case SOURCE_ADF: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF, strlen (SANE_VALUE_SCAN_SOURCE_ADF)); - break; - case SOURCE_ADF_DUPLEX: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, strlen (SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX)); - break; - case SOURCE_TMA_SLIDES: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_SLIDES)); - break; - case SOURCE_TMA_NEGATIVES: - memset (value , 0, scanner->opts[option].size); - memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES)); - break; - case SOURCE_NONE: - default: - return SANE_STATUS_INVAL; - } - } + { + switch (scanner->source) { + case SOURCE_FLATBED: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_SOURCE_FLATBED, strlen (SANE_VALUE_SCAN_SOURCE_FLATBED)); + break; + case SOURCE_ADF: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF, strlen (SANE_VALUE_SCAN_SOURCE_ADF)); + break; + case SOURCE_ADF_DUPLEX: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX, strlen (SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX)); + break; + case SOURCE_TMA_SLIDES: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_SLIDES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_SLIDES)); + break; + case SOURCE_TMA_NEGATIVES: + memset (value , 0, scanner->opts[option].size); + memcpy (value, SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES, strlen (SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES)); + break; + case SOURCE_NONE: + default: + return SANE_STATUS_INVAL; + } + } if (option == HP5590_OPT_RESOLUTION) - { - *(SANE_Int *) value = scanner->dpi; - } + { + *(SANE_Int *) value = scanner->dpi; + } if (option == HP5590_OPT_LAMP_TIMEOUT) - { - *(SANE_Bool *) value = scanner->extend_lamp_timeout; - } + { + *(SANE_Bool *) value = scanner->extend_lamp_timeout; + } if (option == HP5590_OPT_WAIT_FOR_BUTTON) - { - *(SANE_Bool *) value = scanner->wait_for_button; - } + { + *(SANE_Bool *) value = scanner->wait_for_button; + } + + if (option == HP5590_OPT_BUTTON_PRESSED) + { + enum button_status button_pressed = BUTTON_NONE; + SANE_Status ret = read_button_pressed(scanner, &button_pressed); + if (ret != SANE_STATUS_GOOD) + return ret; + switch (button_pressed) { + case BUTTON_POWER: + strncpy (value, BUTTON_PRESSED_VALUE_POWER_KEY, scanner->opts[option].size); + break; + case BUTTON_SCAN: + strncpy (value, BUTTON_PRESSED_VALUE_SCAN_KEY, scanner->opts[option].size); + break; + case BUTTON_COLLECT: + strncpy (value, BUTTON_PRESSED_VALUE_COLLECT_KEY, scanner->opts[option].size); + break; + case BUTTON_FILE: + strncpy (value, BUTTON_PRESSED_VALUE_FILE_KEY, scanner->opts[option].size); + break; + case BUTTON_EMAIL: + strncpy (value, BUTTON_PRESSED_VALUE_EMAIL_KEY, scanner->opts[option].size); + break; + case BUTTON_COPY: + strncpy (value, BUTTON_PRESSED_VALUE_COPY_KEY, scanner->opts[option].size); + break; + case BUTTON_UP: + strncpy (value, BUTTON_PRESSED_VALUE_UP_KEY, scanner->opts[option].size); + break; + case BUTTON_DOWN: + strncpy (value, BUTTON_PRESSED_VALUE_DOWN_KEY, scanner->opts[option].size); + break; + case BUTTON_MODE: + strncpy (value, BUTTON_PRESSED_VALUE_MODE_KEY, scanner->opts[option].size); + break; + case BUTTON_CANCEL: + strncpy (value, BUTTON_PRESSED_VALUE_CANCEL_KEY, scanner->opts[option].size); + break; + case BUTTON_NONE: + default: + strncpy (value, BUTTON_PRESSED_VALUE_NONE_KEY, scanner->opts[option].size); + } + } + + if (option == HP5590_OPT_COLOR_LED) + { + SANE_Int lcd_counter = 0; + enum color_led_status color_led = LED_COLOR; + SANE_Status ret = read_lcd_and_led_values(scanner, &lcd_counter, &color_led); + if (ret != SANE_STATUS_GOOD) + return ret; + switch (color_led) { + case LED_BLACKWHITE: + strncpy (value, COLOR_LED_VALUE_BLACKWHITE_KEY, scanner->opts[option].size); + break; + case LED_COLOR: + default: + strncpy (value, COLOR_LED_VALUE_COLOR_KEY, scanner->opts[option].size); + } + } + + if (option == HP5590_OPT_LCD_COUNTER) + { + SANE_Int lcd_counter = 0; + enum color_led_status color_led = LED_COLOR; + SANE_Status ret = read_lcd_and_led_values(scanner, &lcd_counter, &color_led); + if (ret != SANE_STATUS_GOOD) + return ret; + *(SANE_Int *) value = lcd_counter; + } + + if (option == HP5590_OPT_DOC_IN_ADF) + { + SANE_Bool doc_in_adf = SANE_FALSE; + SANE_Status ret = read_doc_in_adf_value(scanner, &doc_in_adf); + if (ret != SANE_STATUS_GOOD) + return ret; + *(SANE_Bool *) value = doc_in_adf; + } if (option == HP5590_OPT_PREVIEW) - { - *(SANE_Bool *) value = scanner->preview; - } + { + *(SANE_Bool *) value = scanner->preview; + } + + if (option == HP5590_OPT_OVERWRITE_EOP_PIXEL) + { + *(SANE_Bool *) value = scanner->overwrite_eop_pixel; + } + + if (option == HP5590_OPT_TRAILING_LINES_MODE) + { + switch (scanner->eop_trailing_lines_mode) { + case TRAILING_LINES_MODE_RAW: + memset (value , 0, scanner->opts[option].size); + memcpy (value, TRAILING_LINES_MODE_RAW_KEY, strlen (TRAILING_LINES_MODE_RAW_KEY)); + break; + case TRAILING_LINES_MODE_LAST: + memset (value , 0, scanner->opts[option].size); + memcpy (value, TRAILING_LINES_MODE_LAST_KEY, strlen (TRAILING_LINES_MODE_LAST_KEY)); + break; + case TRAILING_LINES_MODE_RASTER: + memset (value , 0, scanner->opts[option].size); + memcpy (value, TRAILING_LINES_MODE_RASTER_KEY, strlen (TRAILING_LINES_MODE_RASTER_KEY)); + break; + case TRAILING_LINES_MODE_BLACK: + memset (value , 0, scanner->opts[option].size); + memcpy (value, TRAILING_LINES_MODE_BLACK_KEY, strlen (TRAILING_LINES_MODE_BLACK_KEY)); + break; + case TRAILING_LINES_MODE_WHITE: + memset (value , 0, scanner->opts[option].size); + memcpy (value, TRAILING_LINES_MODE_WHITE_KEY, strlen (TRAILING_LINES_MODE_WHITE_KEY)); + break; + case TRAILING_LINES_MODE_COLOR: + memset (value , 0, scanner->opts[option].size); + memcpy (value, TRAILING_LINES_MODE_COLOR_KEY, strlen (TRAILING_LINES_MODE_COLOR_KEY)); + break; + default: + return SANE_STATUS_INVAL; + } + } + + if (option == HP5590_OPT_TRAILING_LINES_COLOR) + { + *(SANE_Int *) value = scanner->eop_trailing_lines_color; + } } - + if (action == SANE_ACTION_SET_VALUE) { if (option == HP5590_OPT_NUM) - return SANE_STATUS_INVAL; + return SANE_STATUS_INVAL; if (option == HP5590_OPT_BR_X) - { - float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; - if (val <= scanner->tl_x) - return SANE_STATUS_GOOD; - scanner->br_x = val; - if (info) - *info = SANE_INFO_RELOAD_PARAMS; - } + { + float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; + if (val <= scanner->tl_x) + return SANE_STATUS_GOOD; + scanner->br_x = val; + if (info) + *info = SANE_INFO_RELOAD_PARAMS; + } if (option == HP5590_OPT_BR_Y) - { - float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; - if (val <= scanner->tl_y) - return SANE_STATUS_GOOD; - scanner->br_y = val; - if (info) - *info = SANE_INFO_RELOAD_PARAMS; - } + { + float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; + if (val <= scanner->tl_y) + return SANE_STATUS_GOOD; + scanner->br_y = val; + if (info) + *info = SANE_INFO_RELOAD_PARAMS; + } if (option == HP5590_OPT_TL_X) - { - float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; - if (val >= scanner->br_x) - return SANE_STATUS_GOOD; - scanner->tl_x = val; - if (info) - *info = SANE_INFO_RELOAD_PARAMS; - } + { + float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; + if (val >= scanner->br_x) + return SANE_STATUS_GOOD; + scanner->tl_x = val; + if (info) + *info = SANE_INFO_RELOAD_PARAMS; + } if (option == HP5590_OPT_TL_Y) - { - float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; - if (val >= scanner->br_y) - return SANE_STATUS_GOOD; - scanner->tl_y = val; - if (info) - *info = SANE_INFO_RELOAD_PARAMS; - } + { + float val = SANE_UNFIX(*(SANE_Fixed *) value) / 25.4; + if (val >= scanner->br_y) + return SANE_STATUS_GOOD; + scanner->tl_y = val; + if (info) + *info = SANE_INFO_RELOAD_PARAMS; + } if (option == HP5590_OPT_MODE) - { - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_LINEART) == 0) - { - scanner->depth = DEPTH_BW; - } - - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_GRAY) == 0) - { - scanner->depth = DEPTH_GRAY; - } - - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_24) == 0) - { - scanner->depth = DEPTH_COLOR_24; - } - - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_48) == 0) - { - scanner->depth = DEPTH_COLOR_48; - } - if (info) - *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - } + { + if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_LINEART) == 0) + { + scanner->depth = DEPTH_BW; + } + else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_GRAY) == 0) + { + scanner->depth = DEPTH_GRAY; + } + else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_24) == 0) + { + scanner->depth = DEPTH_COLOR_24; + } + else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_MODE_COLOR_48) == 0) + { + scanner->depth = DEPTH_COLOR_48; + } + else + { + return SANE_STATUS_INVAL; + } + + if (info) + *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + } if (option == HP5590_OPT_SOURCE) - { + { range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4); - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_FLATBED) == 0) - { - scanner->source = SOURCE_FLATBED; - range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); - range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4); - scanner->br_x = scanner->info->max_size_x; - scanner->br_y = scanner->info->max_size_y; - } - /* In ADF modes the device can scan up to ADF_MAX_Y_INCHES, which is usually - * bigger than what scanner reports back during initialization - */ - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF) == 0) - { - scanner->source = SOURCE_ADF; - range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); - range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4); - scanner->br_x = scanner->info->max_size_x; - scanner->br_y = ADF_MAX_Y_INCHES * 25.4; - } - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX) == 0) - { - scanner->source = SOURCE_ADF_DUPLEX; - range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); - range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4 * 2); - scanner->br_y = ADF_MAX_Y_INCHES * 25.4 * 2; - scanner->br_x = scanner->info->max_size_x; - } - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_SLIDES) == 0) - { - scanner->source = SOURCE_TMA_SLIDES; - range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4); - range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4); - scanner->br_x = TMA_MAX_X_INCHES * 25.4; - scanner->br_y = TMA_MAX_Y_INCHES * 25.4; - } - if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES) == 0) - { - scanner->source = SOURCE_TMA_NEGATIVES; - range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4); - range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4); - scanner->br_x = TMA_MAX_X_INCHES * 25.4; - scanner->br_y = TMA_MAX_Y_INCHES * 25.4; - } - if (info) - *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - } + if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_FLATBED) == 0) + { + scanner->source = SOURCE_FLATBED; + range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); + range_y.max = SANE_FIX(scanner->info->max_size_y * 25.4); + scanner->br_x = scanner->info->max_size_x; + scanner->br_y = scanner->info->max_size_y; + } + else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF) == 0) + { + /* In ADF modes the device can scan up to ADF_MAX_Y_INCHES, which is usually + * bigger than what scanner reports back during initialization + */ + if (! (scanner->info->features & FEATURE_ADF)) + { + DBG(DBG_err, "ADF feature not available: %s\n", (char *) value); + return SANE_STATUS_UNSUPPORTED; + } + scanner->source = SOURCE_ADF; + range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); + range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4); + scanner->br_x = scanner->info->max_size_x; + scanner->br_y = ADF_MAX_Y_INCHES; + } + else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_ADF_DUPLEX) == 0) + { + if (! (scanner->info->features & FEATURE_ADF)) + { + DBG(DBG_err, "ADF feature not available: %s\n", (char *) value); + return SANE_STATUS_UNSUPPORTED; + } + scanner->source = SOURCE_ADF_DUPLEX; + range_x.max = SANE_FIX(scanner->info->max_size_x * 25.4); + range_y.max = SANE_FIX(ADF_MAX_Y_INCHES * 25.4); + scanner->br_x = scanner->info->max_size_x; + scanner->br_y = ADF_MAX_Y_INCHES; + } + else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_SLIDES) == 0) + { + if (! (scanner->info->features & FEATURE_TMA)) + { + DBG(DBG_err, "TMA feature not available: %s\n", (char *) value); + return SANE_STATUS_UNSUPPORTED; + } + scanner->source = SOURCE_TMA_SLIDES; + range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4); + range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4); + scanner->br_x = TMA_MAX_X_INCHES; + scanner->br_y = TMA_MAX_Y_INCHES; + } + else if (strcmp ((char *) value, (char *) SANE_VALUE_SCAN_SOURCE_TMA_NEGATIVES) == 0) + { + if (! (scanner->info->features & FEATURE_TMA)) + { + DBG(DBG_err, "TMA feature not available: %s\n", (char *) value); + return SANE_STATUS_UNSUPPORTED; + } + scanner->source = SOURCE_TMA_NEGATIVES; + range_x.max = SANE_FIX(TMA_MAX_X_INCHES * 25.4); + range_y.max = SANE_FIX(TMA_MAX_Y_INCHES * 25.4); + scanner->br_x = TMA_MAX_X_INCHES; + scanner->br_y = TMA_MAX_Y_INCHES; + } + else + { + return SANE_STATUS_INVAL; + } + if (info) + *info = SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + } if (option == HP5590_OPT_RESOLUTION) - { - scanner->dpi = *(SANE_Int *) value; - if (info) - *info = SANE_INFO_RELOAD_PARAMS; - } + { + scanner->dpi = *(SANE_Int *) value; + if (info) + *info = SANE_INFO_RELOAD_PARAMS; + } if (option == HP5590_OPT_LAMP_TIMEOUT) - { - scanner->extend_lamp_timeout = *(SANE_Bool *) value; - } + { + scanner->extend_lamp_timeout = *(SANE_Bool *) value; + } if (option == HP5590_OPT_WAIT_FOR_BUTTON) - { - scanner->wait_for_button = *(SANE_Bool *) value; - } + { + scanner->wait_for_button = *(SANE_Bool *) value; + } + + if (option == HP5590_OPT_BUTTON_PRESSED) + { + DBG(DBG_verbose, "State of buttons is read only. Setting of state will be ignored.\n"); + } + + if (option == HP5590_OPT_COLOR_LED) + { + DBG(DBG_verbose, "State of color LED indicator is read only. Setting of state will be ignored.\n"); + } + + if (option == HP5590_OPT_LCD_COUNTER) + { + DBG(DBG_verbose, "Value of LCD counter is read only. Setting of value will be ignored.\n"); + } + + if (option == HP5590_OPT_DOC_IN_ADF) + { + DBG(DBG_verbose, "Value of document-available indicator is read only. Setting of value will be ignored.\n"); + } if (option == HP5590_OPT_PREVIEW) - { - scanner->preview = *(SANE_Bool *) value; - } + { + scanner->preview = *(SANE_Bool *) value; + } + + if (option == HP5590_OPT_OVERWRITE_EOP_PIXEL) + { + scanner->overwrite_eop_pixel = *(SANE_Bool *) value; + } + + if (option == HP5590_OPT_TRAILING_LINES_MODE) + { + if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_RAW_KEY) == 0) + scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_RAW; + if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_LAST_KEY) == 0) + scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_LAST; + if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_RASTER_KEY) == 0) + scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_RASTER; + if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_BLACK_KEY) == 0) + scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_BLACK; + if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_WHITE_KEY) == 0) + scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_WHITE; + if (strcmp ((char *) value, (char *) TRAILING_LINES_MODE_COLOR_KEY) == 0) + scanner->eop_trailing_lines_mode = TRAILING_LINES_MODE_COLOR; + } + + if (option == HP5590_OPT_TRAILING_LINES_COLOR) + { + scanner->eop_trailing_lines_color = *(SANE_Int *) value; + } } - + return SANE_STATUS_GOOD; } /******************************************************************************/ SANE_Status sane_get_parameters (SANE_Handle handle, - SANE_Parameters * params) + SANE_Parameters * params) { - struct hp5590_scanner *scanner = handle; - SANE_Status ret; - unsigned int pixel_bits; + struct hp5590_scanner *scanner = handle; + SANE_Status ret; + unsigned int pixel_bits; DBG (DBG_proc, "%s\n", __func__); @@ -935,10 +1428,10 @@ SANE_Status sane_get_parameters (SANE_Handle handle, return SANE_STATUS_INVAL; ret = calc_image_params (scanner, - (unsigned int *) &pixel_bits, - (unsigned int *) ¶ms->pixels_per_line, - (unsigned int *) ¶ms->bytes_per_line, - (unsigned int *) ¶ms->lines, NULL); + (unsigned int *) &pixel_bits, + (unsigned int *) ¶ms->pixels_per_line, + (unsigned int *) ¶ms->bytes_per_line, + (unsigned int *) ¶ms->lines, NULL); if (ret != SANE_STATUS_GOOD) return ret; @@ -964,11 +1457,11 @@ SANE_Status sane_get_parameters (SANE_Handle handle, params->format = SANE_FRAME_RGB; break; default: - DBG(0, "%s: Unknown depth\n", __func__); + DBG(DBG_err, "%s: Unknown depth\n", __func__); return SANE_STATUS_INVAL; } - + DBG (DBG_proc, "format: %u, last_frame: %u, bytes_per_line: %u, " "pixels_per_line: %u, lines: %u, depth: %u\n", params->format, params->last_frame, @@ -982,31 +1475,61 @@ SANE_Status sane_get_parameters (SANE_Handle handle, SANE_Status sane_start (SANE_Handle handle) { - struct hp5590_scanner *scanner = handle; - SANE_Status ret; - unsigned int bytes_per_line; + struct hp5590_scanner *scanner = handle; + SANE_Status ret; + unsigned int bytes_per_line; DBG (DBG_proc, "%s\n", __func__); if (!scanner) return SANE_STATUS_INVAL; + /* Cleanup for all pages. */ + if (scanner->eop_last_line_data) + { + /* Release last line data */ + free (scanner->eop_last_line_data); + scanner->eop_last_line_data = NULL; + scanner->eop_last_line_data_rpos = 0; + } + if (scanner->one_line_read_buffer) + { + /* Release temporary line buffer. */ + free (scanner->one_line_read_buffer); + scanner->one_line_read_buffer = NULL; + scanner->one_line_read_buffer_rpos = 0; + } + if (scanner->color_shift_line_buffer1) + { + /* Release line buffer1 for shifting colors. */ + free (scanner->color_shift_line_buffer1); + scanner->color_shift_line_buffer1 = NULL; + scanner->color_shift_buffered_lines1 = 0; + } + if (scanner->color_shift_line_buffer2) + { + /* Release line buffer2 for shifting colors. */ + free (scanner->color_shift_line_buffer2); + scanner->color_shift_line_buffer2 = NULL; + scanner->color_shift_buffered_lines2 = 0; + } + if ( scanner->scanning == SANE_TRUE && ( scanner->source == SOURCE_ADF - || scanner->source == SOURCE_ADF_DUPLEX)) + || scanner->source == SOURCE_ADF_DUPLEX)) { DBG (DBG_verbose, "%s: Scanner is scanning, check if more data is available\n", - __func__); + __func__); ret = hp5590_is_data_available (scanner->dn, scanner->proto_flags); if (ret == SANE_STATUS_GOOD) - { - DBG (DBG_verbose, "%s: More data is available\n", __func__); - scanner->transferred_image_size = scanner->image_size; - return SANE_STATUS_GOOD; - } + { + DBG (DBG_verbose, "%s: More data is available\n", __func__); + scanner->transferred_image_size = scanner->image_size; + return SANE_STATUS_GOOD; + } if (ret != SANE_STATUS_NO_DOCS) - return ret; + return ret; } sane_cancel (handle); @@ -1015,25 +1538,25 @@ sane_start (SANE_Handle handle) { enum button_status status; for (;;) - { - ret = hp5590_read_buttons (scanner->dn, - scanner->proto_flags, - &status); - if (ret != SANE_STATUS_GOOD) - return ret; - - if (status == BUTTON_CANCEL) - return SANE_STATUS_CANCELLED; - - if (status != BUTTON_NONE && status != BUTTON_POWER) - break; - sleep (1); - } + { + ret = hp5590_read_buttons (scanner->dn, + scanner->proto_flags, + &status); + if (ret != SANE_STATUS_GOOD) + return ret; + + if (status == BUTTON_CANCEL) + return SANE_STATUS_CANCELLED; + + if (status != BUTTON_NONE && status != BUTTON_POWER) + break; + usleep (100 * 1000); + } } - DBG (DBG_verbose, "Init scanner\n"); + DBG (DBG_verbose, "Init scanner\n"); ret = hp5590_init_scanner (scanner->dn, scanner->proto_flags, - NULL, SCANNER_NONE); + NULL, SCANNER_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -1043,21 +1566,21 @@ sane_start (SANE_Handle handle) DBG (DBG_verbose, "Wakeup\n"); ret = hp5590_select_source_and_wakeup (scanner->dn, scanner->proto_flags, - scanner->source, - scanner->extend_lamp_timeout); + scanner->source, + scanner->extend_lamp_timeout); if (ret != SANE_STATUS_GOOD) return ret; - + ret = hp5590_set_scan_params (scanner->dn, - scanner->proto_flags, - scanner->info, - scanner->tl_x * scanner->dpi, - scanner->tl_y * scanner->dpi, - (scanner->br_x - scanner->tl_x) * scanner->dpi, - (scanner->br_y - scanner->tl_y) * scanner->dpi, - scanner->dpi, - scanner->depth, scanner->preview ? MODE_PREVIEW : MODE_NORMAL, - scanner->source); + scanner->proto_flags, + scanner->info, + scanner->tl_x * scanner->dpi, + scanner->tl_y * scanner->dpi, + (scanner->br_x - scanner->tl_x) * scanner->dpi, + (scanner->br_y - scanner->tl_y) * scanner->dpi, + scanner->dpi, + scanner->depth, scanner->preview ? MODE_PREVIEW : MODE_NORMAL, + scanner->source); if (ret != SANE_STATUS_GOOD) { hp5590_reset_scan_head (scanner->dn, scanner->proto_flags); @@ -1065,8 +1588,8 @@ sane_start (SANE_Handle handle) } ret = calc_image_params (scanner, NULL, NULL, - &bytes_per_line, NULL, - &scanner->image_size); + &bytes_per_line, NULL, + &scanner->image_size); if (ret != SANE_STATUS_GOOD) { hp5590_reset_scan_head (scanner->dn, scanner->proto_flags); @@ -1079,35 +1602,35 @@ sane_start (SANE_Handle handle) || scanner->depth == DEPTH_COLOR_48) { DBG (1, "Color 24/48 bits: checking if image size is correctly " - "aligned on number of colors\n"); + "aligned on number of colors\n"); if (bytes_per_line % 3) - { - DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on number of colors (3) " - "(image size: %u, bytes per line %u)\n", - scanner->image_size, bytes_per_line); + { + DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on number of colors (3) " + "(image size: %llu, bytes per line %u)\n", + scanner->image_size, bytes_per_line); hp5590_reset_scan_head (scanner->dn, scanner->proto_flags); - return SANE_STATUS_INVAL; - } + return SANE_STATUS_INVAL; + } DBG (1, "Color 24/48 bits: image size is correctly aligned on number of colors " - "(image size: %u, bytes per line %u)\n", - scanner->image_size, bytes_per_line); + "(image size: %llu, bytes per line %u)\n", + scanner->image_size, bytes_per_line); DBG (1, "Color 24/48 bits: checking if image size is correctly " - "aligned on bytes per line\n"); + "aligned on bytes per line\n"); if (scanner->image_size % bytes_per_line) - { - DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on bytes per line " - "(image size: %u, bytes per line %u)\n", - scanner->image_size, bytes_per_line); + { + DBG (DBG_err, "Color 24/48 bits: image size doesn't lined up on bytes per line " + "(image size: %llu, bytes per line %u)\n", + scanner->image_size, bytes_per_line); hp5590_reset_scan_head (scanner->dn, scanner->proto_flags); - return SANE_STATUS_INVAL; - } + return SANE_STATUS_INVAL; + } DBG (1, "Color 24/48 bits: image size correctly aligned on bytes per line " - "(images size: %u, bytes per line: %u)\n", - scanner->image_size, bytes_per_line); + "(images size: %llu, bytes per line: %u)\n", + scanner->image_size, bytes_per_line); } - - DBG (DBG_verbose, "Final image size: %u\n", scanner->image_size); + + DBG (DBG_verbose, "Final image size: %llu\n", scanner->image_size); DBG (DBG_verbose, "Reverse calibration maps\n"); ret = hp5590_send_reverse_calibration_map (scanner->dn, scanner->proto_flags); @@ -1125,14 +1648,23 @@ sane_start (SANE_Handle handle) return ret; } + if (scanner->adf_next_page_lines_data) + { + free (scanner->adf_next_page_lines_data); + scanner->adf_next_page_lines_data = NULL; + scanner->adf_next_page_lines_data_size = 0; + scanner->adf_next_page_lines_data_rpos = 0; + scanner->adf_next_page_lines_data_wpos = 0; + } + scanner->scanning = SANE_TRUE; DBG (DBG_verbose, "Starting scan\n"); ret = hp5590_start_scan (scanner->dn, scanner->proto_flags); /* Check for paper jam */ - if ( ret == SANE_STATUS_DEVICE_BUSY + if ( ret == SANE_STATUS_DEVICE_BUSY && ( scanner->source == SOURCE_ADF - || scanner->source == SOURCE_ADF_DUPLEX)) + || scanner->source == SOURCE_ADF_DUPLEX)) return SANE_STATUS_JAMMED; if (ret != SANE_STATUS_GOOD) @@ -1145,44 +1677,218 @@ sane_start (SANE_Handle handle) } /******************************************************************************/ -static SANE_Status -convert_lineart (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size) +static void +invert_negative_colors (unsigned char *buf, unsigned int bytes_per_line, struct hp5590_scanner *scanner) { - SANE_Int i; + /* Invert lineart or negatives. */ + int is_linear = (scanner->depth == DEPTH_BW); + int is_negative = (scanner->source == SOURCE_TMA_NEGATIVES); + if (is_linear ^ is_negative) + { + for (unsigned int k = 0; k < bytes_per_line; k++) + buf[k] ^= 0xff; + } +} - DBG (DBG_proc, "%s\n", __func__); +/******************************************************************************/ +static SANE_Status +convert_gray_and_lineart (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size) +{ + unsigned int pixels_per_line; + unsigned int pixel_bits; + unsigned int bytes_per_line; + unsigned int lines; + unsigned char *buf; + SANE_Status ret; hp5590_assert (scanner != NULL); hp5590_assert (data != NULL); - /* Invert lineart */ - if (scanner->depth == DEPTH_BW) + if ( ! (scanner->depth == DEPTH_BW || scanner->depth == DEPTH_GRAY)) + return SANE_STATUS_GOOD; + + DBG (DBG_proc, "%s\n", __func__); + + ret = calc_image_params (scanner, + &pixel_bits, + &pixels_per_line, &bytes_per_line, + NULL, NULL); + if (ret != SANE_STATUS_GOOD) + return ret; + + lines = size / bytes_per_line; + + buf = data; + for (unsigned int i = 0; i < lines; buf += bytes_per_line, ++i) { - for (i = 0; i < size; i++) - data[i] ^= 0xff; + if (! scanner->eop_last_line_data) + { + if (pixels_per_line > 0) + { + /* Test for last-line indicator pixel. If found, store last line + * and optionally overwrite indicator pixel with neighbor value. + */ + unsigned int j = bytes_per_line - 1; + int eop_found = 0; + if (scanner->depth == DEPTH_GRAY) + { + eop_found = (buf[j] != 0); + if (scanner->overwrite_eop_pixel && (j > 0)) + { + buf[j] = buf[j-1]; + } + } + else if (scanner->depth == DEPTH_BW) + { + eop_found = (buf[j] != 0); + if (scanner->overwrite_eop_pixel && (j > 0)) + { + buf[j] = (buf[j-1] & 0x01) ? 0xff : 0; + } + } + + invert_negative_colors (buf, bytes_per_line, scanner); + + if (eop_found && (! scanner->eop_last_line_data)) + { + DBG (DBG_verbose, "Found end-of-page at line %u in reading block.\n", i); + scanner->eop_last_line_data = malloc(bytes_per_line); + if (! scanner->eop_last_line_data) + return SANE_STATUS_NO_MEM; + + memcpy (scanner->eop_last_line_data, buf, bytes_per_line); + scanner->eop_last_line_data_rpos = 0; + + /* Fill trailing line buffer with requested color. */ + if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_RASTER) + { + /* Black-white raster. */ + if (scanner->depth == DEPTH_BW) + { + memset (scanner->eop_last_line_data, 0xaa, bytes_per_line); + } + else + { + /* Gray. */ + for (unsigned int k = 0; k < bytes_per_line; ++k) + { + scanner->eop_last_line_data[k] = (k & 1 ? 0xff : 0); + } + } + } + else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_WHITE) + { + /* White. */ + if (scanner->depth == DEPTH_BW) + { + memset (scanner->eop_last_line_data, 0x00, bytes_per_line); + } + else + { + memset (scanner->eop_last_line_data, 0xff, bytes_per_line); + } + } + else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_BLACK) + { + /* Black. */ + if (scanner->depth == DEPTH_BW) + { + memset (scanner->eop_last_line_data, 0xff, bytes_per_line); + } + else + { + memset (scanner->eop_last_line_data, 0x00, bytes_per_line); + } + } + else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_COLOR) + { + if (scanner->depth == DEPTH_BW) + { + /* Black or white. */ + memset (scanner->eop_last_line_data, scanner->eop_trailing_lines_color & 0x01 ? 0x00 : 0xff, bytes_per_line); + } + else + { + /* Gray value */ + memset (scanner->eop_last_line_data, scanner->eop_trailing_lines_color & 0xff, bytes_per_line); + } + } + } + } + } + else + { + DBG (DBG_verbose, "Trailing lines mode: line=%u, mode=%d, color=%u\n", + i, scanner->eop_trailing_lines_mode, scanner->eop_trailing_lines_color); + + if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX)) + { + /* We are in in ADF mode after last-line and store next page data + * to buffer. + */ + if (! scanner->adf_next_page_lines_data) + { + unsigned int n_rest_lines = lines - i; + unsigned int buf_size = n_rest_lines * bytes_per_line; + scanner->adf_next_page_lines_data = malloc(buf_size); + if (! scanner->adf_next_page_lines_data) + return SANE_STATUS_NO_MEM; + scanner->adf_next_page_lines_data_size = buf_size; + scanner->adf_next_page_lines_data_rpos = 0; + scanner->adf_next_page_lines_data_wpos = 0; + DBG (DBG_verbose, "ADF between pages: Save n=%u next page lines in buffer.\n", n_rest_lines); + } + DBG (DBG_verbose, "ADF between pages: Store line %u of %u.\n", i, lines); + invert_negative_colors (buf, bytes_per_line, scanner); + memcpy (scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_wpos, buf, bytes_per_line); + scanner->adf_next_page_lines_data_wpos += bytes_per_line; + } + + if (scanner->eop_trailing_lines_mode != TRAILING_LINES_MODE_RAW) + { + /* Copy last line data or corresponding color over trailing lines + * data. + */ + memcpy (buf, scanner->eop_last_line_data, bytes_per_line); + } + } } return SANE_STATUS_GOOD; } +/******************************************************************************/ +static unsigned char +get_checked (unsigned char *ptr, unsigned int i, unsigned int length) +{ + if (i < length) + { + return ptr[i]; + } + DBG (DBG_details, "get from array out of range: idx=%u, size=%u\n", i, length); + return 0; +} + /******************************************************************************/ static SANE_Status convert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size) { unsigned int pixels_per_line; + unsigned int pixel_bits; unsigned int bytes_per_color; unsigned int bytes_per_line; + unsigned int bytes_per_line_limit; unsigned int lines; unsigned int i, j; unsigned char *buf; + unsigned char *bufptr; unsigned char *ptr; - SANE_Status ret; + SANE_Status ret; hp5590_assert (scanner != NULL); hp5590_assert (data != NULL); - if ( scanner->depth == DEPTH_BW - || scanner->depth == DEPTH_GRAY) + if ( ! (scanner->depth == DEPTH_COLOR_24 || scanner->depth == DEPTH_COLOR_48)) return SANE_STATUS_GOOD; DBG (DBG_proc, "%s\n", __func__); @@ -1193,79 +1899,555 @@ convert_to_rgb (struct hp5590_scanner *scanner, SANE_Byte *data, SANE_Int size) #endif ret = calc_image_params (scanner, - NULL, - &pixels_per_line, &bytes_per_line, - NULL, NULL); + &pixel_bits, + &pixels_per_line, &bytes_per_line, + NULL, NULL); if (ret != SANE_STATUS_GOOD) return ret; lines = size / bytes_per_line; - bytes_per_color = bytes_per_line / 3; - - DBG (DBG_verbose, "Length : %u\n", size); + bytes_per_color = (pixel_bits + 7) / 8; + + bytes_per_line_limit = bytes_per_line; + if ((scanner->depth == DEPTH_COLOR_48) && (bytes_per_line_limit > 3)) + { + /* Last-line indicator pixel has only 3 bytes instead of 6. */ + bytes_per_line_limit -= 3; + } + + DBG (DBG_verbose, "Length : %u\n", size); DBG (DBG_verbose, "Converting row RGB to normal RGB\n"); DBG (DBG_verbose, "Bytes per line %u\n", bytes_per_line); + DBG (DBG_verbose, "Bytes per line limited %u\n", bytes_per_line_limit); DBG (DBG_verbose, "Bytes per color %u\n", bytes_per_color); + DBG (DBG_verbose, "Pixels per line %u\n", pixels_per_line); DBG (DBG_verbose, "Lines %u\n", lines); - buf = malloc (bytes_per_line); - if (!buf) + /* Use working buffer for color mapping. */ + bufptr = malloc (size); + if (! bufptr) return SANE_STATUS_NO_MEM; + memset (bufptr, 0, size); + buf = bufptr; ptr = data; - for (j = 0; j < lines; ptr += bytes_per_line, j++) + for (j = 0; j < lines; ptr += bytes_per_line_limit, buf += bytes_per_line, j++) { - memset (buf, 0, bytes_per_line); for (i = 0; i < pixels_per_line; i++) - { - if (scanner->depth == DEPTH_COLOR_24) - { - /* R */ - buf[i*3] = ptr[i]; - /* G */ - buf[i*3+1] = ptr[i+bytes_per_color]; - /* B */ - buf[i*3+2] = ptr[i+bytes_per_color*2]; - } - else - { - /* R */ - buf[i*6] = ptr[2*i+1]; - buf[i*6+1] = ptr[2*i]; - /* G */ - buf[i*6+2] = ptr[2*i+bytes_per_color+1]; - buf[i*6+3] = ptr[2*i+bytes_per_color]; - /* B */ - buf[i*6+4] = ptr[2*i+bytes_per_color*2+1]; - buf[i*6+5] = ptr[2*i+bytes_per_color*2]; - } - } - - /* Invert pixels in case of TMA Negatives source has been selected */ - if (scanner->source == SOURCE_TMA_NEGATIVES) { - for (i = 0; i < bytes_per_line; i++) - buf[i] ^= 0xff; + /* Color mapping from raw scanner data to RGB buffer. */ + if (scanner->depth == DEPTH_COLOR_24) + { + /* R */ + buf[i*3] = get_checked(ptr, i, bytes_per_line_limit); + /* G */ + buf[i*3+1] = get_checked(ptr, i+pixels_per_line, bytes_per_line_limit);; + /* B */ + buf[i*3+2] = get_checked(ptr, i+pixels_per_line*2, bytes_per_line_limit); + } + else if (scanner->depth == DEPTH_COLOR_48) + { + /* Note: The last-line indicator pixel uses only 24 bits, not 48. + *Blue uses offset of 2 bytes. Green swaps lo and hi. + */ + /* R lo, hi*/ + buf[i*6] = get_checked(ptr, 2*i+(pixels_per_line-1)*0+1, bytes_per_line_limit); + buf[i*6+1] = get_checked(ptr, 2*i+(pixels_per_line-1)*0+0, bytes_per_line_limit); + /* G lo, hi*/ + buf[i*6+2] = get_checked(ptr, 2*i+(pixels_per_line-1)*2+0, bytes_per_line_limit); + buf[i*6+3] = get_checked(ptr, 2*i+(pixels_per_line-1)*2+1, bytes_per_line_limit); + /* B lo, hi*/ + buf[i*6+4] = get_checked(ptr, 2*i+(pixels_per_line-1)*4+1+2, bytes_per_line_limit); + buf[i*6+5] = get_checked(ptr, 2*i+(pixels_per_line-1)*4+0+2, bytes_per_line_limit); + } + } + + if (! scanner->eop_last_line_data) + { + if (pixels_per_line > 0) + { + /* Test for last-line indicator pixel on blue. If found, store + * last line and optionally overwrite indicator pixel with + * neighbor value. + */ + i = pixels_per_line - 1; + int eop_found = 0; + if (scanner->depth == DEPTH_COLOR_24) + { + /* DBG (DBG_details, "BUF24: %u %u %u\n", buf[i*3], buf[i*3+1], buf[i*3+2]); */ + eop_found = (buf[i*3+2] != 0); + if (scanner->overwrite_eop_pixel && (i > 0)) + { + buf[i*3] = buf[(i-1)*3]; + buf[i*3+1] = buf[(i-1)*3+1]; + buf[i*3+2] = buf[(i-1)*3+2]; + } + } + else if (scanner->depth == DEPTH_COLOR_48) + { + /* DBG (DBG_details, "BUF48: %u %u %u\n", buf[i*6+1], buf[i*6+3], buf[i*6+5]); */ + eop_found = (buf[i*6+5] != 0); + if (scanner->overwrite_eop_pixel && (i > 0)) + { + buf[i*6] = buf[(i-1)*6]; + buf[i*6+1] = buf[(i-1)*6+1]; + buf[i*6+2] = buf[(i-1)*6+2]; + buf[i*6+3] = buf[(i-1)*6+3]; + buf[i*6+4] = buf[(i-1)*6+4]; + buf[i*6+5] = buf[(i-1)*6+5]; + } + } + + invert_negative_colors (buf, bytes_per_line, scanner); + + if (eop_found && (! scanner->eop_last_line_data)) + { + DBG (DBG_verbose, "Found end-of-page at line %u in reading block.\n", j); + scanner->eop_last_line_data = malloc(bytes_per_line); + if (! scanner->eop_last_line_data) + return SANE_STATUS_NO_MEM; + + memcpy (scanner->eop_last_line_data, buf, bytes_per_line); + scanner->eop_last_line_data_rpos = 0; + + /* Fill trailing line buffer with requested color. */ + if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_RASTER) + { + /* Black-white raster. */ + if (scanner->depth == DEPTH_COLOR_24) + { + for (unsigned int k = 0; k < bytes_per_line; ++k) + { + scanner->eop_last_line_data[k] = (k % 6 < 3 ? 0xff : 0); + } + } + else + { + /* Color48. */ + for (unsigned int k = 0; k < bytes_per_line; ++k) + { + scanner->eop_last_line_data[k] = (k % 12 < 6 ? 0xff : 0); + } + } + } + else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_WHITE) + { + memset (scanner->eop_last_line_data, 0xff, bytes_per_line); + } + else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_BLACK) + { + memset (scanner->eop_last_line_data, 0x00, bytes_per_line); + } + else if (scanner->eop_trailing_lines_mode == TRAILING_LINES_MODE_COLOR) + { + /* RGB color value. */ + int rgb[3]; + rgb[0] = (scanner->eop_trailing_lines_color >> 16) & 0xff; + rgb[1] = (scanner->eop_trailing_lines_color >> 8) & 0xff; + rgb[2] = scanner->eop_trailing_lines_color & 0xff; + if (scanner->depth == DEPTH_COLOR_24) + { + for (unsigned int k = 0; k < bytes_per_line; ++k) + { + scanner->eop_last_line_data[k] = rgb[k % 3]; + } + } + else + { + /* Color48. */ + for (unsigned int k = 0; k < bytes_per_line; ++k) + { + scanner->eop_last_line_data[k] = rgb[(k % 6) >> 1]; + } + } + } + } + } + } + else + { + DBG (DBG_verbose, "Trailing lines mode: line=%u, mode=%d, color=%u\n", + j, scanner->eop_trailing_lines_mode, scanner->eop_trailing_lines_color); + + if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX)) + { + /* We are in in ADF mode after last-line and store next page data + * to buffer. + */ + if (! scanner->adf_next_page_lines_data) + { + unsigned int n_rest_lines = lines - j; + unsigned int buf_size = n_rest_lines * bytes_per_line; + scanner->adf_next_page_lines_data = malloc(buf_size); + if (! scanner->adf_next_page_lines_data) + return SANE_STATUS_NO_MEM; + scanner->adf_next_page_lines_data_size = buf_size; + scanner->adf_next_page_lines_data_rpos = 0; + scanner->adf_next_page_lines_data_wpos = 0; + DBG (DBG_verbose, "ADF between pages: Save n=%u next page lines in buffer.\n", n_rest_lines); + } + DBG (DBG_verbose, "ADF between pages: Store line %u of %u.\n", j, lines); + invert_negative_colors (buf, bytes_per_line, scanner); + memcpy (scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_wpos, buf, bytes_per_line); + scanner->adf_next_page_lines_data_wpos += bytes_per_line; + } + + if (scanner->eop_trailing_lines_mode != TRAILING_LINES_MODE_RAW) + { + /* Copy last line data or corresponding color over trailing lines + * data. + */ + memcpy (buf, scanner->eop_last_line_data, bytes_per_line); + } + } + } + memcpy (data, bufptr, size); + free (bufptr); + + return SANE_STATUS_GOOD; +} + +/******************************************************************************/ +static void +read_data_from_temporary_buffer(struct hp5590_scanner *scanner, + SANE_Byte * data, unsigned int max_length, + unsigned int bytes_per_line, SANE_Int *length) +{ + *length = 0; + if (scanner && scanner->one_line_read_buffer) + { + /* Copy scan data from temporary read buffer and return size copied data. */ + /* Release buffer, when no data left. */ + unsigned int rest_len; + rest_len = bytes_per_line - scanner->one_line_read_buffer_rpos; + rest_len = (rest_len < max_length) ? rest_len : max_length; + if (rest_len > 0) + { + memcpy (data, scanner->one_line_read_buffer + scanner->one_line_read_buffer_rpos, rest_len); + scanner->one_line_read_buffer_rpos += rest_len; + scanner->transferred_image_size -= rest_len; + *length = rest_len; + } + + DBG (DBG_verbose, "Copy scan data from temporary buffer: length = %u, rest in buffer = %u.\n", + *length, bytes_per_line - scanner->one_line_read_buffer_rpos); + + if (scanner->one_line_read_buffer_rpos >= bytes_per_line) + { + DBG (DBG_verbose, "Release temporary buffer.\n"); + free (scanner->one_line_read_buffer); + scanner->one_line_read_buffer = NULL; + scanner->one_line_read_buffer_rpos = 0; + } + } +} + +/******************************************************************************/ +static SANE_Status +sane_read_internal (struct hp5590_scanner * scanner, SANE_Byte * data, + SANE_Int max_length, SANE_Int * length, unsigned int bytes_per_line) +{ + SANE_Status ret; + + DBG (DBG_proc, "%s, length %u, left %llu\n", + __func__, + max_length, + scanner->transferred_image_size); + + SANE_Int length_limited = 0; + *length = max_length; + if ((unsigned long long) *length > scanner->transferred_image_size) + *length = (SANE_Int) scanner->transferred_image_size; + + /* Align reading size to bytes per line. */ + *length -= *length % bytes_per_line; + + if (scanner->depth == DEPTH_COLOR_48) + { + /* Note: The last-line indicator pixel uses only 24 bits (3 bytes), not + * 48 bits (6 bytes). + */ + if (bytes_per_line > 3) + { + length_limited = *length - *length % (bytes_per_line - 3); + } + } + + DBG (DBG_verbose, "Aligning requested size to bytes per line " + "(requested: %d, aligned: %u, limit_for_48bit: %u)\n", + max_length, *length, length_limited); + + if (max_length <= 0) + { + DBG (DBG_verbose, "Buffer too small for one scan line. Need at least %u bytes per line.\n", + bytes_per_line); + scanner->scanning = SANE_FALSE; + return SANE_STATUS_UNSUPPORTED; + } + + if (scanner->one_line_read_buffer) + { + /* Copy scan data from temporary read buffer. */ + read_data_from_temporary_buffer (scanner, data, max_length, bytes_per_line, length); + if (*length > 0) + { + DBG (DBG_verbose, "Return %d bytes, left %llu bytes.\n", *length, scanner->transferred_image_size); + return SANE_STATUS_GOOD; + } + } + + /* Buffer to return scanned data. We need at least space for one line to + * simplify color processing and last-line detection. If call buffer is too + * small, use temporary read buffer for reading one line instead. + */ + SANE_Byte * scan_data; + SANE_Int scan_data_length; + scan_data = data; + scan_data_length = *length; + + /* Note, read length is shorter in 48bit mode. */ + SANE_Int length_for_read = length_limited ? length_limited : scan_data_length; + if (length_for_read == 0) + { + /* Call buffer is too small for one line. Use temporary read buffer + * instead. + */ + if (! scanner->one_line_read_buffer) + { + scanner->one_line_read_buffer = malloc (bytes_per_line); + if (! scanner->one_line_read_buffer) + return SANE_STATUS_NO_MEM; + memset (scanner->one_line_read_buffer, 0, bytes_per_line); } - memcpy (ptr, buf, bytes_per_line); + DBG (DBG_verbose, "Call buffer too small for one scan line. Use temporary read buffer for one line with %u bytes.\n", + bytes_per_line); + + /* Scan and process next line in temporary buffer. */ + scan_data = scanner->one_line_read_buffer; + scan_data_length = bytes_per_line; + length_for_read = bytes_per_line; + if (scanner->depth == DEPTH_COLOR_48) + { + /* The last-line indicator pixel uses only 24 bits (3 bytes), not 48 + * bits (6 bytes). + */ + if (length_for_read > 3) + { + length_for_read -= 3; + } + } } - free (buf); + int read_from_scanner = 1; + if ((scanner->source == SOURCE_ADF) || (scanner->source == SOURCE_ADF_DUPLEX)) + { + if (scanner->eop_last_line_data) + { + /* Scanner is in ADF mode between last-line of previous page and + * start of next page. + * Fill remaining lines with last-line data. + */ + unsigned int wpos = 0; + while (wpos < (unsigned int) scan_data_length) + { + unsigned int n1 = scan_data_length - wpos; + unsigned int n2 = bytes_per_line - scanner->eop_last_line_data_rpos; + n1 = (n1 < n2) ? n1 : n2; + memcpy (scan_data + wpos, scanner->eop_last_line_data + scanner->eop_last_line_data_rpos, n1); + wpos += n1; + scanner->eop_last_line_data_rpos += n1; + if (scanner->eop_last_line_data_rpos >= bytes_per_line) + scanner->eop_last_line_data_rpos = 0; + } + read_from_scanner = (wpos == 0); + DBG (DBG_verbose, "ADF use last-line data, wlength=%u, length=%u\n", wpos, scan_data_length); + } + else if (scanner->adf_next_page_lines_data) + { + /* Scanner is in ADF mode at start of next page and already some next + * page data is available from earlier read operation. Return this + * data. + */ + unsigned int wpos = 0; + while ((wpos < (unsigned int) scan_data_length) && + (scanner->adf_next_page_lines_data_rpos < scanner->adf_next_page_lines_data_size)) + { + unsigned int n1 = scan_data_length - wpos; + unsigned int n2 = scanner->adf_next_page_lines_data_size - scanner->adf_next_page_lines_data_rpos; + n1 = (n1 < n2) ? n1 : n2; + memcpy (scan_data + wpos, scanner->adf_next_page_lines_data + scanner->adf_next_page_lines_data_rpos, n1); + wpos += n1; + scanner->adf_next_page_lines_data_rpos += n1; + if (scanner->adf_next_page_lines_data_rpos >= scanner->adf_next_page_lines_data_size) + { + free (scanner->adf_next_page_lines_data); + scanner->adf_next_page_lines_data = NULL; + scanner->adf_next_page_lines_data_size = 0; + scanner->adf_next_page_lines_data_rpos = 0; + scanner->adf_next_page_lines_data_wpos = 0; + } + } + scan_data_length = wpos; + read_from_scanner = (wpos == 0); + DBG (DBG_verbose, "ADF use next-page data, wlength=%u, length=%u\n", wpos, scan_data_length); + } + } + + if (read_from_scanner) + { + /* Read data from scanner. */ + ret = hp5590_read (scanner->dn, scanner->proto_flags, + scan_data, length_for_read, + scanner->bulk_read_state); + if (ret != SANE_STATUS_GOOD) + { + scanner->scanning = SANE_FALSE; + return ret; + } + + /* Look for last-line indicator pixels in convert functions. + * If found: + * - Overwrite indicator pixel with neighboring color (optional). + * - Save last line data for later use. + */ + ret = convert_to_rgb (scanner, scan_data, scan_data_length); + if (ret != SANE_STATUS_GOOD) + { + scanner->scanning = SANE_FALSE; + return ret; + } + + ret = convert_gray_and_lineart (scanner, scan_data, scan_data_length); + if (ret != SANE_STATUS_GOOD) + return ret; + } + + if (data == scan_data) + { + /* Scanned to call buffer. */ + scanner->transferred_image_size -= scan_data_length; + *length = scan_data_length; + } + else + { + /* Scanned to temporary read buffer. */ + if (scanner->one_line_read_buffer) + { + /* Copy scan data from temporary read buffer. */ + read_data_from_temporary_buffer (scanner, data, max_length, scan_data_length, length); + } + else + { + *length = 0; + } + } + + DBG (DBG_verbose, "Return %d bytes, left %llu bytes\n", *length, scanner->transferred_image_size); return SANE_STATUS_GOOD; } +/****************************************************************************** + * Copy at maximum the last n lines from the src buffer to the begin of the dst + * buffer. + * Return number of lines copied. + */ +static SANE_Int +copy_n_last_lines(SANE_Byte * src, SANE_Int src_len, SANE_Byte * dst, SANE_Int n, unsigned int bytes_per_line) +{ + DBG (DBG_proc, "%s\n", __func__); + SANE_Int n_copy = MY_MIN(src_len, n); + SANE_Byte * src1 = src + (src_len - n_copy) * bytes_per_line; + memcpy (dst, src1, n_copy * bytes_per_line); + return n_copy; +} + +/****************************************************************************** + * Copy the color values from line - delta_lines to line. + * buffer2 : Source and target buffer. + * buffer1 : Only source buffer. Contains lines scanned before lines in buffer1. + * color_idx : Index of color to be copied (0..2). + * delta_lines : color shift. + * color_48 : True = 2 byte , false = 1 byte per color. + */ +static void +shift_color_lines(SANE_Byte * buffer2, SANE_Int n_lines2, SANE_Byte * buffer1, SANE_Int n_lines1, SANE_Int color_idx, SANE_Int delta_lines, SANE_Bool color_48, unsigned int bytes_per_line) +{ + DBG (DBG_proc, "%s\n", __func__); + for (SANE_Int i = n_lines2 - 1; i >= 0; --i) { + SANE_Byte * dst = buffer2 + i * bytes_per_line; + SANE_Int ii = i - delta_lines; + SANE_Byte * src = NULL; + SANE_Int source_color_idx = color_idx; + if (ii >= 0) { + /* Read from source and target buffer. */ + src = buffer2 + ii * bytes_per_line; + } else { + ii += n_lines1; + if (ii >= 0) { + /* Read from source only buffer. */ + src = buffer1 + ii * bytes_per_line; + } else { + /* Read other color from source position. */ + src = dst; + source_color_idx = 2; + } + } + /* Copy selected color values. */ + SANE_Int step = color_48 ? 2 : 1; + SANE_Int stride = 3 * step; + for (unsigned int pos = 0; pos < bytes_per_line; pos += stride) { + SANE_Int p1 = pos + step * source_color_idx; + SANE_Int p2 = pos + step * color_idx; + dst[p2] = src[p1]; + if (color_48) { + dst[p2 + 1] = src[p1 + 1]; + } + } + } +} + +/****************************************************************************** + * Append all lines from buffer2 to the end of buffer1 and keep max_lines last + * lines. + * buffer2 : Source line buffer. + * buffer1 : Target line buffer. Length will be adjusted. + * max_lines : Max number of lines in buffer1. + */ +static void +append_and_move_lines(SANE_Byte * buffer2, SANE_Int n_lines2, SANE_Byte * buffer1, unsigned int * n_lines1_ptr, SANE_Int max_lines, unsigned int bytes_per_line) +{ + DBG (DBG_proc, "%s\n", __func__); + SANE_Int rest1 = max_lines - *n_lines1_ptr; + SANE_Int copy2 = MY_MIN(n_lines2, max_lines); + if (copy2 > rest1) { + SANE_Int shift1 = *n_lines1_ptr + copy2 - max_lines; + SANE_Int blen = MY_MIN(max_lines - shift1, (SANE_Int) *n_lines1_ptr); + SANE_Byte * pdst = buffer1; + SANE_Byte * psrc = pdst + shift1 * bytes_per_line; + for (SANE_Int i = 0; i < blen; ++i) { + memcpy (pdst, psrc, bytes_per_line); + pdst += bytes_per_line; + psrc += bytes_per_line; + } + *n_lines1_ptr -= shift1; + } + SANE_Int n_copied = copy_n_last_lines(buffer2, n_lines2, buffer1 + *n_lines1_ptr * bytes_per_line, copy2, bytes_per_line); + *n_lines1_ptr += n_copied; +} + + /******************************************************************************/ SANE_Status sane_read (SANE_Handle handle, SANE_Byte * data, - SANE_Int max_length, SANE_Int * length) + SANE_Int max_length, SANE_Int * length) { - struct hp5590_scanner *scanner = handle; - SANE_Status ret; + struct hp5590_scanner *scanner = handle; + SANE_Status ret; - DBG (DBG_proc, "%s, length %u, left %u\n", + DBG (DBG_proc, "%s, length %u, left %llu\n", __func__, max_length, scanner->transferred_image_size); @@ -1283,7 +2465,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, ret = hp5590_inc_scan_count (scanner->dn, scanner->proto_flags); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; /* Don't free bulk read state, some bytes could be left * for the next images from ADF @@ -1295,70 +2477,78 @@ sane_read (SANE_Handle handle, SANE_Byte * data, { ret = hp5590_low_init_bulk_read_state (&scanner->bulk_read_state); if (ret != SANE_STATUS_GOOD) - { - scanner->scanning = SANE_FALSE; - return ret; - } + { + scanner->scanning = SANE_FALSE; + return ret; + } } - *length = max_length; - if (*length > scanner->transferred_image_size) - *length = scanner->transferred_image_size; - - if ( scanner->depth == DEPTH_COLOR_24 - || scanner->depth == DEPTH_COLOR_48) - { - unsigned int bytes_per_line; - ret = calc_image_params (scanner, - NULL, NULL, - &bytes_per_line, - NULL, NULL); - if (ret != SANE_STATUS_GOOD) - return ret; + unsigned int bytes_per_line; + ret = calc_image_params (scanner, + NULL, NULL, + &bytes_per_line, + NULL, NULL); + if (ret != SANE_STATUS_GOOD) + return ret; - *length -= *length % bytes_per_line; - DBG (2, "Aligning requested size to bytes per line " - "(requested: %u, aligned: %u)\n", - max_length, *length); - } + ret = sane_read_internal(scanner, data, max_length, length, bytes_per_line); - ret = hp5590_read (scanner->dn, scanner->proto_flags, - data, *length, scanner->bulk_read_state); - if (ret != SANE_STATUS_GOOD) + if ((ret == SANE_STATUS_GOOD) && (scanner->dpi == 2400) && + ((scanner->depth == DEPTH_COLOR_48) || (scanner->depth == DEPTH_COLOR_24))) { - scanner->scanning = SANE_FALSE; - return ret; - } + /* Correct color shift bug for 2400 dpi. + * Note: 2400 dpi only works in color mode. Grey mode and lineart seem to + * fail. + * Align colors by shifting B channel by 48 lines and G channel by 24 + * lines. + */ + const SANE_Int offset_max = 48; + const SANE_Int offset_part = 24; + SANE_Bool color_48 = (scanner->depth == DEPTH_COLOR_48); - scanner->transferred_image_size -= *length; + if (! scanner->color_shift_line_buffer1) + { + scanner->color_shift_buffered_lines1 = 0; + scanner->color_shift_line_buffer1 = malloc (bytes_per_line * offset_max); + if (! scanner->color_shift_line_buffer1) + return SANE_STATUS_NO_MEM; + memset (scanner->color_shift_line_buffer1, 0, bytes_per_line * offset_max); + } + if (! scanner->color_shift_line_buffer2) + { + scanner->color_shift_buffered_lines2 = 0; + scanner->color_shift_line_buffer2 = malloc (bytes_per_line * offset_max); + if (! scanner->color_shift_line_buffer2) + return SANE_STATUS_NO_MEM; + memset (scanner->color_shift_line_buffer2, 0, bytes_per_line * offset_max); + } - ret = convert_to_rgb (scanner, data, *length); - if (ret != SANE_STATUS_GOOD) - { - scanner->scanning = SANE_FALSE; - return ret; - } + SANE_Int n_lines = *length / bytes_per_line; + scanner->color_shift_buffered_lines2 = MY_MIN(n_lines, offset_max); + copy_n_last_lines(data, n_lines, scanner->color_shift_line_buffer2, scanner->color_shift_buffered_lines2, bytes_per_line); - ret = convert_lineart (scanner, data, *length); - if (ret != SANE_STATUS_GOOD) - return ret; + shift_color_lines(data, n_lines, scanner->color_shift_line_buffer1, scanner->color_shift_buffered_lines1, 1, offset_part, color_48, bytes_per_line); + shift_color_lines(data, n_lines, scanner->color_shift_line_buffer1, scanner->color_shift_buffered_lines1, 0, offset_max, color_48, bytes_per_line); - return SANE_STATUS_GOOD; + append_and_move_lines(scanner->color_shift_line_buffer2, scanner->color_shift_buffered_lines2, scanner->color_shift_line_buffer1, &(scanner->color_shift_buffered_lines1), offset_max, bytes_per_line); + } + + return ret; } /******************************************************************************/ void sane_cancel (SANE_Handle handle) { - struct hp5590_scanner *scanner = handle; - SANE_Status ret; + struct hp5590_scanner *scanner = handle; + SANE_Status ret; DBG (DBG_proc, "%s\n", __func__); scanner->scanning = SANE_FALSE; if (scanner->dn < 0) - return; + return; hp5590_low_free_bulk_read_state (&scanner->bulk_read_state); @@ -1371,7 +2561,7 @@ sane_cancel (SANE_Handle handle) SANE_Status sane_set_io_mode (SANE_Handle __sane_unused__ handle, - SANE_Bool __sane_unused__ non_blocking) + SANE_Bool __sane_unused__ non_blocking) { DBG (DBG_proc, "%s\n", __func__); @@ -1381,7 +2571,7 @@ sane_set_io_mode (SANE_Handle __sane_unused__ handle, /******************************************************************************/ SANE_Status sane_get_select_fd (SANE_Handle __sane_unused__ handle, - SANE_Int __sane_unused__ * fd) + SANE_Int __sane_unused__ * fd) { DBG (DBG_proc, "%s\n", __func__); diff --git a/backend/hp5590_cmds.c b/backend/hp5590_cmds.c index 06fd91a..1eb96d3 100644 --- a/backend/hp5590_cmds.c +++ b/backend/hp5590_cmds.c @@ -1,6 +1,8 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2007 Ilia Sotnikov HP ScanJet 4570c support by Markham Thomas + ADF page detection and high DPI fixes by Bernard Badeer + scanbd integration by Damiano Scaramuzza and Bernard Badeer This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -71,9 +73,9 @@ hp5590_models[] = { SCANNER_HP5550, 0x03f0, 0x1205, "SILITEKIPenguin", "4500C/5550C", "Workgroup scanner", - PF_NO_USB_IN_USB_ACK /* These devices need no - * acknowledgement after USB-in-USB - * commands */ + PF_NO_USB_IN_USB_ACK /* These devices need no + * acknowledgment after USB-in-USB + * commands */ }, { SCANNER_HP5590, @@ -90,35 +92,36 @@ hp5590_models[] = { }; /* Debug levels */ -#define DBG_err 0 -#define DBG_proc 10 -#define DBG_cmds 40 +#define DBG_err 0 +#define DBG_proc 10 +#define DBG_verbose 20 +#define DBG_cmds 40 #define hp5590_cmds_assert(exp) if(!(exp)) { \ DBG (DBG_err, "Assertion '%s' failed at %s:%u\n", #exp, __FILE__, __LINE__);\ return SANE_STATUS_INVAL; \ } -#define WAKEUP_TIMEOUT 90 +#define WAKEUP_TIMEOUT 90 /* First byte of init (0x12 cmd) response */ -#define INIT_FLAG_TMA 1 << 0 -#define INIT_FLAG_ADF 1 << 1 -#define INIT_FLAG_LCD 1 << 3 +#define INIT_FLAG_TMA 1 << 0 +#define INIT_FLAG_ADF 1 << 1 +#define INIT_FLAG_LCD 1 << 3 /* Power (0x24 cmd) */ -#define POWER_FLAG_ON 1 << 1 +#define POWER_FLAG_ON 1 << 1 /* ADF (0x03 cmd) */ -#define FLAG_ADF_EMPTY 1 << 1 +#define FLAG_ADF_EMPTY 1 << 1 -#define PART_NUMBER_LEN 10 +#define PART_NUMBER_LEN 10 -#define REVERSE_MAP_LEN 128 * 1024 / sizeof(uint16_t) -#define FORWARD_MAP_LEN 128 * 1024 / sizeof(uint16_t) +#define REVERSE_MAP_LEN 128 * 1024 / sizeof(uint16_t) +#define FORWARD_MAP_LEN 128 * 1024 / sizeof(uint16_t) /* Button flags */ -/* From left to rigth */ +/* From left to right */ /* 1: Power * 1: Scan * 2: Collect @@ -129,48 +132,49 @@ hp5590_models[] = { * 8: Mode * 9: Cancel */ -#define BUTTON_FLAG_EMAIL 1 << 15 -#define BUTTON_FLAG_COPY 1 << 14 -#define BUTTON_FLAG_DOWN 1 << 13 -#define BUTTON_FLAG_MODE 1 << 12 -#define BUTTON_FLAG_UP 1 << 11 -#define BUTTON_FLAG_FILE 1 << 9 -#define BUTTON_FLAG_POWER 1 << 5 -#define BUTTON_FLAG_SCAN 1 << 2 -#define BUTTON_FLAG_COLLECT 1 << 1 -#define BUTTON_FLAG_CANCEL 1 << 0 - -#define CMD_INIT 0x0012 -#define CMD_EEPROM_ADDR 0x00f2 -#define CMD_EEPROM_READ 0x0bf0 -#define CMD_EEPROM_WRITE 0x0bf1 -#define CMD_DATA_STATUS 0x0001 -#define CMD_STOP_SCAN 0x011b -#define CMD_CONTROL_LAMP 0x00c0 -#define CMD_POWER_STATUS 0x0024 -#define CMD_SELECT_SOURCE 0x00d6 -#define CMD_MISC_STATUS 0x0003 -#define CMD_LOCK_UNLOCK 0x0000 -#define CMD_SET_BASE_DPI 0x0015 -#define CMD_SET_COLOR_MAP 0x0240 -#define CMD_SET_SCAN_PARAMS 0x0025 -#define CMD_GET_IMAGE_PARAMS 0x0034 -#define CMD_START_SCAN 0x051b -#define CMD_BUTTON_STATUS 0x0020 +#define BUTTON_FLAG_EMAIL 1 << 15 +#define BUTTON_FLAG_COPY 1 << 14 +#define BUTTON_FLAG_DOWN 1 << 13 +#define BUTTON_FLAG_MODE 1 << 12 +#define BUTTON_FLAG_UP 1 << 11 +#define BUTTON_FLAG_FILE 1 << 9 +#define BUTTON_FLAG_POWER 1 << 5 +#define BUTTON_FLAG_SCAN 1 << 2 +#define BUTTON_FLAG_COLLECT 1 << 1 +#define BUTTON_FLAG_CANCEL 1 << 0 + +#define CMD_INIT 0x0012 +#define CMD_EEPROM_ADDR 0x00f2 +#define CMD_EEPROM_READ 0x0bf0 +#define CMD_EEPROM_WRITE 0x0bf1 +#define CMD_DATA_STATUS 0x0001 +#define CMD_STOP_SCAN 0x011b +#define CMD_CONTROL_LAMP 0x00c0 +#define CMD_POWER_STATUS 0x0024 +#define CMD_SELECT_SOURCE 0x00d6 +#define CMD_MISC_STATUS 0x0003 +#define CMD_LOCK_UNLOCK 0x0000 +#define CMD_SET_BASE_DPI 0x0015 +#define CMD_SET_COLOR_MAP 0x0240 +#define CMD_SET_SCAN_PARAMS 0x0025 +#define CMD_GET_IMAGE_PARAMS 0x0034 +#define CMD_START_SCAN 0x051b +#define CMD_BUTTON_STATUS 0x0020 +#define CMD_LCD_STATUS 0x0021 struct init_resp { - uint8_t flags; /* bit 0 - TMA, bit 1 - ADF, bit 3 - LCD present */ - uint8_t id[15]; /* SILITEKPenguin */ - uint8_t pad1[9]; /* 00 00 00 00 00 00 00 00 00 */ - uint8_t version[5]; /* 0.0.67 */ - uint16_t max_dpi_x; /* 09 60 = 2400 */ - uint16_t max_dpi_y; /* 09 60 = 2400 */ - uint16_t max_pixels_x; /* 4F B0 = 20400 (20400 / 2400 = 8.5") */ - uint16_t max_pixels_y; /* 6D E0 = 28128 (28128 / 2400 = 11.72") */ - uint8_t pad2[8]; /* 00 00 00 00 00 00 00 00 */ - uint16_t motor_param_normal; /* 00 64 = 100 */ - uint16_t motor_param_max; /* 03 E8 = 1000 */ + uint8_t flags; /* bit 0 - TMA, bit 1 - ADF, bit 3 - LCD present */ + uint8_t id[15]; /* SILITEKPenguin */ + uint8_t pad1[9]; /* 00 00 00 00 00 00 00 00 00 */ + uint8_t version[5]; /* 0.0.67 */ + uint16_t max_dpi_x; /* 09 60 = 2400 */ + uint16_t max_dpi_y; /* 09 60 = 2400 */ + uint16_t max_pixels_x; /* 4F B0 = 20400 (20400 / 2400 = 8.5") */ + uint16_t max_pixels_y; /* 6D E0 = 28128 (28128 / 2400 = 11.72") */ + uint8_t pad2[8]; /* 00 00 00 00 00 00 00 00 */ + uint16_t motor_param_normal; /* 00 64 = 100 */ + uint16_t motor_param_max; /* 03 E8 = 1000 */ } __attribute__ ((packed)); struct power_resp @@ -179,10 +183,10 @@ struct power_resp uint16_t unk1; } __attribute__ ((packed)); -/* +/* * 215.9 mm x 297.2 mm * 8.5" x 11.72" - * + * * 50 : 425.00 x 586.00 * 75 : 637.50 x 879.50 * 100 : 850.00 x 1172.00 @@ -193,264 +197,264 @@ struct power_resp * 600 : 5100.00 x 7032.00 (base DPI) */ -#define SCAN_PARAMS_SOURCE_TMA_NEGATIVES 1 << 0 -#define SCAN_PARAMS_SOURCE_TMA_SLIDES 1 << 1 -#define SCAN_PARAMS_SOURCE_ADF 1 << 2 -#define SCAN_PARAMS_SOURCE_FLATBED 1 << 3 -#define SCAN_PARAMS_SOURCE_SIMPLEX 1 << 4 -#define SCAN_PARAMS_SOURCE_DUPLEX 1 << 6 +#define SCAN_PARAMS_SOURCE_TMA_NEGATIVES 1 << 0 +#define SCAN_PARAMS_SOURCE_TMA_SLIDES 1 << 1 +#define SCAN_PARAMS_SOURCE_ADF 1 << 2 +#define SCAN_PARAMS_SOURCE_FLATBED 1 << 3 +#define SCAN_PARAMS_SOURCE_SIMPLEX 1 << 4 +#define SCAN_PARAMS_SOURCE_DUPLEX 1 << 6 struct scan_params { - uint8_t source; /* - * TMA Negatives : 11 = 17 - * TMA Slides : 12 = 18 - * ADF : 14 = 20 - * Flatbed : 18 = 24 - * ADF Duplex : 54 = 84 - */ - - uint16_t dpi_x; /* - * 50 : 00 64 = 100 - * 75 : 00 64 = 100 - * 100 : 00 64 = 100 - * 150 : 00 c8 = 200 - * 200 : 00 c8 = 200 - * 300 : 01 2c = 300 - * 400 : 02 58 = 600 - * 600 : 02 58 = 600 - * 1200 : 04 b0 = 1200 - */ - - uint16_t dpi_y; /* - * 50 : 00 64 = 100 - * 75 : 00 64 = 100 - * 100 : 00 64 = 100 - * 150 : 00 c8 = 200 - * 200 : 00 c8 = 200 - * 300 : 01 2c = 300 - * 400 : 02 58 = 600 - * 600 : 02 58 = 600 - * 1200 : 04 b0 = 1200 - */ - - uint16_t top_x; /* - * pixels * (Base DPI / current DPI) - * 00 00, 01 6e = 366 (x = 425 - 302 = 123) - * 04 b0 = 1200 (x = 425 - 24 = 401) - */ - - uint16_t top_y; /* - * pixels * (Base DPI / current DPI) - * 00 00, 06 99 = 1689 (y = 585 - 21 = 564) - */ - - uint16_t size_x; /* X pixels in Base DPI (CMD 15) - * 50 : 04f8 = 1272 ; 150 - * 75 : 04f8 = 1272 ; 150 - * 100 : 04f8 = 1272 ; 150 - * 100 TMA : 00fc = 252 ; 150 - * 150 : 09f6 = 2550, 09f0 = 2544, 09f4 = 2548 ; 300 - * 200 : 09f0 = 2544, 09f6 = 2550, 09f6 = 2550 ; 300 - * 300 : 09f6 = 2550, 09f0 = 2544, 09f4 = 2548 ; 300 - * 300 TMA : 01fc = 508 ; 300 - * 400 : 13ec = 5100 ; 600 - * 600 : 13e8 = 5096, 13ec = 5100 ,13ec = 5100 ; 600 - * 1200 : 27a8 = 10152 ; 1200 - */ - - uint16_t size_y; /* Y pixels in Base DPI (CMD 15) - * 50 : 06db = 1755 ; 150 - * 75 : 06da = 1754 ; 150 - * 100 : 06db = 1755 ; 150 - * 100 TMA : 0384 = 900 ; 150 - * 150 : 0db6 = 3510 ; 300 - * 200 : 0db6 = 3510 ; 300 - * 300 : 0db6 = 3510 ; 300 - * 300 TMA : 0708 = 1800 ; 300 - * 400 : 1b6c = 7020 ; 600 - * 600 : 1b6c = 7020 ; 600 - * 1200 : 36d8 = 14040 ; 1200 - */ - - uint16_t unk1; /* 00 80 */ - - uint16_t bw_gray_flag; /* - * 00 40 - bw (ntsc gray)/gray, - * 00 20 - bw (by green band), - * 00 10 - bw (by red band), - * 00 30 - bw (by blue band), - * 00 00 - color - */ - - uint8_t pixel_bits; /* - * bw 50/75/150/400 : 08 = 8 - * bw 100/200/300/600/1200 : 01 = 1 - * gray 50/75/100/150/200/400/600 : 08 = 8 - * color 24 bit 50/75/100/150/200/400/600 : 18 = 24 - * color 48 bit 100/200 : 30 = 48 - */ - - uint16_t flags; /* - * 50/75/100/150/200/300 : e8 40 = 59456 - * 400/600/1200 : c8 40 = 51264 - */ - - uint16_t motor_param1; /* - * 00 64 = 100 - */ - uint16_t motor_param2; /* - * 00 64 = 100 - ADF, Flatbed, TMA slides - * 00 c8 = 200 - TMA Negatives - */ - uint16_t motor_param3; /* - * 00 64 = 100 - ADF, Flatbed, TMA slides - * 01 90 = 400 - TMA negatives - */ - uint32_t pad1; /* 00 00 00 00 */ - uint16_t pad2; /* 00 00 */ - uint8_t mode; /* 00 - normal scan, 04 - preview scan */ - uint16_t pad3; /* 00 00 */ - - uint16_t line_width; /* Based on current .dpi_x - * bw 50 : 03 50 = 848 - * gray 50 : 03 50 = 848 - * color 50 : 09 f0 = 2544 (3 * gray) - * - * bw 75 : 03 50 = 848 - * gray 75 : 03 50 = 848 - * color 75 : 09 f0 = 2544 (3 * gray) - * - * bw 100 : 00 6a = 106 - * gray 100 : 03 50 = 848 (8 * bw) - * color 100(24) : 09 f0 = 2544 (3 * gray) - * color 100(48) : 13 e0 = 5088 (2 * color 24) - * color 100(48) TMA : 03 f0 = 1008 - * - * bw 150 : 06 a4 = 1700 - * gray 150 : 06 a4 = 1700 - * color 150 : 13 ec = 5100 (3 * gray) - * - * bw 200 : 00 d4 = 212 - * gray 200 : 06 a4 = 1700 (8 * bw) - * color 200(24) : 13 ec = 5100 (3 * gray) - * color 200(48) : 27 a8 = 10152 - * - * bw 300 : 01 3e = 318 - * gray 300 : 09 f4 = 2548 (8 * bw) - * color 300 : 1d dc = 7644 (3 * gray) - * color 300(48) TMA : 0b e8 = 3048 - * - * bw 400 : 13 ec = 5100 - * gray 400 : 13 ec = 5100 - * color 400 : 3b c4 = 15300 (3 * gray) - * - * bw 600 : 02 7d = 637 - * gray 600 : 13 ec = 5100 (8 * bw) - * color 600 : 3b c4 = 15300 (3 * gray) - * - * bw 1200 : 04 f5 = 1269 - */ + uint8_t source; /* + * TMA Negatives : 11 = 17 + * TMA Slides : 12 = 18 + * ADF : 14 = 20 + * Flatbed : 18 = 24 + * ADF Duplex : 54 = 84 + */ + + uint16_t dpi_x; /* + * 50 : 00 64 = 100 + * 75 : 00 64 = 100 + * 100 : 00 64 = 100 + * 150 : 00 c8 = 200 + * 200 : 00 c8 = 200 + * 300 : 01 2c = 300 + * 400 : 02 58 = 600 + * 600 : 02 58 = 600 + * 1200 : 04 b0 = 1200 + */ + + uint16_t dpi_y; /* + * 50 : 00 64 = 100 + * 75 : 00 64 = 100 + * 100 : 00 64 = 100 + * 150 : 00 c8 = 200 + * 200 : 00 c8 = 200 + * 300 : 01 2c = 300 + * 400 : 02 58 = 600 + * 600 : 02 58 = 600 + * 1200 : 04 b0 = 1200 + */ + + uint16_t top_x; /* + * pixels * (Base DPI / current DPI) + * 00 00, 01 6e = 366 (x = 425 - 302 = 123) + * 04 b0 = 1200 (x = 425 - 24 = 401) + */ + + uint16_t top_y; /* + * pixels * (Base DPI / current DPI) + * 00 00, 06 99 = 1689 (y = 585 - 21 = 564) + */ + + uint16_t size_x; /* X pixels in Base DPI (CMD 15) + * 50 : 04f8 = 1272 ; 150 + * 75 : 04f8 = 1272 ; 150 + * 100 : 04f8 = 1272 ; 150 + * 100 TMA : 00fc = 252 ; 150 + * 150 : 09f6 = 2550, 09f0 = 2544, 09f4 = 2548 ; 300 + * 200 : 09f0 = 2544, 09f6 = 2550, 09f6 = 2550 ; 300 + * 300 : 09f6 = 2550, 09f0 = 2544, 09f4 = 2548 ; 300 + * 300 TMA : 01fc = 508 ; 300 + * 400 : 13ec = 5100 ; 600 + * 600 : 13e8 = 5096, 13ec = 5100 ,13ec = 5100 ; 600 + * 1200 : 27a8 = 10152 ; 1200 + */ + + uint16_t size_y; /* Y pixels in Base DPI (CMD 15) + * 50 : 06db = 1755 ; 150 + * 75 : 06da = 1754 ; 150 + * 100 : 06db = 1755 ; 150 + * 100 TMA : 0384 = 900 ; 150 + * 150 : 0db6 = 3510 ; 300 + * 200 : 0db6 = 3510 ; 300 + * 300 : 0db6 = 3510 ; 300 + * 300 TMA : 0708 = 1800 ; 300 + * 400 : 1b6c = 7020 ; 600 + * 600 : 1b6c = 7020 ; 600 + * 1200 : 36d8 = 14040 ; 1200 + */ + + uint16_t unk1; /* 00 80 */ + + uint16_t bw_gray_flag; /* + * 00 40 - bw (ntsc gray)/gray, + * 00 20 - bw (by green band), + * 00 10 - bw (by red band), + * 00 30 - bw (by blue band), + * 00 00 - color + */ + + uint8_t pixel_bits; /* + * bw 50/75/150/400 : 08 = 8 + * bw 100/200/300/600/1200 : 01 = 1 + * gray 50/75/100/150/200/400/600 : 08 = 8 + * color 24 bit 50/75/100/150/200/400/600 : 18 = 24 + * color 48 bit 100/200 : 30 = 48 + */ + + uint16_t flags; /* + * 50/75/100/150/200/300 : e8 40 = 59456 + * 400/600/1200 : c8 40 = 51264 + */ + + uint16_t motor_param1; /* + * 00 64 = 100 + */ + uint16_t motor_param2; /* + * 00 64 = 100 - ADF, Flatbed, TMA slides + * 00 c8 = 200 - TMA Negatives + */ + uint16_t motor_param3; /* + * 00 64 = 100 - ADF, Flatbed, TMA slides + * 01 90 = 400 - TMA negatives + */ + uint32_t pad1; /* 00 00 00 00 */ + uint16_t pad2; /* 00 00 */ + uint8_t mode; /* 00 - normal scan, 04 - preview scan */ + uint16_t pad3; /* 00 00 */ + + uint16_t line_width; /* Based on current .dpi_x + * bw 50 : 03 50 = 848 + * gray 50 : 03 50 = 848 + * color 50 : 09 f0 = 2544 (3 * gray) + * + * bw 75 : 03 50 = 848 + * gray 75 : 03 50 = 848 + * color 75 : 09 f0 = 2544 (3 * gray) + * + * bw 100 : 00 6a = 106 + * gray 100 : 03 50 = 848 (8 * bw) + * color 100(24) : 09 f0 = 2544 (3 * gray) + * color 100(48) : 13 e0 = 5088 (2 * color 24) + * color 100(48) TMA : 03 f0 = 1008 + * + * bw 150 : 06 a4 = 1700 + * gray 150 : 06 a4 = 1700 + * color 150 : 13 ec = 5100 (3 * gray) + * + * bw 200 : 00 d4 = 212 + * gray 200 : 06 a4 = 1700 (8 * bw) + * color 200(24) : 13 ec = 5100 (3 * gray) + * color 200(48) : 27 a8 = 10152 + * + * bw 300 : 01 3e = 318 + * gray 300 : 09 f4 = 2548 (8 * bw) + * color 300 : 1d dc = 7644 (3 * gray) + * color 300(48) TMA : 0b e8 = 3048 + * + * bw 400 : 13 ec = 5100 + * gray 400 : 13 ec = 5100 + * color 400 : 3b c4 = 15300 (3 * gray) + * + * bw 600 : 02 7d = 637 + * gray 600 : 13 ec = 5100 (8 * bw) + * color 600 : 3b c4 = 15300 (3 * gray) + * + * bw 1200 : 04 f5 = 1269 + */ } __attribute__ ((packed)); struct image_params { - uint8_t signature; /* c0 */ - uint8_t pad1; /* 00 */ - uint32_t image_size; /* - * bw 50 : 00 0f 23 a0 = 992 160 - * gray 50 : 00 0f 23 a0 = 992 160 - * color 50 : 00 2d 6a e0 = 2 976 480 - * - * bw 75 : 00 0f 20 50 = 991 312 - * gray 75 : 00 0f 20 50 = 991 312 - * color 75 : 00 2d 60 f0 = 2 973 936 - * color 75(48) : 00 5a 86 40 = 5 932 608 - * - * bw 100 : 00 01 e4 74 = 124 020 - * gray 100 : 00 0f 23 a0 = 992 160 - * color 100 : 00 2d 6a e0 = 2 976 480 - * color 100(48) : 00 5a 68 10 = 5 924 880 - * color 100(48), preview: 00 5a d5 c0 = 5 952 960 - * - * bw 150 : 00 3c b3 10 = 3 978 000 - * gray 150 : 00 3c b3 10 = 3 978 000 - * color 150 : 00 b6 19 30 = 11 934 000 - * color 150(48) : 01 6a 7b a0 = 23 755 680 - * - * bw 200 : 00 07 91 d0 = 496 080 - * gray 200 : 00 3c b3 10 = 3 978 000 - * color 200 : 00 b6 19 30 = 11 934 000 - * color 200(48) : 01 6a f3 a0 = 23 786 400 - * - * bw 300 : 00 11 08 14 = 1 116 180 - * gray 300 : 00 88 77 78 = 8 943 480 - * color 300 : 01 99 66 68 = 26 830 440 - * - * bw 400 : 02 22 4b 90 = 35 802 000 - * gray 400 : 02 22 4b 90 = 35 802 000 - * color 400 : 06 66 e2 b0 = 107 406 000 - * - * bw 600 : 00 44 3b bc = 4 471 740 - * gray 600 : 02 22 4b 90 = 35 802 000 - * color 600 : 06 66 e2 b0 = 107 406 000 - */ - uint16_t pad2; /* 00 00 */ + uint8_t signature; /* c0 */ + uint8_t pad1; /* 00 */ + uint32_t image_size; /* + * bw 50 : 00 0f 23 a0 = 992 160 + * gray 50 : 00 0f 23 a0 = 992 160 + * color 50 : 00 2d 6a e0 = 2 976 480 + * + * bw 75 : 00 0f 20 50 = 991 312 + * gray 75 : 00 0f 20 50 = 991 312 + * color 75 : 00 2d 60 f0 = 2 973 936 + * color 75(48) : 00 5a 86 40 = 5 932 608 + * + * bw 100 : 00 01 e4 74 = 124 020 + * gray 100 : 00 0f 23 a0 = 992 160 + * color 100 : 00 2d 6a e0 = 2 976 480 + * color 100(48) : 00 5a 68 10 = 5 924 880 + * color 100(48), preview: 00 5a d5 c0 = 5 952 960 + * + * bw 150 : 00 3c b3 10 = 3 978 000 + * gray 150 : 00 3c b3 10 = 3 978 000 + * color 150 : 00 b6 19 30 = 11 934 000 + * color 150(48) : 01 6a 7b a0 = 23 755 680 + * + * bw 200 : 00 07 91 d0 = 496 080 + * gray 200 : 00 3c b3 10 = 3 978 000 + * color 200 : 00 b6 19 30 = 11 934 000 + * color 200(48) : 01 6a f3 a0 = 23 786 400 + * + * bw 300 : 00 11 08 14 = 1 116 180 + * gray 300 : 00 88 77 78 = 8 943 480 + * color 300 : 01 99 66 68 = 26 830 440 + * + * bw 400 : 02 22 4b 90 = 35 802 000 + * gray 400 : 02 22 4b 90 = 35 802 000 + * color 400 : 06 66 e2 b0 = 107 406 000 + * + * bw 600 : 00 44 3b bc = 4 471 740 + * gray 600 : 02 22 4b 90 = 35 802 000 + * color 600 : 06 66 e2 b0 = 107 406 000 + */ + uint16_t pad2; /* 00 00 */ uint16_t line_width; uint16_t real_size_y; - uint32_t pad3; /* 00 00 00 00 */ + uint32_t pad3; /* 00 00 00 00 */ } __attribute__ ((packed)); struct lamp_state { - uint8_t unk1; /* 02 */ - uint8_t flag; /* 01 on start, 02 - TMA, 03 - all other */ - uint16_t turnoff_time; /* 0a 0a, 03 36, 0f 36 */ + uint8_t unk1; /* 02 */ + uint8_t flag; /* 01 on start, 02 - TMA, 03 - all other */ + uint16_t turnoff_time; /* 0a 0a, 03 36, 0f 36 */ } __attribute__ ((packed)); struct color_map { - uint8_t color1[6]; /* 00 00 00 00 01 00 */ - uint8_t color2[6]; /* 00 00 00 00 01 00 */ - uint8_t color3[6]; /* 00 00 00 00 01 00 */ + uint8_t color1[6]; /* 00 00 00 00 01 00 */ + uint8_t color2[6]; /* 00 00 00 00 01 00 */ + uint8_t color3[6]; /* 00 00 00 00 01 00 */ } __attribute__ ((packed)); struct reg_03 { - uint8_t unk1; /* 0x0b - ADF ready, 0x03 - not */ - uint8_t unk2; /* 0x80 */ - uint8_t adf_flags; /* 0x01 - ADF ready when selected, 0x02 - not */ + uint8_t unk1; /* 0x0b - ADF ready, 0x03 - not */ + uint8_t unk2; /* 0x80 */ + uint8_t adf_flags; /* 0x01 - ADF ready when selected, 0x02 - not */ } __attribute__ ((packed)); /******************************************************************************/ static SANE_Status hp5590_model_def (enum hp_scanner_types scanner_type, - const struct hp5590_model ** model) + const struct hp5590_model ** model) { unsigned int i; - + hp5590_cmds_assert (model != NULL); for (i = 0; i < sizeof (hp5590_models) / sizeof (struct hp5590_model); i++) { if (hp5590_models[i].scanner_type == scanner_type) - { - *model = &hp5590_models[i]; - return SANE_STATUS_GOOD; - } + { + *model = &hp5590_models[i]; + return SANE_STATUS_GOOD; + } } - + return SANE_STATUS_INVAL; } /******************************************************************************/ static SANE_Status hp5590_vendor_product_id (enum hp_scanner_types scanner_type, - SANE_Word * vendor_id, - SANE_Word * product_id) + SANE_Word * vendor_id, + SANE_Word * product_id) { - const struct hp5590_model *model; - SANE_Status ret; + const struct hp5590_model *model; + SANE_Status ret; hp5590_cmds_assert (vendor_id != NULL); hp5590_cmds_assert (product_id != NULL); @@ -467,15 +471,15 @@ hp5590_vendor_product_id (enum hp_scanner_types scanner_type, /******************************************************************************/ static SANE_Status hp5590_init_scanner (SANE_Int dn, - enum proto_flags proto_flags, - struct scanner_info ** info, - enum hp_scanner_types scanner_type) + enum proto_flags proto_flags, + struct scanner_info ** info, + enum hp_scanner_types scanner_type) { - struct init_resp init_resp; - char id_buf[sizeof (init_resp.id) + 1]; - char ver_buf[sizeof (init_resp.version) + 1]; - SANE_Status ret; - const struct hp5590_model *scanner_model; + struct init_resp init_resp; + char id_buf[sizeof (init_resp.id) + 1]; + char ver_buf[sizeof (init_resp.version) + 1]; + SANE_Status ret; + const struct hp5590_model *scanner_model; /* * 0A 53 49 4C 49 54 45 4B 49 50 65 6E 67 75 69 6E .SILITEKIPenguin @@ -489,11 +493,11 @@ hp5590_init_scanner (SANE_Int dn, /* Init scanner */ ret = hp5590_cmd (dn, - proto_flags, - CMD_IN | CMD_VERIFY, - CMD_INIT, - (unsigned char *) &init_resp, - sizeof (init_resp), CORE_NONE); + proto_flags, + CMD_IN | CMD_VERIFY, + CMD_INIT, + (unsigned char *) &init_resp, + sizeof (init_resp), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -504,23 +508,23 @@ hp5590_init_scanner (SANE_Int dn, { unsigned int i; for (i = 0; i < sizeof (hp5590_models) / sizeof (struct hp5590_model); - i++) - { - if (hp5590_models[i].scanner_type == scanner_type) - { - if (strcmp (id_buf, hp5590_models[i].vendor_id) != 0) - { - DBG (DBG_err, "%s: Vendor id mismatch for scanner HP%s - " - "required '%s', got '%s'\n", - __func__, - hp5590_models[i].model, - hp5590_models[i].vendor_id, id_buf); - return SANE_STATUS_INVAL; - } - scanner_model = &hp5590_models[i]; - break; - } - } + i++) + { + if (hp5590_models[i].scanner_type == scanner_type) + { + if (strcmp (id_buf, hp5590_models[i].vendor_id) != 0) + { + DBG (DBG_err, "%s: Vendor id mismatch for scanner HP%s - " + "required '%s', got '%s'\n", + __func__, + hp5590_models[i].model, + hp5590_models[i].vendor_id, id_buf); + return SANE_STATUS_INVAL; + } + scanner_model = &hp5590_models[i]; + break; + } + } hp5590_cmds_assert (scanner_model != NULL); } @@ -529,10 +533,10 @@ hp5590_init_scanner (SANE_Int dn, DBG (DBG_cmds, "HP%s flags (0x%02x)\n", scanner_model->model, init_resp.flags); DBG (DBG_cmds, "HP%s flags: ADF %s, TMA %s, LCD %s\n", - scanner_model->model, - init_resp.flags & INIT_FLAG_ADF ? "yes" : "no", - init_resp.flags & INIT_FLAG_TMA ? "yes" : "no", - init_resp.flags & INIT_FLAG_LCD ? "yes" : "no"); + scanner_model->model, + init_resp.flags & INIT_FLAG_ADF ? "yes" : "no", + init_resp.flags & INIT_FLAG_TMA ? "yes" : "no", + init_resp.flags & INIT_FLAG_LCD ? "yes" : "no"); memset (ver_buf, 0, sizeof (ver_buf)); @@ -540,33 +544,33 @@ hp5590_init_scanner (SANE_Int dn, DBG (DBG_cmds, "HP%s firmware version: %s\n", scanner_model->model, ver_buf); DBG (DBG_cmds, "HP%s max resolution X: %u DPI\n", - scanner_model->model, ntohs (init_resp.max_dpi_x)); + scanner_model->model, ntohs (init_resp.max_dpi_x)); DBG (DBG_cmds, "HP%s max resolution Y: %u DPI\n", - scanner_model->model, ntohs (init_resp.max_dpi_y)); + scanner_model->model, ntohs (init_resp.max_dpi_y)); DBG (DBG_cmds, "HP%s max pixels X: %u\n", - scanner_model->model, ntohs (init_resp.max_pixels_x)); + scanner_model->model, ntohs (init_resp.max_pixels_x)); DBG (DBG_cmds, "HP%s max pixels Y: %u\n", - scanner_model->model, ntohs (init_resp.max_pixels_y)); + scanner_model->model, ntohs (init_resp.max_pixels_y)); DBG (DBG_cmds, "HP%s max size X: %.3f inches\n", - scanner_model->model, - ntohs (init_resp.max_pixels_x) * 1.0 / - ntohs (init_resp.max_dpi_x)); + scanner_model->model, + ntohs (init_resp.max_pixels_x) * 1.0 / + ntohs (init_resp.max_dpi_x)); DBG (DBG_cmds, "HP%s max size Y: %.3f inches\n", scanner_model->model, - ntohs (init_resp.max_pixels_y) * 1.0 / - ntohs (init_resp.max_dpi_y)); + ntohs (init_resp.max_pixels_y) * 1.0 / + ntohs (init_resp.max_dpi_y)); DBG (DBG_cmds, "HP%s normal motor param: %u, max motor param: %u\n", - scanner_model->model, ntohs (init_resp.motor_param_normal), - ntohs (init_resp.motor_param_max)); + scanner_model->model, ntohs (init_resp.motor_param_normal), + ntohs (init_resp.motor_param_max)); } if (info) { *info = malloc (sizeof (struct scanner_info)); if (!*info) - { - DBG (DBG_err, "Memory allocation failed\n"); - return SANE_STATUS_NO_MEM; - } + { + DBG (DBG_err, "Memory allocation failed\n"); + return SANE_STATUS_NO_MEM; + } memset (*info, 0, sizeof (struct scanner_info)); (*info)->max_dpi_x = ntohs (init_resp.max_dpi_x); @@ -577,23 +581,23 @@ hp5590_init_scanner (SANE_Int dn, (*info)->max_size_y = (*info)->max_pixels_y * 1.0 / (*info)->max_dpi_y; (*info)->features = FEATURE_NONE; if (init_resp.flags & INIT_FLAG_LCD) - (*info)->features |= FEATURE_LCD; + (*info)->features |= FEATURE_LCD; if (init_resp.flags & INIT_FLAG_ADF) - (*info)->features |= FEATURE_ADF; + (*info)->features |= FEATURE_ADF; if (init_resp.flags & INIT_FLAG_TMA) - (*info)->features |= FEATURE_TMA; + (*info)->features |= FEATURE_TMA; if (scanner_model) - { - (*info)->model = scanner_model->model; - (*info)->kind = scanner_model->kind; - } + { + (*info)->model = scanner_model->model; + (*info)->kind = scanner_model->kind; + } } ret = hp5590_get_status (dn, proto_flags); if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: scanner reports non-zero status: %s\n", - __func__, sane_strstatus (ret)); + __func__, sane_strstatus (ret)); return ret; } DBG (DBG_cmds, "%s: scanner status OK\n", __func__); @@ -604,9 +608,9 @@ hp5590_init_scanner (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_read_eeprom (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int addr, - unsigned char *data, unsigned int size) + enum proto_flags proto_flags, + unsigned int addr, + unsigned char *data, unsigned int size) { uint8_t eeprom_addr = addr; SANE_Status ret; @@ -618,18 +622,18 @@ hp5590_read_eeprom (SANE_Int dn, DBG (DBG_proc, "Reading EEPROM: addr %04x, size %u\n", addr, size); ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_EEPROM_ADDR, - (unsigned char *) &eeprom_addr, - sizeof (eeprom_addr), CORE_NONE); + proto_flags, + CMD_VERIFY, + CMD_EEPROM_ADDR, + (unsigned char *) &eeprom_addr, + sizeof (eeprom_addr), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; ret = hp5590_cmd (dn, - proto_flags, - CMD_IN | CMD_VERIFY, - CMD_EEPROM_READ, data, size, CORE_NONE); + proto_flags, + CMD_IN | CMD_VERIFY, + CMD_EEPROM_READ, data, size, CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -639,9 +643,9 @@ hp5590_read_eeprom (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_write_eeprom (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int addr, - unsigned char *data, unsigned int size) + enum proto_flags proto_flags, + unsigned int addr, + unsigned char *data, unsigned int size) { uint8_t eeprom_addr = addr; SANE_Status ret; @@ -653,18 +657,18 @@ hp5590_write_eeprom (SANE_Int dn, DBG (DBG_proc, "Writing EEPROM: addr %04x, size: %u\n", addr, size); ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_EEPROM_ADDR, - (unsigned char *) &eeprom_addr, - sizeof (eeprom_addr), CORE_NONE); + proto_flags, + CMD_VERIFY, + CMD_EEPROM_ADDR, + (unsigned char *) &eeprom_addr, + sizeof (eeprom_addr), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_EEPROM_WRITE, data, size, CORE_DATA); + proto_flags, + CMD_VERIFY, + CMD_EEPROM_WRITE, data, size, CORE_DATA); if (ret != SANE_STATUS_GOOD) return ret; @@ -674,8 +678,8 @@ hp5590_write_eeprom (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_read_scan_count (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int *count) + enum proto_flags proto_flags, + unsigned int *count) { uint32_t scan_count; SANE_Status ret; @@ -687,10 +691,10 @@ hp5590_read_scan_count (SANE_Int dn, DBG (DBG_proc, "Reading scan count\n"); ret = hp5590_read_eeprom (dn, - proto_flags, - 0x00, - (unsigned char *) &scan_count, - sizeof (scan_count)); + proto_flags, + 0x00, + (unsigned char *) &scan_count, + sizeof (scan_count)); if (ret != SANE_STATUS_GOOD) return ret; @@ -706,11 +710,11 @@ hp5590_read_scan_count (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_inc_scan_count (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { uint32_t scan_count; - unsigned int count; - unsigned int new_count; + uint32_t count; + uint32_t new_count; SANE_Status ret; DBG (DBG_proc, "%s\n", __func__); @@ -721,12 +725,13 @@ hp5590_inc_scan_count (SANE_Int dn, return ret; scan_count = ++count; + DBG (DBG_verbose, "Scan count = %u\n", scan_count); ret = hp5590_write_eeprom (dn, - proto_flags, - 0x00, - (unsigned char *) &scan_count, - sizeof (scan_count)); + proto_flags, + 0x00, + (unsigned char *) &scan_count, + sizeof (scan_count)); if (ret != SANE_STATUS_GOOD) return ret; @@ -747,8 +752,8 @@ hp5590_inc_scan_count (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_read_max_scan_count (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int *max_count) + enum proto_flags proto_flags, + unsigned int *max_count) { uint8_t max_scan_count[3]; SANE_Status ret; @@ -760,10 +765,10 @@ hp5590_read_max_scan_count (SANE_Int dn, DBG (DBG_proc, "Reading max scan count\n"); ret = hp5590_read_eeprom (dn, - proto_flags, - 0x10, - (unsigned char *) max_scan_count, - sizeof (max_scan_count)); + proto_flags, + 0x10, + (unsigned char *) max_scan_count, + sizeof (max_scan_count)); if (ret != SANE_STATUS_GOOD) return ret; @@ -777,9 +782,9 @@ hp5590_read_max_scan_count (SANE_Int dn, } /*************************************************************************** - * + * * EEPROM contents: - * + * * 0000: 6A 11 00 00 FF FF FF FF FF FF FF FF 09 0E 0F 00 j............... * 0010: 0C 13 0F 00 00 3A 00 FF FF FF 4E 35 39 45 54 52 ..........N59ETR * 0020: 31 52 4D 00 FF FF 00 16 00 0A 00 0D 00 11 00 10 1RM............. @@ -806,7 +811,7 @@ hp5590_read_max_scan_count (SANE_Int dn, /******************************************************************************/ static __sane_unused__ SANE_Status hp5590_read_eeprom_all_cmd (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { uint8_t eeprom[255]; SANE_Status ret; @@ -814,14 +819,35 @@ hp5590_read_eeprom_all_cmd (SANE_Int dn, DBG (DBG_proc, "%s\n", __func__); ret = hp5590_read_eeprom (dn, - proto_flags, - 0x00, - (unsigned char *) eeprom, - sizeof (eeprom)); + proto_flags, + 0x00, + (unsigned char *) eeprom, + sizeof (eeprom)); if (ret != SANE_STATUS_GOOD) return ret; - /* FIXME: Debug output */ + DBG (DBG_verbose, "hp5590_read_eeprom_all_cmd: rc = %d\n", ret); + { + const int LEN = 4096; + char buf[LEN]; + char* p = buf; + for (size_t i = 0; i < sizeof(eeprom); ++i) { + if (i % 16 == 0) { + int n = sprintf(p, "\n%04x ", (int)i); + if (n < 0) { + break; + } + p += n; + } + int n = sprintf(p, " %02x", eeprom[i]); + if (n < 0 ) { + break; + } + p += n; + } + *p = '\0'; + DBG (DBG_verbose, "dump:%s\n", buf); + } return SANE_STATUS_GOOD; } @@ -829,7 +855,7 @@ hp5590_read_eeprom_all_cmd (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_read_part_number (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { unsigned int part_number_len = PART_NUMBER_LEN; unsigned char part_number[PART_NUMBER_LEN + 1]; @@ -839,9 +865,9 @@ hp5590_read_part_number (SANE_Int dn, memset (part_number, 0, sizeof (part_number)); ret = hp5590_read_eeprom (dn, - proto_flags, - 0x1a, - part_number, part_number_len); + proto_flags, + 0x1a, + part_number, part_number_len); if (ret != SANE_STATUS_GOOD) return ret; @@ -853,7 +879,7 @@ hp5590_read_part_number (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_is_data_available (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { uint8_t data_status; SANE_Status ret; @@ -865,11 +891,11 @@ hp5590_is_data_available (SANE_Int dn, data_available = SANE_FALSE; ret = hp5590_cmd (dn, - proto_flags, - CMD_IN | CMD_VERIFY, - CMD_DATA_STATUS, - (unsigned char *) &data_status, - sizeof (data_status), CORE_DATA); + proto_flags, + CMD_IN | CMD_VERIFY, + CMD_DATA_STATUS, + (unsigned char *) &data_status, + sizeof (data_status), CORE_DATA); if (ret != SANE_STATUS_GOOD) return ret; @@ -888,7 +914,7 @@ hp5590_is_data_available (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_stop_scan (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { uint8_t reg_011b = 0x40; SANE_Status ret; @@ -898,11 +924,11 @@ hp5590_stop_scan (SANE_Int dn, hp5590_cmds_assert (sizeof (reg_011b) == 1); ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_STOP_SCAN, - (unsigned char *) ®_011b, - sizeof (reg_011b), CORE_NONE); + proto_flags, + CMD_VERIFY, + CMD_STOP_SCAN, + (unsigned char *) ®_011b, + sizeof (reg_011b), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -914,8 +940,8 @@ hp5590_stop_scan (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_turnon_lamp (SANE_Int dn, - enum proto_flags proto_flags, - enum hp5590_lamp_state state) + enum proto_flags proto_flags, + enum hp5590_lamp_state state) { struct lamp_state lamp_state; SANE_Status ret; @@ -961,11 +987,11 @@ hp5590_turnon_lamp (SANE_Int dn, } ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_CONTROL_LAMP, - (unsigned char *) &lamp_state, - sizeof (lamp_state), CORE_DATA); + proto_flags, + CMD_VERIFY, + CMD_CONTROL_LAMP, + (unsigned char *) &lamp_state, + sizeof (lamp_state), CORE_DATA); if (ret != SANE_STATUS_GOOD) return ret; @@ -973,7 +999,7 @@ hp5590_turnon_lamp (SANE_Int dn, { ret = hp5590_init_scanner (dn, proto_flags, NULL, SCANNER_NONE); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; } return SANE_STATUS_GOOD; @@ -982,7 +1008,7 @@ hp5590_turnon_lamp (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_power_status (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { struct power_resp power_resp; SANE_Status ret; @@ -992,11 +1018,11 @@ hp5590_power_status (SANE_Int dn, hp5590_cmds_assert (sizeof (power_resp) == 3); ret = hp5590_cmd (dn, - proto_flags, - CMD_IN | CMD_VERIFY, - CMD_POWER_STATUS, - (unsigned char *) &power_resp, - sizeof (power_resp), CORE_NONE); + proto_flags, + CMD_IN | CMD_VERIFY, + CMD_POWER_STATUS, + (unsigned char *) &power_resp, + sizeof (power_resp), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -1008,7 +1034,7 @@ hp5590_power_status (SANE_Int dn, DBG (DBG_cmds, "Turning lamp on\n"); ret = hp5590_turnon_lamp (dn, proto_flags, LAMP_STATE_TURNON); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; } return SANE_STATUS_GOOD; @@ -1017,25 +1043,25 @@ hp5590_power_status (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_read_error_code (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int *adf_flags) + enum proto_flags proto_flags, + unsigned int *adf_flags) { struct reg_03 reg_03; - SANE_Status ret; + SANE_Status ret; DBG (DBG_proc, "%s\n", __func__); - + hp5590_cmds_assert (sizeof (reg_03) == 3); hp5590_cmds_assert (adf_flags != NULL); memset (®_03, 0, sizeof (reg_03)); *adf_flags = 0; ret = hp5590_cmd (dn, - proto_flags, - CMD_IN, - CMD_MISC_STATUS, - (unsigned char *) ®_03, - sizeof (reg_03), CORE_NONE); + proto_flags, + CMD_IN, + CMD_MISC_STATUS, + (unsigned char *) ®_03, + sizeof (reg_03), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -1052,12 +1078,12 @@ hp5590_read_error_code (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_reset_scan_head (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { - SANE_Status ret; + SANE_Status ret; DBG (DBG_proc, "%s\n", __func__); - + ret = hp5590_turnon_lamp (dn, proto_flags, LAMP_STATE_TURNOFF); if (ret != SANE_STATUS_GOOD) return ret; @@ -1074,13 +1100,13 @@ hp5590_reset_scan_head (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_select_source_and_wakeup (SANE_Int dn, - enum proto_flags proto_flags, - enum scan_sources source, - SANE_Bool extend_lamp_timeout) + enum proto_flags proto_flags, + enum scan_sources source, + SANE_Bool extend_lamp_timeout) { - uint8_t reg_d6 = 0x04; - SANE_Status ret; - unsigned int adf_flags; + uint8_t reg_d6 = 0x04; + SANE_Status ret; + unsigned int adf_flags; DBG (DBG_proc, "%s\n", __func__); @@ -1090,50 +1116,50 @@ hp5590_select_source_and_wakeup (SANE_Int dn, { ret = hp5590_turnon_lamp (dn, proto_flags, LAMP_STATE_TURNOFF); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; } else { ret = hp5590_turnon_lamp (dn, - proto_flags, - extend_lamp_timeout == SANE_TRUE ? - LAMP_STATE_SET_TURNOFF_TIME_LONG : - LAMP_STATE_SET_TURNOFF_TIME); + proto_flags, + extend_lamp_timeout == SANE_TRUE ? + LAMP_STATE_SET_TURNOFF_TIME_LONG : + LAMP_STATE_SET_TURNOFF_TIME); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; } switch (source) { case SOURCE_ADF: case SOURCE_ADF_DUPLEX: - reg_d6 = 0x03; - break; + reg_d6 = 0x03; + break; case SOURCE_FLATBED: - reg_d6 = 0x04; - break; + reg_d6 = 0x04; + break; case SOURCE_TMA_SLIDES: - reg_d6 = 0x02; - break; + reg_d6 = 0x02; + break; case SOURCE_TMA_NEGATIVES: - reg_d6 = 0x01; - break; + reg_d6 = 0x01; + break; case SOURCE_NONE: - DBG (DBG_err, "Scan source not selected\n"); - return SANE_STATUS_INVAL; + DBG (DBG_err, "Scan source not selected\n"); + return SANE_STATUS_INVAL; default: - DBG (DBG_err, "Unknown scan source: %u\n", source); - return SANE_STATUS_INVAL; + DBG (DBG_err, "Unknown scan source: %u\n", source); + return SANE_STATUS_INVAL; } DBG (DBG_cmds, "Scan source: %u\n", reg_d6); ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_SELECT_SOURCE, - (unsigned char *) ®_d6, - sizeof (reg_d6), CORE_NONE); + proto_flags, + CMD_VERIFY, + CMD_SELECT_SOURCE, + (unsigned char *) ®_d6, + sizeof (reg_d6), CORE_NONE); if (ret != SANE_STATUS_GOOD && ret != SANE_STATUS_DEVICE_BUSY) return ret; @@ -1154,12 +1180,12 @@ hp5590_select_source_and_wakeup (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_lock_unlock_scanner (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { - uint8_t reg_00 = 0x01; - SANE_Status ret; - unsigned int adf_flags; - unsigned int waiting; + uint8_t reg_00 = 0x01; + SANE_Status ret; + unsigned int adf_flags; + unsigned int waiting; DBG (DBG_proc, "%s\n", __func__); hp5590_cmds_assert (sizeof (reg_00) == 1); @@ -1167,27 +1193,27 @@ hp5590_lock_unlock_scanner (SANE_Int dn, for (waiting = 0; waiting < WAKEUP_TIMEOUT; waiting++, sleep (1)) { ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_LOCK_UNLOCK, - (unsigned char *) ®_00, - sizeof (reg_00), CORE_NONE); + proto_flags, + CMD_VERIFY, + CMD_LOCK_UNLOCK, + (unsigned char *) ®_00, + sizeof (reg_00), CORE_NONE); if (ret == SANE_STATUS_GOOD) - break; + break; if (ret != SANE_STATUS_DEVICE_BUSY) - return ret; + return ret; DBG (DBG_cmds, "Waiting for scanner...\n"); ret = hp5590_read_error_code (dn, proto_flags, &adf_flags); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; if (adf_flags & FLAG_ADF_EMPTY) - { - DBG (DBG_cmds, "ADF empty\n"); - return SANE_STATUS_NO_DOCS; - } + { + DBG (DBG_cmds, "ADF empty\n"); + return SANE_STATUS_NO_DOCS; + } } if (waiting == WAKEUP_TIMEOUT) @@ -1199,9 +1225,9 @@ hp5590_lock_unlock_scanner (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_set_base_dpi (SANE_Int dn, - enum proto_flags proto_flags, - struct scanner_info *scanner_info, - unsigned int base_dpi) + enum proto_flags proto_flags, + struct scanner_info *scanner_info, + unsigned int base_dpi) { uint16_t _base_dpi; SANE_Status ret; @@ -1216,21 +1242,21 @@ hp5590_set_base_dpi (SANE_Int dn, || base_dpi > scanner_info->max_dpi_y) { DBG (DBG_err, "Base DPI too large " - "(given: %u, max X DPI: %u, max Y DPI: %u)\n", - base_dpi, - scanner_info->max_dpi_x, - scanner_info->max_dpi_y); + "(given: %u, max X DPI: %u, max Y DPI: %u)\n", + base_dpi, + scanner_info->max_dpi_x, + scanner_info->max_dpi_y); return SANE_STATUS_INVAL; } _base_dpi = htons (base_dpi); ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_SET_BASE_DPI, - (unsigned char *) &_base_dpi, - sizeof (_base_dpi), CORE_DATA); + proto_flags, + CMD_VERIFY, + CMD_SET_BASE_DPI, + (unsigned char *) &_base_dpi, + sizeof (_base_dpi), CORE_DATA); if (ret != SANE_STATUS_GOOD) return ret; @@ -1240,8 +1266,8 @@ hp5590_set_base_dpi (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_set_color_map (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int base_dpi) + enum proto_flags proto_flags, + unsigned int base_dpi) { struct color_map color_map; SANE_Status ret; @@ -1260,28 +1286,48 @@ hp5590_set_color_map (SANE_Int dn, } else { - color_map.color1[2] = 0xff; - color_map.color1[3] = 0x01; - color_map.color1[4] = 0x04; - color_map.color1[5] = 0x02; - - color_map.color2[2] = 0xff; - color_map.color2[3] = 0x01; - color_map.color2[4] = 0x04; - color_map.color2[5] = 0x02; - - color_map.color3[2] = 0xff; - color_map.color3[3] = 0x01; - color_map.color3[4] = 0x04; - color_map.color3[5] = 0x02; + if (0) { + /* Does not work with hp5590 and 2400 dpi. */ + color_map.color1[2] = 0xff; + color_map.color1[3] = 0x01; + color_map.color1[4] = 0x04; + color_map.color1[5] = 0x02; + + color_map.color2[2] = 0xff; + color_map.color2[3] = 0x01; + color_map.color2[4] = 0x04; + color_map.color2[5] = 0x02; + + color_map.color3[2] = 0xff; + color_map.color3[3] = 0x01; + color_map.color3[4] = 0x04; + color_map.color3[5] = 0x02; + + } else { + /* Needs documentation. */ + color_map.color1[2] = 0x00; + color_map.color1[3] = 0x00; + color_map.color1[4] = 0x01; + color_map.color1[5] = 0x00; + + color_map.color2[2] = 0x00; + color_map.color2[3] = 0x00; + color_map.color2[4] = 0x01; + color_map.color2[5] = 0x00; + + color_map.color3[2] = 0x00; + color_map.color3[3] = 0x00; + color_map.color3[4] = 0x01; + color_map.color3[5] = 0x00; + } } ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_SET_COLOR_MAP, - (unsigned char *) &color_map, - sizeof (color_map), CORE_DATA); + proto_flags, + CMD_VERIFY, + CMD_SET_COLOR_MAP, + (unsigned char *) &color_map, + sizeof (color_map), CORE_DATA); if (ret != SANE_STATUS_GOOD) return ret; @@ -1394,7 +1440,7 @@ calc_scanner_dpi (unsigned int dpi, unsigned int *scanner_dpi) /******************************************************************************/ static SANE_Status hp5590_calc_pixel_bits (unsigned int dpi, enum color_depths color_depth, - unsigned int *pixel_bits) + unsigned int *pixel_bits) { unsigned int scanner_dpi; SANE_Status ret; @@ -1429,9 +1475,9 @@ hp5590_calc_pixel_bits (unsigned int dpi, enum color_depths color_depth, if (color_depth == DEPTH_BW) { if (dpi == scanner_dpi) - *pixel_bits = 1; + *pixel_bits = 1; else - *pixel_bits = 8; + *pixel_bits = 8; return SANE_STATUS_GOOD; } @@ -1442,28 +1488,28 @@ hp5590_calc_pixel_bits (unsigned int dpi, enum color_depths color_depth, /******************************************************************************/ static SANE_Status hp5590_set_scan_area (SANE_Int dn, - enum proto_flags proto_flags, - struct scanner_info *scanner_info, - unsigned int top_x, unsigned int top_y, - unsigned int width, unsigned int height, - unsigned int dpi, enum color_depths color_depth, - enum scan_modes scan_mode, - enum scan_sources scan_source) + enum proto_flags proto_flags, + struct scanner_info *scanner_info, + unsigned int top_x, unsigned int top_y, + unsigned int width, unsigned int height, + unsigned int dpi, enum color_depths color_depth, + enum scan_modes scan_mode, + enum scan_sources scan_source) { - struct scan_params scan_params; - unsigned int scanner_top_x; - unsigned int scanner_top_y; - unsigned int scanner_pixels_x; - unsigned int scanner_pixels_y; - unsigned int base_dpi; - unsigned int scanner_dpi; - unsigned int pixel_bits; - unsigned int scanner_line_width; - unsigned int max_pixels_x_current_dpi; - unsigned int max_pixels_y_current_dpi; - unsigned int pixels_x; - unsigned int pixels_y; - SANE_Status ret; + struct scan_params scan_params; + unsigned int scanner_top_x; + unsigned int scanner_top_y; + unsigned int scanner_pixels_x; + unsigned int scanner_pixels_y; + unsigned int base_dpi; + unsigned int scanner_dpi; + unsigned int pixel_bits; + unsigned int scanner_line_width; + unsigned int max_pixels_x_current_dpi; + unsigned int max_pixels_y_current_dpi; + unsigned int pixels_x; + unsigned int pixels_y; + SANE_Status ret; DBG (DBG_proc, "%s\n", __func__); @@ -1491,8 +1537,8 @@ hp5590_set_scan_area (SANE_Int dn, if (dpi > scanner_info->max_dpi_x || dpi > scanner_info->max_dpi_y) { DBG (DBG_err, "DPI too large " - "(given: %u, max X DPI: %u, max Y DPI: %u)\n", - dpi, scanner_info->max_dpi_x, scanner_info->max_dpi_y); + "(given: %u, max X DPI: %u, max Y DPI: %u)\n", + dpi, scanner_info->max_dpi_x, scanner_info->max_dpi_y); return SANE_STATUS_INVAL; } @@ -1580,14 +1626,14 @@ hp5590_set_scan_area (SANE_Int dn, if (top_x + pixels_x > max_pixels_x_current_dpi) { DBG (DBG_err, "Top X (%u) + pixels X (%u) exceeds max X %u\n", - top_x, pixels_x, max_pixels_x_current_dpi); + top_x, pixels_x, max_pixels_x_current_dpi); return SANE_STATUS_INVAL; } if (top_y + pixels_y > max_pixels_y_current_dpi) { DBG (DBG_err, "Top Y (%u) + pixels Y (%u) exceeds max Y %u\n", - top_y, pixels_y, max_pixels_y_current_dpi); + top_y, pixels_y, max_pixels_y_current_dpi); return SANE_STATUS_INVAL; } @@ -1597,23 +1643,23 @@ hp5590_set_scan_area (SANE_Int dn, scan_params.size_y = htons (scanner_pixels_y); scanner_line_width = (float) (pixels_x - * (1.0 * scanner_dpi / dpi) / 8 * pixel_bits); + * (1.0 * scanner_dpi / dpi) / 8 * pixel_bits); /* Scanner hangs at scan command if line width less than 18 */ if (scanner_line_width < 18) { - DBG (DBG_err, "Line width too smal, extending to minimum\n"); + DBG (DBG_err, "Line width too small, extending to minimum\n"); scanner_line_width = 18; } scan_params.line_width = htons (scanner_line_width); DBG (DBG_cmds, "Line width: %u\n", scanner_line_width); ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_SET_SCAN_PARAMS, - (unsigned char *) &scan_params, - sizeof (scan_params), CORE_DATA); + proto_flags, + CMD_VERIFY, + CMD_SET_SCAN_PARAMS, + (unsigned char *) &scan_params, + sizeof (scan_params), CORE_DATA); if (ret != SANE_STATUS_GOOD) return ret; @@ -1623,7 +1669,7 @@ hp5590_set_scan_area (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_read_image_params (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { struct image_params image_params; SANE_Status ret; @@ -1635,18 +1681,18 @@ hp5590_read_image_params (SANE_Int dn, memset (&image_params, 0, sizeof (image_params)); ret = hp5590_cmd (dn, - proto_flags, - CMD_IN | CMD_VERIFY, - CMD_GET_IMAGE_PARAMS, - (unsigned char *) &image_params, - sizeof (image_params), CORE_NONE); + proto_flags, + CMD_IN | CMD_VERIFY, + CMD_GET_IMAGE_PARAMS, + (unsigned char *) &image_params, + sizeof (image_params), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; if (image_params.signature != 0xc0) { DBG (DBG_err, "Wrong signature for image parameters structure " - "received (needed 0xc0, got %02x)\n", image_params.signature); + "received (needed 0xc0, got %02x)\n", image_params.signature); return SANE_STATUS_IO_ERROR; } DBG (DBG_cmds, "Received image params:\n"); @@ -1665,13 +1711,13 @@ hp5590_read_image_params (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_set_scan_params (SANE_Int dn, - enum proto_flags proto_flags, - struct scanner_info * scanner_info, - unsigned int top_x, unsigned int top_y, - unsigned int width, unsigned int height, - unsigned int dpi, enum color_depths color_depth, - enum scan_modes scan_mode, - enum scan_sources scan_source) + enum proto_flags proto_flags, + struct scanner_info * scanner_info, + unsigned int top_x, unsigned int top_y, + unsigned int width, unsigned int height, + unsigned int dpi, enum color_depths color_depth, + enum scan_modes scan_mode, + enum scan_sources scan_source) { unsigned int base_dpi; SANE_Status ret; @@ -1714,11 +1760,11 @@ hp5590_set_scan_params (SANE_Int dn, } ret = hp5590_set_scan_area (dn, - proto_flags, - scanner_info, - top_x, top_y, - width, height, - dpi, color_depth, scan_mode, scan_source); + proto_flags, + scanner_info, + top_x, top_y, + width, height, + dpi, color_depth, scan_mode, scan_source); if (ret != SANE_STATUS_GOOD) { /* Unlock scanner */ @@ -1745,7 +1791,7 @@ hp5590_set_scan_params (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_send_reverse_calibration_map (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { unsigned int reverse_map_size = REVERSE_MAP_LEN; uint16_t reverse_map[REVERSE_MAP_LEN]; @@ -1778,16 +1824,21 @@ hp5590_send_reverse_calibration_map (SANE_Int dn, for (i = len * 3; i < len * 4; i++) { - reverse_map[i] = htons (0xffff); + if (1) { + reverse_map[i] = htons (0xffff); + } else { + reverse_map[i] = htons (val); + val -= 1; + } } - DBG (DBG_proc, "Done preparing reverse calibration map\n"); + DBG (DBG_proc, "Done preparing reverse calibration map. n=%u, bytes_per_entry=%zu\n", reverse_map_size, sizeof(uint16_t)); ret = hp5590_bulk_write (dn, - proto_flags, - 0x2b, - (unsigned char *) reverse_map, - reverse_map_size * sizeof (uint16_t)); + proto_flags, + 0x2b, + (unsigned char *) reverse_map, + reverse_map_size * sizeof (uint16_t)); if (ret != SANE_STATUS_GOOD) return ret; @@ -1797,7 +1848,7 @@ hp5590_send_reverse_calibration_map (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_send_forward_calibration_maps (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { unsigned int forward_map_size = FORWARD_MAP_LEN; uint16_t forward_map[FORWARD_MAP_LEN]; @@ -1812,31 +1863,31 @@ hp5590_send_forward_calibration_maps (SANE_Int dn, { forward_map[i] = htons (val); if (val < 0xffff) - val += 1; + val += 1; } - DBG (DBG_proc, "Done preparing forward calibration map\n"); + DBG (DBG_proc, "Done preparing forward calibration map. n=%u, bytes_per_entry=%zu\n", forward_map_size, sizeof(uint16_t)); ret = hp5590_bulk_write (dn, - proto_flags, - 0x012a, - (unsigned char *) forward_map, - forward_map_size * sizeof (uint16_t)); + proto_flags, + 0x012a, + (unsigned char *) forward_map, + forward_map_size * sizeof (uint16_t)); if (ret != SANE_STATUS_GOOD) return ret; ret = hp5590_bulk_write (dn, - proto_flags, - 0x022a, - (unsigned char *) forward_map, - forward_map_size * sizeof (uint16_t)); + proto_flags, + 0x022a, + (unsigned char *) forward_map, + forward_map_size * sizeof (uint16_t)); if (ret != SANE_STATUS_GOOD) return ret; ret = hp5590_bulk_write (dn, - proto_flags, - 0x032a, - (unsigned char *) forward_map, - forward_map_size * sizeof (uint16_t)); + proto_flags, + 0x032a, + (unsigned char *) forward_map, + forward_map_size * sizeof (uint16_t)); if (ret != SANE_STATUS_GOOD) return ret; @@ -1846,9 +1897,9 @@ hp5590_send_forward_calibration_maps (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_read (SANE_Int dn, - enum proto_flags proto_flags, - unsigned char *bytes, unsigned int size, - void *state) + enum proto_flags proto_flags, + unsigned char *bytes, unsigned int size, + void *state) { SANE_Status ret; @@ -1867,7 +1918,7 @@ hp5590_read (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_start_scan (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { uint8_t reg_051b = 0x40; SANE_Status ret; @@ -1877,11 +1928,11 @@ hp5590_start_scan (SANE_Int dn, hp5590_cmds_assert (sizeof (reg_051b) == 1); ret = hp5590_cmd (dn, - proto_flags, - CMD_VERIFY, - CMD_START_SCAN, - (unsigned char *) ®_051b, - sizeof (reg_051b), CORE_NONE); + proto_flags, + CMD_VERIFY, + CMD_START_SCAN, + (unsigned char *) ®_051b, + sizeof (reg_051b), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -1891,8 +1942,8 @@ hp5590_start_scan (SANE_Int dn, /******************************************************************************/ static SANE_Status hp5590_read_buttons (SANE_Int dn, - enum proto_flags proto_flags, - enum button_status * status) + enum proto_flags proto_flags, + enum button_status * status) { uint16_t button_status; SANE_Status ret; @@ -1903,11 +1954,11 @@ hp5590_read_buttons (SANE_Int dn, hp5590_cmds_assert (sizeof (button_status) == 2); ret = hp5590_cmd (dn, - proto_flags, - CMD_IN | CMD_VERIFY, - CMD_BUTTON_STATUS, - (unsigned char *) &button_status, - sizeof (button_status), CORE_NONE); + proto_flags, + CMD_IN | CMD_VERIFY, + CMD_BUTTON_STATUS, + (unsigned char *) &button_status, + sizeof (button_status), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -1962,6 +2013,47 @@ hp5590_read_buttons (SANE_Int dn, return SANE_STATUS_GOOD; } +/******************************************************************************/ +static SANE_Status +hp5590_read_lcd_and_led (SANE_Int dn, + enum proto_flags proto_flags, + SANE_Int * lcd_counter, + enum color_led_status * color_led) +{ + SANE_Status ret; + + DBG (DBG_proc, "%s\n", __func__); + + hp5590_cmds_assert (lcd_counter != NULL); + hp5590_cmds_assert (color_led != NULL); + + /* + * Read LCD status bytes and get current value of counter and + * state of color/black_white LED. + * data[0x29]: LCD counter value, data[0x2a]: 1=color / 2=black_white. + */ + uint8_t data[0x30]; + ret = hp5590_cmd (dn, + proto_flags, + CMD_IN | CMD_VERIFY, + CMD_LCD_STATUS, + (unsigned char *) &data, + sizeof (data), CORE_NONE); + if (ret != SANE_STATUS_GOOD) + return ret; + + *lcd_counter = data[0x29]; + if (data[0x2a] == 2) { + *color_led = LED_BLACKWHITE; + } else { + *color_led = LED_COLOR; + } + DBG (DBG_cmds, "LCD and LED values: lcd=%d, led=%s\n", *lcd_counter, + *color_led == LED_BLACKWHITE ? "black_white" : "color"); + + return SANE_STATUS_GOOD; +} + /* SET SCAN PARAMETERS ==================== 50 ======================= BW 50 (425 x 585) @@ -2040,13 +2132,13 @@ GRAY 100 18 00 64 00 64 00 00 00 00 04 f8 06 db 00 80 00 40 08 e8 40 00 64 00 64 00 64 00 00 00 00 00 00 00 00 00 03 50 - + COLOR 100 18 00 64 00 64 00 00 00 00 04 f8 06 db 00 80 00 00 18 e8 40 00 64 00 64 00 64 00 00 00 00 00 00 00 00 00 09 f0 -COLOR 100 48bit, preview +COLOR 100 48bit, preview 18 00 64 00 64 00 00 00 00 04 f8 06 db 00 80 00 00 30 e8 40 00 64 00 64 00 64 00 00 00 00 00 00 04 00 00 13 e0 @@ -2144,7 +2236,7 @@ GRAY 400 18 02 58 02 58 00 00 00 00 13 ec 1b 6c 00 80 00 40 08 c8 40 00 64 00 64 00 64 00 00 00 00 00 00 00 00 00 13 ec - + COLOR 400 18 02 58 02 58 00 00 00 00 13 ec 1b 6c 00 80 00 00 18 c8 40 00 64 00 64 00 64 00 00 00 00 00 00 diff --git a/backend/hp5590_cmds.h b/backend/hp5590_cmds.h index c8da0f2..7179853 100644 --- a/backend/hp5590_cmds.h +++ b/backend/hp5590_cmds.h @@ -48,10 +48,10 @@ #include "hp5590_low.h" -#define TMA_MAX_X_INCHES 1.69 -#define TMA_MAX_Y_INCHES 6 +#define TMA_MAX_X_INCHES 1.69 +#define TMA_MAX_Y_INCHES 6 -#define ADF_MAX_Y_INCHES 14 +#define ADF_MAX_Y_INCHES 14 enum hp_scanner_types { @@ -101,6 +101,12 @@ enum button_status BUTTON_CANCEL }; +enum color_led_status +{ + LED_COLOR = 1, + LED_BLACKWHITE +}; + enum hp5590_lamp_state { LAMP_STATE_TURNOFF = 1, @@ -111,92 +117,92 @@ enum hp5590_lamp_state struct hp5590_model { - enum hp_scanner_types scanner_type; - unsigned int usb_vendor_id; - unsigned int usb_product_id; - const char *vendor_id; - const char *model; - const char *kind; - enum proto_flags proto_flags; + enum hp_scanner_types scanner_type; + unsigned int usb_vendor_id; + unsigned int usb_product_id; + const char *vendor_id; + const char *model; + const char *kind; + enum proto_flags proto_flags; }; -#define FEATURE_NONE 0 -#define FEATURE_ADF 1 << 0 -#define FEATURE_TMA 1 << 1 -#define FEATURE_LCD 1 << 2 +#define FEATURE_NONE 0 +#define FEATURE_ADF 1 << 0 +#define FEATURE_TMA 1 << 1 +#define FEATURE_LCD 1 << 2 struct scanner_info { - const char *model; - const char *kind; - unsigned int features; - const char *fw_version; - unsigned int max_dpi_x; - unsigned int max_dpi_y; - unsigned int max_pixels_x; - unsigned int max_pixels_y; - float max_size_x; - float max_size_y; - unsigned int max_motor_param; - unsigned int normal_motor_param; + const char *model; + const char *kind; + unsigned int features; + const char *fw_version; + unsigned int max_dpi_x; + unsigned int max_dpi_y; + unsigned int max_pixels_x; + unsigned int max_pixels_y; + float max_size_x; + float max_size_y; + unsigned int max_motor_param; + unsigned int normal_motor_param; }; static SANE_Status hp5590_model_def (enum hp_scanner_types scanner_type, - const struct hp5590_model ** model); + const struct hp5590_model ** model); static SANE_Status hp5590_vendor_product_id (enum hp_scanner_types scanner_type, - SANE_Word * vendor_id, - SANE_Word * product_id); + SANE_Word * vendor_id, + SANE_Word * product_id); static SANE_Status hp5590_init_scanner (SANE_Int dn, - enum proto_flags proto_flags, - struct scanner_info **info, - enum hp_scanner_types scanner_type); + enum proto_flags proto_flags, + struct scanner_info **info, + enum hp_scanner_types scanner_type); static SANE_Status hp5590_power_status (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_read_max_scan_count (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int *max_count); + enum proto_flags proto_flags, + unsigned int *max_count); static SANE_Status hp5590_select_source_and_wakeup (SANE_Int dn, - enum proto_flags proto_flags, - enum scan_sources source, - SANE_Bool extend_lamp_timeout); + enum proto_flags proto_flags, + enum scan_sources source, + SANE_Bool extend_lamp_timeout); static SANE_Status hp5590_stop_scan (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_read_scan_count (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int *count); + enum proto_flags proto_flags, + unsigned int *count); static SANE_Status hp5590_set_scan_params (SANE_Int dn, - enum proto_flags proto_flags, - struct scanner_info *scanner_info, - unsigned int top_x, unsigned int top_y, - unsigned int width, unsigned int height, - unsigned int dpi, - enum color_depths color_depth, - enum scan_modes scan_mode, - enum scan_sources scan_source); + enum proto_flags proto_flags, + struct scanner_info *scanner_info, + unsigned int top_x, unsigned int top_y, + unsigned int width, unsigned int height, + unsigned int dpi, + enum color_depths color_depth, + enum scan_modes scan_mode, + enum scan_sources scan_source); static SANE_Status hp5590_send_forward_calibration_maps (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_send_reverse_calibration_map (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_inc_scan_count (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_start_scan (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_read (SANE_Int dn, - enum proto_flags proto_flags, - unsigned char *bytes, - unsigned int size, void *state); + enum proto_flags proto_flags, + unsigned char *bytes, + unsigned int size, void *state); static SANE_Status hp5590_read_buttons (SANE_Int dn, - enum proto_flags proto_flags, - enum button_status *status); + enum proto_flags proto_flags, + enum button_status *status); static SANE_Status hp5590_read_part_number (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_calc_pixel_bits (unsigned int dpi, - enum color_depths color_depth, - unsigned int *pixel_bits); + enum color_depths color_depth, + unsigned int *pixel_bits); static SANE_Status hp5590_is_data_available (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_reset_scan_head (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); #endif /* HP5590_H */ /* vim: sw=2 ts=8 */ diff --git a/backend/hp5590_low.c b/backend/hp5590_low.c index 4961fd7..4936c58 100644 --- a/backend/hp5590_low.c +++ b/backend/hp5590_low.c @@ -59,9 +59,9 @@ #include "hp5590_low.h" /* Debug levels */ -#define DBG_err 0 -#define DBG_proc 10 -#define DBG_usb 50 +#define DBG_err 0 +#define DBG_proc 10 +#define DBG_usb 50 /* Custom assert() macro */ #define hp5590_low_assert(exp) if(!(exp)) { \ @@ -72,38 +72,38 @@ /* Structure describing bulk transfer size */ struct bulk_size { - uint16_t size; - uint8_t unused; + uint16_t size; + uint8_t unused; } __attribute__ ((packed)); /* Structure describing bulk URB */ /* FIXME: Verify according to USB standard */ struct usb_in_usb_bulk_setup { - uint8_t bRequestType; - uint8_t bRequest; - uint8_t bEndpoint; - uint16_t unknown; - uint16_t wLength; /* MSB first */ - uint8_t pad; + uint8_t bRequestType; + uint8_t bRequest; + uint8_t bEndpoint; + uint16_t unknown; + uint16_t wLength; /* MSB first */ + uint8_t pad; } __attribute__ ((packed)); /* Structure describing control URB */ struct usb_in_usb_ctrl_setup { uint8_t bRequestType; uint8_t bRequest; - uint16_t wValue; /* MSB first */ - uint16_t wIndex; /* MSB first */ - uint16_t wLength; /* LSB first */ + uint16_t wValue; /* MSB first */ + uint16_t wIndex; /* MSB first */ + uint16_t wLength; /* LSB first */ } __attribute__ ((packed)); /* CORE status flag - ready or not */ -#define CORE_FLAG_NOT_READY 1 << 1 +#define CORE_FLAG_NOT_READY 1 << 1 /* Bulk transfers are done in pages, below their respective sizes */ -#define BULK_WRITE_PAGE_SIZE 0x0f000 -#define BULK_READ_PAGE_SIZE 0x10000 -#define ALLOCATE_BULK_READ_PAGES 16 /* 16 * 65536 = 1Mb */ +#define BULK_WRITE_PAGE_SIZE 0x0f000 +#define BULK_READ_PAGE_SIZE 0x10000 +#define ALLOCATE_BULK_READ_PAGES 16 /* 16 * 65536 = 1Mb */ /* Structure describing bulk read state, because bulk reads will be done in * pages, but function caller uses its own buffer, whose size is certainly @@ -112,14 +112,14 @@ struct usb_in_usb_ctrl_setup { */ struct bulk_read_state { - unsigned char *buffer; - unsigned int buffer_size; - unsigned int bytes_available; + unsigned char *buffer; + unsigned int buffer_size; + unsigned int bytes_available; unsigned char *buffer_out_ptr; unsigned char *buffer_in_ptr; - unsigned int total_pages; + unsigned int total_pages; unsigned char *buffer_end_ptr; - unsigned int initialized; + unsigned int initialized; }; /******************************************************************************* @@ -134,10 +134,10 @@ struct bulk_read_state */ static SANE_Status hp5590_get_ack (SANE_Int dn, - enum proto_flags proto_flags) + enum proto_flags proto_flags) { - uint8_t status; - SANE_Status ret; + uint8_t status; + SANE_Status ret; /* Bypass reading acknowledge if the device doesn't need it */ if (proto_flags & PF_NO_USB_IN_USB_ACK) @@ -147,22 +147,22 @@ hp5590_get_ack (SANE_Int dn, /* Check if USB-in-USB operation was accepted */ ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, - 0x0c, 0x8e, 0x20, - sizeof (status), &status); + 0x0c, 0x8e, 0x20, + sizeof (status), &status); if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error getting acknowledge\n", - __func__); + __func__); return ret; } DBG (DBG_usb, "%s: USB-in-USB: accepted\n", __func__); - /* Check if we received correct acknowledgement */ + /* Check if we received correct acknowledgment */ if (status != 0x01) { DBG (DBG_err, "%s: USB-in-USB: not accepted (status %u)\n", - __func__, status); + __func__, status); return SANE_STATUS_DEVICE_BUSY; } @@ -181,7 +181,7 @@ hp5590_get_ack (SANE_Int dn, */ static SANE_Status hp5590_get_status (SANE_Int dn, - __sane_unused__ enum proto_flags proto_flags) + __sane_unused__ enum proto_flags proto_flags) { uint8_t status; SANE_Status ret; @@ -189,12 +189,12 @@ hp5590_get_status (SANE_Int dn, DBG (DBG_proc, "%s\n", __func__); ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, - 0x0c, 0x8e, 0x00, - sizeof (status), &status); + 0x0c, 0x8e, 0x00, + sizeof (status), &status); if (ret != SANE_STATUS_GOOD) { DBG (DBG_err, "%s: USB-in-USB: error getting device status\n", - __func__); + __func__); return ret; } @@ -202,7 +202,7 @@ hp5590_get_status (SANE_Int dn, if (status != 0x00) { DBG (DBG_err, "%s: USB-in-USB: got non-zero device status (status %u)\n", - __func__, status); + __func__, status); return SANE_STATUS_DEVICE_BUSY; } @@ -214,15 +214,15 @@ hp5590_get_status (SANE_Int dn, * * Parameters * dn - sanei_usb device descriptor - * requesttype, request, value, index - their meaninings are similar to + * requesttype, request, value, index - their meanings are similar to * sanei_control_msg() * bytes - pointer to data buffer * size - size of data - * core_flags - + * core_flags - * CORE_NONE - no CORE operation will be performed * CORE_DATA - operation on CORE data will be performed * CORE_BULK_IN - preparation for bulk IN transfer (not used yet) - * CORE_BULK_OUT - preparation for bulk OUT trasfer + * CORE_BULK_OUT - preparation for bulk OUT transfer * * Returns * SANE_STATUS_GOOD - control message was sent w/o any errors @@ -230,18 +230,18 @@ hp5590_get_status (SANE_Int dn, */ static SANE_Status hp5590_control_msg (SANE_Int dn, - enum proto_flags proto_flags, - int requesttype, int request, - int value, int index, unsigned char *bytes, - int size, int core_flags) + enum proto_flags proto_flags, + int requesttype, int request, + int value, int index, unsigned char *bytes, + int size, int core_flags) { - struct usb_in_usb_ctrl_setup ctrl; - SANE_Status ret; - unsigned int len; - unsigned char *ptr; - uint8_t ack; - uint8_t response; - unsigned int needed_response; + struct usb_in_usb_ctrl_setup ctrl; + SANE_Status ret; + unsigned int len; + unsigned char *ptr; + uint8_t ack; + uint8_t response; + unsigned int needed_response; DBG (DBG_proc, "%s: USB-in-USB: core data: %s\n", __func__, core_flags & CORE_DATA ? "yes" : "no"); @@ -262,60 +262,60 @@ hp5590_control_msg (SANE_Int dn, DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __func__); /* Send USB-in-USB control message */ ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, - 0x04, 0x8f, 0x00, - sizeof (ctrl), (unsigned char *) &ctrl); + 0x04, 0x8f, 0x00, + sizeof (ctrl), (unsigned char *) &ctrl); if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error sending control message\n", - __func__); - return ret; - } + { + DBG (DBG_err, "%s: USB-in-USB: error sending control message\n", + __func__); + return ret; + } /* USB-in-USB: checking acknowledge for control message */ ret = hp5590_get_ack (dn, proto_flags); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; len = size; ptr = bytes; /* Data is read in 8 byte portions */ while (len) - { - unsigned int next_packet_size; - next_packet_size = 8; - if (len < 8) - next_packet_size = len; - - /* Read USB-in-USB data */ - ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, - core_flags & CORE_DATA ? 0x0c : 0x04, - 0x90, 0x00, next_packet_size, ptr); - if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error reading data\n", __func__); - return ret; - } - - ptr += next_packet_size; - len -= next_packet_size; - } + { + unsigned int next_packet_size; + next_packet_size = 8; + if (len < 8) + next_packet_size = len; + + /* Read USB-in-USB data */ + ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, + core_flags & CORE_DATA ? 0x0c : 0x04, + 0x90, 0x00, next_packet_size, ptr); + if (ret != SANE_STATUS_GOOD) + { + DBG (DBG_err, "%s: USB-in-USB: error reading data\n", __func__); + return ret; + } + + ptr += next_packet_size; + len -= next_packet_size; + } /* Confirm data reception */ ack = 0; ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, - 0x0c, 0x8f, 0x00, - sizeof (ack), &ack); + 0x0c, 0x8f, 0x00, + sizeof (ack), &ack); if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error confirming data reception\n", - __func__); - return -1; - } + { + DBG (DBG_err, "%s: USB-in-USB: error confirming data reception\n", + __func__); + return -1; + } /* USB-in-USB: checking if confirmation was acknowledged */ ret = hp5590_get_ack (dn, proto_flags); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; } /* OUT (write) operation will be performed */ @@ -332,112 +332,112 @@ hp5590_control_msg (SANE_Int dn, DBG (DBG_usb, "%s: USB-in-USB: sending control msg\n", __func__); /* Send USB-in-USB control message */ ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, - 0x04, 0x8f, 0x00, - sizeof (ctrl), (unsigned char *) &ctrl); + 0x04, 0x8f, 0x00, + sizeof (ctrl), (unsigned char *) &ctrl); if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error sending control message\n", - __func__); - return ret; - } + { + DBG (DBG_err, "%s: USB-in-USB: error sending control message\n", + __func__); + return ret; + } /* USB-in-USB: checking acknowledge for control message */ ret = hp5590_get_ack (dn, proto_flags); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; len = size; ptr = bytes; /* Data is sent in 8 byte portions */ while (len) - { - unsigned int next_packet_size; - next_packet_size = 8; - if (len < 8) - next_packet_size = len; - - /* Send USB-in-USB data */ - ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, - core_flags & CORE_DATA ? 0x04 : 0x0c, - 0x8f, 0x00, next_packet_size, ptr); - if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error sending data\n", __func__); - return ret; - } - - /* CORE data is acknowledged packet by packet */ - if (core_flags & CORE_DATA) - { - /* USB-in-USB: checking if data was accepted */ - ret = hp5590_get_ack (dn, proto_flags); - if (ret != SANE_STATUS_GOOD) - return ret; - } - - ptr += next_packet_size; - len -= next_packet_size; - } + { + unsigned int next_packet_size; + next_packet_size = 8; + if (len < 8) + next_packet_size = len; + + /* Send USB-in-USB data */ + ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, + core_flags & CORE_DATA ? 0x04 : 0x0c, + 0x8f, 0x00, next_packet_size, ptr); + if (ret != SANE_STATUS_GOOD) + { + DBG (DBG_err, "%s: USB-in-USB: error sending data\n", __func__); + return ret; + } + + /* CORE data is acknowledged packet by packet */ + if (core_flags & CORE_DATA) + { + /* USB-in-USB: checking if data was accepted */ + ret = hp5590_get_ack (dn, proto_flags); + if (ret != SANE_STATUS_GOOD) + return ret; + } + + ptr += next_packet_size; + len -= next_packet_size; + } /* Normal (non-CORE) data is acknowledged after its full transmission */ if (!(core_flags & CORE_DATA)) - { - /* USB-in-USB: checking if data was accepted */ - ret = hp5590_get_ack (dn, proto_flags); - if (ret != SANE_STATUS_GOOD) - return ret; - } + { + /* USB-in-USB: checking if data was accepted */ + ret = hp5590_get_ack (dn, proto_flags); + if (ret != SANE_STATUS_GOOD) + return ret; + } /* Getting response after data transmission */ DBG (DBG_usb, "%s: USB-in-USB: getting response\n", __func__); ret = sanei_usb_control_msg (dn, USB_DIR_IN | USB_TYPE_VENDOR, - 0x0c, 0x90, 0x00, - sizeof (response), &response); + 0x0c, 0x90, 0x00, + sizeof (response), &response); if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error getting response\n", __func__); - return ret; - } + { + DBG (DBG_err, "%s: USB-in-USB: error getting response\n", __func__); + return ret; + } /* Necessary response after normal (non-CORE) data is 0x00, * after bulk OUT preparation - 0x24 */ needed_response = core_flags & CORE_BULK_OUT ? 0x24 : 0x00; if (response == needed_response) - DBG (DBG_usb, "%s: USB-in-USB: got correct response\n", - __func__); + DBG (DBG_usb, "%s: USB-in-USB: got correct response\n", + __func__); if (response != needed_response) - { - DBG (DBG_err, - "%s: USB-in-USB: invalid response received " - "(needed %04x, got %04x)\n", - __func__, needed_response, response); - return SANE_STATUS_IO_ERROR; - } + { + DBG (DBG_err, + "%s: USB-in-USB: invalid response received " + "(needed %04x, got %04x)\n", + __func__, needed_response, response); + return SANE_STATUS_IO_ERROR; + } /* Send bulk OUT flags is bulk OUT preparation is performed */ if (core_flags & CORE_BULK_OUT) - { - uint8_t bulk_flags = 0x24; - DBG (DBG_usb, "%s: USB-in-USB: sending bulk flags\n", - __func__); - - ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, - 0x0c, 0x83, 0x00, - sizeof (bulk_flags), &bulk_flags); - if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n", - __func__); - return ret; - } - - /* USB-in-USB: checking confirmation for bulk flags */ - ret = hp5590_get_ack (dn, proto_flags); - if (ret != SANE_STATUS_GOOD) - return ret; - } + { + uint8_t bulk_flags = 0x24; + DBG (DBG_usb, "%s: USB-in-USB: sending bulk flags\n", + __func__); + + ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, + 0x0c, 0x83, 0x00, + sizeof (bulk_flags), &bulk_flags); + if (ret != SANE_STATUS_GOOD) + { + DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n", + __func__); + return ret; + } + + /* USB-in-USB: checking confirmation for bulk flags */ + ret = hp5590_get_ack (dn, proto_flags); + if (ret != SANE_STATUS_GOOD) + return ret; + } } return SANE_STATUS_GOOD; @@ -458,24 +458,24 @@ hp5590_control_msg (SANE_Int dn, */ static SANE_Status hp5590_verify_last_cmd (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int cmd) + enum proto_flags proto_flags, + unsigned int cmd) { - uint16_t verify_cmd; - unsigned int last_cmd; - unsigned int core_status; - SANE_Status ret; + uint16_t verify_cmd; + unsigned int last_cmd; + unsigned int core_status; + SANE_Status ret; DBG (3, "%s: USB-in-USB: command verification requested\n", __func__); /* Read last command along with CORE status */ ret = hp5590_control_msg (dn, - proto_flags, - USB_DIR_IN, - 0x04, 0xc5, 0x00, - (unsigned char *) &verify_cmd, - sizeof (verify_cmd), CORE_NONE); + proto_flags, + USB_DIR_IN, + 0x04, 0xc5, 0x00, + (unsigned char *) &verify_cmd, + sizeof (verify_cmd), CORE_NONE); if (ret != SANE_STATUS_GOOD) return ret; @@ -493,8 +493,8 @@ hp5590_verify_last_cmd (SANE_Int dn, if ((cmd & 0x00ff) != last_cmd) { DBG (DBG_err, "%s: USB-in-USB: command verification failed: " - "expected 0x%04x, got 0x%04x\n", - __func__, cmd, last_cmd); + "expected 0x%04x, got 0x%04x\n", + __func__, cmd, last_cmd); return SANE_STATUS_IO_ERROR; } @@ -511,15 +511,15 @@ hp5590_verify_last_cmd (SANE_Int dn, * * Parameters * dn - sanei_usb device descriptor - * requesttype, request, value, index - their meaninings are similar to + * requesttype, request, value, index - their meanings are similar to * sanei_control_msg() * bytes - pointer to data buffer * size - size of data - * core_flags - + * core_flags - * CORE_NONE - no CORE operation will be performed * CORE_DATA - operation on CORE data will be performed * CORE_BULK_IN - preparation for bulk IN transfer (not used yet) - * CORE_BULK_OUT - preparation for bulk OUT trasfer + * CORE_BULK_OUT - preparation for bulk OUT transfer * * Returns * SANE_STATUS_GOOD - command was sent (and possible verified) w/o any errors @@ -527,19 +527,19 @@ hp5590_verify_last_cmd (SANE_Int dn, */ static SANE_Status hp5590_cmd (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int flags, - unsigned int cmd, unsigned char *data, unsigned int size, - unsigned int core_flags) + enum proto_flags proto_flags, + unsigned int flags, + unsigned int cmd, unsigned char *data, unsigned int size, + unsigned int core_flags) { SANE_Status ret; DBG (3, "%s: USB-in-USB: command : %04x\n", __func__, cmd); ret = hp5590_control_msg (dn, - proto_flags, - flags & CMD_IN ? USB_DIR_IN : USB_DIR_OUT, - 0x04, cmd, 0x00, data, size, core_flags); + proto_flags, + flags & CMD_IN ? USB_DIR_IN : USB_DIR_OUT, + 0x04, cmd, 0x00, data, size, core_flags); if (ret != SANE_STATUS_GOOD) return ret; @@ -578,21 +578,21 @@ hp5590_low_init_bulk_read_state (void **state) memset (bulk_read_state, 0, sizeof (struct bulk_read_state)); bulk_read_state->buffer = malloc (ALLOCATE_BULK_READ_PAGES - * BULK_READ_PAGE_SIZE); + * BULK_READ_PAGE_SIZE); if (!bulk_read_state->buffer) { DBG (DBG_err, "%s: Memory allocation failed for %u bytes\n", - __func__, ALLOCATE_BULK_READ_PAGES * BULK_READ_PAGE_SIZE); + __func__, ALLOCATE_BULK_READ_PAGES * BULK_READ_PAGE_SIZE); return SANE_STATUS_NO_MEM; } bulk_read_state->buffer_size = ALLOCATE_BULK_READ_PAGES - * BULK_READ_PAGE_SIZE; + * BULK_READ_PAGE_SIZE; bulk_read_state->bytes_available = 0; bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; bulk_read_state->buffer_in_ptr = bulk_read_state->buffer; bulk_read_state->total_pages = 0; bulk_read_state->buffer_end_ptr = bulk_read_state->buffer - + bulk_read_state->buffer_size; + + bulk_read_state->buffer_size; bulk_read_state->initialized = 1; *state = bulk_read_state; @@ -644,17 +644,17 @@ hp5590_low_free_bulk_read_state (void **state) */ static SANE_Status hp5590_bulk_read (SANE_Int dn, - enum proto_flags proto_flags, - unsigned char *bytes, unsigned int size, - void *state) + enum proto_flags proto_flags, + unsigned char *bytes, unsigned int size, + void *state) { - struct usb_in_usb_bulk_setup ctrl; - SANE_Status ret; - unsigned int next_pages; - uint8_t bulk_flags; - size_t next_portion; - struct bulk_read_state *bulk_read_state; - unsigned int bytes_until_buffer_end; + struct usb_in_usb_bulk_setup ctrl; + SANE_Status ret; + unsigned int next_pages; + uint8_t bulk_flags; + size_t next_portion; + struct bulk_read_state *bulk_read_state; + unsigned int bytes_until_buffer_end; DBG (3, "%s\n", __func__); @@ -665,7 +665,7 @@ hp5590_bulk_read (SANE_Int dn, if (bulk_read_state->initialized == 0) { DBG (DBG_err, "%s: USB-in-USB: bulk read state not initialized\n", - __func__); + __func__); return SANE_STATUS_INVAL; } @@ -675,8 +675,8 @@ hp5590_bulk_read (SANE_Int dn, if (size > bulk_read_state->buffer_size) { DBG (DBG_err, "Data requested won't fit in the bulk read buffer " - "(requested: %u, buffer size: %u\n", size, - bulk_read_state->buffer_size); + "(requested: %u, buffer size: %u\n", size, + bulk_read_state->buffer_size); return SANE_STATUS_NO_MEM; } @@ -684,8 +684,8 @@ hp5590_bulk_read (SANE_Int dn, while (bulk_read_state->bytes_available < size) { DBG (DBG_usb, "%s: USB-in-USB: not enough data in buffer available " - "(available: %u, requested: %u)\n", - __func__, bulk_read_state->bytes_available, size); + "(available: %u, requested: %u)\n", + __func__, bulk_read_state->bytes_available, size); /* IMPORTANT! 'next_pages' means 'request and receive next_pages pages in * one bulk transfer request '. Windows driver uses 4 pages between each @@ -703,114 +703,114 @@ hp5590_bulk_read (SANE_Int dn, */ bulk_read_state->total_pages++; DBG (DBG_usb, "%s: USB-in-USB: total pages done: %u\n", - __func__, bulk_read_state->total_pages); + __func__, bulk_read_state->total_pages); /* Send another bulk request for 'next_pages' before first * page or next necessary one */ if ( bulk_read_state->total_pages == 1 - || bulk_read_state->total_pages % next_pages == 0) - { - /* Send bulk flags */ - DBG (DBG_usb, "%s: USB-in-USB: sending USB-in-USB bulk flags\n", - __func__); - bulk_flags = 0x24; - ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, - 0x0c, 0x83, 0x00, - sizeof (bulk_flags), &bulk_flags); - if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n", - __func__); - return ret; - } - - /* USB-in-USB: checking confirmation for bulk flags\n" */ - ret = hp5590_get_ack (dn, proto_flags); - if (ret != SANE_STATUS_GOOD) - return ret; - - /* Prepare bulk read request */ - memset (&ctrl, 0, sizeof (ctrl)); - ctrl.bRequestType = 0x00; - ctrl.bEndpoint = 0x82; - ctrl.wLength = htons (next_pages); - - /* Send bulk read request */ - DBG (DBG_usb, "%s: USB-in-USB: sending control msg for bulk\n", - __func__); - ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, - 0x04, 0x82, 0x00, - sizeof (ctrl), - (unsigned char *) &ctrl); - if (ret != SANE_STATUS_GOOD) - { - DBG (DBG_err, "%s: USB-in-USB: error sending control msg\n", - __func__); - return ret; - } - - /* USB-in-USB: checking if control msg was accepted */ - ret = hp5590_get_ack (dn, proto_flags); - if (ret != SANE_STATUS_GOOD) - return ret; - } + || bulk_read_state->total_pages % next_pages == 0) + { + /* Send bulk flags */ + DBG (DBG_usb, "%s: USB-in-USB: sending USB-in-USB bulk flags\n", + __func__); + bulk_flags = 0x24; + ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, + 0x0c, 0x83, 0x00, + sizeof (bulk_flags), &bulk_flags); + if (ret != SANE_STATUS_GOOD) + { + DBG (DBG_err, "%s: USB-in-USB: error sending bulk flags\n", + __func__); + return ret; + } + + /* USB-in-USB: checking confirmation for bulk flags\n" */ + ret = hp5590_get_ack (dn, proto_flags); + if (ret != SANE_STATUS_GOOD) + return ret; + + /* Prepare bulk read request */ + memset (&ctrl, 0, sizeof (ctrl)); + ctrl.bRequestType = 0x00; + ctrl.bEndpoint = 0x82; + ctrl.wLength = htons (next_pages); + + /* Send bulk read request */ + DBG (DBG_usb, "%s: USB-in-USB: sending control msg for bulk\n", + __func__); + ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, + 0x04, 0x82, 0x00, + sizeof (ctrl), + (unsigned char *) &ctrl); + if (ret != SANE_STATUS_GOOD) + { + DBG (DBG_err, "%s: USB-in-USB: error sending control msg\n", + __func__); + return ret; + } + + /* USB-in-USB: checking if control msg was accepted */ + ret = hp5590_get_ack (dn, proto_flags); + if (ret != SANE_STATUS_GOOD) + return ret; + } next_portion = BULK_READ_PAGE_SIZE; /* Check if next page will fit into the buffer */ if (bulk_read_state->buffer_size - - bulk_read_state->bytes_available < next_portion) - { - DBG (DBG_err, "%s: USB-in-USB: buffer too small\n", __func__); - return SANE_STATUS_NO_MEM; - } + - bulk_read_state->bytes_available < next_portion) + { + DBG (DBG_err, "%s: USB-in-USB: buffer too small\n", __func__); + return SANE_STATUS_NO_MEM; + } /* Bulk read next page */ DBG (DBG_usb, "%s: USB-in-USB: bulk reading %lu bytes\n", - __func__, (u_long) next_portion); + __func__, (u_long) next_portion); ret = sanei_usb_read_bulk (dn, - bulk_read_state->buffer_in_ptr, - &next_portion); + bulk_read_state->buffer_in_ptr, + &next_portion); if (ret != SANE_STATUS_GOOD) - { - if (ret == SANE_STATUS_EOF) - return ret; - DBG (DBG_err, "%s: USB-in-USB: error during bulk read: %s\n", - __func__, sane_strstatus (ret)); - return ret; - } - - /* Check if we received the same amount of data as requsted */ + { + if (ret == SANE_STATUS_EOF) + return ret; + DBG (DBG_err, "%s: USB-in-USB: error during bulk read: %s\n", + __func__, sane_strstatus (ret)); + return ret; + } + + /* Check if we received the same amount of data as requested */ if (next_portion != BULK_READ_PAGE_SIZE) - { - DBG (DBG_err, "%s: USB-in-USB: incomplete bulk read " - "(requested %u bytes, got %lu bytes)\n", - __func__, BULK_READ_PAGE_SIZE, (u_long) next_portion); - return SANE_STATUS_IO_ERROR; - } + { + DBG (DBG_err, "%s: USB-in-USB: incomplete bulk read " + "(requested %u bytes, got %lu bytes)\n", + __func__, BULK_READ_PAGE_SIZE, (u_long) next_portion); + return SANE_STATUS_IO_ERROR; + } /* Move pointers to the next position */ bulk_read_state->buffer_in_ptr += next_portion; /* Check for the end of the buffer */ if (bulk_read_state->buffer_in_ptr > bulk_read_state->buffer_end_ptr) - { - DBG (DBG_err, - "%s: USB-in-USB: attempted to access over the end of buffer " - "(in_ptr: %p, end_ptr: %p, ptr: %p, buffer size: %u\n", - __func__, bulk_read_state->buffer_in_ptr, - bulk_read_state->buffer_end_ptr, bulk_read_state->buffer, - bulk_read_state->buffer_size); - return SANE_STATUS_NO_MEM; - } + { + DBG (DBG_err, + "%s: USB-in-USB: attempted to access over the end of buffer " + "(in_ptr: %p, end_ptr: %p, ptr: %p, buffer size: %u\n", + __func__, bulk_read_state->buffer_in_ptr, + bulk_read_state->buffer_end_ptr, bulk_read_state->buffer, + bulk_read_state->buffer_size); + return SANE_STATUS_NO_MEM; + } /* Check for buffer pointer wrapping */ if (bulk_read_state->buffer_in_ptr == bulk_read_state->buffer_end_ptr) - { - DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while writing\n", - __func__); - bulk_read_state->buffer_in_ptr = bulk_read_state->buffer; - } + { + DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while writing\n", + __func__); + bulk_read_state->buffer_in_ptr = bulk_read_state->buffer; + } /* Count the amount of data we read */ bulk_read_state->bytes_available += next_portion; @@ -832,13 +832,13 @@ hp5590_bulk_read (SANE_Int dn, bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; /* And second part (if any) */ if (bytes_until_buffer_end < size) - { - DBG (DBG_usb, "%s: USB-in-USB: giving 2nd buffer part\n", __func__); - memcpy (bytes + bytes_until_buffer_end, - bulk_read_state->buffer_out_ptr, - size - bytes_until_buffer_end); - bulk_read_state->buffer_out_ptr += size - bytes_until_buffer_end; - } + { + DBG (DBG_usb, "%s: USB-in-USB: giving 2nd buffer part\n", __func__); + memcpy (bytes + bytes_until_buffer_end, + bulk_read_state->buffer_out_ptr, + size - bytes_until_buffer_end); + bulk_read_state->buffer_out_ptr += size - bytes_until_buffer_end; + } } else { @@ -846,11 +846,11 @@ hp5590_bulk_read (SANE_Int dn, memcpy (bytes, bulk_read_state->buffer_out_ptr, size); bulk_read_state->buffer_out_ptr += size; if (bulk_read_state->buffer_out_ptr == bulk_read_state->buffer_end_ptr) - { - DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while reading\n", - __func__); - bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; - } + { + DBG (DBG_usb, "%s: USB-in-USB: buffer wrapped while reading\n", + __func__); + bulk_read_state->buffer_out_ptr = bulk_read_state->buffer; + } } /* Count the amount of data transferred to the caller */ @@ -870,17 +870,17 @@ hp5590_bulk_read (SANE_Int dn, * * Returns * SANE_STATUS_GOOD - all data transferred successfully - * all other SANE_Status value - otherwise + * all other SANE_Status value - otherwise */ static SANE_Status hp5590_bulk_write (SANE_Int dn, - enum proto_flags proto_flags, - int cmd, unsigned char *bytes, - unsigned int size) + enum proto_flags proto_flags, + int cmd, unsigned char *bytes, + unsigned int size) { - struct usb_in_usb_bulk_setup ctrl; - SANE_Status ret; - struct bulk_size bulk_size; + struct usb_in_usb_bulk_setup ctrl; + SANE_Status ret; + struct bulk_size bulk_size; unsigned int len; unsigned char *ptr; @@ -891,7 +891,7 @@ hp5590_bulk_write (SANE_Int dn, hp5590_low_assert (bytes != NULL); - /* Prepare bulk write request */ + /* Prepare bulk write request */ memset (&bulk_size, 0, sizeof (bulk_size)); /* Counted in page size */ bulk_size.size = size / BULK_WRITE_PAGE_SIZE; @@ -900,11 +900,11 @@ hp5590_bulk_write (SANE_Int dn, DBG (3, "%s: USB-in-USB: total %u pages (each of %u bytes)\n", __func__, bulk_size.size, BULK_WRITE_PAGE_SIZE); ret = hp5590_control_msg (dn, - proto_flags, - USB_DIR_OUT, - 0x04, cmd, 0, - (unsigned char *) &bulk_size, sizeof (bulk_size), - CORE_DATA | CORE_BULK_OUT); + proto_flags, + USB_DIR_OUT, + 0x04, cmd, 0, + (unsigned char *) &bulk_size, sizeof (bulk_size), + CORE_DATA | CORE_BULK_OUT); if (ret != SANE_STATUS_GOOD) return ret; @@ -916,10 +916,10 @@ hp5590_bulk_write (SANE_Int dn, { next_portion = BULK_WRITE_PAGE_SIZE; if (len < next_portion) - next_portion = len; + next_portion = len; DBG (3, "%s: USB-in-USB: next portion %lu bytes\n", - __func__, (u_long) next_portion); + __func__, (u_long) next_portion); /* Prepare bulk write request */ memset (&ctrl, 0, sizeof (ctrl)); @@ -929,29 +929,29 @@ hp5590_bulk_write (SANE_Int dn, /* Send bulk write request */ ret = sanei_usb_control_msg (dn, USB_DIR_OUT | USB_TYPE_VENDOR, - 0x04, 0x82, 0, - sizeof (ctrl), (unsigned char *) &ctrl); + 0x04, 0x82, 0, + sizeof (ctrl), (unsigned char *) &ctrl); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; /* USB-in-USB: checking if command was accepted */ ret = hp5590_get_ack (dn, proto_flags); if (ret != SANE_STATUS_GOOD) - return ret; + return ret; /* Write bulk data */ DBG (3, "%s: USB-in-USB: bulk writing %lu bytes\n", - __func__, (u_long) next_portion); + __func__, (u_long) next_portion); ret = sanei_usb_write_bulk (dn, ptr, &next_portion); if (ret != SANE_STATUS_GOOD) - { - /* Treast EOF as successful result */ - if (ret == SANE_STATUS_EOF) - break; - DBG (DBG_err, "%s: USB-in-USB: error during bulk write: %s\n", - __func__, sane_strstatus (ret)); - return ret; - } + { + /* Treast EOF as successful result */ + if (ret == SANE_STATUS_EOF) + break; + DBG (DBG_err, "%s: USB-in-USB: error during bulk write: %s\n", + __func__, sane_strstatus (ret)); + return ret; + } /* Move to the next page */ len -= next_portion; diff --git a/backend/hp5590_low.h b/backend/hp5590_low.h index 5ca191d..4882860 100644 --- a/backend/hp5590_low.h +++ b/backend/hp5590_low.h @@ -48,40 +48,40 @@ #include "../include/sane/sane.h" enum proto_flags { - PF_NONE = 0, - PF_NO_USB_IN_USB_ACK = 1 << 0 /* Getting acknowledge after USB-in-USB command - * will be skipped */ + PF_NONE = 0, + PF_NO_USB_IN_USB_ACK = 1 << 0 /* Getting acknowledge after USB-in-USB command + * will be skipped */ }; /* Flags for hp5590_cmd() */ -#define CMD_IN 1 << 0 /* Indicates IN direction, otherwise - OUT */ -#define CMD_VERIFY 1 << 1 /* Requests last command verification */ +#define CMD_IN 1 << 0 /* Indicates IN direction, otherwise - OUT */ +#define CMD_VERIFY 1 << 1 /* Requests last command verification */ /* Core flags for hp5590_cmd() - they indicate so called CORE commands */ -#define CORE_NONE 0 /* No CORE operation */ -#define CORE_DATA 1 << 0 /* Operate on CORE data */ -#define CORE_BULK_IN 1 << 1 /* CORE bulk operation - prepare for bulk IN - * transfer (not used yet) - */ -#define CORE_BULK_OUT 1 << 2 /* CORE bulk operation - prepare for bulk OUT - * transfer - */ +#define CORE_NONE 0 /* No CORE operation */ +#define CORE_DATA 1 << 0 /* Operate on CORE data */ +#define CORE_BULK_IN 1 << 1 /* CORE bulk operation - prepare for bulk IN + * transfer (not used yet) + */ +#define CORE_BULK_OUT 1 << 2 /* CORE bulk operation - prepare for bulk OUT + * transfer + */ static SANE_Status hp5590_cmd (SANE_Int dn, - enum proto_flags proto_flags, - unsigned int flags, - unsigned int cmd, unsigned char *data, - unsigned int size, unsigned int core_flags); + enum proto_flags proto_flags, + unsigned int flags, + unsigned int cmd, unsigned char *data, + unsigned int size, unsigned int core_flags); static SANE_Status hp5590_bulk_read (SANE_Int dn, - enum proto_flags proto_flags, - unsigned char *bytes, - unsigned int size, void *state); + enum proto_flags proto_flags, + unsigned char *bytes, + unsigned int size, void *state); static SANE_Status hp5590_bulk_write (SANE_Int dn, - enum proto_flags proto_flags, - int cmd, - unsigned char *bytes, - unsigned int size); + enum proto_flags proto_flags, + int cmd, + unsigned char *bytes, + unsigned int size); static SANE_Status hp5590_get_status (SANE_Int dn, - enum proto_flags proto_flags); + enum proto_flags proto_flags); static SANE_Status hp5590_low_init_bulk_read_state (void **state); static SANE_Status hp5590_low_free_bulk_read_state (void **state); #endif /* HP5590_LOW_H */ diff --git a/backend/hpljm1005.c b/backend/hpljm1005.c index 9460c48..be3b8f4 100644 --- a/backend/hpljm1005.c +++ b/backend/hpljm1005.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2007-2008 Philippe Rétornaz + Copyright (C) 2007-2008 Philippe Rétornaz This file is part of the SANE package. @@ -41,7 +41,7 @@ If you do not wish that, delete this exception notice. This backend is for HP LaserJet M1005 MFP - + Highly inspired from the epson backend */ @@ -177,7 +177,7 @@ static int devlist_count; /* Number of element in the list */ /* * List of pointers to devices - will be dynamically allocated depending - * on the number of devices found. + * on the number of devices found. */ static SANE_Device **devlist = NULL; @@ -193,7 +193,7 @@ update_img_size (struct device_s *dev) { int dx, dy; - /* Only update the width when not scanning, + /* Only update the width when not scanning, * otherwise the scanner give us the correct width */ if (dev->status == STATUS_SCANNING) { @@ -235,7 +235,7 @@ update_img_size (struct device_s *dev) dev->height = round2 ((dy / ((double) MAX_Y_S)) * 14025); break; } - + DBG(2,"New image size: %dx%d\n",dev->width, dev->height); } @@ -990,8 +990,8 @@ sane_start (SANE_Handle h) } -static void -do_cancel(struct device_s *dev) +static void +do_cancel(struct device_s *dev) { while (get_data (dev) == SANE_STATUS_GOOD); free (dev->buffer); @@ -1064,7 +1064,7 @@ sane_read (SANE_Handle h, SANE_Byte * buf, SANE_Int maxlen, SANE_Int * len) } /* Special case where sane_cancel is called while scanning */ - if (dev->status == STATUS_CANCELING) + if (dev->status == STATUS_CANCELING) { do_cancel(dev); return SANE_STATUS_CANCELLED; @@ -1078,7 +1078,7 @@ sane_cancel (SANE_Handle h) struct device_s *dev = (struct device_s *) h; - if (dev->status == STATUS_SCANNING) + if (dev->status == STATUS_SCANNING) { dev->status = STATUS_CANCELING; return; @@ -1101,4 +1101,3 @@ sane_get_select_fd (SANE_Handle __sane_unused__ handle, { return SANE_STATUS_UNSUPPORTED; } - diff --git a/backend/hpsj5s.c b/backend/hpsj5s.c index 9c6ad79..786a8d6 100644 --- a/backend/hpsj5s.c +++ b/backend/hpsj5s.c @@ -1065,7 +1065,7 @@ CalibrateScanElements () SANE_Byte CurrentLowTransferBorder; SANE_Byte CurrentUpSaveBorder; SANE_Byte CurrentLowSaveBorder; - SANE_Byte CurrentSpeed1, CurrentSpeed2; + SANE_Byte CurrentSpeed1, CurrentSpeed2; SANE_Byte CorrectionValue; SANE_Byte FilteredBuffer[2570]; @@ -1167,14 +1167,14 @@ CalibrateScanElements () CallFunctionWithParameter (0x91, 0); /*Stop engine. */ /*Note: if first read failed, junk would be calculated, but if previous - read was succeded, but last one failed, previous data'ld be used. + read was succeeded, but last one failed, previous data'ld be used. */ for(Temp = 0, j = 0; j < 2570; j++) Temp += FilteredBuffer[j]; Temp /= 2570; if((Average == 0)||(Average > Temp)) - Average = Temp; + Average = Temp; } for(Index = 0; Index < 3; Index++) /*Three color components*/ @@ -1190,7 +1190,7 @@ CalibrateScanElements () CallFunctionWithParameter (0x92, CurrentLowTransferBorder|0x80); for(j=2999; j>0; j--) CallFunctionWithParameter (0xC6, 0); - + CurrentUpSaveBorder = arUpSaveBorders[Index]; CallFunctionWithParameter (CurrentUpSaveBorder, 0xFF); @@ -1199,9 +1199,9 @@ CalibrateScanElements () CallFunctionWithParameter (0x90,0); Calibration = 0x80; CallFunctionWithParameter (CurrentUpSaveBorder, 0x80); - + CurrentSpeed1 = CurrentSpeed2 = arSpeeds[Index]; - + for(CorrectionValue = 0x40; CorrectionValue != 0;CorrectionValue >>= 2) { CallFunctionWithParameter (0x91, CurrentSpeed2); @@ -1235,11 +1235,11 @@ CalibrateScanElements () Perhaps, we can optimize it in future.*/ WriteScannerRegister (0x91, 0); usleep(10); - + for(Temp = 0,j = 0; j < 16;j++) Temp += FilteredBuffer[509+j]; /*At this offset calcalates HP's driver.*/ Temp /= 16; - + if(Average > Temp) { Calibration += CorrectionValue; @@ -1247,7 +1247,7 @@ CalibrateScanElements () } else Calibration -= CorrectionValue; - + WriteScannerRegister (CurrentUpSaveBorder, Calibration); }/*By CorrectionValue we tune UpSaveBorder*/ diff --git a/backend/hpsj5s.conf.in b/backend/hpsj5s.conf.in index 77fb4e4..d2e5f96 100644 --- a/backend/hpsj5s.conf.in +++ b/backend/hpsj5s.conf.in @@ -1,2 +1,2 @@ #hpsj5s.conf -#parport0 \ No newline at end of file +#parport0 diff --git a/backend/hs2p-saneopts.h b/backend/hs2p-saneopts.h index 0e712a3..938c7da 100644 --- a/backend/hs2p-saneopts.h +++ b/backend/hs2p-saneopts.h @@ -2,7 +2,7 @@ Copyright (C) 2007 Jeremy Johnson This file is part of a SANE backend for Ricoh IS450 and IS420 family of HS2P Scanners using the SCSI controller. - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -309,7 +309,7 @@ typedef enum /*OPT_CHECK_ADF, check for page in ADF before scanning */ OPT_ENHANCEMENT_GROUP, - /* OPT_ACE_FUNCTION, + /* OPT_ACE_FUNCTION, OPT_ACE_SENSITIVITY, */ OPT_BRIGHTNESS, /* Brightness */ OPT_THRESHOLD, /* Threshold */ diff --git a/backend/hs2p-scsi.c b/backend/hs2p-scsi.c index 431ba9d..6063acd 100644 --- a/backend/hs2p-scsi.c +++ b/backend/hs2p-scsi.c @@ -2,7 +2,7 @@ Copyright (C) 2007 Jeremy Johnson This file is part of a SANE backend for Ricoh IS450 and IS420 family of HS2P Scanners using the SCSI controller. - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -291,7 +291,7 @@ print_jis_info (struct inquiry_jis_data *jbuf) DBG (DBG_info, "[29] reserved %#02x\n", jbuf->reserved2); } -/* 1-3-1 TEST UNIT READY +/* 1-3-1 TEST UNIT READY Byte0: | 0x00 | Byte1: | 7-5 Logical Unit Number | Reserved | Byte2: | Reserved | @@ -407,8 +407,8 @@ lookup_ascq_errmsg (unsigned int code) } /* a sensible sense handler - arg is a pointer to the associated HS2P_Scanner structure - + arg is a pointer to the associated HS2P_Scanner structure + SENSE DATA FORMAT: 14 bytes bits[7-0] Byte 0: [7]:valid [6-0]:Error Code Byte 1: Segment Number @@ -488,9 +488,9 @@ sense_handler (int __sane_unused__ scsi_fd, u_char * sense_buffer, void *sd) DBG (DBG_sense, "sense_handler: ascq=(%#x,%#x): %#x '%s'\n", asc, ascq, ascq_key->codequalifier, ascq_key->description); - /* handle each sense key: Translate from HS2P message to SANE_STATUS_ message - * SANE_STATUS_GOOD, _ACCESS_DEINIED, _NO_MEM, _INVAL, _IO_ERROR, _DEVICE_BUSY, - * _EOF, _UNSUPPORTED, _CANCELLED, _JAMMED, _NO_DOCS, _COVER_OPEN + /* handle each sense key: Translate from HS2P message to SANE_STATUS_ message + * SANE_STATUS_GOOD, _ACCESS_DEINIED, _NO_MEM, _INVAL, _IO_ERROR, _DEVICE_BUSY, + * _EOF, _UNSUPPORTED, _CANCELLED, _JAMMED, _NO_DOCS, _COVER_OPEN */ switch (sense) { @@ -1436,7 +1436,7 @@ set_halftone_mask (int fd, SANE_Byte halftone_id, void *buf, cmd.dtc = DATA_TYPE_HALFTONE; _lto2b (halftone_id, cmd.dtq); - /* Each cell of an NxM dither pattern is 1 byte from the set {2,3,4,6,8,16} + /* Each cell of an NxM dither pattern is 1 byte from the set {2,3,4,6,8,16} * 0x80, 0x81 are User definable custom dither patterns */ if (halftone_id != 0x80 && halftone_id != 0x81) @@ -1547,7 +1547,7 @@ read_adf_status (int fd, SANE_Byte * adf_status_byte) /* 1-3-4 MODE SELECT */ -/* 1-3-5 Reserve Unit: 0x16 +/* 1-3-5 Reserve Unit: 0x16 * 1-3-6 Release Unit: 0x17 */ static SANE_Status @@ -1750,7 +1750,7 @@ trigger_scan (HS2P_Scanner * s) /* Transfer length is the byte length of Window List transferred * Window List is a list of Window Identifier created by SET WINDOW command * Since only 1 Window is supported by SCAN command, 0 or 1 is used for Window Identifier - * and 1 or 2 for length + * and 1 or 2 for length status = sanei_scsi_cmd (s->fd, &trigger, sizeof (trigger), &window_id_list[0], &wl_size); */ scan.cmd.len = (s->val[OPT_DUPLEX].w == SANE_TRUE) ? 2 : 1; diff --git a/backend/hs2p-scsi.h b/backend/hs2p-scsi.h index eecb60c..cdf227e 100644 --- a/backend/hs2p-scsi.h +++ b/backend/hs2p-scsi.h @@ -2,7 +2,7 @@ Copyright (C) 2007 Jeremy Johnson This file is part of a SANE backend for Ricoh IS450 and IS420 family of HS2P Scanners using the SCSI controller. - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -56,14 +56,14 @@ /* All other status byte keys are reserved */ /* - * SCSI Command List for Command Descriptor Block + * SCSI Command List for Command Descriptor Block * All reserved bit and fields in the CDB must be zero * Values in the CDB described as "Reserved" must no be specified * The FLAG and LINK bits in the CONTROL byte must be zero * Any values in the Vendor Unique field are ignored * The Logical Unit Number in the CDB must always be zero * All Reserved bit and fields in the data fields must be zero - * Values of parameters in the data fields described as + * Values of parameters in the data fields described as * "Reserved" or "Not supported" must not be specified */ @@ -132,7 +132,7 @@ static struct sense_key sensekey_errmsg[16] = { {0x0f, "RESERVED", "Invalid"} }; -/* When Error_Code = 0x70 more detailed information is available: +/* When Error_Code = 0x70 more detailed information is available: * code, qualifier, description */ struct ASCQ @@ -219,7 +219,7 @@ static struct ASCQ ascq_errmsg[74] = { typedef struct sense_data { /* HS2P_REQUEST_SENSE_DATA */ - /* bit7:valid is 1 if information byte is valid, + /* bit7:valid is 1 if information byte is valid, bits6:0 error_code */ SANE_Byte error_code; @@ -249,10 +249,10 @@ typedef struct sense_data #define HS2P_INQUIRY_JIS_PAGE_CODE 0xF0 /* - * The EVPD and Page Code are used in pair. When the EVPD bit is 0, INQUIRY data + * The EVPD and Page Code are used in pair. When the EVPD bit is 0, INQUIRY data * in the standard format is returned to the initiator. When the EVPD bit is 1, * the EVPD information specified by each Page Code is returned in each Page Code - * data format. + * data format. * * EVPD=0x00, Page_Code=0x00 => Standard Data Format * @@ -273,7 +273,7 @@ struct inquiry_standard_data */ SANE_Byte devtype; /* must be 0x06 */ - /* bit7: repaceable media bit is set to 0 + /* bit7: repaceable media bit is set to 0 * bits6-1: reserved * bit0: EVPD */ @@ -324,21 +324,21 @@ struct inquiry_vpd_data SANE_Byte pagecode; /* Page Code => 0xC0 */ SANE_Byte byte2; /* Reserved */ SANE_Byte pagelength; /* Page Length => 12 (0x0C) */ - SANE_Byte adf_id; /* ADF Identification + SANE_Byte adf_id; /* ADF Identification * 0: No ADF is mounted * 1: Single sided ADF is mounted * 2: Double sided ADF is mounted * 3: ARDF is mounted. (Reverse double side scanning available) - * 4: Reserved + * 4: Reserved * It should be 1 or 2 with this scanner. */ - SANE_Byte end_id; /* Endorser Identification + SANE_Byte end_id; /* Endorser Identification * 0: No endorser * 1: Endorser mounted - * 2: Reserved + * 2: Reserved * It should be 0 or 1 with this scanner */ - SANE_Byte ipu_id; /* Image Processing Unit Identification + SANE_Byte ipu_id; /* Image Processing Unit Identification * bits 7:2 Reserved * bit 1 0:Extended board not mounted * 1:Extended board is mounted @@ -346,8 +346,8 @@ struct inquiry_vpd_data * 1:IPU is mounted * It should always be 0 with this scanner */ - SANE_Byte imagecomposition; /* indicates supported image data type. - * This is set to 0x37 + SANE_Byte imagecomposition; /* indicates supported image data type. + * This is set to 0x37 * bit0 => Line art supported ? 1:0 * bit1 => Dither supported ? 1:0 * bit2 => Error Diffusion supported ? 1:0 @@ -379,13 +379,13 @@ struct inquiry_vpd_data * bit0 => Marker Recognition supported ? 1:0 * bits1-7 => Reserved */ - SANE_Byte sizerecognition; /* Size Detection + SANE_Byte sizerecognition; /* Size Detection * bit0 => Size Detection Supported ? 1:0 * bits1-7 => Reserved */ SANE_Byte byte13; /* Reserved */ SANE_Byte xmaxoutputpixels[2]; /* X Maximum Output Pixel is set to 4960 (0x1360) - * indicates maximum number of pixels in the main + * indicates maximum number of pixels in the main * scanning direction that can be output by scanner */ @@ -440,8 +440,8 @@ struct inquiry_jis_data typedef struct scsi_mode_select_cmd { SANE_Byte opcode; /* 15H */ - SANE_Byte byte1; /* 7-5:LUN; 4:PF; 2:Reserved; 1:SP - * Save Page Bit must be 0 since pages cannot be saved + SANE_Byte byte1; /* 7-5:LUN; 4:PF; 2:Reserved; 1:SP + * Save Page Bit must be 0 since pages cannot be saved * Page Format Bit must be 1 */ SANE_Byte reserved[2]; SANE_Byte len; /* Parameter List Length */ @@ -538,7 +538,7 @@ typedef struct mode_page_scanning_measurement SANE_Byte len; /* Parameter Length (06H) */ SANE_Byte bmu; /* Basic Measurement Unit */ SANE_Byte reserved0; - SANE_Byte mud[2]; /* Measurement Unit Divisor + SANE_Byte mud[2]; /* Measurement Unit Divisor * produces an error if 0 * mud is fixed to 1 for millimeter or point * point is default when scanner powers on */ @@ -574,9 +574,9 @@ typedef struct mode_page_adf_control * 01H Simplex ADF * 02H Duplex ADF * 03H-FFH Reserved */ - SANE_Byte adf_mode_control; /* 7-3:Reserved; 2:Prefeed Mode Validity 1-0:Ignored + SANE_Byte adf_mode_control; /* 7-3:Reserved; 2:Prefeed Mode Validity 1-0:Ignored * Prefeed Mode "0" means invalid, "1" means valid */ - SANE_Byte medium_wait_timer; /* indicates time for scanner to wait for media. Scanner + SANE_Byte medium_wait_timer; /* indicates time for scanner to wait for media. Scanner * will send CHECK on timeout. NOT SUPPORTED */ SANE_Byte ignored[3]; } MP_ADF; /* ADF Control */ @@ -636,9 +636,9 @@ typedef struct scsi_mode_sense_cmd SANE_Byte len; /* Allocation length */ SANE_Byte control; /* 7-6:Vendor Unique; 5-2:Reserved; 1:Flag; 0:Link */ } SENSE; -/* MODE SENSE DATA FORMAT -- - * The format of Sense Data to be returned is Mode Parameter Header + Page - * see struct scsi_mode_parameter_header +/* MODE SENSE DATA FORMAT -- + * The format of Sense Data to be returned is Mode Parameter Header + Page + * see struct scsi_mode_parameter_header * struct mode_pages */ @@ -649,8 +649,8 @@ typedef struct scsi_start_scan_cmd SANE_Byte byte1; /* 7-5:LUN; 4-0:Reserved */ SANE_Byte page_code; SANE_Byte reserved; - SANE_Byte len; /* Transfer Length - * Length of Window List in bytes + SANE_Byte len; /* Transfer Length + * Length of Window List in bytes * Since scanner supports up to 2 windows, len is 1 or 2 */ SANE_Byte control; /* 7-6:Vendor Unique; 5-2:Reserved; 1:Flag; 0:Link */ @@ -847,7 +847,7 @@ struct window_section * Transfer length indicates the byte length of Window Parameters (Set Window Data Header + * Window Descriptor Bytes transferred from the initiator in the DATA OUT PHASE * The scanner supports 2 windows, so Transfer Length is 648 bytes: - * Set Window Header 8 bytes + Window Descriptor Bytes 640 (320*2) bytes). + * Set Window Header 8 bytes + Window Descriptor Bytes 640 (320*2) bytes). * If data length is longer than 648 bytes only the first 648 bytes are valid, The remainng data is ignored. * If data length is shorter than 648 only the specified byte length is valid data. * @@ -874,19 +874,19 @@ struct hs2p_window_data SANE_Byte brightness; /* 22: Brightness [0-255] dark-light 0 means default value of 128 */ SANE_Byte threshold; /* 23: Threshold [0-255] 0 means default value of 128 */ SANE_Byte contrast; /* 24: Contrast [0-255] low-high 0 means default value of 128 */ - SANE_Byte image_composition; /* 25: Image Composition + SANE_Byte image_composition; /* 25: Image Composition * 00H Lineart * 01H Dithered Halftone * 02H Gray scale */ SANE_Byte bpp; /* 26: Bits Per Pixel */ - SANE_Byte halftone_code; /* 27: Halftone Code + SANE_Byte halftone_code; /* 27: Halftone Code * 00H-01H Reserved * 02H Dither (partial Dot) * 03H Error Diffusion * 04H-07H Reserved */ - SANE_Byte halftone_id; /* 28: Halftone ID + SANE_Byte halftone_id; /* 28: Halftone ID * 00H Reserved * 01H 8x4, 45 degree * 02H 6x6, 90 degree @@ -907,7 +907,7 @@ struct hs2p_window_data * Image Composition field must be lineart or dithered halftone * RIF=0: White=0 Black=1 * RIF=1: White=1 Black=0 - * 6-3: Reserved; + * 6-3: Reserved; * 2-0: Padding Type: * 00H Reserved * 01H Pad with 0's to byte boundary @@ -940,7 +940,7 @@ struct hs2p_window_data * 100 Reserved * 110 Reserved * 111 Reserved - * 3-0: Gamma ID + * 3-0: Gamma ID * 00H Normal * 01H Soft * 02H Sharp @@ -951,7 +951,7 @@ struct hs2p_window_data */ SANE_Byte ignored3; /* 43: Ignored */ SANE_Byte ignored4; /* 44: Ignored */ - SANE_Byte binary_filtering; /* 45: Binary Filtering + SANE_Byte binary_filtering; /* 45: Binary Filtering * 0-1: Noise Removal Matrix: * 00: 3x3 * 01: 4x4 @@ -965,14 +965,14 @@ struct hs2p_window_data * Setting is ignored for reverse side because optional IPU is not valid * for reverse side scanning */ - /* + /* * The following is only available when IPU is installed: * SECTION, Automatic Separation, Automatic Binarization - * 46-319 is ignored for Window 2 + * 46-319 is ignored for Window 2 */ SANE_Byte ignored5; /* 46: Ignored */ SANE_Byte ignored6; /* 47: Ignored */ - SANE_Byte automatic_separation; /* 48: Automatic Separation + SANE_Byte automatic_separation; /* 48: Automatic Separation * 00H OFF * 01H Default * 02H-7FH Reserved @@ -980,7 +980,7 @@ struct hs2p_window_data * 91H-FFH Reserved */ SANE_Byte ignored7; /* 49: Ignored */ - SANE_Byte automatic_binarization; /* 50: Automatic Binarization + SANE_Byte automatic_binarization; /* 50: Automatic Binarization * 00H OFF * 01H Default * 02H Enhancement of light characters @@ -992,8 +992,8 @@ struct hs2p_window_data SANE_Byte ignored8[13]; /* 51-63: Ignored */ struct window_section sec[8]; /* Each window can have multiple sections, each of 32 bytes long * 53-319: = 256 bytes = 8 sections of 32 bytes - * IS450 supports up to 4 sections, - * IS420 supports up to 6 sections + * IS450 supports up to 4 sections, + * IS420 supports up to 6 sections */ }; struct set_window_cmd @@ -1031,7 +1031,7 @@ struct get_window_cmd SANE_Byte control; /* 7-6:Vendor Unique; 5-2:Reserved; 1:Flag; 0:Link */ }; /* The data format to be returned is Get Window Data header + Window Descriptor Bytes - * The format of Window Descriptor Bytes is the same as that for SET WINDOW + * The format of Window Descriptor Bytes is the same as that for SET WINDOW */ struct get_window_data_hdr { @@ -1149,9 +1149,9 @@ typedef struct maintenance_data SANE_Byte reserved2; SANE_Byte zero[2]; /* All set as 0 */ } MAINTENANCE_DATA; -/* ADF status 1byte: - * 7-3:Reserved; - * 2:Reserved; +/* ADF status 1byte: + * 7-3:Reserved; + * 2:Reserved; * 1: '0'-ADF cover closed; '1'-ADF cover open * 0: '0'-Document on ADF; '1'-No document on ADF * @@ -1164,7 +1164,7 @@ struct IPU }; struct IPU_Auto_PhotoLetter { - /* Halftone Separations for each level + /* Halftone Separations for each level * 256 steps of relative value with 0 the sharpest and 255 the softest * The relation of strength is Strength2 > Strength3 > Strength4 ... */ @@ -1173,7 +1173,7 @@ struct IPU_Auto_PhotoLetter SANE_Byte level[6]; } halftone_separation[2]; - /* 7-2:Reversed 1-0:Halftone + /* 7-2:Reversed 1-0:Halftone * 00 Default * 01 Peak Detection Soft * 10 Peak Detection Sharp @@ -1198,40 +1198,40 @@ struct IPU_Auto_PhotoLetter */ SANE_Byte byte24; - /* 7-4:Filter A; 3-0:Filter B + /* 7-4:Filter A; 3-0:Filter B * FilterA: 16 types are valid from 0000 to 1111 * FilterB: 0000 to 1110 are valid; 1111 is not valid */ SANE_Byte MTF_correction; - /* 7-4:Filter A; 3-0:Filter B + /* 7-4:Filter A; 3-0:Filter B * 0000(soft) to 0111(sharp) are valid; 1000 to 1111 are invalid */ SANE_Byte MTF_strength; - /* 7-4:Filter A; 3-0:Filter B + /* 7-4:Filter A; 3-0:Filter B * slightly adjusts the strength of the filters */ SANE_Byte MTF_adjustment; - /* 7-4:Reserved; 3-0: smoothing filter select + /* 7-4:Reserved; 3-0: smoothing filter select * 14 kinds are valid from 0000 to 1101; 1110 to 1111 are invalid */ SANE_Byte smoothing; - /* 7-2:Reversed; 1-0: Filter Select + /* 7-2:Reversed; 1-0: Filter Select * 10 MTF Correction Select * 11 Smoothing Select * from 00 to 01 are not valid and basically it is set as 10 */ SANE_Byte byte29; - /* 7-4:Reserved; 3-0: MTF Correction Filter C + /* 7-4:Reserved; 3-0: MTF Correction Filter C * 16 kinds are valid from 0000 to 1111 */ SANE_Byte MTF_correction_c; - /* 7-3:Reserved; 2-0: MTF Correction Filter strength C + /* 7-3:Reserved; 2-0: MTF Correction Filter strength C * 000(soft) to 111(sharp) are valid */ SANE_Byte MTF_strength_c; diff --git a/backend/hs2p.c b/backend/hs2p.c index de3be42..deee3b0 100644 --- a/backend/hs2p.c +++ b/backend/hs2p.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2007 Jeremy Johnson - This file is part of a SANE backend for Ricoh IS450 + This file is part of a SANE backend for Ricoh IS450 and IS420 family of HS2P Scanners using the SCSI controller. This file is part of the SANE package. @@ -217,8 +217,8 @@ init_options (HS2P_Scanner * s) s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; - /* - * "Scan Mode" GROUP: + /* + * "Scan Mode" GROUP: */ s->opt[OPT_MODE_GROUP].name = ""; s->opt[OPT_MODE_GROUP].title = SANE_TITLE_SCAN_MODE_GROUP; @@ -311,8 +311,8 @@ init_options (HS2P_Scanner * s) - /* - * "Geometry" GROUP: + /* + * "Geometry" GROUP: */ s->opt[OPT_GEOMETRY_GROUP].name = ""; s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY_GROUP; @@ -419,8 +419,8 @@ init_options (HS2P_Scanner * s) - /* - * "Feeder" GROUP: + /* + * "Feeder" GROUP: */ s->opt[OPT_FEEDER_GROUP].name = ""; s->opt[OPT_FEEDER_GROUP].title = SANE_TITLE_FEEDER_GROUP; @@ -493,8 +493,8 @@ init_options (HS2P_Scanner * s) /* timeout ADF */ /* timeout Manual */ - /* - * "Enhancement" GROUP: + /* + * "Enhancement" GROUP: */ s->opt[OPT_ENHANCEMENT_GROUP].name = ""; s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_TITLE_ENHANCEMENT_GROUP; @@ -684,7 +684,7 @@ init_options (HS2P_Scanner * s) if (!s->hw->info.hasIPU) s->opt[OPT_AUTOBIN].cap |= SANE_CAP_INACTIVE; - /* SECTION + /* SECTION * The IS450 supports up to 4 Section; The IS420 supports up to 6 Sections * For each struct window_section[i] we need to fill in ulx,uly,width,height,etc * NOT YET IMPLEMENTED @@ -708,8 +708,8 @@ init_options (HS2P_Scanner * s) s->opt[OPT_WHITE_BALANCE].constraint_type = SANE_CONSTRAINT_NONE; s->val[OPT_WHITE_BALANCE].w = SANE_FALSE; /* F/T = Relative/Absolute White */ - /* - * "Miscellaneous" GROUP: + /* + * "Miscellaneous" GROUP: */ s->opt[OPT_MISCELLANEOUS_GROUP].name = ""; s->opt[OPT_MISCELLANEOUS_GROUP].title = SANE_TITLE_MISCELLANEOUS_GROUP; @@ -1192,7 +1192,7 @@ attach (SANE_String_Const devname, int __sane_unused__ connType, /* ipu_id: Bit0: '0'-no IPU, '1'-has IPU * Bit1: '0'-no extended board, '1'-has extended board; - * should always be 0 + * should always be 0 */ dev->info.hasIPU = (vbuf.ipu_id & 0x01) == 0x01 ? SANE_TRUE : SANE_FALSE; dev->info.hasXBD = (vbuf.ipu_id & 0x02) == 0x02 ? SANE_TRUE : SANE_FALSE; @@ -1229,8 +1229,8 @@ attach (SANE_String_Const devname, int __sane_unused__ connType, dev->sane.type = strdup (device_string); /* ACE Image Data Processing Binary Filters - * For IS450 this is set to 0x18 (0001 1000) if IPU installed, else 0x00 - * For IS420 this is set to 0x3C (0011 1100) if IPU installed, else 0x00 + * For IS450 this is set to 0x18 (0001 1000) if IPU installed, else 0x00 + * For IS420 this is set to 0x3C (0011 1100) if IPU installed, else 0x00 */ dev->info.supports_whiteframing = ((vbuf.imagedataprocessing[0] & 0x01) == 0x01) ? SANE_TRUE : SANE_FALSE; @@ -1272,16 +1272,16 @@ attach (SANE_String_Const devname, int __sane_unused__ connType, dev->info.supports_markerrecognition = ((vbuf.markerrecognition & 0x01) == 0x01) ? SANE_TRUE : SANE_FALSE; - /* Size Recognition + /* Size Recognition * For IS450 this is set to 0x01 when IPU installed; else 0x00 - * For IS420 this is set to 0x01 + * For IS420 this is set to 0x01 */ dev->info.supports_sizerecognition = ((vbuf.sizerecognition & 0x01) == 0x01) ? SANE_TRUE : SANE_FALSE; - /* X Maximum Output Pixel in main scanning direction - * For IS450 this is set to 0x1360 (4960) - * For IS420 this is set to (4880) + /* X Maximum Output Pixel in main scanning direction + * For IS450 this is set to 0x1360 (4960) + * For IS420 this is set to (4880) * [MostSignificantByte LeastSignificantByte] */ dev->info.xmaxoutputpixels = @@ -2397,7 +2397,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, return SANE_STATUS_GOOD; case OPT_SCAN_SOURCE: /* a string option */ - /* Since the scanner ejects the sheet in ADF mode + /* Since the scanner ejects the sheet in ADF mode * it is impossible to scan multiple sections in one document * In ADF mode, because of mechanical limitations: * the minimum document size is (x,y)=(69mm x 120mm) @@ -2824,7 +2824,7 @@ set_window_data (HS2P_Scanner * s, SWD * wbuf) (paddingtype[get_paddingtype_id (s->val[OPT_PADDING_TYPE].s)]. val & 0x07); - /* Bit Ordering: + /* Bit Ordering: * Manual Says DEFAULT: [1111 1111][1111 1000] * Bits15-8 reserved; * Bit7: '0'-Normal '1'-Mirroring @@ -2877,7 +2877,7 @@ set_window_data (HS2P_Scanner * s, SWD * wbuf) data->automatic_binarization = get_auto_binarization_val (s->val[OPT_AUTOBIN].s); /* fill in values for each section - for(j=0; jEOM = SANE_TRUE; - /* + /* * If status != SANE_STATUS_GOOD, then sense_handler() has already * been called and the sanei_* functions have already gotten the * sense data buffer (which apparently clears the error conditionn) @@ -3283,7 +3283,7 @@ sane_cancel (SANE_Handle handle) DBG (DBG_proc, ">> sane_cancel\n"); if (s->scanning) - { /* if batchmode is enabled, then call set_window to abort the batch + { /* if batchmode is enabled, then call set_window to abort the batch if (_OPT_VAL_WORD(s, OPT_BATCH) == SANE_TRUE) { DBG(5, "sane_cancel: calling set_window to abort batch\n"); set_window(s, BH_BATCH_ABORT); diff --git a/backend/hs2p.h b/backend/hs2p.h index 091fce2..6270154 100644 --- a/backend/hs2p.h +++ b/backend/hs2p.h @@ -2,7 +2,7 @@ Copyright (C) 2007 Jeremy Johnson This file is part of a SANE backend for Ricoh IS450 and IS420 family of HS2P Scanners using the SCSI controller. - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -117,8 +117,8 @@ typedef struct char inquiry_data[256]; - SANE_Byte max_win_sections; /* Number of supported window subsections - IS450 supports max of 4 sections + SANE_Byte max_win_sections; /* Number of supported window subsections + IS450 supports max of 4 sections IS420 supports max of 6 sections */ @@ -239,7 +239,7 @@ typedef struct HS2P_Device struct HS2P_Device *next; /* * struct with pointers to device/vendor/model names, and a type value - * used to inform sane frontend about the device + * used to inform sane frontend about the device */ SANE_Device sane; HS2P_Info info; diff --git a/backend/ibm-scsi.c b/backend/ibm-scsi.c index 59b42cb..b6436bd 100644 --- a/backend/ibm-scsi.c +++ b/backend/ibm-scsi.c @@ -1,5 +1,5 @@ /* sane - Scanner Access Now Easy. - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -38,7 +38,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. */ -/* +/* */ #include @@ -62,7 +62,7 @@ /* for object_position command */ #define OBJECT_POSITION_UNLOAD 0 #define OBJECT_POSITION_LOAD 1 - + struct scsi_window_cmd { SANE_Byte opcode; SANE_Byte byte2; @@ -162,7 +162,7 @@ inquiry (int fd, void *buf, size_t * buf_size) memset (cmd, 0, sizeof (cmd)); cmd[0] = IBM_SCSI_INQUIRY; - cmd[4] = *buf_size; + cmd[4] = *buf_size; status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), buf, buf_size); DBG (11, "<< inquiry\n"); @@ -266,7 +266,7 @@ set_window (int fd, struct ibm_window_data *iwd) static SANE_Status get_window (int fd, struct ibm_window_data *iwd) { - + static struct scsi_window_cmd cmd; static size_t iwd_size; SANE_Status status; @@ -343,7 +343,7 @@ get_data_status (int fd, struct scsi_status_desc *dbs) status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), &ssd, &ssd_size); memcpy (dbs, &ssd.desc, sizeof(*dbs)); - if (status == SANE_STATUS_GOOD && + if (status == SANE_STATUS_GOOD && ((unsigned int) _3btol(ssd.len) <= sizeof(*dbs) || _3btol(ssd.desc.filled) == 0)) { DBG (11, "get_data_status: busy\n"); status = SANE_STATUS_DEVICE_BUSY; diff --git a/backend/ibm.c b/backend/ibm.c index 3ab7890..e527a04 100644 --- a/backend/ibm.c +++ b/backend/ibm.c @@ -1,5 +1,5 @@ /* sane - Scanner Access Now Easy. - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -157,12 +157,12 @@ attach (const char *devnam, Ibm_Device ** devp) if (!( (strncmp ((char *)ibuf.vendor, "IBM", 3) ==0 && strncmp ((char *)ibuf.product, "2456", 4) == 0) - || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 - && strncmp ((char *)ibuf.product, "IS420", 5) == 0) - || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 - && strncmp ((char *)ibuf.product, "IS410", 5) == 0) - || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 - && strncmp ((char *)ibuf.product, "IS430", 5) == 0) + || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 + && strncmp ((char *)ibuf.product, "IS420", 5) == 0) + || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 + && strncmp ((char *)ibuf.product, "IS410", 5) == 0) + || (strncmp ((char *)ibuf.vendor, "RICOH", 5) == 0 + && strncmp ((char *)ibuf.product, "IS430", 5) == 0) )) { DBG (1, "attach: device \"%s\" doesn't look like a scanner I know\n", @@ -213,7 +213,7 @@ attach (const char *devnam, Ibm_Device ** devp) DBG (1, "attach: MODE_SELECT failed\n"); sanei_scsi_close (fd); return (SANE_STATUS_INVAL); - } + } #endif #if 0 @@ -286,13 +286,13 @@ attach (const char *devnam, Ibm_Device ** devp) dev->info.brightness_default = wbuf.brightness; dev->info.contrast_default = wbuf.contrast; } - + /* da rivedere dev->info.adf_default = wbuf.adf_state; */ dev->info.adf_default = ADF_UNUSED; dev->info.adf_default = IBM_PAPER_USER_DEFINED; - + #if 1 dev->info.bmu = mup.bmu; dev->info.mud = _2btol(mup.mud); @@ -324,7 +324,7 @@ attach (const char *devnam, Ibm_Device ** devp) DBG (5, "brightness=%d\n", dev->info.brightness_default); DBG (5, "contrast=%d\n", dev->info.contrast_default); - + DBG (5, "adf_state=%d\n", dev->info.adf_default); DBG (5, "bmu=%d\n", dev->info.bmu); @@ -411,7 +411,7 @@ init_options (Ibm_Scanner * s) s->opt[OPT_Y_RESOLUTION].constraint_type = SANE_CONSTRAINT_RANGE; s->val[OPT_Y_RESOLUTION].w = s->hw->info.yres_default; s->opt[OPT_Y_RESOLUTION].constraint.range = &ibm2456_res_range; - + /* adf */ s->opt[OPT_ADF].name = "adf"; s->opt[OPT_ADF].title = "Use ADF"; @@ -437,7 +437,7 @@ init_options (Ibm_Scanner * s) s->opt[OPT_PAPER].constraint_type = SANE_CONSTRAINT_STRING_LIST; s->opt[OPT_PAPER].constraint.string_list = paper_list; s->val[OPT_PAPER].s = strdup (paper_list[s->hw->info.paper_default]); - + /* top-left x */ s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; @@ -563,7 +563,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) if (line[0] == '#') /* ignore line comments */ continue; len = strlen (line); - + if (!len) continue; /* ignore empty lines */ @@ -734,7 +734,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_CONTRAST: *(SANE_Word *) val = s->val[option].w; return (SANE_STATUS_GOOD); - + /* bool options: */ case OPT_ADF: *(SANE_Bool *) val = s->val[option].b; @@ -767,7 +767,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *info |= SANE_INFO_RELOAD_PARAMS; s->val[option].w = *(SANE_Word *) val; return (SANE_STATUS_GOOD); - + case OPT_TL_X: case OPT_TL_Y: case OPT_BR_X: @@ -785,7 +785,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->val[OPT_PAPER].s = strdup (paper_list[IBM_PAPER_USER_DEFINED]); } return (SANE_STATUS_GOOD); - + case OPT_NUM_OPTS: case OPT_BRIGHTNESS: case OPT_CONTRAST: @@ -799,15 +799,15 @@ sane_control_option (SANE_Handle handle, SANE_Int option, free (s->val[option].s); s->val[option].s = strdup (val); return (SANE_STATUS_GOOD); - + case OPT_ADF: s->val[option].b = *(SANE_Bool *) val; if (*(SANE_Bool *) val) s->adf_state = ADF_ARMED; - else + else s->adf_state = ADF_UNUSED; return (SANE_STATUS_GOOD); - + case OPT_PAPER: if (info && strcmp (s->val[option].s, (SANE_String) val)) *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; @@ -957,7 +957,7 @@ sane_start (SANE_Handle handle) s->hw->sane.name, sane_strstatus (status)); return (status); } - + mode_str = s->val[OPT_MODE].s; s->xres = s->val[OPT_X_RESOLUTION].w; s->yres = s->val[OPT_Y_RESOLUTION].w; @@ -968,7 +968,7 @@ sane_start (SANE_Handle handle) s->brightness = s->val[OPT_BRIGHTNESS].w; s->contrast = s->val[OPT_CONTRAST].w; s->bpp = s->params.depth; - if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_LINEART) == 0) + if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_LINEART) == 0) { s->image_composition = IBM_BINARY_MONOCHROME; } @@ -996,11 +996,11 @@ sane_start (SANE_Handle handle) wbuf.image_comp = s->image_composition; /* if you throw the MRIF bit the brighness control reverses too */ /* so I reverse the reversal in software for symmetry's sake */ - if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME) + if (wbuf.image_comp == IBM_GRAYSCALE || wbuf.image_comp == IBM_DITHERED_MONOCHROME) { - if (wbuf.image_comp == IBM_GRAYSCALE) + if (wbuf.image_comp == IBM_GRAYSCALE) wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x80; /* it was 0x90 */ - if (wbuf.image_comp == IBM_DITHERED_MONOCHROME) + if (wbuf.image_comp == IBM_DITHERED_MONOCHROME) wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x10; wbuf.brightness = 256 - (SANE_Byte) s->brightness; /* @@ -1048,7 +1048,7 @@ sane_start (SANE_Handle handle) if (status != SANE_STATUS_GOOD) { DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status)); - return (status); + return (status); } DBG (5, "xres=%d\n", _2btol(wbuf.x_res)); DBG (5, "yres=%d\n", _2btol(wbuf.y_res)); @@ -1073,7 +1073,7 @@ sane_start (SANE_Handle handle) else mup.adf_control = 0; /* end lines by mf */ - + status = mode_select (s->fd, (struct mode_pages *) &mup); if (status != SANE_STATUS_GOOD) { @@ -1096,18 +1096,18 @@ sane_start (SANE_Handle handle) { DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status)); return (status); - } + } s->bytes_to_read = s->params.bytes_per_line * s->params.lines; DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, " "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line, s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_Y_RESOLUTION].w); - + s->scanning = SANE_TRUE; - DBG (11, "<< sane_start\n"); - return (SANE_STATUS_GOOD); + DBG (11, "<< sane_start\n"); + return (SANE_STATUS_GOOD); } SANE_Status @@ -1122,7 +1122,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, *len = 0; DBG (11, "sane_read: bytes left to read: %ld\n", (u_long) s->bytes_to_read); - + if (s->bytes_to_read == 0) { do_cancel (s); @@ -1132,7 +1132,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, if (!s->scanning) { DBG (11, "sane_read: scanning is false!\n"); return (do_cancel (s)); - } + } nread = max_len; if (nread > s->bytes_to_read) diff --git a/backend/ibm.h b/backend/ibm.h index a10c923..742ebeb 100644 --- a/backend/ibm.h +++ b/backend/ibm.h @@ -1,5 +1,5 @@ /* sane - Scanner Access Now Easy. - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -154,7 +154,7 @@ static const SANE_Range default_y_range = static inline void _lto2b(SANE_Int val, SANE_Byte *bytes) - + { bytes[0] = (val >> 8) & 0xff; @@ -163,7 +163,7 @@ _lto2b(SANE_Int val, SANE_Byte *bytes) static inline void _lto3b(SANE_Int val, SANE_Byte *bytes) - + { bytes[0] = (val >> 16) & 0xff; @@ -214,7 +214,7 @@ _4btol(SANE_Byte *bytes) return (rv); } -typedef enum +typedef enum { OPT_NUM_OPTS = 0, @@ -374,7 +374,7 @@ struct measurements_units_page { }; struct mode_pages { - SANE_Byte page_code; + SANE_Byte page_code; SANE_Byte parameter_length; SANE_Byte rest[14]; /* modified by mf; it was 6; see above */ #if 0 diff --git a/backend/kodak-cmd.h b/backend/kodak-cmd.h index 9f9880e..995d622 100644 --- a/backend/kodak-cmd.h +++ b/backend/kodak-cmd.h @@ -1,9 +1,9 @@ #ifndef KODAK_CMD_H #define KODAK_CMD_H -/* +/* * Part of SANE - Scanner Access Now Easy. - * + * * Please see to opening comments in kodak.c */ @@ -27,7 +27,7 @@ getnbyte (unsigned char *pnt, int nbytes) { unsigned int result = 0; int i; - + for (i = 0; i < nbytes; i++) result = (result << 8) | (pnt[i] & 0xff); return result; @@ -37,7 +37,7 @@ static void putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) { int i; - + for (i = nbytes - 1; i >= 0; i--) { pnt[i] = value & 0xff; value = value >> 8; @@ -398,7 +398,7 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) /* output */ #define set_SR_datatype_code(sb, val) sb[0x02] = val #define SR_datatype_imagedata 0x00 -#define SR_datatype_random 0x80 +#define SR_datatype_random 0x80 #define SR_datatype_imageheader 0x81 #define SR_len_imageheader 1088 @@ -416,11 +416,11 @@ putnbyte (unsigned char *pnt, unsigned int value, unsigned int nbytes) #define get_SR_ih_length(in) getnbyte(in + 23, 4) #define get_SR_ih_bpp(in) in[27] #define get_SR_ih_comp_type(in) in[28] -#define get_SR_ih_ACD(in) getbit(in + 29, 1, 5) -#define get_SR_ih_MF(in) getbit(in + 29, 1, 4) -#define get_SR_ih_RIF(in) getbit(in + 29, 1, 2) -#define get_SR_ih_ID(in) getbit(in + 29, 1, 1) -#define get_SR_ih_DE(in) getbit(in + 29, 1, 0) +#define get_SR_ih_ACD(in) getbit(in + 29, 1, 5) +#define get_SR_ih_MF(in) getbit(in + 29, 1, 4) +#define get_SR_ih_RIF(in) getbit(in + 29, 1, 2) +#define get_SR_ih_ID(in) getbit(in + 29, 1, 1) +#define get_SR_ih_DE(in) getbit(in + 29, 1, 0) #define get_SR_ih_skew_angle(in) getnbyte(in + 30, 2) #define get_SR_ih_ia_level(in) in[32] #define get_SR_ih_ia(in) getnbyte(in + 33, 60) diff --git a/backend/kodak.c b/backend/kodak.c index 73243db..845ad11 100644 --- a/backend/kodak.c +++ b/backend/kodak.c @@ -83,7 +83,7 @@ . . - sane_start() : start image acquisition . . - sane_get_parameters() : returns actual scan parameters . . - sane_read() : read image data (from pipe) - . . (sane_read called multiple times; after sane_read returns EOF, + . . (sane_read called multiple times; after sane_read returns EOF, . . loop may continue with sane_start which may return a 2nd page . . when doing duplex scans, or load the next page from the ADF) . . @@ -124,14 +124,14 @@ #include "kodak.h" #define DEBUG 1 -#define BUILD 7 +#define BUILD 7 /* values for SANE_DEBUG_KODAK env var: - errors 5 - function trace 10 - function detail 15 - get/setopt cmds 20 - - scsi cmd trace 25 + - scsi cmd trace 25 - scsi cmd detail 30 - useless noise 35 */ @@ -163,7 +163,7 @@ static struct scanner *scanner_devList = NULL; /* * Called by SANE initially. - * + * * From the SANE spec: * This function must be called before any other SANE function can be * called. The behavior of a SANE backend is undefined if this @@ -195,7 +195,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /* * Called by SANE to find out about supported devices. - * + * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a @@ -208,7 +208,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. - * + * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and @@ -241,41 +241,41 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) DBG (15, "sane_get_devices: reading config file %s\n", KODAK_CONFIG_FILE); while (sanei_config_read (line, PATH_MAX, fp)) { - + lp = line; - + /* ignore comments */ if (*lp == '#') continue; - + /* skip empty lines */ if (*lp == 0) continue; - + if ((strncmp ("option", lp, 6) == 0) && isspace (lp[6])) { - + lp += 6; lp = sanei_config_skip_whitespace (lp); - + /* we allow setting buffersize too big */ if ((strncmp (lp, "buffer-size", 11) == 0) && isspace (lp[11])) { - + int buf; lp += 11; lp = sanei_config_skip_whitespace (lp); buf = atoi (lp); - + if (buf < 4096) { DBG (5, "sane_get_devices: config option \"buffer-size\" \ (%d) is < 4096, ignoring!\n", buf); continue; } - + if (buf > DEFAULT_BUFFER_SIZE) { DBG (5, "sane_get_devices: config option \"buffer-size\" \ (%d) is > %d, warning!\n", buf, DEFAULT_BUFFER_SIZE); } - + DBG (15, "sane_get_devices: setting \"buffer-size\" to %d\n", buf); global_buffer_size = buf; @@ -330,8 +330,8 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) return SANE_STATUS_GOOD; } -/* build the scanner struct and link to global list - * unless struct is already loaded, then pretend +/* build the scanner struct and link to global list + * unless struct is already loaded, then pretend */ static SANE_Status attach_one (const char *device_name) @@ -485,9 +485,9 @@ init_inquire (struct scanner *s) set_I_evpd (cmd, 0); set_I_page_code (cmd, I_page_code_default); set_I_data_length (cmd, inLen); - + ret = do_cmd ( - s, 1, 0, + s, 1, 0, cmd, cmdLen, NULL, 0, in, &inLen @@ -648,7 +648,7 @@ init_model (struct scanner *s) s->s_mode[MODE_HALFTONE] = 1; s->s_mode[MODE_GRAYSCALE] = 1; s->s_mode[MODE_COLOR] = 1; - + /* scanner did not tell us these */ s->s_res_min[MODE_HALFTONE] = s->s_res_min[MODE_LINEART]; s->s_res_max[MODE_HALFTONE] = s->s_res_max[MODE_LINEART]; @@ -728,9 +728,9 @@ init_options (struct scanner *s) s->opt[i].cap = SANE_CAP_INACTIVE; } - /* go ahead and setup the first opt, because - * frontend may call control_option on it - * before calling get_option_descriptor + /* go ahead and setup the first opt, because + * frontend may call control_option on it + * before calling get_option_descriptor */ s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; @@ -765,7 +765,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) time_t gmt_tt; struct tm * gmt_tm_p; struct tm * local_tm_p; - + DBG (10, "sane_open: start\n"); if(scanner_devList){ @@ -786,7 +786,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) } else{ DBG (15, "sane_open: device %s requested\n", name); - + for (dev = scanner_devList; dev; dev = dev->next) { if (strcmp (dev->sane.name, name) == 0) { s = dev; @@ -998,7 +998,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->o_mode_list[i++]=STRING_COLOR; } s->o_mode_list[i]=NULL; - + opt->name = SANE_NAME_SCAN_MODE; opt->title = SANE_TITLE_SCAN_MODE; opt->desc = SANE_DESC_SCAN_MODE; @@ -1017,13 +1017,13 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) i=0; for(j=0;j<6;j++){ - if(reslist[j] >= s->s_res_min[s->u_mode] + if(reslist[j] >= s->s_res_min[s->u_mode] && reslist[j] <= s->s_res_max[s->u_mode]){ s->o_res_list[s->u_mode][++i] = reslist[j]; } } s->o_res_list[s->u_mode][0] = i; - + opt->name = SANE_NAME_SCAN_RESOLUTION; opt->title = SANE_TITLE_SCAN_RESOLUTION; opt->desc = SANE_DESC_SCAN_RESOLUTION; @@ -1049,7 +1049,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->o_tl_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->s_width_min); s->o_tl_x_range.max = SCANNER_UNIT_TO_FIXED_MM(s->s_width_max); s->o_tl_x_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_TL_X; opt->title = SANE_TITLE_SCAN_TL_X; opt->desc = SANE_DESC_SCAN_TL_X; @@ -1067,7 +1067,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->o_tl_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->s_length_min); s->o_tl_y_range.max = SCANNER_UNIT_TO_FIXED_MM(s->s_length_max); s->o_tl_y_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_TL_Y; opt->title = SANE_TITLE_SCAN_TL_Y; opt->desc = SANE_DESC_SCAN_TL_Y; @@ -1085,7 +1085,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->o_br_x_range.min = SCANNER_UNIT_TO_FIXED_MM(s->s_width_min); s->o_br_x_range.max = SCANNER_UNIT_TO_FIXED_MM(s->s_width_max); s->o_br_x_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_BR_X; opt->title = SANE_TITLE_SCAN_BR_X; opt->desc = SANE_DESC_SCAN_BR_X; @@ -1103,7 +1103,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) s->o_br_y_range.min = SCANNER_UNIT_TO_FIXED_MM(s->s_length_min); s->o_br_y_range.max = SCANNER_UNIT_TO_FIXED_MM(s->s_length_max); s->o_br_y_range.quant = MM_PER_UNIT_FIX; - + opt->name = SANE_NAME_SCAN_BR_Y; opt->title = SANE_TITLE_SCAN_BR_Y; opt->desc = SANE_DESC_SCAN_BR_Y; @@ -1236,7 +1236,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /** * Gets or sets an option value. - * + * * From the SANE spec: * This function is used to set or inquire the current value of option * number n of the device represented by handle h. The manner in which @@ -1247,7 +1247,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) * area pointed to by v must be big enough to hold the entire option * value (determined by member size in the corresponding option * descriptor). - * + * * The only exception to this rule is that when setting the value of a * string option, the string pointed to by argument v may be shorter * since the backend will stop reading the option value upon @@ -1304,7 +1304,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, strcpy (val, STRING_ADFDUPLEX); } else{ - DBG(5,"missing option val for source\n"); + DBG(5,"missing option val for source\n"); } return SANE_STATUS_GOOD; @@ -1402,7 +1402,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, * below. */ switch (option) { - + /* Mode Group */ case OPT_SOURCE: if (!strcmp (val, STRING_ADFFRONT)) { @@ -1537,7 +1537,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, * completion of that request. Outside of that window, the returned * values are best-effort estimates of what the parameters will be * when sane_start() gets invoked. - * + * * Calling this function before a scan has actually started allows, * for example, to get an estimate of how big the scanned image will * be. The parameters passed to this function are the handle h of the @@ -1557,9 +1557,9 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) { SANE_Status ret = SANE_STATUS_GOOD; struct scanner *s = (struct scanner *) handle; - + DBG (10, "sane_get_parameters: start\n"); - + /* started? get param data from image header */ if(s->started){ DBG (15, "sane_get_parameters: image settings:\n"); @@ -1574,7 +1574,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) params->last_frame = 1; params->lines = s->i_length; params->pixels_per_line = s->i_width; - + /* bitonal */ if (s->i_bpp == 1) { params->format = SANE_FRAME_GRAY; @@ -1632,7 +1632,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) DBG (15, " res=%d, user_x=%d, user_y=%d\n", s->u_res, (s->u_res * (s->u_br_x - s->u_tl_x) / 1200), (s->u_res * (s->u_br_y - s->u_tl_y) / 1200)); - + if (s->u_mode == MODE_COLOR) { params->format = SANE_FRAME_RGB; params->depth = 8; @@ -1649,7 +1649,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) params->last_frame = 1; params->lines = s->u_res * (s->u_br_y - s->u_tl_y) / 1200; params->pixels_per_line = s->u_res * (s->u_br_x - s->u_tl_x) / 1200; - + /* bytes per line differs by mode */ if (s->u_mode == MODE_COLOR) { params->bytes_per_line = params->pixels_per_line * 3; @@ -1662,16 +1662,16 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) } } - + DBG (15, "sane_get_parameters: returning:\n"); - DBG (15, " scan_x=%d, Bpl=%d, depth=%d\n", + DBG (15, " scan_x=%d, Bpl=%d, depth=%d\n", params->pixels_per_line, params->bytes_per_line, params->depth ); - - DBG (15, " scan_y=%d, frame=%d, last=%d\n", + + DBG (15, " scan_y=%d, frame=%d, last=%d\n", params->lines, params->format, params->last_frame ); DBG (10, "sane_get_parameters: finish\n"); - + return ret; } @@ -1680,7 +1680,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) * commands: scanner control (lampon), send (lut), send (dither), * set window, object pos, and scan * - * this will be called before each image, including duplex backsides, + * this will be called before each image, including duplex backsides, * and at the start of adf batch. * hence, we spend alot of time playing with s->started, etc. */ @@ -1716,7 +1716,7 @@ sane_start (SANE_Handle handle) do_cancel(s); return ret; } - + /* read/send JQ command */ /* read/send SC command */ @@ -1726,13 +1726,13 @@ sane_start (SANE_Handle handle) do_cancel(s); return ret; } - + /* read/send CT command */ DBG (15, "sane_start: send SCAN\n"); memset(cmd, 0, SCAN_len); set_SCSI_opcode(cmd, SCAN_code); - + ret = do_cmd ( s, 1, 0, cmd, SCAN_len, @@ -1752,11 +1752,11 @@ sane_start (SANE_Handle handle) set_SR_datatype_code(cmd,SR_datatype_random); set_SR_datatype_qual(cmd,SR_qual_startstop); set_SR_xfer_length(cmd,SR_len_startstop); - + memset(pay,0,SR_len_startstop); set_SR_payload_len(pay,SR_len_startstop); set_SR_startstop_cmd(pay,1); - + ret = do_cmd ( s, 1, 0, cmd, SEND_len, @@ -1786,7 +1786,7 @@ sane_start (SANE_Handle handle) /* make large buffer to hold the images */ DBG (15, "sane_start: setup buffer\n"); - + /* free current buffer if too small */ if (s->buffer && s->bytes_buf < s->i_bytes) { DBG (15, "sane_start: free buffer.\n"); @@ -1794,7 +1794,7 @@ sane_start (SANE_Handle handle) s->buffer = NULL; s->bytes_buf = 0; } - + /* grab new buffer if dont have one */ if (!s->buffer) { DBG (15, "sane_start: calloc buffer.\n"); @@ -1827,7 +1827,7 @@ set_window (struct scanner *s) unsigned char cmd[SET_WINDOW_len]; size_t cmdLen = SET_WINDOW_len; - /* the data phase has a header, followed by a window desc block + /* the data phase has a header, followed by a window desc block * the header specifies the number of bytes in 1 window desc block */ unsigned char pay[WINDOW_HEADER_len + WINDOW_DESCRIPTOR_len]; size_t payLen = WINDOW_HEADER_len + WINDOW_DESCRIPTOR_len; @@ -2059,7 +2059,7 @@ send_sc(struct scanner *s) set_SR_datatype_code(cmd,SR_datatype_random); set_SR_datatype_qual(cmd,SR_qual_config); set_SR_xfer_length(cmd,SR_len_config); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, @@ -2077,7 +2077,7 @@ send_sc(struct scanner *s) set_SR_datatype_code(cmd,SR_datatype_random); set_SR_datatype_qual(cmd,SR_qual_config); set_SR_xfer_length(cmd,payLen); - + if(s->u_source == SOURCE_ADF_FRONT){ if(s->u_mode == MODE_COLOR || s->u_mode == MODE_GRAYSCALE){ set_SR_sc_io1(pay,SR_sc_io_front_color); @@ -2150,7 +2150,7 @@ read_imageheader (struct scanner *s) set_SR_xfer_length(cmd,SR_len_imageheader); while (pass++ < 1000){ - + DBG (15, "read_imageheader: pass %d\n", pass); payLen = SR_len_imageheader; @@ -2174,34 +2174,34 @@ read_imageheader (struct scanner *s) if (ret == SANE_STATUS_GOOD){ DBG (15, "image header:\n"); - + DBG (15, " bytes: %d\n",get_SR_ih_image_length(pay)); s->i_bytes = get_SR_ih_image_length(pay); - + DBG (15, " id: %d\n",get_SR_ih_image_id(pay)); s->i_id = get_SR_ih_image_id(pay); - + DBG (15, " dpi: %d\n",get_SR_ih_resolution(pay)); s->i_dpi = get_SR_ih_resolution(pay); - + DBG (15, " tlx: %d\n",get_SR_ih_ulx(pay)); s->i_tlx = get_SR_ih_ulx(pay); - + DBG (15, " tly: %d\n",get_SR_ih_uly(pay)); s->i_tly = get_SR_ih_uly(pay); - + DBG (15, " width: %d\n",get_SR_ih_width(pay)); s->i_width = get_SR_ih_width(pay); - + DBG (15, " length: %d\n",get_SR_ih_length(pay)); s->i_length = get_SR_ih_length(pay); - + DBG (15, " bpp: %d\n",get_SR_ih_bpp(pay)); s->i_bpp = get_SR_ih_bpp(pay); - + DBG (15, " comp: %d\n",get_SR_ih_comp_type(pay)); s->i_compr = get_SR_ih_comp_type(pay); - + /*FIXME: there are alot more of these?*/ } @@ -2212,7 +2212,7 @@ read_imageheader (struct scanner *s) /* * Called by SANE to read data. - * + * * From the SANE spec: * This function is used to read image data from the device * represented by handle h. Argument buf is a pointer to a memory @@ -2220,7 +2220,7 @@ read_imageheader (struct scanner *s) * returned is stored in *len. A backend must set this to zero when * the call fails (i.e., when a status other than SANE_STATUS_GOOD is * returned). - * + * * When the call succeeds, the number of bytes returned can be * anywhere in the range from 0 to maxlen bytes. */ @@ -2270,12 +2270,12 @@ read_from_scanner(struct scanner *s) int remain = s->i_bytes - s->bytes_rx; unsigned char * buf; size_t inLen = 0; - + unsigned char cmd[READ_len]; int cmdLen=READ_len; DBG (10, "read_from_scanner: start\n"); - + memset(cmd, 0, cmdLen); set_SCSI_opcode(cmd, READ_code); @@ -2283,32 +2283,32 @@ read_from_scanner(struct scanner *s) if(bytes > remain){ bytes = remain; } - + DBG(15, "read_from_scanner: to:%d rx:%d re:%d bu:%d pa:%d\n", s->i_bytes, s->bytes_rx, remain, s->buffer_size, bytes); - + if(ret){ return ret; } - + inLen = bytes; - + buf = malloc(bytes); if(!buf){ DBG(5, "read_from_scanner: not enough mem for buffer: %d\n",bytes); return SANE_STATUS_NO_MEM; } - + set_SR_datatype_code (cmd, SR_datatype_imagedata); set_SR_xfer_length (cmd, bytes); - + ret = do_cmd ( s, 1, 0, cmd, cmdLen, NULL, 0, buf, &inLen ); - + if (ret == SANE_STATUS_GOOD) { DBG(15, "read_from_scanner: got GOOD, returning GOOD\n"); } @@ -2324,13 +2324,13 @@ read_from_scanner(struct scanner *s) DBG(5, "read_from_scanner: error reading data block status = %d\n",ret); inLen = 0; } - + if(inLen){ copy_buffer (s, buf, inLen); } - + free(buf); - + if(ret == SANE_STATUS_EOF){ DBG (5, "read_from_scanner: unexpected EOF, shortening image\n"); s->i_bytes = s->bytes_rx; @@ -2338,7 +2338,7 @@ read_from_scanner(struct scanner *s) } DBG (10, "read_from_scanner: finish\n"); - + return ret; } @@ -2364,31 +2364,31 @@ read_from_buffer(struct scanner *s, SANE_Byte * buf, SANE_Status ret=SANE_STATUS_GOOD; int bytes = max_len; int remain = s->bytes_rx - s->bytes_tx; - + DBG (10, "read_from_buffer: start\n"); - + /* figure out the max amount to transfer */ if(bytes > remain){ bytes = remain; } - + *len = bytes; - + DBG(15, "read_from_buffer: to:%d tx:%d re:%d bu:%d pa:%d\n", s->i_bytes, s->bytes_tx, remain, max_len, bytes); - + /*FIXME this needs to timeout eventually */ if(!bytes){ DBG(5,"read_from_buffer: nothing to do\n"); return SANE_STATUS_GOOD; } - + memcpy(buf,s->buffer+s->bytes_tx,bytes); - + s->bytes_tx += *len; - + DBG (10, "read_from_buffer: finish\n"); - + return ret; } @@ -2397,26 +2397,26 @@ read_from_buffer(struct scanner *s, SANE_Byte * buf, * @@ Section 4 - SANE cleanup functions */ /* - * Cancels a scan. + * Cancels a scan. * * It has been said on the mailing list that sane_cancel is a bit of a * misnomer because it is routinely called to signal the end of a * batch - quoting David Mosberger-Tang: - * + * * > In other words, the idea is to have sane_start() be called, and * > collect as many images as the frontend wants (which could in turn * > consist of multiple frames each as indicated by frame-type) and - * > when the frontend is done, it should call sane_cancel(). + * > when the frontend is done, it should call sane_cancel(). * > Sometimes it's better to think of sane_cancel() as "sane_stop()" * > but that name would have had some misleading connotations as * > well, that's why we stuck with "cancel". - * + * * The current consensus regarding duplex and ADF scans seems to be * the following call sequence: sane_start; sane_read (repeat until * EOF); sane_start; sane_read... and then call sane_cancel if the * batch is at an end. I.e. do not call sane_cancel during the run but * as soon as you get a SANE_STATUS_NO_DOCS. - * + * * From the SANE spec: * This function is used to immediately or as quickly as possible * cancel the currently pending operation of the device represented by @@ -2459,7 +2459,7 @@ do_cancel (struct scanner *s) /* * Ends use of the scanner. - * + * * From the SANE spec: * This function terminates the association between the device handle * passed in argument h and the device it represents. If the device is @@ -2495,7 +2495,7 @@ disconnect_fd (struct scanner *s) /* * Terminates the backend. - * + * * From the SANE spec: * This function must be called to terminate use of a backend. The * function will first close all device handles that still might be @@ -2721,9 +2721,9 @@ do_rs(scanner * s) SANE_Status ret; unsigned char cmd[REQUEST_SENSE_len]; size_t cmdLen = REQUEST_SENSE_len; - + DBG (10, "do_rs: start\n"); - + memset(cmd,0,cmdLen); set_SCSI_opcode(cmd,REQUEST_SENSE_code); set_SR_datatype_code(cmd,SR_datatype_random); @@ -2792,7 +2792,7 @@ do_cmd(struct scanner *s, int runRS, int shortTime, #if 0 /* unused */ static SANE_Status -wait_scanner(struct scanner *s) +wait_scanner(struct scanner *s) { int ret; @@ -2810,7 +2810,7 @@ wait_scanner(struct scanner *s) NULL, 0, NULL, NULL ); - + if (ret != SANE_STATUS_GOOD) { DBG(5,"WARNING: Brain-dead scanner. Hitting with stick\n"); ret = do_cmd ( diff --git a/backend/kodak.h b/backend/kodak.h index ea2a3e4..31c5712 100644 --- a/backend/kodak.h +++ b/backend/kodak.h @@ -1,12 +1,12 @@ #ifndef KODAK_H #define KODAK_H -/* +/* * Part of SANE - Scanner Access Now Easy. * Please see opening comment in kodak.c */ -/* ------------------------------------------------------------------------- +/* ------------------------------------------------------------------------- * This option list has to contain all options for all scanners supported by * this driver. If a certain scanner cannot handle a certain option, there's * still the possibility to say so, later. diff --git a/backend/kodakaio.c b/backend/kodakaio.c index a9bec7b..c8cc9a7 100644 --- a/backend/kodakaio.c +++ b/backend/kodakaio.c @@ -3,7 +3,7 @@ * * Copyright (C) 2011-2017 Paul Newall * - * Based on the Magicolor sane backend: + * Based on the Magicolor sane backend: * Based on the epson2 sane backend: * Based on Kazuhiro Sasayama previous * work on epson.[ch] file from the SANE package. @@ -16,13 +16,13 @@ * Modified 30/12/14 to fix bug where network connection was broken after 30s of idle time. * The connection is now made in sane_start and ended in sane_cancel. - * 01/01/13 Now with adf, the scan can be padded to make up the full page length, + * 01/01/13 Now with adf, the scan can be padded to make up the full page length, * or the page can terminate at the end of the paper. This is a selectable option. * 25/11/12 Using avahi now for net autodiscovery. Use configure option --enable-avahi * 1/5/17 patched to use local pointer for avahi callback */ -/* +/* Packages to add to a clean ubuntu install libavahi-common-dev libusb-dev @@ -45,7 +45,7 @@ If you want to use the test backend, for example with sane-troubleshoot, you sho */ /* SANE-FLOW-DIAGRAM Kodakaio commands in [] brackets - + - sane_init() : initialize backend, attach scanners(devicename,0) . - sane_get_devices() : query list of scanner-devices . - sane_open() : open a particular scanner-device and attach_scanner(devicename,&dev) @@ -58,7 +58,7 @@ If you want to use the test backend, for example with sane-troubleshoot, you sho . . - sane_get_parameters() : returns actual scan-parameters . . - sane_read() : read image-data (from pipe) . . - sane_cancel() : cancel operation, kill reader_process [(F), U] - + . - sane_close() : close opened scanner-device, do_cancel, free buffer and handle - sane_exit() : terminate use of backend, free devicename and device-struture */ @@ -169,7 +169,7 @@ In terminal use: export SANE_DEBUG_KODAKAIO=40 to set the level to 40 or whateve level you want. Then you can scan with scanimage or simple-scan from terminal and see debug info -use these defines to promote certain functions that you are interested in +use these defines to promote certain functions that you are interested in define low values to make detail of a section appear when DBG level is low define a high value eg 99 to get normal behaviour. */ #define DBG_READ 99 @@ -248,7 +248,7 @@ FILE *RawScan = NULL; char RawScanPath[] = ""; /* empty path means no raw scan file is made */ /* - * Devices supported by this backend + * Devices supported by this backend */ /* kodak command strings */ @@ -286,7 +286,7 @@ The following are not used but may be in future commandtype, max depth, pointer to depth list */ -/* list of cap data the first scanner is the default +/* list of cap data the first scanner is the default */ /* KODAK AIO DEFAULT, */ { @@ -295,7 +295,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(100), 0}, {0, SANE_FIX(100), 0} /* ADF x/y ranges (TODO!) */ }, /* KODAK ESP 5100, */ @@ -305,7 +305,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP 5300, */ @@ -315,7 +315,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP 5500, */ @@ -325,7 +325,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP 5000, */ @@ -335,7 +335,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP 3300, */ @@ -345,7 +345,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP5, */ @@ -355,7 +355,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP7, */ @@ -365,7 +365,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP9, */ @@ -375,7 +375,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP5210 or 5250, */ @@ -385,7 +385,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP3200 , */ @@ -395,7 +395,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP4100 , */ @@ -405,7 +405,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP6100 , */ @@ -415,7 +415,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_TRUE, SANE_FALSE, /* ADF, duplex */ + SANE_TRUE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP7200 , */ @@ -425,7 +425,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP C110 , */ @@ -435,7 +435,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP C115 , */ @@ -445,7 +445,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP 2150 , */ @@ -455,7 +455,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_TRUE, SANE_FALSE, /* ADF, duplex */ + SANE_TRUE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP C310 , */ @@ -465,7 +465,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP C315 , */ @@ -475,7 +475,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_FALSE, SANE_FALSE, /* ADF, duplex */ + SANE_FALSE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* ADVENT AW10, */ @@ -525,7 +525,7 @@ commandtype, max depth, pointer to depth list 600, {75, 600, 0}, kodakaio_resolution_list, 4, /* 600 dpi max, 4 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_TRUE, SANE_FALSE, /* ADF, duplex */ + SANE_TRUE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK ESP2170 , */ @@ -535,7 +535,7 @@ commandtype, max depth, pointer to depth list 1200, {75, 1200, 0}, kodakaio_resolution_list, 5, /* 1200 dpi optical, {from, to, 0} 5 resolutions */ 8, kodakaio_depth_list, /* color depth max 8, list above */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(11.7 * MM_PER_INCH), 0}, /* FBF x/y ranges */ - SANE_TRUE, SANE_FALSE, /* ADF, duplex */ + SANE_TRUE, SANE_FALSE, /* ADF, duplex */ {0, SANE_FIX(8.5 * MM_PER_INCH), 0}, {0, SANE_FIX(14 * MM_PER_INCH), 0} /* 14 ADF x/y ranges */ }, /* KODAK HERO 9.1, */ @@ -748,7 +748,7 @@ sanei_kodakaio_net_write_raw(struct KodakAio_Scanner *s, SANE_Status *status) { DBG(32, "net write:%x,%x,%x,%x,%x,%x,%x,%x\n",buf[0],buf[1],buf[2],buf[3],buf[4],buf[5],buf[6],buf[7]); - + sanei_tcp_write(s->fd, buf, buf_size); /* TODO: Check whether sending failed... */ @@ -863,8 +863,8 @@ static ssize_t k_recv(KodakAio_Scanner * s, void *buf, ssize_t buf_size, SANE_Status * status) { -/* requests and receives data this function makes the split between USB and NET -this function called by a number of others +/* requests and receives data this function makes the split between USB and NET +this function called by a number of others In USB mode, this function will wait until data is available for a maximum of SCANNER_READ_TIMEOUT seconds. In NET mode the timeout is in kodakaio_net_read @@ -878,7 +878,7 @@ In NET mode the timeout is in kodakaio_net_read usb_delay.tv_nsec = 300000000; /* 0.3 sec */ if (s->hw->connection == SANE_KODAKAIO_NET) { - + time(&time_start); DBG(min(16,DBG_READ), "[%ld] %s: net req size = %ld ", (long) time_start, __func__, (long) buf_size); n = kodakaio_net_read(s, buf, buf_size, status); @@ -1015,7 +1015,7 @@ and returns appropriate status s->adf_loaded = SANE_TRUE; DBG(5, "%s: News - docs in ADF\n", __func__); } - else if (rxbuf[4] != + else if (rxbuf[4] != 0x01 && s->adf_loaded == SANE_TRUE) { s->adf_loaded = SANE_FALSE; DBG(5, "%s: News - ADF is empty\n", __func__); @@ -1031,7 +1031,7 @@ and returns appropriate status } /* unused function -static ssize_t +static ssize_t kodakaio_rxflush(KodakAio_Scanner *s) Tries to get 64 byte reply @@ -1052,7 +1052,7 @@ and returns number of bytes read */ /* - * high-level communication commands + * high-level communication commands */ static SANE_Status @@ -1064,7 +1064,7 @@ k_hello (KodakAio_Scanner * s) DBG(5, "%s\n", __func__); -/* check that there is nothing already in the input buffer before starting +/* check that there is nothing already in the input buffer before starting kodakaio_rxflush(s); */ /* preset the reply, so I can see if it gets changed */ @@ -1129,12 +1129,12 @@ cmd_cancel_scan (SANE_Handle handle) unsigned char reply[8]; /* adf added 20/2/12 should it be adf? or adf with paper in? */ if (strcmp(source_list[s->val[OPT_SOURCE].w], ADF_STR) == 0) { /* adf */ - if (kodakaio_txrxack(s, KodakEsp_F, reply)!= SANE_STATUS_GOOD) + if (kodakaio_txrxack(s, KodakEsp_F, reply)!= SANE_STATUS_GOOD) { DBG(1, "%s: KodakEsp_F command failed\n", __func__); return SANE_STATUS_IO_ERROR; } - if (kodakaio_txrxack(s, KodakEsp_UnLock, reply)!= SANE_STATUS_GOOD) + if (kodakaio_txrxack(s, KodakEsp_UnLock, reply)!= SANE_STATUS_GOOD) { DBG(1, "%s: KodakEsp_UnLock command failed\n", __func__); return SANE_STATUS_IO_ERROR; @@ -1193,7 +1193,7 @@ cmd_set_color_curve(SANE_Handle handle, unsigned char col) int i; /* 7/9/14 was unsigned char and that stopped the loop that made the linear curve from going to 255 */ DBG(32, "%s: start\n", __func__); tx_col[0]=0x1b; tx_col[1]='S'; tx_col[2]='K'; tx_col[3]=col; tx_col[4]=0; tx_col[5]=0; tx_col[6]=0; tx_col[7]=0; -/* linear curve now but could send tailor made curves in future */ +/* linear curve now but could send tailor made curves in future */ for(i=0;i<=255;++i) tx_curve[i]=i; /* 7/9/14 was i<255 the missing elements caused speckles */ k_send(s, tx_col, 8, &status); @@ -1255,7 +1255,7 @@ cmd_set_scanning_parameters(SANE_Handle handle, tx_dpi[7]=0; kodakaio_txrxack(s, tx_dpi, bufread); -/* colour curves don't seem to be sent for usb preview +/* colour curves don't seem to be sent for usb preview but it seems to do no harm to send them */ cmd_set_color_curve(s, 'R'); cmd_set_color_curve(s, 'G'); @@ -1298,7 +1298,7 @@ this command needs actual DPI units*/ int cmparray (unsigned char *array1, unsigned char *array2, size_t len) { -/* compares len bytes of the arrays returns 0 if they match +/* compares len bytes of the arrays returns 0 if they match returns the first missmatch position if they don't match */ unsigned int i; for(i=0; iack and do padding if the padding option is selected @@ -1363,7 +1363,7 @@ But it seems that the scanner takes care of that, and gives you the ack as a sep /* it may be the last block from the scanner so look for Ack response in last 8 bytes */ Last8 = buf + bytecount - 8; - /* only compare 4 bytes because we sometimes get escSS02.. or escSS00.. + /* only compare 4 bytes because we sometimes get escSS02.. or escSS00.. is 4 the right number ? */ if (cmparray(Last8,KodakEsp_Ack,4) == 0) { DBG(min(10,DBG_READ), "%s: found KodakEsp_Ack at %lu bytes of %lu\n", __func__, (unsigned long) bytecount, (unsigned long) *len); @@ -1404,12 +1404,12 @@ But it seems that the scanner takes care of that, and gives you the ack as a sep if (status == SANE_STATUS_GOOD) if (s->bytes_unread <= 0) - DBG(min(2,DBG_READ), "%s: Page fully read %d blocks, %ld bytes unread\n", __func__, s->counter, (long) s->bytes_unread); + DBG(min(2,DBG_READ), "%s: Page fully read %d blocks, %ld bytes unread\n", __func__, s->counter, (long) s->bytes_unread); else DBG(min(20,DBG_READ), "%s: Image data successfully read %ld bytes, %ld bytes unread\n", __func__, (long) bytecount, (long) s->bytes_unread); else if (s->ack) /* was (status == SANE_STATUS_EOF) */ DBG(min(2,DBG_READ), "%s: scanner data read ended %d blocks %ld bytes, %ld bytes unread\n", __func__, s->counter, (long) bytecount, (long) s->bytes_unread); - else + else DBG(min(1,DBG_READ), "%s: Image data read stopped with %s after %d blocks %ld bytes, %ld bytes unread\n", __func__, sane_strstatus(status), s->counter, (long) bytecount, (long) s->bytes_unread); return status; @@ -1549,7 +1549,7 @@ k_setup_block_mode (KodakAio_Scanner *s) return SANE_STATUS_GOOD; } -/* Call the commands to set scanning parameters +/* Call the commands to set scanning parameters In the Kodak Aio the parameters are: (x1b,"S","F",0,0,0,0,0) (x1b,"S","S",1,0,0,0,0) @@ -1615,7 +1615,7 @@ k_set_scanning_parameters(KodakAio_Scanner * s) /* TODO: Any way to set PREVIEW??? */ /* Remaining bytes unused */ - status = cmd_set_scanning_parameters(s, dpi, + status = cmd_set_scanning_parameters(s, dpi, s->left * dpi / optres, s->top * dpi / optres, /* top/left start (dpi units)*/ s->params.pixels_per_line, s->params.lines, /* extent was s->width, s->height*/ source); /* source */ @@ -1696,7 +1696,7 @@ k_scan_finish(KodakAio_Scanner * s) static void k_copy_image_data(KodakAio_Scanner * s, SANE_Byte * data, SANE_Int max_length, SANE_Int * length) -/* copies the read data from s->line_buffer to the position in data pointer to by s->ptr +/* copies the read data from s->line_buffer to the position in data pointer to by s->ptr uncompressed data is RRRR...GGGG...BBBB per line */ { SANE_Int bytes_available; @@ -1724,7 +1724,7 @@ uncompressed data is RRRR...GGGG...BBBB per line */ /* We have filled as much as possible of the current line * with data from the scanner. If we have a complete line, - * copy it over. + * copy it over. line points to the current byte in the input s->line_buffer data points to the output buffer*/ if ((s->bytes_read_in_line >= s->scan_bytes_per_line) && @@ -1753,8 +1753,8 @@ uncompressed data is RRRR...GGGG...BBBB per line */ *data &= ~mask; /* white clear the bit in mask */ else *data |= mask; /* black set the bit in mask */ - - if (offset == 7 || i == s->params.pixels_per_line-1) + + if (offset == 7 || i == s->params.pixels_per_line-1) data++; /* move on a byte if the byte is full or the line is complete */ } @@ -1768,7 +1768,7 @@ uncompressed data is RRRR...GGGG...BBBB per line */ } /*debug file The same for color or grey because the scan is colour */ if (RawScan != NULL) { - for (i=0; i< s->scan_bytes_per_line; ++i) fputc(s->line_buffer[i],RawScan); + for (i=0; i< s->scan_bytes_per_line; ++i) fputc(s->line_buffer[i],RawScan); } max_length -= s->params.bytes_per_line; s->bytes_read_in_line -= s->scan_bytes_per_line; @@ -1840,7 +1840,7 @@ k_init_parametersta(KodakAio_Scanner * s) s->params.last_frame = SANE_TRUE; s->params.bytes_per_line = 3 * ceil (s->params.depth * s->params.pixels_per_line / 8.0); -/* kodak only scans in color and conversion to grey or lineart is done in the driver +/* kodak only scans in color and conversion to grey or lineart is done in the driver s->params.format = SANE_FRAME_RGB; */ DBG(20, "%s: s->val[OPT_MODE].w = %d (color is %d)\n", __func__,s->val[OPT_MODE].w, MODE_COLOR); if (s->val[OPT_MODE].w == MODE_COLOR) s->params.format = SANE_FRAME_RGB; @@ -1870,7 +1870,7 @@ k_read(struct KodakAio_Scanner *s) { unsigned char rx[8]; -/* monitors progress of blocks and calls cmd_read_data to get each block +/* monitors progress of blocks and calls cmd_read_data to get each block you don't know how many blocks there will be in advance because their size may be determined by the scanner*/ SANE_Status status = SANE_STATUS_GOOD; size_t buf_len = 0; @@ -1907,7 +1907,7 @@ you don't know how many blocks there will be in advance because their size may b if (status == SANE_STATUS_EOF) { /* page ended prematurely. */ } - } + } else { /* s->bytes_unread <=0 This is the end of a page */ s->eof = SANE_TRUE; DBG(min(10,DBG_READ), "%s: set EOF after %d blocks\n=============\n", __func__, s->counter); @@ -1932,7 +1932,7 @@ you don't know how many blocks there will be in advance because their size may b } /* - * SANE API implementation (high-level functions) + * SANE API implementation (high-level functions) */ #if WITH_AVAHI @@ -1951,12 +1951,12 @@ get_device_from_identification (const char *ident, const char *vid, const char * return NULL; } for (n = 0; n < NELEMS (kodakaio_cap); n++) { - + if (strcmp (kodakaio_cap[n].model, ident)==0) { DBG(20, "matched <%s> & <%s>\n", kodakaio_cap[n].model, ident); return &kodakaio_cap[n]; } - else + else if (kodakaio_cap[n].id == pidnum && 0x040A == vidnum) { DBG(20, "matched <%s> & <%s:%s>\n", kodakaio_cap[n].model, vid, pid); return &kodakaio_cap[n]; @@ -2124,7 +2124,7 @@ detect_usb(struct KodakAio_Scanner *s) * about the device */ while (i != numIds && !is_valid) { /* if (product == kodakaio_usb_product_ids[i]) */ - if (product == kodakaio_cap[i].id) + if (product == kodakaio_cap[i].id) is_valid = SANE_TRUE; i++; } @@ -2259,20 +2259,20 @@ device_detect(const char *name, int type, SANE_Status *status) #if WITH_AVAHI /* ProcessAvahiDevice is called to process each discovered device in turn */ -void +void ProcessAvahiDevice(const char *device_id, const char *vid, const char *pid, const char *ip_addr) { struct KodakaioCap *cap; DBG(min(10,DBG_AUTO),"device_id = <%s> vid:pid = <%s:%s>\n", device_id,vid,pid); -/* check if it is a model likely to be supported: "KODAK ESP" or "KODAK HERO" +/* check if it is a model likely to be supported: "KODAK ESP" or "KODAK HERO" DBG(min(10,DBG_AUTO),"look up model <%s>\n", device_model); */ cap = get_device_from_identification("", vid, pid); if (cap == NULL) { return; - } + } DBG(min(10,DBG_AUTO), "%s: Found autodiscovered device: %s (type 0x%x)\n", __func__, cap->model, cap->id); attach_one_net (ip_addr, cap->id); @@ -2337,12 +2337,12 @@ static void resolve_callback( else DBG(min(10,DBG_AUTO), "didn't call ProcessAvahiDevice\n"); if(vid_pair_list != NULL) { - avahi_free(vidkey); + avahi_free(vidkey); avahi_free(vidvalue); DBG(min(15,DBG_AUTO), "vidkey and vidvalue freed\n"); } if(pid_pair_list != NULL) { - avahi_free(pidkey); + avahi_free(pidkey); avahi_free(pidvalue); DBG(min(15,DBG_AUTO), "pidkey and pidvalue freed\n"); } @@ -2413,7 +2413,7 @@ static void client_callback(AvahiClient *c, AvahiClientState state, void * userd static int kodak_network_discovery(const char*host) -/* If host = NULL do autodiscovery. If host != NULL try to verify the model +/* If host = NULL do autodiscovery. If host != NULL try to verify the model First version only does autodiscovery */ { AvahiSimplePoll *simple_poll; @@ -2586,7 +2586,7 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line) /* Timeout for all other read requests */ DBG(50, "%s: Request timeout set to %d\n", __func__, timeout); K_Request_Timeout = timeout; - + } else { /* TODO: Warning about unparsable line! */ } @@ -2790,7 +2790,7 @@ init_options(KodakAio_Scanner *s) s->opt[OPT_BIT_DEPTH].constraint.word_list = s->hw->cap->depth_list; s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; s->val[OPT_BIT_DEPTH].w = s->hw->cap->depth_list[1]; /* the first "real" element is the default */ - + DBG(20, "%s: depth list has depth_list[0] = %d entries\n", __func__, s->hw->cap->depth_list[0]); if (s->hw->cap->depth_list[0] == 1) { /* only one element in the list -> hide the option */ s->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; @@ -2814,7 +2814,7 @@ init_options(KodakAio_Scanner *s) s->val[OPT_RESOLUTION].w = s->hw->cap->dpi_range.min; - /* trial option for debugging + /* trial option for debugging s->opt[OPT_TRIALOPT].name = "trialoption"; s->opt[OPT_TRIALOPT].title = "trialoption"; s->opt[OPT_TRIALOPT].desc = "trialoption"; @@ -2834,7 +2834,7 @@ init_options(KodakAio_Scanner *s) for(i=0;source_list[i]!=NULL;++i) DBG(18, "source_list: %s\n",source_list[i]); - + /* source */ s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; @@ -2850,7 +2850,7 @@ init_options(KodakAio_Scanner *s) s->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; } -/* Are there any ESP scanners that are duplex? */ +/* Are there any ESP scanners that are duplex? */ s->opt[OPT_ADF_MODE].name = "adf-mode"; s->opt[OPT_ADF_MODE].title = SANE_I18N("ADF Mode"); s->opt[OPT_ADF_MODE].desc = @@ -2991,7 +2991,7 @@ sane_open(SANE_String_Const name, SANE_Handle *handle) /* s is always valid here */ DBG(10, "handle obtained\n"); - status = k_discover_capabilities(s); /* added 27/12/11 to fix source list problem + status = k_discover_capabilities(s); /* added 27/12/11 to fix source list problem maybe we should only be rebuilding the source list here? */ if (status != SANE_STATUS_GOOD) return status; @@ -3000,7 +3000,7 @@ maybe we should only be rebuilding the source list here? */ *handle = (SANE_Handle) s; -/* moving the open scanner section below to sane_start 27/12/14 +/* moving the open scanner section below to sane_start 27/12/14 status = open_scanner(s); if (status != SANE_STATUS_GOOD) { free(s); @@ -3400,8 +3400,8 @@ sane_start(SANE_Handle handle) /* set scanning parameters; also query the current image * parameters from the sanner and save - * them to s->params -Only set scanning params the first time, or after a cancel + * them to s->params +Only set scanning params the first time, or after a cancel try change 22/2/12 take lock scanner out of k_set_scanning_parameters */ /* moved open_scanner here 27/12/14 from sane_open */ diff --git a/backend/kodakaio.conf.in b/backend/kodakaio.conf.in index 2ad3ed4..0241408 100644 --- a/backend/kodakaio.conf.in +++ b/backend/kodakaio.conf.in @@ -9,7 +9,7 @@ # snmp-timeout controls auto-detection timeout in ms (1500=1.5s). snmp-timeout 2000 -# scan-data-timeout controls the timeout for scan data +# scan-data-timeout controls the timeout for scan data # (scans may take several seconds to initialize, so we need to wait longer) scan-data-timeout 10000 @@ -77,4 +77,3 @@ usb # 0x4062, /* kodak Office Hero 6.1 */ # 0x4063, /* kodak Hero 7.1 */ # 0x4067, /* kodak Hero 9.1 */ - diff --git a/backend/kvs1025_low.c b/backend/kvs1025_low.c index d834f61..98cf3be 100644 --- a/backend/kvs1025_low.c +++ b/backend/kvs1025_low.c @@ -988,7 +988,7 @@ buffer_deskew(PKV_DEV s, int side) &s->params[side_index],s->img_buffers[side_index], resolution,resolution, &s->deskew_vals[0],&s->deskew_vals[1],&s->deskew_slope); - + if(s->deskew_stat){ DBG (5, "buffer_despeck: bad findSkew, bailing\n"); goto cleanup; @@ -997,7 +997,7 @@ buffer_deskew(PKV_DEV s, int side) /* backside images can use a 'flipped' version of frontside data */ else{ s->deskew_slope *= -1; - s->deskew_vals[0] + s->deskew_vals[0] = s->params[side_index].pixels_per_line - s->deskew_vals[0]; } @@ -1039,7 +1039,7 @@ buffer_crop(PKV_DEV s, int side) DBG (5, "buffer_crop: bad edges, bailing\n"); goto cleanup; } - + DBG (15, "buffer_crop: t:%d b:%d l:%d r:%d\n", s->crop_vals[0],s->crop_vals[1],s->crop_vals[2],s->crop_vals[3]); @@ -1066,9 +1066,9 @@ buffer_crop(PKV_DEV s, int side) } /* update image size counter to new, smaller size */ - s->img_size[side_index] + s->img_size[side_index] = s->params[side_index].lines * s->params[side_index].bytes_per_line; - + cleanup: DBG (10, "buffer_crop: finish\n"); return ret; @@ -1143,7 +1143,7 @@ buffer_rotate(PKV_DEV s, int side) ret = sanei_magic_findTurn( &s->params[side_index],s->img_buffers[side_index], resolution,resolution,&angle); - + if(ret){ DBG (5, "buffer_rotate: error %d\n",ret); ret = SANE_STATUS_GOOD; @@ -1161,7 +1161,7 @@ buffer_rotate(PKV_DEV s, int side) ret = sanei_magic_turn( &s->params[side_index],s->img_buffers[side_index], angle); - + if(ret){ DBG (5, "buffer_rotate: error %d\n",ret); ret = SANE_STATUS_GOOD; @@ -1169,9 +1169,9 @@ buffer_rotate(PKV_DEV s, int side) } /* update image size counter to new, smaller size */ - s->img_size[side_index] + s->img_size[side_index] = s->params[side_index].lines * s->params[side_index].bytes_per_line; - + cleanup: DBG (10, "buffer_rotate: finished\n"); return ret; diff --git a/backend/kvs1025_opt.c b/backend/kvs1025_opt.c index b7581f9..71fbf89 100644 --- a/backend/kvs1025_opt.c +++ b/backend/kvs1025_opt.c @@ -141,7 +141,6 @@ static const KV_PAPER_SIZE go_paper_sizes[] = { }; static const int default_paper_size_idx = 3; /* A4 */ -static const int go_paper_max_width = 216; /* US letter */ /* Lists of supported halftone. They are only valid with * for the Black&White mode. */ diff --git a/backend/kvs1025_usb.c b/backend/kvs1025_usb.c index 90ce4d0..d7a4dde 100644 --- a/backend/kvs1025_usb.c +++ b/backend/kvs1025_usb.c @@ -303,7 +303,7 @@ kv_usb_escape (PKV_DEV dev, size_t len = 16; ret = sanei_usb_read_bulk (dev->usb_fd, (SANE_Byte *) cmd_buff, &len); - + if (ret || len != 16) { DBG (DBG_error, "usb_bulk_read: Error reading response." diff --git a/backend/kvs20xx_opt.c b/backend/kvs20xx_opt.c index 94c4133..fc527f3 100644 --- a/backend/kvs20xx_opt.c +++ b/backend/kvs20xx_opt.c @@ -207,7 +207,7 @@ kvs20xx_init_options (struct scanner *s) o->unit = SANE_UNIT_NONE; s->val[DUPLEX].w = SANE_FALSE; - /*FIXME + /*FIXME if (!s->support_info.support_duplex) o->cap |= SANE_CAP_INACTIVE; */ diff --git a/backend/kvs40xx_opt.c b/backend/kvs40xx_opt.c index bd9d85e..2bf9a5c 100644 --- a/backend/kvs40xx_opt.c +++ b/backend/kvs40xx_opt.c @@ -356,7 +356,7 @@ kvs40xx_init_options (struct scanner *s) o->unit = SANE_UNIT_NONE; s->val[DUPLEX].w = SANE_FALSE; - /*FIXME + /*FIXME if (!s->support_info.support_duplex) o->cap |= SANE_CAP_INACTIVE; */ diff --git a/backend/leo.c b/backend/leo.c index b44a343..e0200de 100644 --- a/backend/leo.c +++ b/backend/leo.c @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002-2003 Frank Zago (sane at zago dot net) - + 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. + If you do not wish that, delete this exception notice. */ /* @@ -945,7 +945,7 @@ leo_init_options (Leo_Scanner * dev) (SANE_String_Const *) scan_mode_list[0], NULL); } -/* +/* * Wait until the scanner is ready. */ static SANE_Status @@ -1000,7 +1000,7 @@ leo_fill_image (Leo_Scanner * dev) while (dev->real_bytes_left) { - /* + /* * Try to read the maximum number of bytes. */ size = 0; @@ -1027,7 +1027,7 @@ leo_fill_image (Leo_Scanner * dev) if (size == 0) { - /* Probably reached the end of the buffer. + /* Probably reached the end of the buffer. * Check, just in case. */ assert (dev->image_end != 0); return (SANE_STATUS_GOOD); @@ -1093,7 +1093,7 @@ leo_fill_image (Leo_Scanner * dev) return (SANE_STATUS_GOOD); /* unreachable */ } -/* Copy from the raw buffer to the buffer given by the backend. +/* Copy from the raw buffer to the buffer given by the backend. * * len in input is the maximum length available in buf, and, in * output, is the length written into buf. diff --git a/backend/leo.conf.in b/backend/leo.conf.in index ecd918c..8aeb9bf 100644 --- a/backend/leo.conf.in +++ b/backend/leo.conf.in @@ -5,4 +5,3 @@ scsi ACROSS * Scanner * * * 0 scsi "LEO" "LEOScan-S3" /dev/scanner - diff --git a/backend/leo.h b/backend/leo.h index 73bb7b1..d9595bf 100644 --- a/backend/leo.h +++ b/backend/leo.h @@ -38,10 +38,10 @@ 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. + If you do not wish that, delete this exception notice. */ -/* +/* $Id$ */ @@ -241,8 +241,8 @@ enum Leo_Option /*--------------------------------------------------------------------------*/ -/* - * Scanner supported by this backend. +/* + * Scanner supported by this backend. */ struct scanners_supported { @@ -338,7 +338,7 @@ Leo_Scanner; /*--------------------------------------------------------------------------*/ -/* Debug levels. +/* Debug levels. * Should be common to all backends. */ #define DBG_error0 0 diff --git a/backend/lexmark.c b/backend/lexmark.c index e0cd21f..36c33f3 100644 --- a/backend/lexmark.c +++ b/backend/lexmark.c @@ -2,9 +2,9 @@ (C) 2003-2004 Lexmark International, Inc. (Original Source code) (C) 2005 Fred Odendaal - (C) 2006-2013 Stéphane Voltz + (C) 2006-2013 Stéphane Voltz (C) 2010 "Torsten Houwaart" X74 support - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -625,7 +625,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) * Open the backend, ie return the struct handle of a detected scanner * The struct returned is choosne if it matches the name given, which is * usefull when several scanners handled by the backend have been detected. - * However, special case empty string "" and "lexmark" pick the first + * However, special case empty string "" and "lexmark" pick the first * available handle. */ SANE_Status @@ -1144,7 +1144,7 @@ sane_start (SANE_Handle handle) lexmark_device->eof = SANE_FALSE; - /* Need this cancel_ctr to determine how many times sane_cancel is called + /* Need this cancel_ctr to determine how many times sane_cancel is called since it is called more than once. */ lexmark_device->cancel_ctr = 0; @@ -1180,15 +1180,15 @@ sane_start (SANE_Handle handle) return status; } - /* At this point we're somewhere in the dot. We need to read a number of - lines greater than the diameter of the dot and determine how many lines - past the dot we've gone. We then use this information to see how far the + /* At this point we're somewhere in the dot. We need to read a number of + lines greater than the diameter of the dot and determine how many lines + past the dot we've gone. We then use this information to see how far the scan head must move before starting the scan. */ /* offset is in 600 dpi unit */ offset = sanei_lexmark_low_find_start_line (lexmark_device); DBG (7, "start line offset=%d\n", offset); - /* Set the shadow registers for scan with the options (resolution, mode, + /* Set the shadow registers for scan with the options (resolution, mode, size) set in the front end. Pass the offset so we can get the vert. start. */ sanei_lexmark_low_set_scan_regs (lexmark_device, diff --git a/backend/lexmark.h b/backend/lexmark.h index 0790551..9b7de98 100644 --- a/backend/lexmark.h +++ b/backend/lexmark.h @@ -2,7 +2,7 @@ lexmark.h - SANE library for Lexmark scanners. Copyright (C) 2003-2004 Lexmark International, Inc. (original source) Copyright (C) 2005 Fred Odendaal - Copyright (C) 2006-2010 Stéphane Voltz + Copyright (C) 2006-2010 Stéphane Voltz Copyright (C) 2010 "Torsten Houwaart" X74 support This file is part of the SANE package. diff --git a/backend/lexmark_low.c b/backend/lexmark_low.c index fe20e89..db1dab5 100644 --- a/backend/lexmark_low.c +++ b/backend/lexmark_low.c @@ -1,9 +1,9 @@ /* lexmark-low.c: scanner-interface file for low Lexmark scanners. (C) 2005 Fred Odendaal - (C) 2006-2013 Stéphane Voltz + (C) 2006-2013 Stéphane Voltz (C) 2010 "Torsten Houwaart" X74 support - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -180,7 +180,7 @@ rts88xx_set_scan_frequency (SANE_Byte * regs, int frequency) } /* - * read one register at given index + * read one register at given index */ static SANE_Status rts88xx_read_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg) @@ -218,7 +218,7 @@ rts88xx_read_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg) } /* - * write one register at given index + * write one register at given index */ static SANE_Status rts88xx_write_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg) @@ -412,7 +412,7 @@ lexmark_low_wake_up (Lexmark_Device * dev) /** - * + * */ #ifdef DEEP_DEBUG static void @@ -1254,7 +1254,7 @@ sanei_lexmark_low_close_device (Lexmark_Device * dev) } -/* This function writes the contents of the given registers to the +/* This function writes the contents of the given registers to the scanner. */ SANE_Status low_write_all_regs (SANE_Int devnum, SANE_Byte * regs) @@ -1306,31 +1306,31 @@ SANE_Bool low_is_home_line (Lexmark_Device * dev, unsigned char *buffer) { /* - This function assumes the buffer has a size of 2500 bytes.It is + This function assumes the buffer has a size of 2500 bytes.It is destructive to the buffer. Here is what it does: - Go through the buffer finding low and high values, which are computed by - comparing to the average: + Go through the buffer finding low and high values, which are computed by + comparing to the average: average = (lowest value + highest value)/2 - High bytes are changed to 0xFF (white), lower or equal bytes are changed - to 0x00 (black),so that the buffer only contains white (0xFF) or black + High bytes are changed to 0xFF (white), lower or equal bytes are changed + to 0x00 (black),so that the buffer only contains white (0xFF) or black (0x00) values. Next, we go through the buffer. We use a tolerance of 5 bytes on each end of the buffer and check a region from bytes 5 to 2495. We start assuming we are in a white region and look for the start of a black region. We save - this index as the transition from white to black. We also save where we - change from black back to white. We continue checking for transitions - until the end of the check region. If we don't have exactly two + this index as the transition from white to black. We also save where we + change from black back to white. We continue checking for transitions + until the end of the check region. If we don't have exactly two transitions when we reach the end we return SANE_FALSE. The final check compares the transition indices to the nominal values plus or minus the tolerence. For the first transition (white to black index) the value must lie in the range 1235-30 (1205) to 1235+30 (1265). For the second transition (black to white) the value must lie in the range - 1258-30 (1228) to 1258+30 (1288). If the indices are out of range we + 1258-30 (1228) to 1258+30 (1288). If the indices are out of range we return SANE_FALSE. Otherwise, we return SANE_TRUE. */ @@ -1467,9 +1467,9 @@ sanei_lexmark_low_move_fwd (SANE_Int distance, Lexmark_Device * dev, SANE_Byte * regs) { /* - This function moves the scan head forward with the highest vertical + This function moves the scan head forward with the highest vertical resolution of 1200dpi. The distance moved is given by the distance - parameter. + parameter. As an example, given a distance parameter of 600, the scan head will move 600/1200", or 1/2" forward. @@ -1950,7 +1950,7 @@ sanei_lexmark_low_search_home_bwd (Lexmark_Device * dev) /* This function must only be called if the scan head is past the home dot. It could damage the scanner if not. - This function tells the scanner to do a grayscale scan backwards with a + This function tells the scanner to do a grayscale scan backwards with a 300dpi resolution. It reads 2500 bytes of data between horizontal co-ordinates 0x6a and 0x13f2. @@ -1959,8 +1959,8 @@ sanei_lexmark_low_search_home_bwd (Lexmark_Device * dev) before it bangs against the end. A line limit is set so that a maximum of 0x0F3C (13"*300dpi) lines can be read. - To read the scan data we create a buffer space large enough to hold 10 - lines of data. For each read we poll twice, ignoring the first poll. This + To read the scan data we create a buffer space large enough to hold 10 + lines of data. For each read we poll twice, ignoring the first poll. This is required for timing. We repeat the double poll until there is data available. The number of lines (or number of buffers in our buffer space) is calculated from the size of the data available from the scanner. The @@ -2462,10 +2462,10 @@ sanei_lexmark_low_find_start_line (Lexmark_Device * dev) This function scans forward 59 lines, reading 88 bytes per line from the middle of the horizontal line: pixel 0xa84 to pixel 0x9d4. It scans with the following parameters: - dir=fwd + dir=fwd mode=grayscale h.res=300 dpi - v.res=600 dpi + v.res=600 dpi hor. pixels = (0xa84 - 0x9d4)/2 = 0x58 = 88 vert. pixels = 0x3e - 0x03 = 0x3b = 59 data = 88x59=5192=0x1448 @@ -2479,18 +2479,18 @@ sanei_lexmark_low_find_start_line (Lexmark_Device * dev) Byte swap the order of the bytes in the buffer. - Go through the buffer finding low and high values, which are computed by - comparing to the weighted average: + Go through the buffer finding low and high values, which are computed by + comparing to the weighted average: weighted_average = (lowest value + (highest value - lowest value)/4) - Low bytes are changed to 0xFF (white), higher of equal bytes are changed - to 0x00 (black),so that the buffer only contains white (0xFF) or black + Low bytes are changed to 0xFF (white), higher of equal bytes are changed + to 0x00 (black),so that the buffer only contains white (0xFF) or black (0x00) values. Next, we go through the buffer a line (88 bytes) at a time for 59 lines to read the entire buffer. For each byte in a line we check if the byte is black. If it is we increment the black byte counter. - After each line we check the black byte counter. If it is greater than 0 + After each line we check the black byte counter. If it is greater than 0 we increment the black line count and set the white line count to 0. If there were no black bytes in the line we set the black line count to 0 and increment the white line count. @@ -2852,7 +2852,7 @@ sanei_lexmark_low_find_start_line (Lexmark_Device * dev) } /* end for buffer */ free (buffer); - /* Stop the scanner. + /* Stop the scanner. This is needed to get the right distance to the scanning area */ if (dev->model.sensor_type == X74_SENSOR) low_stop_mvmt (dev->devnum); @@ -3879,7 +3879,7 @@ sanei_lexmark_low_set_scan_regs (Lexmark_Device * dev, SANE_Int resolution, /* set motor resolution divisor */ dev->shadow_regs[0x39] = 0x03; - /* data compression + /* data compression dev->shadow_regs[0x40] = 0x90; dev->shadow_regs[0x50] = 0x20; */ /* no data compression */ @@ -4296,7 +4296,7 @@ sanei_lexmark_low_set_scan_regs (Lexmark_Device * dev, SANE_Int resolution, dev->shadow_regs[0x36] = 0x0a; dev->shadow_regs[0x38] = 0x04; - /* data compression + /* data compression dev->shadow_regs[0x40] = 0x90; dev->shadow_regs[0x50] = 0x20; */ @@ -4499,8 +4499,8 @@ sanei_lexmark_low_set_scan_regs (Lexmark_Device * dev, SANE_Int resolution, dev->shadow_regs[0x37] = 0x07; dev->shadow_regs[0x38] = 0x0b; - /* data compression - dev->shadow_regs[0x40] = 0x90; + /* data compression + dev->shadow_regs[0x40] = 0x90; dev->shadow_regs[0x50] = 0x20; */ /* no data compression */ dev->shadow_regs[0x40] = 0x80; @@ -5471,7 +5471,7 @@ read_buffer_is_empty (Read_Buffer * read_buffer) return read_buffer->empty; } -/* +/* * average a width*height rgb/monochrome area * return values in given pointers */ @@ -5882,7 +5882,7 @@ sanei_lexmark_low_shading_calibration (Lexmark_Device * dev) /* computes coefficients */ /* there are 8 lines usable for shading calibration at 150 dpi, between - bottom of "home position" dot and the start of the scanner's window + bottom of "home position" dot and the start of the scanner's window assembly, we only use 7 of them */ if (yoffset + (8 * 4) / regs[0x7a] < lines) lines = yoffset + (8 * 4) / regs[0x7a]; @@ -6003,7 +6003,7 @@ sanei_lexmark_low_calibration (Lexmark_Device * dev) return status; } - /* put the calibrated or manual settings before shading calibration + /* put the calibrated or manual settings before shading calibration which must be done with final setting values */ if (rts88xx_is_color (dev->shadow_regs)) { @@ -6049,7 +6049,7 @@ sanei_lexmark_low_assign_sensor (Lexmark_Device * dev) return SANE_STATUS_GOOD; } -/* assign model description, based on USB id, and register content when +/* assign model description, based on USB id, and register content when * available */ SANE_Status sanei_lexmark_low_assign_model (Lexmark_Device * dev, diff --git a/backend/lexmark_models.c b/backend/lexmark_models.c index 7819a8d..4ca675d 100644 --- a/backend/lexmark_models.c +++ b/backend/lexmark_models.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2006-2010 Stéphane Voltz + Copyright (C) 2006-2010 Stéphane Voltz Copyright (C) 2010 "Torsten Houwaart" X74 support This file is part of the SANE package. diff --git a/backend/lexmark_sensors.c b/backend/lexmark_sensors.c index 9a34354..4b63d7d 100644 --- a/backend/lexmark_sensors.c +++ b/backend/lexmark_sensors.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2006-2010 Stéphane Voltz + Copyright (C) 2006-2010 Stéphane Voltz Copyright (C) 2010 "Torsten Houwaart" X74 support This file is part of the SANE package. diff --git a/backend/magicolor.c b/backend/magicolor.c index d3af142..3b27a85 100644 --- a/backend/magicolor.c +++ b/backend/magicolor.c @@ -1288,9 +1288,10 @@ mc_scan_finish(Magicolor_Scanner * s) status = cmd_finish_scan (s); status = cmd_request_error(s); - if (status != SANE_STATUS_GOOD) + if (status != SANE_STATUS_GOOD) { cmd_cancel_scan (s); return status; + } /* XXX required? */ /* TODO: cmd_reset(s);*/ @@ -2050,7 +2051,7 @@ mc_network_discovery(const char*host) fd_set fdset; DBG(1, " loop=%d\n", i++); timeout.tv_sec = 0; - /* Use a 125ms timeout for select. If we get a response, + /* Use a 125ms timeout for select. If we get a response, * the loop will be entered earlier again, anyway */ timeout.tv_usec = 125000; FD_ZERO (&fdset); @@ -2193,7 +2194,7 @@ attach_one_config(SANEI_Config __sane_unused__ *config, const char *line) /* Timeout for all other read requests */ DBG(50, "%s: Request timeout set to %d\n", __func__, timeout); MC_Request_Timeout = timeout; - + } else { /* TODO: Warning about unparsable line! */ } @@ -2414,7 +2415,7 @@ init_options(Magicolor_Scanner *s) s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; s->opt[OPT_SOURCE].constraint.string_list = source_list; s->val[OPT_SOURCE].w = 0; /* always use Flatbed as default */ - + s->opt[OPT_ADF_MODE].name = "adf-mode"; s->opt[OPT_ADF_MODE].title = SANE_I18N("ADF Mode"); s->opt[OPT_ADF_MODE].desc = diff --git a/backend/magicolor.conf.in b/backend/magicolor.conf.in index 9c25994..a7b7a4f 100644 --- a/backend/magicolor.conf.in +++ b/backend/magicolor.conf.in @@ -39,4 +39,3 @@ usb ### e.g.: # usb 0x132b 0x2098 - diff --git a/backend/matsushita.c b/backend/matsushita.c index e70c60a..62bfb06 100644 --- a/backend/matsushita.c +++ b/backend/matsushita.c @@ -2,49 +2,49 @@ Copyright (C) 2002, 2004 Frank Zago (sane at zago dot net) Copyright (C) 2002 Other SANE contributors - + 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. + If you do not wish that, delete this exception notice. */ /* $Id$ - Matsushita/Panasonic KV-SS25, KV-SS50, KV-SS55, KV-SS50EX, + Matsushita/Panasonic KV-SS25, KV-SS50, KV-SS55, KV-SS50EX, KV-SS55EX, KV-SS850, KV-SS855 SCSI scanners. This backend may support more Panasonic scanners. @@ -132,7 +132,7 @@ static const SANE_Word resolutions_rounds_400[8] = { /*--------------------------------------------------------------------------*/ -/* Lists of supported halftone. They are only valid with +/* Lists of supported halftone. They are only valid with * for the Black&White mode. */ static SANE_String_Const halftone_pattern_list[] = { SANE_I18N ("None"), @@ -265,7 +265,7 @@ static const int feeder_mode_val[] = { /*--------------------------------------------------------------------------*/ -/* Paper size in millimeters. +/* Paper size in millimeters. * Values from http://www.twics.com/~eds/paper/. */ static const struct paper_sizes paper_sizes[] = { {"2A0", 1189, 1682}, @@ -1317,7 +1317,7 @@ matsushita_init_options (Matsushita_Scanner * dev) /* Wait until the scanner is ready. * * The only reason I know the scanner is not ready is because it is - * moving the CCD. + * moving the CCD. */ static SANE_Status matsushita_wait_scanner (Matsushita_Scanner * dev) @@ -1524,17 +1524,17 @@ matsushita_fill_image (Matsushita_Scanner * dev) while (dev->real_bytes_left) { - /* + /* * Try to read the maximum number of bytes. * - * The windows driver reads no more than 0x8000 byte. + * The windows driver reads no more than 0x8000 byte. * * This backend operates differently than the windows * driver. The windows TWAIN driver always read 2 more bytes * at the end, so it gets a CHECK CONDITION with a short read * sense. Since the linux scsi layer seem to be buggy * regarding the resid, always read exactly the number of - * remaining bytes. + * remaining bytes. */ size = dev->real_bytes_left; @@ -1545,7 +1545,7 @@ matsushita_fill_image (Matsushita_Scanner * dev) if (size == 0) { - /* Probably reached the end of the buffer. + /* Probably reached the end of the buffer. * Check, just in case. */ assert (dev->image_end != 0); return (SANE_STATUS_GOOD); @@ -1620,7 +1620,7 @@ matsushita_fill_image (Matsushita_Scanner * dev) case 4: { - /* Adjust from a depth of 4 bits ([0..15]) to + /* Adjust from a depth of 4 bits ([0..15]) to * a depth of 8 bits ([0..255]) */ unsigned char *src = dev->buffer; @@ -1654,7 +1654,7 @@ matsushita_fill_image (Matsushita_Scanner * dev) return (SANE_STATUS_GOOD); /* unreachable */ } -/* Copy from the raw buffer to the buffer given by the backend. +/* Copy from the raw buffer to the buffer given by the backend. * * len in input is the maximum length available in buf, and, in * output, is the length written into buf. diff --git a/backend/matsushita.conf.in b/backend/matsushita.conf.in index 4d3cf24..98eaa88 100644 --- a/backend/matsushita.conf.in +++ b/backend/matsushita.conf.in @@ -7,7 +7,7 @@ scsi "K.M.E. " "KV-S2025C " scsi "K.M.E. " "KV-S2045C " scsi "K.M.E. " "KV-S2065L " -# These scanners are untested. +# These scanners are untested. # If you have one: # - check that the vendor/product strings are correct # - uncomment the line diff --git a/backend/matsushita.h b/backend/matsushita.h index a1528bf..bff7a04 100644 --- a/backend/matsushita.h +++ b/backend/matsushita.h @@ -37,10 +37,10 @@ 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. + If you do not wish that, delete this exception notice. */ -/* +/* $Id$ */ @@ -228,7 +228,7 @@ SANE_I18N("Automatic separation") /*--------------------------------------------------------------------------*/ -/* Differences between the scanners. +/* Differences between the scanners. * The scsi_* fields are used to lookup the correcte entry. */ struct scanners_supported { @@ -342,7 +342,7 @@ Matsushita_Scanner; /*--------------------------------------------------------------------------*/ -/* Debug levels. +/* Debug levels. * Should be common to all backends. */ #define DBG_error0 0 diff --git a/backend/microtek.c b/backend/microtek.c index ff82df4..05f8003 100644 --- a/backend/microtek.c +++ b/backend/microtek.c @@ -1,7 +1,7 @@ /*************************************************************************** * SANE - Scanner Access Now Easy. - microtek.c + microtek.c This file Copyright 2002 Matthew Marjanovic @@ -151,7 +151,7 @@ static SANE_Range brightness_range = {-100, 100, 1}; /*static SANE_Range exposure_range = {-18, 21, 3};*/ /*static SANE_Range contrast_range = {-42, 49, 7};*/ static SANE_Range u8_range = {0, 255, 1}; -static SANE_Range analog_gamma_range = +static SANE_Range analog_gamma_range = { SANE_FIX(0.1), SANE_FIX(4.0), SANE_FIX(0) }; @@ -235,7 +235,7 @@ ring_alloc (size_t initial_size, size_t bpl, size_t ppl) rb->green_extra = 0; rb->blue_extra = 0; rb->complete_count = 0; - + return rb; } @@ -260,7 +260,7 @@ ring_expand (ring_buffer *rb, size_t amount) DBG(23, "ring_expand: old, new, inc size: %lu, %lu, %lu\n", (u_long)oldsize, (u_long)rb->size, (u_long)amount); DBG(23, "ring_expand: old tr: %lu tg: %lu tb: %lu hc: %lu\n", - (u_long)rb->tail_red, (u_long)rb->tail_green, + (u_long)rb->tail_red, (u_long)rb->tail_green, (u_long)rb->tail_blue, (u_long)rb->head_complete); /* if necessary, move data and fix up them pointers */ /* (will break subtly if ring is filled with G or B bytes, @@ -276,20 +276,20 @@ ring_expand (ring_buffer *rb, size_t amount) oldsize - rb->head_complete); if ((rb->tail_red > rb->head_complete) || ((rb->tail_red == rb->head_complete) && - !(rb->complete_count) && !(rb->red_extra))) + !(rb->complete_count) && !(rb->red_extra))) rb->tail_red += amount; if ((rb->tail_green > rb->head_complete) || ((rb->tail_green == rb->head_complete) && - !(rb->complete_count) && !(rb->green_extra))) + !(rb->complete_count) && !(rb->green_extra))) rb->tail_green += amount; if ((rb->tail_blue > rb->head_complete) || ((rb->tail_blue == rb->head_complete) && - !(rb->complete_count) && !(rb->blue_extra))) + !(rb->complete_count) && !(rb->blue_extra))) rb->tail_blue += amount; rb->head_complete += amount; } DBG(23, "ring_expand: new tr: %lu tg: %lu tb: %lu hc: %lu\n", - (u_long)rb->tail_red, (u_long)rb->tail_green, + (u_long)rb->tail_red, (u_long)rb->tail_green, (u_long)rb->tail_blue, (u_long)rb->head_complete); return SANE_STATUS_GOOD; } @@ -320,13 +320,13 @@ ring_free (ring_buffer *rb) /* typically misinterpreted/munged by the low-level scsi driver) */ /********************************************************************/ static SANE_Status -sense_handler (int scsi_fd, u_char *sense, void *arg) +sense_handler (int scsi_fd, u_char *sense, void *arg) { int *sense_flags = (int *)arg; SANE_Status stat; DBG(10, "SENSE! fd = %d\n", scsi_fd); - DBG(10, "sense = %02x %02x %02x %02x.\n", + DBG(10, "sense = %02x %02x %02x %02x.\n", sense[0], sense[1], sense[2], sense[3]); switch(sense[0]) { case 0x00: @@ -340,7 +340,7 @@ sense_handler (int scsi_fd, u_char *sense, void *arg) DBG(10, "sense: ERR_SCSICMD\n"); stat = SANE_STATUS_IO_ERROR; } - } + } if (sense[1] & 0x02) { DBG(10, "sense: ERR_TOOMANY\n"); stat = SANE_STATUS_IO_ERROR; @@ -394,7 +394,7 @@ wait_ready(Microtek_Scanner *ms) int retry = 0; DBG(23, ".wait_ready %d...\n", ms->sfd); - while ((status = sanei_scsi_cmd(ms->sfd, comm, 6, 0, 0)) + while ((status = sanei_scsi_cmd(ms->sfd, comm, 6, 0, 0)) != SANE_STATUS_GOOD) { DBG(23, "wait_ready failed (%d)\n", retry); if (retry > 5) return SANE_STATUS_IO_ERROR; /* XXXXXXXX */ @@ -403,7 +403,7 @@ wait_ready(Microtek_Scanner *ms) } return SANE_STATUS_GOOD; } - + /********************************************************************/ /* send scan region coordinates */ @@ -432,7 +432,7 @@ scanning_frame(Microtek_Scanner *ms) ms->x1, ms->y1, ms->x2, ms->y2); DBG(23, ".scanning_frame: out- %d,%d %d,%d\n", x1, y1, x2, y2); data = comm + 6; - data[0] = + data[0] = ((ms->unit_type == MS_UNIT_PIXELS) ? 0x08 : 0 ) | ((ms->mode == MS_MODE_HALFTONE) ? 0x01 : 0 ); data[1] = x1 & 0xFF; @@ -444,7 +444,7 @@ scanning_frame(Microtek_Scanner *ms) data[7] = y2 & 0xFF; data[8] = (y2 >> 8) & 0xFF; if (DBG_LEVEL >= 192) { - int i; + int i; #if 0 fprintf(stderr, "SF: "); for (i=0;i<6+0x09;i++) fprintf(stderr, "%2x ", comm[i]); @@ -468,8 +468,8 @@ mode_select(Microtek_Scanner *ms) uint8_t *data, comm[19] = { 0x15, 0, 0, 0, 0, 0 }; DBG(23, ".mode_select %d...\n", ms->sfd); - data = comm + 6; - data[0] = + data = comm + 6; + data[0] = 0x81 | ((ms->unit_type == MS_UNIT_18INCH) ? 0 : 0x08) | ((ms->res_type == MS_RES_5PER) ? 0 : 0x02); @@ -488,8 +488,8 @@ mode_select(Microtek_Scanner *ms) comm[4] = (ms->midtone_support) ? 0x0B : 0x0A; if (DBG_LEVEL >= 192) { - int i; -#if 0 + int i; +#if 0 fprintf(stderr, "MSL: "); for (i=0;i<6+comm[4];i++) fprintf(stderr, "%2x ", comm[i]); fprintf(stderr, "\n"); @@ -518,8 +518,8 @@ mode_select_1(Microtek_Scanner *ms) data[3] = ((ms->allow_calibrate) ? 0 : 0x02); /* | 0x01; */ if (DBG_LEVEL >= 192) { - int i; -#if 0 + int i; +#if 0 fprintf(stderr, "MSL1: "); for (i=0;i<6+0x0A;i++) fprintf(stderr, "%2x ", comm[i]); fprintf(stderr, "\n"); @@ -532,7 +532,7 @@ mode_select_1(Microtek_Scanner *ms) } - + /********************************************************************/ /* record mode_sense results in the mode_sense buffer */ /* (this is to tell if something catastrophic has happened */ @@ -556,7 +556,7 @@ save_mode_sense(Microtek_Scanner *ms) for (i=0; i<10; i++) ms->mode_sense_cache[i] = data[i]; if (DBG_LEVEL >= 192) { - unsigned int i; + unsigned int i; #if 0 fprintf(stderr, "SMS: "); for (i=0;isfd, comm, 6, data, &lenp); *match = 1; - for (i=0; i<10; i++) + for (i=0; i<10; i++) *match = *match && (ms->mode_sense_cache[i] == data[i]); if (DBG_LEVEL >= 192) { - unsigned int i; + unsigned int i; #if 0 fprintf(stderr, "CMS: "); - for (i=0;imode_sense_cache[i]); fprintf(stderr, "\n"); #endif MDBG_INIT("CMS: "); - for (i=0;imode_sense_cache[i]); MDBG_FINISH(192); @@ -611,10 +611,10 @@ compare_mode_sense(Microtek_Scanner *ms, int *match) return status; } - + /********************************************************************/ /* send mode_sense_1, and upset every scsi driver known to mankind */ -/********************************************************************/ +/********************************************************************/ #if 0 static SANE_Status mode_sense_1(Microtek_Scanner *ms) @@ -628,7 +628,7 @@ mode_sense_1(Microtek_Scanner *ms) data[2] = ms->bright_g; data[3] = ms->bright_b; if (DBG_LEVEL >= 192) { - int i; + int i; fprintf(stderr, "MS1: "); for (i=0;i<6+0x1E;i++) fprintf(stderr, "%2x ", comm[i]); fprintf(stderr, "\n"); @@ -639,23 +639,23 @@ mode_sense_1(Microtek_Scanner *ms) -/********************************************************************/ +/********************************************************************/ /* send "accessory" command */ -/********************************************************************/ +/********************************************************************/ static SANE_Status accessory(Microtek_Scanner *ms) { uint8_t comm[6] = { 0x10, 0, 0, 0, 0, 0 }; DBG(23, ".accessory...\n"); - comm[4] = + comm[4] = ((ms->useADF) ? 0x41 : 0x40) | ((ms->prescan) ? 0x18 : 0x10) | ((ms->transparency) ? 0x24 : 0x20) | ((ms->allowbacktrack) ? 0x82 : 0x80); if (DBG_LEVEL >= 192) { - int i; + int i; #if 0 fprintf(stderr, "AC: "); for (i=0;i<6;i++) fprintf(stderr, "%2x ", comm[i]); @@ -670,16 +670,16 @@ accessory(Microtek_Scanner *ms) -/********************************************************************/ +/********************************************************************/ /* start the scanner a-scannin' */ -/********************************************************************/ +/********************************************************************/ static SANE_Status start_scan(Microtek_Scanner *ms) { uint8_t comm[6] = { 0x1B, 0, 0, 0, 0, 0 }; DBG(23, ".start_scan...\n"); - comm[4] = + comm[4] = 0x01 | /* "start" */ ((ms->expandedresolution) ? 0x80 : 0) | ((ms->multibit) ? 0x40 : 0) | @@ -691,7 +691,7 @@ start_scan(Microtek_Scanner *ms) ((ms->filter == MS_FILT_BLUE) ? 0x18 : 0) ; if (DBG_LEVEL >= 192) { - int i; + int i; #if 0 fprintf(stderr, "SS: "); for (i=0;i<6;i++) fprintf(stderr, "%2x ", comm[i]); @@ -706,9 +706,9 @@ start_scan(Microtek_Scanner *ms) -/********************************************************************/ +/********************************************************************/ /* stop the scanner a-scannin' */ -/********************************************************************/ +/********************************************************************/ static SANE_Status stop_scan(Microtek_Scanner *ms) { @@ -716,8 +716,8 @@ stop_scan(Microtek_Scanner *ms) DBG(23, ".stop_scan...\n"); if (DBG_LEVEL >= 192) { - int i; -#if 0 + int i; +#if 0 fprintf(stderr, "SPS:"); for (i=0;i<6;i++) fprintf(stderr, "%2x ", comm[i]); fprintf(stderr, "\n"); @@ -729,11 +729,11 @@ stop_scan(Microtek_Scanner *ms) return sanei_scsi_cmd(ms->sfd, comm, 6, 0, 0); } - -/********************************************************************/ + +/********************************************************************/ /* get scan status */ -/********************************************************************/ +/********************************************************************/ static SANE_Status get_scan_status(Microtek_Scanner *ms, SANE_Int *busy, @@ -758,8 +758,8 @@ get_scan_status(Microtek_Scanner *ms, *busy = data[0]; *bytes_per_line = (data[1]) + (data[2] << 8); *lines = (data[3]) + (data[4] << 8) + (data[5] << 16); - - DBG(20, "get_scan_status(%lu): %d, %d, %d -> #%d\n", + + DBG(20, "get_scan_status(%lu): %d, %d, %d -> #%d\n", (u_long) lenp, *busy, *bytes_per_line, *lines, retry); DBG(20, "> %2x %2x %2x %2x %2x %2x\n", data[0], data[1], data[2], data[3], data[4], data[5]); @@ -770,20 +770,20 @@ get_scan_status(Microtek_Scanner *ms, sleep(M_GSS_WAIT * retry); } } while ((*busy != 0) && (retry < 4)); - + if (*busy == 0) return status; else return SANE_STATUS_IO_ERROR; } -/********************************************************************/ +/********************************************************************/ /* get scanlines from scanner */ -/********************************************************************/ +/********************************************************************/ static SANE_Status read_scan_data(Microtek_Scanner *ms, int lines, - uint8_t *buffer, + uint8_t *buffer, size_t *bufsize) { uint8_t comm[6] = { 0x08, 0, 0, 0, 0, 0 }; @@ -792,15 +792,15 @@ read_scan_data(Microtek_Scanner *ms, comm[2] = (lines >> 16) & 0xFF; comm[3] = (lines >> 8) & 0xFF; comm[4] = (lines) & 0xFF; - + return sanei_scsi_cmd(ms->sfd, comm, 6, buffer, bufsize); } - - -/********************************************************************/ + + +/********************************************************************/ /* download color LUT to scanner (if it takes one) */ -/********************************************************************/ +/********************************************************************/ static SANE_Status download_gamma(Microtek_Scanner *ms) { @@ -824,7 +824,7 @@ download_gamma(Microtek_Scanner *ms) } max_entry = (1 << bit_depth) - 1; - + DBG(23, ".download_gamma: %d entries of %d bytes, max %d\n", ms->gamma_entries, ms->gamma_entry_size, max_entry); commsize = 10 + (ms->gamma_entries * ms->gamma_entry_size); @@ -835,7 +835,7 @@ download_gamma(Microtek_Scanner *ms) return SANE_STATUS_NO_MEM; } data = comm + 10; - + comm[0] = 0x55; comm[1] = 0; comm[2] = 0x27; @@ -873,9 +873,9 @@ download_gamma(Microtek_Scanner *ms) do { SANE_Int *pl_lut; switch (pl) { - case 1: pl_lut = ms->red_lut; break; - case 2: pl_lut = ms->green_lut; break; - case 3: pl_lut = ms->blue_lut; break; + case 1: pl_lut = ms->red_lut; break; + case 2: pl_lut = ms->green_lut; break; + case 3: pl_lut = ms->blue_lut; break; default: DBG(23, ".download_gamma: uh, exceeded pl bound!\n"); free(comm); @@ -906,7 +906,7 @@ download_gamma(Microtek_Scanner *ms) if (ms->val[OPT_GAMMA_BIND].w == SANE_TRUE) { double gamma = SANE_UNFIX(ms->val[OPT_ANALOG_GAMMA].w); for (i=0; igamma_entries; i++) { - int val = (max_entry * + int val = (max_entry * pow((double) i / ((double) ms->gamma_entries - 1.0), 1.0 / gamma)); switch (ms->gamma_entry_size) { @@ -931,7 +931,7 @@ download_gamma(Microtek_Scanner *ms) default: gamma = 1.0; break; /* should never happen */ } for (i=0; igamma_entries; i++) { - int val = (max_entry * + int val = (max_entry * pow((double) i / ((double) ms->gamma_entries - 1.0), 1.0 / gamma)); switch (ms->gamma_entry_size) { @@ -949,15 +949,15 @@ download_gamma(Microtek_Scanner *ms) pl++; } while ((pl < 4) && (status == SANE_STATUS_GOOD)); } - } else { + } else { /***** No custom Gamma *****/ DBG(23, ".download_gamma: by default\n"); for (i=0; igamma_entries; i++) { /* int val = (((double) max_entry * (double) i / ((double) ms->gamma_entries - 1.0)) + 0.5); ROUNDING????*/ - int val = + int val = (double) max_entry * (double) i / - ((double) ms->gamma_entries - 1.0); + ((double) ms->gamma_entries - 1.0); switch (ms->gamma_entry_size) { case 1: data[i] = (uint8_t) val; @@ -975,9 +975,9 @@ download_gamma(Microtek_Scanner *ms) } -/********************************************************************/ +/********************************************************************/ /* magic command to start calibration */ -/********************************************************************/ +/********************************************************************/ static SANE_Status start_calibration(Microtek_Scanner *ms) { @@ -985,7 +985,7 @@ start_calibration(Microtek_Scanner *ms) DBG(23, ".start_calibrate...\n"); if (DBG_LEVEL >= 192) { - int i; + int i; #if 0 fprintf(stderr, "STCal:"); for (i=0;i<8;i++) fprintf(stderr, "%2x ", comm[i]); @@ -995,14 +995,14 @@ start_calibration(Microtek_Scanner *ms) for (i=0;i<8;i++) MDBG_ADD("%2x ", comm[i]); MDBG_FINISH(192); } - return sanei_scsi_cmd(ms->sfd, comm, 8, 0, 0); + return sanei_scsi_cmd(ms->sfd, comm, 8, 0, 0); } - -/********************************************************************/ + +/********************************************************************/ /* magic command to download calibration values */ -/********************************************************************/ +/********************************************************************/ static SANE_Status download_calibration(Microtek_Scanner *ms, uint8_t *comm, uint8_t letter, int linewidth) @@ -1042,7 +1042,7 @@ download_calibration(Microtek_Scanner *ms, uint8_t *comm, /********************************************************************/ /* Initialize the options registry */ /********************************************************************/ -static SANE_Status +static SANE_Status init_options(Microtek_Scanner *ms) { int i; @@ -1136,7 +1136,7 @@ init_options(Microtek_Scanner *ms) sod[OPT_NEGATIVE].title = SANE_TITLE_NEGATIVE; sod[OPT_NEGATIVE].desc = SANE_DESC_NEGATIVE; sod[OPT_NEGATIVE].type = SANE_TYPE_BOOL; - sod[OPT_NEGATIVE].cap |= + sod[OPT_NEGATIVE].cap |= (ms->dev->info.modes & MI_MODES_NEGATIVE) ? 0 : SANE_CAP_INACTIVE; val[OPT_NEGATIVE].w = SANE_FALSE; @@ -1171,7 +1171,7 @@ init_options(Microtek_Scanner *ms) source_list[i] = NULL; sod[OPT_SOURCE].constraint.string_list = source_list; sod[OPT_SOURCE].size = max_string_size(source_list); - if (i < 2) + if (i < 2) sod[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; val[OPT_SOURCE].s = strdup(source_list[0]); } @@ -1179,7 +1179,7 @@ init_options(Microtek_Scanner *ms) sod[OPT_PREVIEW].name = SANE_NAME_PREVIEW; sod[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; sod[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; - sod[OPT_PREVIEW].type = SANE_TYPE_BOOL; + sod[OPT_PREVIEW].type = SANE_TYPE_BOOL; sod[OPT_PREVIEW].unit = SANE_UNIT_NONE; sod[OPT_PREVIEW].size = sizeof(SANE_Word); val[OPT_PREVIEW].w = SANE_FALSE; @@ -1224,10 +1224,10 @@ init_options(Microtek_Scanner *ms) sod[OPT_BR_Y].unit = SANE_UNIT_MM; sod[OPT_BR_Y].size = sizeof(SANE_Word); sod[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; - - sod[OPT_TL_X].constraint.range = + + sod[OPT_TL_X].constraint.range = sod[OPT_BR_X].constraint.range = &(ms->dev->info.doc_x_range); - sod[OPT_TL_Y].constraint.range = + sod[OPT_TL_Y].constraint.range = sod[OPT_BR_Y].constraint.range = &(ms->dev->info.doc_y_range); /* set default scan region to be maximum size */ @@ -1262,7 +1262,7 @@ init_options(Microtek_Scanner *ms) sod[OPT_BRIGHTNESS].type = SANE_TYPE_INT; sod[OPT_BRIGHTNESS].unit = SANE_UNIT_PERCENT; sod[OPT_BRIGHTNESS].size = sizeof(SANE_Word); - sod[OPT_BRIGHTNESS].cap |= + sod[OPT_BRIGHTNESS].cap |= ((ms->dev->info.extra_cap & MI_EXCAP_OFF_CTL) ? 0: SANE_CAP_INACTIVE); sod[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; sod[OPT_BRIGHTNESS].constraint.range = &brightness_range; @@ -1308,8 +1308,8 @@ init_options(Microtek_Scanner *ms) } else { sod[OPT_HIGHLIGHT].cap |= SANE_CAP_INACTIVE; sod[OPT_SHADOW].cap |= SANE_CAP_INACTIVE; - } - + } + sod[OPT_MIDTONE].name = "midtone"; sod[OPT_MIDTONE].title = "Midtone Level"; sod[OPT_MIDTONE].desc = "Midtone Level"; @@ -1465,7 +1465,7 @@ init_options(Microtek_Scanner *ms) if (!(ms->do_real_calib)) { sod[OPT_CALIB_ONCE].cap |= SANE_CAP_INACTIVE; val[OPT_CALIB_ONCE].w = SANE_FALSE; - } else + } else val[OPT_CALIB_ONCE].w = SANE_TRUE; /* @@ -1499,7 +1499,7 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) 0x32,0x2e,0x33,0x30,0x53,0x43,0x53,0x49,0x20,0x46,0x2f,0x57,0x56,0x33,0x2e,0x31, 0x20,0x43,0x54,0x4c,0x35,0x33,0x38,0x30,0x03,0x4f,0x8c,0xc5,0x00,0xee,0x5b,0x43, 0x01,0x01,0x02,0x00,0x00,0x03,0x00,0x01,0x00,0x4a,0x01,0x04,0x00,0x00,0x00,0x00, - 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff }; #endif DBG(15, "parse_inquiry...\n"); @@ -1511,14 +1511,14 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) mi->model_name[16] = 0; mi->revision_num[4] = 0; mi->vendor_string[20] = 0; - + mi->device_type = (SANE_Byte)(result[0] & 0x1f); mi->SCSI_firmware_ver_major = (SANE_Byte)((result[1] & 0xf0) >> 4); mi->SCSI_firmware_ver_minor = (SANE_Byte)(result[1] & 0x0f); mi->scanner_firmware_ver_major = (SANE_Byte)((result[2] & 0xf0) >> 4); mi->scanner_firmware_ver_minor = (SANE_Byte)(result[2] & 0x0f); mi->response_data_format = (SANE_Byte)(result[3]); - + mi->res_step = (SANE_Byte)(result[56] & 0x03); mi->modes = (SANE_Byte)(result[57]); mi->pattern_count = (SANE_Int)(result[58] & 0x7f); @@ -1526,7 +1526,7 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) mi->feed_type = (SANE_Byte)(result[59] & 0x0F); mi->compress_type = (SANE_Byte)(result[59] & 0x30); mi->unit_type = (SANE_Byte)(result[59] & 0xC0); - + mi->doc_size_code = (SANE_Byte)result[60]; /* we'll compute the max sizes after we know base resolution... */ @@ -1536,7 +1536,7 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) mi->cont_settings = (SANE_Int)(result[72]); mi->min_contrast = -42; mi->max_contrast = (mi->cont_settings * 7) - 49; - + mi->exp_settings = (SANE_Int)(result[61] & 0x0f); if ((SANE_Int)(result[73])) mi->exp_settings = (SANE_Int)(result[73]); @@ -1548,7 +1548,7 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) mi->max_contrast = 49; if (mi->contrast_vals) mi->max_contrast = (mi->contrast_vals * 7) - 49; - + mi->exposure_vals = (SANE_Int)(result[73]); mi->min_exposure = -18; mi->max_exposure = 21; @@ -1606,7 +1606,7 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) mi->max_x = 8.5 * mi->base_resolution - 1; mi->max_y = 14.0 * mi->base_resolution - 1; break; - case 0x01: + case 0x01: mi->max_x = 8.5 * mi->base_resolution - 1; mi->max_y = 11.0 * mi->base_resolution - 1; break; @@ -1625,15 +1625,15 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) case 0x05: mi->max_x = 8.3 * mi->base_resolution - 1; mi->max_y = 14.0 * mi->base_resolution - 1; - break; + break; case 0x06: mi->max_x = 8.3 * mi->base_resolution - 1; mi->max_y = 13.5 * mi->base_resolution - 1; - break; + break; case 0x07: mi->max_x = 8.0 * mi->base_resolution - 1; mi->max_y = 14.0 * mi->base_resolution - 1; - break; + break; case 0x80: /* Slide format, size is mm */ mi->max_x = (35.0 / MM_PER_INCH) * mi->base_resolution - 1; @@ -1666,9 +1666,9 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) mi->doc_y_range.max = SANE_FIX((float)mi->max_y / base_res_dpmm); mi->doc_y_range.quant = SANE_FIX(0); } - - mi->source_options = (SANE_Byte)(result[63]); - + + mi->source_options = (SANE_Byte)(result[63]); + mi->expanded_resolution = (result[64] & 0x01); /* my E6 reports exp-res capability incorrectly */ if ((mi->model_code == 0x66) || (mi->model_code == 0x63)) { @@ -1685,27 +1685,27 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) mi->enhance_cap = (result[65] & 0x03); - /* + /* switch (result[66] & 0x0F) { case 0x00: mi->max_lookup_size = 0; break; case 0x01: mi->max_lookup_size = 256; break; case 0x03: mi->max_lookup_size = 1024; break; case 0x05: mi->max_lookup_size = 4096; break; case 0x09: mi->max_lookup_size = 65536; break; - default: + default: mi->max_lookup_size = 0; DBG(15, "parse_inquiry: Unknown gamma LUT size! 0x%x\n", result[66]); } */ - + /* This is not how the vague documentation specifies this register. We're going to take it literally here -- i.e. if the bit is set, the scanner supports the value, otherwise it doesn't. (The docs say all lower values are always supported. This is - not the case for the StudioScan IIsi, at least, which only + not the case for the StudioScan IIsi, at least, which only specifies 0x02==1024-byte table, and only supports that, too.) - + All-in-all, it doesn't matter, since we take the largest allowed LUT size anyway. */ @@ -1717,7 +1717,7 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) mi->max_lookup_size = 1024; else if (result[66] & 0x01) mi->max_lookup_size = 256; - else + else mi->max_lookup_size = 0; /* my E6 reports incorrectly */ @@ -1748,13 +1748,13 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) DBG(15, "parse_inquiry: Unknown gamma max val! 0x%x\n", result[66]); } - + mi->fast_color_preview = (SANE_Byte)(result[67] & 0x01); mi->xfer_format_select = (SANE_Byte)(result[68] & 0x01); mi->color_sequence = (SANE_Byte)(result[69] & 0x7f); mi->does_3pass = (SANE_Byte)(!(result[69] & 0x80)); mi->does_mode1 = (SANE_Byte)(result[71] & 0x01); - + mi->bit_formats = (SANE_Byte)(result[74] & 0x0F); mi->extra_cap = (SANE_Byte)(result[75] & 0x07); @@ -1780,7 +1780,7 @@ parse_inquiry(Microtek_Info *mi, unsigned char *result) /********************************************************************/ /* Dump all we know about scanner to stderr */ /********************************************************************/ -static SANE_Status +static SANE_Status dump_inquiry(Microtek_Info *mi, unsigned char *result) { int i; @@ -1802,12 +1802,12 @@ dump_inquiry(Microtek_Info *mi, unsigned char *result) mi->vendor_id, mi->model_name); DBG(1, "Vendor Specific String: '%s'\n", mi->vendor_string); DBG(1, "Firmware Rev: '%s'\n", mi->revision_num); - DBG(1, + DBG(1, "SCSI F/W version: %1d.%1d Scanner F/W version: %1d.%1d\n", mi->SCSI_firmware_ver_major, mi->SCSI_firmware_ver_minor, mi->scanner_firmware_ver_major, mi->scanner_firmware_ver_minor); DBG(1, "Response data format: 0x%02x\n", mi->response_data_format); - + DBG(1, "===== Imaging Capabilities...\n"); DBG(1, "Modes: %s%s%s%s%s%s%s\n", (mi->modes & MI_MODES_LINEART) ? "Lineart " : "", @@ -1817,7 +1817,7 @@ dump_inquiry(Microtek_Info *mi, unsigned char *result) (mi->modes & MI_MODES_TRANSMSV) ? "(X-msv) " : "", (mi->modes & MI_MODES_ONEPASS) ? "(OnePass) " : "", (mi->modes & MI_MODES_NEGATIVE) ? "(Negative) " : ""); - DBG(1, + DBG(1, "Resolution Step Sizes: %s%s Expanded Resolution Support? %s%s\n", (mi->res_step & MI_RESSTEP_1PER) ? "1% " : "", (mi->res_step & MI_RESSTEP_5PER) ? "5%" : "", @@ -1849,11 +1849,11 @@ dump_inquiry(Microtek_Info *mi, unsigned char *result) DBG(1, "Digital brightness/offset? %s\n", (mi->extra_cap & MI_EXCAP_OFF_CTL) ? "yes" : "no"); /* - fprintf(stderr, + fprintf(stderr, "Gamma Table Size: %d entries of %d bytes (max. value: %d)\n", mi->max_lookup_size, mi->gamma_size, mi->max_gamma_val); */ - DBG(1, + DBG(1, "Gamma Table Size: %d entries of %d bytes (max. depth: %d)\n", mi->max_lookup_size, mi->gamma_size, mi->max_gamma_bit_depth); @@ -1861,7 +1861,7 @@ dump_inquiry(Microtek_Info *mi, unsigned char *result) DBG(1, "Feed type: %s%s ADF support? %s\n", (mi->feed_type & MI_FEED_FLATBED) ? "flatbed " : "", (mi->feed_type & MI_FEED_EDGEFEED) ? "edge-feed " : "", - (mi->feed_type & MI_FEED_AUTOSUPP) ? "yes" : "no"); + (mi->feed_type & MI_FEED_AUTOSUPP) ? "yes" : "no"); DBG(1, "Document Feeder Support? %s Feeder Backtracking? %s\n", (mi->source_options & MI_SRC_FEED_SUPP) ? "yes" : "no ", (mi->source_options & MI_SRC_FEED_BT) ? "yes" : "no "); @@ -1882,15 +1882,15 @@ dump_inquiry(Microtek_Info *mi, unsigned char *result) (mi->xfer_format_select) ? "yes" : "no"); MDBG_INIT("Color Transfer Sequence: "); switch (mi->color_sequence) { - case MI_COLSEQ_PLANE: + case MI_COLSEQ_PLANE: MDBG_ADD("plane-by-plane (3-pass)"); break; - case MI_COLSEQ_PIXEL: + case MI_COLSEQ_PIXEL: MDBG_ADD("pixel-by-pixel RGB"); break; case MI_COLSEQ_RGB: MDBG_ADD("line-by-line, R-G-B sequence"); break; case MI_COLSEQ_NONRGB: MDBG_ADD("line-by-line, non-sequential with headers"); break; - case MI_COLSEQ_2PIXEL: + case MI_COLSEQ_2PIXEL: MDBG_ADD("2pixel-by-2pixel RRGGBB"); break; default: MDBG_ADD("UNKNOWN CODE (0x%02x)", mi->color_sequence); @@ -1905,7 +1905,7 @@ dump_inquiry(Microtek_Info *mi, unsigned char *result) (mi->extra_cap & MI_EXCAP_DIS_LNTBL) ? "yes" : "no"); DBG(1, "Can Disable Start-of-Scan Recalibration? %s\n", (mi->extra_cap & MI_EXCAP_DIS_RECAL) ? "yes" : "no"); - + DBG(1, "Internal expanded expansion? %s\n", mi->does_expansion ? "yes" : "no"); /* @@ -1922,7 +1922,7 @@ dump_inquiry(Microtek_Info *mi, unsigned char *result) /********************************************************************/ /* Dump all we know about some unknown scanner to stderr */ /********************************************************************/ -static SANE_Status +static SANE_Status dump_suspect_inquiry(unsigned char *result) { int i; @@ -1953,7 +1953,7 @@ dump_suspect_inquiry(unsigned char *result) strncpy(revision_num, (char *)&result[32], 4); vendor_id[8] = 0; model_name[16] = 0; - revision_num[5] = 0; + revision_num[5] = 0; device_type = (SANE_Byte)(result[0] & 0x1f); SCSI_firmware_ver_major = (SANE_Byte)((result[1] & 0xf0) >> 4); SCSI_firmware_ver_minor = (SANE_Byte)(result[1] & 0x0f); @@ -1969,7 +1969,7 @@ dump_suspect_inquiry(unsigned char *result) DBG(1, "Vendor Name: '%s' Model Name: '%s'\n", vendor_id, model_name); DBG(1, "Firmware Rev: '%s'\n", revision_num); - DBG(1, + DBG(1, "SCSI F/W version: %1d.%1d Scanner F/W version: %1d.%1d\n", SCSI_firmware_ver_major, SCSI_firmware_ver_minor, scanner_firmware_ver_major, scanner_firmware_ver_minor); @@ -2035,7 +2035,7 @@ id_microtek(uint8_t *result, char **model_string) case 0x5f : *model_string = "ScanMaker E3"; break; case 0x62 : - if (!(strncmp("Polaroid", (char *)&(result[8]), 8))) + if (!(strncmp("Polaroid", (char *)&(result[8]), 8))) *model_string = "Polaroid SprintScan 35/LE"; else *model_string = "ScanMaker 35t+"; @@ -2123,7 +2123,7 @@ id_microtek(uint8_t *result, char **model_string) /********************************************************************/ /* Try to attach a device as a Microtek scanner */ /********************************************************************/ -static SANE_Status +static SANE_Status attach_scanner(const char *devicename, Microtek_Device **devp) { Microtek_Device *dev; @@ -2165,7 +2165,7 @@ attach_scanner(const char *devicename, Microtek_Device **devp) if (DBG_LEVEL >= 5) dump_suspect_inquiry(result); return SANE_STATUS_INVAL; } - + dev=malloc(sizeof(*dev)); if (!dev) return SANE_STATUS_NO_MEM; memset(dev, 0, sizeof(*dev)); @@ -2217,7 +2217,7 @@ static SANE_Status end_scan(Microtek_Scanner *s, SANE_Status ostat) /* stop the scanner */ if (s->scan_started) { status = stop_scan(s); - if (status != SANE_STATUS_GOOD) + if (status != SANE_STATUS_GOOD) DBG(23, "end_scan: OY! on stop_scan\n"); s->scan_started = SANE_FALSE; } @@ -2285,7 +2285,7 @@ static void sort_values(int *result, uint8_t *scanline[], int pix) /********************************************************************/ -static void calc_calibration(uint8_t *caldata, uint8_t *scanline[], +static void calc_calibration(uint8_t *caldata, uint8_t *scanline[], int pixels) { int i,j; @@ -2303,14 +2303,14 @@ static void calc_calibration(uint8_t *caldata, uint8_t *scanline[], q3 = sorted[STRIPS * 3 / 4]; /* third quartile */ bot = q1 - 3 * (q3 - q1) / 2; /* quick'n'easy bounds */ top = q3 + 3 * (q3 - q1) / 2; - + for (j=0; j= bot) && (sorted[j] <= top)) { sum += sorted[j]; count++; } } - if (count) + if (count) caldata[i] = (sum + (count / 2)) / count; else { DBG(23, "zero: i=%d b/t=%d/%d ", i, bot, top); @@ -2343,9 +2343,9 @@ static SANE_Status do_real_calibrate(Microtek_Scanner *s) uint8_t letter; int i, spot; int nmax, ntoget, nleft; - + DBG(10, "do_real_calibrate...\n"); - + /* tell scanner to read it's little chart */ if ((status = start_calibration(s)) != SANE_STATUS_GOOD) return status; if ((status = get_scan_status(s, &busy, &linewidth, &lines)) @@ -2372,7 +2372,7 @@ static SANE_Status do_real_calibrate(Microtek_Scanner *s) buffsize = ntoget * 3 * linewidth; DBG(23, "...nleft %d toget %d size %lu spot %d input+spot %p\n", nleft, ntoget, (u_long) buffsize, spot, input+spot); - if ((statusA = read_scan_data(s, ntoget, input+spot, &buffsize)) + if ((statusA = read_scan_data(s, ntoget, input+spot, &buffsize)) != SANE_STATUS_GOOD) { DBG(23, "...read scan failed\n"); break; @@ -2409,7 +2409,7 @@ static SANE_Status do_real_calibrate(Microtek_Scanner *s) switch (letter) { case 'R': letter = 'G'; break; case 'G': letter = 'B'; break; - case 'B': + case 'B': default: letter = 'X'; break; } } @@ -2431,9 +2431,9 @@ static SANE_Status do_precalibrate(SANE_Handle handle) Microtek_Scanner *s = handle; SANE_Status status, statusA; SANE_Int busy, linewidth, lines; - + DBG(10, "do_precalibrate...\n"); - + if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return status; { SANE_Int y1 = s->y1; @@ -2441,7 +2441,7 @@ static SANE_Status do_precalibrate(SANE_Handle handle) /* some small range, but large enough to cause the scanner to think it'll scan *something*... */ s->y1 = 0; - s->y2 = + s->y2 = (s->resolution > s->dev->info.base_resolution) ? 4 : 4 * s->dev->info.base_resolution / s->resolution; status = scanning_frame(s); @@ -2450,7 +2450,7 @@ static SANE_Status do_precalibrate(SANE_Handle handle) if (status != SANE_STATUS_GOOD) return status; } - if (s->dev->info.source_options & + if (s->dev->info.source_options & (MI_SRC_FEED_BT | MI_SRC_HAS_TRANS | MI_SRC_FEED_SUPP | MI_SRC_HAS_FEED)) { /* ZZZZZZZZZZZ */ if ((status = accessory(s)) != SANE_STATUS_GOOD) return status; @@ -2465,10 +2465,10 @@ static SANE_Status do_precalibrate(SANE_Handle handle) s->allow_calibrate = allow_calibrate; if (status != SANE_STATUS_GOOD) return status; } - + if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return status; if ((status = start_scan(s)) != SANE_STATUS_GOOD) return status; - if ((statusA = get_scan_status(s, &busy, + if ((statusA = get_scan_status(s, &busy, &linewidth, &lines)) != SANE_STATUS_GOOD) { DBG(10, "do_precalibrate: get_scan_status fails\n"); } @@ -2492,7 +2492,7 @@ static SANE_Status finagle_precal(SANE_Handle handle) int match; /* try to check if scanner has been reset */ - /* if so, calibrate it + /* if so, calibrate it (either for real, or via a fake scan, with calibration */ /* (but only bother if you *could* disable calibration) */ DBG(23, "finagle_precal...\n"); @@ -2523,7 +2523,7 @@ static SANE_Status finagle_precal(SANE_Handle handle) } else s->precal_record = MS_PRECAL_GRAY; } else - DBG(23, "finagle_precal: no precalibrate necessary.\n"); + DBG(23, "finagle_precal: no precalibrate necessary.\n"); } return SANE_STATUS_GOOD; } @@ -2544,7 +2544,7 @@ set_pass_parameters (SANE_Handle handle) switch (s->this_pass) { case 1: s->filter = MS_FILT_RED; - s->params.format = SANE_FRAME_RED; + s->params.format = SANE_FRAME_RED; s->params.last_frame = SANE_FALSE; break; case 2: @@ -2552,7 +2552,7 @@ set_pass_parameters (SANE_Handle handle) s->params.format = SANE_FRAME_GREEN; s->params.last_frame = SANE_FALSE; break; - case 3: + case 3: s->filter = MS_FILT_BLUE; s->params.format = SANE_FRAME_BLUE; s->params.last_frame = SANE_TRUE; @@ -2588,7 +2588,7 @@ static SANE_Status pack_flat_data(Microtek_Scanner *s, size_t nlines) size_t nbytes = nlines * rb->bpl; size_t start = (rb->head_complete + rb->complete_count) % rb->size; - size_t max_xfer = + size_t max_xfer = (start < rb->head_complete) ? (rb->head_complete - start) : (rb->size - start + rb->head_complete); @@ -2616,14 +2616,14 @@ static SANE_Status pack_flat_data(Microtek_Scanner *s, size_t nlines) size_t i; double x1, x2, n1, n2; for (i = 0, x1 = 0.0, x2 = s->exp_aspect, n1 = 0.0, n2 = floor(x2); - i < rb->bpl; + i < rb->bpl; i++) { byte = 0; - for (bit=0; - bit < 8; + for (bit=0; + bit < 8; bit++, x1 = x2, n1 = n2, x2 += s->exp_aspect, n2 = floor(x2)) { /* #define getbit(byte, index) (((byte)>>(index))&1) */ - byte |= + byte |= (( (x2 == n2) ? (((sb[(int)n1 / 8])>>(7 - ((int)n1) % 8))&1) : @@ -2638,13 +2638,13 @@ static SANE_Status pack_flat_data(Microtek_Scanner *s, size_t nlines) sb += s->pixel_bpl; } } else { /* multibit scan (8 is assumed!) */ - for (line=0; lineexp_aspect, n1 = 0.0, n2 = floor(x2); - i < s->dest_ppl; + i < s->dest_ppl; i++, x1 = x2, n1 = n2, x2 += s->exp_aspect, n2 = floor(x2)) { - db[pos] = + db[pos] = (x2 == n2) ? sb[(int)n1] : (int)(((double)sb[(int)n1] * (n2 - x1) + @@ -2683,12 +2683,12 @@ pack_seqrgb_data (Microtek_Scanner *s, size_t nlines) size_t completed; size_t spot; SANE_Byte id; - + { size_t ar, ag, ab; /* allowed additions */ size_t dr, dg, db; /* additions which will occur */ SANE_Status status; - + dr = dg = db = nlines * rb->bpl; ar = rb->size - (rb->complete_count + rb->red_extra * 3); ag = rb->size - (rb->complete_count + rb->green_extra * 3); @@ -2700,7 +2700,7 @@ pack_seqrgb_data (Microtek_Scanner *s, size_t nlines) if ((dr > ar) || (dg > ag) || (db > ab)) { - size_t increase = 0; + size_t increase = 0; if (dr > ar) increase = (dr - ar); if (dg > ag) increase = MAX(increase, (dg - ag)); if (db > ab) increase = MAX(increase, (db - ab)); @@ -2725,9 +2725,9 @@ pack_seqrgb_data (Microtek_Scanner *s, size_t nlines) int i; double x1, x2, n1, n2; for (i = 0, x1 = 0.0, x2 = s->exp_aspect, n1 = 0.0, n2 = floor(x2); - i < s->dest_ppl; + i < s->dest_ppl; i++, x1 = x2, n1 = n2, x2 += s->exp_aspect, n2 = floor(x2)) { - db[spot] = + db[spot] = (x2 == n2) ? sb[(int)n1] : (int)(((double)sb[(int)n1] * (n2 - x1) + @@ -2756,9 +2756,9 @@ pack_seqrgb_data (Microtek_Scanner *s, size_t nlines) rb->red_extra -= completed; rb->green_extra -= completed; rb->blue_extra -= completed; - + DBG(18, "pack_seq: extra r: %lu g: %lu b: %lu\n", - (u_long)rb->red_extra, + (u_long)rb->red_extra, (u_long)rb->green_extra, (u_long)rb->blue_extra); DBG(18, "pack_seq: completed: %lu complete: %lu\n", @@ -2767,21 +2767,21 @@ pack_seqrgb_data (Microtek_Scanner *s, size_t nlines) return SANE_STATUS_GOOD; } - + /********************************************************************/ /* Process non-sequential R,G, and B scan-lines */ /********************************************************************/ static SANE_Status pack_goofyrgb_data(Microtek_Scanner *s, size_t nlines) { - ring_buffer *rb = s->rb; + ring_buffer *rb = s->rb; unsigned int seg; /* , i;*/ SANE_Byte *db; SANE_Byte *sb = s->scsi_buffer; size_t completed; size_t spot; SANE_Byte id; - + /* prescan to decide if ring should be expanded */ { size_t ar, ag, ab; /* allowed additions */ @@ -2790,7 +2790,7 @@ pack_goofyrgb_data(Microtek_Scanner *s, size_t nlines) SANE_Byte *pt; for (dr = dg = db = 0, seg = 0, pt = s->scsi_buffer + 1; - seg < nlines * 3; + seg < nlines * 3; seg++, pt += s->ppl + 2) { switch (*pt) { case 'R': dr += rb->bpl; break; @@ -2809,7 +2809,7 @@ pack_goofyrgb_data(Microtek_Scanner *s, size_t nlines) if ((dr > ar) || (dg > ag) || (db > ab)) { - size_t increase = 0; + size_t increase = 0; if (dr > ar) increase = (dr - ar); if (dg > ag) increase = MAX(increase, (dg - ag)); if (db > ab) increase = MAX(increase, (db - ab)); @@ -2838,9 +2838,9 @@ pack_goofyrgb_data(Microtek_Scanner *s, size_t nlines) int i; double x1, x2, n1, n2; for (i = 0, x1 = 0.0, x2 = s->exp_aspect, n1 = 0.0, n2 = floor(x2); - i < s->dest_ppl; + i < s->dest_ppl; i++, x1 = x2, n1 = n2, x2 += s->exp_aspect, n2 = floor(x2)) { - db[spot] = + db[spot] = (x2 == n2) ? sb[(int)n1] : (int)(((double)sb[(int)n1] * (n2 - x1) + @@ -2868,9 +2868,9 @@ pack_goofyrgb_data(Microtek_Scanner *s, size_t nlines) rb->red_extra -= completed; rb->green_extra -= completed; rb->blue_extra -= completed; - + DBG(18, "pack_goofy: extra r: %lu g: %lu b: %lu\n", - (u_long)rb->red_extra, + (u_long)rb->red_extra, (u_long)rb->green_extra, (u_long)rb->blue_extra); DBG(18, "pack_goofy: completed: %lu complete: %lu\n", @@ -2878,7 +2878,7 @@ pack_goofyrgb_data(Microtek_Scanner *s, size_t nlines) return SANE_STATUS_GOOD; } - + /********************************************************************/ @@ -2891,14 +2891,14 @@ pack_seq2r2g2b_data(Microtek_Scanner *s, size_t nlines) SANE_Status status; ring_buffer *rb = s->rb; size_t nbytes = nlines * rb->bpl; - + size_t start = (rb->head_complete + rb->complete_count) % rb->size; - size_t max_xfer = + size_t max_xfer = (start < rb->head_complete) ? (rb->head_complete - start) : (rb->size - start + rb->head_complete); size_t length = MIN(nbytes, max_xfer); - + if (nbytes > max_xfer) { DBG(23, "pack_2r2g2b: must expand ring, %lu + %lu\n", (u_long)rb->size, (u_long)(nbytes - max_xfer)); @@ -2908,7 +2908,7 @@ pack_seq2r2g2b_data(Microtek_Scanner *s, size_t nlines) { unsigned int line; int p; - size_t pos = start; + size_t pos = start; SANE_Byte *sb = s->scsi_buffer; SANE_Byte *db = rb->base; @@ -2968,11 +2968,11 @@ read_from_scanner (Microtek_Scanner *s, int *nlines) DBG(18, "read_from_scanner: no gss/no unscanned\n"); remaining = 0; } - + *nlines = MIN(remaining, s->max_scsi_lines); DBG(18, "sane_read: max_scsi: %d, rem: %d, nlines: %d\n", s->max_scsi_lines, remaining, *nlines); - + /* grab them bytes! (only if the scanner still has bytes to give...) */ if (*nlines > 0) { buffsize = *nlines * (s->pixel_bpl + s->header_bpl);/* == "* linewidth" */ @@ -3002,7 +3002,7 @@ pack_into_ring(Microtek_Scanner *s, int nlines) switch (s->line_format) { case MS_LNFMT_FLAT: status = pack_flat_data(s, nlines); break; - case MS_LNFMT_SEQ_RGB: + case MS_LNFMT_SEQ_RGB: status = pack_seqrgb_data(s, nlines); break; case MS_LNFMT_GOOFY_RGB: status = pack_goofyrgb_data(s, nlines); break; @@ -3081,13 +3081,13 @@ sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize) DBG(23, "sane_init: config-> %s\n", dev_name); if (dev_name[0] == '#') continue; /* ignore comments */ if (!(strncmp("noprecal", dev_name, 8))) { - DBG(23, + DBG(23, "sane_init: Clever Precalibration will be forcibly disabled...\n"); inhibit_clever_precal = SANE_TRUE; continue; } if (!(strncmp("norealcal", dev_name, 9))) { - DBG(23, + DBG(23, "sane_init: Real calibration will be forcibly disabled...\n"); inhibit_real_calib = SANE_TRUE; continue; @@ -3106,7 +3106,7 @@ sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize) /* sane_get_devices */ /********************************************************************/ SANE_Status -sane_get_devices(const SANE_Device ***device_list, +sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only) { Microtek_Device *dev; @@ -3168,14 +3168,14 @@ sane_open(SANE_String_Const devicename, /* initialize scanner dependent stuff */ DBG(23, "sane_open: initialize scanner dependent stuff...\n"); /* ZZZZZZZZZZZZZZ */ - scanner->unit_type = + scanner->unit_type = (dev->info.unit_type & MI_UNIT_PIXELS) ? MS_UNIT_PIXELS : MS_UNIT_18INCH; scanner->res_type = (dev->info.res_step & MI_RESSTEP_1PER) ? MS_RES_1PER : MS_RES_5PER; - scanner->midtone_support = + scanner->midtone_support = (dev->info.enhance_cap & MI_ENH_CAP_MIDTONE) ? SANE_TRUE : SANE_FALSE; - scanner->paper_length = - (scanner->unit_type == MS_UNIT_PIXELS) ? + scanner->paper_length = + (scanner->unit_type == MS_UNIT_PIXELS) ? dev->info.max_y : (SANE_Int)((double)dev->info.max_y * 8.0 / (double)dev->info.base_resolution); @@ -3202,7 +3202,7 @@ sane_open(SANE_String_Const devicename, scanner->do_clever_precal = SANE_TRUE; } else { DBG(23, "sane_open: All calibration routines disabled.\n"); - scanner->allow_calibrate = SANE_TRUE; + scanner->allow_calibrate = SANE_TRUE; scanner->do_real_calib = SANE_FALSE; scanner->do_clever_precal = SANE_FALSE; } @@ -3227,7 +3227,7 @@ sane_open(SANE_String_Const devicename, scanner->gray_lut = calloc(scanner->gamma_entries, sizeof(scanner->gray_lut[0])); - scanner->red_lut = calloc(scanner->gamma_entries, + scanner->red_lut = calloc(scanner->gamma_entries, sizeof(scanner->red_lut[0])); scanner->green_lut = calloc(scanner->gamma_entries, sizeof(scanner->green_lut[0])); @@ -3246,7 +3246,7 @@ sane_open(SANE_String_Const devicename, free(scanner->blue_lut); } for (j=0; jgamma_entries; j += scanner->gamma_entry_size) { - v = (SANE_Int) + v = (SANE_Int) ((double) j * (double) max_entry / ((double) scanner->gamma_entries - 1.0) + 0.5); scanner->gray_lut[j] = v; @@ -3278,7 +3278,7 @@ sane_open(SANE_String_Const devicename, /* clear out that clever cache, so it doesn't match anything */ { int j; - for (j=0; j<10; j++) + for (j=0; j<10; j++) scanner->mode_sense_cache[j] = 0; scanner->precal_record = MS_PRECAL_NONE; } @@ -3347,7 +3347,7 @@ sane_get_option_descriptor (SANE_Handle handle, /********************************************************************/ /* sane_control_option */ /********************************************************************/ -SANE_Status +SANE_Status sane_control_option (SANE_Handle handle, SANE_Int option, SANE_Action action, @@ -3429,12 +3429,12 @@ sane_control_option (SANE_Handle handle, return SANE_STATUS_INVAL; } break; - + case SANE_ACTION_SET_VALUE: { status = sanei_constrain_value(sod + option, value, info); if (status != SANE_STATUS_GOOD) return status; - + switch (option) { /* set word options... */ case OPT_TL_X: @@ -3457,12 +3457,12 @@ sane_control_option (SANE_Handle handle, case OPT_ANALOG_GAMMA_B: val[option].w = *(SANE_Word *)value; return SANE_STATUS_GOOD; - + case OPT_HIGHLIGHT: case OPT_SHADOW: case OPT_MIDTONE: val[option].w = *(SANE_Word *)value; - /* we need to (silently) make sure shadow <= midtone <= highlight */ + /* we need to (silently) make sure shadow <= midtone <= highlight */ if (scanner->midtone_support) { if (val[OPT_SHADOW].w > val[OPT_MIDTONE].w) { if (option == OPT_SHADOW) @@ -3514,7 +3514,7 @@ sane_control_option (SANE_Handle handle, val[option].w = *(SANE_Word *) value; } else if (option == OPT_CUSTOM_GAMMA) { if (val[option].s) { - if (strcmp(value, val[option].s)) + if (strcmp(value, val[option].s)) if (info) *info |= SANE_INFO_RELOAD_OPTIONS; free(val[option].s); } @@ -3526,7 +3526,7 @@ sane_control_option (SANE_Handle handle, sod[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; sod[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; sod[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; - } + } if ( !(strcmp(val[OPT_CUSTOM_GAMMA].s, M_NONE)) || !(strcmp(val[OPT_CUSTOM_GAMMA].s, M_TABLE)) ) { sod[OPT_ANALOG_GAMMA].cap |= SANE_CAP_INACTIVE; @@ -3565,12 +3565,12 @@ sane_control_option (SANE_Handle handle, else if (!(strcmp(val[OPT_MODE].s, M_COLOR))) sod[OPT_GAMMA_BIND].cap &= ~SANE_CAP_INACTIVE; return SANE_STATUS_GOOD; - - case OPT_MODE: + + case OPT_MODE: if (val[option].s) { if (strcmp(val[option].s, value)) - if (info) + if (info) *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; free(val[option].s); } @@ -3586,7 +3586,7 @@ sane_control_option (SANE_Handle handle, { SANE_Bool Trueness = SANE_TRUE; SANE_Status status; - status = sane_control_option(handle, + status = sane_control_option(handle, OPT_GAMMA_BIND, SANE_ACTION_SET_VALUE, &Trueness, @@ -3619,7 +3619,7 @@ sane_control_option (SANE_Handle handle, } } break; - + case SANE_ACTION_SET_AUTO: return SANE_STATUS_UNSUPPORTED; /* We are DUMB. */ } @@ -3662,7 +3662,7 @@ sane_get_parameters (SANE_Handle handle, s->threepasscolor = SANE_TRUE; s->onepasscolor = SANE_FALSE; s->color_seq = s->dev->info.color_sequence; - } + } } else { /* not color! */ DBG(23, "sane_get_parameters: non-color\n"); s->threepasscolor = SANE_FALSE; @@ -3673,18 +3673,18 @@ sane_get_parameters (SANE_Handle handle, s->transparency = !(strcmp(s->val[OPT_SOURCE].s, M_TRANS)); s->useADF = !(strcmp(s->val[OPT_SOURCE].s, M_AUTOFEED)); /* disallow exp. res. during preview scan XXXXXXXXXXX */ - /*s->expandedresolution = + /*s->expandedresolution = (s->val[OPT_EXP_RES].w) && !(s->val[OPT_PREVIEW].w);*/ s->expandedresolution = (s->val[OPT_EXP_RES].w); s->doexpansion = (s->expandedresolution && !(s->dev->info.does_expansion)); if (s->res_type == MS_RES_1PER) { s->resolution = (SANE_Int)(SANE_UNFIX(s->val[OPT_RESOLUTION].w)); - s->resolution_code = - 0xFF & ((s->resolution * 100) / + s->resolution_code = + 0xFF & ((s->resolution * 100) / s->dev->info.base_resolution / (s->expandedresolution ? 2 : 1)); - DBG(23, "sane_get_parameters: res_code = %d (%2x)\n", + DBG(23, "sane_get_parameters: res_code = %d (%2x)\n", s->resolution_code, s->resolution_code); } else { DBG(23, "sane_get_parameters: 5 percent!!!\n"); @@ -3725,18 +3725,18 @@ sane_get_parameters (SANE_Handle handle, s->pattern = ((i < s->dev->info.pattern_count) ? i : 0); } else s->pattern = 0; - + { /* need to 'round' things properly! XXXXXXXX */ SANE_Int widthpix; double dots_per_mm = s->resolution / MM_PER_INCH; - double units_per_mm = - (s->unit_type == MS_UNIT_18INCH) ? + double units_per_mm = + (s->unit_type == MS_UNIT_18INCH) ? (8.0 / MM_PER_INCH) : /* 1/8 inches */ (s->dev->info.base_resolution / MM_PER_INCH); /* pixels */ - + DBG(23, "sane_get_parameters: dots_per_mm: %f\n", dots_per_mm); DBG(23, "sane_get_parameters: units_per_mm: %f\n", units_per_mm); @@ -3755,22 +3755,22 @@ sane_get_parameters (SANE_Handle handle, /* these are just an estimate... (but *should* be completely accurate) * real values come from scanner after sane_start. */ - if (s->unit_type == MS_UNIT_18INCH) { + if (s->unit_type == MS_UNIT_18INCH) { /* who *knows* what happens */ - widthpix = + widthpix = (SANE_Int)((double)(s->x2 - s->x1 + 1) / 8.0 * (double)s->resolution); - s->params.lines = + s->params.lines = (SANE_Int)((double)(s->y2 - s->y1 + 1) / 8.0 * (double)s->resolution); } else { /* calculate pixels per scanline returned by scanner... */ /* scanner (E6 at least) always seems to return an -even- number of -bytes- */ - if (s->resolution <= s->dev->info.base_resolution) + if (s->resolution <= s->dev->info.base_resolution) widthpix = (SANE_Int)((double)(s->x2 - s->x1 + 1) * - (double)(s->resolution) / + (double)(s->resolution) / (double)(s->dev->info.base_resolution)); else widthpix = (s->x2 - s->x1 + 1); @@ -3784,14 +3784,14 @@ sane_get_parameters (SANE_Handle handle, } DBG(23, "WIDTHPIX: before exp: %d\n", widthpix); /* ok, now fix up expanded-mode conversions */ - if (s->resolution > s->dev->info.base_resolution) + if (s->resolution > s->dev->info.base_resolution) widthpix = (SANE_Int) ((double)widthpix * (double)s->resolution / (double)s->dev->info.base_resolution); s->params.pixels_per_line = widthpix; - s->params.lines = + s->params.lines = (SANE_Int)((double)(s->y2 - s->y1 + 1) * - (double)(s->resolution) / + (double)(s->resolution) / (double)(s->dev->info.base_resolution)); } } @@ -3822,13 +3822,13 @@ sane_get_parameters (SANE_Handle handle, } else { /* a three-pass color scan */ s->params.depth = s->bits_per_color; /* this will be correctly set in sane_start */ - s->params.format = SANE_FRAME_RED; + s->params.format = SANE_FRAME_RED; s->params.bytes_per_line = s->params.pixels_per_line; } break; } - DBG(23, "sane_get_parameters: lines: %d ppl: %d bpl: %d\n", + DBG(23, "sane_get_parameters: lines: %d ppl: %d bpl: %d\n", s->params.lines, s->params.pixels_per_line, s->params.bytes_per_line); /* also fixed in sane_start for multi-pass scans */ @@ -3852,7 +3852,7 @@ sane_start_guts (SANE_Handle handle) Microtek_Scanner *s = handle; SANE_Status status; SANE_Int busy, linewidth; - + DBG(10, "sane_start...\n"); if (s->sfd != -1) { @@ -3863,10 +3863,10 @@ sane_start_guts (SANE_Handle handle) if ((status = sane_get_parameters(s, 0)) != SANE_STATUS_GOOD) return end_scan(s, status); set_pass_parameters(s); - + s->scanning = SANE_TRUE; s->cancel = SANE_FALSE; - + status = sanei_scsi_open(s->dev->sane.name, &(s->sfd), sense_handler, @@ -3877,50 +3877,50 @@ sane_start_guts (SANE_Handle handle) s->sfd = -1; return end_scan(s, status); } - + if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return end_scan(s, status); - if ((status = finagle_precal(s)) != SANE_STATUS_GOOD) + if ((status = finagle_precal(s)) != SANE_STATUS_GOOD) return end_scan(s, status); if ((status = scanning_frame(s)) != SANE_STATUS_GOOD) return end_scan(s, status); - if (s->dev->info.source_options & + if (s->dev->info.source_options & (MI_SRC_FEED_BT | MI_SRC_HAS_TRANS | MI_SRC_FEED_SUPP | MI_SRC_HAS_FEED)) { /* ZZZZZZZZZZZ */ if ((status = accessory(s)) != SANE_STATUS_GOOD) return end_scan(s, status); /* if SWslct ???? XXXXXXXXXXXXXXX */ } - if ((status = download_gamma(s)) != SANE_STATUS_GOOD) + if ((status = download_gamma(s)) != SANE_STATUS_GOOD) return end_scan(s, status); - if ((status = mode_select(s)) != SANE_STATUS_GOOD) + if ((status = mode_select(s)) != SANE_STATUS_GOOD) return end_scan(s, status); if (s->dev->info.does_mode1) { - if ((status = mode_select_1(s)) != SANE_STATUS_GOOD) + if ((status = mode_select_1(s)) != SANE_STATUS_GOOD) return end_scan(s, status); } if ((s->do_clever_precal) || (s->do_real_calib)) { - if ((status = save_mode_sense(s)) != SANE_STATUS_GOOD) + if ((status = save_mode_sense(s)) != SANE_STATUS_GOOD) return end_scan(s, status); - } + } if ((status = wait_ready(s)) != SANE_STATUS_GOOD) return end_scan(s, status); s->scan_started = SANE_TRUE; if ((status = start_scan(s)) != SANE_STATUS_GOOD) return end_scan(s, status); - if ((status = get_scan_status(s, &busy, + if ((status = get_scan_status(s, &busy, &linewidth, &(s->unscanned_lines))) != SANE_STATUS_GOOD) { DBG(10, "sane_start: get_scan_status fails\n"); return end_scan(s, status); } /* check for a bizarre linecount */ - if ((s->unscanned_lines < 0) || - (s->unscanned_lines > + if ((s->unscanned_lines < 0) || + (s->unscanned_lines > (s->params.lines * 2 * (s->expandedresolution ? 2 : 1)))) { DBG(10, "sane_start: get_scan_status returns weird line count %d\n", s->unscanned_lines); return end_scan(s, SANE_STATUS_DEVICE_BUSY); } - - + + /* figure out image format parameters */ switch (s->mode) { case MS_MODE_LINEART: @@ -3990,16 +3990,16 @@ sane_start_guts (SANE_Handle handle) DBG(10, "sane_start: Unknown scan mode: %d\n", s->mode); return end_scan(s, SANE_STATUS_INVAL); } - + if ((s->doexpansion) && (s->resolution > s->dev->info.base_resolution)) { s->dest_ppl = (int) ((double)s->ppl * (double)s->resolution / (double)s->dev->info.base_resolution); - /*+ 0.5 XXXXXX */ + /*+ 0.5 XXXXXX */ s->exp_aspect = (double)s->ppl / (double)s->dest_ppl; s->dest_pixel_bpl = (int) ceil((double)s->pixel_bpl / s->exp_aspect); - /*s->exp_aspect = + /*s->exp_aspect = (double) s->dev->info.base_resolution / (double) s->resolution;*/ /* s->dest_pixel_bpl = s->pixel_bpl / s->exp_aspect; s->dest_ppl = s->ppl / s->exp_aspect;*/ @@ -4012,27 +4012,27 @@ sane_start_guts (SANE_Handle handle) s->dest_pixel_bpl = s->pixel_bpl; s->dest_ppl = s->ppl; } - + s->params.lines = s->unscanned_lines; - s->params.pixels_per_line = s->dest_ppl; - s->params.bytes_per_line = s->dest_pixel_bpl; - + s->params.pixels_per_line = s->dest_ppl; + s->params.bytes_per_line = s->dest_pixel_bpl; + /* calculate maximum line capacity of SCSI buffer */ s->max_scsi_lines = SCSI_BUFF_SIZE / (s->pixel_bpl + s->header_bpl); if (s->max_scsi_lines < 1) { DBG(10, "sane_start: SCSI buffer smaller that one scan line!\n"); return end_scan(s, SANE_STATUS_NO_MEM); } - + s->scsi_buffer = (uint8_t *) malloc(SCSI_BUFF_SIZE * sizeof(uint8_t)); if (s->scsi_buffer == NULL) return SANE_STATUS_NO_MEM; - + /* what's a good initial size for this? */ s->rb = ring_alloc(s->max_scsi_lines * s->dest_pixel_bpl, s->dest_pixel_bpl, s->dest_ppl); - + s->undelivered_bytes = s->unscanned_lines * s->dest_pixel_bpl; - + DBG(23, "Scan Param:\n"); DBG(23, "pix bpl: %d hdr bpl: %d ppl: %d\n", s->pixel_bpl, s->header_bpl, s->ppl); @@ -4040,7 +4040,7 @@ sane_start_guts (SANE_Handle handle) s->undelivered_bytes, s->unscanned_lines, s->planes); DBG(23, "dest bpl: %d dest ppl: %d aspect: %f\n", s->dest_pixel_bpl, s->dest_ppl, s->exp_aspect); - + return SANE_STATUS_GOOD; } @@ -4062,7 +4062,7 @@ sane_start (SANE_Handle handle) /********************************************************************/ /* sane_read */ /********************************************************************/ -static SANE_Status +static SANE_Status sane_read_guts (SANE_Handle handle, SANE_Byte *dest_buffer, SANE_Int dest_length, SANE_Int *ret_length) { @@ -4072,7 +4072,7 @@ sane_read_guts (SANE_Handle handle, SANE_Byte *dest_buffer, ring_buffer *rb = s->rb; DBG(10, "sane_read...\n"); - + *ret_length = 0; /* default: no data */ /* we have been cancelled... */ if (s->cancel) return end_scan(s, SANE_STATUS_CANCELLED); @@ -4102,7 +4102,7 @@ sane_read_guts (SANE_Handle handle, SANE_Byte *dest_buffer, } -SANE_Status +SANE_Status sane_read (SANE_Handle handle, SANE_Byte *dest_buffer, SANE_Int dest_length, SANE_Int *ret_length) { diff --git a/backend/microtek.h b/backend/microtek.h index d4c7abf..880dc3c 100644 --- a/backend/microtek.h +++ b/backend/microtek.h @@ -1,7 +1,7 @@ /*************************************************************************** * SANE - Scanner Access Now Easy. - microtek.h + microtek.h This file Copyright 2002 Matthew Marjanovic @@ -60,13 +60,13 @@ /*******************************************************************/ -/***** enumeration of Option Descriptors *****/ +/***** enumeration of Option Descriptors *****/ /*******************************************************************/ enum Mtek_Option { OPT_NUM_OPTS = 0, - + OPT_MODE_GROUP, OPT_MODE, /* -a,b,c,g */ OPT_HALFTONE_PATTERN, /* -H */ @@ -77,13 +77,13 @@ enum Mtek_Option OPT_SOURCE, /* -t */ OPT_PREVIEW, OPT_CALIB_ONCE, - + OPT_GEOMETRY_GROUP, /* -f .... */ OPT_TL_X, /* top-left x */ OPT_TL_Y, /* top-left y */ OPT_BR_X, /* bottom-right x */ - OPT_BR_Y, /* bottom-right y */ - + OPT_BR_Y, /* bottom-right y */ + OPT_ENHANCEMENT_GROUP, OPT_EXPOSURE, OPT_BRIGHTNESS, /* -d */ @@ -91,7 +91,7 @@ enum Mtek_Option OPT_HIGHLIGHT, /* -l */ OPT_SHADOW, /* -s */ OPT_MIDTONE, /* -m */ - + OPT_GAMMA_GROUP, OPT_CUSTOM_GAMMA, OPT_ANALOG_GAMMA, @@ -106,16 +106,16 @@ enum Mtek_Option OPT_GAMMA_BIND, NUM_OPTIONS, - + OPT_BACKTRACK, /* -B */ - + /* must come last: */ RNUM_OPTIONS }; /*******************************************************************/ -/***** scanner hardware information (as discovered by INQUIRY) *****/ +/***** scanner hardware information (as discovered by INQUIRY) *****/ /*******************************************************************/ typedef struct Microtek_Info { @@ -131,7 +131,7 @@ typedef struct Microtek_Info { SANE_Byte response_data_format; #define MI_RESSTEP_1PER 0x01 #define MI_RESSTEP_5PER 0x02 - SANE_Byte res_step; + SANE_Byte res_step; #define MI_MODES_LINEART 0x01 #define MI_MODES_HALFTONE 0x02 #define MI_MODES_GRAY 0x04 /* ??????? or "MultiBit"??? XXXXX*/ @@ -139,9 +139,9 @@ typedef struct Microtek_Info { #define MI_MODES_TRANSMSV 0x20 #define MI_MODES_ONEPASS 0x40 #define MI_MODES_NEGATIVE 0x80 - SANE_Byte modes; - SANE_Int pattern_count; - SANE_Byte pattern_dwnld; + SANE_Byte modes; + SANE_Int pattern_count; + SANE_Byte pattern_dwnld; #define MI_FEED_FLATBED 0x01 #define MI_FEED_EDGEFEED 0x02 #define MI_FEED_AUTOSUPP 0x04 @@ -191,7 +191,7 @@ typedef struct Microtek_Info { #define MI_FMT_CAP_12BPP 0x04 #define MI_FMT_CAP_16BPP 0x08 SANE_Byte bit_formats; /* output bit formats capabilities */ -#define MI_EXCAP_OFF_CTL 0x01 +#define MI_EXCAP_OFF_CTL 0x01 #define MI_EXCAP_DIS_LNTBL 0x02 #define MI_EXCAP_DIS_RECAL 0x04 SANE_Byte extra_cap; @@ -240,7 +240,7 @@ typedef struct ring_buffer { size_t green_extra; /* unmatched green bytes */ size_t red_extra; /* unmatched red bytes */ - size_t complete_count; + size_t complete_count; size_t head_complete; } ring_buffer; @@ -256,7 +256,7 @@ typedef struct ring_buffer { typedef struct Microtek_Scanner { struct Microtek_Scanner *next; /* for linked list */ Microtek_Device *dev; /* raw device info */ - + SANE_Option_Descriptor sod[RNUM_OPTIONS]; /* option list for session */ Option_Value val[RNUM_OPTIONS]; /* option values for session */ @@ -295,7 +295,7 @@ typedef struct Microtek_Scanner { SANE_Int gamma_entry_size; SANE_Int gamma_bit_depth; /* SANE_Int gamma_max_entry;*/ - + SANE_Range gamma_entry_range; SANE_Range contrast_range; SANE_Range exposure_range; @@ -366,7 +366,7 @@ typedef struct Microtek_Scanner { #define MS_PRECAL_EXP_COLOR 3 SANE_Byte precal_record; /* record what precalibrations have been done */ -#define MS_SENSE_IGNORE 1 +#define MS_SENSE_IGNORE 1 int sense_flags; /* flags passed to the sense handler */ uint8_t *scsi_buffer; @@ -376,4 +376,3 @@ typedef struct Microtek_Scanner { #endif /* microtek_h */ - diff --git a/backend/microtek2.c b/backend/microtek2.c index dccd707..f7c63d6 100644 --- a/backend/microtek2.c +++ b/backend/microtek2.c @@ -554,7 +554,7 @@ sane_open(SANE_String_Const name, SANE_Handle *handle) ms->cancelled = SANE_FALSE; ms->current_pass = 0; ms->sfd = -1; - ms->pid = -1; + sanei_thread_initialize(ms->pid); ms->fp = NULL; ms->gamma_table = NULL; ms->buf.src_buf = ms->buf.src_buffer[0] = ms->buf.src_buffer[1] = NULL; @@ -692,7 +692,7 @@ add_device_list(SANE_String_Const dev_name, Microtek2_Device **mdev) if ( (hdev = strdup(dev_name)) == NULL) - { + { DBG(5, "add_device_list: malloc() for hdev failed\n"); return SANE_STATUS_NO_MEM; } @@ -760,7 +760,7 @@ attach(Microtek2_Device *md) /* device is passed in sane_open() this function may also be called */ /* from sane_open() or sane_get_devices(). */ - SANE_String model_string; + SANE_String model_string; SANE_Status status; SANE_Byte source_info; @@ -1172,7 +1172,7 @@ check_inquiry(Microtek2_Device *md, SANE_String *model_string) md->shading_depth = 12; else if ( mi->depth & MI_HASDEPTH_10 ) md->shading_depth = 10; - else + else md->shading_depth = 8; switch (mi->model_code) @@ -1353,7 +1353,7 @@ cleanup_scanner(Microtek2_Scanner *ms) if ( ms->sfd != -1 ) sanei_scsi_close(ms->sfd); ms->sfd = -1; - ms->pid = -1; + sanei_thread_invalidate(ms->pid); ms->fp = NULL; ms->current_pass = 0; ms->scanning = SANE_FALSE; @@ -1465,7 +1465,7 @@ do_authorization(char *ressource) return SANE_STATUS_ACCESS_DENIED; } } - + linep = &line[0]; device_found = 0; while ( fgets(line, MAX_LINE_LEN, fp) ) @@ -1479,7 +1479,7 @@ do_authorization(char *ressource) { DBG(2, "equal\n"); device_found = 1; - break; + break; } } } @@ -1491,9 +1491,9 @@ do_authorization(char *ressource) } fseek(fp, 0L, SEEK_SET); - + (*auth_callback) (ressource, username, password); - + status = SANE_STATUS_ACCESS_DENIED; do { @@ -1509,7 +1509,7 @@ do_authorization(char *ressource) if ( strcmp( device, ressource) != 0 ) /* not a matching entry */ continue; - linep = ++p; + linep = ++p; p = index(linep, SEPARATOR); if ( p == NULL ) continue; @@ -1616,7 +1616,7 @@ dump_area2(uint8_t *area, int len, char *info) char *outbuf; if ( ! info[0] ) - info = "No additional info available"; + info = "No additional info available"; DBG(1, "[%s]\n", info); @@ -3241,7 +3241,7 @@ sane_control_option(SANE_Handle handle, SANE_Int option, case OPT_BR_Y: if ( info ) *info |= SANE_INFO_RELOAD_PARAMS; - return SANE_STATUS_GOOD; + return SANE_STATUS_GOOD; case OPT_DISABLE_BACKTRACK: case OPT_CALIB_BACKEND: case OPT_LIGHTLID35: @@ -3300,7 +3300,7 @@ sane_control_option(SANE_Handle handle, SANE_Int option, if ( info ) *info |= SANE_INFO_RELOAD_PARAMS; - return SANE_STATUS_GOOD; + return SANE_STATUS_GOOD; case OPT_SOURCE: if ( info ) @@ -3751,12 +3751,12 @@ get_calib_params(Microtek2_Scanner *ms) Microtek2_Device *md; Microtek2_Info *mi; - + DBG(30, "get_calib_params: handle=%p\n", (void *) ms); md = ms->dev; mi = &md->info[md->scan_source]; - + if ( md->model_flags & MD_CALIB_DIVISOR_600 ) { if ( ms->x_resolution_dpi <= 600 ) @@ -3787,7 +3787,7 @@ get_calib_params(Microtek2_Scanner *ms) ms->depth = 12; else if ( mi->depth & MI_HASDEPTH_10 ) ms->depth = 10; - else + else ms->depth = 8; ms->stay = 0; @@ -3830,7 +3830,7 @@ get_scan_parameters(Microtek2_Scanner *ms) get_scan_mode_and_depth(ms, &ms->mode, &ms->depth, &ms->bits_per_pixel_in, &ms->bits_per_pixel_out); - + /* get the scan_source */ if ( strcmp(ms->val[OPT_SOURCE].s, MD_SOURCESTRING_FLATBED) == 0 ) ms->scan_source = MS_SOURCE_FLATBED; @@ -3871,19 +3871,19 @@ get_scan_parameters(Microtek2_Scanner *ms) if ( ms->mode == MS_MODE_HALFTONE ) { i = 0; - while ( strcmp(md->halftone_mode_list[i], ms->val[OPT_HALFTONE].s) ) + while ( strcmp(md->halftone_mode_list[i], ms->val[OPT_HALFTONE].s) ) ++i; ms->internal_ht_index = i; } - /* if lineart get the value for threshold */ - if ( ms->mode == MS_MODE_LINEART || ms->mode == MS_MODE_LINEARTFAKE) + /* if lineart get the value for threshold */ + if ( ms->mode == MS_MODE_LINEART || ms->mode == MS_MODE_LINEARTFAKE) ms->threshold = (uint8_t) ms->val[OPT_THRESHOLD].w; else ms->threshold = (uint8_t) M_THRESHOLD_DEFAULT; DBG(30, "get_scan_parameters: mode=%d, depth=%d, bpp_in=%d, bpp_out=%d\n", - ms->mode, ms->depth, ms->bits_per_pixel_in, + ms->mode, ms->depth, ms->bits_per_pixel_in, ms->bits_per_pixel_out); /* calculate positions, width and height in dots */ @@ -4115,7 +4115,7 @@ get_scan_mode_and_depth(Microtek2_Scanner *ms, " bits_pp_in=%d, bits_pp_out=%d, preview=%d\n", *mode, *depth, *bits_per_pixel_in, *bits_per_pixel_out, ms->val[OPT_PREVIEW].w); - + return SANE_STATUS_GOOD; } @@ -5237,8 +5237,8 @@ scsi_test_unit_ready(Microtek2_Device *md) status = sanei_scsi_cmd(sfd, tur, sizeof(tur), NULL, 0); if ( status != SANE_STATUS_GOOD ) DBG(1, "scsi_test_unit_ready: cmd '%s'\n", sane_strstatus(status)); - - sanei_scsi_close(sfd); + + sanei_scsi_close(sfd); return status; } @@ -5319,7 +5319,7 @@ sane_start(SANE_Handle handle) goto cleanup; } } - + status = get_scan_parameters(ms); if ( status != SANE_STATUS_GOOD ) goto cleanup; @@ -5349,7 +5349,7 @@ sane_start(SANE_Handle handle) /* md->status.tlamp |= MD_TLAMP_ON;*/ /* with this line on some scanners (X6, 0x91) the Flamp goes on */ } - + if ( ms->no_backtracking ) md->status.ntrack |= MD_NTRACK_ON; else @@ -5447,8 +5447,8 @@ sane_start(SANE_Handle handle) if ( status != SANE_STATUS_GOOD ) goto cleanup; } - - if ( ms->lightlid35 ) + + if ( ms->lightlid35 ) /* hopefully this leads to a switched off flatbed lamp with lightlid */ { status = scsi_read_system_status(md, ms->sfd); @@ -5457,7 +5457,7 @@ sane_start(SANE_Handle handle) md->status.flamp &= ~MD_FLAMP_ON; md->status.tlamp &= ~MD_TLAMP_ON; - + status = scsi_send_system_status(md, ms->sfd); if ( status != SANE_STATUS_GOOD ) goto cleanup; @@ -5518,7 +5518,7 @@ prepare_buffers(Microtek2_Scanner *ms) status = SANE_STATUS_GOOD; DBG(30, "prepare_buffers: ms=0x%p\n", (void *) ms); - + md = ms->dev; mi = &md->info[md->scan_source]; @@ -5541,19 +5541,19 @@ prepare_buffers(Microtek2_Scanner *ms) } /* allocate buffers */ - ms->src_buffer_size = ms->src_max_lines * ms->bpl; + ms->src_buffer_size = ms->src_max_lines * ms->bpl; - if ( ms->mode == MS_MODE_COLOR && mi->data_format == MI_DATAFMT_LPLSEGREG ) - { + if ( ms->mode == MS_MODE_COLOR && mi->data_format == MI_DATAFMT_LPLSEGREG ) + { /* In this case the data is not neccessarily in the order RGB */ /* and there may be different numbers of read red, green and blue */ /* segments. We allocate a second buffer to read new lines in */ /* and hold undelivered pixels in the other buffer */ int extra_buf_size; - extra_buf_size = 2 * ms->bpl * mi->ccd_gap + extra_buf_size = 2 * ms->bpl * mi->ccd_gap * (int) ceil( (double) mi->max_yresolution - / (double) mi->opt_resolution); + / (double) mi->opt_resolution); for ( i = 0; i < 2; i++ ) { if ( ms->buf.src_buffer[i] ) @@ -5610,15 +5610,15 @@ prepare_buffers(Microtek2_Scanner *ms) DBG(1, "sane_start: malloc() for temporary buffer failed\n"); status = SANE_STATUS_NO_MEM; goto cleanup; - } + } } - else + else ms->temporary_buffer = NULL; /* some data formats have additional information in a scan line, which */ /* is not transferred to the frontend; real_bpl is the number of bytes */ /* per line, that is copied into the frontend's buffer */ - ms->real_bpl = (uint32_t) ceil( ((double) ms->ppl * + ms->real_bpl = (uint32_t) ceil( ((double) ms->ppl * (double) ms->bits_per_pixel_out) / 8.0 ); if ( mi->onepass && ms->mode == MS_MODE_COLOR ) ms->real_bpl *= 3; @@ -5629,7 +5629,7 @@ prepare_buffers(Microtek2_Scanner *ms) cleanup: cleanup_scanner(ms); - return status; + return status; } static void @@ -5691,7 +5691,7 @@ write_shading_buf_pnm(Microtek2_Scanner *ms, uint32_t lines) + mi->color_sequence[color] * ( ms->bpl / ms->lut_entry_size / 3 ) + pixel); - + break; case MI_DATAFMT_CHUNKY: case MI_DATAFMT_9800: @@ -7067,7 +7067,7 @@ set_exposure(Microtek2_Scanner *ms) uint8_t exposure; uint8_t exposure_rgb[3]; - + DBG(30, "set_exposure: ms=%p\n", (void *) ms); md = ms->dev; @@ -7118,7 +7118,7 @@ set_exposure(Microtek2_Scanner *ms) for ( byte = 0; byte < size; byte++ ) { val32 = (uint32_t) *((uint16_t *) from + color * size + byte); - val32 = MIN(val32 + val32 + val32 = MIN(val32 + val32 * (2 * (uint32_t) exposure_rgb[color] / 100), (uint32_t) maxval); *((uint16_t *) from + color * size + byte) = (uint16_t) val32; @@ -7162,7 +7162,7 @@ reader_process(void *data) DBG(1, "reader_process: fdopen() failed, errno=%d\n", errno); return SANE_STATUS_IO_ERROR; } - + if ( ms->auto_adjust == 1 ) { if ( temp_current == NULL ) @@ -7171,7 +7171,7 @@ reader_process(void *data) while ( ms->src_remaining_lines > 0 ) { - + ms->src_lines_to_read = MIN(ms->src_remaining_lines, ms->src_max_lines); ms->transfer_length = ms->src_lines_to_read * ms->bpl; @@ -7182,13 +7182,13 @@ reader_process(void *data) sigprocmask (SIG_BLOCK, &sigterm_set, 0); status = scsi_read_image(ms, ms->buf.src_buf, (ms->depth > 8) ? 2 : 1); sigprocmask (SIG_UNBLOCK, &sigterm_set, 0); - if ( status != SANE_STATUS_GOOD ) + if ( status != SANE_STATUS_GOOD ) return SANE_STATUS_IO_ERROR; ms->src_remaining_lines -= ms->src_lines_to_read; /* prepare data for frontend */ - switch (ms->mode) + switch (ms->mode) { case MS_MODE_COLOR: if ( ! mi->onepass ) @@ -7197,9 +7197,9 @@ reader_process(void *data) DBG(1, "reader_process: 3 pass not yet supported\n"); return SANE_STATUS_IO_ERROR; } - else + else { - switch ( mi->data_format ) + switch ( mi->data_format ) { case MI_DATAFMT_CHUNKY: case MI_DATAFMT_9800: @@ -7225,9 +7225,9 @@ reader_process(void *data) default: DBG(1, "reader_process: format %d\n", mi->data_format); return SANE_STATUS_IO_ERROR; - } + } } - break; + break; case MS_MODE_GRAY: status = gray_proc_data(ms); if ( status != SANE_STATUS_GOOD ) @@ -7260,7 +7260,7 @@ reader_process(void *data) /*---------- chunky_proc_data() ----------------------------------------------*/ -static SANE_Status +static SANE_Status chunky_proc_data(Microtek2_Scanner *ms) { SANE_Status status; @@ -7275,7 +7275,7 @@ chunky_proc_data(Microtek2_Scanner *ms) DBG(30, "chunky_proc_data: ms=%p\n", (void *) ms); - + md = ms->dev; bits_pp_in = ms->bits_per_pixel_in; bits_pp_out = ms->bits_per_pixel_out; @@ -7621,7 +7621,7 @@ segreg_copy_pixels(Microtek2_Scanner *ms) val = MAX( 0.0, val); val = MIN( maxval, val ); } - + val16 = (uint16_t) val; val8 = (uint8_t) val; @@ -7789,7 +7789,7 @@ lplconcat_copy_pixels(Microtek2_Scanner *ms, DBG(1, "lplconcat_copy_pixels: Unknown depth %d\n", ms->depth); return SANE_STATUS_IO_ERROR; } - + if ((md->model_flags & MD_READ_CONTROL_BIT) && ms->calib_backend && ( ms->condensed_shading_w != NULL )) /* apply shading by backend */ diff --git a/backend/microtek2.h b/backend/microtek2.h index 2a1f697..326eac8 100644 --- a/backend/microtek2.h +++ b/backend/microtek2.h @@ -1,7 +1,7 @@ /******************************************************************************* * SANE - Scanner Access Now Easy. - microtek2.h + microtek2.h This file (C) 1998, 1999 Bernd Schroeder 2000, 2001 Karsten Festag @@ -160,7 +160,7 @@ #define RG_COLOR(d,p) (d)[5] |= (((p) << 5) & 0x60) #define RG_WORD(d,p) (d)[5] |= ((p) & 0x01) #define RG_TRANSFERLENGTH(d,p) (d)[7] = (((p) >> 8) & 0xff); \ - (d)[8] = ((p) & 0xff) + (d)[8] = ((p) & 0xff) /* SEND GAMMA TABLE */ #define SG_SET_CMD(d) (d)[0] = 0x2a; (d)[1] = 0x00; (d)[2] = 0x03; \ @@ -172,7 +172,7 @@ #define SG_SET_COLOR(d,p) (d)[5] |= (((p) << 5) & 0x60) #define SG_SET_WORD(d,p) (d)[5] |= ((p) & 0x01) #define SG_SET_TRANSFERLENGTH(d,p) (d)[7] = (((p) >> 8) & 0xff); \ - (d)[8] = ((p) & 0xff) + (d)[8] = ((p) & 0xff) #define SG_DATA_P SG_CMD_L @@ -394,7 +394,7 @@ #define SW_BODY_L 61 #define SW_CMD_P 0 /* command at postion 0 */ #define SW_HEADER_P SW_CMD_L -#define SW_BODY_P(n) SW_CMD_L + SW_HEADER_L + (n) * SW_BODY_L +#define SW_BODY_P(n) SW_CMD_L + SW_HEADER_L + (n) * SW_BODY_L /* d: SW_CMD_P, SW_HEADER_P, SW_BODY_P(n) */ #define SW_PARAM_LENGTH(d,p) (d)[6] = ((p) >> 16) & 0xff; \ @@ -402,7 +402,7 @@ (d)[8] = (p) & 0xff #define SW_WNDDESCVAL SW_BODY_L #define SW_WNDDESCLEN(d,p) (d)[6] = ((p) >> 8) & 0xff; \ - (d)[7] = (p) & 0xff + (d)[7] = (p) & 0xff #define SW_WNDID(d,p) (d)[0] = (p) #define SW_XRESDPI(d,p) (d)[2] = ((p) >> 8) & 0xff; \ (d)[3] = (p) & 0xff @@ -415,15 +415,15 @@ #define SW_YPOSTL(d,p) (d)[10] = ((p) >> 24) & 0xff; \ (d)[11] = ((p) >> 16) & 0xff; \ (d)[12] = ((p) >> 8) & 0xff; \ - (d)[13] = (p) & 0xff + (d)[13] = (p) & 0xff #define SW_WNDWIDTH(d,p) (d)[14] = ((p) >> 24) & 0xff; \ (d)[15] = ((p) >> 16) & 0xff; \ (d)[16] = ((p) >> 8) & 0xff; \ - (d)[17] = (p) & 0xff + (d)[17] = (p) & 0xff #define SW_WNDHEIGHT(d,p) (d)[18] = ((p) >> 24) & 0xff; \ (d)[19] = ((p) >> 16) & 0xff; \ (d)[20] = ((p) >> 8) & 0xff; \ - (d)[21] = (p) & 0xff + (d)[21] = (p) & 0xff #define SW_BRIGHTNESS_M(d,p) (d)[22] = (p) #define SW_THRESHOLD(d,p) (d)[23] = (p) #define SW_CONTRAST_M(d,p) (d)[24] = (p) @@ -1219,7 +1219,7 @@ static SANE_Status dump_to_file(uint8_t *, int, char *, char *); #endif -static SANE_Status +static SANE_Status dump_attributes(Microtek2_Info *); static void @@ -1251,7 +1251,7 @@ gray_set_exposure(uint8_t *, uint32_t, uint8_t, uint8_t); static SANE_Status init_options(Microtek2_Scanner *, uint8_t); -static SANE_Status +static SANE_Status lineartfake_copy_pixels(Microtek2_Scanner *, uint8_t *, uint32_t, uint8_t, int, FILE *); diff --git a/backend/mustek.c b/backend/mustek.c index 8426dfe..eafdb99 100644 --- a/backend/mustek.c +++ b/backend/mustek.c @@ -3,7 +3,7 @@ 1998 Andreas Bolsch for extension to ScanExpress models version 0.6, 2000-2005 Henning Meier-Geinitz, 2003 James Perry (600 EP). - + This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -188,9 +188,9 @@ static SANE_String_Const halftone_list[] = { /* Range used for brightness and contrast */ static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 1 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(-100), /* minimum */ + SANE_FIX(100), /* maximum */ + SANE_FIX(1) /* quantization */ }; /* SCSI command buffers used by the backend */ @@ -200,9 +200,15 @@ static const SANE_Byte scsi_inquiry[] = { static const SANE_Byte scsi_test_unit_ready[] = { MUSTEK_SCSI_TEST_UNIT_READY, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/* Remove #ifdef and this comment when this SCSI command is used for + something. Keeping this definition around so we don't loose info + about the protocol. + */ +#ifdef ENABLE_MUSTEK_SCSI_AREA_AND_WINDOWS static const SANE_Byte scsi_area_and_windows[] = { MUSTEK_SCSI_AREA_AND_WINDOWS, 0x00, 0x00, 0x00, 0x09, 0x00 }; +#endif static const SANE_Byte scsi_request_sense[] = { MUSTEK_SCSI_REQUEST_SENSE, 0x00, 0x00, 0x00, 0x04, 0x00 }; @@ -227,10 +233,16 @@ static const SANE_Byte scsi_read_data[] = { static const SANE_Byte scsi_send_data[] = { MUSTEK_SCSI_SEND_DATA, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +/* Remove #ifdef and this comment when this SCSI command is used for + something. Keeping this definition around so we don't loose info + about the protocol. + */ +#ifdef ENABLE_MUSTEK_SCSI_LOOKUP_TABLE static const SANE_Byte scsi_lookup_table[] = { MUSTEK_SCSI_LOOKUP_TABLE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; +#endif /* prototypes */ static SANE_Status area_and_windows (Mustek_Scanner * s); @@ -1214,7 +1226,7 @@ attach (SANE_String_Const devname, Mustek_Device ** devp, SANE_Bool may_wait) /* Paragon 1-pass 14" series I */ /* I haven't seen a single report for this, but it is mentioned in - the old man page. All reported Paragon 1200SP had a model name + the old man page. All reported Paragon 1200SP had a model name "MFS-12000SP" */ else if (strncmp ((SANE_String) model_name, "MSF-12000SP", 11) == 0) { @@ -1269,7 +1281,7 @@ attach (SANE_String_Const devname, Mustek_Device ** devp, SANE_Bool may_wait) dev->y_trans_range.max = SANE_FIX (255.0); dev->dpi_range.max = SANE_FIX (600); /* Looks like at least some versions of this scanner produce black images - in gray and color mode if MUSTEK_FORCE_GAMMA is not set. At least + in gray and color mode if MUSTEK_FORCE_GAMMA is not set. At least versions 2.01, 2.02 and 2.10 are reported as having this bug. 3.12 doesn't need this workaround but it doesn't harm either. */ dev->flags |= MUSTEK_FLAG_FORCE_GAMMA; @@ -1451,12 +1463,12 @@ attach (SANE_String_Const devname, Mustek_Device ** devp, SANE_Bool may_wait) dev->y_range.min = SANE_FIX (0); dev->x_range.max = SANE_FIX (215.9); dev->y_range.max = SANE_FIX (291.2); - + dev->x_trans_range.min = SANE_FIX (0); dev->y_trans_range.min = SANE_FIX (0); dev->x_trans_range.max = SANE_FIX (150.0); dev->y_trans_range.max = SANE_FIX (175.0); - + dev->dpi_range.max = SANE_FIX (1200); dev->dpi_range.min = SANE_FIX (60); dev->flags |= MUSTEK_FLAG_SE; @@ -1476,12 +1488,12 @@ attach (SANE_String_Const devname, Mustek_Device ** devp, SANE_Bool may_wait) dev->y_range.min = SANE_FIX (0); dev->x_range.max = SANE_FIX (215.9); dev->y_range.max = SANE_FIX (291.2); - + dev->x_trans_range.min = SANE_FIX (0); dev->y_trans_range.min = SANE_FIX (0); dev->x_trans_range.max = SANE_FIX (150.0); dev->y_trans_range.max = SANE_FIX (175.0); - + dev->dpi_range.max = SANE_FIX (1200); dev->dpi_range.min = SANE_FIX (60); dev->flags |= MUSTEK_FLAG_SE; @@ -1672,7 +1684,7 @@ attach (SANE_String_Const devname, Mustek_Device ** devp, SANE_Bool may_wait) "careful and read\n the PROBLEMS file in the sane directory. " "Please set the debug level of this\n backend to maximum " "(export SANE_DEBUG_MUSTEK=255) and send the output of\n " - "scanimage -L to the SANE mailing list sane-devel@lists.alioth.debian.org. " + "scanimage -L to the SANE mailing list sane-devel@alioth-lists.debian.net. " "Please include\n the exact model name of your scanner and to " "which extend it works.\n"); } @@ -2996,7 +3008,7 @@ do_stop (Mustek_Scanner * s) status = exit_status; } - s->reader_pid = -1; + sanei_thread_invalidate (s->reader_pid); } if (s->fd >= 0) @@ -3415,7 +3427,7 @@ fix_line_distance_n_2 (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, if (!s->ld.buf[0]) { /* This buffer must be big enough to hold maximum line distance - times max_bpl bytes. The maximum line distance for the + times max_bpl bytes. The maximum line distance for the Paragon 600 II N scanner is 23, so 40 should be safe. */ DBG (5, "fix_line_distance_n_2: allocating temp buffer of %d*%d bytes\n", @@ -3495,7 +3507,7 @@ fix_line_distance_n_1 (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, if (!s->ld.buf[0]) { /* This buffer must be big enough to hold maximum line distance - times max_bpl bytes. The maximum line distance for the 600 II N + times max_bpl bytes. The maximum line distance for the 600 II N is 23, so 40 is safe. */ DBG (5, "fix_line_distance_n_1: allocating temp buffer of %d*%d bytes\n", @@ -3643,7 +3655,7 @@ fix_line_distance_se (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, DBG (5, "fix_line_distance_se: start color: %d; %d lines \n", s->ld.color, num_lines); - /* First scan the lines read and count red, green and blue ones. + /* First scan the lines read and count red, green and blue ones. Since we will step through the lines a second time we must not alter any global variables here! */ for (color = 0; color < 3; ++color) @@ -3676,8 +3688,8 @@ fix_line_distance_se (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, color = 0; } - /* Calculate how many triples of color lines we can output now. - Because the number of available red lines is always greater + /* Calculate how many triples of color lines we can output now. + Because the number of available red lines is always greater than for the other colors we may ignore the red ones here. */ num_lines = MIN (lines[1], lines[2]); @@ -3688,7 +3700,7 @@ fix_line_distance_se (Mustek_Scanner * s, SANE_Int num_lines, SANE_Int bpl, lines[0] = lines[1] = lines[2] = num_lines; - /* Output the color lines saved in previous call first. + /* Output the color lines saved in previous call first. Note that data is converted in r/g/b interleave on the fly. */ for (color = 0; color < 3; ++color) { @@ -4710,7 +4722,7 @@ output_data (Mustek_Scanner * s, FILE * fp, else { DBG (5, "output_data: write %d lpb; %d bpl\n", lines_per_buffer, bpl); - /* Scale x-resolution above 1/2 of the maximum resolution for + /* Scale x-resolution above 1/2 of the maximum resolution for SE and Pro scanners */ if ((s->hw->flags & MUSTEK_FLAG_ENLARGE_X) && (s->val[OPT_RESOLUTION].w > (s->hw->dpi_range.max / 2))) @@ -6011,7 +6023,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { /* enable brightness/contrast for when in a binary mode */ s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE; - /* The SE and paragon models support only threshold + /* The SE and paragon models support only threshold in lineart */ if (!(s->hw->flags & MUSTEK_FLAG_SE) && !(s->hw->flags & MUSTEK_FLAG_PRO)) @@ -6548,8 +6560,8 @@ sane_start (SANE_Handle handle) s->line = 0; - /* don't call any SIGTERM or SIGCHLD handlers - this is to stop xsane and other frontends from calling + /* don't call any SIGTERM or SIGCHLD handlers + this is to stop xsane and other frontends from calling its quit handlers */ memset (&act, 0, sizeof (act)); sigaction (SIGTERM, &act, 0); diff --git a/backend/mustek.conf.in b/backend/mustek.conf.in index 3233fd8..3868d0e 100644 --- a/backend/mustek.conf.in +++ b/backend/mustek.conf.in @@ -1,7 +1,7 @@ # See sane-mustek(5) for documentation. #--------------------------- Global options --------------------------------- -#option strip-height 1 # some SCSI adapters need this; scanning may +#option strip-height 1 # some SCSI adapters need this; scanning may # be faster without this option #option force-wait # wait for scanner to be ready (only necessary # when scanner freezes) @@ -36,6 +36,6 @@ scsi SCANNER # option linedistance-fix # only neccessary with firmware 2.x #-------------------------- 600 II EP --------------------------------------- -#parport0 - # parport0, parport1, ..., +#parport0 + # parport0, parport1, ..., # or: 0x378(=lpt1), 0x278(=lpt2), 0x3bc(=lpt3) diff --git a/backend/mustek.h b/backend/mustek.h index 5532af5..ca7aa2e 100644 --- a/backend/mustek.h +++ b/backend/mustek.h @@ -3,7 +3,7 @@ extension to ScanExpress models version 0.5, 2000 - 2005 Henning Meier-Geinitz. 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 @@ -38,7 +38,7 @@ 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. + If you do not wish that, delete this exception notice. This file implements a SANE backend for Mustek and some Trust flatbed scanners with SCSI or proprietary interface. */ @@ -292,7 +292,7 @@ typedef struct Mustek_Scanner /* these are used for SE, MFS and N line-distance correction: */ SANE_Byte *buf[3]; /* these are used for N line-distance correction only: */ - SANE_Int ld_line; /* line # currently processed in + SANE_Int ld_line; /* line # currently processed in ld-correction */ SANE_Int lmod3; /* line # modulo 3 */ } diff --git a/backend/mustek_pp.c b/backend/mustek_pp.c index 9c9a533..912c3bd 100644 --- a/backend/mustek_pp.c +++ b/backend/mustek_pp.c @@ -86,7 +86,7 @@ #include "mustek_pp_drivers.h" #define MIN(a,b) ((a) < (b) ? (a) : (b)) - + /* converts millimeter to pixels at a given resolution */ #define MM_TO_PIXEL(mm, dpi) (((float )mm * 5.0 / 127.0) * (float)dpi) /* and back */ @@ -120,27 +120,27 @@ static Mustek_pp_Handle *first_hndl = NULL; static SANE_String_Const mustek_pp_modes[4] = {SANE_VALUE_SCAN_MODE_LINEART, SANE_VALUE_SCAN_MODE_GRAY, SANE_VALUE_SCAN_MODE_COLOR, NULL}; static SANE_Word mustek_pp_modes_size = 10; - + static SANE_String_Const mustek_pp_speeds[6] = {"Slowest", "Slower", "Normal", "Faster", "Fastest", NULL}; static SANE_Word mustek_pp_speeds_size = 8; -static SANE_Word mustek_pp_depths[5] = {4, 8, 10, 12, 16}; +static SANE_Word mustek_pp_depths[5] = {4, 8, 10, 12, 16}; /* prototypes */ static void free_cfg_options(int *numoptions, Mustek_pp_config_option** options); static SANE_Status do_eof(Mustek_pp_Handle *hndl); static SANE_Status do_stop(Mustek_pp_Handle *hndl); static int reader_process (Mustek_pp_Handle * hndl, int pipe); -static SANE_Status sane_attach(SANE_String_Const port, SANE_String_Const name, +static SANE_Status sane_attach(SANE_String_Const port, SANE_String_Const name, SANE_Int driver, SANE_Int info); static void init_options(Mustek_pp_Handle *hndl); -static void attach_device(SANE_String *driver, SANE_String *name, +static void attach_device(SANE_String *driver, SANE_String *name, SANE_String *port, SANE_String *option_ta); /* - * Auxiliary function for freeing arrays of configuration options, + * Auxiliary function for freeing arrays of configuration options, */ -static void +static void free_cfg_options(int *numoptions, Mustek_pp_config_option** options) { int i; @@ -225,7 +225,7 @@ do_stop(Mustek_pp_Handle *hndl) * * EDG - Jan 14, 2004: * Make sure that the parport is released again by the child process - * under all circumstances, because otherwise the parent process may no + * under all circumstances, because otherwise the parent process may no * longer be able to claim it (they share the same file descriptor, and * the kernel doesn't release the child's claim because the file * descriptor isn't cleaned up). If that would happen, the lamp may stay @@ -267,13 +267,13 @@ reader_process (Mustek_pp_Handle * hndl, int pipe) sigemptyset (&sigterm_set); sigaddset (&sigterm_set, SIGTERM); - + if (!(buffer = malloc (hndl->params.bytes_per_line))) return SANE_STATUS_NO_MEM; - + if (!(fp = fdopen(pipe, "w"))) return SANE_STATUS_IO_ERROR; - + fd_to_release = hndl->fd; memset (&act, 0, sizeof(act)); act.sa_handler = sigterm_handler; @@ -290,11 +290,11 @@ reader_process (Mustek_pp_Handle * hndl, int pipe) sigprocmask (SIG_BLOCK, &sigterm_set, NULL); hndl->dev->func->read (hndl, buffer); - + if (getppid() == 1) { /* The parent process has died. Stop the scan (to make sure that the lamp is off and returns home). This is - a safety measure to make sure that we don't break + a safety measure to make sure that we don't break the scanner in case the frontend crashes. */ DBG (1, "reader_process: front-end died; aborting.\n"); hndl->dev->func->stop (hndl); @@ -312,7 +312,7 @@ reader_process (Mustek_pp_Handle * hndl, int pipe) return SANE_STATUS_GOOD; } - + /* sane_attach: @@ -334,7 +334,7 @@ sane_attach (SANE_String_Const port, SANE_String_Const name, SANE_Int driver, SA { Mustek_pp_Device *dev; - DBG (3, "sane_attach: attaching device ``%s'' to port %s (driver %s v%s by %s)\n", + DBG (3, "sane_attach: attaching device ``%s'' to port %s (driver %s v%s by %s)\n", name, port, Mustek_pp_Drivers[driver].driver, Mustek_pp_Drivers[driver].version, Mustek_pp_Drivers[driver].author); @@ -355,7 +355,7 @@ sane_attach (SANE_String_Const port, SANE_String_Const name, SANE_Int driver, SA dev->sane.name = dev->name = strdup (name); dev->port = strdup (port); dev->info = info; /* Modified by EDG */ - + /* Transfer the options parsed from the configuration file */ dev->numcfgoptions = numcfgoptions; dev->cfgoptions = cfgoptions; @@ -469,7 +469,7 @@ init_options(Mustek_pp_Handle *hndl) /* color dept */ hndl->opt[OPT_DEPTH].name = SANE_NAME_BIT_DEPTH; hndl->opt[OPT_DEPTH].title = SANE_TITLE_BIT_DEPTH; - hndl->opt[OPT_DEPTH].desc = + hndl->opt[OPT_DEPTH].desc = "Number of bits per sample for color scans, typical values are 8 for truecolor (24bpp)" "up to 16 for far-to-many-color (48bpp)."; hndl->opt[OPT_DEPTH].type = SANE_TYPE_INT; @@ -634,7 +634,7 @@ init_options(Mustek_pp_Handle *hndl) * this driver is called to initialize the device. */ static void -attach_device(SANE_String *driver, SANE_String *name, +attach_device(SANE_String *driver, SANE_String *name, SANE_String *port, SANE_String *option_ta) { int found = 0, driver_no, port_no; @@ -681,15 +681,15 @@ attach_device(SANE_String *driver, SANE_String *name, if (*option_ta) free (*option_ta); *name = *port = *driver = *option_ta = 0; - + /* In case of a successful initialization, the configuration options should have been transfered to the device, but this function can deal with that. */ free_cfg_options(&numcfgoptions, &cfgoptions); } - + /* sane_init: - * Reads configuration file and registers hardware driver + * Reads configuration file and registers hardware driver * * ChangeLog: * @@ -711,7 +711,7 @@ attach_device(SANE_String *driver, SANE_String *name, * * if the optional argument "option_ta" is present the driver uses special * parameters fitting for a trasparency adapter. - */ + */ SANE_Status sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) @@ -740,9 +740,9 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) char driver_name[64]; const char **devices = sanei_pa4s2_devices(); int device_no; - + DBG (2, "sane_init: could not open configuration file\n"); - + for (device_no = 0; devices[device_no] != NULL; device_no++) { DBG (3, "sane_init: trying ``%s''\n", devices[device_no]); @@ -774,14 +774,14 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) if (strncmp(config_line_ptr, "scanner", 7) == 0) { config_line_ptr += 7; - + if (name) { /* Parsing of previous scanner + options is finished. Attach the device before we parse the next section. */ attach_device(&driver, &name, &port, &option_ta); } - + config_line_ptr = sanei_config_skip_whitespace (config_line_ptr); if (!*config_line_ptr) { @@ -858,7 +858,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) config_line_ptr = sanei_config_get_string (config_line_ptr, &option_ta); - if ((option_ta == NULL) || (!*option_ta) || + if ((option_ta == NULL) || (!*option_ta) || (strcasecmp (option_ta, "use_ta") != 0)) { DBG (1, "sane_init: parse error in line %d after " @@ -889,12 +889,12 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) } else if (strncmp(config_line_ptr, "option", 6) == 0) { - /* Format for options: option [] - Note that the value is optional. */ + /* Format for options: option [] + Note that the value is optional. */ char *optname, *optval = 0; Mustek_pp_config_option *tmpoptions; - config_line_ptr += 6; + config_line_ptr += 6; config_line_ptr = sanei_config_skip_whitespace (config_line_ptr); if (!*config_line_ptr) { @@ -918,7 +918,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { /* The option has a value. No need to check the value; that's up to the backend */ - config_line_ptr = sanei_config_get_string (config_line_ptr, + config_line_ptr = sanei_config_get_string (config_line_ptr, &optval); config_line_ptr = sanei_config_skip_whitespace (config_line_ptr); @@ -927,10 +927,10 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) if (*config_line_ptr) { DBG (1, "sane_init: parse error in line %d after " - "``option %s %s''\n", line, optname, + "``option %s %s''\n", line, optname, (optval == 0 ? "" : optval)); free (optname); - if (optval) + if (optval) free (optval); continue; } @@ -959,14 +959,14 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) DBG (1, "sane_init: parse error in line %d: unexpected " " ``option''\n", line); free (optname); - if (optval) + if (optval) free (optval); continue; } /* Extend the (global) array of options */ - tmpoptions = realloc(cfgoptions, + tmpoptions = realloc(cfgoptions, (numcfgoptions+1)*sizeof(cfgoptions[0])); if (!tmpoptions) { @@ -987,7 +987,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) } } - + /* If we hit the end of the file, we still may have to process the last driver */ if (name) @@ -996,7 +996,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) fclose(fp); return SANE_STATUS_GOOD; -} +} /* sane_exit: * Unloads all drivers and frees allocated memory @@ -1060,7 +1060,7 @@ sane_exit (void) */ /*ARGSUSED*/ SANE_Status -sane_get_devices (const SANE_Device *** device_list, +sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only __UNUSED__) { int ctr; @@ -1078,7 +1078,7 @@ sane_get_devices (const SANE_Device *** device_list, } dev = devlist; - + for (ctr=0 ; ctrsane; dev = dev->next; @@ -1142,7 +1142,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) return SANE_STATUS_INVAL; } - DBG (3, "sane_open: Using device ``%s'' (driver %s v%s by %s)\n", + DBG (3, "sane_open: Using device ``%s'' (driver %s v%s by %s)\n", dev->name, dev->func->driver, dev->func->version, dev->func->author); if ((hndl = malloc (sizeof (Mustek_pp_Handle))) == NULL) { @@ -1151,7 +1151,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) return SANE_STATUS_NO_MEM; } - + if ((status = dev->func->open (dev->port, dev->caps, &fd)) != SANE_STATUS_GOOD) { DBG (1, "sane_open: could not open device (%s)\n", @@ -1167,32 +1167,32 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) hndl->pipe = -1; init_options (hndl); - + dev->func->setup (hndl); - + /* Initialize driver-specific configuration options. This must be done after calling the setup() function because only then the driver is guaranteed to be fully initialized */ for (i = 0; inumcfgoptions; ++i) { - status = dev->func->config (hndl, + status = dev->func->config (hndl, dev->cfgoptions[i].name, dev->cfgoptions[i].value); if (status != SANE_STATUS_GOOD) { DBG (1, "sane_open: could not set option %s for device (%s)\n", dev->cfgoptions[i].name, sane_strstatus (status)); - - /* Question: should the initialization be aborted when an - option cannot be handled ? - The driver should have reasonable built-in defaults, so - an illegal option value or an unknown option should not + + /* Question: should the initialization be aborted when an + option cannot be handled ? + The driver should have reasonable built-in defaults, so + an illegal option value or an unknown option should not be fatal. Therefore, it's probably ok to ignore the error. */ } } first_hndl = hndl; - + *handle = hndl; return SANE_STATUS_GOOD; @@ -1297,7 +1297,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) * values aren't supported. * * before a value is written, some checks are performed. Depending - * on the option, that is written, other options also change + * on the option, that is written, other options also change * */ SANE_Status @@ -1487,7 +1487,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, hndl->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; hndl->opt[OPT_DEPTH].cap |= SANE_CAP_INACTIVE; - + if ((hndl->dev->caps & CAP_DEPTH) && (strcmp(val, SANE_VALUE_SCAN_MODE_COLOR) == 0)) hndl->opt[OPT_DEPTH].cap &= ~SANE_CAP_INACTIVE; @@ -1543,7 +1543,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, * supported) or 24bit by default * (ignored in bw/grayscale or if not * supported) - * dpi: resolution + * dpi: resolution * invert: if supported else defaults to false * gamma: if supported and selected * ta: if supported by the device @@ -1577,9 +1577,9 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) hndl->depth = hndl->val[OPT_DEPTH].w; else hndl->depth = 8; - + dpi = (int) (SANE_UNFIX (hndl->val[OPT_RESOLUTION].w) + 0.5); - + hndl->res = dpi; if (hndl->dev->caps & CAP_INVERT) @@ -1603,11 +1603,11 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) if (strcmp(mustek_pp_speeds[ctr], hndl->val[OPT_SPEED].s) == 0) hndl->speed = ctr; - + } else hndl->speed = SPEED_NORMAL; - + mode = hndl->val[OPT_MODE].s; if (strcmp (mode, SANE_VALUE_SCAN_MODE_LINEART) == 0) @@ -1651,7 +1651,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) MIN ((int) (MM_TO_PIXEL (SANE_UNFIX(hndl->val[OPT_BR_Y].w), hndl->dev->maxres) + 0.5), hndl->dev->maxvsize); - + /* If necessary, swap the upper and lower boundaries to avoid negative distances. */ if (hndl->topX > hndl->bottomX) { @@ -1913,7 +1913,7 @@ sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) if (hndl->state != STATE_SCANNING) return SANE_STATUS_INVAL; - + if (fcntl (hndl->pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) { @@ -1943,7 +1943,7 @@ sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) if (hndl->state != STATE_SCANNING) return SANE_STATUS_INVAL; - + *fd = hndl->pipe; return SANE_STATUS_GOOD; diff --git a/backend/mustek_pp.conf.in b/backend/mustek_pp.conf.in index 17f0e26..b2abf9a 100644 --- a/backend/mustek_pp.conf.in +++ b/backend/mustek_pp.conf.in @@ -12,7 +12,7 @@ # # SANE_DEBUG_SANEI_PA4S2=128 scanimage -L # ... # hangs here -> [sanei_pa4s2] sanei_pa4s2_readbyte: read in EPP mode -# +# # Scanner definition template: # ============================ # @@ -39,20 +39,20 @@ # - cis1200+ (for Mustek 1200CP+ & OEM versions), # - ccd300 (for Mustek 600 III EPP & OEM versions) # - ... more types will be added in the future -# +# # is a name of an option, and an optional value # for the option. # Currently available options for *CIS* type scanners are: -# - top_adjust : +# - top_adjust : # Vertical adjustment of origin, in millimeter. -# Values between -5.0 and +5.0 mm are possible +# Values between -5.0 and +5.0 mm are possible # (floating point). # Default: 0.0 -# - slow_skip: +# - slow_skip: # Boolean option. Disables fast skipping to the start # of the scan region. May be necessary in case fast # skipping results in inaccuracies. -# Default: fast skipping enabled +# Default: fast skipping enabled # - bw : # Black/white discrimination value for lineart scans. # Pixel values below that value are considered black, diff --git a/backend/mustek_pp.h b/backend/mustek_pp.h index 19f1765..09b4ceb 100644 --- a/backend/mustek_pp.h +++ b/backend/mustek_pp.h @@ -47,13 +47,13 @@ #if defined(HAVE_SYS_TIME_H) # include #endif - + #define DEBUG_NOT_STATIC #include "../include/sane/sanei_debug.h" /* Please note: ASSERT won't go away if you define NDEBUG, it just won't * output a message when ASSERT failes. So if "cond" does anything, it will - * be executed, even if NDEBUG is defined... + * be executed, even if NDEBUG is defined... */ #define ASSERT(cond, retval) do { \ if (!(cond)) { \ @@ -112,7 +112,7 @@ typedef struct { void (*setup)(SANE_Handle hndl); /* processes a configuration option */ - SANE_Status (*config)(SANE_Handle hndl, + SANE_Status (*config)(SANE_Handle hndl, SANE_String_Const optname, SANE_String_Const optval); @@ -150,7 +150,7 @@ typedef struct Mustek_pp_config_option { SANE_String name; SANE_String value; - + } Mustek_pp_config_option; typedef struct Mustek_pp_Device { @@ -174,11 +174,11 @@ typedef struct Mustek_pp_Device { /* functions */ Mustek_pp_Functions *func; - + /* Modified by EDG: device identification is needed to initialize private device descriptor */ SANE_Int info; - + /* Array of configuration file options */ int numcfgoptions; Mustek_pp_config_option *cfgoptions; @@ -240,8 +240,8 @@ typedef struct Mustek_pp_Handle { struct Mustek_pp_Handle *next; - - + + Mustek_pp_Device *dev; int fd; @@ -250,7 +250,7 @@ typedef struct Mustek_pp_Handle { int pipe; int state; - + int topX, topY; int bottomX, bottomY; int mode; @@ -263,7 +263,7 @@ typedef struct Mustek_pp_Handle { int use_ta; int depth; int speed; - + /* current parameters */ SANE_Parameters params; @@ -271,7 +271,7 @@ typedef struct Mustek_pp_Handle { SANE_Range x_range; SANE_Range y_range; SANE_Range gamma_range; - + /* options */ SANE_Option_Descriptor opt[NUM_OPTIONS]; Option_Value val[NUM_OPTIONS]; @@ -280,7 +280,7 @@ typedef struct Mustek_pp_Handle { time_t lamp_on; void *priv; - + } Mustek_pp_Handle; #endif /* mustek_pp_h */ diff --git a/backend/mustek_pp_ccd300.c b/backend/mustek_pp_ccd300.c index 41ad0ec..2bf06b3 100644 --- a/backend/mustek_pp_ccd300.c +++ b/backend/mustek_pp_ccd300.c @@ -36,8 +36,8 @@ 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. - + If you do not wish that, delete this exception notice. + This file implements the hardware driver scanners using a 300dpi CCD */ #include "mustek_pp_ccd300.h" @@ -1881,7 +1881,7 @@ ccd300_start (SANE_Handle handle) priv->hwres); priv->skipimagebytes = dev->topX; - + sanei_pa4s2_enable (dev->fd, SANE_TRUE); config_ccd (dev); set_voltages (dev); diff --git a/backend/mustek_pp_ccd300.h b/backend/mustek_pp_ccd300.h index 5dfe42d..a8cf009 100644 --- a/backend/mustek_pp_ccd300.h +++ b/backend/mustek_pp_ccd300.h @@ -36,8 +36,8 @@ 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. - + If you do not wish that, delete this exception notice. + This file implements the hardware driver scanners using a 300dpi CCD */ #ifndef __MUSTEK_PP_CCD300_H #define __MUSTEK_PP_CCD300_H diff --git a/backend/mustek_pp_cis.c b/backend/mustek_pp_cis.c index 96e89f1..e95c6cf 100644 --- a/backend/mustek_pp_cis.c +++ b/backend/mustek_pp_cis.c @@ -44,14 +44,14 @@ /* Global picture - + Mustek_PP_handle -> Mustek_PP_dev -> priv = Mustek_PP_CIS_dev -> CIS */ - + /* * This flag determines whether the scanner uses fast skipping at high - * resolutions. It is possible that this fast skipping introduces + * resolutions. It is possible that this fast skipping introduces * inaccuracies. It if turns out to be a problem, fast skipping can * be disabled by setting this flag to 0. */ @@ -68,7 +68,7 @@ #define MUSTEK_PP_CIS_1200CP_DEFAULT_SKIP 330 /* - * Number of scan lines on which the average is taken to determine the + * Number of scan lines on which the average is taken to determine the * maximum number of color levels. */ #define MUSTEK_PP_CIS_AVERAGE_COUNT 32 @@ -110,14 +110,14 @@ *** MA1015 chipset related functionality *** ****************************************************************************** *****************************************************************************/ - + /* - These defines control some debugging functionality + These defines control some debugging functionality #define M1015_TRACE_REGS -> trace the status of the internal registers #define M1015_LOG_HL -> create a high-level log file (register-level) #define M1015_LOG_LL -> create a low-level log file (byte-level) - + By default, all logging/tracing is turned off. */ @@ -130,13 +130,13 @@ #ifdef M1015_LOG_LL static FILE* M1015_LOG_1; - + #define M1015_START_LL\ M1015_LOG_1 = fopen("cis_ll.log", "w"); - + #define M1015_STOP_LL\ fclose(M1015_LOG_1); - + #define SANEI_PA4S2_WRITEBYTE(fd, reg, val)\ do\ {\ @@ -144,10 +144,10 @@ fprintf(M1015_LOG_1, "\tsanei_pa4s2_writebyte(fd, %d, 0x%02X);\n", \ reg, val);\ } while (0) - + static const char* cis_last_rreg_name; - static int cis_read_count; - + static int cis_read_count; + #define SANEI_PA4S2_READBEGIN(fd, reg)\ do\ {\ @@ -155,14 +155,14 @@ cis_read_count = 0;\ sanei_pa4s2_readbegin(fd, reg);\ } while (0) - + #define SANEI_PA4S2_READBYTE(fd, val)\ do\ {\ sanei_pa4s2_readbyte(fd, val);\ ++cis_read_count;\ } while (0) - + #define SANEI_PA4S2_READEND(fd)\ do\ {\ @@ -170,41 +170,41 @@ fprintf(M1015_LOG_1, "\tread_reg(%s, %d);\n", \ cis_last_rreg_name, cis_read_count);\ } while (0) - + #define M1015_MARK_LL(info)\ fprintf(M1015_LOG_1, "* %s\n", info); - + #else /* M1015_LOG_LL */ #define M1015_START_LL #define M1015_STOP_LL - + #define SANEI_PA4S2_WRITEBYTE(fd, reg, val)\ sanei_pa4s2_writebyte (fd, reg, val) - + #define SANEI_PA4S2_READBEGIN(fd, reg)\ sanei_pa4s2_readbegin(fd, reg) - + #define SANEI_PA4S2_READBYTE(fd, val)\ sanei_pa4s2_readbyte(fd, val) - + #define SANEI_PA4S2_READEND(fd)\ sanei_pa4s2_readend(fd) - + #define M1015_MARK_LL(info) - + #endif /* M1015_LOG_LL */ - + /****************************************************************************** * High-level logging: traces the flow of the driver in a hierarchical way * up to the level of register acccesses. - *****************************************************************************/ + *****************************************************************************/ #ifdef M1015_LOG_HL static FILE* M1015_LOG_2; static char hl_prev_line[4096], hl_next_line[4096], hl_repeat_count; - + /* * A few variables for hierarchical log message indentation. */ @@ -213,7 +213,7 @@ " "; static const char* cis_indent; static const char* cis_indent_end; - + #define M1015_START_HL\ M1015_LOG_2 = fopen("cis_hl.log", "w");\ cis_indent = cis_indent_start + strlen(cis_indent_start);\ @@ -221,7 +221,7 @@ hl_prev_line[0] = 0;\ hl_next_line[0] = 0;\ hl_repeat_count = 0; - + #define M1015_FLUSH_HL\ if (strcmp(hl_prev_line, hl_next_line))\ {\ @@ -238,7 +238,7 @@ {\ hl_repeat_count += 1;\ } - + #define M1015_MARK(info)\ sprintf(&hl_next_line[0], "%s+ %s\n", cis_indent, info);\ M1015_FLUSH_HL @@ -246,45 +246,45 @@ #define M1015_STOP_HL\ hl_next_line[0] = 0;\ M1015_FLUSH_HL\ - fclose(M1015_LOG_2); - -#else /* M1015_LOG_HL */ + fclose(M1015_LOG_2); + +#else /* M1015_LOG_HL */ #define M1015_START_HL #define M1015_STOP_HL #define M1015_MARK(info) #define M1015_FLUSH_HL - + #endif /* M1015_LOG_HL */ #ifdef M1015_TRACE_REGS #define M1015_DISPLAY_REGS(dev, msg) Mustek_PP_1015_display_regs(dev, msg) #define M1015_DISPLAY_REG(msg, val) Mustek_PP_1015_display_reg(msg, val) #else - #define M1015_DISPLAY_REGS(dev, msg) - #define M1015_DISPLAY_REG(msg, val) + #define M1015_DISPLAY_REGS(dev, msg) + #define M1015_DISPLAY_REG(msg, val) #endif - + #if defined (M1015_LOG_HL) || defined (M1015_LOG_LL) -static const char* +static const char* Mustek_PP_1015_reg_r_name(Mustek_PP_1015R_reg id) { static const char* names[4] = { "ASIC", "SCAN_VAL", "MOTOR", "BANK_COUNT" }; return names[id & 0x03]; } -static const char* +static const char* Mustek_PP_1015_bit_name(Mustek_PP_1015R_bit id) { static const char* names[4] = { "????", "MOTOR_HOME", "????", "MOTOR_BUSY" }; return names[id & 0x03]; } -static const char* +static const char* Mustek_PP_1015_reg_w_name(Mustek_PP_1015R_reg id) { - static const char* names[4][4] = + static const char* names[4][4] = { { "RED_REF", "GREEN_REF", "BLUE_REF", "DPI_CONTROL" }, { "BYTE_COUNT_HB", "BYTE_COUNT_LB", "SKIP_COUNT", "EXPOSE_TIME" }, @@ -304,9 +304,9 @@ Mustek_PP_1015_show_val(int val) /* Since we use a static temporary buffer, we must make sure that the buffer isn't altered while it is still in use (typically because - more than one value is converted in a printf statement). + more than one value is converted in a printf statement). Therefore the buffer is organized as a ring buffer. If should contain - at least 21 elements in order to be able to display all registers + at least 21 elements in order to be able to display all registers with one printf statement. */ #define Mustek_PP_1015_RING_BUFFER_SIZE 50 @@ -314,9 +314,9 @@ Mustek_PP_1015_show_val(int val) static int index = 0; int i; char* current = (char*)buf[index++]; - + if (index >= Mustek_PP_1015_RING_BUFFER_SIZE) index = 0; - + if (val < 0) { /* The register has not been initialized yet. */ @@ -345,8 +345,8 @@ Mustek_PP_1015_display_regs(Mustek_PP_CIS_dev * dev, const char* info) * Rx : read-only register no. x * ByWx : write-only register no. x of bank no. y */ - - fprintf(stderr, + + fprintf(stderr, "\n" "Register status: %s\n" "\n" @@ -403,12 +403,12 @@ Mustek_PP_1015_display_regs(Mustek_PP_CIS_dev * dev, const char* info) (dev->CIS.regs.channel == 0x40 ? "GREEN" : (dev->CIS.regs.channel == 0xC0 ? "BLUE" : "unknown"))) ); -} +} /****************************************************************************** * Displays a single register value *****************************************************************************/ -static void +static void Mustek_PP_1015_display_reg(const char* info, int val) { fprintf (stderr, "%s: %s\n", info, Mustek_PP_1015_show_val(val)); @@ -432,21 +432,21 @@ Mustek_PP_1015_read_reg(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg) { SANE_Byte tmp; assert(reg <= 3); - - SANEI_PA4S2_READBEGIN (dev->desc->fd, reg & 0x03); - SANEI_PA4S2_READBYTE (dev->desc->fd, &tmp); - SANEI_PA4S2_READEND (dev->desc->fd); - + + SANEI_PA4S2_READBEGIN (dev->desc->fd, reg & 0x03); + SANEI_PA4S2_READBYTE (dev->desc->fd, &tmp); + SANEI_PA4S2_READEND (dev->desc->fd); + #ifdef M1015_LOG_HL - sprintf(&hl_next_line[0], "%s read_reg(%s); [%s]\n", cis_indent, + sprintf(&hl_next_line[0], "%s read_reg(%s); [%s]\n", cis_indent, Mustek_PP_1015_reg_r_name(reg), Mustek_PP_1015_show_val(tmp)); M1015_FLUSH_HL; #endif - -#ifdef M1015_TRACE_REGS + +#ifdef M1015_TRACE_REGS dev->CIS.regs.in_regs[reg & 0x03] = tmp; #endif - + return tmp; } @@ -463,12 +463,12 @@ Mustek_PP_1015_wait_bit(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg, SANE_Byte tmp; SANE_Byte mask, val; int tries = 0; - + assert(reg <= 3); assert(bit <= 3); - + mask = 1 << bit; - + /* We don't want to wait forever */ while (dev->desc->state != STATE_CANCELLED) { @@ -476,26 +476,26 @@ Mustek_PP_1015_wait_bit(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg, ++tries; #endif - sanei_pa4s2_readbegin (dev->desc->fd, reg & 0x03); - sanei_pa4s2_readbyte (dev->desc->fd, &tmp); - sanei_pa4s2_readend (dev->desc->fd); - + sanei_pa4s2_readbegin (dev->desc->fd, reg & 0x03); + sanei_pa4s2_readbyte (dev->desc->fd, &tmp); + sanei_pa4s2_readend (dev->desc->fd); + #ifdef M1015_LOG_HL - sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d): %s %s;\n", cis_indent, + sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d): %s %s;\n", cis_indent, Mustek_PP_1015_reg_r_name(reg), Mustek_PP_1015_bit_name(bit), on?1:0, Mustek_PP_1015_show_val(mask), Mustek_PP_1015_show_val(tmp)); M1015_FLUSH_HL; #endif val = ((on == SANE_TRUE) ? tmp : ~tmp ) & mask; - + if (val != 0) break; - + if (period) usleep(period); - - if (tries > 50000) + + if (tries > 50000) { #ifdef M1015_LOG_HL - sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d): failed;\n", cis_indent, + sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d): failed;\n", cis_indent, Mustek_PP_1015_reg_r_name(reg), Mustek_PP_1015_bit_name(bit), on?1:0); M1015_FLUSH_HL; #endif @@ -504,9 +504,9 @@ Mustek_PP_1015_wait_bit(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg, return SANE_FALSE; } } - + #ifdef M1015_LOG_HL - sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d);\n", cis_indent, + sprintf(&hl_next_line[0], "%s wait_bit(%s, %s, %d);\n", cis_indent, Mustek_PP_1015_reg_r_name(reg), Mustek_PP_1015_bit_name(bit), on?1:0); M1015_FLUSH_HL; #endif @@ -514,12 +514,12 @@ Mustek_PP_1015_wait_bit(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg, fprintf(M1015_LOG_1, "\tread_reg(%s, %d);\n", Mustek_PP_1015_reg_r_name(reg), tries); #endif - -#ifdef M1015_TRACE_REGS + +#ifdef M1015_TRACE_REGS dev->CIS.regs.in_regs[reg & 0x03] = tmp; #endif return dev->desc->state != STATE_CANCELLED ? SANE_TRUE : SANE_FALSE; -} +} /****************************************************************************** * @@ -540,9 +540,9 @@ Mustek_PP_1015_wait_bit(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg, * Bank 2 * 0: unknown, used to start linear sequence during calibration * 1: motor control code (forward, return home, ...) - * 2: never used + * 2: never used * 3: never used - * + * * Bank 3 * 0: reduction factor (16bit internal -> 8bit) -> target for calibration * 1: unknown -> always set to 0x05 @@ -550,27 +550,27 @@ Mustek_PP_1015_wait_bit(Mustek_PP_CIS_dev * dev, Mustek_PP_1015R_reg reg, * 3: never used * *****************************************************************************/ - + static void Mustek_PP_1015_write_reg(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, SANE_Byte val) { - + SANE_Byte regBank = (reg & 0xF0) >> 4; SANE_Byte regNo = (reg & 0x0F); - + assert (regNo <= 3); assert (regBank <= 3); - + SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (4+regNo))+ regBank); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, regBank); - -#ifdef M1015_TRACE_REGS + +#ifdef M1015_TRACE_REGS dev->CIS.regs.out_regs[regBank][regNo] = val; #endif #ifdef M1015_LOG_HL - sprintf(&hl_next_line[0], "%s write_reg(%s, 0x%02X);\n", cis_indent, + sprintf(&hl_next_line[0], "%s write_reg(%s, 0x%02X);\n", cis_indent, Mustek_PP_1015_reg_w_name(reg), val); M1015_FLUSH_HL; #endif @@ -586,28 +586,28 @@ Mustek_PP_1015_write_reg(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, SANE_ * *****************************************************************************/ static void -Mustek_PP_1015_write_reg2(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, +Mustek_PP_1015_write_reg2(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, SANE_Byte val1, SANE_Byte val2) { SANE_Byte regBank = (reg & 0xF0) >> 4; SANE_Byte regNo = (reg & 0x0F); - + assert (regNo <= 2); assert (regBank <= 3); - + SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (4+regNo))+ regBank); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val1); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (5+regNo))+ regBank); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val2); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, regBank); - -#ifdef M1015_TRACE_REGS + +#ifdef M1015_TRACE_REGS dev->CIS.regs.out_regs[regBank][regNo] = val1; dev->CIS.regs.out_regs[regBank][regNo+1] = val2; #endif - + #ifdef M1015_LOG_HL - sprintf(&hl_next_line[0], "%s write_reg2(%s, 0x%02X, 0x%02X);\n", + sprintf(&hl_next_line[0], "%s write_reg2(%s, 0x%02X, 0x%02X);\n", cis_indent, Mustek_PP_1015_reg_w_name(reg), val1, val2); M1015_FLUSH_HL; #endif @@ -624,15 +624,15 @@ Mustek_PP_1015_write_reg2(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, * *****************************************************************************/ static void -Mustek_PP_1015_write_reg3(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, +Mustek_PP_1015_write_reg3(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, SANE_Byte val1, SANE_Byte val2, SANE_Byte val3) { SANE_Byte regBank = (reg & 0xF0) >> 4; SANE_Byte regNo = (reg & 0x0F); - + assert (regNo <= 1); assert (regBank <= 3); - + SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (4+regNo))+ regBank); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val1); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (5+regNo))+ regBank); @@ -640,15 +640,15 @@ Mustek_PP_1015_write_reg3(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (6+regNo))+ regBank); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val3); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, regBank); - -#ifdef M1015_TRACE_REGS + +#ifdef M1015_TRACE_REGS dev->CIS.regs.out_regs[regBank][regNo ] = val1; dev->CIS.regs.out_regs[regBank][regNo+1] = val2; dev->CIS.regs.out_regs[regBank][regNo+2] = val3; #endif - + #ifdef M1015_LOG_HL - sprintf(&hl_next_line[0], "%s write_reg3(%s, 0x%02X, 0x%02X, 0x%02X);\n", + sprintf(&hl_next_line[0], "%s write_reg3(%s, 0x%02X, 0x%02X, 0x%02X);\n", cis_indent, Mustek_PP_1015_reg_w_name(reg), val1, val2, val3); M1015_FLUSH_HL; #endif @@ -656,43 +656,43 @@ Mustek_PP_1015_write_reg3(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg, /****************************************************************************** * Opens a register for a (series of) write operation(s). - *****************************************************************************/ + *****************************************************************************/ static void Mustek_PP_1015_write_reg_start(Mustek_PP_CIS_dev * dev, Mustek_PP_1015W_reg reg) { SANE_Byte regBank = (reg & 0xF0) >> 4; SANE_Byte regNo = (reg & 0x0F); - + assert (regNo <= 3); assert (regBank <= 3); - + dev->CIS.regs.current_write_reg = reg; - + #ifdef M1015_LOG_HL dev->CIS.regs.write_count = 0; #endif - + SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, (1 << (4+regNo))+ regBank); } /****************************************************************************** * Writes a value to the currently open register. - *****************************************************************************/ + *****************************************************************************/ static void Mustek_PP_1015_write_reg_val(Mustek_PP_CIS_dev * dev, SANE_Byte val) { -#ifdef M1015_TRACE_REGS +#ifdef M1015_TRACE_REGS SANE_Byte regBank = (dev->CIS.regs.current_write_reg & 0xF0) >> 4; SANE_Byte regNo = (dev->CIS.regs.current_write_reg & 0x0F); - + assert (regNo <= 3); assert (regBank <= 3); - + dev->CIS.regs.out_regs[regBank][regNo] = val; #endif - + SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 5, val); - + #ifdef M1015_LOG_HL ++dev->CIS.regs.write_count; #endif @@ -700,7 +700,7 @@ Mustek_PP_1015_write_reg_val(Mustek_PP_CIS_dev * dev, SANE_Byte val) /****************************************************************************** * Closes a register after a (series of) write operation(s). - *****************************************************************************/ + *****************************************************************************/ static void Mustek_PP_1015_write_reg_stop(Mustek_PP_CIS_dev * dev) { @@ -708,16 +708,16 @@ Mustek_PP_1015_write_reg_stop(Mustek_PP_CIS_dev * dev) #ifdef M1015_LOG_HL SANE_Byte regNo = (dev->CIS.regs.current_write_reg & 0x0F); assert (regNo <= 3); - + sprintf(&hl_next_line[0], "%s write_reg_multi(%s, *%d);\n", cis_indent, - Mustek_PP_1015_reg_w_name(dev->CIS.regs.current_write_reg), + Mustek_PP_1015_reg_w_name(dev->CIS.regs.current_write_reg), dev->CIS.regs.write_count); M1015_FLUSH_HL; #endif assert (regBank <= 3); - + SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, regBank); -} +} /****************************************************************************** * @@ -725,12 +725,12 @@ Mustek_PP_1015_write_reg_stop(Mustek_PP_CIS_dev * dev) * internal registers, ie., the 3rd bit should not be zero. * *****************************************************************************/ -static void +static void Mustek_PP_1015_send_command(Mustek_PP_CIS_dev * dev, SANE_Byte command) { assert (command & 0x04); SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, command); - + #ifdef M1015_LOG_HL sprintf(&hl_next_line[0], "%s send_command(0x%02X);\n", cis_indent, command); M1015_FLUSH_HL; @@ -742,7 +742,7 @@ Mustek_PP_1015_send_command(Mustek_PP_CIS_dev * dev, SANE_Byte command) ## CIS driver ## ############################################################################## *****************************************************************************/ - + /****************************************************************************** * Resolution conversion functions *****************************************************************************/ @@ -810,7 +810,7 @@ cis_wait_bank_change (Mustek_PP_CIS_dev * dev, int bankcount) struct timeval start, end; unsigned long diff; int firsttime = 1; - + gettimeofday (&start, NULL); do @@ -830,14 +830,14 @@ cis_wait_bank_change (Mustek_PP_CIS_dev * dev, int bankcount) } while ((dev->bank_count != bankcount) && (diff < MUSTEK_PP_CIS_WAIT_BANK)); - + if (dev->bank_count != bankcount && dev->desc->state != STATE_CANCELLED) { u_char tmp; tmp = Mustek_PP_1015_read_reg(dev, 3); DBG(2, "cis_wait_bank_change: Missed a bank: got %d [%s], " - "wanted %d, waited %d msec\n", - dev->bank_count, Mustek_PP_1015_show_val(tmp), bankcount, + "wanted %d, waited %d msec\n", + dev->bank_count, Mustek_PP_1015_show_val(tmp), bankcount, MUSTEK_PP_CIS_WAIT_BANK); } @@ -846,10 +846,10 @@ cis_wait_bank_change (Mustek_PP_CIS_dev * dev, int bankcount) /****************************************************************************** * Configure the CIS for a given resolution. - * - * CIS scanners seem to have 2 modes: * - * low resolution (50-300 DPI) and + * CIS scanners seem to have 2 modes: + * + * low resolution (50-300 DPI) and * high resolution (300-600 DPI). * * Depending on the resolution requested by the user, the scanner is used @@ -861,7 +861,7 @@ static void cis_set_dpi_value (Mustek_PP_CIS_dev * dev) { u_char val = 0; - + if (dev->model == MUSTEK_PP_CIS1200PLUS) { /* Toshiba CIS: only 600 DPI + decimation */ @@ -887,7 +887,7 @@ cis_set_dpi_value (Mustek_PP_CIS_dev * dev) break; default: assert (0); - } + } } else { @@ -916,7 +916,7 @@ cis_set_dpi_value (Mustek_PP_CIS_dev * dev) assert (0); } } - + Mustek_PP_1015_write_reg(dev, MA1015W_DPI_CONTROL, val | 0x04); DBG (4, "cis_set_dpi_value: dpi: %d -> value 0x%02x\n", dev->CIS.hw_hres, val); @@ -928,19 +928,19 @@ cis_set_ccd_channel (Mustek_PP_CIS_dev * dev) SANE_Byte codes[] = { 0x84, 0x44, 0xC4 }; SANE_Byte chancode; - + assert (dev->CIS.channel < 3); - + chancode = codes[dev->CIS.channel]; - - /* - The TWAIN driver sets an extra bit in lineart mode. - When I do this too, I don't see any effect on the image. - Moreover, for 1 resolution, namely 400 dpi, the bank counter seems + + /* + The TWAIN driver sets an extra bit in lineart mode. + When I do this too, I don't see any effect on the image. + Moreover, for 1 resolution, namely 400 dpi, the bank counter seems to behave strangely, and the synchronization get completely lost. I guess the software conversion from gray to lineart is good enough, so I'll leave it like that. - + if (dev->CIS.setParameters) { chancode |= (dev->desc->mode == MODE_BW) ? 0x20: 0; @@ -948,7 +948,7 @@ cis_set_ccd_channel (Mustek_PP_CIS_dev * dev) */ SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, chancode); - + #ifdef M1015_TRACE_REGS dev->CIS.regs.channel = chancode; #endif @@ -958,43 +958,43 @@ static void cis_config_ccd (Mustek_PP_CIS_dev * dev) { SANE_Int skipCount, byteCount; - + if (dev->CIS.res != 0) dev->CIS.hres_step = SANE_FIX ((float) dev->CIS.hw_hres / (float) dev->CIS.res); /* CIS: <= 300 dpi -> 0x86 - > 300 dpi -> 0x96 */ + > 300 dpi -> 0x96 */ if (dev->CIS.cisRes == 600) SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, 0x96); else SANEI_PA4S2_WRITEBYTE (dev->desc->fd, 6, 0x86); - + cis_set_dpi_value(dev); - + if (dev->CIS.setParameters) { dev->CIS.channel = dev->desc->mode == MODE_COLOR ? MUSTEK_PP_CIS_CHANNEL_RED : MUSTEK_PP_CIS_CHANNEL_GRAY; } else - { + { dev->CIS.channel = MUSTEK_PP_CIS_CHANNEL_GRAY; } - + cis_set_ccd_channel (dev); - + Mustek_PP_1015_write_reg (dev, MA1015W_POWER_ON_DELAY, 0xAA); - Mustek_PP_1015_write_reg (dev, MA1015W_CCD_TIMING, 0x05); - Mustek_PP_1015_write_reg (dev, MA1015W_CCD_TIMING_ADJ, 0x00); + Mustek_PP_1015_write_reg (dev, MA1015W_CCD_TIMING, 0x05); + Mustek_PP_1015_write_reg (dev, MA1015W_CCD_TIMING_ADJ, 0x00); Mustek_PP_1015_send_command (dev, 0x45); /* or 0x05 for no 8kbank */ /* * Unknown sequence. * Seems to be always the same during configuration, independent of the - * mode and the resolution. + * mode and the resolution. */ CIS_CLEAR_FULLFLAG(dev); CIS_INC_READ(dev); @@ -1020,14 +1020,14 @@ cis_config_ccd (Mustek_PP_CIS_dev * dev) # > 300 DPI # # Skip = 67 + skipimage - # + # # Skip1 = Skip / 32 # Skip2 = Skip % 32 # # Bytes = Skip2*hw_hres/600 + (imagebytes * hw_hres/res) + 2 # */ - + skipCount = 67; /* Hardware parameter - fixed */ if (dev->CIS.setParameters == SANE_TRUE) @@ -1043,11 +1043,11 @@ cis_config_ccd (Mustek_PP_CIS_dev * dev) */ DBG(4, "cis_config_ccd: Skip count: %d\n", skipCount); skipCount += max2cis_hres(dev, dev->CIS.skipimagebytes); - DBG(4, "cis_config_ccd: Skip count: %d (cis res: %d)\n", skipCount, + DBG(4, "cis_config_ccd: Skip count: %d (cis res: %d)\n", skipCount, dev->CIS.cisRes); skipCount += (int)(2.0/25.4*dev->CIS.cisRes); DBG(4, "cis_config_ccd: Skip count: %d\n", skipCount); - + Mustek_PP_1015_write_reg (dev, MA1015W_SKIP_COUNT, skipCount / 32); DBG(4, "cis_config_ccd: Skip count: %d (x32)\n", skipCount / 32); } @@ -1056,12 +1056,12 @@ cis_config_ccd (Mustek_PP_CIS_dev * dev) Mustek_PP_1015_write_reg (dev, MA1015W_SKIP_COUNT, 0); DBG(4, "cis_config_ccd: Skip count: 67 (x32)\n"); } - + skipCount %= 32; skipCount = cis2max_res(dev, skipCount); /* Back to max res */ - - Mustek_PP_1015_write_reg(dev, MA1015W_EXPOSE_TIME, dev->CIS.exposeTime); - + + Mustek_PP_1015_write_reg(dev, MA1015W_EXPOSE_TIME, dev->CIS.exposeTime); + DBG(4, "cis_config_ccd: skipcount: %d imagebytes: %d\n", skipCount, dev->CIS.imagebytes); /* set_initial_skip_1015 (dev); */ if (dev->CIS.setParameters == SANE_TRUE) @@ -1071,20 +1071,20 @@ cis_config_ccd (Mustek_PP_CIS_dev * dev) /* The TWAIN drivers always sends the same value: 0x96 */ Mustek_PP_1015_write_reg3(dev, MA1015W_RED_REF, 0x96, 0x96, 0x96); dev->CIS.adjustskip = max2hw_hres(dev, skipCount); - byteCount = max2hw_hres(dev, skipCount + dev->CIS.imagebytes) + 2; + byteCount = max2hw_hres(dev, skipCount + dev->CIS.imagebytes) + 2; dev->CIS.setParameters = SANE_FALSE; } else { dev->CIS.adjustskip = 0; - byteCount = max2hw_hres(dev, skipCount); + byteCount = max2hw_hres(dev, skipCount); } - DBG(4, "cis_config_ccd: adjust skip: %d bytecount: %d\n", + DBG(4, "cis_config_ccd: adjust skip: %d bytecount: %d\n", dev->CIS.adjustskip, byteCount); - - Mustek_PP_1015_write_reg2(dev, MA1015W_BYTE_COUNT_HB, - byteCount >> 8, byteCount & 0xFF); - + + Mustek_PP_1015_write_reg2(dev, MA1015W_BYTE_COUNT_HB, + byteCount >> 8, byteCount & 0xFF); + cis_get_bank_count (dev); DBG(5, "cis_config_ccd: done\n"); } @@ -1093,8 +1093,8 @@ static SANE_Bool cis_wait_motor_stable (Mustek_PP_CIS_dev * dev) { static struct timeval timeoutVal; - SANE_Bool ret = - Mustek_PP_1015_wait_bit (dev, MA1015R_MOTOR, MA1015B_MOTOR_STABLE, + SANE_Bool ret = + Mustek_PP_1015_wait_bit (dev, MA1015R_MOTOR, MA1015B_MOTOR_STABLE, SANE_FALSE, 0); #ifdef HAVE_SYS_SELECT_H if (dev->engine_delay > 0) @@ -1111,7 +1111,7 @@ static void cis_motor_forward (Mustek_PP_CIS_dev * dev) { SANE_Byte control; - + if (dev->model == MUSTEK_PP_CIS600) { switch (dev->CIS.hw_vres) @@ -1150,11 +1150,11 @@ cis_motor_forward (Mustek_PP_CIS_dev * dev) #if MUSTEK_PP_CIS_MOTOR_REVERSE == 1 control ^= 0x10; #endif - + DBG(4, "cis_motor_forward: @%d dpi: 0x%02X.\n", dev->CIS.hw_vres, control); if (!cis_wait_motor_stable (dev)) return; - + Mustek_PP_1015_write_reg(dev, MA1015W_MOTOR_CONTROL, control); } @@ -1166,20 +1166,20 @@ cis_move_motor (Mustek_PP_CIS_dev * dev, SANE_Int steps) /* steps @ maxres */ SANE_Int fullSteps, biSteps, quadSteps; /* * During a multi-step feed, the expose time is fixed. The value depends - * on the type of the motor (600/1200 CP) + * on the type of the motor (600/1200 CP) */ SANE_Byte savedExposeTime = dev->CIS.exposeTime; dev->CIS.exposeTime = 85; - + DBG(4, "cis_move_motor: Moving motor %d steps.\n", steps); - + /* Just in case ... */ if (steps < 0) { DBG(1, "cis_move_motor: trying to move negative steps: %d\n", steps); steps = 0; /* We must go through the configuration procedure */ - } - + } + /* * Using the parameter settings for the 600 CP on a 1200 CP scanner * doesn't work: the engine doesn't move and makes a sharp noise, which @@ -1190,8 +1190,8 @@ cis_move_motor (Mustek_PP_CIS_dev * dev, SANE_Int steps) /* steps @ maxres */ dev->CIS.exposeTime <<= 1; cis_config_ccd(dev); dev->CIS.exposeTime = savedExposeTime; - - /* + + /* * This is a minor speed optimization: when we are using the high * resolution mode, long feeds (eg, to move to a scan area at the bottom * of the page) can be made almost twice as fast by using double motor @@ -1199,8 +1199,8 @@ cis_move_motor (Mustek_PP_CIS_dev * dev, SANE_Int steps) /* steps @ maxres */ * It is possible, though, that fast skipping (which is the default) is * not very accurate on some scanners. Therefore, the user can disable * this through the configuration file. - */ - + */ + fullSteps = steps & 1; biSteps = steps >> 1; if (dev->fast_skip) { @@ -1210,33 +1210,33 @@ cis_move_motor (Mustek_PP_CIS_dev * dev, SANE_Int steps) /* steps @ maxres */ else { quadSteps = 0; } - + M1015_DISPLAY_REGS(dev, "Before move"); - + #if MUSTEK_PP_CIS_MOTOR_REVERSE == 1 fullStep ^= 0x10; biStep ^= 0x10; quadStep ^= 0x10; #endif - + DBG(4, "cis_move_motor: 4x%d 2x%d 1x%d\n", quadSteps, biSteps, fullSteps); - /* Note: the TWAIN driver opens the motor control register only + /* Note: the TWAIN driver opens the motor control register only once before the loop, and closes it after the loop. I've tried this too, but it resulted in inaccurate skip distances; therefore, the motor control register is now opened and closed for each step. */ - + while (quadSteps-- > 0 && dev->desc->state != STATE_CANCELLED) { cis_wait_motor_stable (dev); Mustek_PP_1015_write_reg(dev, MA1015W_MOTOR_CONTROL, quadStep); } - + while (biSteps-- > 0 && dev->desc->state != STATE_CANCELLED) { cis_wait_motor_stable (dev); Mustek_PP_1015_write_reg(dev, MA1015W_MOTOR_CONTROL, biStep); } - + while (fullSteps-- > 0 && dev->desc->state != STATE_CANCELLED) { cis_wait_motor_stable (dev); @@ -1247,16 +1247,16 @@ cis_move_motor (Mustek_PP_CIS_dev * dev, SANE_Int steps) /* steps @ maxres */ static void cis_set_et_pd_sti (Mustek_PP_CIS_dev * dev) { - Mustek_PP_1015_write_reg(dev, MA1015W_EXPOSE_TIME, + Mustek_PP_1015_write_reg(dev, MA1015W_EXPOSE_TIME, dev->CIS.exposeTime); - Mustek_PP_1015_write_reg(dev, MA1015W_POWER_ON_DELAY, + Mustek_PP_1015_write_reg(dev, MA1015W_POWER_ON_DELAY, dev->CIS.powerOnDelay[dev->CIS.channel]); cis_set_ccd_channel (dev); cis_set_sti (dev); } /* - * Prepare the scanner for catching the next channel and, if necessary, + * Prepare the scanner for catching the next channel and, if necessary, * move the head one step further. */ static SANE_Bool @@ -1264,32 +1264,32 @@ cis_wait_next_channel (Mustek_PP_CIS_dev * dev) { int moveAtChannel = dev->desc->mode == MODE_COLOR ? MUSTEK_PP_CIS_CHANNEL_BLUE : MUSTEK_PP_CIS_CHANNEL_GRAY; - + if (!cis_wait_bank_change (dev, dev->bank_count)) { DBG(2, "cis_wait_next_channel: Could not get next bank.\n"); return SANE_FALSE; } - + moveAtChannel = (dev->desc->mode == MODE_COLOR) ? MUSTEK_PP_CIS_CHANNEL_BLUE : MUSTEK_PP_CIS_CHANNEL_GRAY; - + if (dev->CIS.channel == moveAtChannel && !dev->CIS.dontMove) { cis_motor_forward (dev); } - + cis_set_et_pd_sti (dev); - + if (dev->desc->mode == MODE_COLOR) { ++dev->CIS.channel; dev->CIS.channel %= 3; } - + return SANE_TRUE; } - + /* * Wait for the device to be ready for scanning. Cycles through the different * channels and sets the parameters (only green channel in gray/lineart). @@ -1299,10 +1299,10 @@ cis_wait_read_ready (Mustek_PP_CIS_dev * dev) { int channel; dev->CIS.dontIncRead = SANE_TRUE; - + dev->CIS.channel = dev->desc->mode == MODE_COLOR ? MUSTEK_PP_CIS_CHANNEL_RED : MUSTEK_PP_CIS_CHANNEL_GRAY; - + for (channel = 0; channel < 3; ++channel) { if (!cis_wait_next_channel(dev)) return SANE_FALSE; @@ -1313,9 +1313,9 @@ cis_wait_read_ready (Mustek_PP_CIS_dev * dev) static int delay_read (int delay) { - /* + /* * A (very) smart compiler may complete optimize the delay loop away. By - * adding some difficult data dependencies, we can try to prevent this. + * adding some difficult data dependencies, we can try to prevent this. */ static int prevent_removal, i; for (i = 0; idesc->fd, 1); while(skips-- >= 0) @@ -1384,7 +1384,7 @@ cis_read_line_low_level (Mustek_PP_CIS_dev * dev, SANE_Byte * buf, else if (dev->CIS.hw_hres > dev->CIS.res) { /* Sub-sampling */ - + int pos = 0; DBG (6, "cis_read_line_low_level: sub-sampling\n"); ctr = 0; @@ -1428,8 +1428,8 @@ cis_read_line_low_level (Mustek_PP_CIS_dev * dev, SANE_Byte * buf, int calctr = 0; SANE_Int pos = 0, nextPos = 1; /* Step: eg: 600 DPI -> 700 DPI -> hres_step = 6/7 -> step = 1/7 */ - SANE_Int step = SANE_FIX(1) - dev->CIS.hres_step; - + SANE_Int step = SANE_FIX(1) - dev->CIS.hres_step; + /* Super-sampling */ DBG (6, "cis_read_line_low_level: super-sampling\n"); do @@ -1446,11 +1446,11 @@ cis_read_line_low_level (Mustek_PP_CIS_dev * dev, SANE_Byte * buf, if (calib_hi) { hi_val = calib_hi[calctr] ; } - + if (++calctr >= dev->calib_pixels) { - /* Avoid array boundary violations due to rounding errors + /* Avoid array boundary violations due to rounding errors (due to the incremental calculation, the current position - may be inaccurate to up to two pixels, so we may need to + may be inaccurate to up to two pixels, so we may need to read a few extra bytes -> use the last calibration value) */ calctr = dev->calib_pixels - 1; DBG (3, "cis_read_line_low_level: calibration overshoot\n"); @@ -1467,19 +1467,19 @@ cis_read_line_low_level (Mustek_PP_CIS_dev * dev, SANE_Byte * buf, cval = gamma[cval]; pos += step; - + if ((pos >> SANE_FIXED_SCALE_SHIFT) >= nextPos) { nextPos++; - + /* Insert an interpolated value */ buf[bpos] = (buf[bpos-1] + cval)/2; /* Interpolate */ ++bpos; - + /* Store the plain value, but only if we still need pixels */ if (bpos < pixel) buf[bpos++] = cval; - + pos += step; /* Take interpolated value into account for pos */ } else @@ -1489,7 +1489,7 @@ cis_read_line_low_level (Mustek_PP_CIS_dev * dev, SANE_Byte * buf, } while (bpos < pixel); } - + SANEI_PA4S2_READEND (dev->desc->fd); DBG (6, "cis_read_line_low_level: done\n"); } @@ -1502,8 +1502,8 @@ cis_read_line (Mustek_PP_CIS_dev * dev, SANE_Byte* buf, SANE_Int pixel, CIS_INC_READ(dev); else dev->CIS.dontIncRead = SANE_FALSE; - - + + if (raw) { /* No color correction; raw data */ @@ -1513,12 +1513,12 @@ cis_read_line (Mustek_PP_CIS_dev * dev, SANE_Byte* buf, SANE_Int pixel, { /* Color correction */ cis_read_line_low_level (dev, buf, pixel, - dev->calib_low[dev->CIS.channel], - dev->calib_hi[dev->CIS.channel], - (dev->desc->val[OPT_CUSTOM_GAMMA].w ? + dev->calib_low[dev->CIS.channel], + dev->calib_hi[dev->CIS.channel], + (dev->desc->val[OPT_CUSTOM_GAMMA].w ? dev->desc->gamma_table[dev->CIS.channel] : NULL)); } - + return cis_wait_next_channel(dev); } @@ -1528,7 +1528,7 @@ cis_get_next_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) SANE_Byte *dest, *tmpbuf = dev->tmpbuf; int ctr, channel, first, last, stride, step = dev->CIS.line_step; SANE_Byte gotline; - + if (dev->desc->mode == MODE_COLOR) { first = MUSTEK_PP_CIS_CHANNEL_RED; @@ -1541,7 +1541,7 @@ cis_get_next_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) last = MUSTEK_PP_CIS_CHANNEL_GRAY; stride = 1; } - + gotline = SANE_FALSE; do { @@ -1556,8 +1556,8 @@ cis_get_next_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) for (channel = first; channel <= last; ++channel) { - if (!cis_read_line(dev, tmpbuf, dev->desc->params.pixels_per_line, - SANE_FALSE)) + if (!cis_read_line(dev, tmpbuf, dev->desc->params.pixels_per_line, + SANE_FALSE)) return; dest = buf + channel - first; @@ -1601,7 +1601,7 @@ cis_get_color_line (Mustek_PP_CIS_dev * dev, SANE_Byte * buf) /****************************************************************************** * Saves the state of the device during reset and calibration. *****************************************************************************/ -static void +static void cis_save_state (Mustek_PP_CIS_dev * dev) { dev->Saved_CIS = dev->CIS; @@ -1610,7 +1610,7 @@ cis_save_state (Mustek_PP_CIS_dev * dev) /****************************************************************************** * Restores the state of the device after reset and calibration. *****************************************************************************/ -static void +static void cis_restore_state (Mustek_PP_CIS_dev * dev) { dev->CIS = dev->Saved_CIS; @@ -1624,10 +1624,10 @@ static int cis_check_result(SANE_Byte* buffer, int pixel) { int i, maxVal = 0; - - for (i=0;i maxVal) maxVal = buffer[i]; - + if (maxVal > 250) return CIS_TOO_BRIGHT; if (maxVal < 240) return CIS_TOO_DARK; return CIS_OK; @@ -1641,29 +1641,29 @@ cis_maximize_dynamic_range(Mustek_PP_CIS_dev * dev) SANE_Byte powerOnDelayLower[3], powerOnDelayUpper[3], exposeTime[3]; SANE_Byte buf[3][MUSTEK_PP_CIS_MAX_H_PIXEL]; SANE_Int pixels = dev->calib_pixels; - + DBG(3, "cis_maximize_dynamic_range: starting\n"); - + for (channel = 0; channel < 3; ++channel) { exposeTime[channel] = 254; dev->CIS.powerOnDelay[channel] = 170; powerOnDelayLower[channel] = 1; powerOnDelayUpper[channel] = 254; - } + } dev->CIS.setParameters = SANE_TRUE; dev->CIS.exposeTime = exposeTime[MUSTEK_PP_CIS_CHANNEL_GREEN]; cis_config_ccd(dev); - + M1015_DISPLAY_REGS(dev, "before maximizing dynamic range"); dev->CIS.dontMove = SANE_TRUE; /* Don't move while calibrating */ - + if (!cis_wait_read_ready(dev) && dev->desc->state != STATE_CANCELLED) { DBG(2, "cis_maximize_dynamic_range: DEVICE NOT READY!\n"); return SANE_FALSE; } - + if (dev->desc->mode == MODE_COLOR) { first = MUSTEK_PP_CIS_CHANNEL_RED; @@ -1674,10 +1674,10 @@ cis_maximize_dynamic_range(Mustek_PP_CIS_dev * dev) first = MUSTEK_PP_CIS_CHANNEL_GRAY; last = MUSTEK_PP_CIS_CHANNEL_GRAY; } - + dev->CIS.channel = first; - - /* Perform a kind of binary search. In the worst case, we should find + + /* Perform a kind of binary search. In the worst case, we should find the optimal power delay values after 8 iterations */ for( i=0; i<8; i++) { @@ -1686,20 +1686,20 @@ cis_maximize_dynamic_range(Mustek_PP_CIS_dev * dev) dev->CIS.powerOnDelay[channel] = (powerOnDelayLower[channel] + powerOnDelayUpper[channel]) / 2; } - Mustek_PP_1015_write_reg(dev, MA1015W_POWER_ON_DELAY, + Mustek_PP_1015_write_reg(dev, MA1015W_POWER_ON_DELAY, dev->CIS.powerOnDelay[1]); /* Green */ for (pixel = 0; pixel < pixels; ++pixel) { buf[0][pixel] = buf[1][pixel] = buf[2][pixel] = 255; } - + /* Scan 4 lines, but ignore the first 3 ones. */ for (j = 0; j < 4; ++j) { for (channel = first; channel <= last; ++channel) { - if (!cis_read_line(dev, &buf[channel][0], pixels, + if (!cis_read_line(dev, &buf[channel][0], pixels, /* raw = */ SANE_TRUE)) return SANE_FALSE; } @@ -1711,50 +1711,50 @@ cis_maximize_dynamic_range(Mustek_PP_CIS_dev * dev) { case CIS_TOO_BRIGHT: powerOnDelayLower[channel] = dev->CIS.powerOnDelay[channel]; - break; - + break; + case CIS_TOO_DARK: powerOnDelayUpper[channel] = dev->CIS.powerOnDelay[channel]; - break; - + break; + default: - break; + break; } - } - DBG (4, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", - dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], + } + DBG (4, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", + dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], dev->CIS.powerOnDelay[2]); } dev->CIS.dontMove = SANE_FALSE; - - DBG (3, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", - dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], + + DBG (3, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", + dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], dev->CIS.powerOnDelay[2]); - + minExposeTime = (dev->CIS.hw_hres <= 300) ? 170 : 253; - + for (channel = first; channel <= last; ++channel) { dev->CIS.powerOnDelay[channel] = (powerOnDelayLower[channel] + powerOnDelayUpper[channel]) / 2; exposeTime[channel] -= dev->CIS.powerOnDelay[channel] - 1; dev->CIS.powerOnDelay[channel] = 1; - + if (exposeTime[channel] < minExposeTime) { - dev->CIS.powerOnDelay[channel] += + dev->CIS.powerOnDelay[channel] += minExposeTime - exposeTime[channel]; exposeTime[channel] = minExposeTime; } - } - + } + dev->CIS.exposeTime = exposeTime[MUSTEK_PP_CIS_CHANNEL_GREEN]; - + DBG (3, "cis_maximize_dynamic_range: expose time: %3d\n", exposeTime[1]); - DBG (3, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", - dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], + DBG (3, "cis_maximize_dynamic_range: power on delay %3d %3d %3d\n", + dev->CIS.powerOnDelay[0], dev->CIS.powerOnDelay[1], dev->CIS.powerOnDelay[2]); - + /* * Short the calibration. Temporary, to find out what is wrong with * the calibration on a 600 CP. @@ -1776,29 +1776,29 @@ cis_measure_extremes(Mustek_PP_CIS_dev * dev, SANE_Byte* calib[3], SANE_Byte max[3][MUSTEK_PP_CIS_MAX_H_PIXEL]; SANE_Int sum[3][MUSTEK_PP_CIS_MAX_H_PIXEL]; int channel, cnt, p; - + memset((void*)&min, 255, 3*MUSTEK_PP_CIS_MAX_H_PIXEL*sizeof(SANE_Byte)); memset((void*)&max, 0, 3*MUSTEK_PP_CIS_MAX_H_PIXEL*sizeof(SANE_Byte)); memset((void*)&sum, 0, 3*MUSTEK_PP_CIS_MAX_H_PIXEL*sizeof(SANE_Int)); - + dev->CIS.channel = first; - + /* Purge the banks first (there's always a 3-cycle delay) */ for (channel = first; channel <= last; ++channel) { - if (!cis_read_line(dev, &buf[channel%3][0], pixels, + if (!cis_read_line(dev, &buf[channel%3][0], pixels, /* raw = */ SANE_TRUE)) return SANE_FALSE; } --dev->CIS.skipsToOrigin; - + for (cnt = 0; cnt < MUSTEK_PP_CIS_AVERAGE_COUNT + 2; ++cnt) { for (channel = first; channel <= last; ++channel) { - DBG(4, "cis_measure_extremes: Reading line %d - channel %d\n", + DBG(4, "cis_measure_extremes: Reading line %d - channel %d\n", cnt, channel); - if (!cis_read_line(dev, &buf[channel][0], pixels, + if (!cis_read_line(dev, &buf[channel][0], pixels, /* raw = */ SANE_TRUE)) return SANE_FALSE; @@ -1813,7 +1813,7 @@ cis_measure_extremes(Mustek_PP_CIS_dev * dev, SANE_Byte* calib[3], --dev->CIS.skipsToOrigin; } DBG(4, "cis_measure_extremes: Averaging\n"); - for (channel = first; channel <= last; ++channel) + for (channel = first; channel <= last; ++channel) { /* Ignore the extreme values and take the average of the others. */ for (p = 0; p < pixels; ++p) @@ -1825,7 +1825,7 @@ cis_measure_extremes(Mustek_PP_CIS_dev * dev, SANE_Byte* calib[3], } DBG(4, "cis_measure_extremes: Done\n"); return SANE_TRUE; -} +} static SANE_Bool cis_normalize_ranges(Mustek_PP_CIS_dev * dev) @@ -1834,7 +1834,7 @@ cis_normalize_ranges(Mustek_PP_CIS_dev * dev) SANE_Byte powerOnDelay[3] ; SANE_Int pixels = dev->calib_pixels; SANE_Int channel, p, first, last; - + if (dev->desc->mode == MODE_COLOR) { first = MUSTEK_PP_CIS_CHANNEL_RED; @@ -1845,7 +1845,7 @@ cis_normalize_ranges(Mustek_PP_CIS_dev * dev) first = MUSTEK_PP_CIS_CHANNEL_GRAY; last = MUSTEK_PP_CIS_CHANNEL_GRAY; } - + DBG(3, "cis_normalize_ranges: Measuring high extremes\n"); /* Measure extremes with normal lighting */ if (!cis_measure_extremes(dev, dev->calib_hi, pixels, first, last)) { @@ -1857,17 +1857,17 @@ cis_normalize_ranges(Mustek_PP_CIS_dev * dev) powerOnDelay[channel] = dev->CIS.powerOnDelay[channel]; dev->CIS.powerOnDelay[channel] = dev->CIS.exposeTime; } - + DBG(3, "cis_normalize_ranges: Measuring low extremes\n"); if (!cis_measure_extremes(dev, dev->calib_low, pixels, first, last)) { return SANE_FALSE; } - + /* Restore settings */ for (channel=first; channel<=last; ++channel) { dev->CIS.powerOnDelay[channel] = powerOnDelay[channel]; } - + /* Make sure calib_hi is greater than calib_low */ for (channel = first; channel <= last; ++channel) { for (p = 0; pCIS.adjustskip == 0); - + /* Sawtooth */ for (i=0; i<2048; ++i) { buf[0][i] = i % 255; /* Why 255 ? Seems to have no real importance */ } - + Mustek_PP_1015_write_reg_start(dev, MA1015W_SRAM_SOURCE_PC); for (i=0; i<2048; ++i) { Mustek_PP_1015_write_reg_val(dev, buf[0][i]); } Mustek_PP_1015_write_reg_stop(dev); - + /* Bank offset measurement */ dev->CIS.delay = 0; /* Initialize to zero, measure next */ - + saved_res = dev->CIS.res; dev->CIS.res = dev->CIS.hw_hres; - + /* * Note: the TWAIN driver seems to have a fast EPP mode too. That one is * tried first, and then they try the normal mode. I haven't figured out @@ -1953,7 +1953,7 @@ cis_measure_delay(Mustek_PP_CIS_dev * dev) for (d = 0; d < 75 /* 255 */ && dev->desc->state != STATE_CANCELLED; d += 5) { dev->CIS.delay = d; - + /* * We read the line 5 times to make sure that all garbage is flushed. */ @@ -1964,7 +1964,7 @@ cis_measure_delay(Mustek_PP_CIS_dev * dev) cis_read_line_low_level (dev, &buf[1][0], 2048, NULL, NULL, NULL); if (dev->desc->state == STATE_CANCELLED) return SANE_FALSE; } - + error = SANE_FALSE; /* Check 100 times whether we can read without errors. */ for (i=0; i<100 && !error; ++i) @@ -1973,24 +1973,24 @@ cis_measure_delay(Mustek_PP_CIS_dev * dev) CIS_CLEAR_READ_BANK(dev); cis_read_line_low_level (dev, &buf[1][0], 2048, NULL, NULL, NULL); if (dev->desc->state == STATE_CANCELLED) return SANE_FALSE; - + for (j=0; j<2048; ++j) { - if (buf[0][j] != buf[1][j]) + if (buf[0][j] != buf[1][j]) { error = SANE_TRUE; break; } } } - - DBG (3, "cis_measure_delay: delay %d\n", dev->CIS.delay); + + DBG (3, "cis_measure_delay: delay %d\n", dev->CIS.delay); if (!error) break; } - + dev->CIS.res = saved_res; - + if (error) { fprintf(stderr, "mustek_pp_cis: failed to measure delay.\n"); @@ -2000,10 +2000,10 @@ cis_measure_delay(Mustek_PP_CIS_dev * dev) fprintf(stderr, "%d ", buf[1][j]); } fprintf(stderr, "\n"); - dev->CIS.delay = 0; + dev->CIS.delay = 0; } - - DBG (3, "cis_measure_delay: delay %d\n", dev->CIS.delay); + + DBG (3, "cis_measure_delay: delay %d\n", dev->CIS.delay); return SANE_TRUE; } @@ -2023,11 +2023,11 @@ cis_return_home (Mustek_PP_CIS_dev * dev, SANE_Bool nowait) dev->CIS.exposeTime = 170; cis_config_ccd(dev); dev->CIS.exposeTime = savedExposeTime; - + cis_motor_control (dev, 0xEB); if (nowait == SANE_FALSE) - Mustek_PP_1015_wait_bit(dev, MA1015R_MOTOR, MA1015B_MOTOR_HOME, + Mustek_PP_1015_wait_bit(dev, MA1015R_MOTOR, MA1015B_MOTOR_HOME, SANE_TRUE, 1000); } @@ -2043,25 +2043,25 @@ cis_reset_device (Mustek_PP_CIS_dev * dev) dev->CIS.adjustskip = 0; dev->CIS.dontIncRead = SANE_TRUE; dev->CIS.dontMove = SANE_FALSE; - + cis_save_state(dev); dev->CIS.hw_hres = 300; dev->CIS.channel = MUSTEK_PP_CIS_CHANNEL_GREEN; dev->CIS.setParameters = SANE_FALSE; dev->CIS.exposeTime = 0xAA; - + cis_config_ccd (dev); - + cis_restore_state(dev); - + } static SANE_Bool cis_calibrate (Mustek_PP_CIS_dev * dev) { int i, saved_res = dev->CIS.res, saved_vres = dev->CIS.hw_vres; - + /* * Flow of operation observed from the twain driver * (it is assumed that the lamp is at the origin, and that the CIS is @@ -2078,11 +2078,11 @@ cis_calibrate (Mustek_PP_CIS_dev * dev) * doesn't seem to be any correlation with the current mode of the * scanner, so I assume that the exact number isn't really relevant. * The values that are read are the one that were sent to the bank, - * rotated by 1 byte in my case. + * rotated by 1 byte in my case. * * - * It seems that the width of the black border is being measured at - * this stage, possibly multiple times till it stabilizes. + * It seems that the width of the black border is being measured at + * this stage, possibly multiple times till it stabilizes. * I assume that the buffer is read 100 times to allow the lamp to * warm up and that the width of the black border is then being * measured till it stabilizes. That would explain the minimum number @@ -2091,38 +2091,38 @@ cis_calibrate (Mustek_PP_CIS_dev * dev) * - reset the device * * - move the motor 110 steps forward. The TWAIN driver moves 90 steps, - * and I've used 90 steps for a long time too, but occasionally, - * 90 steps is a fraction to short to reach the start of the + * and I've used 90 steps for a long time too, but occasionally, + * 90 steps is a fraction to short to reach the start of the * calibration strip (the motor movements are not very accurate; * an offset of 1 mm is not unusual). Therefore, I've increased it to * 110 steps. This gives us an additional 1.6 mm slack, which should - * prevent calibration errors. - * (Note that the MUSTEK_PP_CIS_????CP_DEFAULT_SKIP constants have to + * prevent calibration errors. + * (Note that the MUSTEK_PP_CIS_????CP_DEFAULT_SKIP constants have to * be adjusted if the number of steps is altered.) * * - configure the CIS : actual resolution + set parameters - * + * */ - - /* + + /* * We must make sure that we are in the scanning state; otherwise we may * still be in the canceled state from a previous scan (even if terminated - * normally), and the whole calibration would go wrong. - */ + * normally), and the whole calibration would go wrong. + */ dev->desc->state = STATE_SCANNING; - + cis_reset_device (dev); cis_return_home (dev, SANE_FALSE); /* Wait till it's home */ - + /* Use maximum resolution during calibration; otherwise we may calibrate past the calibration strip. */ dev->CIS.hw_vres = dev->desc->dev->maxres; /* This field remembers how many steps we still have to go @ max res */ dev->CIS.skipsToOrigin = dev->top_skip; /*max2hw_vres(dev, dev->top_skip); */ - + if (!cis_measure_delay(dev)) return SANE_FALSE; - + cis_reset_device (dev); /* Move motor 110 steps @ 300 DPI */ @@ -2140,30 +2140,30 @@ cis_calibrate (Mustek_PP_CIS_dev * dev) cis_wait_motor_stable (dev); } Mustek_PP_1015_write_reg_stop(dev); - + /* Next, we maximize the dynamic range of the scanner. During calibration we don't want to extrapolate, so we limit the resolution if necessary */ - - if (dev->CIS.hw_hres < dev->CIS.res) + + if (dev->CIS.hw_hres < dev->CIS.res) dev->CIS.res = dev->CIS.hw_hres; - + if (!cis_maximize_dynamic_range(dev)) return SANE_FALSE; - + if (!cis_normalize_ranges(dev)) return SANE_FALSE; - + dev->CIS.res = saved_res; dev->CIS.hw_vres = saved_vres; - + /* Convert steps back to max res size, which are used during skipping */ /* dev->CIS.skipsToOrigin = hw2max_vres(dev, dev->CIS.skipsToOrigin); */ - + /* Move to the origin */ - DBG(3, "cis_calibrate: remaining skips to origin @maxres: %d\n", + DBG(3, "cis_calibrate: remaining skips to origin @maxres: %d\n", dev->CIS.skipsToOrigin); cis_move_motor(dev, dev->CIS.skipsToOrigin); - + if (dev->calib_mode) { /* In calibration mode, we scan the interior of the scanner before the @@ -2172,10 +2172,10 @@ cis_calibrate (Mustek_PP_CIS_dev * dev) DBG(3, "cis_calibrate: running in calibration mode. Returning home.\n"); cis_return_home (dev, SANE_FALSE); /* Wait till it's home */ } - + return dev->desc->state != STATE_CANCELLED ? SANE_TRUE : SANE_FALSE; - -} + +} /****************************************************************************** ****************************************************************************** @@ -2189,7 +2189,7 @@ cis_calibrate (Mustek_PP_CIS_dev * dev) /* Shared initialization routine */ static SANE_Status cis_attach(SANE_String_Const port, - SANE_String_Const name, + SANE_String_Const name, SANE_Attach_Callback attach, SANE_Int driverNo, SANE_Int info) @@ -2204,19 +2204,19 @@ static SANE_Status cis_attach(SANE_String_Const port, { SANE_Status altStatus; SANE_String_Const altPort; - + DBG (2, "cis_attach: couldn't attach to `%s' (%s)\n", port, sane_strstatus (status)); - - /* Make migration to libieee1284 painless for users that used + + /* Make migration to libieee1284 painless for users that used direct io in the past */ if (strcmp(port, "0x378") == 0) altPort = "parport0"; else if (strcmp(port, "0x278") == 0) altPort = "parport1"; else if (strcmp(port, "0x3BC") == 0) altPort = "parport2"; else return status; - + DBG (2, "cis_attach: trying alternative port name: %s\n", altPort); - + altStatus = sanei_pa4s2_open (altPort, &fd); if (altStatus != SANE_STATUS_GOOD) { @@ -2225,7 +2225,7 @@ static SANE_Status cis_attach(SANE_String_Const port, return status; /* Return original status, not alternative status */ } } - + M1015_START_LL; M1015_START_HL; @@ -2237,17 +2237,17 @@ static SANE_Status cis_attach(SANE_String_Const port, sanei_pa4s2_enable (fd, SANE_FALSE); sanei_pa4s2_close (fd); - + if (asic != 0xA5) /* Identifies the MA1015 chipset */ { /* CIS driver only works for MA1015 chipset */ DBG (2, "cis_attach: asic id (0x%02x) not recognized\n", asic); - return SANE_STATUS_INVAL; + return SANE_STATUS_INVAL; } DBG (3, "cis_attach: device %s attached\n", name); DBG (3, "cis_attach: asic 0x%02x\n", asic); - + return attach(port, name, driverNo, info); } @@ -2292,7 +2292,7 @@ void cis_drv_capabilities(SANE_Int info, SANE_String *model, *caps = CAP_NOTHING; switch(info) - { + { case MUSTEK_PP_CIS600: *model = strdup("600CP"); *maxres = 600; @@ -2338,19 +2338,19 @@ SANE_Status cis_drv_open (SANE_String port, SANE_Int caps, SANE_Int *fd) { SANE_Status altStatus; SANE_String_Const altPort; - + DBG (2, "cis_attach: couldn't attach to `%s' (%s)\n", port, sane_strstatus (status)); - - /* Make migration to libieee1284 painless for users that used + + /* Make migration to libieee1284 painless for users that used direct io in the past */ if (strcmp(port, "0x378") == 0) altPort = "parport0"; else if (strcmp(port, "0x278") == 0) altPort = "parport1"; else if (strcmp(port, "0x3BC") == 0) altPort = "parport2"; else return status; - + DBG (2, "cis_attach: trying alternative port name: %s\n", altPort); - + altStatus = sanei_pa4s2_open (altPort, fd); if (altStatus != SANE_STATUS_GOOD) { @@ -2379,16 +2379,16 @@ void cis_drv_setup (SANE_Handle hndl) } memset(cisdev, 0, sizeof(Mustek_PP_CIS_dev)); DBG(3, "cis_drv_setup: cis device allocated\n"); - + dev->lamp_on = 0; dev->priv = cisdev; - + cisdev->desc = dev; cisdev->model = dev->dev->info; cisdev->CIS.hw_hres = 300; cisdev->CIS.cisRes = 300; cisdev->CIS.hw_vres = 300; - + /* Default values for configurable parameters; configuration file may override them. */ cisdev->fast_skip = SANE_TRUE; @@ -2424,7 +2424,7 @@ SANE_Status cis_drv_config(SANE_Handle hndl, SANE_String_Const optname, return SANE_STATUS_INVAL; } dvalue = atof(optval); - + /* An adjustment of +/- 5 mm should be sufficient and safe */ if (dvalue < -5.0) { @@ -2440,13 +2440,13 @@ SANE_Status cis_drv_config(SANE_Handle hndl, SANE_String_Const optname, } /* In practice, there is a lower bound on the value that can be used, but if the top_skip value is smaller than that value, the only result - will be that the driver tries to move the head a negative number + will be that the driver tries to move the head a negative number of steps after calibration. The move routine just ignores negative steps, so no harm can be done. */ cisdev->top_skip += MM_TO_PIXEL(dvalue, dev->dev->maxres); - DBG (3, "cis_drv_config: setting top skip value to %d\n", + DBG (3, "cis_drv_config: setting top skip value to %d\n", cisdev->top_skip); - + /* Just to be cautious; we don't want the head to hit the bottom */ if (cisdev->top_skip > 600) cisdev->top_skip = 600; if (cisdev->top_skip < -600) cisdev->top_skip = -600; @@ -2519,7 +2519,7 @@ void cis_drv_close (SANE_Handle hndl) Mustek_pp_Handle *dev = hndl; Mustek_PP_CIS_dev *cisdev = dev->priv; DBG (3, "cis_close: resetting device.\n"); - sanei_pa4s2_enable (dev->fd, SANE_TRUE); + sanei_pa4s2_enable (dev->fd, SANE_TRUE); cis_reset_device (cisdev); DBG (3, "cis_close: returning home.\n"); cis_return_home (cisdev, SANE_TRUE); /* Don't wait */ @@ -2541,7 +2541,7 @@ SANE_Status cis_drv_start (SANE_Handle hndl) Mustek_pp_Handle *dev = hndl; Mustek_PP_CIS_dev *cisdev = dev->priv; SANE_Int pixels = dev->params.pixels_per_line; - + if (!cisdev) { DBG (2, "cis_drv_start: not enough memory for device\n"); @@ -2629,7 +2629,7 @@ SANE_Status cis_drv_start (SANE_Handle hndl) (cisdev->model == MUSTEK_PP_CIS1200 && dev->res <= 300)) cisdev->CIS.cisRes = 300; else - cisdev->CIS.cisRes = 600; + cisdev->CIS.cisRes = 600; /* Calibration only makes sense for hardware pixels, not for interpolated pixels, so we limit the number of calibration pixels to the maximum @@ -2638,10 +2638,10 @@ SANE_Status cis_drv_start (SANE_Handle hndl) cisdev->calib_pixels = (pixels * cisdev->CIS.hw_hres) / dev->res; else cisdev->calib_pixels = pixels; - - DBG (3, "cis_drv_start: hres: %d vres: %d cisres: %d\n", + + DBG (3, "cis_drv_start: hres: %d vres: %d cisres: %d\n", cisdev->CIS.hw_hres, cisdev->CIS.hw_vres, cisdev->CIS.cisRes); - + sanei_pa4s2_enable (dev->fd, SANE_TRUE); cis_reset_device (cisdev); @@ -2653,7 +2653,7 @@ SANE_Status cis_drv_start (SANE_Handle hndl) /* * Set all registers to -1 (uninitialized) - */ + */ for (i=0; i<4; ++i) { cisdev->CIS.regs.in_regs[i] = -1; @@ -2682,12 +2682,12 @@ SANE_Status cis_drv_start (SANE_Handle hndl) dev->priv = NULL; return SANE_STATUS_NO_MEM; } - - /* Allocate memory for calibration; calibrating interpolated pixels + + /* Allocate memory for calibration; calibrating interpolated pixels makes no sense */ - if (pixels > (dev->dev->maxhsize >> 1)) + if (pixels > (dev->dev->maxhsize >> 1)) pixels = (dev->dev->maxhsize >> 1); - + cisdev->calib_low[1] = malloc (pixels); cisdev->calib_hi[1] = malloc (pixels); @@ -2751,7 +2751,7 @@ SANE_Status cis_drv_start (SANE_Handle hndl) cis_move_motor (cisdev, dev->topY); /* Measured in max resolution */ - /* It is vital to reinitialize the scanner right before we start the + /* It is vital to reinitialize the scanner right before we start the real scanning. Otherwise the bank synchronization may have gotten lost by the time we reach the top of the scan area */ @@ -2759,12 +2759,12 @@ SANE_Status cis_drv_start (SANE_Handle hndl) cis_config_ccd(cisdev); cis_wait_read_ready(cisdev); - sanei_pa4s2_enable (dev->fd, SANE_FALSE); + sanei_pa4s2_enable (dev->fd, SANE_FALSE); cisdev->CIS.line_step = SANE_FIX ((float) cisdev->CIS.hw_vres / (float) cisdev->CIS.res); - /* + /* * It is very important that line_diff is not initialized at zero ! * If it is set to zero, the motor will keep on moving forever (or better, * till the scanner breaks). @@ -2789,7 +2789,7 @@ void cis_drv_read (SANE_Handle hndl, SANE_Byte *buffer) Mustek_pp_Handle *dev = hndl; Mustek_PP_CIS_dev *cisdev = dev->priv; DBG(6, "cis_drv_read: Reading line\n"); - sanei_pa4s2_enable (dev->fd, SANE_TRUE); + sanei_pa4s2_enable (dev->fd, SANE_TRUE); switch (dev->mode) { case MODE_BW: @@ -2814,13 +2814,13 @@ void cis_drv_stop (SANE_Handle hndl) { Mustek_pp_Handle *dev = hndl; Mustek_PP_CIS_dev *cisdev = dev->priv; - + /* device is scanning: return lamp and free buffers */ DBG (3, "cis_drv_stop: stopping current scan\n"); dev->state = STATE_CANCELLED; DBG (9, "cis_drv_stop: enabling fd\n"); - sanei_pa4s2_enable (dev->fd, SANE_TRUE); + sanei_pa4s2_enable (dev->fd, SANE_TRUE); Mustek_PP_1015_write_reg(cisdev, MA1015W_MOTOR_CONTROL, 0); /* stop */ DBG (9, "cis_drv_stop: resetting device (1)\n"); cis_reset_device (cisdev); @@ -2829,7 +2829,7 @@ void cis_drv_stop (SANE_Handle hndl) DBG (9, "cis_drv_stop: resetting device (2)\n"); cis_reset_device (cisdev); DBG (9, "cis_drv_stop: disabling fd\n"); - sanei_pa4s2_enable (dev->fd, SANE_FALSE); + sanei_pa4s2_enable (dev->fd, SANE_FALSE); DBG (9, "cis_drv_stop: freeing buffers\n"); /* This is no good: canceling while the device is scanning and diff --git a/backend/mustek_pp_cis.h b/backend/mustek_pp_cis.h index 2a38d89..fcbdfa6 100644 --- a/backend/mustek_pp_cis.h +++ b/backend/mustek_pp_cis.h @@ -50,28 +50,28 @@ /****************************************************************************** * Read register symbols. *****************************************************************************/ -typedef enum { +typedef enum { MA1015R_ASIC = 0x00, MA1015R_SCAN_VAL = 0x01, MA1015R_MOTOR = 0x02, - MA1015R_BANK_COUNT = 0x03 - } + MA1015R_BANK_COUNT = 0x03 + } Mustek_PP_1015R_reg; /****************************************************************************** * Read register bitmask symbols. *****************************************************************************/ -typedef enum { +typedef enum { MA1015B_MOTOR_HOME = 0x01, - MA1015B_MOTOR_STABLE = 0x03 + MA1015B_MOTOR_STABLE = 0x03 } Mustek_PP_1015R_bit; /****************************************************************************** * Write register symbols: (bank number << 4) + register number. *****************************************************************************/ - -typedef enum { + +typedef enum { MA1015W_RED_REF = 0x00, MA1015W_GREEN_REF = 0x01, MA1015W_BLUE_REF = 0x02, @@ -105,13 +105,13 @@ typedef struct Mustek_PP_1015_Registers SANE_Byte in_regs[4]; SANE_Byte out_regs[4][4]; SANE_Byte channel; - + Mustek_PP_1015R_reg current_read_reg; SANE_Int read_count; - + Mustek_PP_1015W_reg current_write_reg; /* always used */ SANE_Int write_count; -} +} Mustek_PP_1015_Registers; @@ -122,74 +122,74 @@ typedef struct Mustek_PP_CIS_Info { /* Expose time (= time the lamp is on ?) */ SANE_Byte exposeTime; - + /* Power-on delay (= time between lamp on and start of capturing ?) */ SANE_Byte powerOnDelay[3]; - + /* Motor step control */ SANE_Byte phaseType; - + /* Use 8K bank or 4K bank */ SANE_Bool use8KBank; - + /* High resolution (600 DPI) or not (300 DPI) */ SANE_Bool highRes; - + /* delay between pixels; reading too fast causes stability problems */ SANE_Int delay; /* Register representation */ Mustek_PP_1015_Registers regs; - + /* Current color channel */ SANE_Int channel; - + /* Blocks motor movements during calibration */ SANE_Bool dontMove; - + /* Prevents read increment the before the first read */ SANE_Bool dontIncRead; - - /* Controls whether or not calibration parameters are transmitted + + /* Controls whether or not calibration parameters are transmitted during CIS configuration */ SANE_Bool setParameters; - + /* Number of lines to skip to reach the origin (used during calibration) */ SANE_Int skipsToOrigin; - + /* Physical resolution of the CIS: either 300 or 600 DPI */ SANE_Int cisRes; - + /* CCD mode (color/grayscale/lineart) */ SANE_Int mode; - + /* how many positions to skip until scan area starts @ max res */ SANE_Int skipimagebytes; - + /* how many image bytes to scan @ max res */ SANE_Int imagebytes; - + /* total skip, adjusted to resolution */ SANE_Int adjustskip; - + /* current resolution */ SANE_Int res; - + /* current horizontal hardware resolution */ SANE_Int hw_hres; - + /* current vertical hardware resolution */ SANE_Int hw_vres; - + /* how many positions to scan for one pixel */ SANE_Int hres_step; - + /* how many lines to scan for one scanline */ SANE_Int line_step; - + /* inversion */ SANE_Bool invert; - + } Mustek_PP_CIS_Info; struct Mustek_pp_Handle; @@ -200,7 +200,7 @@ typedef struct Mustek_PP_CIS_dev /* model identification (600CP/1200CP/1200CP+) */ SANE_Int model; - + /* CIS status */ Mustek_PP_CIS_Info CIS; @@ -216,26 +216,26 @@ typedef struct Mustek_PP_CIS_dev int line_diff; int ccd_line; int lines_left; - + /* Configuration parameters that the user can calibrate */ /* Starting position at the top */ SANE_Int top_skip; /* Use fast skipping method for head movements ? (default: yes) */ SANE_Bool fast_skip; /* Discrimination value to choose between black and white */ - SANE_Byte bw_limit; + SANE_Byte bw_limit; /* Run in calibration mode ? (default: no) */ SANE_Bool calib_mode; /* Extra delay between engine commands (ms). Default: zero. */ SANE_Int engine_delay; - + /* temporary buffer for 1 line (of one color) */ SANE_Byte *tmpbuf; /* calibration buffers (low cut, high cut) */ SANE_Byte *calib_low[3]; SANE_Byte *calib_hi[3]; - + /* Number of pixels in calibration buffers (<= number of pixels to scan) */ int calib_pixels; diff --git a/backend/mustek_pp_decl.h b/backend/mustek_pp_decl.h index 3875f3d..2ccce95 100644 --- a/backend/mustek_pp_decl.h +++ b/backend/mustek_pp_decl.h @@ -23,25 +23,25 @@ static void debug_drv_stop (SANE_Handle hndl); /* CIS drivers for 600CP, 1200CP, and 1200CP+ Version 0.13-beta, author Eddy De Greef */ -static SANE_Status cis600_drv_init (SANE_Int options, +static SANE_Status cis600_drv_init (SANE_Int options, SANE_String_Const port, - SANE_String_Const name, + SANE_String_Const name, SANE_Attach_Callback attach); -static SANE_Status cis1200_drv_init (SANE_Int options, +static SANE_Status cis1200_drv_init (SANE_Int options, SANE_String_Const port, - SANE_String_Const name, + SANE_String_Const name, SANE_Attach_Callback attach); -static SANE_Status cis1200p_drv_init(SANE_Int options, +static SANE_Status cis1200p_drv_init(SANE_Int options, SANE_String_Const port, - SANE_String_Const name, + SANE_String_Const name, SANE_Attach_Callback attach); -static void cis_drv_capabilities(SANE_Int info, +static void cis_drv_capabilities(SANE_Int info, SANE_String *model, - SANE_String *vendor, + SANE_String *vendor, SANE_String *type, - SANE_Int *maxres, + SANE_Int *maxres, SANE_Int *minres, - SANE_Int *maxhsize, + SANE_Int *maxhsize, SANE_Int *maxvsize, SANE_Int *caps); static SANE_Status cis_drv_open (SANE_String port, SANE_Int caps, SANE_Int *fd); @@ -57,17 +57,17 @@ static void cis_drv_stop (SANE_Handle hndl); /* CCD drivers for 300 dpi models Version 0.11-devel, author Jochen Eisinger */ -static SANE_Status ccd300_init (SANE_Int options, +static SANE_Status ccd300_init (SANE_Int options, SANE_String_Const port, - SANE_String_Const name, + SANE_String_Const name, SANE_Attach_Callback attach); -static void ccd300_capabilities(SANE_Int info, +static void ccd300_capabilities(SANE_Int info, SANE_String *model, - SANE_String *vendor, + SANE_String *vendor, SANE_String *type, - SANE_Int *maxres, + SANE_Int *maxres, SANE_Int *minres, - SANE_Int *maxhsize, + SANE_Int *maxhsize, SANE_Int *maxvsize, SANE_Int *caps); static SANE_Status ccd300_open (SANE_String port, SANE_Int caps, SANE_Int *fd); diff --git a/backend/mustek_pp_null.c b/backend/mustek_pp_null.c index e1c6a35..06045cb 100644 --- a/backend/mustek_pp_null.c +++ b/backend/mustek_pp_null.c @@ -39,7 +39,7 @@ If you do not wish that, delete this exception notice. This file implements a SANE backend for Mustek PP flatbed scanners. */ - + #include "../include/sane/config.h" #if defined(HAVE_STDLIB_H) @@ -62,7 +62,7 @@ #define MUSTEK_PP_NULL_DRIVER 0 -static SANE_Status +static SANE_Status debug_drv_init(SANE_Int options, SANE_String_Const port, SANE_String_Const name, SANE_Attach_Callback attach) { @@ -75,7 +75,7 @@ debug_drv_init(SANE_Int options, SANE_String_Const port, } /*ARGSUSED*/ -static void +static void debug_drv_capabilities(SANE_Int info __UNUSED__, SANE_String *model, SANE_String *vendor, SANE_String *type, SANE_Int *maxres, SANE_Int *minres, @@ -96,14 +96,14 @@ debug_drv_capabilities(SANE_Int info __UNUSED__, SANE_String *model, /*ARGSUSED*/ static SANE_Status -debug_drv_open (SANE_String port __UNUSED__, +debug_drv_open (SANE_String port __UNUSED__, SANE_Int caps __UNUSED__, SANE_Int *fd) { *fd = 1; return SANE_STATUS_GOOD; } -static void +static void debug_drv_setup (SANE_Handle hndl) { @@ -115,7 +115,7 @@ debug_drv_setup (SANE_Handle hndl) /*ARGSUSED*/ static SANE_Status -debug_drv_config(SANE_Handle hndl __UNUSED__, +debug_drv_config(SANE_Handle hndl __UNUSED__, SANE_String_Const optname, SANE_String_Const optval) { @@ -136,7 +136,7 @@ debug_drv_start (SANE_Handle hndl __UNUSED__) return SANE_STATUS_GOOD; } -static void +static void debug_drv_read (SANE_Handle hndl, SANE_Byte *buffer) { diff --git a/backend/mustek_scsi_pp.c b/backend/mustek_scsi_pp.c index 3dab544..304afce 100644 --- a/backend/mustek_scsi_pp.c +++ b/backend/mustek_scsi_pp.c @@ -793,7 +793,7 @@ mustek_scsi_pp_cmd (int fd, const void *src, size_t src_size, /* * Retry the command several times, as occasionally it doesn't - * work first time. + * work first time. */ do { diff --git a/backend/mustek_scsi_pp.h b/backend/mustek_scsi_pp.h index 5d1c900..363f2c0 100644 --- a/backend/mustek_scsi_pp.h +++ b/backend/mustek_scsi_pp.h @@ -1,7 +1,7 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2003 James Perry 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 @@ -36,7 +36,7 @@ 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. + If you do not wish that, delete this exception notice. This file implements the SCSI-over-parallel port protocol used in, for example, the Paragon 600 II EP @@ -113,7 +113,7 @@ static SANE_Status mustek_scsi_pp_cmd (int fd, const void *src, size_t src_size, * * @return * - SANE_STATUS_GOOD - on success - * - SANE_STATUS_IO_ERROR - if an error occured during the dialog with the + * - SANE_STATUS_IO_ERROR - if an error occured during the dialog with the * device */ static SANE_Status mustek_scsi_pp_rdata (int fd, int planes, diff --git a/backend/mustek_usb.c b/backend/mustek_usb.c index 58dcc58..d048fef 100644 --- a/backend/mustek_usb.c +++ b/backend/mustek_usb.c @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for Mustek 1200UB and similar + This file implements a SANE backend for Mustek 1200UB and similar USB flatbed scanners. */ #define BUILD 18 @@ -100,10 +100,6 @@ static SANE_Int new_dev_alloced; static SANE_String_Const mode_list[6]; -static const SANE_Range char_range = { - -127, 127, 1 -}; - static const SANE_Range u8_range = { 0, /* minimum */ 255, /* maximum */ @@ -1533,7 +1529,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, *len = MIN (max_len, (SANE_Int) s->hw->scan_buffer_len); memcpy (buf, s->hw->scan_buffer_start, *len); DBG (4, "sane_read: exit, read %d bytes from scan_buffer; " - "%ld bytes remaining\n", *len, + "%ld bytes remaining\n", *len, (long int) (s->hw->scan_buffer_len - *len)); s->hw->scan_buffer_len -= (*len); s->hw->scan_buffer_start += (*len); diff --git a/backend/mustek_usb.conf.in b/backend/mustek_usb.conf.in index c9b3ec4..fd58cdd 100644 --- a/backend/mustek_usb.conf.in +++ b/backend/mustek_usb.conf.in @@ -36,4 +36,3 @@ usb 0x055f 0x0873 #option 1200cu #option 1200cu_plus #option 600cu - diff --git a/backend/mustek_usb.h b/backend/mustek_usb.h index 7e68402..b5a7518 100644 --- a/backend/mustek_usb.h +++ b/backend/mustek_usb.h @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for Mustek 1200UB and similar + This file implements a SANE backend for Mustek 1200UB and similar USB flatbed scanners. */ #ifndef mustek_usb_h diff --git a/backend/mustek_usb2.c b/backend/mustek_usb2.c index 58d9e9e..bc112e6 100644 --- a/backend/mustek_usb2.c +++ b/backend/mustek_usb2.c @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro + This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro and similar USB2 scanners. */ #define BUILD 10 @@ -396,7 +396,7 @@ init_options (Mustek_Scanner * s) s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; s->opt[OPT_RESOLUTION].constraint.word_list = dpi_list; - s->val[OPT_RESOLUTION].w = 300; + s->val[OPT_RESOLUTION].w = 300; /* preview */ s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; @@ -528,14 +528,14 @@ static unsigned int g_dwAlreadyGetNegLines = 0; /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: Check the device connect status Parameters: none -Return value: +Return value: if the device is connected return TRUE - else + else return FALSE ***********************************************************************/ static SANE_Bool @@ -547,12 +547,12 @@ GetDeviceStatus () /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: Turn the lamp on or off Parameters: isLampOn: turn the lamp on or off isTALampOn: turn the TA lamp on or off -Return value: +Return value: if operation success return TRUE else @@ -567,11 +567,11 @@ PowerControl (SANE_Bool isLampOn, SANE_Bool isTALampOn) /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: Turn the carriage home Parameters: none -Return value: +Return value: if the operation success return TRUE else @@ -587,11 +587,11 @@ CarriageHome () #ifdef SANE_UNUSED /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: Get gamma input/output bit count Parameters: pGammaInfo: the gamma information -Return value: +Return value: if the operation success return TRUE else @@ -632,11 +632,11 @@ GetGammaInfo (LPGAMMAINFO pGammaInfo) #endif /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: set scan parameters Parameters: pSetParameters: the information of scaning -Return value: +Return value: if the operation success return TRUE else @@ -861,11 +861,11 @@ SetParameters (LPSETPARAMETERS pSetParameters) /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: get the optical dpi and scan area Parameters: pGetParameters: the information of scan -Return value: +Return value: if the operation is success return TRUE else @@ -905,7 +905,7 @@ GetParameters (LPGETPARAMETERS pGetParameters) /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: start scan image Parameters: none @@ -949,12 +949,12 @@ StartScan () /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Read the scanner data Parameters: pImageRows: the information of the data -Return value: +Return value: if the operation is seccuss return TRUE else @@ -1090,11 +1090,11 @@ ReadScannedData (LPIMAGEROWS pImageRows) /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Stop scan Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -1150,11 +1150,11 @@ StopScan () /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Check the status of TA Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -1187,11 +1187,11 @@ IsTAConnected () #ifdef SANE_UNUSED /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Get the status of the HK Parameters: pKey: the status of key -Return value: +Return value: if the operation is success return TRUE else @@ -1250,14 +1250,14 @@ GetKeyStatus (SANE_Byte * pKey) #endif /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: - Deal with the image with auto level +Routine Description: + Deal with the image with auto level Parameters: lpSource: the data of image scanMode: the scan mode ScanLines: the rows of image BytesPerLine: the bytes of per line -Return value: +Return value: none ***********************************************************************/ static void @@ -1497,13 +1497,13 @@ AutoLevel (SANE_Byte *lpSource, SCANMODE scanMode, unsigned short ScanLines, #ifdef SANE_UNUSED /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Deal with image with auto level Parameters: pDIB: the data of image ImageWidth: the width of image ImageHeight: the height of image -Return value: +Return value: none ***********************************************************************/ static void @@ -1792,14 +1792,14 @@ QBETDetectAutoLevel (void *pDIB, unsigned int ImageWidth, unsigned int ImageHeig #ifdef SANE_UNUSED /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: - Change the image data and deal with auto level +Routine Description: + Change the image data and deal with auto level Parameters: lpSource: the data of image scanMode: the scan mode ScanLines: the rows of image BytesPerLine: the bytes of per line -Return value: +Return value: none ***********************************************************************/ static void diff --git a/backend/mustek_usb2.h b/backend/mustek_usb2.h index b80c51a..9dc3a2b 100644 --- a/backend/mustek_usb2.h +++ b/backend/mustek_usb2.h @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro + This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro and similar USB2 scanners. */ #ifndef MUSTEK_USB2_H diff --git a/backend/mustek_usb2_asic.c b/backend/mustek_usb2_asic.c index d9b1a28..b31c749 100644 --- a/backend/mustek_usb2_asic.c +++ b/backend/mustek_usb2_asic.c @@ -42,7 +42,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro + This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro and similar USB2 scanners. */ #include "mustek_usb2_asic.h" @@ -255,6 +255,7 @@ Mustek_DMARead (PAsic chip, unsigned int size, SANE_Byte * lpdata) STATUS status = STATUS_GOOD; unsigned int i, buf[1]; unsigned int read_size; + size_t read_size_usb; DBG (DBG_ASIC, "Mustek_DMARead: Enter\n"); @@ -268,9 +269,11 @@ Mustek_DMARead (PAsic chip, unsigned int size, SANE_Byte * lpdata) SetRWSize (chip, 1, buf[0]); status = WriteIOControl (chip, 0x03, 0, 4, (SANE_Byte *) (buf)); + read_size_usb = buf[0]; status = sanei_usb_read_bulk (chip->fd, lpdata + i * read_size, - (size_t *) buf); + &read_size_usb); + buf[0] = read_size_usb; if (status != STATUS_GOOD) { DBG (DBG_ERR, "Mustek_DMARead: read error\n"); @@ -284,9 +287,11 @@ Mustek_DMARead (PAsic chip, unsigned int size, SANE_Byte * lpdata) SetRWSize (chip, 1, buf[0]); status = WriteIOControl (chip, 0x03, 0, 4, (SANE_Byte *) (buf)); + read_size_usb = buf[0]; status = sanei_usb_read_bulk (chip->fd, lpdata + i * read_size, - (size_t *) buf); + &read_size_usb); + buf[0] = read_size_usb; if (status != STATUS_GOOD) { DBG (DBG_ERR, "Mustek_DMARead: read error\n"); @@ -307,6 +312,7 @@ Mustek_DMAWrite (PAsic chip, unsigned int size, SANE_Byte * lpdata) unsigned int buf[1]; unsigned int i; unsigned int write_size; + size_t write_size_usb; DBG (DBG_ASIC, "Mustek_DMAWrite: Enter:size=%d\n", size); @@ -320,9 +326,11 @@ Mustek_DMAWrite (PAsic chip, unsigned int size, SANE_Byte * lpdata) SetRWSize (chip, 0, buf[0]); WriteIOControl (chip, 0x02, 0, 4, (SANE_Byte *) buf); + write_size_usb = buf[0]; status = sanei_usb_write_bulk (chip->fd, lpdata + i * write_size, - (size_t *) buf); + &write_size_usb); + buf[0] = write_size_usb; if (status != STATUS_GOOD) { DBG (DBG_ERR, "Mustek_DMAWrite: write error\n"); @@ -337,9 +345,11 @@ Mustek_DMAWrite (PAsic chip, unsigned int size, SANE_Byte * lpdata) SetRWSize (chip, 0, buf[0]); WriteIOControl (chip, 0x02, 0, 4, (SANE_Byte *) buf); + write_size_usb = buf[0]; status = sanei_usb_write_bulk (chip->fd, lpdata + i * write_size, - (size_t *) buf); + &write_size_usb); + buf[0] = write_size_usb; if (status != STATUS_GOOD) { DBG (DBG_ERR, "Mustek_DMAWrite: write error\n"); @@ -1649,7 +1659,7 @@ LLFMotorMove (PAsic chip, LLF_MOTORMOVE * LLF_MotorMove) Mustek_SendData (chip, ES01_E5_MotorDecStep, LLF_MotorMove->DecStep); DBG (DBG_ASIC, "DecStep=%d\n", LLF_MotorMove->DecStep); - /*set motor uniform speed only for uniform speed + /*set motor uniform speed only for uniform speed //only used for UNIFORM_MOTOR_AND_SCAN_SPEED_ENABLE //If you use acc mode, this two reg are not used. */ Mustek_SendData (chip, ES01_FD_MotorFixedspeedLSB, @@ -4541,7 +4551,7 @@ Asic_ReadCalibrationData (PAsic chip, void * pBuffer, pCalBuffer = (SANE_Byte *) malloc (dwXferBytes); if (pCalBuffer == NULL) { - DBG (DBG_ERR, + DBG (DBG_ERR, "Asic_ReadCalibrationData: Can't malloc bCalBuffer memory\n"); return STATUS_MEM_ERROR; } diff --git a/backend/mustek_usb2_asic.h b/backend/mustek_usb2_asic.h index ffc92ff..1a55903 100644 --- a/backend/mustek_usb2_asic.h +++ b/backend/mustek_usb2_asic.h @@ -42,7 +42,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro + This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro and similar USB2 scanners. */ #ifndef MUSTEK_USB2_ASIC_H @@ -299,8 +299,8 @@ RGBColor; /* debug levels */ #define DBG_CRIT 0 /* Critical errors thatshould be printed even - if user hasn't enabled debugging -- use - with care and only after sane_open has been + if user hasn't enabled debugging -- use + with care and only after sane_open has been called */ #define DBG_ERR 1 /* Other errors */ #define DBG_WARN 2 /* unusual conditions that may not be fatal */ diff --git a/backend/mustek_usb2_high.c b/backend/mustek_usb2_high.c index 664528e..b1ba65e 100644 --- a/backend/mustek_usb2_high.c +++ b/backend/mustek_usb2_high.c @@ -42,7 +42,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro + This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro and similar USB2 scanners. */ #include /* HOLD */ @@ -191,10 +191,10 @@ static void ModifyLinePoint (SANE_Byte * lpImageData, /********************************************************************** Author: Jack Date: 2005/05/13 - Routine Description: + Routine Description: Parameters: none -Return value: +Return value: if initialize the scanner success return TRUE else @@ -251,14 +251,14 @@ MustScanner_Init () /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: check the scanner connect status Parameters: none -Return value: +Return value: if scanner's status is OK return TRUE - else + else return FASLE ***********************************************************************/ static SANE_Bool @@ -279,12 +279,12 @@ MustScanner_GetScannerState () /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: Turn the lamp on or off Parameters: isLampOn: turn the lamp on or off isTALampOn: turn the TA lamp on or off -Return value: +Return value: if operation success return TRUE else @@ -334,11 +334,11 @@ MustScanner_PowerControl (SANE_Bool isLampOn, SANE_Bool isTALampOn) /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: Turn the carriage home Parameters: none -Return value: +Return value: if the operation success return TRUE else @@ -377,11 +377,11 @@ MustScanner_BackHome () /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: prepare the scan image Parameters: bScanSource: the scan source -Return value: +Return value: if operation is success return TRUE else @@ -466,7 +466,7 @@ MustScanner_Prepare (SANE_Byte bScanSource) #ifdef SANE_UNUSED /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Adjuest the offset Parameters: nTimes: Adjuest offset the times @@ -479,7 +479,7 @@ Parameters: bOffsetLowerBound: the lower bound of offset wStdMinLevel: the min level of offset wStdMaxLevel: the max level of offset -Return value: +Return value: if the operation is success return TRUE else @@ -624,7 +624,7 @@ MustScanner_AdjustOffset (int nTimes, SANE_Bool * bDirection, SANE_Byte * bOffse /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Adjuest the offset second times Parameters: nTimes: Adjuest offset the times @@ -637,7 +637,7 @@ Parameters: bOffsetLowerBound: the lower bound of offset wStdMinLevel: the min level of offset wStdMaxLevel: the max level of offset -Return value: +Return value: if the operation is success return TRUE else @@ -745,15 +745,15 @@ MustScanner_SecondAdjustOffset (int nTimes, SANE_Bool * bDirection, SANE_Byte * /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Filter the data Parameters: pSort: the sort data - TotalCount: the total count + TotalCount: the total count LowCount: the low count HighCount: the upper count -Return value: - the data of Filter +Return value: + the data of Filter ***********************************************************************/ static unsigned short MustScanner_FiltLower (unsigned short * pSort, unsigned short TotalCount, unsigned short LowCount, @@ -786,13 +786,13 @@ MustScanner_FiltLower (unsigned short * pSort, unsigned short TotalCount, unsign /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when single CCD and color is 48bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -982,13 +982,13 @@ MustScanner_GetRgb48BitLine (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when double CCD and color is 48bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -1427,13 +1427,13 @@ MustScanner_GetRgb48BitLine1200DPI (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when single CCD and color is 24bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -1680,13 +1680,13 @@ MustScanner_GetRgb24BitLine (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when double CCD and color is 24bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -2111,13 +2111,13 @@ MustScanner_GetRgb24BitLine1200DPI (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when single CCD and color is 16bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -2206,13 +2206,13 @@ MustScanner_GetMono16BitLine (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when double CCD and color is 16bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -2387,13 +2387,13 @@ MustScanner_GetMono16BitLine1200DPI (SANE_Byte * lpLine, SANE_Bool isOrderInvert /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when single CCD and color is 8bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -2478,13 +2478,13 @@ MustScanner_GetMono8BitLine (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when double CCD and color is 8bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -2641,13 +2641,13 @@ MustScanner_GetMono8BitLine1200DPI (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when single CCD and color is 1bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -2732,13 +2732,13 @@ MustScanner_GetMono1BitLine (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Repair line when double CCD and color is 1bit Parameters: lpLine: point to image be repaired isOrderInvert: RGB or BGR wLinesCount: how many line be repaired -Return value: +Return value: if the operation is success return TRUE else @@ -2849,12 +2849,12 @@ MustScanner_GetMono1BitLine1200DPI (SANE_Byte * lpLine, SANE_Bool isOrderInvert, /********************************************************************** Author: Jack Date: 2005/05/21 -Routine Description: - prepare calculate Max and Min value +Routine Description: + prepare calculate Max and Min value Parameters: wResolution: the scan resolution Return value: - none + none ***********************************************************************/ static void MustScanner_PrepareCalculateMaxMin (unsigned short wResolution) @@ -2904,7 +2904,7 @@ MustScanner_PrepareCalculateMaxMin (unsigned short wResolution) /********************************************************************** Author: Jack Date: 2005/05/21 -Routine Description: +Routine Description: calculate the Max and Min value Parameters: pBuffer: the image data @@ -2912,7 +2912,7 @@ Parameters: lpMinValue: the min value wResolution: the scan resolution Return value: - none + none ***********************************************************************/ static void MustScanner_CalculateMaxMin (SANE_Byte * pBuffer, unsigned short * lpMaxValue, @@ -2981,11 +2981,11 @@ MustScanner_CalculateMaxMin (SANE_Byte * pBuffer, unsigned short * lpMaxValue, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Read the data from scanner Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -3075,11 +3075,11 @@ MustScanner_ReadDataFromScanner (void * dummy) /********************************************************************** Author: Jack Date: 2005/05/26 -Routine Description: +Routine Description: get the lines of scanned Parameters: none -Return value: +Return value: the lines of scanned ***********************************************************************/ static unsigned int @@ -3097,7 +3097,7 @@ GetScannedLines () /********************************************************************** Author: Jack Date: 2005/05/26 -Routine Description: +Routine Description: get lines which pass to superstratum Parameters: none @@ -3118,11 +3118,11 @@ GetReadyLines () /********************************************************************** Author: Jack Date: 2005/05/26 -Routine Description: +Routine Description: add the scanned total lines Parameters: wAddLines: add the lines -Return value: +Return value: none ***********************************************************************/ static void @@ -3137,11 +3137,11 @@ AddScannedLines (unsigned short wAddLines) /********************************************************************** Author: Jack Date: 2005/05/26 -Routine Description: +Routine Description: add the ready lines Parameters: none -Return value: +Return value: none ***********************************************************************/ static void @@ -3202,8 +3202,8 @@ ModifyLinePoint (SANE_Byte * lpImageData, /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: - Modifiy the image data +Routine Description: + Modifiy the image data Parameters: A: the input the image data B: the input the iamge data diff --git a/backend/mustek_usb2_high.h b/backend/mustek_usb2_high.h index 33f463f..aec79bb 100644 --- a/backend/mustek_usb2_high.h +++ b/backend/mustek_usb2_high.h @@ -42,7 +42,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro + This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro and similar USB2 scanners. */ #ifndef MUSTEK_USB2_HIGH_H diff --git a/backend/mustek_usb2_reflective.c b/backend/mustek_usb2_reflective.c index 7bf954c..aa95e5b 100644 --- a/backend/mustek_usb2_reflective.c +++ b/backend/mustek_usb2_reflective.c @@ -42,7 +42,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro + This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro and similar USB2 scanners. */ /* forward declarations */ @@ -63,11 +63,11 @@ static SANE_Bool Reflective_PrepareScan (void); /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: reset the scanner status Parameters: none -Return value: +Return value: if operation is success return TRUE els @@ -140,12 +140,12 @@ Reflective_Reset () /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: get the suggest parameter of scaning Parameters: pTarget: the information of scaning pSuggest: suggest parameter of scaning -Return value: +Return value: if the operation is success return TRUE els @@ -341,7 +341,7 @@ Reflective_ScanSuggest (PTARGETIMAGE pTarget, PSUGGESTSETTING pSuggest) /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: setup scanning process Parameters: ColorMode: ScanMode of Scanning, CM_RGB48, CM_GRAY and so on @@ -352,7 +352,7 @@ Parameters: Y: Y start coordinate Width: Width of Scan Image Height: Height of Scan Image -Return value: +Return value: if the operation is success return TRUE else @@ -567,11 +567,11 @@ Reflective_SetupScan (COLORMODE ColorMode, /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: To adjust the value of offset gain of R/G/B Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -1102,7 +1102,7 @@ Reflective_AdjustAD () /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Find top and left side Parameters: lpwStartX: the left side @@ -1284,11 +1284,11 @@ Reflective_FindTopLeft (unsigned short * lpwStartX, unsigned short * lpwStartY) /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Stop scan Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -1329,11 +1329,11 @@ Reflective_StopScan () /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Get the calibration data Parameters: none -Return value: +Return value: if the operation is success return TRUE else @@ -1749,11 +1749,11 @@ Reflective_LineCalibration16Bits () /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Prepare scan image Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -1870,7 +1870,7 @@ Reflective_PrepareScan () /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Get the data of image Parameters: lpBlock: the data of image diff --git a/backend/mustek_usb2_transparent.c b/backend/mustek_usb2_transparent.c index 43bda0b..33adcc0 100644 --- a/backend/mustek_usb2_transparent.c +++ b/backend/mustek_usb2_transparent.c @@ -42,7 +42,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro + This file implements a SANE backend for the Mustek BearPaw 2448 TA Pro and similar USB2 scanners. */ @@ -64,11 +64,11 @@ static SANE_Bool Transparent_PrepareScan (void); /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: reset the scanner Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -132,7 +132,7 @@ Transparent_Reset () /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: get suggest parameter of scaning Parameters: pTarget: the information of scaning @@ -283,7 +283,7 @@ Transparent_ScanSuggest (PTARGETIMAGE pTarget, PSUGGESTSETTING pSuggest) /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: setup scanning process Parameters: ColorMode: ScanMode of Scanning, CM_RGB48, CM_GRAY and so on @@ -294,7 +294,7 @@ Parameters: Y: Y start coordinate Width: Width of Scan Image Height: Height of Scan Image -Return value: +Return value: if the operation is success return TRUE else @@ -493,11 +493,11 @@ Transparent_SetupScan (COLORMODE ColorMode, unsigned short XDpi, unsigned short /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Stop scan Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -534,7 +534,7 @@ Transparent_StopScan () /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Get the data of image Parameters: lpBlock: the data of image @@ -604,11 +604,11 @@ Transparent_GetRows (SANE_Byte * lpBlock, unsigned short * Rows, SANE_Bool isOrd /********************************************************************** Author: Jack Date: 2005/05/13 -Routine Description: +Routine Description: To adjust the value of offset gain of R/G/B Parameters: none -Return value: +Return value: if operation is success return TRUE else @@ -1114,7 +1114,7 @@ Transparent_AdjustAD () /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Find top and left side Parameters: lpwStartX: the left side @@ -1266,11 +1266,11 @@ Transparent_FindTopLeft (unsigned short * lpwStartX, unsigned short * lpwStartY) /********************************************************************** Author: Jack Date: 2005/05/15 -Routine Description: +Routine Description: Get the calibration data Parameters: none -Return value: +Return value: if the operation is success return TRUE else @@ -1650,11 +1650,11 @@ Transparent_LineCalibration16Bits (unsigned short wTAShadingMinus) /********************************************************************** Author: Jack Date: 2005/05/14 -Routine Description: +Routine Description: Prepare scan image Parameters: none -Return value: +Return value: if operation is success return TRUE else diff --git a/backend/mustek_usb_high.c b/backend/mustek_usb_high.c index f6a0125..bf7807e 100644 --- a/backend/mustek_usb_high.c +++ b/backend/mustek_usb_high.c @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for Mustek 1200UB and similar + This file implements a SANE backend for Mustek 1200UB and similar USB flatbed scanners. */ #include "mustek_usb_high.h" diff --git a/backend/mustek_usb_high.h b/backend/mustek_usb_high.h index d3f1ae4..916ecb7 100644 --- a/backend/mustek_usb_high.h +++ b/backend/mustek_usb_high.h @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for Mustek 1200UB and similar + This file implements a SANE backend for Mustek 1200UB and similar USB flatbed scanners. */ #ifndef mustek_usb_high_h @@ -333,7 +333,7 @@ typedef struct Mustek_Usb_Scanner double tl_y; double width; double height; - /* scan window in dots (at current resolution): + /* scan window in dots (at current resolution): top left x+y and width+height */ SANE_Int tl_x_dots; SANE_Int tl_y_dots; diff --git a/backend/mustek_usb_low.c b/backend/mustek_usb_low.c index e626b65..3e4c760 100644 --- a/backend/mustek_usb_low.c +++ b/backend/mustek_usb_low.c @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for Mustek 1200UB and similar + This file implements a SANE backend for Mustek 1200UB and similar USB flatbed scanners. */ #include @@ -170,7 +170,7 @@ usb_low_exit (ma1017 * chip) DBG (7, "usb_low_exit: freeing chip\n"); free (chip); } - DBG (5, "usb_low_exit: read %d URBs, wrote %d URBs\n", + DBG (5, "usb_low_exit: read %d URBs, wrote %d URBs\n", chip->total_read_urbs, chip->total_write_urbs); DBG (7, "usb_low_exit: exit\n"); return SANE_STATUS_GOOD; diff --git a/backend/mustek_usb_low.h b/backend/mustek_usb_low.h index e5605db..46637e8 100644 --- a/backend/mustek_usb_low.h +++ b/backend/mustek_usb_low.h @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for Mustek 1200UB and similar + This file implements a SANE backend for Mustek 1200UB and similar USB flatbed scanners. */ #ifndef mustek_usb_low_h diff --git a/backend/mustek_usb_mid.c b/backend/mustek_usb_mid.c index 9ca51d9..5935cb7 100644 --- a/backend/mustek_usb_mid.c +++ b/backend/mustek_usb_mid.c @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for Mustek 1200UB and similar + This file implements a SANE backend for Mustek 1200UB and similar USB flatbed scanners. */ #include "mustek_usb_mid.h" diff --git a/backend/mustek_usb_mid.h b/backend/mustek_usb_mid.h index d8701a7..23e9c32 100644 --- a/backend/mustek_usb_mid.h +++ b/backend/mustek_usb_mid.h @@ -43,7 +43,7 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. - This file implements a SANE backend for Mustek 1200UB and similar + This file implements a SANE backend for Mustek 1200UB and similar USB flatbed scanners. */ #ifndef mustek_usb_mid_h diff --git a/backend/nec.c b/backend/nec.c index d5179d3..f12e997 100644 --- a/backend/nec.c +++ b/backend/nec.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2000-2001 Kazuya Fukuda, based on sharp.c, which is + Copyright (C) 2000-2001 Kazuya Fukuda, based on sharp.c, which is based on canon.c. This file is part of the SANE package. @@ -52,7 +52,7 @@ - resolution setting bug fixed(PC-IN500/4C 10dpi step) - remove resolution list Version 0.11 - - get_data_buffer_status is not called in sane_get_parameter and + - get_data_buffer_status is not called in sane_get_parameter and sane_read_direct, sane_read_shuffled. - change some #include <> to "" Version 0.10 @@ -114,12 +114,12 @@ #ifndef USE_COLOR_THRESHOLD #define USE_COLOR_THRESHOLD #endif -/* enable a short list of some standard resolutions. XSane provides +/* enable a short list of some standard resolutions. XSane provides its own resolution list; therefore its is generally not reasonable to enable this list, if you mainly using XSane. But it might be handy if you are working with xscanimage */ -/* #define USE_RESOLUTION_LIST */ +/* #define USE_RESOLUTION_LIST */ #define BACKEND_NAME nec #include "../include/sane/sanei_backend.h" @@ -202,8 +202,8 @@ static SANE_String use_simple = "Flatbed"; #define HAVE_FSU 1 #define HAVE_ADF 2 -/* The follow #defines are used in NEC_Scanner.adf_fsu_mode - and as indexes for the arrays x_ranges, y_ranges in NEC_Device +/* The follow #defines are used in NEC_Scanner.adf_fsu_mode + and as indexes for the arrays x_ranges, y_ranges in NEC_Device */ #define SCAN_SIMPLE 0 #define SCAN_WITH_FSU 1 @@ -291,19 +291,19 @@ sense_handler(int fd, u_char *sense_buffer, void *ss) { int sense_key; NEC_Sense_Data *sdat = (NEC_Sense_Data *) ss; - + fd = fd; /* silence compilation warnings */ #define add_sense_code sense_buffer[12] #define add_sense_qual sense_buffer[13] memcpy(sdat->sb, sense_buffer, 16); - + DBG(10, "sense code: %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n", - sense_buffer[0], sense_buffer[1], sense_buffer[2], sense_buffer[3], - sense_buffer[4], sense_buffer[5], sense_buffer[6], sense_buffer[7], - sense_buffer[8], sense_buffer[9], sense_buffer[10], sense_buffer[11], + sense_buffer[0], sense_buffer[1], sense_buffer[2], sense_buffer[3], + sense_buffer[4], sense_buffer[5], sense_buffer[6], sense_buffer[7], + sense_buffer[8], sense_buffer[9], sense_buffer[10], sense_buffer[11], sense_buffer[12], sense_buffer[13], sense_buffer[14], sense_buffer[15]); sense_key = sense_buffer[1] & 0x0F; @@ -418,7 +418,7 @@ inquiry (int fd, void *inq_buf, size_t *inq_size) static SANE_Status mode_select_mud (int fd, int mud) { - static u_char cmd[6 + MODEPARAM_LEN] = + static u_char cmd[6 + MODEPARAM_LEN] = {MODE_SELECT6, 0x10, 0, 0, MODEPARAM_LEN, 0}; mode_select_param *mp; SANE_Status status; @@ -442,7 +442,7 @@ mode_select_mud (int fd, int mud) static SANE_Status mode_select_adf_fsu (int fd, int mode) { - static u_char cmd[6 + MODE_SUBDEV_LEN] = + static u_char cmd[6 + MODE_SUBDEV_LEN] = {MODE_SELECT6, 0x10, 0, 0, MODE_SUBDEV_LEN, 0}; mode_select_subdevice *mp; SANE_Status status; @@ -478,7 +478,7 @@ mode_select_adf_fsu (int fd, int mode) static SANE_Status wait_ready(int fd); static SANE_Status -mode_sense (int fd, void *modeparam_buf, size_t * modeparam_size, +mode_sense (int fd, void *modeparam_buf, size_t * modeparam_size, int page) { static u_char cmd[6] = {MODE_SENSE6, 0, 0, 0, 0, 0}; @@ -487,7 +487,7 @@ mode_sense (int fd, void *modeparam_buf, size_t * modeparam_size, cmd[0] = 0x1a; cmd[2] = page; cmd[4] = *modeparam_size; - status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), modeparam_buf, + status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), modeparam_buf, modeparam_size); DBG (11, ">>\n"); @@ -525,7 +525,7 @@ send_diagnostics (int fd) static SANE_Status set_window (int fd, window_param *wp, int len) { - static u_char cmd[10 + WINDOW_LEN] = + static u_char cmd[10 + WINDOW_LEN] = {SET_WINDOW, 0, 0, 0, 0, 0, 0, 0, 0, 0}; window_param *winp; SANE_Status status; @@ -560,7 +560,7 @@ get_window (int fd, void *buf, size_t * buf_size) static SANE_Status get_data_buffer_status (int fd, void *buf, size_t *buf_size) { - static u_char cmd[10] = + static u_char cmd[10] = {GET_DATA_BUFFER_STATUS, 0, 0, 0, 0, 0, 0, 0, 0, 0}; SANE_Status status; DBG (11, "<< get_data_buffer_status "); @@ -576,17 +576,17 @@ get_data_buffer_status (int fd, void *buf, size_t *buf_size) #ifdef USE_FORK /* the following four functions serve simply the purpose - to avoid "over-optimised" code when reader_process and - read_data wait for the buffer to become ready. The simple - while-loops in these functions which check the buffer - status may be optimised so that the machine code only - operates with registers instead of using the variable - values stored in memory. (This is only a workaround - + to avoid "over-optimised" code when reader_process and + read_data wait for the buffer to become ready. The simple + while-loops in these functions which check the buffer + status may be optimised so that the machine code only + operates with registers instead of using the variable + values stored in memory. (This is only a workaround - it would be better to set a compiler pragma, which ensures that the program looks into the RAM in these while loops -- but unfortunately I could not find appropriate information - about this at least for gcc, not to speak about other - compilers... + about this at least for gcc, not to speak about other + compilers... Abel) */ @@ -596,7 +596,7 @@ cancel_requested(NEC_Scanner *s) return s->rdr_ctl->cancel; } -static SANE_Status +static SANE_Status rdr_status(NEC_Scanner *s) { return s->rdr_ctl->status; @@ -633,18 +633,18 @@ reader_process(NEC_Scanner *s) DBG(11, "<< reader_process\n"); sigemptyset (&sigterm_set); - + bytes_to_queue = s->bytes_to_read; - + max_bytes_per_read = s->dev->info.bufsize / s->params.bytes_per_line; if (max_bytes_per_read) max_bytes_per_read *= s->params.bytes_per_line; else /* this is a really tiny buffer..*/ max_bytes_per_read = s->dev->info.bufsize; - + /* wait_ready(s->fd); */ - + if (s->dev->info.queued_reads <= s->dev->info.buffers) max_queue = s->dev->info.queued_reads; else @@ -664,16 +664,16 @@ reader_process(NEC_Scanner *s) #ifdef QUEUEDEBUG DBG(2, "reader: req_enter...\n"); #endif - status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd), - bc->buffer, - &bc->used, + status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd), + bc->buffer, + &bc->used, &bc->qid); #ifdef QUEUEDEBUG DBG(2, "reader: req_enter ok\n"); #endif if (status != SANE_STATUS_GOOD) { - DBG(1, "reader_process: read command failed: %s", + DBG(1, "reader_process: read command failed: %s", sane_strstatus(status)); #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED sanei_scsi_req_flush_all_extended(s->fd); @@ -697,9 +697,9 @@ reader_process(NEC_Scanner *s) waitindex = 0; cmdindex = i % s->dev->info.buffers; - while(s->bytes_to_read > 0) + while(s->bytes_to_read > 0) { - if (cancel_requested(s)) + if (cancel_requested(s)) { #ifdef QUEUEDEBUG DBG(2, "reader: flushing requests...\n"); @@ -720,7 +720,7 @@ reader_process(NEC_Scanner *s) } bc = &s->rdr_ctl->buf_ctl[waitindex]; - if (bc->shm_status == SHM_BUSY) + if (bc->shm_status == SHM_BUSY) { #ifdef DEBUG { @@ -745,7 +745,7 @@ reader_process(NEC_Scanner *s) #endif if (status != SANE_STATUS_GOOD) { - DBG(1, "reader_process: read command failed: %s", + DBG(1, "reader_process: read command failed: %s", sane_strstatus(status)); #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED sanei_scsi_req_flush_all_extended(s->fd); @@ -766,7 +766,7 @@ reader_process(NEC_Scanner *s) waitindex = 0; } - + if (bytes_to_queue) { /* wait until the next buffer is completely read via read_data */ @@ -801,11 +801,11 @@ reader_process(NEC_Scanner *s) cmd[6] = nread >> 16; cmd[7] = nread >> 8; cmd[8] = nread; - status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd), + status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd), bc->buffer, &bc->used, &bc->qid); if (status != SANE_STATUS_GOOD) { - DBG(1, "reader_process: read command failed: %s", + DBG(1, "reader_process: read command failed: %s", sane_strstatus(status)); #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED sanei_scsi_req_flush_all_extended(s->fd); @@ -819,13 +819,13 @@ reader_process(NEC_Scanner *s) bc->shm_status = SHM_BUSY; bc->nreq = nread; bytes_to_queue -= nread; - + cmdindex++; if (cmdindex == s->dev->info.buffers) cmdindex = 0; } - - if (cancel_requested(s)) + + if (cancel_requested(s)) { #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED sanei_scsi_req_flush_all_extended(s->fd); @@ -839,7 +839,7 @@ reader_process(NEC_Scanner *s) return 1; } } - + DBG(1, "buffer full conditions: %i\n", full_count); DBG(11, " reader_process>>\n"); @@ -852,7 +852,7 @@ read_data (NEC_Scanner *s, SANE_Byte *buf, size_t * buf_size) { size_t copysize, copied = 0; NEC_shmem_ctl *bc; - + DBG(11, "<< read_data "); bc = &s->rdr_ctl->buf_ctl[s->read_buff]; @@ -861,7 +861,7 @@ read_data (NEC_Scanner *s, SANE_Byte *buf, size_t * buf_size) { /* wait until the reader process delivers data or a scanner error occurs: */ while ( buf_status(bc) != SHM_FULL - && rdr_status(s) == SANE_STATUS_GOOD) + && rdr_status(s) == SANE_STATUS_GOOD) { usleep(10); /* could perhaps be longer. make this user configurable?? */ } @@ -873,10 +873,10 @@ read_data (NEC_Scanner *s, SANE_Byte *buf, size_t * buf_size) } copysize = bc->used - bc->start; - + if (copysize > *buf_size - copied ) copysize = *buf_size - copied; - + memcpy(buf, &(bc->buffer[bc->start]), copysize); copied += copysize; @@ -911,8 +911,8 @@ read_data (NEC_Scanner *s, SANE_Byte *buf, size_t * buf_size) /* sane_read_shuffled requires that read_data returns exactly *buf_size bytes, so it must be guaranteed here. - Further make sure that not more bytes are read in than - sanei_scsi_max_request_size allows, to avoid a failure + Further make sure that not more bytes are read in than + sanei_scsi_max_request_size allows, to avoid a failure of the read command */ while (remain > 0) @@ -923,7 +923,7 @@ read_data (NEC_Scanner *s, SANE_Byte *buf, size_t * buf_size) cmd[6] = nread >> 16; cmd[7] = nread >> 8; cmd[8] = nread; - status = sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), + status = sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), &buf[*buf_size - remain], &nread); if (status != SANE_STATUS_GOOD) { @@ -971,7 +971,7 @@ wait_ready(int fd) sleep(3); } return (status); - + } static SANE_Status @@ -1111,7 +1111,7 @@ attach (const char *devnam, NEC_Device ** devp) model_name = inquiry_data + 16; dev->sane.model = strndup ((const char *)model_name, 10); dev->sane.type = "flatbed scanner"; - + dev->sensedat.model = sensedat.model; DBG (5, "dev->sane.name = %s\n", dev->sane.name); @@ -1144,7 +1144,7 @@ attach (const char *devnam, NEC_Device ** devp) dev->info.bmu = msp.bmu; dev->info.mud = (msp.mud[0] << 8) + msp.mud[1]; - + dev->info.adf_fsu_installed = 0; if (dev->sensedat.model == PCIN500) { @@ -1173,7 +1173,7 @@ attach (const char *devnam, NEC_Device ** devp) dev->info.br_y_ranges[SCAN_SIMPLE].max = SANE_FIX(297); /* 431.8 is the real max */ } sanei_scsi_close (fd); - + dev->info.threshold_range.min = 1; dev->info.threshold_range.max = 255; dev->info.threshold_range.quant = 0; @@ -1253,12 +1253,12 @@ attach (const char *devnam, NEC_Device ** devp) } /* Enabling / disabling of gamma options. - Depends on many user settable options, so lets put it into + Depends on many user settable options, so lets put it into one function to be called by init_options and by sane_control_option */ #ifdef USE_CUSTOM_GAMMA -static void +static void set_gamma_caps(NEC_Scanner *s) { /* neither fixed nor custom gamma for line art modes */ @@ -1397,11 +1397,11 @@ clip_value (const SANE_Option_Descriptor * opt, void * value) /* make sure that enough memory is allocated for each string, so that the strcpy in sane_control_option / set value cannot - write behind the end of the allocated memory. + write behind the end of the allocated memory. */ static SANE_Status -init_string_option(NEC_Scanner *s, SANE_String_Const name, - SANE_String_Const title, SANE_String_Const desc, +init_string_option(NEC_Scanner *s, SANE_String_Const name, + SANE_String_Const title, SANE_String_Const desc, const SANE_String_Const *string_list, int option, int default_index) { int i; @@ -1486,7 +1486,7 @@ init_options (NEC_Scanner * s) if (default_source < 0) default_source = SCAN_SIMPLE; s->dev->info.scansources[i] = 0; - + init_string_option(s, SANE_NAME_SCAN_SOURCE, SANE_TITLE_SCAN_SOURCE, SANE_DESC_SCAN_SOURCE, (SANE_String_Const*)s->dev->info.scansources, OPT_SCANSOURCE, 0); @@ -1514,13 +1514,13 @@ init_options (NEC_Scanner * s) #ifdef USE_RESOLUTION_LIST /* select resolution */ if (s->dev->sensedat.model == PCIN500) - init_string_option(s, "Resolution", "Resolution", "Resolution", + init_string_option(s, "Resolution", "Resolution", "Resolution", resolution_list_pcin500, OPT_RESOLUTION_LIST, RESOLUTION_MAX_PCIN500); else - init_string_option(s, "Resolution", "Resolution", "Resolution", + init_string_option(s, "Resolution", "Resolution", "Resolution", resolution_list_pcinxxx, OPT_RESOLUTION_LIST, RESOLUTION_MAX_PCINXXX); #endif - + /* x & y resolution */ s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; if (s->dev->sensedat.model == PCIN500) @@ -1665,7 +1665,7 @@ init_options (NEC_Scanner * s) #ifdef USE_COLOR_THRESHOLD s->opt[OPT_THRESHOLD_R].name = SANE_NAME_THRESHOLD "-red"; /* xxx the titles and decriptions are confusing: - "set white point (red)" + "set white point (red)" Any idea? maybe "threshold to get the red component on" */ s->opt[OPT_THRESHOLD_R].title = SANE_TITLE_THRESHOLD " (red)"; @@ -1710,7 +1710,7 @@ init_options (NEC_Scanner * s) s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; s->val[OPT_PREVIEW].w = SANE_FALSE; - + #ifdef USE_CUSTOM_GAMMA /* custom-gamma table */ @@ -1796,7 +1796,7 @@ do_cancel (NEC_Scanner * s) DBG(11, "stopping reader process\n"); s->rdr_ctl->cancel = 1; - while(reader_running(s) && count < 100) + while(reader_running(s) && count < 100) { usleep(100000); count++; @@ -1838,13 +1838,13 @@ do_cancel (NEC_Scanner * s) static NEC_New_Device *new_devs = 0; static NEC_New_Device *new_dev_pool = 0; -static SANE_Status +static SANE_Status attach_and_list(const char *devnam) { SANE_Status res; NEC_Device *devp; NEC_New_Device *np; - + res = attach(devnam, &devp); if (res == SANE_STATUS_GOOD) { @@ -1975,7 +1975,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) linecount); DBG(1, "%s\n", line); } - else + else queued_reads[opt_index] = i; } else @@ -1989,7 +1989,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) { while (new_devs) { - if (buffers[1] >= 2) + if (buffers[1] >= 2) new_devs->dev->info.buffers = buffers[1]; else new_devs->dev->info.buffers = 2; @@ -2021,7 +2021,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) while (new_devs) { - if (buffers[1] >= 2) + if (buffers[1] >= 2) new_devs->dev->info.buffers = buffers[1]; else new_devs->dev->info.buffers = 2; @@ -2139,8 +2139,8 @@ sane_open (SANE_String_Const devnam, SANE_Handle * handle) s->fd = -1; s->dev = dev; - - s->buffer = 0; + + s->buffer = 0; #ifdef USE_CUSTOM_GAMMA for (i = 0; i < 4; ++i) for (j = 0; j < 256; ++j) @@ -2308,7 +2308,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *info |= SANE_INFO_RELOAD_PARAMS; case OPT_NUM_OPTS: case OPT_THRESHOLD: - /* xxx theoretically, we could use OPT_THRESHOLD in + /* xxx theoretically, we could use OPT_THRESHOLD in bi-level color mode to adjust all three other threshold together. But this would require to set the bit SANE_INFO_RELOAD_OPTIONS in *info, and that @@ -2385,8 +2385,8 @@ sane_control_option (SANE_Handle handle, SANE_Int option, #endif s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE; } -#if 0 - if ( strcmp (val, M_LINEART) == 0 +#if 0 + if ( strcmp (val, M_LINEART) == 0 || strcmp (val, M_GRAY) == 0) { s->opt[OPT_LIGHTCOLOR].cap &= ~SANE_CAP_INACTIVE; @@ -2395,7 +2395,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { s->opt[OPT_LIGHTCOLOR].cap |= SANE_CAP_INACTIVE; } -#endif +#endif strcpy(s->val[option].s, val); #ifdef USE_CUSTOM_GAMMA set_gamma_caps(s); @@ -2432,19 +2432,19 @@ sane_control_option (SANE_Handle handle, SANE_Int option, else range_index = SCAN_SIMPLE; - s->opt[OPT_TL_X].constraint.range + s->opt[OPT_TL_X].constraint.range = &s->dev->info.tl_x_ranges[range_index]; clip_value (&s->opt[OPT_TL_X], &s->val[OPT_TL_X].w); - s->opt[OPT_TL_Y].constraint.range + s->opt[OPT_TL_Y].constraint.range = &s->dev->info.tl_y_ranges[range_index]; clip_value (&s->opt[OPT_TL_Y], &s->val[OPT_TL_Y].w); - s->opt[OPT_BR_X].constraint.range + s->opt[OPT_BR_X].constraint.range = &s->dev->info.br_x_ranges[range_index]; clip_value (&s->opt[OPT_BR_X], &s->val[OPT_BR_X].w); - s->opt[OPT_BR_Y].constraint.range + s->opt[OPT_BR_Y].constraint.range = &s->dev->info.br_y_ranges[range_index]; clip_value (&s->opt[OPT_BR_Y], &s->val[OPT_BR_Y].w); @@ -2505,9 +2505,9 @@ sane_control_option (SANE_Handle handle, SANE_Int option, s->val[option].s = strdup (val); #endif for (i = 0; s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]; i++) { - if (strcmp (val, + if (strcmp (val, s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]) == 0){ - s->val[OPT_RESOLUTION].w + s->val[OPT_RESOLUTION].w = atoi(s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]); if (info) *info |= SANE_INFO_RELOAD_PARAMS; @@ -2560,7 +2560,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) scanning starts. */ memset (&s->params, 0, sizeof (s->params)); - width = MM_TO_PIX( SANE_UNFIX(s->val[OPT_BR_X].w) + width = MM_TO_PIX( SANE_UNFIX(s->val[OPT_BR_X].w) - SANE_UNFIX(s->val[OPT_TL_X].w), s->dev->info.mud); length = MM_TO_PIX( SANE_UNFIX(s->val[OPT_BR_Y].w) @@ -2657,7 +2657,7 @@ sprint_gamma(Option_Value val, SANE_Byte *dst) { int i; SANE_Byte *p = dst; - + p += sprintf((char *) p, "%i", val.wa[0]); for (i = 1; i < 256; i++) p += sprintf((char *) p, ",%i", val.wa[i] > 255 ? 255 : val.wa[i]); @@ -2669,17 +2669,17 @@ send_ascii_gamma_tables (NEC_Scanner *s) { SANE_Status status; int i; - + DBG(11, "<< send_ascii_gamma_tables "); - + /* we need: 4 bytes for each gamma value (3 digits + delimiter) + 10 bytes for the command header i.e. 4 * 4 * 256 + 10 = 4106 bytes */ - + if (s->dev->info.bufsize < 4106) return SANE_STATUS_NO_MEM; - + memset(s->buffer, 0, 4106); i = sprint_gamma(s->val[OPT_GAMMA_VECTOR_R], &s->buffer[10]); @@ -2689,19 +2689,19 @@ send_ascii_gamma_tables (NEC_Scanner *s) i += sprint_gamma(s->val[OPT_GAMMA_VECTOR_B], &s->buffer[10+i]); s->buffer[10+i++] = '/'; i += sprint_gamma(s->val[OPT_GAMMA_VECTOR], &s->buffer[10+i]); - + DBG(12, "%s\n", &s->buffer[10]); s->buffer[0] = SEND; s->buffer[2] = 0x03; s->buffer[7] = i >> 8; s->buffer[8] = i & 0xff; - + wait_ready(s->fd); status = sanei_scsi_cmd (s->fd, s->buffer, i+10, 0, 0); DBG(11, ">>\n"); - + return status; } #endif @@ -2711,9 +2711,9 @@ send_binary_g_table(NEC_Scanner *s, SANE_Word *a, int dtq) { SANE_Status status; unsigned int i, j; - + dtq = dtq; /* silence compilation warnings */ - + DBG(11, "<< send_binary_g_table\n"); i = 256; @@ -2725,19 +2725,19 @@ send_binary_g_table(NEC_Scanner *s, SANE_Word *a, int dtq) s->buffer[2] = 0x03; s->buffer[7] = i >> 8; s->buffer[8] = i & 0xff; - + for (i = 0; i < 256; i++) { s->buffer[i+11] = a[i&0xff] & 0xff; } - + for (j = 0; j < 256; j += 16) { DBG(11, "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n", - a[j ], a[j+1], a[j+2], a[j+3], + a[j ], a[j+1], a[j+2], a[j+3], a[j+4], a[j+5], a[j+6], a[j+7], - a[j+8], a[j+9], a[j+10], a[j+11], + a[j+8], a[j+9], a[j+10], a[j+11], a[j+12], a[j+13], a[j+14], a[j+15]); } DBG(12, "transfer length = %d\n", i); @@ -2757,20 +2757,20 @@ static SANE_Status send_binary_gamma_tables (NEC_Scanner *s) { SANE_Status status; - + status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR].wa, 0x10); if (status != SANE_STATUS_GOOD) return status; DBG(11, "send_binary_gamma_tables\n"); -#if 0 +#if 0 status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_R].wa, 0x11); if (status != SANE_STATUS_GOOD) return status; - + status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_G].wa, 0x12); if (status != SANE_STATUS_GOOD) return status; - + status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_B].wa, 0x13); #endif return status; @@ -2787,7 +2787,7 @@ send_gamma_tables (NEC_Scanner *s) { return send_ascii_gamma_tables(s); } - + } #endif @@ -2800,19 +2800,19 @@ send_threshold_data(NEC_Scanner *s) SANE_Status status; SANE_Byte cmd[26] = {SEND, 0, 0x82, 0, 0, 0, 0, 0, 0, 0}; int len; - + memset(cmd, 0, sizeof(cmd)); - /* maximum string length: 3 bytes for each number (they are + /* maximum string length: 3 bytes for each number (they are restricted to the range 0..255), 3 '/' and the null-byte, total: 16 bytes. */ - len = sprintf((char *) &cmd[10], "%i/%i/%i/%i", + len = sprintf((char *) &cmd[10], "%i/%i/%i/%i", s->val[OPT_THRESHOLD_R].w, s->val[OPT_THRESHOLD_G].w, s->val[OPT_THRESHOLD_B].w, s->val[OPT_THRESHOLD].w); cmd[8] = len; - + wait_ready(s->fd); status = sanei_scsi_cmd(s->fd, cmd, len + 10, 0, 0); return status; @@ -2845,7 +2845,7 @@ sane_start (SANE_Handle handle) s->dev->info.bufsize = 32 * 1024; { int bsize = s->dev->info.bufsize; - status = sanei_scsi_open_extended (s->dev->sane.name, &s->fd, + status = sanei_scsi_open_extended (s->dev->sane.name, &s->fd, &sense_handler, &s->dev->sensedat, &bsize); s->dev->info.bufsize = bsize; } @@ -2858,8 +2858,8 @@ sane_start (SANE_Handle handle) } /* make sure that we got at least 32 kB. Even then, the scan will be - awfully slow. - + awfully slow. + */ if (s->dev->info.bufsize < 32 * 1024) { @@ -2868,13 +2868,13 @@ sane_start (SANE_Handle handle) return SANE_STATUS_NO_MEM; } #else - status = sanei_scsi_open(s->dev->sane.name, &s->fd, &sense_handler, + status = sanei_scsi_open(s->dev->sane.name, &s->fd, &sense_handler, &s->dev->sensedat); if (s->dev->info.wanted_bufsize < sanei_scsi_max_request_size) s->dev->info.bufsize = s->dev->info.wanted_bufsize; else s->dev->info.bufsize = sanei_scsi_max_request_size; - + if (status != SANE_STATUS_GOOD) { DBG (1, "open of %s failed: %s\n", @@ -2932,7 +2932,7 @@ sane_start (SANE_Handle handle) DBG (5, "start: TEST_UNIT_READY\n"); status = test_unit_ready (s->fd); - + if (status != SANE_STATUS_GOOD) { DBG (1, "TEST UNIT READY failed: %s\n", sane_strstatus (status)); @@ -3046,7 +3046,7 @@ sane_start (SANE_Handle handle) else if (strcmp (edge, EDGE_BLUR) == 0) s->edge = 3; } - + s->lightcolor = 3; if (strcmp(lightcolor, LIGHT_GREEN) == 0) s->lightcolor = 0; @@ -3058,7 +3058,7 @@ sane_start (SANE_Handle handle) s->lightcolor = 3; s->adf_scan = 0; - + #ifdef USE_CUSTOM_GAMMA if (s->val[OPT_CUSTOM_GAMMA].w == SANE_FALSE) { @@ -3136,14 +3136,14 @@ sane_start (SANE_Handle handle) s->color = s->val[OPT_COLOR].w; memset (&wp, 0, sizeof (wp)); - /* every NEC scanner seems to have a different + /* every NEC scanner seems to have a different window descriptor block... */ if (s->dev->sensedat.model == PCIN500) buf_size = sizeof(WDB) + sizeof(WDBX500); else buf_size = sizeof(WDB); - + wp.wpdh.wdl[0] = buf_size >> 8; wp.wpdh.wdl[1] = buf_size; wp.wdb.x_res[0] = s->res >> 8; @@ -3372,7 +3372,7 @@ sane_start (SANE_Handle handle) #ifdef USE_FORK { size_t i; - for (i = 0; i < s->dev->info.buffers; i++) + for (i = 0; i < s->dev->info.buffers; i++) s->rdr_ctl->buf_ctl[i].shm_status = SHM_EMPTY; s->read_buff = 0; s->rdr_ctl->cancel = 0; @@ -3388,7 +3388,7 @@ sane_start (SANE_Handle handle) s->reader_pid); } #endif - if (s->reader_pid == 0) + if (s->reader_pid == 0) { sigset_t ignore_set; struct SIGACTION act; @@ -3409,9 +3409,9 @@ sane_start (SANE_Handle handle) do_cancel(s); return SANE_STATUS_NO_MEM; } - + #endif /* USE_FORK */ - + DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, " "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line, @@ -3421,7 +3421,7 @@ sane_start (SANE_Handle handle) s->buf_used = 0; s->buf_pos = 0; - if (s->cancel == SANE_TRUE) + if (s->cancel == SANE_TRUE) { do_cancel(s); DBG (10, ">>\n"); @@ -3447,7 +3447,7 @@ sane_read_direct (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, buffer_status bs; size_t len = sizeof (buffer_status); get_data_buffer_status (s->fd, &bs, &len); - DBG (20, "buffer_status: %i ", bs.fdb[0]*256*256 + bs.fdb[1]*256 + bs.fdb[2]); + DBG (20, "buffer_status: %i ", bs.fdb[0]*256*256 + bs.fdb[1]*256 + bs.fdb[2]); } #endif DBG (20, "remaining: %lu ", (u_long) s->bytes_to_read); @@ -3505,18 +3505,18 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, buffer_status bs; size_t len = sizeof (buffer_status); get_data_buffer_status (s->fd, &bs, &len); - DBG (20, "buffer_status: %i ", bs.fdb[0]*256*256 + bs.fdb[1]*256 + bs.fdb[2]); + DBG (20, "buffer_status: %i ", bs.fdb[0]*256*256 + bs.fdb[1]*256 + bs.fdb[2]); } #endif *len = 0; - if (s->bytes_to_read == 0 && s->buf_pos == s->buf_used) + if (s->bytes_to_read == 0 && s->buf_pos == s->buf_used) { do_cancel (s); DBG (10, ">>\n"); return (SANE_STATUS_EOF); } - - if (!s->scanning) + + if (!s->scanning) { DBG (10, ">>\n"); return(do_cancel(s)); @@ -3527,14 +3527,14 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, transfer = s->buf_used - s->buf_pos; if (transfer > max_len) transfer = max_len; - + memcpy(dst_buf, &(s->buffer[s->buf_pos]), transfer); s->buf_pos += transfer; max_len -= transfer; *len = transfer; } - while (max_len > 0 && s->bytes_to_read > 0) + while (max_len > 0 && s->bytes_to_read > 0) { if (eight_bit_data) { @@ -3561,7 +3561,7 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, start_input = s->dev->info.bufsize - nread; } ntest = nread; - + #ifdef USE_FORK status = read_data (s, &(s->buffer[start_input]), &nread); #else @@ -3573,8 +3573,8 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, DBG (10, ">>\n"); return (SANE_STATUS_IO_ERROR); } - - if (nread != ntest) + + if (nread != ntest) { /* if this happens, something is wrong in the input buffer management... @@ -3582,8 +3582,8 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, DBG(1, "Warning: could not read an integral number of scan lines\n"); DBG(1, " image will be scrambled\n"); } - - + + s->buf_used = max_line * s->params.bytes_per_line; s->buf_pos = 0; s->bytes_to_read -= nread; @@ -3625,12 +3625,12 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, } } } - + transfer = max_len; if (transfer > s->buf_used) transfer = s->buf_used; memcpy(&(dst_buf[*len]), s->buffer, transfer); - + max_len -= transfer; s->buf_pos += transfer; *len += transfer; @@ -3651,13 +3651,13 @@ sane_read (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, DBG (10, "<< sane_read "); s->busy = SANE_TRUE; - if (s->cancel == SANE_TRUE) + if (s->cancel == SANE_TRUE) { do_cancel(s); *len = 0; return (SANE_STATUS_CANCELLED); } - + if (s->image_composition <= 2) status = sane_read_direct(handle, dst_buf, max_len, len); else if (s->image_composition <= 4) @@ -3708,7 +3708,7 @@ sane_get_select_fd (SANE_Handle handle, SANE_Int * fd) { handle = handle; fd = fd; /* silence compilation warnings */ - + DBG (10, "<< sane_get_select_fd"); DBG (10, ">>\n"); diff --git a/backend/nec.h b/backend/nec.h index 5f03513..d7848e4 100644 --- a/backend/nec.h +++ b/backend/nec.h @@ -47,21 +47,21 @@ /* default values for configurable options. Though these options are only meaningful if USE_FORK is defined, - they are + they are DEFAULT_BUFFERS: number of buffers allocated as shared memory for the data transfer from reader_process to read_data. The minimum value is 2 DEFAULT_BUFSIZE: default size of one buffer. Must be greater than zero. - DEFAULT_QUEUED_READS: number of read requests queued by + DEFAULT_QUEUED_READS: number of read requests queued by sanei_scsi_req_enter. Since queued read requests - are currently only supported for Linux and + are currently only supported for Linux and DomainOS, this value should automatically be set dependent on the target OS... For Linux, 2 is the optimum; for DomainOS, I don't have any recommendation; other OS should use the value zero. - + The value for DEFAULT_BUFSIZE is probably too Linux-oriented... */ @@ -113,7 +113,7 @@ typedef enum OPT_COLOR, OPT_PREVIEW, -#ifdef USE_CUSTOM_GAMMA +#ifdef USE_CUSTOM_GAMMA OPT_GAMMA_VECTOR, OPT_GAMMA_VECTOR_R, OPT_GAMMA_VECTOR_G, @@ -126,7 +126,7 @@ NEC_Option; #ifdef USE_FORK -/* status defines for a buffer: +/* status defines for a buffer: buffer not used / read request queued / buffer contains data */ #define SHM_EMPTY 0 @@ -153,7 +153,7 @@ typedef struct NEC_rdr_ctl NEC_rdr_ctl; #endif /* USE_FORK */ -typedef enum +typedef enum { /* PCIN500, PCINXXX are used as array indices, so the corresponding numbers should start at 0 @@ -192,14 +192,14 @@ NEC_Info; typedef struct NEC_Sense_Data { NEC_Model model; - /* flag, if conditions like "paper jam" or "cover open" + /* flag, if conditions like "paper jam" or "cover open" are considered as an error. Should be 0 for attach, else a frontend might refuse to start, if the scanner returns these errors. */ int complain_on_adf_error; /* Linux returns only 16 bytes of sense data... */ - u_char sb[16]; + u_char sb[16]; } NEC_Sense_Data; @@ -213,7 +213,7 @@ typedef struct NEC_Device } NEC_Device; -typedef struct NEC_New_Device +typedef struct NEC_New_Device { struct NEC_Device *dev; struct NEC_New_Device *next; @@ -286,7 +286,7 @@ typedef struct WPDH { u_char wpdh[6]; u_char wdl[2]; -} +} WPDH; typedef struct WDB @@ -416,7 +416,7 @@ typedef struct buffer_status SANE_Byte block; SANE_Byte window_id; SANE_Byte reserved; - SANE_Byte bsa[3]; /* buffer space available */ + SANE_Byte bsa[3]; /* buffer space available */ SANE_Byte fdb[3]; /* filled data buffer */ } buffer_status; diff --git a/backend/net.c b/backend/net.c index 57889a2..df19192 100644 --- a/backend/net.c +++ b/backend/net.c @@ -197,22 +197,22 @@ add_device (const char *name, Net_Device ** ndp) } else { - for (resp = res; resp != NULL; resp = resp->ai_next) - { - switch (resp->ai_family) - { - case AF_INET: - sin = (struct sockaddr_in *) resp->ai_addr; - sin->sin_port = sane_port; - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - sin6 = (struct sockaddr_in6 *) resp->ai_addr; - sin6->sin6_port = sane_port; - break; -#endif /* ENABLE_IPV6 */ + for (resp = res; resp != NULL; resp = resp->ai_next) + { + switch (resp->ai_family) + { + case AF_INET: + sin = (struct sockaddr_in *) resp->ai_addr; + sin->sin_port = sane_port; + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + sin6 = (struct sockaddr_in6 *) resp->ai_addr; + sin6->sin6_port = sane_port; + break; +#endif /* ENABLE_IPV6 */ } - } + } } } @@ -220,7 +220,7 @@ add_device (const char *name, Net_Device ** ndp) if (!nd) { DBG (1, "add_device: not enough memory for Net_Device struct\n"); - + freeaddrinfo (res); return SANE_STATUS_NO_MEM; } @@ -233,14 +233,14 @@ add_device (const char *name, Net_Device ** ndp) free(nd); return SANE_STATUS_NO_MEM; } - + nd->addr = res; nd->ctl = -1; nd->next = first_device; first_device = nd; - + if (ndp) *ndp = nd; DBG (2, "add_device: backend %s added\n", name); @@ -347,7 +347,7 @@ connect_dev (Net_Device * dev) i, addrp->ai_family); continue; } - + dev->ctl = socket (addrp->ai_family, SOCK_STREAM, 0); if (dev->ctl < 0) { @@ -577,15 +577,15 @@ fetch_options (Net_Scanner * s) { DBG (3, "fetch_options: creating %d local option descriptors\n", s->opt.num_options); - s->local_opt.desc = + s->local_opt.desc = malloc (s->opt.num_options * sizeof (s->local_opt.desc)); if (!s->local_opt.desc) { DBG (1, "fetch_options: couldn't malloc s->local_opt.desc\n"); return SANE_STATUS_NO_MEM; } - for (option_number = 0; - option_number < s->opt.num_options; + for (option_number = 0; + option_number < s->opt.num_options; option_number++) { s->local_opt.desc[option_number] = @@ -605,15 +605,15 @@ fetch_options (Net_Scanner * s) return SANE_STATUS_INVAL; } - DBG (3, "fetch_options: copying %d option descriptors\n", + DBG (3, "fetch_options: copying %d option descriptors\n", s->opt.num_options); - + for (option_number = 0; option_number < s->opt.num_options; option_number++) { memcpy (s->local_opt.desc[option_number], s->opt.desc[option_number], sizeof (SANE_Option_Descriptor)); } - + s->options_valid = 1; DBG (3, "fetch_options: %d options fetched\n", s->opt.num_options); return SANE_STATUS_GOOD; @@ -1082,13 +1082,13 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /* add back the ":" that got removed by the strsep() */ host[strlen (host)] = ':'; /* host now holds the IPv6 address */ - + /* skip the ':' that could be after ] (avoids a call to strsep() */ if (next[0] == ':') next++; } - /* + /* * if the IPv6 is last in the list, the strsep() call in the while() * will return a string with the first char being '\0'. Skip it. */ @@ -1162,7 +1162,7 @@ sane_exit (void) if (dev->name) free ((void *) dev->name); -#ifdef NET_USES_AF_INDEP +#ifdef NET_USES_AF_INDEP if (dev->addr) freeaddrinfo(dev->addr); #endif /* NET_USES_AF_INDEP */ @@ -1309,7 +1309,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) memset (mem, 0, sizeof (*dev) + len); full_name = mem + sizeof (*dev); - + #ifdef ENABLE_IPV6 if (IPv6 == SANE_TRUE) strcat (full_name, "["); @@ -1317,7 +1317,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) strcat (full_name, dev->name); -#ifdef ENABLE_IPV6 +#ifdef ENABLE_IPV6 if (IPv6 == SANE_TRUE) strcat (full_name, "]"); #endif /* ENABLE_IPV6 */ @@ -1382,7 +1382,7 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) int need_auth; DBG (3, "sane_open(\"%s\")\n", full_name); - + #ifdef ENABLE_IPV6 /* * Check whether a numerical IPv6 host was specified @@ -1405,7 +1405,7 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) dev_name = strchr (tmp_name, ':'); #else /* !ENABLE_IPV6 */ - dev_name = strchr (full_name, ':'); + dev_name = strchr (full_name, ':'); #endif /* ENABLE_IPV6 */ if (dev_name) @@ -2153,7 +2153,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, { DBG (3, "sane_read: left_over from previous call, return " "immediately\n"); - /* return the byte, we've currently scanned; hang_over becomes + /* return the byte, we've currently scanned; hang_over becomes left_over */ *data = (SANE_Byte) left_over; left_over = -1; @@ -2171,7 +2171,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, if (s->bytes_remaining == 0) { /* boy, is this painful or what? */ - + DBG (4, "sane_read: reading packet length\n"); nread = read (s->data, s->reclen_buf + s->reclen_buf_offset, 4 - s->reclen_buf_offset); @@ -2232,7 +2232,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, max_length = s->bytes_remaining; nread = read (s->data, data, max_length); - + if (nread < 0) { DBG (2, "sane_read: error code %s\n", strerror (errno)); @@ -2261,7 +2261,7 @@ sane_read (SANE_Handle handle, SANE_Byte * data, SANE_Int max_length, /* special case: 1 byte scanned and hang_over */ if ((nread == 1) && (hang_over > -1)) { - /* return the byte, we've currently scanned; hang_over becomes + /* return the byte, we've currently scanned; hang_over becomes left_over */ left_over = hang_over; hang_over = -1; diff --git a/backend/niash_core.c b/backend/niash_core.c index b87f4f6..951ad67 100644 --- a/backend/niash_core.c +++ b/backend/niash_core.c @@ -973,7 +973,7 @@ CircBufferGetLine (int iHandle, TDataPipe * p, unsigned char *pabLine, } -/* try to keep the number of transfers the same, but make them all +/* try to keep the number of transfers the same, but make them all as good as possible the same size to avoid cranking in critical situations */ diff --git a/backend/niash_core.h b/backend/niash_core.h index 9bd6b91..fc0adbd 100644 --- a/backend/niash_core.h +++ b/backend/niash_core.h @@ -124,7 +124,7 @@ STATIC SANE_Bool CircBufferGetLine (int iHandle, TDataPipe * p, unsigned char *pabLine, SANE_Bool iReversedHead); -/* returns false, when trying to read after end of buffer +/* returns false, when trying to read after end of buffer if fReturn==SANE_TRUE, the head will return automatically on an end of scan */ STATIC SANE_Bool diff --git a/backend/p5.c b/backend/p5.c index 30ab41e..d4b5724 100644 --- a/backend/p5.c +++ b/backend/p5.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2009-12 Stéphane Voltz + Copyright (C) 2009-12 Stéphane Voltz This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as @@ -32,7 +32,7 @@ * \section sane_api SANE API * * \subsection sane_flow sane flow - SANE FLOW + SANE FLOW - sane_init() : initialize backend, attach scanners. - sane_get_devices() : query list of scanner devices, backend must probe for new devices. @@ -60,7 +60,7 @@ /** * Import directly the low level part needed to - * operate scanner. The alternative is to prefix all public functions + * operate scanner. The alternative is to prefix all public functions * with sanei_p5_ ,and have all the functions prototyped in * p5_device.h . */ @@ -72,7 +72,7 @@ static int init_count = 0; /** - * NULL terminated list of opened frontend sessions. Sessions are + * NULL terminated list of opened frontend sessions. Sessions are * inserted here on sane_open() and removed on sane_close(). */ static P5_Session *sessions = NULL; @@ -85,7 +85,7 @@ static P5_Session *sessions = NULL; static P5_Device *devices = NULL; /** - * NULL terminated list of devices needed by sane_get_devices(), since + * NULL terminated list of devices needed by sane_get_devices(), since * the result returned must stay consistent until next call. */ static const SANE_Device **devlist = 0; @@ -112,18 +112,6 @@ static SANE_Range y_range = { SANE_FIX (0.0) /* no quantization */ }; -static const SANE_Range u8_range = { - 0, /* minimum */ - 255, /* maximum */ - 0 /* no quantization */ -}; - -static const SANE_Range threshold_percentage_range = { - SANE_FIX (0), /* minimum */ - SANE_FIX (100), /* maximum */ - SANE_FIX (1) /* quantization */ -}; - /** * finds the maximum string length in a string array. */ @@ -155,7 +143,7 @@ static P5_Config p5cfg; /** * Called by SANE initially. - * + * * From the SANE spec: * This function must be called before any other SANE function can be * called. The behavior of a SANE backend is undefined if this @@ -195,7 +183,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /** * Called by SANE to find out about supported devices. - * + * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a @@ -208,7 +196,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. - * + * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and @@ -239,7 +227,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) /** * Since sane_get_devices() may be called repeatedly to detect new devices, - * the device detection must be run at each call. We are handling + * the device detection must be run at each call. We are handling * hot-plugging : we probe for devices plugged since sane_init() was called. */ probe_p5_devices (); @@ -327,7 +315,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) * the name of the backend as the device name, in this case the first * available device will also be used. * @param name name of the device to open - * @param handle opaque pointer where to store the pointer of + * @param handle opaque pointer where to store the pointer of * the opened P5_Session * @return SANE_STATUS_GOOD on success */ @@ -383,7 +371,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) /* device initialization */ if (device->initialized == SANE_FALSE) { - /** + /** * call to hardware initialization function here. */ device->fd = open_pp (device->name); @@ -690,7 +678,7 @@ get_option_value (P5_Session * s, int option, void *val) /** * Gets or sets an option value. - * + * * From the SANE spec: * This function is used to set or inquire the current value of option * number n of the device represented by handle h. The manner in which @@ -701,7 +689,7 @@ get_option_value (P5_Session * s, int option, void *val) * area pointed to by v must be big enough to hold the entire option * value (determined by member size in the corresponding option * descriptor). - * + * * The only exception to this rule is that when setting the value of a * string option, the string pointed to by argument v may be shorter * since the backend will stop reading the option value upon @@ -917,8 +905,8 @@ sane_start (SANE_Handle handle) /** @brief compute scan parameters * This function computes two set of parameters. The one for the SANE's standard - * and the other for the hardware. Among these parameters are the bit depth, total - * number of lines, total number of columns, extra line to read for data reordering... + * and the other for the hardware. Among these parameters are the bit depth, total + * number of lines, total number of columns, extra line to read for data reordering... * @param session fronted session to compute final scan parameters * @return SANE_STATUS_GOOD on success */ @@ -1086,7 +1074,7 @@ compute_parameters (P5_Session * session) * completion of that request. Outside of that window, the returned * values are best-effort estimates of what the parameters will be * when sane_start() gets invoked. - * + * * Calling this function before a scan has actually started allows, * for example, to get an estimate of how big the scanned image will * be. The parameters passed to this function are the handle of the @@ -1113,7 +1101,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) /** * Called by SANE to read data. - * + * * From the SANE spec: * This function is used to read image data from the device * represented by handle h. Argument buf is a pointer to a memory @@ -1121,7 +1109,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) * returned is stored in *len. A backend must set this to zero when * the call fails (i.e., when a status other than SANE_STATUS_GOOD is * returned). - * + * * When the call succeeds, the number of bytes returned can be * anywhere in the range from 0 to maxlen bytes. * @@ -1343,7 +1331,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, /** - * Cancels a scan. + * Cancels a scan. * * From the SANE spec: * This function is used to immediately or as quickly as possible @@ -1393,7 +1381,7 @@ sane_cancel (SANE_Handle handle) /** * Ends use of the session. - * + * * From the SANE spec: * This function terminates the association between the device handle * passed in argument h and the device it represents. If the device is @@ -1476,7 +1464,7 @@ sane_close (SANE_Handle handle) /** * Terminates the backend. - * + * * From the SANE spec: * This function must be called to terminate use of a backend. The * function will first close all device handles that still might be @@ -1542,7 +1530,7 @@ sane_exit (void) /** @brief probe for all supported devices - * This functions tries to probe if any of the supported devices of + * This functions tries to probe if any of the supported devices of * the backend is present. Each detected device will be added to the * 'devices' list */ @@ -1609,10 +1597,10 @@ config_attach (SANEI_Config * config, const char *devname) * using an attach function with a config parameter */ config = config; - /* the devname has been processed and is ready to be used + /* the devname has been processed and is ready to be used * directly. The config struct contains all the configuration data for * the corresponding device. Since there is no ressources common to each - * backends regarding parallel port, we can directly call the attach + * backends regarding parallel port, we can directly call the attach * function. */ attach_p5 (devname, config); @@ -1661,7 +1649,7 @@ attach_p5 (const char *devicename, SANEI_Config * config) /** * do physical probe of the device here. In case the device is recognized, - * we allocate a device struct and give it options and model. + * we allocate a device struct and give it options and model. * Else we return SANE_STATUS_UNSUPPORTED. */ model = probe (devicename); @@ -1772,7 +1760,7 @@ init_options (struct P5_Session *session) SANE_CONSTRAINT_NONE; session->options[OPT_PREVIEW].value.w = SANE_FALSE; - /** @brief build resolution list + /** @brief build resolution list * We merge xdpi and ydpi list to provide only one resolution option control. * This is the most common case for backends and fronteds and give 'square' * pixels. The SANE API allow to control x and y dpi independantly, but this is diff --git a/backend/p5.h b/backend/p5.h index 10352a3..eae62f7 100644 --- a/backend/p5.h +++ b/backend/p5.h @@ -1,22 +1,22 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2009-2012 stef.dev@free.fr - + 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. - + */ /** @file p5.h @@ -77,7 +77,7 @@ #include "p5_device.h" -/** +/** * List of all SANE options available for the frontend. Given a specific * device, some options may be set to inactive when the scanner model is * detected. The default values and the ranges they belong maybe also model @@ -95,7 +95,7 @@ enum P5_Options OPT_RESOLUTION, /** set scan's resolution */ /* @} */ - /** @name geometry group + /** @name geometry group * geometry related options */ /* @{ */ @@ -139,9 +139,9 @@ typedef struct P5_Option Option_Value value; /** option value */ } P5_Option; -/** +/** * Frontend session. This struct holds informations usefull for - * the functions defined in SANE's standard. Informations closer + * the functions defined in SANE's standard. Informations closer * to the hardware are in the P5_Device structure. There is * as many session structure than frontends using the backend. */ @@ -175,7 +175,7 @@ typedef struct P5_Session SANE_Bool non_blocking; /** - * SANE Parameters describes what the next or current scan will be + * SANE Parameters describes what the next or current scan will be * according to the current values of the options */ SANE_Parameters params; diff --git a/backend/p5_device.c b/backend/p5_device.c index 924144e..4a257a7 100644 --- a/backend/p5_device.c +++ b/backend/p5_device.c @@ -1,4 +1,4 @@ -/** +/** * Description of the Primax PagePartner model */ static P5_Model pagepartner_model = { @@ -249,7 +249,7 @@ write_reg2 (int fd, uint8_t index, uint16_t value) static int read_data (int fd, uint8_t * data, int length) -{ +{ if(fd && data && length) return -1; return -1; @@ -463,7 +463,7 @@ setadresses (int fd, uint16_t start, uint16_t end) #ifdef HAVE_LINUX_PPDEV_H /** @brief open parallel port device * opens parallel port's low level device in EPP mode - * @param devicename nam of the real device or the special value 'auto' + * @param devicename nam of the real device or the special value 'auto' * @return file descriptor in cas of successn -1 otherwise */ static int @@ -532,7 +532,7 @@ open_pp (const char *devicename) } else { - /* + /* if (mode & PARPORT_MODE_ECP) { mode = IEEE1284_MODE_ECP; @@ -557,7 +557,7 @@ open_pp (const char *devicename) } /** close low level device - * release and close low level hardware device + * release and close low level hardware device */ static void close_pp (int fd) @@ -615,7 +615,7 @@ test_document (int fd) /** * return the amount of scanned data available * @param fd file descriptor to access scanner - * @return avaible byte number + * @return avaible byte number */ static int available_bytes (int fd) @@ -710,7 +710,7 @@ build_correction (P5_Device * dev, unsigned int dpi, unsigned int mode, * @param dev device describing hardware * @param mode color, gray level or lineart. * @param dpi desired scan resolution. - * @param startx coordinate of the first pixel to scan in + * @param startx coordinate of the first pixel to scan in * scan's resolution coordinate * @param width width of the scanned area * scanner's physical scan aread. diff --git a/backend/p5_device.h b/backend/p5_device.h index 4582256..744fe1c 100644 --- a/backend/p5_device.h +++ b/backend/p5_device.h @@ -1,17 +1,17 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2009-2012 stef.dev@free.fr - + 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, @@ -83,8 +83,8 @@ typedef struct P5_Calibration_Data uint8_t white_data[MAX_SENSOR_PIXELS * 3]; } P5_Calibration_Data; -/** - * This structure describes a particular model which is handled by the backend. +/** + * This structure describes a particular model which is handled by the backend. * Contained data is immutable and is used to initalize the P5_Device * structure. */ @@ -178,7 +178,7 @@ typedef struct P5_Device struct P5_Device *next; /** - * Points to a structure that decribes model capabilities, geometry + * Points to a structure that decribes model capabilities, geometry * and default settings. */ P5_Model *model; @@ -203,16 +203,16 @@ typedef struct P5_Device /** * Configuration options for the device read from - * configuration file at attach time. This member is filled at + * configuration file at attach time. This member is filled at * attach time. */ P5_Config *config; /** @brief scan parameters * The scan done by the hardware can be different from the one at the SANE - * frontend session. For instance: + * frontend session. For instance: * - xdpy and ydpi may be different to accomodate hardware capabilites. - * - many CCD scanners need to scan more lines to correct the 'line + * - many CCD scanners need to scan more lines to correct the 'line * distance shift' effect. * - emulated modes (lineart from gray scan, or gray scan for color one) */ diff --git a/backend/pie-scsidef.h b/backend/pie-scsidef.h index d86a0c9..f80e1da 100644 --- a/backend/pie-scsidef.h +++ b/backend/pie-scsidef.h @@ -363,12 +363,12 @@ static scsiblk request_sense = { request_senseC, sizeof(request_senseC) }; #define get_RS_filemark(b) getbitfield(b + 0x02, 1, 7) #define get_RS_EOM(b) getbitfield(b + 0x02, 1, 6) #define get_RS_ILI(b) getbitfield(b + 0x02, 1, 5) -#define get_RS_sense_key(b) getbitfield(b + 0x02, 0x0f, 0) -#define get_RS_information(b) getnbyte(b+0x03, 4) +#define get_RS_sense_key(b) getbitfield(b + 0x02, 0x0f, 0) +#define get_RS_information(b) getnbyte(b+0x03, 4) #define get_RS_additional_length(b) b[0x07] #define get_RS_ASC(b) b[0x0c] #define get_RS_ASCQ(b) b[0x0d] -#define get_RS_SKSV(b) getbitfield(b+0x0f,1,7) /* valid */ +#define get_RS_SKSV(b) getbitfield(b+0x0f,1,7) /* valid */ #define get_RS_CD(b) getbitfield(b+0x0f,1,6) /* 1=CDB */ #define get_RS_field_pointer(b) getnbyte(b+0x10, 2) diff --git a/backend/pie.c b/backend/pie.c index 76cbb47..0e56a5a 100644 --- a/backend/pie.c +++ b/backend/pie.c @@ -2901,7 +2901,7 @@ do_cancel (Pie_Scanner * scanner) DBG (DBG_sane_info, "killing reader_process\n"); sanei_thread_kill (scanner->reader_pid); sanei_thread_waitpid (scanner->reader_pid, 0); - scanner->reader_pid = -1; + sanei_thread_invalidate (scanner->reader_pid); DBG (DBG_sane_info, "reader_process killed\n"); } diff --git a/backend/pieusb_usb.c b/backend/pieusb_usb.c index 71b6bcf..31008fa 100644 --- a/backend/pieusb_usb.c +++ b/backend/pieusb_usb.c @@ -176,11 +176,13 @@ _hexdump(char *msg, unsigned char *ptr, int size) clipped = size; size = 128; } - while (size-- > 0) - { - if ((count % 16) == 0) - fprintf (stderr, "%s\t%08lx:", msg?msg:"", start); - msg = NULL; + while (size-- > 0) + { + if ((count % 16) == 0) + { + fprintf (stderr, "%s\t%08lx:", msg?msg:"", start); + msg = NULL; + } fprintf (stderr, " %02x", *ptr++); count++; start++; @@ -207,7 +209,7 @@ _hexdump(char *msg, unsigned char *ptr, int size) if ((count % 16) != 0) fprintf (stderr, "\n"); if (clipped > 0) - fprintf (stderr, "\t%08lx bytes clipped\n", clipped); + fprintf (stderr, "\t%08lx bytes clipped\n", clipped); fflush(stderr); return; diff --git a/backend/pixma.c b/backend/pixma.c index d50e4ca..d33a74e 100644 --- a/backend/pixma.c +++ b/backend/pixma.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2007-2008 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -66,6 +66,7 @@ # 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) @@ -122,8 +123,26 @@ typedef struct pixma_sane_t 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"; @@ -291,7 +310,7 @@ update_button_state (pixma_sane_t * ss, SANE_Int * info) } 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; @@ -642,9 +661,9 @@ control_option (pixma_sane_t * ss, SANE_Int n, SANE_Int dummy; /* info may be null, better to set a dummy here then test everywhere */ - if (info == NULL) + if (info == NULL) info = &dummy; - + cfg = pixma_get_config (ss->s); /* PDBG (pixma_dbg (4, "*control_option***** n = %u, a = %u\n", n, a)); */ @@ -697,7 +716,7 @@ control_option (pixma_sane_t * ss, SANE_Int n, ss->button_option_is_cached[ BUTTON_GROUP_INDEX(n) ] = 0; } - /* now deal with getting and setting of options */ + /* now deal with getting and setting of options */ switch (SOD (n).type) { case SANE_TYPE_BOOL: @@ -1094,7 +1113,7 @@ terminate_reader_task (pixma_sane_t * ss, int *exit_code) pid = ss->reader_taskid; if (!sanei_thread_is_valid (pid)) - return -1; + return pid; if (sanei_thread_is_forked ()) { sanei_thread_kill (pid); @@ -1105,7 +1124,7 @@ terminate_reader_task (pixma_sane_t * ss, int *exit_code) /* pixma_cancel (ss->s); What is this for ? Makes end-of-scan buggy => removing */ } result = sanei_thread_waitpid (pid, &status); - ss->reader_taskid = -1; + sanei_thread_invalidate (ss->reader_taskid); if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) ss->idle = SANE_TRUE; @@ -1119,7 +1138,8 @@ terminate_reader_task (pixma_sane_t * ss, int *exit_code) else { PDBG (pixma_dbg (1, "WARNING:waitpid() failed %s\n", strerror (errno))); - return -1; + sanei_thread_invalidate (pid); + return pid; } } @@ -1159,7 +1179,7 @@ start_reader_task (pixma_sane_t * ss) if (is_forked) { pid = sanei_thread_begin (reader_process, ss); - if (pid > 0) + if (sanei_thread_is_valid (pid)) { close (ss->wpipe); ss->wpipe = -1; @@ -1184,6 +1204,245 @@ start_reader_task (pixma_sane_t * ss) 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) { @@ -1199,7 +1458,35 @@ read_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen) if (ss->cancel) /* ss->rpipe has already been closed by sane_cancel(). */ return SANE_STATUS_CANCELLED; - count = read (ss->rpipe, buf, size); + 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); @@ -1215,6 +1502,8 @@ read_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen) 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; } @@ -1229,6 +1518,8 @@ read_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen) close (ss->rpipe); ss->rpipe = -1; terminate_reader_task (ss, NULL); + if (ss->sp.mode_jpeg) + pixma_jpeg_finish(ss); } else if (count == 0) { @@ -1236,6 +1527,8 @@ read_image (pixma_sane_t * ss, void *buf, unsigned size, int *readlen) 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) @@ -1376,7 +1669,7 @@ sane_open (SANE_String_Const name, SANE_Handle * h) return SANE_STATUS_NO_MEM; ss->next = first_scanner; first_scanner = ss; - ss->reader_taskid = -1; + sanei_thread_initialize (ss->reader_taskid); ss->wpipe = -1; ss->rpipe = -1; ss->idle = SANE_TRUE; @@ -1441,7 +1734,7 @@ sane_control_option (SANE_Handle h, SANE_Int n, 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) + if (ss->sp.source != PIXMA_SOURCE_ADF && ss->sp.source != PIXMA_SOURCE_ADFDUP) return SANE_STATUS_INVAL; } @@ -1454,16 +1747,16 @@ sane_control_option (SANE_Handle h, SANE_Int n, if ((opt->sod.type != SANE_TYPE_BUTTON && !v) || !SANE_OPTION_IS_SETTABLE (opt->sod.cap)) return SANE_STATUS_INVAL; /* or _UNSUPPORTED? */ - break; + 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; + break; case SANE_ACTION_GET_VALUE: if (!v || !(opt->sod.cap & SANE_CAP_SOFT_DETECT)) return SANE_STATUS_INVAL; /* or _UNSUPPORTED? */ - break; + break; default: return SANE_STATUS_UNSUPPORTED; } @@ -1527,6 +1820,19 @@ sane_start (SANE_Handle h) 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. */ @@ -1538,6 +1844,22 @@ sane_start (SANE_Handle h) 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); } @@ -1635,6 +1957,8 @@ sane_cancel (SANE_Handle h) 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; @@ -1799,7 +2123,7 @@ type int original type int target default 0 title Target operation type - cap soft_detect advanced + cap soft_detect advanced type int scan-resolution default 0 diff --git a/backend/pixma.h b/backend/pixma.h index 6d723fb..370203a 100644 --- a/backend/pixma.h +++ b/backend/pixma.h @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2007-2008 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -104,7 +104,7 @@ typedef uint16_t uint16_t; typedef uint32_t uint32_t; #endif /* HAVE_STDINT_H */ -#ifdef HAVE_INTTYPES_H +#ifdef HAVE_INTTYPES_H # include /* available in ISO C99 */ #endif /* HAVE_INTTYPES_H */ @@ -116,8 +116,8 @@ typedef uint32_t uint32_t; /** \name Version of the driver */ /**@{*/ #define PIXMA_VERSION_MAJOR 0 -#define PIXMA_VERSION_MINOR 17 -#define PIXMA_VERSION_BUILD 37 +#define PIXMA_VERSION_MINOR 23 +#define PIXMA_VERSION_BUILD 0 /**@}*/ /** \name Error codes */ @@ -154,6 +154,7 @@ typedef uint32_t uint32_t; #define PIXMA_CAP_NEGATIVE (1 << 10) #define PIXMA_CAP_TPUIR ((1 << 11) | PIXMA_CAP_TPU) #define PIXMA_CAP_ADF_WAIT (1 << 12) +#define PIXMA_CAP_ADF_JPEG (1 << 13) #define PIXMA_CAP_EXPERIMENT (1 << 31) /**@}*/ @@ -278,7 +279,7 @@ struct pixma_scan_param_t * line_size >= depth / 8 * channels * w
* This field will be set by pixma_check_scan_param(). */ uint64_t line_size; - + /** Size in bytes of the whole image. * image_size = line_size * h
* This field will be set by pixma_check_scan_param(). */ @@ -310,11 +311,14 @@ struct pixma_scan_param_t unsigned x, y, w, h, xs, wx; /*@} */ - /** Flag indicating whether the offset correction for TPU scans + /** Flag indicating whether the offset correction for TPU scans * was already performed (to avoid repeated corrections). * Currently only used in pixma_mp810.c sub-driver */ unsigned tpu_offset_added; + /* Flag indicating if data from scanner will be in JPEG format */ + unsigned mode_jpeg; + /** Flag indicating whether a software-lineart scan is in progress * 0 = other scan * 1 = software-lineart scan */ diff --git a/backend/pixma_bjnp.c b/backend/pixma_bjnp.c index fc4c501..5a9932e 100644 --- a/backend/pixma_bjnp.c +++ b/backend/pixma_bjnp.c @@ -69,7 +69,7 @@ #include #endif -/* +/* * networking stuff */ #ifdef HAVE_SYS_SOCKET_H @@ -104,7 +104,7 @@ #ifndef SSIZE_MAX # define SSIZE_MAX LONG_MAX -#endif +#endif /* static data */ static bjnp_device_t device[BJNP_NO_DEVICES]; @@ -198,7 +198,7 @@ static int sa_is_equal( const bjnp_sockaddr_t * sa1, const bjnp_sockaddr_t * sa2 { return 1; } - } + } #ifdef ENABLE_IPV6 else if (sa1 -> addr.sa_family == AF_INET6 ) { @@ -207,18 +207,18 @@ static int sa_is_equal( const bjnp_sockaddr_t * sa1, const bjnp_sockaddr_t * sa2 { return 1; } - } + } #endif } - return 0; + return 0; } -static int +static int sa_size( const bjnp_sockaddr_t *sa) { switch (sa -> addr.sa_family) { - case AF_INET: + case AF_INET: return (sizeof(struct sockaddr_in) ); #ifdef ENABLE_IPV6 case AF_INET6: @@ -269,7 +269,7 @@ get_address_info ( const bjnp_sockaddr_t *addr, char * addr_string, int *port) *port = ntohs (addr->ipv6.sin6_port); } #endif - else + else { /* unknown address family, should not occur */ strcpy(addr_string, "Unknown address family"); @@ -455,7 +455,7 @@ bjnp_open_tcp (int devno) * Close this socket when starting another process... */ - fcntl (sock, F_SETFD, FD_CLOEXEC); + fcntl (sock, F_SETFD, FD_CLOEXEC); if (connect (sock, &(addr->addr), sa_size(device[devno].addr) )!= 0) @@ -510,9 +510,9 @@ split_uri (const char *devname, char *method, char *host, char *port, { /* literal IPv6 address */ - char *end_of_address = strchr(start, ']'); + char *end_of_address = strchr(start, ']'); - if ( ( end_of_address == NULL) || + if ( ( end_of_address == NULL) || ( (end_of_address[1] != ':') && (end_of_address[1] != '/' ) && (end_of_address[1] != '\0' )) || ( (end_of_address - start) >= BJNP_HOST_MAX ) ) { @@ -552,8 +552,8 @@ split_uri (const char *devname, char *method, char *host, char *port, else { char *end_of_port = strchr(start, '/'); - if (end_of_port == NULL) - { + if (end_of_port == NULL) + { next = '\0'; } else @@ -669,9 +669,9 @@ static int udp_command (const int dev_no, char *command, int cmd_len, char *response, int resp_len) { - /* + /* * send udp command to given device and recieve the response` - * returns: the legth of the response or -1 + * returns: the legth of the response or -1 */ int sockfd; struct timeval timeout; @@ -681,7 +681,7 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response, fd_set fdset; struct BJNP_command *resp = (struct BJNP_command *) response; struct BJNP_command *cmd = (struct BJNP_command *) command; - + if ( (sockfd = bjnp_setup_udp_socket(dev_no) ) == -1 ) { PDBG (bjnp_dbg( LOG_CRIT, "udp_command: ERROR - Can not setup socket\n") ); @@ -712,7 +712,7 @@ udp_command (const int dev_no, char *command, int cmd_len, char *response, } while (((result = select (sockfd + 1, &fdset, NULL, NULL, &timeout)) <= 0) - && (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS) + && (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS) && resp-> seq_no != cmd->seq_no); if (result <= 0) @@ -780,7 +780,7 @@ get_scanner_id (const int dev_no, char *model) id = (struct IDENTITY *) resp_buf; if (device[dev_no].protocol == PROTOCOL_BJNP) - { + { id_len = MIN(ntohl( id-> cmd.payload_len ) - sizeof(id-> payload.bjnp.id_len), BJNP_IEEE1284_MAX); strncpy(scanner_id, id->payload.bjnp.id, id_len); scanner_id[id_len] = '\0'; @@ -815,7 +815,7 @@ get_scanner_name(const bjnp_sockaddr_t *scanner_sa, char *host) struct addrinfo *result; char ip_address[BJNP_HOST_MAX]; int port; - int error; + int error; int match = 0; int level; char service[64]; @@ -832,10 +832,10 @@ get_scanner_name(const bjnp_sockaddr_t *scanner_sa, char *host) /* do reverse name lookup, if hostname can not be found return ip-address */ - if( (error = getnameinfo( &(scanner_sa -> addr) , sa_size( scanner_sa), + if( (error = getnameinfo( &(scanner_sa -> addr) , sa_size( scanner_sa), host, BJNP_HOST_MAX , NULL, 0, NI_NAMEREQD) ) != 0 ) { - PDBG (bjnp_dbg(LOG_INFO, "get_scanner_name: Name for %s not found : %s\n", + PDBG (bjnp_dbg(LOG_INFO, "get_scanner_name: Name for %s not found : %s\n", ip_address, gai_strerror(error) ) ); strcpy(host, ip_address); return level; @@ -843,19 +843,19 @@ get_scanner_name(const bjnp_sockaddr_t *scanner_sa, char *host) else { sprintf(service, "%d", port); - /* some buggy routers return rubbish if reverse lookup fails, so + /* some buggy routers return rubbish if reverse lookup fails, so * we do a forward lookup on the received name to see if the result matches */ - if (getaddrinfo(host , service, NULL, &results) == 0) + if (getaddrinfo(host , service, NULL, &results) == 0) { result = results; - while (result != NULL) + while (result != NULL) { if(sa_is_equal( scanner_sa, (bjnp_sockaddr_t *)result-> ai_addr)) { /* found match, good */ - PDBG (bjnp_dbg (LOG_INFO, + PDBG (bjnp_dbg (LOG_INFO, "get_scanner_name: Forward lookup for %s succeeded, using as hostname\n", host)); match = 1; level = BJNP_ADDRESS_HAS_FQDN; @@ -865,15 +865,15 @@ get_scanner_name(const bjnp_sockaddr_t *scanner_sa, char *host) } freeaddrinfo(results); - if (match != 1) + if (match != 1) { - PDBG (bjnp_dbg (LOG_INFO, - "get_scanner_name: Forward lookup for %s succeeded, IP-address does not match, using IP-address %s instead\n", + PDBG (bjnp_dbg (LOG_INFO, + "get_scanner_name: Forward lookup for %s succeeded, IP-address does not match, using IP-address %s instead\n", host, ip_address)); strcpy (host, ip_address); } - } - else + } + else { /* forward lookup failed, use ip-address */ PDBG ( bjnp_dbg (LOG_INFO, "get_scanner_name: Forward lookup of %s failed, using IP-address", ip_address)); @@ -956,8 +956,8 @@ static int create_broadcast_socket( const bjnp_sockaddr_t * local_addr ) return sockfd; } -static int -prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, +static int +prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, const bjnp_sockaddr_t *broadcast_sa, bjnp_sockaddr_t * dest_sa) { /* @@ -975,7 +975,7 @@ prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, if ( local_sa == NULL ) { - PDBG (bjnp_dbg (LOG_DEBUG, + PDBG (bjnp_dbg (LOG_DEBUG, "prepare_socket: %s is not a valid IPv4 interface, skipping...\n", if_name)); return -1; @@ -994,7 +994,7 @@ prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, { /* not a valid interface */ - PDBG (bjnp_dbg (LOG_DEBUG, + PDBG (bjnp_dbg (LOG_DEBUG, "prepare_socket: %s is not a valid IPv4 interface, skipping...\n", if_name)); return -1; @@ -1008,7 +1008,7 @@ prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, /* we fill port when we send the broadcast */ dest_sa -> ipv4.sin_port = htons(0); - if ( (socket = create_broadcast_socket( &local_sa_copy) ) != -1) + if ( (socket = create_broadcast_socket( &local_sa_copy) ) != -1) { PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: %s is IPv4 capable, sending broadcast, socket = %d\n", if_name, socket)); @@ -1030,7 +1030,7 @@ prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, { /* not a valid interface */ - PDBG (bjnp_dbg (LOG_DEBUG, + PDBG (bjnp_dbg (LOG_DEBUG, "prepare_socket: %s is not a valid IPv6 interface, skipping...\n", if_name)); return -1; @@ -1043,7 +1043,7 @@ prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, dest_sa -> ipv6.sin6_port = htons(0); inet_pton(AF_INET6, "ff02::1", dest_sa -> ipv6.sin6_addr.s6_addr); - if ( (socket = create_broadcast_socket( &local_sa_copy ) ) != -1) + if ( (socket = create_broadcast_socket( &local_sa_copy ) ) != -1) { PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: %s is IPv6 capable, sending broadcast, socket = %d\n", if_name, socket)); @@ -1055,7 +1055,7 @@ prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, return -1; } } - } + } break; #endif @@ -1084,7 +1084,7 @@ bjnp_send_broadcast (int sockfd, const bjnp_sockaddr_t * broadcast_addr, int por if( dest_addr.addr.sa_family == AF_INET6) { dest_addr.ipv6.sin6_port = htons(port); - } + } #endif if ((num_bytes = sendto (sockfd, &cmd, size, 0, @@ -1104,7 +1104,7 @@ bjnp_send_broadcast (int sockfd, const bjnp_sockaddr_t * broadcast_addr, int por static void bjnp_finish_job (int devno) { -/* +/* * Signal end of scanjob to scanner */ @@ -1138,7 +1138,7 @@ bjnp_finish_job (int devno) static int bjnp_poll_scanner (int devno, char type,char *hostname, char *user, SANE_Byte *status, int size) { -/* +/* * send details of user to the scanner */ @@ -1149,7 +1149,7 @@ bjnp_poll_scanner (int devno, char type,char *hostname, char *user, SANE_Byte *s int buf_len; /* length of the whole command buffer */ struct POLL_DETAILS *poll; struct POLL_RESPONSE *response; - char user_host[256]; + char user_host[256]; time_t t; int user_host_len; @@ -1174,27 +1174,27 @@ bjnp_poll_scanner (int devno, char type,char *hostname, char *user, SANE_Byte *s len = 80; break; case 2: - poll->extensions.type2.dialog = htonl(device[devno].dialog); - charTo2byte(poll->extensions.type2.user_host, user_host, user_host_len); + poll->extensions.type2.dialog = htonl(device[devno].dialog); + charTo2byte(poll->extensions.type2.user_host, user_host, user_host_len); poll->extensions.type2.unknown_1 = htonl(0x14); - poll->extensions.type2.unknown_2 = htonl(0x10); + poll->extensions.type2.unknown_2 = htonl(0x10); t = time (NULL); - strftime (poll->extensions.type2.ascii_date, - sizeof (poll->extensions.type2.ascii_date), + strftime (poll->extensions.type2.ascii_date, + sizeof (poll->extensions.type2.ascii_date), "%Y%m%d%H%M%S", localtime (&t)); len = 116; break; case 5: - poll->extensions.type5.dialog = htonl(device[devno].dialog); - charTo2byte(poll->extensions.type5.user_host, user_host, user_host_len); + poll->extensions.type5.dialog = htonl(device[devno].dialog); + charTo2byte(poll->extensions.type5.user_host, user_host, user_host_len); poll->extensions.type5.unknown_1 = htonl(0x14); - poll->extensions.type5.key = htonl(device[devno].status_key); + poll->extensions.type5.key = htonl(device[devno].status_key); len = 100; break; default: PDBG (bjnp_dbg (LOG_INFO, "bjnp_poll_scanner: unknown packet type: %d\n", type)); return -1; - }; + }; /* we can only now set the header as we now know the length of the payload */ set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_POLL, len); @@ -1218,7 +1218,7 @@ bjnp_poll_scanner (int devno, char type,char *hostname, char *user, SANE_Byte *s { return BJNP_RESTART_POLL; } - if ( (response -> result[2] & 0x80) != 0) + if ( (response -> result[2] & 0x80) != 0) { memcpy( status, response->status, size); PDBG( bjnp_dbg(LOG_INFO, "bjnp_poll_scanner: received button status!\n")); @@ -1234,7 +1234,7 @@ bjnp_poll_scanner (int devno, char type,char *hostname, char *user, SANE_Byte *s static void bjnp_send_job_details (int devno, char *hostname, char *user, char *title) { -/* +/* * send details of scanjob to scanner */ @@ -1277,7 +1277,7 @@ bjnp_send_job_details (int devno, char *hostname, char *user, char *title) static int bjnp_get_scanner_mac_address ( int devno, char *mac_address ) { -/* +/* * send discover to scanner */ @@ -1297,7 +1297,7 @@ bjnp_get_scanner_mac_address ( int devno, char *mac_address ) { PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_get_scanner_mac_address: Discover response:\n")); PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); - u8tohex( mac_address, resp -> mac_addr, sizeof( resp -> mac_addr ) ); + u8tohex( mac_address, resp -> mac_addr, sizeof( resp -> mac_addr ) ); return 0; } return -1; @@ -1307,7 +1307,7 @@ static int bjnp_write (int devno, const SANE_Byte * buf, size_t count) { /* - * This function writes TCP data to the scanner. + * This function writes TCP data to the scanner. * Returns: number of bytes written to the scanner */ int sent_bytes; @@ -1355,9 +1355,9 @@ static int bjnp_send_read_request (int devno) { /* - * This function reads responses from the scanner. + * This function reads responses from the scanner. * Returns: 0 on success, else -1 - * + * */ int sent_bytes; int terrno; @@ -1398,8 +1398,8 @@ bjnp_recv_header (int devno, size_t *payload_size ) /* * This function receives the response header to bjnp commands. * devno device number - * size: return value for data size returned by scanner - * Returns: + * size: return value for data size returned by scanner + * Returns: * SANE_STATUS_IO_ERROR when any IO error occurs * SANE_STATUS_GOOD in case no errors were encountered */ @@ -1443,7 +1443,7 @@ bjnp_recv_header (int devno, size_t *payload_size ) { terrno = errno; PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_header: ERROR - could not read response header (select timed out after %d ms)!\n", + "bjnp_recv_header: ERROR - could not read response header (select timed out after %d ms)!\n", device[devno].bjnp_timeout ) ); errno = terrno; return SANE_STATUS_IO_ERROR; @@ -1512,7 +1512,7 @@ bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *pr device[dn].open = 0; #ifdef PIXMA_BJNP_USE_STATUS - device[dn].polling_status = BJNP_POLL_STOPPED; + device[dn].polling_status = BJNP_POLL_STOPPED; device[dn].dialog = 0; device[dn].status_key = 0; #endif @@ -1521,7 +1521,7 @@ bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *pr device[dn].tcp_socket = -1; device[dn].addr = (bjnp_sockaddr_t *) malloc(sizeof ( bjnp_sockaddr_t) ); - memset( device[dn].addr, 0, sizeof( bjnp_sockaddr_t ) ); + memset( device[dn].addr, 0, sizeof( bjnp_sockaddr_t ) ); memcpy(device[dn].addr, sa, sa_size((bjnp_sockaddr_t *)sa) ); device[dn].address_level = get_scanner_name(sa, name); device[dn].session_id = 0; @@ -1530,7 +1530,7 @@ bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *pr device[dn].bjnp_min_timeout = min_timeout; device[dn].scanner_data_left = 0; device[dn].last_cmd = 0; - device[dn].blocksize = BJNP_BLOCKSIZE_START; + device[dn].blocksize = BJNP_BLOCKSIZE_START; device[dn].last_block = 0; /* fill mac_address */ @@ -1620,7 +1620,7 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len) { terrno = errno; PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_data: ERROR - could not read response payload (select timed out after %d ms)!\n", + "bjnp_recv_data: ERROR - could not read response payload (select timed out after %d ms)!\n", device[devno].bjnp_timeout) ); errno = terrno; *len = 0; @@ -1646,10 +1646,10 @@ bjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len) } static BJNP_Status -bjnp_allocate_device (SANE_String_Const devname, +bjnp_allocate_device (SANE_String_Const devname, SANE_Int * dn, char *resulting_host) { - char method[BJNP_METHOD_MAX]; + char method[BJNP_METHOD_MAX]; char host[BJNP_HOST_MAX]; char port[BJNP_PORT_MAX] = ""; char args[BJNP_ARGS_MAX]; @@ -1697,7 +1697,7 @@ bjnp_allocate_device (SANE_String_Const devname, { sprintf( port, "%d", protocol_defs->default_port ); } - + hints.ai_flags = 0; #ifdef ENABLE_IPV6 hints.ai_family = AF_UNSPEC; @@ -1712,7 +1712,7 @@ bjnp_allocate_device (SANE_String_Const devname, hints.ai_next = NULL; result = getaddrinfo (host, port, &hints, &res ); - if (result != 0 ) + if (result != 0 ) { PDBG (bjnp_dbg (LOG_CRIT, "bjnp_allocate_device: ERROR - Cannot resolve host: %s port %s\n", host, port)); return SANE_STATUS_INVAL; @@ -1724,7 +1724,7 @@ bjnp_allocate_device (SANE_String_Const devname, while( cur != NULL) { /* create a new device structure for this address */ - + if (bjnp_no_devices == BJNP_NO_DEVICES) { PDBG (bjnp_dbg @@ -1743,14 +1743,14 @@ bjnp_allocate_device (SANE_String_Const devname, for (i = 0; i < bjnp_no_devices; i++) { - /* Check if found the scanner before, if so we use the best address + /* Check if found the scanner before, if so we use the best address * but still make sure the scanner is listed only once. - * We check for matching addresses as wel as matching mac_addresses as + * We check for matching addresses as wel as matching mac_addresses as * an IPv6 host can have multiple adresses */ if ( strcmp( device[i].mac_address, device[bjnp_no_devices].mac_address ) == 0 ) { - if ( device[i].address_level < device[bjnp_no_devices].address_level ) + if ( device[i].address_level < device[bjnp_no_devices].address_level ) { /* use the new address instead as it is better */ free (device[i].addr); @@ -1768,7 +1768,7 @@ bjnp_allocate_device (SANE_String_Const devname, device[i].bjnp_timeout = device[bjnp_no_devices].bjnp_min_timeout; device[i].bjnp_min_timeout = device[bjnp_no_devices].bjnp_min_timeout; } - freeaddrinfo(res); + freeaddrinfo(res); *dn = i; bjnp_free_device_structure( bjnp_no_devices); return BJNP_STATUS_ALREADY_ALLOCATED; @@ -1795,8 +1795,8 @@ bjnp_allocate_device (SANE_String_Const devname, return BJNP_STATUS_GOOD; } -static void add_scanner(SANE_Int *dev_no, - const char *uri, +static void add_scanner(SANE_Int *dev_no, + const char *uri, SANE_Status (*attach_bjnp) (SANE_String_Const devname, SANE_String_Const makemodel, @@ -1816,7 +1816,7 @@ static void add_scanner(SANE_Int *dev_no, case BJNP_STATUS_GOOD: if (get_scanner_id (*dev_no, makemodel) != 0) { - PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: ERROR - Cannot read scanner make & model: %s\n", + PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: ERROR - Cannot read scanner make & model: %s\n", uri)); } else @@ -1829,7 +1829,7 @@ static void add_scanner(SANE_Int *dev_no, attach_bjnp (uri, makemodel, serial, pixma_devices); - PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner added: %s, serial %s, mac addres: %s.\n", + PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner added: %s, serial %s, mac address: %s.\n", uri, serial, device[*dev_no].mac_address)); } break; @@ -1845,7 +1845,7 @@ static void add_scanner(SANE_Int *dev_no, } } -int rewrite_uri(char *uri, int timeout, int max_len) +int add_default_timeout(char *uri, int timeout, int max_len) { char method[BJNP_METHOD_MAX]; char host[BJNP_HOST_MAX]; @@ -1869,7 +1869,7 @@ int rewrite_uri(char *uri, int timeout, int max_len) sprintf(args, "timeout=%d", timeout); } - snprintf(uri, max_len -1, "bjnp://%s:%d/%s", host, port, args); + snprintf(uri, max_len -1, "%s://%s:%d/%s", method,host, port, args); return 0; } @@ -1889,7 +1889,7 @@ sanei_bjnp_init (void) bjnp_no_devices = 0; } -/** +/** * Find devices that implement the bjnp protocol * * The function attach is called for every device which has been found. @@ -1911,7 +1911,7 @@ sanei_bjnp_find_devices (const char **conf_devices, int numbytes = 0; struct BJNP_command cmd; unsigned char resp_buf[2048]; - struct DISCOVER_RESPONSE *disc_resp = ( struct DISCOVER_RESPONSE *) & resp_buf; + struct DISCOVER_RESPONSE *disc_resp = ( struct DISCOVER_RESPONSE *) & resp_buf; int socket_fd[BJNP_SOCK_MAX]; int no_sockets; int i; @@ -1921,19 +1921,19 @@ sanei_bjnp_find_devices (const char **conf_devices, fd_set fdset; fd_set active_fdset; struct timeval timeout; - char scanner_host[256]; + char scanner_host[256]; char uri[256]; int dev_no; int port; int timeout_default = BJNP_TIMEOUT_DEFAULT; bjnp_sockaddr_t broadcast_addr[BJNP_SOCK_MAX]; - bjnp_sockaddr_t scanner_sa; + bjnp_sockaddr_t scanner_sa; socklen_t socklen; bjnp_protocol_defs_t *protocol_defs; memset( broadcast_addr, 0, sizeof( broadcast_addr) ); memset( &scanner_sa, 0 ,sizeof( scanner_sa ) ); - PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_find_devices, pixma backend version: %d.%d.%d\n", + PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_find_devices, pixma backend version: %d.%d.%d\n", PIXMA_VERSION_MAJOR, PIXMA_VERSION_MINOR, PIXMA_VERSION_BUILD)); bjnp_no_devices = 0; @@ -1954,7 +1954,7 @@ sanei_bjnp_find_devices (const char **conf_devices, timeout_default = atoi(conf_devices[i] + strlen("bjnp-timeout=") ); if (timeout_default < BJNP_TIMEOUT_DEFAULT) { - timeout_default = BJNP_TIMEOUT_DEFAULT; + timeout_default = BJNP_TIMEOUT_DEFAULT; } PDBG ( bjnp_dbg (LOG_DEBUG, "Set new default timeout value: %d ms.", timeout_default)); @@ -1963,7 +1963,7 @@ sanei_bjnp_find_devices (const char **conf_devices, PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Adding scanner from pixma.conf: %s\n", conf_devices[i])); strncpy(uri, conf_devices[i], sizeof(uri)); - rewrite_uri(uri, timeout_default, sizeof(uri)); + add_default_timeout(uri, timeout_default, sizeof(uri)); add_scanner(&dev_no, uri, attach_bjnp, pixma_devices); } PDBG (bjnp_dbg @@ -1988,10 +1988,10 @@ sanei_bjnp_find_devices (const char **conf_devices, interface = interfaces; while ((no_sockets < BJNP_SOCK_MAX) && (interface != NULL)) { - if ( ! (interface -> ifa_flags & IFF_POINTOPOINT) && - ( (socket_fd[no_sockets] = - prepare_socket( interface -> ifa_name, - (bjnp_sockaddr_t *) interface -> ifa_addr, + if ( ! (interface -> ifa_flags & IFF_POINTOPOINT) && + ( (socket_fd[no_sockets] = + prepare_socket( interface -> ifa_name, + (bjnp_sockaddr_t *) interface -> ifa_addr, (bjnp_sockaddr_t *) interface -> ifa_broadaddr, &broadcast_addr[no_sockets] ) ) != -1 ) ) { @@ -2004,7 +2004,7 @@ sanei_bjnp_find_devices (const char **conf_devices, no_sockets++; } interface = interface->ifa_next; - } + } freeifaddrs (interfaces); } #else @@ -2022,10 +2022,10 @@ sanei_bjnp_find_devices (const char **conf_devices, bc_addr.ipv4.sin_port = htons(0); bc_addr.ipv4.sin_addr.s_addr = htonl (INADDR_BROADCAST); - socket_fd[no_sockets] = prepare_socket( "any_interface", - &local, - &bc_addr, - &broadcast_addr[no_sockets] ); + socket_fd[no_sockets] = prepare_socket( "any_interface", + &local, + &bc_addr, + &broadcast_addr[no_sockets] ); if (socket_fd[no_sockets] >= 0) { FD_SET (socket_fd[no_sockets], &fdset); @@ -2039,10 +2039,10 @@ sanei_bjnp_find_devices (const char **conf_devices, local.ipv6.sin6_family = AF_INET6; local.ipv6.sin6_addr = in6addr_any; - socket_fd[no_sockets] = prepare_socket( "any_interface", - &local, + socket_fd[no_sockets] = prepare_socket( "any_interface", + &local, NULL, - &broadcast_addr[no_sockets] ); + &broadcast_addr[no_sockets] ); if (socket_fd[no_sockets] >= 0) { FD_SET (socket_fd[no_sockets], &fdset); @@ -2052,7 +2052,7 @@ sanei_bjnp_find_devices (const char **conf_devices, } no_sockets++; } -#endif +#endif } #endif @@ -2065,7 +2065,7 @@ sanei_bjnp_find_devices (const char **conf_devices, while(bjnp_protocol_defs[j].protocol_version != PROTOCOL_NONE) { set_cmd_from_string (bjnp_protocol_defs[j].proto_string, &cmd, CMD_UDP_DISCOVER, 0); - bjnp_send_broadcast ( socket_fd[i], &broadcast_addr[i], + bjnp_send_broadcast ( socket_fd[i], &broadcast_addr[i], bjnp_protocol_defs[j].default_port, cmd, sizeof (cmd)); j++; } @@ -2092,7 +2092,7 @@ sanei_bjnp_find_devices (const char **conf_devices, { socklen = sizeof(scanner_sa); if ((numbytes = - recvfrom (socket_fd[i], resp_buf, sizeof (resp_buf), 0, + recvfrom (socket_fd[i], resp_buf, sizeof (resp_buf), 0, &(scanner_sa.addr), &socklen ) ) == -1) { PDBG (bjnp_dbg @@ -2114,7 +2114,7 @@ sanei_bjnp_find_devices (const char **conf_devices, char bjnp_id[5]; strncpy(bjnp_id, disc_resp-> response.BJNP_id, 4); bjnp_id[4] = '\0'; - PDBG (bjnp_dbg (LOG_INFO, + PDBG (bjnp_dbg (LOG_INFO, "sanei_find_devices: Invalid discover response! Length = %d, Id = %s\n", numbytes, bjnp_id ) ); break; @@ -2135,7 +2135,7 @@ sanei_bjnp_find_devices (const char **conf_devices, sprintf (uri, "%s://%s:%d/timeout=%d", protocol_defs->method_string, scanner_host, port, timeout_default); - add_scanner( &dev_no, uri, attach_bjnp, pixma_devices); + add_scanner( &dev_no, uri, attach_bjnp, pixma_devices); } } @@ -2154,9 +2154,9 @@ sanei_bjnp_find_devices (const char **conf_devices, /** Open a BJNP device. * * The device is opened by its name devname and the device number is - * returned in dn on success. + * returned in dn on success. * - * Device names consist of an URI + * Device names consist of an URI * Where: * type = bjnp * hostname = resolvable name or IP-address @@ -2182,13 +2182,13 @@ sanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn) result = bjnp_allocate_device (devname, dn, NULL); if ( (result != BJNP_STATUS_GOOD) && (result != BJNP_STATUS_ALREADY_ALLOCATED ) ) { - return SANE_STATUS_INVAL; + return SANE_STATUS_INVAL; } return SANE_STATUS_GOOD; } /** Close a BJNP device. - * + * * @param dn device number */ @@ -2274,7 +2274,7 @@ sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout) * @param buffer buffer to store read data in * @param size size of the data * - * @return + * @return * - SANE_STATUS_GOOD - on succes * - SANE_STATUS_EOF - if zero bytes have been read * - SANE_STATUS_IO_ERROR - if an error occured during the read @@ -2288,7 +2288,7 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) SANE_Status result; SANE_Status error; size_t recvd; - size_t read_size; + size_t read_size; size_t read_size_max; size_t requested; @@ -2300,7 +2300,7 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) requested = *size; PDBG (bjnp_dbg - (LOG_DEBUG, "bjnp_read_bulk: 0x%lx = %ld bytes available at start\n", + (LOG_DEBUG, "bjnp_read_bulk: 0x%lx = %ld bytes available at start\n", (unsigned long) device[dn].scanner_data_left, (unsigned long) device[dn].scanner_data_left ) ); @@ -2309,7 +2309,7 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: Already received 0x%lx = %ld bytes, backend requested 0x%lx = %ld bytes\n", - (unsigned long) recvd, (unsigned long) recvd, + (unsigned long) recvd, (unsigned long) recvd, (unsigned long) requested, (unsigned long)requested )); /* Check first if there is data in flight from the scanner */ @@ -2332,7 +2332,7 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) *size = recvd; return SANE_STATUS_IO_ERROR; } - /* correct blocksize if applicable */ + /* correct blocksize if applicable */ device[dn].blocksize = MAX (device[dn].blocksize, device[dn].scanner_data_left); @@ -2341,7 +2341,7 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) /* the scanner will not react at all to a read request, when no more data is available */ /* we now determine end of data by comparing the payload size to the maximun blocksize */ /* this block is shorter than blocksize, so after this block we are done */ - + device[dn].last_block = 1; } } @@ -2358,9 +2358,9 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: Try to read 0x%lx = %ld (of max 0x%lx = %ld) bytes\n", - (unsigned long) read_size_max, (unsigned long) read_size_max, - (unsigned long) device[dn].scanner_data_left, + (unsigned long) read_size_max, + (unsigned long) device[dn].scanner_data_left, (unsigned long) device[dn].scanner_data_left) ); result = bjnp_recv_data (dn, buffer , recvd, &read_size); @@ -2369,14 +2369,14 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) *size = recvd; return SANE_STATUS_IO_ERROR; } - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: Expected at most %ld bytes, received this time: %ld\n", + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: Expected at most %ld bytes, received this time: %ld\n", read_size_max, read_size) ); device[dn].scanner_data_left = device[dn].scanner_data_left - read_size; recvd = recvd + read_size; } - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: %s: Returning %ld bytes, backend expexts %ld\n", + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: %s: Returning %ld bytes, backend expexts %ld\n", (recvd == *size)? "OK": "NOTICE",recvd, *size ) ); *size = recvd; if ( *size == 0 ) @@ -2393,7 +2393,7 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) * @param buffer buffer to write to device * @param size size of the data * - * @return + * @return * - SANE_STATUS_GOOD - on succes * - SANE_STATUS_IO_ERROR - if an error occured during the write * - SANE_STATUS_INVAL - on every other error @@ -2466,7 +2466,7 @@ sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size) * @param buffer buffer to store read data in * @param size size of the data * - * @return + * @return * - SANE_STATUS_GOOD - on succes * - SANE_STATUS_EOF - if zero bytes have been read * - SANE_STATUS_IO_ERROR - if an error occured during the read @@ -2491,7 +2491,7 @@ sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) int resp_len; int timeout; int seconds; - + PDBG (bjnp_dbg (LOG_INFO, "bjnp_read_int(%d, bufferptr, 0x%lx = %ld):\n", dn, (unsigned long) *size, (unsigned long) *size)); @@ -2523,7 +2523,7 @@ sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) case BJNP_POLL_STARTED: /* we use only seonds accuracy between poll attempts */ timeout = device[dn].bjnp_timeout /1000; - + do { if ( (resp_len = bjnp_poll_scanner (dn, 2, hostname, getusername (), buffer, *size ) ) < 0 ) diff --git a/backend/pixma_bjnp.h b/backend/pixma_bjnp.h index 998c331..a27082c 100644 --- a/backend/pixma_bjnp.h +++ b/backend/pixma_bjnp.h @@ -43,7 +43,7 @@ If you do not wish that, delete this exception notice. */ /** @file sanei_bjnp.h - * This file provides a generic BJNP interface. + * This file provides a generic BJNP interface. */ #ifndef sanei_bjnp_h @@ -65,7 +65,7 @@ extern void sanei_bjnp_init (void); /** Find scanners responding to a BJNP broadcast. * - * The function sanei_bjnp_attach is called for every device which has + * The function sanei_bjnp_attach is called for every device which has * been found. * Serial is the address of the scanner in human readable form of max * SERIAL_MAX characters @@ -91,9 +91,9 @@ sanei_bjnp_find_devices (const char **conf_devices, /** Open a BJNP device. * * The device is opened by its name devname and the device number is - * returned in dn on success. + * returned in dn on success. * - * Device names consist of an URI + * Device names consist of an URI * Where: * method = bjnp * hostname = resolvable name or IP-address @@ -112,7 +112,7 @@ sanei_bjnp_find_devices (const char **conf_devices, extern SANE_Status sanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn); /** Close a BJNP device. - * + * * @param dn device number */ @@ -133,7 +133,7 @@ extern SANE_Status sanei_bjnp_activate (SANE_Int dn); extern SANE_Status sanei_bjnp_deactivate (SANE_Int dn); /** Set the libbjnp timeout for bulk and interrupt reads. - * + * * @param devno device number * @param timeout the new timeout in ms */ @@ -152,7 +152,7 @@ extern void sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout); * @param buffer buffer to store read data in * @param size size of the data * - * @return + * @return * - SANE_STATUS_GOOD - on succes * - SANE_STATUS_EOF - if zero bytes have been read * - SANE_STATUS_IO_ERROR - if an error occured during the read @@ -171,7 +171,7 @@ sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size); * @param buffer buffer to write to device * @param size size of the data * - * @return + * @return * - SANE_STATUS_GOOD - on succes * - SANE_STATUS_IO_ERROR - if an error occured during the write * - SANE_STATUS_INVAL - on every other error @@ -188,7 +188,7 @@ sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size); * @param buffer buffer to store read data in * @param size size of the data * - * @return + * @return * - SANE_STATUS_GOOD - on succes * - SANE_STATUS_EOF - if zero bytes have been read * - SANE_STATUS_IO_ERROR - if an error occured during the read diff --git a/backend/pixma_bjnp_private.h b/backend/pixma_bjnp_private.h index 9ecc6ae..84f5c3f 100644 --- a/backend/pixma_bjnp_private.h +++ b/backend/pixma_bjnp_private.h @@ -1,5 +1,5 @@ /* SANE - Scanner Access Now Easy. - + Copyright (C) 2008 by Louis Lagendijk This file is part of the SANE package. @@ -51,13 +51,13 @@ If you do not wish that, delete this exception notice. */ -/* - * BJNP definitions +/* + * BJNP definitions */ /* selection of options */ /* This works now, disable when it gives you problems */ -#define PIXMA_BJNP_USE_STATUS 1 +#define PIXMA_BJNP_USE_STATUS 1 /* sizes */ @@ -80,7 +80,7 @@ /* timers */ #define BJNP_BROADCAST_INTERVAL 10 /* ms between broadcasts */ #define BJNP_BC_RESPONSE_TIMEOUT 500 /* waiting time for broadc. responses */ -#define BJNP_TIMEOUT_DEFAULT 1000 /* minimum tiemout value for network operations */ +#define BJNP_TIMEOUT_DEFAULT 10000 /* minimum tiemout value for network operations */ #define BJNP_USLEEP_MS 1000 /* sleep for 1 msec */ /* retries */ @@ -116,14 +116,14 @@ typedef enum bjnp_port_e BJNP_PORT_4 = 8614 } bjnp_port_t; -typedef enum +typedef enum { PROTOCOL_BJNP = 0, PROTOCOL_MFNP = 1, PROTOCOL_NONE =2 } bjnp_protocol_t; -typedef struct +typedef struct { bjnp_protocol_t protocol_version; int default_port; @@ -131,7 +131,7 @@ typedef struct char * method_string; } bjnp_protocol_defs_t; -bjnp_protocol_defs_t bjnp_protocol_defs[] = +bjnp_protocol_defs_t bjnp_protocol_defs[] = { {PROTOCOL_BJNP, BJNP_PORT_SCAN,"BJNP", "bjnp"}, {PROTOCOL_MFNP, MFNP_PORT_SCAN,"MFNP", "mfnp"}, @@ -194,7 +194,7 @@ struct __attribute__ ((__packed__)) DISCOVER_RESPONSE unsigned char ipv4_addr[4]; } ipv4; struct __attribute__ ((__packed__)) { - unsigned char ipv6_addr_1[16]; + unsigned char ipv6_addr_1[16]; unsigned char ipv6_addr_2[16]; } ipv6; } addresses; @@ -227,7 +227,7 @@ struct __attribute__ ((__packed__)) POLL_DETAILS char empty1[6]; /* 0 */ char user_host[64]; /* unicode user hostname */ uint64_t emtpy2; /* 0 */ - } type1; /* length = 80 */ + } type1; /* length = 80 */ struct __attribute__ ((__packed__)) { uint16_t empty_1; /* 00 00 */ @@ -256,7 +256,7 @@ struct __attribute__ ((__packed__)) POLL_DETAILS struct __attribute__ ((__packed__)) POLL_RESPONSE { struct BJNP_command cmd; /* command header */ - + unsigned char result[4]; /* unknown stuff, result[2] = 80 -> status is available*/ /* result[8] is dialog, size? */ uint32_t dialog; /* to be returned in next request */ @@ -270,7 +270,7 @@ struct __attribute__ ((__packed__)) POLL_RESPONSE struct __attribute__ ((__packed__)) IDENTITY { struct BJNP_command cmd; - union __attribute__ ((__packed__)) + union __attribute__ ((__packed__)) { struct __attribute__ ((__packed__)) payload_s { @@ -343,7 +343,7 @@ typedef enum typedef struct device_s { int open; /* connection to scanner is opened */ - + /* protocol version */ int protocol; char *protocol_string; @@ -380,4 +380,3 @@ typedef struct device_s uint32_t status_key; /* key of last received status message */ #endif } bjnp_device_t; - diff --git a/backend/pixma_common.c b/backend/pixma_common.c index 2882453..82c4fde 100644 --- a/backend/pixma_common.c +++ b/backend/pixma_common.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2007-2008 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -933,7 +933,7 @@ pixma_read_image (pixma_t * s, void *buf, unsigned len) if (result == 0) { /* end of image? */ s->ops->finish_scan (s); - if (s->cur_image_size != s->param->image_size) + if ((s->cur_image_size != s->param->image_size) && !s->param->mode_jpeg) { pixma_dbg (1, "WARNING:image size mismatches\n"); pixma_dbg (1, @@ -947,7 +947,7 @@ pixma_read_image (pixma_t * s, void *buf, unsigned len) "BUG:received data not multiple of line_size\n"); } } - if (s->cur_image_size < s->param->image_size) + 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); diff --git a/backend/pixma_common.h b/backend/pixma_common.h index 6c55c71..c0ed4ba 100644 --- a/backend/pixma_common.h +++ b/backend/pixma_common.h @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2006-2007 Wittawat Yamwong This file is part of the SANE package. diff --git a/backend/pixma_imageclass.c b/backend/pixma_imageclass.c index 8ad0083..9301bc6 100644 --- a/backend/pixma_imageclass.c +++ b/backend/pixma_imageclass.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2007-2009 Nicolas Martin, Copyright (C) 2008 Dennis Lou, dlou 99 at yahoo dot com @@ -83,6 +83,7 @@ #define MF8300_PID 0x2708 #define MF4500_PID 0x2736 #define MF4410_PID 0x2737 +#define D550_PID 0x2738 #define MF3010_PID 0x2759 #define MF4570_PID 0x275a #define MF4800_PID 0x2773 @@ -103,8 +104,22 @@ #define MF820_PID 0x27a6 #define MF220_PID 0x27a8 #define MF210_PID 0x27a9 +#define MF620_PID 0x27b4 +#define MF410_PID 0x27c0 +#define MF510_PID 0x27c2 #define MF230_PID 0x27d1 #define MF240_PID 0x27d2 +#define MF630_PID 0x27e1 +#define MF634_PID 0x27e2 +#define MF730_PID 0x27e4 +#define MF731_PID 0x27e5 +#define D570_PID 0x27e8 +#define MF110_PID 0x27ed +#define MF520_PID 0x27f0 +#define MF420_PID 0x27f1 +#define MF260_PID 0x27f4 +#define MF740_PID 0x27fb +#define MF640_PID 0x27fe enum iclass_state_t @@ -333,7 +348,7 @@ request_image_block (pixma_t * s, unsigned flag, uint8_t * info, s->cfg->pid == MF8030_PID) { /* 32bit size */ *datalen = mf->cb.reslen - hlen; - *size = (*datalen + hlen == 512) ? pixma_get_be32 (mf->cb.buf + 4) - *datalen : 0; + *size = (*datalen + hlen == 512) ? pixma_get_be32 (mf->cb.buf + 4) - *datalen : *size; memcpy (data, mf->cb.buf + hlen, *datalen); } PDBG (pixma_dbg (11, "*request_image_block***** size = %u *****\n", *size)); @@ -351,7 +366,7 @@ read_image_block (pixma_t * s, uint8_t * data, unsigned size) iclass_t *mf = (iclass_t *) s->subdriver; int error; unsigned maxchunksize, chunksize, count = 0; - + maxchunksize = MAX_CHUNK_SIZE * ((mf->generation >= 2 || s->cfg->pid == MF4600_PID || s->cfg->pid == MF6500_PID || @@ -704,7 +719,7 @@ iclass_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) } first_block_size = 0; - error = request_image_block (s, 4, &info, &block_size, + error = request_image_block (s, 4, &info, &block_size, mf->blkptr + mf->blk_len, &first_block_size); /* add current block to remainder of previous */ mf->blk_len += first_block_size; @@ -919,6 +934,7 @@ const pixma_config_t pixma_iclass_devices[] = { DEV ("Canon imageCLASS MF3240", "MF3240", MF3200_PID, 600, 0, 640, 877, 0), DEV ("Canon imageClass MF6500", "MF6500", MF6500_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), DEV ("Canon imageCLASS MF4410", "MF4410", MF4410_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS D550", "D550", D550_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), DEV ("Canon i-SENSYS MF4500 Series", "MF4500", MF4500_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), DEV ("Canon i-SENSYS MF3010", "MF3010", MF3010_PID, 600, 0, 640, 877, 0), DEV ("Canon i-SENSYS MF4700 Series", "MF4700", MF4700_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), @@ -934,14 +950,30 @@ const pixma_config_t pixma_iclass_devices[] = { DEV ("Canon imageClass MF8030", "MF8030", MF8030_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), DEV ("Canon i-SENSYS MF5880dn", "MF5880", MF5880_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), DEV ("Canon i-SENSYS MF6680dn", "MF6680", MF6680_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), - DEV ("Canon imageRUNNER 1133", "iR1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), + DEV ("Canon imageRUNNER 1133", "iR1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ DEV ("Canon i-SENSYS MF5900 Series", "MF5900", MF5900_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), DEV ("Canon i-SENSYS MF8500C Series", "MF8500C", MF8500_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), DEV ("Canon i-SENSYS MF6100 Series", "MF6100", MF6100_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), DEV ("Canon imageClass MF810/820", "MF810/820", MF820_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF220 Series", "MF220", MF220_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF210 Series", "MF210", MF210_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), - DEV ("Canon i-SENSYS MF230 Series", "MF230", MF230_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), - DEV ("Canon i-SENSYS MF240 Series", "MF240", MF240_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF220 Series", "MF220", MF220_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF210 Series", "MF210", MF210_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF620 Series", "MF620", MF620_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF410 Series", "MF410", MF410_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF510 Series", "MF510", MF510_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF230 Series", "MF230", MF230_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF240 Series", "MF240", MF240_PID, 600, 300, 634, 1050, PIXMA_CAP_ADF), /* max. w = 215mm, */ + /* TODO: fix black stripes for 216mm @ 600dpi */ + DEV ("Canon i-SENSYS MF630 Series", "MF630", MF630_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF730 Series", "MF730", MF730_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF731C", "MF731", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon imageCLASS MF634C", "MF632C/634C", MF634_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon imageCLASS MF733C", "MF731C/733C", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* however, we need this for ethernet/wifi */ + DEV ("Canon imageCLASS D570", "D570", D570_PID, 600, 0, 640, 877, 0), + DEV ("Canon i-SENSYS MF110 Series", "MF110", MF110_PID, 600, 0, 640, 1050, 0), + DEV ("Canon i-SENSYS MF520 Series", "MF520", MF520_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF420 Series", "MF420", MF420_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF260 Series", "MF260", MF260_PID, 600, 0, 640, 1050, 0), + DEV ("Canon i-SENSYS MF740 Series", "MF740", MF740_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF640 Series", "MF640", MF640_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), DEV (NULL, NULL, 0, 0, 0, 0, 0, 0) }; diff --git a/backend/pixma_io.h b/backend/pixma_io.h index 9dc1afb..29bb38d 100644 --- a/backend/pixma_io.h +++ b/backend/pixma_io.h @@ -91,7 +91,7 @@ void pixma_io_cleanup (void); * array of pixma_config_t which is terminated by setting * pixma_config_t::name to \c NULL. * \return Number of devices found */ -unsigned pixma_collect_devices (const char ** conf_devices, +unsigned pixma_collect_devices (const char ** conf_devices, const struct pixma_config_t *const pixma_devices[]); diff --git a/backend/pixma_io_sanei.c b/backend/pixma_io_sanei.c index 8eec883..4710cf4 100644 --- a/backend/pixma_io_sanei.c +++ b/backend/pixma_io_sanei.c @@ -1,7 +1,7 @@ /* SANE - Scanner Access Now Easy. * For limitations, see function sanei_usb_get_vendor_product(). - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2006-2007 Wittawat Yamwong This file is part of the SANE package. @@ -106,9 +106,9 @@ get_scanner_info (unsigned devnr) return si; } -static const struct pixma_config_t *lookup_scanner(const char *makemodel, +static const struct pixma_config_t *lookup_scanner(const char *makemodel, const struct pixma_config_t *const pixma_devices[]) -{ +{ int i; const struct pixma_config_t *cfg; char *match; @@ -120,12 +120,12 @@ static const struct pixma_config_t *lookup_scanner(const char *makemodel, { /* loop through devices in class */ if ((match = strcasestr (makemodel, cfg->model)) != NULL) - { + { /* possible match found, make sure it is not a partial match */ /* MP600 and MP600R are different models! */ /* some models contain ranges, so check for a '-' too */ - if ((match[strlen(cfg->model)] == ' ') || + if ((match[strlen(cfg->model)] == ' ') || (match[strlen(cfg->model)] == '\0') || (match[strlen(cfg->model)] == '-')) { @@ -159,8 +159,8 @@ attach (SANE_String_Const devname) static SANE_Status -attach_bjnp (SANE_String_Const devname, SANE_String_Const makemodel, - SANE_String_Const serial, +attach_bjnp (SANE_String_Const devname, SANE_String_Const makemodel, + SANE_String_Const serial, const struct pixma_config_t *const pixma_devices[]) { scanner_info_t *si; @@ -417,7 +417,7 @@ pixma_connect (unsigned devnr, pixma_io_t ** handle) error = map_error (sanei_bjnp_open (si->devname, &dev)); else error = map_error (sanei_usb_open (si->devname, &dev)); - + if (error < 0) return error; io = (pixma_io_t *) calloc (1, sizeof (*io)); @@ -425,7 +425,7 @@ pixma_connect (unsigned devnr, pixma_io_t ** handle) { if (si -> interface == INT_BJNP) sanei_bjnp_close (dev); - else + else sanei_usb_close (dev); return PIXMA_ENOMEM; } diff --git a/backend/pixma_mp150.c b/backend/pixma_mp150.c index dca0965..5f0a4ac 100644 --- a/backend/pixma_mp150.c +++ b/backend/pixma_mp150.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2007-2009 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -69,7 +69,7 @@ if ((error = (x)) < 0) \ return error; \ } while(0) - + #define WAIT_INTERRUPT(x) do { \ error = handle_interrupt (s, x); \ if (s->cancel) \ @@ -168,6 +168,7 @@ #define MX420_PID 0x174f #define MX880_PID 0x1750 +/* Generation 5 */ /* 2011 new devices (untested) */ #define MG2100_PID 0x1751 #define MG3100_PID 0x1752 @@ -234,13 +235,60 @@ #define MG5700_PID 0x178e /* 2016 new devices (untested) */ +#define MB2700_PID 0x1792 +#define MB2100_PID 0x1793 +#define G3000_PID 0x1794 +#define G2000_PID 0x1795 #define TS9000_PID 0x179f #define TS8000_PID 0x1800 #define TS6000_PID 0x1801 #define TS5000_PID 0x1802 #define MG3000_PID 0x180b #define E470_PID 0x180c -#define G3000_PID 0x181d +#define E410_PID 0x181e + +/* 2017 new devices (untested) */ +#define G4000_PID 0x181d +#define TS6100_PID 0x1822 +#define TS5100_PID 0x1825 +#define TS3100_PID 0x1827 +#define E3100_PID 0x1828 + +/* 2018 new devices (untested) */ +#define MB5400_PID 0x178f +#define MB5100_PID 0x1790 +#define TS9100_PID 0x1820 +#define TR8500_PID 0x1823 +#define TR7500_PID 0x1824 +#define TS9500_PID 0x185c +#define LIDE400_PID 0x1912 /* tested */ +#define LIDE300_PID 0x1913 /* tested */ + +/* 2019 new devices (untested) */ +#define TS8100_PID 0x1821 +#define G3010_PID 0x183b +#define G4010_PID 0x183d +#define TS9180_PID 0x183e +#define TS8180_PID 0x183f +#define TS6180_PID 0x1840 +#define TR8580_PID 0x1841 +#define TS8130_PID 0x1842 +#define TS6130_PID 0x1843 +#define TR8530_PID 0x1844 +#define TR7530_PID 0x1845 +#define XK50_PID 0x1846 +#define XK70_PID 0x1847 +#define TR4500_PID 0x1854 +#define E4200_PID 0x1855 +#define TS6200_PID 0x1856 +#define TS6280_PID 0x1857 +#define TS6230_PID 0x1858 +#define TS8200_PID 0x1859 +#define TS8280_PID 0x185a +#define TS8230_PID 0x185b +#define TS9580_PID 0x185d +#define TR9530_PID 0x185e +#define XK80_PID 0x1873 /* Generation 4 XML messages that encapsulates the Pixma protocol messages */ #define XML_START_1 \ @@ -387,6 +435,12 @@ is_scanning_from_adfdup (pixma_t * s) return (s->param->source == PIXMA_SOURCE_ADFDUP); } +static int +is_scanning_jpeg (pixma_t *s) +{ + return s->param->mode_jpeg; +} + static int is_scanning_from_tpu (pixma_t * s) { @@ -441,7 +495,7 @@ static int send_cmd_start_calibrate_ccd_3 (pixma_t * s) { mp150_t *mp = (mp150_t *) s->subdriver; - + pixma_newcmd (&mp->cb, cmd_start_calibrate_ccd_3, 0, 0); mp->cb.buf[3] = 0x01; return pixma_exec (s, &mp->cb); @@ -469,7 +523,7 @@ static int has_paper (pixma_t * s) { mp150_t *mp = (mp150_t *) s->subdriver; - + if (is_scanning_from_adfdup (s)) return (mp->current_status[1] == 0 || mp->current_status[2] == 0); else @@ -512,19 +566,19 @@ select_source (pixma_t * s) data[0] = 1; data[1] = 1; break; - + case PIXMA_SOURCE_ADF: data[0] = 2; data[5] = 1; data[6] = 1; break; - + case PIXMA_SOURCE_ADFDUP: data[0] = 2; data[5] = 3; data[6] = 3; break; - + case PIXMA_SOURCE_TPU: data[0] = 4; data[1] = 2; @@ -656,7 +710,7 @@ get_cis_ccd_line_size (pixma_t * s) return ((s->param->wx ? s->param->line_size / s->param->w * s->param->wx : s->param->line_size) * ((is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 3 : 1)); } - + static unsigned calc_shifting (pixma_t * s) { @@ -683,7 +737,7 @@ calc_shifting (pixma_t * s) { mp->color_shift = s->param->ydpi / ((s->param->ydpi < 1200) ? 150 : 75); - if (is_scanning_from_tpu (s)) + if (is_scanning_from_tpu (s)) mp->color_shift = s->param->ydpi / 75; /* If you're trying to decipher this color-shifting code, @@ -714,7 +768,7 @@ send_scan_param (pixma_t * s) mp150_t *mp = (mp150_t *) s->subdriver; uint8_t *data; unsigned raw_width = calc_raw_width (mp, s->param); - unsigned h = MIN (s->param->h + calc_shifting (s), + unsigned h = MIN (s->param->h + calc_shifting (s), s->cfg->height * s->param->ydpi / 75); /* TPU scan does not support lineart */ @@ -762,7 +816,14 @@ send_scan_param (pixma_t * s) data[0x02] = 0x03; data[0x03] = 0x03; } - data[0x05] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ + if (is_scanning_jpeg (s)) + { + data[0x03] = 0x01; + } + else + { + data[0x05] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ + } pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x08); pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x0a); /*PDBG (pixma_dbg (4, "*send_scan_param gen. 3+ ***** Setting: xdpi=%hi ydpi=%hi x=%i y=%i w=%i ***** \n", @@ -772,7 +833,7 @@ send_scan_param (pixma_t * s) pixma_set_be32 (raw_width, data + 0x14); pixma_set_be32 (h, data + 0x18); data[0x1c] = ((s->param->channels != 1) || is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 0x08 : 0x04; - + #ifdef DEBUG_TPU_48 data[0x1d] = 24; #else @@ -783,7 +844,14 @@ send_scan_param (pixma_t * s) data[0x1f] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ data[0x20] = 0xff; - data[0x21] = 0x81; + if (is_scanning_jpeg (s)) + { + data[0x21] = 0x83; + } + else + { + data[0x21] = 0x81; + } data[0x23] = 0x02; data[0x24] = 0x01; @@ -882,6 +950,7 @@ read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) return datalen; memcpy (header, mp->cb.buf, hlen); + if (datalen >= hlen) { datalen -= hlen; @@ -959,12 +1028,14 @@ handle_interrupt (pixma_t * s, int timeout) * tt: target * rr: scan resolution * poll event with 'scanimage -A' */ - if (s->cfg->pid == MG5400_PID + if (s->cfg->pid == MG5300_PID + || s->cfg->pid == MG5400_PID || s->cfg->pid == MG6200_PID || s->cfg->pid == MG6300_PID || s->cfg->pid == MX520_PID || s->cfg->pid == MX720_PID || s->cfg->pid == MX920_PID + || s->cfg->pid == MB2300_PID || s->cfg->pid == MB5000_PID) /* button no. in buf[7] * size in buf[10] 01=A4; 02=Letter; 08=10x15; 09=13x18; 0b=auto @@ -977,6 +1048,15 @@ handle_interrupt (pixma_t * s, int timeout) if (buf[7] & 2) s->events = PIXMA_EV_BUTTON2 | buf[11] | buf[10]<<8 | buf[12]<<16; /* b/w scan */ } + else if (s->cfg->pid == LIDE300_PID + || s->cfg->pid == LIDE400_PID) + /* unknown value in buf[4] + * target in buf[0x13] + * always set button-1 */ + { + if (buf[0x13]) + s->events = PIXMA_EV_BUTTON1 | buf[0x13]; + } else /* button no. in buf[0] * original in buf[0] @@ -1037,8 +1117,8 @@ wait_until_ready (pixma_t * s) WAIT_INTERRUPT (1000); if (mp->generation >= 3) RET_IF_ERR (query_status_3 (s)); - else if (s->cfg->pid == MP600_PID || - s->cfg->pid == MP600R_PID || + else if (s->cfg->pid == MP600_PID || + s->cfg->pid == MP600R_PID || s->cfg->pid == MP800R_PID) RET_IF_ERR (query_status (s)); if (--tmo == 0) @@ -1052,8 +1132,8 @@ wait_until_ready (pixma_t * s) } static uint8_t * -shift_colors (uint8_t * dptr, uint8_t * sptr, - unsigned w, unsigned dpi, unsigned pid, unsigned c, +shift_colors (uint8_t * dptr, uint8_t * sptr, + unsigned w, unsigned dpi, unsigned pid, unsigned c, int * colshft, unsigned strshft) { unsigned i, sr, sg, sb, st; @@ -1064,7 +1144,7 @@ shift_colors (uint8_t * dptr, uint8_t * sptr, { /* stripes shift for MP800, MP800R at 2400 dpi */ st = (i % 2 == 0) ? strshft : 0; - + *sptr++ = *(dptr++ + sr + st); if (c == 6) *sptr++ = *(dptr++ + sr + st); *sptr++ = *(dptr++ + sg + st); @@ -1076,7 +1156,7 @@ shift_colors (uint8_t * dptr, uint8_t * sptr, } static void -reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, unsigned n, +reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, unsigned n, unsigned m, unsigned w, unsigned line_size) { unsigned i; @@ -1095,7 +1175,7 @@ pack_48_24_bpc (uint8_t * sptr, unsigned n) unsigned i; uint8_t *cptr, lsb; static uint8_t offset = 0; - + cptr = sptr; if (n % 2 != 0) PDBG (pixma_dbg (3, "WARNING: misaligned image.\n")); @@ -1109,9 +1189,9 @@ pack_48_24_bpc (uint8_t * sptr, unsigned n) } #endif -/* This function deals both with PIXMA CCD sensors producing shifted color +/* This function deals both with PIXMA CCD sensors producing shifted color * planes images, Grayscale CCD scan and Generation >= 3 high dpi images. - * Each complete line in mp->imgbuf is processed for shifting CCD sensor + * Each complete line in mp->imgbuf is processed for shifting CCD sensor * color planes, reordering pixels above 600 dpi for Generation >= 3, and * converting to Grayscale for CCD sensors. */ static unsigned @@ -1121,19 +1201,28 @@ post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) unsigned c, lines, line_size, n, m, cw, cx; uint8_t *sptr, *dptr, *gptr, *cptr; + if (s->param->mode_jpeg) + { + /* No post-processing, send raw JPEG data to main */ + ib->rptr = mp->imgbuf; + ib->rend = mp->data_left_ofs; + return 0; /* # of non processed bytes */ + } + + c = ((is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 3 : s->param->channels) * ((s->param->software_lineart) ? 8 : s->param->depth) / 8; cw = c * s->param->w; cx = c * s->param->xs; - + if (mp->generation >= 3) n = s->param->xdpi / 600; else /* FIXME: maybe need different values for CIS and CCD sensors */ n = s->param->xdpi / 2400; - - if (s->cfg->pid == MP600_PID || s->cfg->pid == MP600R_PID) + + if (s->cfg->pid == MP600_PID || s->cfg->pid == MP600R_PID) n = s->param->xdpi / 1200; - + m = (n > 0) ? s->param->wx / n : 1; sptr = dptr = gptr = cptr = mp->imgbuf; line_size = get_cis_ccd_line_size (s); @@ -1153,38 +1242,33 @@ post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) /*PDBG (pixma_dbg (4, "*post_process_image_data***** Processing with c=%u, n=%u, m=%u, w=%i, line_size=%u ***** \n", c, n, m, s->param->wx, line_size));*/ if (s->cfg->pid != MG5300_PID && s->cfg->pid != MG6300_PID && c >= 3) - dptr = shift_colors (dptr, sptr, + dptr = shift_colors (dptr, sptr, s->param->wx, s->param->xdpi, s->cfg->pid, c, mp->shift, mp->stripe_shift); - - /* special image format for *most* devices at high dpi. - * MP220, MX360, MX370, MX890, MG5300 are exceptions */ + + /* special image format for *most* devices at high dpi. + * MP220, MX360 and generation 5 scanners are exceptions */ if (n > 0 && s->cfg->pid != MP220_PID + && s->cfg->pid != MP490_PID && s->cfg->pid != MX360_PID - && s->cfg->pid != MX370_PID - && s->cfg->pid != MX530_PID - && s->cfg->pid != MX890_PID - && s->cfg->pid != MX720_PID - && s->cfg->pid != MX920_PID - && s->cfg->pid != MG3100_PID - && s->cfg->pid != MG3500_PID - && s->cfg->pid != MG3600_PID - && s->cfg->pid != MG2100_PID - && s->cfg->pid != MG5300_PID - && s->cfg->pid != MG5400_PID - && s->cfg->pid != MG5500_PID - && s->cfg->pid != MG6300_PID - && s->cfg->pid != MG6400_PID - && s->cfg->pid != MG7100_PID - && s->cfg->pid != MG7500_PID - && s->cfg->pid != MG7700_PID - && s->cfg->pid != MB5000_PID) + && (mp->generation < 5 + /* generation 5 scanners *with* special image format */ + || s->cfg->pid == MG2200_PID + || s->cfg->pid == MG3200_PID + || s->cfg->pid == MG4200_PID + || s->cfg->pid == MG5600_PID + || s->cfg->pid == MG5700_PID + || s->cfg->pid == MG6200_PID + || s->cfg->pid == MP230_PID + || s->cfg->pid == MX470_PID + || s->cfg->pid == MX510_PID + || s->cfg->pid == MX520_PID)) reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, line_size); - + /* Crop line to selected borders */ memmove(cptr, sptr + cx, cw); - + /* Color / Gray to Lineart convert */ if (s->param->software_lineart) cptr = gptr = pixma_binarize_line (s->param, gptr, cptr, s->param->w, c); @@ -1237,10 +1321,13 @@ mp150_open (pixma_t * s) if (s->cfg->pid >= MP250_PID) mp->generation = 4; + if (s->cfg->pid >= MG2100_PID) /* this scanners generation doesn't need */ + mp->generation = 5; /* special image conversion @ high dpi */ + /* And exceptions to be added here */ if (s->cfg->pid == MP140_PID) mp->generation = 2; - + PDBG (pixma_dbg (3, "*mp150_open***** This is a generation %d scanner. *****\n", mp->generation)); /* TPU info data setup */ @@ -1253,7 +1340,7 @@ mp150_open (pixma_t * s) { query_status (s); handle_interrupt (s, 200); - if (mp->generation == 3 && has_ccd_sensor (s)) + if (mp->generation == 3 && has_ccd_sensor (s)) send_cmd_start_calibrate_ccd_3 (s); } return 0; @@ -1324,14 +1411,16 @@ mp150_check_param (pixma_t * s, pixma_scan_param_t * sp) sp->wx = calc_raw_width (mp, sp); sp->line_size = sp->w * sp->channels * (((sp->software_lineart) ? 8 : sp->depth) / 8); /* bytes per line per color after cropping */ /*PDBG (pixma_dbg (4, "*mp150_check_param***** Final scan width and line-size: %i, %i *****\n", sp->wx, sp->line_size));*/ - + /* Some exceptions here for particular devices */ /* Those devices can scan up to legal 14" with ADF, but A4 11.7" in flatbed */ /* PIXMA_CAP_ADF also works for PIXMA_CAP_ADFDUP */ if ((s->cfg->cap & PIXMA_CAP_ADF) && sp->source == PIXMA_SOURCE_FLATBED) sp->h = MIN (sp->h, 877 * sp->xdpi / 75); - - if (sp->source == PIXMA_SOURCE_TPU) + + if (sp->source == PIXMA_SOURCE_TPU + || s->cfg->pid == LIDE300_PID + || s->cfg->pid == LIDE400_PID) { uint8_t k; @@ -1340,10 +1429,10 @@ mp150_check_param (pixma_t * s, pixma_scan_param_t * sp) k = MAX (sp->xdpi, 300) / sp->xdpi; else k = MAX (sp->xdpi, 150) / sp->xdpi; - sp->x *= k; + sp->x *= k; sp->xs *= k; sp->y *= k; - sp->w *= k; + sp->w *= k; sp->wx *= k; sp->h *= k; sp->xdpi *= k; @@ -1354,7 +1443,7 @@ mp150_check_param (pixma_t * s, pixma_scan_param_t * sp) { uint8_t k = 1; - /* ADF/ADF duplex mode: max scan res is 600 dpi, at least for generation 4 */ + /* ADF/ADF duplex mode: max scan res is 600 dpi, at least for generation 4+ */ if (mp->generation >= 4) k = sp->xdpi / MIN (sp->xdpi, 600); sp->x /= k; @@ -1367,6 +1456,10 @@ mp150_check_param (pixma_t * s, pixma_scan_param_t * sp) sp->ydpi = sp->xdpi; } + sp->mode_jpeg = (s->cfg->cap & PIXMA_CAP_ADF_JPEG) && + (sp->source == PIXMA_SOURCE_ADF || + sp->source == PIXMA_SOURCE_ADFDUP); + /*PDBG (pixma_dbg (4, "*mp150_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx));*/ return 0; @@ -1381,9 +1474,15 @@ mp150_scan (pixma_t * s) if (mp->state != state_idle) return PIXMA_EBUSY; - /* Generation 4: send XML dialog */ + /* no paper inserted after first adf page => abort session */ + if (s->param->adf_pageid && is_scanning_from_adf(s) && mp->adf_state == state_idle) + { + return PIXMA_ENO_PAPER; + } + + /* Generation 4+: send XML dialog */ /* adf: first page or idle */ - if (mp->generation == 4 && mp->adf_state == state_idle) + if (mp->generation >= 4 && mp->adf_state == state_idle) { if (!send_xml_dialog (s, XML_START_1)) return PIXMA_EPROTO; @@ -1423,9 +1522,9 @@ mp150_scan (pixma_t * s) if (error < 0) return error; - /* Generation 4: send XML dialog */ + /* Generation 4+: send XML dialog */ /* adf: first page or idle */ - if (mp->generation == 4 && mp->adf_state == state_idle) + if (mp->generation >= 4 && mp->adf_state == state_idle) { if (!send_xml_dialog (s, XML_END)) return PIXMA_EPROTO; @@ -1442,14 +1541,14 @@ mp150_scan (pixma_t * s) { case PIXMA_ECANCELED: case PIXMA_EBUSY: - PDBG (pixma_dbg (2, "cmd e920 or d520 returned %s\n", + PDBG (pixma_dbg (2, "cmd e920 or d520 returned %s\n", pixma_strerror (error))); /* fall through */ case 0: query_status (s); break; default: - PDBG (pixma_dbg (1, "WARNING:cmd e920 or d520 failed %s\n", + PDBG (pixma_dbg (1, "WARNING:cmd e920 or d520 failed %s\n", pixma_strerror (error))); return error; } @@ -1496,7 +1595,7 @@ mp150_scan (pixma_t * s) error = select_source (s); if ((error >= 0) && (mp->generation >= 3) && has_ccd_sensor (s)) error = init_ccd_lamp_3 (s); - if ((error >= 0) && !is_scanning_from_tpu (s)) + if ((error >= 0) && !is_scanning_from_tpu (s) && !is_scanning_jpeg (s)) { int i; @@ -1511,8 +1610,6 @@ mp150_scan (pixma_t * s) PDBG (pixma_dbg (4, "*mp150_scan***** scan next sheet from ADF *****\n")); pixma_sleep (1000000); } - - if ((error >= 0) || (mp->generation >= 3)) mp->state = state_warmup; if (error >= 0) @@ -1610,7 +1707,7 @@ mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) #endif bytes_received = pack_48_24_bpc (mp->imgbuf + mp->data_left_len, bytes_received); #endif -#endif +#endif /* Post-process the image data */ mp->data_left_ofs = mp->imgbuf + mp->data_left_len + bytes_received; mp->data_left_len = post_process_image_data (s, ib); @@ -1638,7 +1735,7 @@ mp150_finish_scan (pixma_t * s) /* Send the get TPU info message */ if (is_scanning_from_tpu (s) && mp->tpu_datalen == 0) send_get_tpu_info_3 (s); - /* FIXME: to process several pages ADF scan, must not send + /* FIXME: to process several pages ADF scan, must not send * abort_session and start_session between pages (last_block=0x28) */ if (mp->generation <= 2 || !is_scanning_from_adf (s) || mp->last_block == 0x38) { @@ -1647,8 +1744,8 @@ mp150_finish_scan (pixma_t * s) if (error < 0) PDBG (pixma_dbg (1, "WARNING:abort_session() failed %d\n", error)); - /* Generation 4: send XML end of scan dialog */ - if (mp->generation == 4) + /* Generation 4+: send XML end of scan dialog */ + if (mp->generation >= 4) { if (!send_xml_dialog (s, XML_END)) PDBG (pixma_dbg (1, "WARNING:XML_END dialog failed \n")); @@ -1793,7 +1890,7 @@ const pixma_config_t pixma_mp150_devices[] = { DEVICE ("Canon PIXMA MG5200", "MG5200", MG5200_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA MG6100", "MG6100", MG6100_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - /* Latest devices (2011) Generation 4 CIS/CCD */ + /* Latest devices (2011) Generation 5 CIS/CCD */ DEVICE ("Canon PIXMA MG2100", "MG2100", MG2100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA MG3100", "MG3100", MG3100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA MG4100", "MG4100", MG4100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), @@ -1802,7 +1899,7 @@ const pixma_config_t pixma_mp150_devices[] = { DEVICE ("Canon PIXMA MP493", "MP493", MP493_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA E500", "E500", E500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - /* Latest devices (2012) Generation 4 CIS */ + /* Latest devices (2012) Generation 5 CIS */ DEVICE ("Canon PIXMA MX370 Series", "MX370", MX370_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA MX430 Series", "MX430", MX430_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA MX510 Series", "MX510", MX510_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), @@ -1811,7 +1908,7 @@ const pixma_config_t pixma_mp150_devices[] = { DEVICE ("Canon PIXMA E600 Series", "E600", E600_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA MG4200", "MG4200", MG4200_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - /* Latest devices (2013) Generation 4 CIS */ + /* Latest devices (2013) Generation 5 CIS */ DEVICE ("Canon PIXMA E510", "E510", E510_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA E610", "E610", E610_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA MP230", "MP230", MP230_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), @@ -1832,13 +1929,15 @@ const pixma_config_t pixma_mp150_devices[] = { DEVICE ("Canon PIXMA MG6500 Series", "MG6500", MG6500_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA MG7100 Series", "MG7100", MG7100_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - /* Latest devices (2014) Generation 4 CIS */ + /* Latest devices (2014) Generation 5 CIS */ DEVICE ("Canon PIXMA MX470 Series", "MX470", MX470_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA MX530 Series", "MX530", MX530_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon MAXIFY MB5000 Series", "MB5000", MB5000_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), DEVICE ("Canon MAXIFY MB5300 Series", "MB5300", MB5300_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), DEVICE ("Canon MAXIFY MB2000 Series", "MB2000", MB2000_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon MAXIFY MB2300 Series", "MB2300", MB2300_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon MAXIFY MB2100 Series", "MB2100", MB2100_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), + DEVICE ("Canon MAXIFY MB2300 Series", "MB2300", MB2300_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon MAXIFY MB2700 Series", "MB2700", MB2700_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), DEVICE ("Canon PIXMA E400", "E400", E400_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA E560", "E560", E560_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA MG7500 Series", "MG7500", MG7500_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), @@ -1847,7 +1946,7 @@ const pixma_config_t pixma_mp150_devices[] = { DEVICE ("Canon PIXMA MG2900 Series", "MG2900", MG2900_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA E460 Series", "E460", E460_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - /* Latest devices (2015) Generation 4 CIS */ + /* Latest devices (2015) Generation 5 CIS */ DEVICE ("Canon PIXMA MX490 Series", "MX490", MX490_PID, 600, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA E480 Series", "E480", E480_PID, 600, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), DEVICE ("Canon PIXMA MG3600 Series", "MG3600", MG3600_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), @@ -1856,14 +1955,59 @@ const pixma_config_t pixma_mp150_devices[] = { DEVICE ("Canon PIXMA MG6800 Series", "MG6800", MG6800_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA MG5700 Series", "MG5700", MG5700_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - /* Latest devices (2016) Generation 4 CIS */ - DEVICE ("Canon PIXMA TS9000 Series", "TS9000", TS9000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS8000 Series", "TS8000", TS8000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS6000 Series", "TS6000", TS6000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS5000 Series", "TS5000", TS5000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + /* Latest devices (2016) Generation 5 CIS */ + DEVICE ("Canon PIXMA G3000", "G3000", G3000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G2000", "G2000", G2000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS9000 Series", "TS9000", TS9000_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8000 Series", "TS8000", TS8000_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6000 Series", "TS6000", TS6000_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS5000 Series", "TS5000", TS5000_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA MG3000 Series", "MG3000", MG3000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), DEVICE ("Canon PIXMA E470 Series", "E470", E470_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA G4000 Series", "G3000", G3000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E410 Series", "E410", E410_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2017) Generation 5 CIS */ + DEVICE ("Canon PIXMA G4000", "G4000", G4000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6100 Series", "TS6100", TS6100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS5100 Series", "TS5100", TS5100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS3100 Series", "TS3100", TS3100_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E3100 Series", "E3100", E3100_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2018) Generation 5 CIS */ + DEVICE ("Canon MAXIFY MB5400 Series", "MB5400", MB5400_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon MAXIFY MB5100 Series", "MB5100", MB5100_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon PIXMA TS9100 Series", "TS9100", TS9100_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TR8500 Series", "TR8500", TR8500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TR7500 Series", "TR7500", TR7500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TS9500 Series", "TS9500", TS9500_PID, 1200, 0, 600, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("CanoScan LiDE 400", "LIDE400", LIDE400_PID, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("CanoScan LiDE 300", "LIDE300", LIDE300_PID, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2019) Generation 5 CIS */ + DEVICE ("Canon PIXMA TS8100 Series", "TS8100", TS8100_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G3010 Series", "G3010", G3010_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G4010 Series", "G4010", G4010_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TS9180 Series", "TS9180", TS9180_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8180 Series", "TS8180", TS8180_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6180 Series", "TS6180", TS6180_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TR8580 Series", "TR8580", TR8580_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TS8130 Series", "TS8130", TS8130_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6130 Series", "TS6130", TS6130_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TR8530 Series", "TR8530", TR8530_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TR7530 Series", "TR7530", TR7530_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXUS XK50 Series", "XK50", XK50_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXUS XK70 Series", "XK70", XK70_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TR4500 Series", "TR4500", TR4500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA E4200 Series", "E4200", E4200_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TS6200 Series", "TS6200", TS6200_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6280 Series", "TS6280", TS6280_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6230 Series", "TS6230", TS6230_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8200 Series", "TS8200", TS8200_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8280 Series", "TS8280", TS8280_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8230 Series", "TS8230", TS8230_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS9580 Series", "TS9580", TS9580_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TR9530 Series", "TR9530", TR9530_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXUS XK80 Series", "XK80", XK80_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), END_OF_DEVICE_LIST }; diff --git a/backend/pixma_mp730.c b/backend/pixma_mp730.c index 6bf3f42..c801daa 100644 --- a/backend/pixma_mp730.c +++ b/backend/pixma_mp730.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2007-2008 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -442,10 +442,10 @@ step1 (pixma_t * s) default: break; } - + activate (s, 0); error = calibrate (s); - + switch (s->cfg->pid) { case MF5730_PID: @@ -836,7 +836,7 @@ const pixma_config_t pixma_mp730_devices[] = { DEVICE ("PIXMA MP710", "MP710", MP710_PID, 1200, 637, 868, PIXMA_CAP_LINEART), DEVICE ("PIXMA MP730", "MP730", MP730_PID, 1200, 637, 868, PIXMA_CAP_ADF | PIXMA_CAP_LINEART), DEVICE ("PIXMA MP740", "MP740", MP740_PID, 1200, 637, 868, PIXMA_CAP_ADF | PIXMA_CAP_LINEART), - + DEVICE ("Canon imageCLASS MF5730", "MF5730", MF5730_PID, 1200, 636, 868, PIXMA_CAP_ADF), DEVICE ("Canon imageCLASS MF5750", "MF5750", MF5750_PID, 1200, 636, 868, PIXMA_CAP_ADF), DEVICE ("Canon imageCLASS MF5770", "MF5770", MF5770_PID, 1200, 636, 868, PIXMA_CAP_ADF), diff --git a/backend/pixma_mp750.c b/backend/pixma_mp750.c index c5ac335..5bd6ef0 100644 --- a/backend/pixma_mp750.c +++ b/backend/pixma_mp750.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2006-2007 Wittawat Yamwong This file is part of the SANE package. @@ -229,8 +229,8 @@ is_ccd_grayscale (pixma_t * s) static unsigned get_cis_ccd_line_size (pixma_t * s) { - return (s->param->wx ? s->param->line_size / s->param->w * s->param->wx - : s->param->line_size) * ((is_ccd_grayscale (s)) ? 3 : 1); + return (s->param->wx ? s->param->line_size / s->param->w * s->param->wx + : s->param->line_size) * ((is_ccd_grayscale (s)) ? 3 : 1); } static int @@ -829,17 +829,17 @@ mp750_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) /* Color to Grayscale converion for CCD sensor */ if (is_ccd_grayscale (s)) { - shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, - mp->imgcol + mp->imgbuf_ofs); + shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, + mp->imgcol + mp->imgbuf_ofs); /* dst: img, src: imgcol */ - rgb_to_gray (mp->img, mp->imgcol, n, c); /* cropping occurs later? */ + rgb_to_gray (mp->img, mp->imgcol, n, c); /* cropping occurs later? */ PDBG (pixma_dbg (4, "*fill_buffer: did grayscale conversion \n")); } /* Color image processing */ else { - shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, + shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, mp->img + mp->imgbuf_ofs); - PDBG (pixma_dbg (4, "*fill_buffer: no grayscale conversion---keep color \n")); + PDBG (pixma_dbg (4, "*fill_buffer: no grayscale conversion---keep color \n")); } /* entering remaining unprocessed bytes after last complete pixel into mp->rawimg buffer -- no influence on mp->img */ @@ -852,7 +852,7 @@ mp750_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) } while (mp->shifted_bytes <= 0); - if ((unsigned) mp->shifted_bytes < mp->last_block_size) + if ((unsigned) mp->shifted_bytes < mp->last_block_size) { if (is_ccd_grayscale (s)) ib->rptr = mp->img + mp->last_block_size/3 - mp->shifted_bytes/3; /* testing---works OK */ @@ -864,7 +864,7 @@ mp750_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) if (is_ccd_grayscale (s)) ib->rend = mp->img + mp->last_block_size/3; /* testing---works OK */ else - ib->rend = mp->img + mp->last_block_size; + ib->rend = mp->img + mp->last_block_size; return ib->rend - ib->rptr; } diff --git a/backend/pixma_mp810.c b/backend/pixma_mp810.c index b03bebc..5d81e3f 100644 --- a/backend/pixma_mp810.c +++ b/backend/pixma_mp810.c @@ -1,6 +1,6 @@ /* SANE - Scanner Access Now Easy. - Copyright (C) 2011-2016 Rolf Bensch + Copyright (C) 2011-2019 Rolf Bensch Copyright (C) 2007-2009 Nicolas Martin, Copyright (C) 2006-2007 Wittawat Yamwong @@ -1531,9 +1531,9 @@ pack_48_24_bpc (uint8_t * sptr, unsigned n) } #endif -/* This function deals both with PIXMA CCD sensors producing shifted color +/* This function deals both with PIXMA CCD sensors producing shifted color * planes images, Grayscale CCD scan and Generation >= 3 high dpi images. - * Each complete line in mp->imgbuf is processed for shifting CCD sensor + * Each complete line in mp->imgbuf is processed for shifting CCD sensor * color planes, reordering pixels above 600 dpi for Generation >= 3, and * converting to Grayscale for CCD sensors. */ static unsigned post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) @@ -2251,7 +2251,7 @@ static int mp810_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) #endif bytes_received = pack_48_24_bpc (mp->imgbuf + mp->data_left_len, bytes_received); #endif -#endif +#endif /* Post-process the image data */ mp->data_left_ofs = mp->imgbuf + mp->data_left_len + bytes_received; mp->data_left_len = post_process_image_data (s, ib); @@ -2280,7 +2280,7 @@ static void mp810_finish_scan (pixma_t * s) /* Send the get TPU info message */ if (is_scanning_from_tpu (s) && mp->tpu_datalen == 0) send_get_tpu_info_3 (s); - /* FIXME: to process several pages ADF scan, must not send + /* FIXME: to process several pages ADF scan, must not send * abort_session and start_session between pages (last_block=0x28) */ if (mp->generation <= 2 || !is_scanning_from_adf (s) || mp->last_block == 0x38) diff --git a/backend/pixma_sane_options.c b/backend/pixma_sane_options.c index 2e4a054..6e6abfc 100644 --- a/backend/pixma_sane_options.c +++ b/backend/pixma_sane_options.c @@ -1,13 +1,13 @@ /* Automatically generated from pixma_sane.c */ -static const SANE_Range constraint_gamma_table = +static const SANE_Range constraint_gamma_table = { 0,255,0 }; -static const SANE_Range constraint_gamma = +static const SANE_Range constraint_gamma = { SANE_FIX(0.3),SANE_FIX(5),SANE_FIX(0) }; -static const SANE_Range constraint_threshold = +static const SANE_Range constraint_threshold = { 0,100,1 }; -static const SANE_Range constraint_threshold_curve = +static const SANE_Range constraint_threshold_curve = { 0,127,1 }; -static const SANE_Range constraint_adf_wait = +static const SANE_Range constraint_adf_wait = { 0,3600,1 }; @@ -360,4 +360,3 @@ int build_option_descriptors(struct pixma_sane_t *ss) return 0; } - diff --git a/backend/pixma_sane_options.h b/backend/pixma_sane_options.h index 669a234..1472f1f 100644 --- a/backend/pixma_sane_options.h +++ b/backend/pixma_sane_options.h @@ -49,4 +49,3 @@ typedef struct { struct pixma_sane_t; static int build_option_descriptors(struct pixma_sane_t *ss); - diff --git a/backend/plustek-pp.h b/backend/plustek-pp.h index 3c052f2..5a1c453 100644 --- a/backend/plustek-pp.h +++ b/backend/plustek-pp.h @@ -566,7 +566,7 @@ typedef struct Plustek_Device SANE_Int res_list_size; /* resolution values */ ScannerCaps caps; /* caps reported by the driver */ AdjDef adj; /* for driver adjustment */ - + /* * each device we support may need other access functions... */ @@ -612,9 +612,9 @@ typedef struct Plustek_Scanner SANE_Byte *buf; /* the image buffer */ SANE_Bool scanning; /* TRUE during scan-process */ SANE_Parameters params; /* for keeping the parameter */ - + /************************** gamma tables *********************************/ - + SANE_Word gamma_table[4][4096]; SANE_Range gamma_range; int gamma_length; @@ -626,7 +626,7 @@ typedef struct Plustek_Scanner /** for collecting configuration info... */ typedef struct { - + char devName[PATH_MAX]; /* contains the stuff to adjust... */ diff --git a/backend/plustek-pp_dac.c b/backend/plustek-pp_dac.c index f89d814..f0cfe40 100644 --- a/backend/plustek-pp_dac.c +++ b/backend/plustek-pp_dac.c @@ -311,7 +311,7 @@ static void dacP98CheckLastGain( pScanData ps ) if (b[w] < *p.pb) b[w] = *p.pb; } - + if (b[w] > _GAIN_P98_HIGH) { *(pbReg [w]) -= 1; } @@ -643,7 +643,7 @@ static void dacP98WriteBackToShadingRAM( pScanData ps ) *pBuffer = Data.wValue; pBuffer++; } - + } dacP98DownloadShadingTable( ps, ps->pScanBuffer2, (5400 * 2 * 3)); } @@ -763,7 +763,7 @@ static void dacP98Adjust12BitShading( pScanData ps ) *pt.pdw += (ULong)(*pd.pw * 94 / 100 & 0x0fff); /* one line */ - if (IOReadFifoLength( ps ) <= 2500) + if (IOReadFifoLength( ps ) <= 2500) IORegisterDirectToScanner( ps, ps->RegRefreshScanState ); } @@ -782,7 +782,7 @@ static Bool dacP98WaitForShading( pScanData ps ) DBG( DBG_LOW, "dacP98WaitForShading()\n" ); - /* + /* * before getting the shading data, (re)init the ASIC */ ps->InitialSetCurrentSpeed( ps ); @@ -1079,7 +1079,7 @@ static void dacP96ReadColorShadingLine( pScanData ps ) } } else b2ndDiscard--; - + if (!b3rdDiscard) { if (b3rdReadLines) { b3rdReadLines--; @@ -1159,7 +1159,7 @@ static void dacP96SetShadingGainProc( pScanData ps, Byte bHigh, ULong dwCh ) ps->Asic96Reg.RD_ShadingCorrectCtrl &= bMask; ps->Asic96Reg.RD_ShadingCorrectCtrl |= bGain; - if (!bGain) { + if (!bGain) { /* GammaGain1 (ps) */ for (dw = ps->BufferSizePerModel; dw; dw--, pbSrce++, pbDest++) if (*pbSrce > bDark) @@ -1334,7 +1334,7 @@ static Bool dacP96003WaitForShading( pScanData ps ) dacP96SetInitialGainRAM( ps ); /* SetInitialGainRegister () ++++++++++++++++++++++++++++++++++++*/ - ps->Asic96Reg.u28.RD_RedChShadingOff = + ps->Asic96Reg.u28.RD_RedChShadingOff = ps->Asic96Reg.u29.RD_GreenChShadingOff = ps->Asic96Reg.RD_BlueChShadingOff = ps->Asic96Reg.RD_RedChDarkOff = @@ -1694,7 +1694,7 @@ static Bool dacP96001WaitForShading( pScanData ps ) /* AverageWideBank (pScanData) */ for( dwSum = 0, dw = 0; dw < 2700; dw++ ) dwSum += (ULong)ps->pPrescan16[dw]; - + dwSum /= 2700UL; if( dwSum <= 0x80 ) { @@ -1860,7 +1860,7 @@ static void dacP98003AdjustRGBGain( pScanData ps ) /* PauseColorMotorRunStates () */ memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); - ps->a_nbNewAdrPointer[1] = 0x77; + ps->a_nbNewAdrPointer[1] = 0x77; IOPutOnAllRegisters( ps ); @@ -2221,7 +2221,7 @@ static void dacP98003AdjustShadingWaveform( pScanData ps ) } else pwsum->Red = 0; - if((short)(pwsum->Green -= ps->Shade.DarkOffset.Colors.Green) > 0) { + if((short)(pwsum->Green -= ps->Shade.DarkOffset.Colors.Green) > 0) { pwsum->Green = pwsum->Green * pRGB->Green / 100U; if( pwsum->Green > 0xfff ) pwsum->Green = 0xfff; @@ -2312,7 +2312,7 @@ static void dacP98003AdjustDark( pScanData ps ) /* PauseColorMotorRunStates () */ memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); - ps->a_nbNewAdrPointer[1] = 0x77; + ps->a_nbNewAdrPointer[1] = 0x77; IOPutOnAllRegisters( ps ); _DODELAY( 70 ); @@ -2374,7 +2374,7 @@ static Bool dacP98003WaitForShading( pScanData ps ) DBG( DBG_LOW, "dacP98003WaitForShading()\n" ); - /* + /* * before getting the shading data, (re)init the ASIC */ ps->ReInitAsic( ps, _TRUE ); @@ -2501,7 +2501,7 @@ _LOC void DacP98FillShadingDarkToShadingRegister( pScanData ps ) pValue = (pUChar)&ps->AsicReg.RD_RedDarkOff; for (bReg = ps->RegRedChDarkOffsetLow; bReg <= ps->RegBlueChDarkOffsetHigh; bReg++, pValue++) { - + IODataToRegister( ps, bReg, *pValue ); } } diff --git a/backend/plustek-pp_detect.c b/backend/plustek-pp_detect.c index 51fad69..b7527c3 100644 --- a/backend/plustek-pp_detect.c +++ b/backend/plustek-pp_detect.c @@ -161,8 +161,8 @@ static int detectScannerConnection( pScanData ps ) _ASSERT( ps->ReadWriteTest ); /* - * here we try to detect the operation speed of our parallel - * port if we have tested all the stuff and had no success, + * here we try to detect the operation speed of our parallel + * port if we have tested all the stuff and had no success, * retval will contain the error-code */ for( ps->IO.delay = 0; ps->IO.delay < 5; ps->IO.delay++ ) { @@ -211,11 +211,11 @@ static int detectSetupBuffers( pScanData ps ) */ if ( 0 == ps->TotalBufferRequire ) { -#ifdef __KERNEL__ +#ifdef __KERNEL__ _PRINT( #else DBG( DBG_HIGH, -#endif +#endif "pt_drv: asic 0x%x probably not supported\n", ps->sCaps.AsicID); return _E_ALLOC; /* Out of memory */ @@ -419,7 +419,7 @@ _LOC int DetectScanner( pScanData ps, int mode ) DBG( DBG_HIGH, "Starting Scanner-Autodetection\n" ); - /* try to find a 48xx Scanner + /* try to find a 48xx Scanner * (or even a scanner based on the 96001/3) ASIC */ result = detectP48xx( ps ); diff --git a/backend/plustek-pp_image.c b/backend/plustek-pp_image.c index c1ef743..c7d2db2 100644 --- a/backend/plustek-pp_image.c +++ b/backend/plustek-pp_image.c @@ -107,7 +107,7 @@ static ThreshDef xferSpeed[4] = { /** return the correct DPI-value * The ASIC 96001/3 models are limited to an optical resolution of 300 Dpi - * so it´s necessary to scale in X and Y direction (see scale.c)! + * so it´s necessary to scale in X and Y direction (see scale.c)! */ static UShort imageGetPhysDPI( pScanData ps, pImgDef pImgInf, Bool fDpiX ) { @@ -287,7 +287,7 @@ static void fnP96GrayDirect( pScanData ps, pVoid pBuf, pVoid pImg, ULong bl ) src = (pUChar)pImg; dest = (pUChar)pBuf; - + for (; bl; bl--, src++, dest++ ) *dest = ps->pbMapRed [*src]; } @@ -315,7 +315,7 @@ static void fnHalftoneDirect0( pScanData ps, pVoid pb, pVoid pImg, ULong bL ) src = (pUChar)pImg; dest = (pUChar)pb; - + pDither = &ps->a_bDitherPattern[ps->dwDitherIndex]; for( ; bL; bL--, dest++, pDither -= 8 ) { @@ -365,10 +365,10 @@ static void fnP98ColorDirect( pScanData ps, pVoid pb, pVoid pImg, ULong bL ) { pUChar src; pRGBByteDef dest; - + src = (pUChar)pImg; dest = (pRGBByteDef)pb; - + for ( bL = ps->DataInf.dwAsicPixelsPerPlane; bL; bL--, src++, dest++) { dest->Red = *src; @@ -384,7 +384,7 @@ static void fnP96ColorDirect( pScanData ps, pVoid pb, pVoid pImg, ULong bL ) src = (pUChar)pImg; dest = (pRGBByteDef)pb; - + for ( bL = ps->DataInf.dwAsicPixelsPerPlane; bL; bL--, dest++, src++) { dest->Red =ps->pbMapRed[*src]; @@ -400,13 +400,13 @@ static void fnP98Color48( pScanData ps, pVoid pb, pVoid pImg, ULong bL ) { pUShort src; pRGBUShortDef dest; - + register ULong i; _VAR_NOT_USED( bL ); src = (pUShort)pImg; dest = (pRGBUShortDef)pb; - + for ( i = ps->DataInf.dwAsicPixelsPerPlane; i; i--, src++, dest++) { dest->Red = *src; @@ -960,7 +960,7 @@ static Bool imageP96ReadOneImageLine( pScanData ps ) if ((bData - ps->bCurrentLineCount) < _SCANSTATE_BYTES) continue; } - + ps->bMoveDataOutFlag = _DataAfterRefreshState; } #endif @@ -977,7 +977,7 @@ static Bool imageP96ReadOneImageLine( pScanData ps ) (ps->RedDataReady | ps->GreenDataReady | _BLUE_DATA_READY)); ps->pCurrentColorRunTable++); -#ifdef DEBUG +#ifdef DEBUG if( ps->pCurrentColorRunTable > (ps->pColorRunTable+ps->BufferForColorRunTable)) DBG( DBG_LOW, "WARNING: pCurrentColorRunTab>pColorRunTable\n"); @@ -1216,7 +1216,7 @@ static Bool imageP98003DataIsReady( pScanData ps ) IORegisterToScanner( ps, ps->RegRefreshScanState ); /* direct is done here without copying...*/ - if( fnDataDirect != ps->Scan.DataProcess ) { + if( fnDataDirect != ps->Scan.DataProcess ) { (*ps->Scan.DataProcess)(ps, (pVoid)(ps->Scan.bp.pMonoBuf ), (pVoid)(ps->Scan.BufPut.red.bp), ps->DataInf.dwAppPhyBytesPerLine); @@ -1290,7 +1290,7 @@ static Bool imageP98003ReadOneImageLine( pScanData ps ) } while( !MiscCheckTimer( &timer )); -#ifdef __KERNEL__ +#ifdef __KERNEL__ _PRINT( #else DBG( DBG_HIGH, @@ -1358,7 +1358,7 @@ static void imageP98003SetupScanStateVariables( pScanData ps, ULong index ) if( var.dwValue && ps->DataInf.dwAsicBytesPerPlane > var.dwValue ) { if((var.dwValue << 1) > ps->DataInf.dwAsicBytesPerPlane) - ps->Scan.dwInterval <<= 1; + ps->Scan.dwInterval <<= 1; else if((var.dwValue << 2) > ps->DataInf.dwAsicBytesPerPlane) ps->Scan.dwInterval <<= 2; @@ -1376,7 +1376,7 @@ static void imageP98003SetupScanStateVariables( pScanData ps, ULong index ) if( ps->DataInf.wPhyDataType >= COLOR_TRUE24 ) { - if( ps->DataInf.xyPhyDpi.y > 75U ) { + if( ps->DataInf.xyPhyDpi.y > 75U ) { if( ps->Device.f0_8_16 ) { ps->Scan.gd_gk.wGreenDiscard = ps->DataInf.xyPhyDpi.y / 75U; } else { @@ -1535,7 +1535,7 @@ static int imageP98003SetupScanSettings( pScanData ps, pScanInfo pInf ) ps->Scan.p48BitBuf.pb = ps->Bufs.b1.pReadBuf; } - } + } if( ps->Scan.p48BitBuf.pb ){ ps->Scan.DataRead = fnReadToDriver; diff --git a/backend/plustek-pp_io.c b/backend/plustek-pp_io.c index ba68599..d6e99b9 100644 --- a/backend/plustek-pp_io.c +++ b/backend/plustek-pp_io.c @@ -110,7 +110,7 @@ static Byte ioDataFromSPPFast( pScanData ps ) /* read low nibble */ tmp = _INB_STATUS( ps ); - + /* combine with low nibble */ bData |= (tmp >> 4); @@ -141,7 +141,7 @@ static Byte ioDataFromSPPMiddle( pScanData ps ) /* read low nibble */ _INB_STATUS( ps ); tmp = _INB_STATUS( ps ); - + /* combine with low nibble */ bData |= (tmp >> 4); @@ -174,7 +174,7 @@ static UChar ioDataFromSPPSlow( pScanData ps ) _INB_STATUS( ps ); _INB_STATUS( ps ); tmp = _INB_STATUS( ps ); - + /* combine with low nibble */ bData |= (tmp >> 4); @@ -209,7 +209,7 @@ static UChar ioDataFromSPPSlowest( pScanData ps ) _INB_STATUS( ps ); _INB_STATUS( ps ); tmp = _INB_STATUS( ps ); - + /* combine with low nibble */ bData |= (tmp >> 4); @@ -309,9 +309,9 @@ static Bool fnBiDirRead( pScanData ps, pUChar pBuffer, ULong ulSize ) case 0: for( ; ulSize; ulSize--, pBuffer++ ) { - _OUTB_CTRL( ps, start ); + _OUTB_CTRL( ps, start ); *pBuffer = _INB_DATA( ps ); - _OUTB_CTRL( ps, end ); + _OUTB_CTRL( ps, end ); } break; @@ -327,7 +327,7 @@ static Bool fnBiDirRead( pScanData ps, pUChar pBuffer, ULong ulSize ) _DO_UDELAY( 1 ); } break; - + default: _DO_UDELAY( 2 ); for(; ulSize; ulSize--, pBuffer++ ) { @@ -466,7 +466,7 @@ static Bool ioP98OpenScanPath( pScanData ps ) #endif } else { ioP98003EstablishScannerConnection( ps, dw ); - } + } _INB_STATUS( ps ); tmp = _INB_STATUS( ps ); @@ -524,7 +524,7 @@ static void ioCloseScanPath( pScanData ps ) * (ASIC 9800x only) */ static int ioP98ReadWriteTest( pScanData ps ) -{ +{ UChar tmp; ULong ul; pUChar buffer; @@ -539,10 +539,10 @@ static int ioP98ReadWriteTest( pScanData ps ) /* prepare content */ for( ul = 0; ul < _MEMTEST_SIZE; ul++ ) - buffer[ul] = (UChar)ul; + buffer[ul] = (UChar)ul; ps->OpenScanPath(ps); - + /* avoid switching to Lamp0, when previously scanned in transp./neg mode */ tmp = ps->bLastLampStatus + _SCAN_BYTEMODE; IODataToRegister( ps, ps->RegScanControl, tmp ); @@ -595,7 +595,7 @@ static void ioSPPWrite( pScanData ps, pUChar pBuffer, ULong size ) DBG( DBG_IO , "Moving %u bytes to scanner, IODELAY = %u...\n", size, ps->IO.delay ); switch( ps->IO.delay ) { - + case 0: for (; size; size--, pBuffer++) { _OUTB_DATA( ps, *pBuffer ); @@ -603,7 +603,7 @@ static void ioSPPWrite( pScanData ps, pUChar pBuffer, ULong size ) _OUTB_CTRL( ps, _CTRL_END_DATAWRITE ); } break; - + case 1: case 2: for (; size; size--, pBuffer++) { @@ -647,7 +647,7 @@ static void ioEnterReadMode( pScanData ps ) ps->IO.bOldControlValue = _INB_CTRL( ps ); /* ask ASIC to enter read mode */ - IORegisterToScanner( ps, ps->RegReadDataMode ); + IORegisterToScanner( ps, ps->RegReadDataMode ); } /************************ exported functions *********************************/ @@ -750,7 +750,7 @@ _LOC void IODataToScanner( pScanData ps, Byte bValue ) /* notify asic there is data */ _OUTB_CTRL( ps, _CTRL_START_DATAWRITE ); _DO_UDELAY( deltime ); - + /* end write cycle */ _OUTB_CTRL( ps, _CTRL_END_DATAWRITE ); _DO_UDELAY( deltime-1 ); @@ -767,7 +767,7 @@ _LOC void IODataToRegister( pScanData ps, Byte bReg, Byte bData ) #endif /* specify register */ - IORegisterToScanner( ps, bReg ); + IORegisterToScanner( ps, bReg ); /* then write the content */ IODataToScanner( ps, bData ); diff --git a/backend/plustek-pp_map.c b/backend/plustek-pp_map.c index 8afeb32..00b52a3 100644 --- a/backend/plustek-pp_map.c +++ b/backend/plustek-pp_map.c @@ -164,23 +164,23 @@ static void mapInvertDitherMap( pScanData ps ) static void mapBuildLinearMap( pScanData ps ) { ULong i; - + DBG( DBG_LOW, "mapBuildLinearMap()\n" ); if( _IS_ASIC98(ps->sCaps.AsicID)) { for( i = 0; i < 4096; i++ ) { - ps->a_bMapTable[i] = (UChar)(i >> 4); - ps->a_bMapTable[4096+i] = (UChar)(i >> 4); - ps->a_bMapTable[8192+i] = (UChar)(i >> 4); + ps->a_bMapTable[i] = (UChar)(i >> 4); + ps->a_bMapTable[4096+i] = (UChar)(i >> 4); + ps->a_bMapTable[8192+i] = (UChar)(i >> 4); } } else { for( i = 0; i < 256; i++ ) { - ps->a_bMapTable[i] = (UChar)(i & 0xff); - ps->a_bMapTable[256+i] = (UChar)(i & 0xff); - ps->a_bMapTable[512+i] = (UChar)(i & 0xff); + ps->a_bMapTable[i] = (UChar)(i & 0xff); + ps->a_bMapTable[256+i] = (UChar)(i & 0xff); + ps->a_bMapTable[512+i] = (UChar)(i & 0xff); } } } @@ -221,7 +221,7 @@ _LOC void MapAdjust( pScanData ps, int which ) long b, c, tmp; DBG( DBG_LOW, "MapAdjust(%u)\n", which ); - + if( _IS_ASIC98(ps->sCaps.AsicID)) { tabLen = 4096; } else { @@ -257,7 +257,7 @@ _LOC void MapAdjust( pScanData ps, int which ) if( tmp > 255 ) tmp = 255; ps->a_bMapTable[tabLen+i] = (UChar)tmp; } - + if((_MAP_MASTER == which) || (_MAP_BLUE == which)) { tmp = ((((long)ps->a_bMapTable[tabLen*2+i] * 100) + b) * c) / 10000; if( tmp < 0 ) tmp = 0; @@ -268,33 +268,33 @@ _LOC void MapAdjust( pScanData ps, int which ) if( ps->DataInf.dwScanFlag & SCANDEF_Negative ) { DBG( DBG_LOW, "inverting...\n" ); - + if((_MAP_MASTER == which) || (_MAP_RED == which)) { - + DBG( DBG_LOW, "inverting RED map\n" ); - + pdw = (pULong)ps->a_bMapTable; - + for( dw = tabLen / 4; dw; dw--, pdw++ ) *pdw = ~(*pdw); } - + if((_MAP_MASTER == which) || (_MAP_GREEN == which)) { - + DBG( DBG_LOW, "inverting GREEN map\n" ); - + pdw = (pULong)&ps->a_bMapTable[tabLen]; - + for( dw = tabLen / 4; dw; dw--, pdw++ ) *pdw = ~(*pdw); } - + if((_MAP_MASTER == which) || (_MAP_BLUE == which)) { - + DBG( DBG_LOW, "inverting BLUE map\n" ); - + pdw = (pULong)&ps->a_bMapTable[tabLen*2]; - + for( dw = tabLen / 4; dw; dw--, pdw++ ) *pdw = ~(*pdw); } diff --git a/backend/plustek-pp_misc.c b/backend/plustek-pp_misc.c index d0c1ce7..a0ce200 100644 --- a/backend/plustek-pp_misc.c +++ b/backend/plustek-pp_misc.c @@ -280,7 +280,7 @@ static int miscSetFastMode( pScanData ps ) ps->IO.lastPortMode = a; /* save it for restoring later */ /* set to Fast Centronics/bi-directional/PS2 */ - a = (a & 0x1F) | 0x20; + a = (a & 0x1F) | 0x20; _OUTB_ECTL(ps,a); /* write it back */ _DO_UDELAY(1); @@ -335,7 +335,7 @@ static int miscSetFastMode( pScanData ps ) DBG(DBG_LOW, "Port is set to PS2 bidirectional mode.\n"); ps->IO.portMode = _PORT_BIDI; return _OK; - + } else { DBG(DBG_LOW, "Port could not be set to PS2 mode. " "Using SPP mode.\n"); @@ -458,7 +458,7 @@ _LOC pScanData MiscAllocAndInitStruct( void ) } DBG( DBG_HIGH, "ScanData = 0x%08lx\n", (unsigned long)ps ); - return ps; + return ps; } /** re-initialize the memory for the scanner structure @@ -610,7 +610,7 @@ _LOC void MiscStartTimer( TimerDef *timer , unsigned long us) #ifdef __KERNEL__ _GET_TIME( &start_time ); #else - gettimeofday(&start_time, NULL); + gettimeofday(&start_time, NULL); #endif *timer = (TimerDef)start_time.tv_sec * 1000000 + (TimerDef)start_time.tv_usec + us; @@ -635,7 +635,7 @@ _LOC int MiscCheckTimer( TimerDef *timer ) if ((TimerDef)current_time.tv_sec * 1000000 + (TimerDef)current_time.tv_usec > *timer) { return _E_TIMEOUT; } else { -#ifdef __KERNEL__ +#ifdef __KERNEL__ schedule(); /*#else sched_yield(); @@ -739,7 +739,7 @@ _LOC int MiscRegisterPort( pScanData ps, int portAddr ) return _OK; } -/** unregisters the port from driver +/** unregisters the port from driver */ _LOC void MiscUnregisterPort( pScanData ps ) { diff --git a/backend/plustek-pp_models.c b/backend/plustek-pp_models.c index 55029db..1d29686 100644 --- a/backend/plustek-pp_models.c +++ b/backend/plustek-pp_models.c @@ -115,7 +115,7 @@ static void modelInitPageSettings( pScanData ps ) ps->sCaps.wMaxExtentY = ps->LensInf.rExtentY.wDef = ps->LensInf.rExtentY.wMax = - ps->LensInf.rExtentY.wPhyMax = _MEASURE_BASE * 11.6934; + ps->LensInf.rExtentY.wPhyMax = _MEASURE_BASE * 11.6934; break; case _SCANSIZE_A3: @@ -124,7 +124,7 @@ static void modelInitPageSettings( pScanData ps ) ps->sCaps.wMaxExtentY = ps->LensInf.rExtentY.wMax = ps->LensInf.rExtentY.wDef = - ps->LensInf.rExtentY.wPhyMax = _MEASURE_BASE * 17; + ps->LensInf.rExtentY.wPhyMax = _MEASURE_BASE * 17; /* _MEASURE_BASE * 11.69 */ ps->sCaps.wMaxExtentX = @@ -139,7 +139,7 @@ static void modelInitPageSettings( pScanData ps ) ps->sCaps.wMaxExtentY = ps->LensInf.rExtentY.wDef = ps->LensInf.rExtentY.wMax = - ps->LensInf.rExtentY.wPhyMax = _MEASURE_BASE * 11; + ps->LensInf.rExtentY.wPhyMax = _MEASURE_BASE * 11; break; case _SCANSIZE_LEGAL: @@ -148,7 +148,7 @@ static void modelInitPageSettings( pScanData ps ) ps->sCaps.wMaxExtentY = ps->LensInf.rExtentY.wDef = ps->LensInf.rExtentY.wMax = - ps->LensInf.rExtentY.wPhyMax = _MEASURE_BASE * 14; + ps->LensInf.rExtentY.wPhyMax = _MEASURE_BASE * 14; } /* diff --git a/backend/plustek-pp_motor.c b/backend/plustek-pp_motor.c index f377b7e..7f4b1ac 100644 --- a/backend/plustek-pp_motor.c +++ b/backend/plustek-pp_motor.c @@ -738,7 +738,7 @@ static void motorP98PositionYProc( pScanData ps, ULong dwStates ) } /*............................................................................. - * checks if the sensor is in it´s home position and moves it back if necessary + * checks if the sensor is in it´s home position and moves it back if necessary */ static int motorP98CheckSensorInHome( pScanData ps ) { @@ -1248,7 +1248,7 @@ static void motorP96WaitForPositionY( pScanData ps ) MiscStartTimer( &timer, _SECOND / 4); while (!MiscCheckTimer( &timer )); - memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); + memset( ps->a_nbNewAdrPointer, 0, _SCANSTATE_BYTES ); ps->Asic96Reg.RD_MotorControl = ps->IgnorePF|ps->MotorOn|_MotorDirForward; ps->Scan.fMotorBackward = _FALSE; @@ -1875,7 +1875,7 @@ static void motorP96SetupRunTable( pScanData ps ) if ((siSum -= (Short)ps->DataInf.xyPhyDpi.y) <= 0) { siSum += (Short)wP96BaseDpi; - if((ps->sCaps.Model == MODEL_OP_12000P)|| + if((ps->sCaps.Model == MODEL_OP_12000P)|| (ps->sCaps.Model == MODEL_OP_A3I)) { *p.pb |= _COLORRUNTABLE_GREEN; } else { @@ -2083,7 +2083,7 @@ static void motorP96WaitBack( pScanData ps ) } else { dw = _P96_FORWARDMOVES; } - + memset( a_bScanStateTable, 1, dw ); memset(&a_bScanStateTable[dw], 0xff, 250 - dw ); @@ -2671,7 +2671,7 @@ static void motorP98003WaitForPositionY( pScanData ps ) while(( IOGetExtendedStatus( ps ) & _STILL_FREE_RUNNING) && !MiscCheckTimer(&timer)); - IODataToRegister( ps, ps->RegModeControl, _ModeScan ); + IODataToRegister( ps, ps->RegModeControl, _ModeScan ); } else { MotorP98003PositionYProc( ps, dwBeginY ); IORegisterToScanner( ps, ps->RegRefreshScanState ); diff --git a/backend/plustek-pp_p12.c b/backend/plustek-pp_p12.c index 6f46e58..2dc4e45 100644 --- a/backend/plustek-pp_p12.c +++ b/backend/plustek-pp_p12.c @@ -121,7 +121,7 @@ static void p12InitiateComponentModel( pScanData ps ) case _SCANNER5Button: DBG( DBG_LOW, "Scanner has 5 Buttons\n" ); - ps->Device.dwModelOriginY = 64 + 20; + ps->Device.dwModelOriginY = 64 + 20; p12ButtonSetup( ps, 5 ); break; @@ -153,7 +153,7 @@ static void p12InitiateComponentModel( pScanData ps ) case _SCANNER2Button: DBG( DBG_LOW, "Scanner has 2 Buttons\n" ); DBG( DBG_LOW, "Seems we have a Genius Colorpage Vivid III V2\n" ); - ps->Device.dwModelOriginY = 64 - 33; + ps->Device.dwModelOriginY = 64 - 33; p12ButtonSetup( ps, 2 ); ps->sCaps.Model = MODEL_GEN_CPV2; break; @@ -232,7 +232,7 @@ static void p12SetupScanningCondition( pScanData ps ) ps->Scan.dwMaxReadFifo += (ps->DataInf.dwAsicBytesPerPlane / 2); - DBG( DBG_LOW, "MinReadFifo=%u, MaxReadFifo=%u\n", + DBG( DBG_LOW, "MinReadFifo=%u, MaxReadFifo=%u\n", ps->Scan.dwMinReadFifo, ps->Scan.dwMaxReadFifo ); /* ------- Set the max. read fifo to asic ------- */ @@ -260,7 +260,7 @@ static void p12SetupScanningCondition( pScanData ps ) channel = _GREEN_FULLSIZE << 16; ps->AsicReg.RD_BufFullSize = _SIZE_GREENFIFO; } - + lGreen = (ULong)(-lGreen * ps->DataInf.dwAsicBytesPerPlane); if( ps->DataInf.wPhyDataType > COLOR_TRUE24 ) @@ -434,7 +434,7 @@ static void p12ProgramCCD( pScanData ps) DBG( DBG_IO, " %u regs * %u (intermediate)\n", ps->Device.wNumCCDRegs, ps->Shade.bIntermediate ); - rp = ps->Device.pCCDRegisters + + rp = ps->Device.pCCDRegisters + (ULong)ps->Device.wNumCCDRegs * ps->Shade.bIntermediate; for( w = ps->Device.wNumCCDRegs; w--; rp++ ) { diff --git a/backend/plustek-pp_p12ccd.c b/backend/plustek-pp_p12ccd.c index 178cb2e..1b64b46 100644 --- a/backend/plustek-pp_p12ccd.c +++ b/backend/plustek-pp_p12ccd.c @@ -1105,7 +1105,7 @@ _LOC void P12InitCCDandDAC( pScanData ps, Bool shading ) else ps->Shade.bUniGain = 7; - ps->Shade.wDarkLevels = 10; + ps->Shade.wDarkLevels = 10; if( ps->Shade.bIntermediate & _ScanMode_Mono ) { SamsungDAC8531[0].bParam = 0x57; diff --git a/backend/plustek-pp_p48xx.c b/backend/plustek-pp_p48xx.c index 6175a34..749005b 100644 --- a/backend/plustek-pp_p48xx.c +++ b/backend/plustek-pp_p48xx.c @@ -724,7 +724,7 @@ static void p48xxPutToIdleMode( pScanData ps ) /*............................................................................. * for P96001/3 ASIC * do all the preliminary stuff here (calibrate the scanner and move the - * sensor to it´s start position, also setup the driver for the + * sensor to it´s start position, also setup the driver for the * current run) */ static int p48xxCalibration( pScanData ps ) diff --git a/backend/plustek-pp_p9636.c b/backend/plustek-pp_p9636.c index 0c3fcfd..62da325 100644 --- a/backend/plustek-pp_p9636.c +++ b/backend/plustek-pp_p9636.c @@ -244,7 +244,7 @@ static void p9636Init98001( pScanData ps, Bool shading ) ps->Device.bCCDID = bData; ps->Device.bCCDID &= _P98_CCD_TYPE_ID; DBG( DBG_HIGH, "bData = 0x%04X, PCB-ID = 0x%02X\n", bData, (bData >> 4)); - + /* encode the CCD-id into the flag parameter */ dwID = (ULong)ps->Device.bCCDID; dwID = dwID << 16; @@ -852,7 +852,7 @@ static void p9636PutToIdleMode( pScanData ps ) /*............................................................................. * do all the preliminary stuff here (calibrate the scanner and move the - * sensor to it´s start position, also setup the driver for the + * sensor to it´s start position, also setup the driver for the * current run) */ static int p9636Calibration( pScanData ps ) diff --git a/backend/plustek-pp_procfs.c b/backend/plustek-pp_procfs.c index ed242a8..0cbb999 100644 --- a/backend/plustek-pp_procfs.c +++ b/backend/plustek-pp_procfs.c @@ -62,7 +62,7 @@ #include "plustek-pp_scan.h" /* toggled by your kernel configuration */ -#ifdef CONFIG_PROC_FS +#ifdef CONFIG_PROC_FS /****************************** static vars **********************************/ @@ -197,7 +197,7 @@ static int procfsInfoReadProc( char *buf, char **start, off_t offset, MiscGetModelName(ps->sCaps.Model)); len += sprintf( buf+len, "Portaddress : 0x%X\n", ps->IO.portBase ); len += sprintf( buf+len, "Portmode : %s (%s I/O, %s)\n", - procfsGetMode(ps->IO.portMode), + procfsGetMode(ps->IO.portMode), (ps->IO.slowIO == _TRUE?"delayed":"fast"), (ps->IO.forceMode == 0?"autodetect":"forced")); len += sprintf( buf+len, "Buttons : %u\n", ps->Device.buttons); @@ -278,7 +278,7 @@ static struct proc_dir_entry *new_entry( const char *name, mode_t mode, /* position pointer of name to end of the structure*/ ent->name = ((char *) ent) + sizeof(*ent); strcpy((char *)ent->name, name ); - + ent->namelen = strlen(name); ent->mode = mode; @@ -310,7 +310,7 @@ static inline void destroy_proc_entry( struct proc_dir_entry *root, kfree(*d); #else DBG(DBG_HIGH, "pt_drv: proc del '%s' root='%s'\n", (*d)->name, root->name); - + remove_proc_entry((*d)->name, root ); #endif @@ -407,7 +407,7 @@ void ProcFsRegisterDevice( pScanData ps ) memset( &ps->procDir, 0, sizeof(ProcDirDef)); sprintf( str, "device%u", ps->devno ); - + ps->procDir.entry = new_entry( str, S_IFDIR, base ); if( NULL == ps->procDir.entry ) goto error_exit; diff --git a/backend/plustek-pp_procs.h b/backend/plustek-pp_procs.h index aff67c8..cc84d13 100644 --- a/backend/plustek-pp_procs.h +++ b/backend/plustek-pp_procs.h @@ -12,7 +12,7 @@ * 0.32 - no changes * 0.33 - no changes * 0.34 - added this history - * 0.35 - added Kevins´ changes to MiscRestorePort + * 0.35 - added Kevins´ changes to MiscRestorePort * changed prototype of MiscReinitStruct * added prototype for function PtDrvLegalRequested() * 0.36 - added prototype for function MiscLongRand() diff --git a/backend/plustek-pp_ptdrv.c b/backend/plustek-pp_ptdrv.c index 9409e56..cb0eeb3 100644 --- a/backend/plustek-pp_ptdrv.c +++ b/backend/plustek-pp_ptdrv.c @@ -243,8 +243,8 @@ static CLOSETYPE pt_drv_close( struct inode *, struct file *); #else static int pt_drv_ioctl( struct inode *, struct file *, UInt, unsigned long ); #endif - - + + /* * the driver interface */ @@ -300,7 +300,7 @@ static pScanData get_pt_from_inode(struct inode *ip) /* * unit out of range */ - if (minor >= _MAX_PTDEVS ) + if (minor >= _MAX_PTDEVS ) return NULL; return( PtDrvDevices[minor] ); @@ -442,7 +442,7 @@ static void ptDrvSwitchLampOn( pScanData ps ) ps->bLastLampStatus = _SCAN_NORMALLAMP_ON; } else { - + ps->AsicReg.RD_ScanControl |= ps->bLampOn; ps->bLastLampStatus = ps->bLampOn; } @@ -484,12 +484,12 @@ static void ptdrvLampWarmup( pScanData ps ) MiscStartTimer( &timer, _SECOND * ps->warmup ); while( !MiscCheckTimer( &timer )) { - + /* on break, we setup the initial timer again... */ if( _FALSE == ps->fScanningStatus ) { MiscStartTimer( &toTimer[ps->devno], (_SECOND * ps->warmup)); - return; - } + return; + } }; } @@ -517,7 +517,7 @@ static void ptdrvLampTimerIrq( int sig_num ) pScanData ps; DBG( DBG_HIGH, "!! IRQ !! Lamp-Timer stopped.\n" ); - + #ifdef __KERNEL__ ps = (pScanData)ptr; #else @@ -539,10 +539,10 @@ static void ptdrvLampTimerIrq( int sig_num ) } else { ps->AsicReg.RD_ScanControl &= ~_SCAN_LAMP_ON; } - + /* force warmup... */ ps->bLastLampStatus = 0xFF; - + /* * claim parallel port if necessary... * if the port is busy, restart the timer @@ -847,7 +847,7 @@ static int ptdrvInit( int devno ) if( _OK == retval ) { -#ifdef __KERNEL__ +#ifdef __KERNEL__ _PRINT( "pt_drv%u: %s found on port 0x%04x\n", devno, MiscGetModelName(ps->sCaps.Model), ps->IO.pbSppDataPort ); #else @@ -1097,19 +1097,19 @@ static int ptdrvIoctl( pScanData ps, UInt cmd, pVoid arg ) if( ps->devno < _MAX_PTDEVS ) { if( adj.warmup >= 0 ) { - warmup[ps->devno] = adj.warmup; - ps->warmup = adj.warmup; - } + warmup[ps->devno] = adj.warmup; + ps->warmup = adj.warmup; + } if( adj.lampOff >= 0 ) { lampoff[ps->devno] = adj.lampOff; ps->lampoff = adj.lampOff; - } + } if( adj.lampOffOnEnd >= 0 ) { lOffonEnd[ps->devno] = adj.lampOffOnEnd; ps->lOffonEnd = adj.lampOffOnEnd; - } + } } } break; @@ -1131,13 +1131,13 @@ static int ptdrvIoctl( pScanData ps, UInt cmd, pVoid arg ) x_len = 256; if( _IS_ASIC98(ps->sCaps.AsicID)) x_len = 4096; - + /* check for 0 pointer and len */ if((NULL == map.map) || (x_len != map.len)) { DBG( DBG_LOW, "map pointer == 0, or map len invalid!!\n" ); return _E_INVALID; - } - + } + if( _MAP_MASTER == map.map_id ) { for( i = 0; i < 3; i++ ) { @@ -1159,7 +1159,7 @@ static int ptdrvIoctl( pScanData ps, UInt cmd, pVoid arg ) return _E_FAULT; } } - + /* here we adjust the maps according to * the brightness and contrast settings */ @@ -1254,7 +1254,7 @@ static int ptdrvIoctl( pScanData ps, UInt cmd, pVoid arg ) retval = _E_SEQUENCE; ps->DataInf.dwVxdFlag &= ~_VF_ENVIRONMENT_READY; - + } else { DBG( DBG_LOW, "CANCEL Mode set\n" ); } @@ -1320,7 +1320,7 @@ static int ptdrvRead( pScanData ps, pUChar buffer, int count ) if( _FALSE == ps->fScanningStatus ) return _E_ABORT; - + /* * has the environment been set ? * this should prevent the driver from causing a seg-fault @@ -1374,7 +1374,7 @@ static int ptdrvRead( pScanData ps, pUChar buffer, int count ) (unsigned long)ps->Scan.bp.pMonoBuf, ps->DataInf.dwAppPhyBytesPerLine, (unsigned long)scaleBuf ); - /* + /* * in case of a previous problem, move the sensor back home */ MotorToHomePosition( ps ); @@ -1382,8 +1382,8 @@ static int ptdrvRead( pScanData ps, pUChar buffer, int count ) if( _FALSE == ps->fScanningStatus ) { retval = _E_ABORT; goto ReadFinished; - } - + } + dwLinesRead = 0; /* @@ -1399,7 +1399,7 @@ static int ptdrvRead( pScanData ps, pUChar buffer, int count ) else ps->Scan.fRefreshState = _TRUE; - ptdrvLampWarmup( ps ); + ptdrvLampWarmup( ps ); if( _FALSE == ps->fScanningStatus ) { retval = _E_ABORT; @@ -1465,17 +1465,17 @@ static int ptdrvRead( pScanData ps, pUChar buffer, int count ) if( ps->Scan.dwLinesToRead > ps->DataInf.dwAppLinesPerArea ) ps->Scan.dwLinesToRead = ps->DataInf.dwAppLinesPerArea; - - ps->DataInf.dwAppLinesPerArea -= ps->Scan.dwLinesToRead; + + ps->DataInf.dwAppLinesPerArea -= ps->Scan.dwLinesToRead; if (ps->DataInf.dwScanFlag & SCANDEF_BmpStyle) buffer += ((ps->Scan.dwLinesToRead - 1) * ps->DataInf.dwAppBytesPerLine); - if (ps->DataInf.dwVxdFlag & _VF_DATATOUSERBUFFER) + if (ps->DataInf.dwVxdFlag & _VF_DATATOUSERBUFFER) ps->DataInf.pCurrentBuffer = ps->Scan.bp.pMonoBuf; - while(ps->fScanningStatus && ps->Scan.dwLinesToRead) { + while(ps->fScanningStatus && ps->Scan.dwLinesToRead) { _ASSERT(ps->ReadOneImageLine); if (!ps->ReadOneImageLine(ps)) { @@ -1549,8 +1549,8 @@ static int ptdrvRead( pScanData ps, pUChar buffer, int count ) ReadFinished: - if( _ASIC_IS_98003 == ps->sCaps.AsicID ) - ps->CloseScanPath( ps ); + if( _ASIC_IS_98003 == ps->sCaps.AsicID ) + ps->CloseScanPath( ps ); if( NULL != ps->Scan.bp.pMonoBuf ) _KFREE( ps->Scan.bp.pMonoBuf ); @@ -1638,7 +1638,7 @@ int init_module( void ) (S_IFCHR | S_IRUGO | S_IWUGO | S_IFCHR), &pt_drv_fops, NULL ); # else /* DEVFS_26_STYLE */ - devfs_mk_cdev(MKDEV(_PTDRV_MAJOR, devCount), + devfs_mk_cdev(MKDEV(_PTDRV_MAJOR, devCount), (S_IFCHR | S_IRUGO | S_IWUGO | S_IFCHR), "scanner/pt_drv%d", devCount); # endif @@ -1787,7 +1787,7 @@ static int pt_drv_open(struct inode *inode, struct file *file) return -EAGAIN; #else MOD_INC_USE_COUNT; -#endif +#endif ps->flags |= _PTDRV_OPEN; return _OK; @@ -1811,7 +1811,7 @@ static CLOSETYPE pt_drv_close(struct inode * inode, struct file * file) module_put(THIS_MODULE); #else MOD_DEC_USE_COUNT; -#endif +#endif CLOSERETURN(0); } else { @@ -1851,7 +1851,7 @@ static ssize_t pt_drv_read( struct file *file, */ if( _TRUE == deviceScanning ) { printk( KERN_INFO "pt_drv: device %u busy!!!\n", ps->devno ); - return(-EBUSY); + return(-EBUSY); } deviceScanning = _TRUE; @@ -1924,7 +1924,7 @@ static int PtDrvInit( const char *dev_name, UShort model_override ) port[0] = fd; mov[0] = model_override; - + result = ptdrvInit( 0 ); if( _OK == result ) { diff --git a/backend/plustek-pp_scale.c b/backend/plustek-pp_scale.c index 295a566..6879d66 100644 --- a/backend/plustek-pp_scale.c +++ b/backend/plustek-pp_scale.c @@ -101,7 +101,7 @@ _LOC void ScaleX( pScanData ps, pUChar inBuf, pUChar outBuf ) ddax = 0; x = 0; if( 0 == step ) { - + /* binary scaling */ memset( outBuf, 0, ps->DataInf.dwAppBytesPerLine ); @@ -134,7 +134,7 @@ _LOC void ScaleX( pScanData ps, pUChar inBuf, pUChar outBuf ) while( ddax < 0 ) { for( j = 0; j < (ULong)step; j++ ) { - + if((x+j) < ps->DataInf.dwAppBytesPerLine ) { outBuf[x+j] = inBuf[i+j]; } diff --git a/backend/plustek-pp_scan.h b/backend/plustek-pp_scan.h index 5a8f9d7..1764c79 100644 --- a/backend/plustek-pp_scan.h +++ b/backend/plustek-pp_scan.h @@ -73,11 +73,7 @@ # include # include # include -# ifdef HAVE_SYS_SIGNAL_H -# include -# else -# include -# endif +# include # include # ifdef HAVE_SYS_IO_H # include diff --git a/backend/plustek-pp_scandata.h b/backend/plustek-pp_scandata.h index 1ba2c05..1fb987c 100644 --- a/backend/plustek-pp_scandata.h +++ b/backend/plustek-pp_scandata.h @@ -162,10 +162,10 @@ typedef struct scandata */ ULong devno; int lampoff; - int warmup; + int warmup; int lOffonEnd; - /* + /* * CHECK for controlling the ECP-mode (not used now) */ #if 0 @@ -188,7 +188,7 @@ typedef struct scandata UShort TimePerLine; /* --> to Device */ /* - * scanner properties + * scanner properties */ RegData AsicReg; /* here we have the 98001/3 register set */ Reg96 Asic96Reg; /* here we hold the 96001/3 specific regs */ @@ -287,7 +287,7 @@ typedef struct scandata */ DataInfo DataInf; Bool fReshaded; - ULong dwDitherIndex; + ULong dwDitherIndex; Bool fDoFilter, fFilterFirstLine; ULong dwDivFilter; ULong dwMul; @@ -606,9 +606,9 @@ typedef struct scandata Byte RegFifoFullLength1; Byte RegFifoFullLength2; - Byte RegMotorTotalStep0; + Byte RegMotorTotalStep0; Byte RegMotorTotalStep1; - Byte RegMotorFreeRunCount0; + Byte RegMotorFreeRunCount0; Byte RegMotorFreeRunCount1; Byte RegScanControl1; Byte RegMotorFreeRunTrigger; diff --git a/backend/plustek-pp_sysdep.h b/backend/plustek-pp_sysdep.h index 9e064d2..73d00a4 100644 --- a/backend/plustek-pp_sysdep.h +++ b/backend/plustek-pp_sysdep.h @@ -1,5 +1,5 @@ /* @file plustek-pp_sysdep.h - * @brief a trial to centralize changes between the different + * @brief a trial to centralize changes between the different * kernel-versions some stuff is maybe not relevant, but anyway... * * Copyright (C) 2000-2013 Gerhard Jaeger diff --git a/backend/plustek-pp_tpa.c b/backend/plustek-pp_tpa.c index 021bad6..f2ca1f0 100644 --- a/backend/plustek-pp_tpa.c +++ b/backend/plustek-pp_tpa.c @@ -104,7 +104,7 @@ static void tpaP98SubNoise( pScanData ps, pULong pdwSum, pUShort pwShading, for (dwLines = _DEF_DARKEST_SKIP; dwLines--; pw += 5400UL) dwSum += (ULong) *pw; - + *pwShading = (UShort)((*pdwSum - dwSum) / ps->Shade.dwDiv); } if (ps->dwShadingPixels != 5400UL) { @@ -247,7 +247,7 @@ static void tpaP98GetNegativeTempRamData( pScanData ps ) pNegativeTempRam[dw] = (UShort)((pdwNegativeSumTemp[dw1] + pdwNegativeSumTemp[dw1+1] + pdwNegativeSumTemp[dw1+2] + - pdwNegativeSumTemp[dw1+3]) / 128); + pdwNegativeSumTemp[dw1+3]) / 128); /* shift 6 bits */ } @@ -259,7 +259,7 @@ static void tpaP98GetNegativeTempRamData( pScanData ps ) } /* do R shading average */ - for (dw = 0; dw < 240; dw++, dw1 += 4) { + for (dw = 0; dw < 240; dw++, dw1 += 4) { pNegativeTempRam2[dw] = (UShort)( (((pUShort)ps->pScanBuffer1)[dw1] + ((pUShort)ps->pScanBuffer1)[dw1+1] + diff --git a/backend/plustek-pp_wrapper.c b/backend/plustek-pp_wrapper.c index ba635ef..c41d340 100644 --- a/backend/plustek-pp_wrapper.c +++ b/backend/plustek-pp_wrapper.c @@ -56,7 +56,7 @@ /******************* wrapper functions for parport device ********************/ #ifndef _BACKEND_ENABLED - + static int PtDrvInit( char *dev_name, unsigned short model_override ) { _VAR_NOT_USED( dev_name ); @@ -124,7 +124,7 @@ static int ppDev_open( const char *dev_name, void *misc ) handle = PtDrvOpen(); else handle = open( dev_name, O_RDONLY ); - + if ( handle < 0 ) { DBG( _DBG_ERROR, "open: can't open %s as a device\n", dev_name ); return handle; @@ -134,7 +134,7 @@ static int ppDev_open( const char *dev_name, void *misc ) result = PtDrvIoctl( _PTDRV_OPEN_DEVICE, &version ); else result = ioctl( handle, _PTDRV_OPEN_DEVICE, &version ); - + if( result < 0 ) { if( -9019 == result ) { @@ -149,14 +149,14 @@ static int ppDev_open( const char *dev_name, void *misc ) result = PtDrvIoctl( _PTDRV_OPEN_DEVICE, &version ); else result = ioctl( handle, _PTDRV_OPEN_DEVICE, &version ); - + if( result < 0 ) { - + if( dev->adj.direct_io ) PtDrvClose(); else close( dev->fd ); - + DBG( _DBG_ERROR, "ioctl PT_DRV_OPEN_DEVICE failed(%d)\n", result ); @@ -294,23 +294,23 @@ static int ppDev_setMap( Plustek_Device *dev, SANE_Word *map, m.map_id = channel; m.map = (void *)map; - + DBG(_DBG_INFO,"Setting map[%u] at 0x%08lx\n", channel, (unsigned long)map); buf = (SANE_Byte*)malloc( m.len ); - + if( !buf ) return _E_ALLOC; - + for( i = 0; i < m.len; i++ ) { buf[i] = (SANE_Byte)map[i]; - + if( map[i] > 0xFF ) buf[i] = 0xFF; } - + m.map = buf; - + if( dev->adj.direct_io ) PtDrvIoctl( _PTDRV_SETMAP, &m ); else @@ -334,7 +334,7 @@ static int ppDev_stopScan( Plustek_Device *dev, short *mode ) retval = PtDrvIoctl( _PTDRV_STOP_SCAN, mode ); else retval = ioctl( dev->fd, _PTDRV_STOP_SCAN, mode ); - + /* ... and use it here */ if( 0 == tmp ) { if( dev->adj.direct_io ) diff --git a/backend/plustek-usb.c b/backend/plustek-usb.c index 6c9e67a..5c6fbeb 100644 --- a/backend/plustek-usb.c +++ b/backend/plustek-usb.c @@ -147,7 +147,7 @@ static SANE_Bool usb_normFileName( char *fname, char* buffer, u_long max_len ) } *dst = '\0'; - return SANE_TRUE; + return SANE_TRUE; } /** do some range checking and copy the adjustment values from the @@ -216,13 +216,13 @@ usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor ) /* adjust data origin */ - dev->usbDev.Caps.Positive.DataOrigin.x -= dev->adj.tpa.x; - dev->usbDev.Caps.Positive.DataOrigin.y -= dev->adj.tpa.y; + dev->usbDev.Caps.Positive.DataOrigin.x -= dev->adj.tpa.x; + dev->usbDev.Caps.Positive.DataOrigin.y -= dev->adj.tpa.y; - dev->usbDev.Caps.Negative.DataOrigin.x -= dev->adj.neg.x; - dev->usbDev.Caps.Negative.DataOrigin.y -= dev->adj.neg.y; + dev->usbDev.Caps.Negative.DataOrigin.x -= dev->adj.neg.x; + dev->usbDev.Caps.Negative.DataOrigin.y -= dev->adj.neg.y; - dev->usbDev.Caps.Normal.DataOrigin.x -= dev->adj.pos.x; + dev->usbDev.Caps.Normal.DataOrigin.x -= dev->adj.pos.x; dev->usbDev.Caps.Normal.DataOrigin.y -= dev->adj.pos.y; /** adjust shading position @@ -297,13 +297,13 @@ usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor ) sParam.Size.dwPixels = 0; /* create calibration-filename */ - sprintf( tmp_str2, "%s-%s", + sprintf( tmp_str2, "%s-%s", dev->sane.vendor, dev->usbDev.ModelStr ); if( !usb_normFileName( tmp_str2, tmp_str1, PATH_MAX )) { strcpy( tmp_str1, "plustek-default" ); } - + ptr = getenv ("HOME"); if( NULL == ptr ) { sprintf( tmp_str2, "/tmp/%s", tmp_str1 ); @@ -378,7 +378,7 @@ static int usb_CheckForPlustekDevice( int handle, Plustek_Device *dev ) /* now roam through the setting list... */ strncpy( tmp, dev->usbId, 13 ); tmp[13] = '\0'; - + sprintf( pcbStr, "-%u", pcbID ); strcat ( tmp, pcbStr ); @@ -392,7 +392,7 @@ static int usb_CheckForPlustekDevice( int handle, Plustek_Device *dev ) return handle; } } - + return -1; } @@ -416,7 +416,7 @@ static void usbDev_shutdown( Plustek_Device *dev ) DBG( _DBG_INFO, "Waiting for scanner-ready...\n" ); usb_IsScannerReady( dev ); - + if( 0 != dev->usbDev.bLampOffOnEnd ) { DBG( _DBG_INFO, "Switching lamp off...\n" ); @@ -439,7 +439,7 @@ static void usbDev_shutdown( Plustek_Device *dev ) static SANE_Bool usb_IsDeviceInList( char *usbIdStr ) { int i; - + for( i = 0; NULL != Settings[i].pIDString; i++ ) { if( 0 == strncmp( Settings[i].pIDString, usbIdStr, 13 )) @@ -516,7 +516,7 @@ usbGetList( DevList **devs ) il = SANE_TRUE; break; } - } + } if( il ) { DBG( _DBG_INFO2, "Already in list: 0x%04x-0x%04x\n", v, p ); continue; @@ -528,7 +528,7 @@ usbGetList( DevList **devs ) sanei_usb_find_devices( v, p, usb_attach ); if( getLast(*devs) != tmp ) { - + if( tmp == NULL ) tmp = *devs; else @@ -547,7 +547,7 @@ usbGetList( DevList **devs ) DBG( _DBG_INFO, "NONE.\n" ); for( tmp = *devs; tmp; tmp = tmp->next ) { - DBG( _DBG_INFO, "Device: >%s< - 0x%04xx0x%04x\n", + DBG( _DBG_INFO, "Device: >%s< - 0x%04xx0x%04x\n", tmp->dev_name, tmp->vendor_id, tmp->device_id ); } } @@ -568,7 +568,7 @@ static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) SANE_Status status; DevList *tmp; - DBG( _DBG_INFO, "usbDev_open(%s,%s) - %p\n", + DBG( _DBG_INFO, "usbDev_open(%s,%s) - %p\n", dev->name, dev->usbId, (void*)devs ); /* preset our internal usb device structure */ @@ -576,7 +576,7 @@ static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) /* devs is NULL, when called from sane_start */ if( devs ) { - + dn[0] = '\0'; if( !strcmp( dev->name, "auto" )) { @@ -618,7 +618,7 @@ static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) status = sanei_usb_open( dn, &handle ); if( SANE_STATUS_GOOD != status ) { - DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n", + DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n", strerror(errno), errno); sanei_access_unlock( dev->sane.name ); return -1; @@ -629,7 +629,7 @@ static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) */ free( dev->name ); dev->name = strdup(dn); - dev->sane.name = dev->name; + dev->sane.name = dev->name; } else { @@ -641,7 +641,7 @@ static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) status = sanei_usb_open( dev->name, &handle ); if( SANE_STATUS_GOOD != status ) { - DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n", + DBG( _DBG_ERROR, "sanei_usb_open failed: %s (%d)\n", strerror(errno), errno); sanei_access_unlock( dev->sane.name ); return -1; @@ -659,7 +659,7 @@ static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) DBG(_DBG_INFO,"Vendor ID=0x%04X, Product ID=0x%04X\n",vendor,product); if( dev->usbId[0] != '\0' ) { - + if( 0 != strcmp( dev->usbId, devStr )) { DBG( _DBG_ERROR, "Specified Vendor and Product ID " "doesn't match with the ones\n" @@ -735,9 +735,9 @@ static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) * product ID and up to 7 different devices... */ if( 0x07B3 == vendor ) { - + handle = usb_CheckForPlustekDevice( handle, dev ); - + if( was_empty ) dev->usbId[0] = '\0'; @@ -746,7 +746,7 @@ static int usbDev_open( Plustek_Device *dev, DevList *devs, int keep_lock ) sanei_access_unlock( dev->sane.name ); return handle; } - + } else { /* now roam through the setting list... */ @@ -853,9 +853,9 @@ static int usbDev_setMap( Plustek_Device *dev, SANE_Word *map, DBG(_DBG_INFO,"Setting map[%u] at 0x%08lx\n",channel,(unsigned long)map); _VAR_NOT_USED( dev ); - + if( channel == _MAP_MASTER ) { - + for( i = 0; i < length; i++ ) { a_bMap[i] = (SANE_Byte)map[i]; a_bMap[length +i] = (SANE_Byte)map[i]; @@ -939,7 +939,7 @@ usbDev_setScanEnv( Plustek_Device *dev, ScanInfo *si ) usb_GetImageInfo ( dev, &si->ImgDef, &scan->sParam.Size ); /* mask the flags */ - scan->dwFlag = si->ImgDef.dwFlag & + scan->dwFlag = si->ImgDef.dwFlag & (SCANFLAG_bgr | SCANFLAG_BottomUp | SCANFLAG_Calibration | SCANFLAG_DWORDBoundary | SCANFLAG_RightAlign | SCANFLAG_StillModule | SCANDEF_Adf | SCANDEF_ContinuousScan); @@ -1141,10 +1141,10 @@ usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf ) /* CIS devices need special handling... */ if( usb_IsCISDevice(dev)) { use_alt_cal = SANE_TRUE; - + } else { - if( dev->adj.altCalibrate ) + if( dev->adj.altCalibrate ) use_alt_cal = SANE_TRUE; } @@ -1350,16 +1350,16 @@ usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf ) if( !usb_ScanBegin( dev, (scan->dwFlag&SCANFLAG_StillModule) ? SANE_FALSE:SANE_TRUE)) { - + return _E_INTERNAL; } - + scan->dwFlag |= SCANFLAG_Scanning; if( scan->sParam.UserDpi.y != scan->sParam.PhyDpi.y ) { - + if( scan->sParam.UserDpi.y < scan->sParam.PhyDpi.y ) { - + scan->wSumY = scan->sParam.PhyDpi.y - scan->sParam.UserDpi.y; scan->dwFlag |= SCANFLAG_SampleY; DBG( _DBG_INFO, "SampleY Flag set (%u != %u, wSumY=%u)\n", @@ -1374,7 +1374,7 @@ usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf ) * as the SANE stuff already forked the driver to read data, I think * we should only read data by using a function... */ - scan->dwLinesUser = scan->sParam.Size.dwLines; + scan->dwLinesUser = scan->sParam.Size.dwLines; if( !scan->dwLinesUser ) return _E_BUFFER_TOO_SMALL; @@ -1388,10 +1388,10 @@ usbDev_Prepare( Plustek_Device *dev, SANE_Byte *buf ) scan->UserBuf.pb = buf; DBG(_DBG_INFO,"Reading the data now!\n" ); - DBG(_DBG_INFO,"PhyDpi.x = %u\n", scan->sParam.PhyDpi.x ); - DBG(_DBG_INFO,"PhyDpi.y = %u\n", scan->sParam.PhyDpi.y ); - DBG(_DBG_INFO,"UserDpi.x = %u\n", scan->sParam.UserDpi.x ); - DBG(_DBG_INFO,"UserDpi.y = %u\n", scan->sParam.UserDpi.y ); + DBG(_DBG_INFO,"PhyDpi.x = %u\n", scan->sParam.PhyDpi.x ); + DBG(_DBG_INFO,"PhyDpi.y = %u\n", scan->sParam.PhyDpi.y ); + DBG(_DBG_INFO,"UserDpi.x = %u\n", scan->sParam.UserDpi.x ); + DBG(_DBG_INFO,"UserDpi.y = %u\n", scan->sParam.UserDpi.y ); DBG(_DBG_INFO,"NumberOfScanBufs = %lu\n",scan->dwNumberOfScanBufs); DBG(_DBG_INFO,"LinesPerScanBufs = %lu\n",scan->dwLinesPerScanBufs); DBG(_DBG_INFO,"dwPhyBytes = %lu\n",scan->sParam.Size.dwPhyBytes); diff --git a/backend/plustek-usb.h b/backend/plustek-usb.h index 0f001c9..d989749 100644 --- a/backend/plustek-usb.h +++ b/backend/plustek-usb.h @@ -297,17 +297,14 @@ enum _BUTTONS _PORT2 = ((_MIO5 | _MIO6) << _BUTTON_SHIFT) }; -enum _PAPER_SENSE -{ - _PS_INP1 = (0x01 << _PSENSE_SHIFT), - _PS_INP2 = (0x02 << _PSENSE_SHIFT), - _PS_INP_MIO1 = (_MIO1 << (_PSENSE_SHIFT+2)), - _PS_INP_MIO2 = (_MIO2 << (_PSENSE_SHIFT+2)), - _PS_INP_MIO3 = (_MIO3 << (_PSENSE_SHIFT+2)), - _PS_INP_MIO4 = (_MIO4 << (_PSENSE_SHIFT+2)), - _PS_INP_MIO5 = (_MIO5 << (_PSENSE_SHIFT+2)), - _PS_INP_MIO6 = (_MIO6 << (_PSENSE_SHIFT+2)) -}; +#define _PS_INP1 (0x01 << _PSENSE_SHIFT) +#define _PS_INP2 (0x02 << _PSENSE_SHIFT) +#define _PS_INP_MIO1 (_MIO1 << (_PSENSE_SHIFT+2)) +#define _PS_INP_MIO2 (_MIO2 << (_PSENSE_SHIFT+2)) +#define _PS_INP_MIO3 (_MIO3 << (_PSENSE_SHIFT+2)) +#define _PS_INP_MIO4 (_MIO4 << (_PSENSE_SHIFT+2)) +#define _PS_INP_MIO5 (_MIO5 << (_PSENSE_SHIFT+2)) +#define _PS_INP_MIO6 (_MIO6 << (_PSENSE_SHIFT+2)) /** for encoding a misc I/O register as TPA */ #define _TPA(register) ((u_long)(register << _TPA_SHIFT)) @@ -381,7 +378,7 @@ enum SCANFLAG SCANFLAG_BottomUp = 0x00008000, SCANFLAG_DWORDBoundary = 0x00020000, SCANFLAG_RightAlign = 0x00040000, - SCANFLAG_StillModule = 0x00080000, + SCANFLAG_StillModule = 0x00080000, SCANFLAG_Pseudo48 = 0x08000000, SCANFLAG_SampleY = 0x04000000, SCANFLAG_Calibration = 0x10000000, @@ -469,10 +466,10 @@ typedef struct HWDefault u_char bReg_0x0f_Mono [10]; /* 0x0f to 0x18 */ u_char bReg_0x0f_Color [10]; /* 0x0f to 0x18 */ - /* color mode settings */ + /* color mode settings */ u_char bReg_0x26; u_char bReg_0x27; - + /* illumination mode reg 0x29 (runtime) */ u_char bReg_0x29; @@ -484,7 +481,7 @@ typedef struct HWDefault * format, you have to pay your attention when you * write this value to register. */ - u_short StepperPhaseCorrection; + u_short StepperPhaseCorrection; /* Sensor Pixel Configuration * Actually, the wActivePixelsStart will be set to 0 for shading purpose. @@ -656,11 +653,11 @@ typedef struct ScanDef AnyPtr Green; AnyPtr Red; AnyPtr Blue; - + long lBufAdjust; /**< bytes to adjust buffer pointer */ /* after a image line processed */ u_short wSumY; /**< for line sampling */ - + u_char bLineDistance; /**< Color offset in specific dpi y */ int fGrayFromColor; /**< channel to use for gray mode */ diff --git a/backend/plustek-usbcal.c b/backend/plustek-usbcal.c index f2e7608..3b9d93a 100644 --- a/backend/plustek-usbcal.c +++ b/backend/plustek-usbcal.c @@ -21,7 +21,7 @@ * or can test. * * Therefore, I'm splitting out a few calibration functions I need - * to modify for the CanoScan which allows me to simplify things + * to modify for the CanoScan which allows me to simplify things * greatly for the CanoScan without worrying about breaking other * scanners, as well as reuse the vast majority of the Plustek * driver infrastructure without forking. @@ -109,7 +109,7 @@ cano_PrepareToReadWhiteCal( Plustek_Device *dev, SANE_Bool mv2shading_pos ) { SANE_Bool goto_shading_pos = SANE_TRUE; HWDef *hw = &dev->usbDev.HwSetting; - + switch (strip_state) { case 0: if( !usb_IsSheetFedDevice(dev)) { @@ -152,7 +152,7 @@ cano_PrepareToReadBlackCal( Plustek_Device *dev ) if( strip_state == 0 ) if(cano_PrepareToReadWhiteCal(dev, SANE_FALSE)) return SANE_FALSE; - + if( strip_state != 2 ) { /* * if we have a dark shading strip, there's no need to switch @@ -203,7 +203,7 @@ cano_LampOnAfterCalibration( Plustek_Device *dev ) * @param max - pointer to the max OFF point for the CIS-channel * @param off - pointer to the current OFF point of the CIS-channel * @param val - current value to check - * @return returns 0 if the value is fine, 1, if we need to adjust + * @return returns 0 if the value is fine, 1, if we need to adjust */ static int cano_adjLampSetting( u_short *min, u_short *max, u_short *off, u_short val ) @@ -249,7 +249,7 @@ cano_adjLampSetting( u_short *min, u_short *max, u_short *off, u_short val ) * coarse calibration step 0 * [Monty changes]: On the CanoScan at least, the default lamp * settings are several *hundred* percent too high and vary from - * scanner-to-scanner by 20-50%. This is only for CIS devices + * scanner-to-scanner by 20-50%. This is only for CIS devices * where the lamp_off parameter is adjustable; I'd make it more general, * but I only have the CIS hardware to test. */ @@ -305,7 +305,7 @@ cano_AdjustLightsource( Plustek_Device *dev ) min_rgb.Green = hw->green_lamp_on; min_rgb.Blue = hw->blue_lamp_on; - if((dev->adj.rlampoff != -1) && + if((dev->adj.rlampoff != -1) && (dev->adj.glampoff != -1) && (dev->adj.rlampoff != -1)) { DBG( _DBG_INFO, "- function skipped, using frontend values!\n" ); return SANE_TRUE; @@ -393,10 +393,10 @@ cano_AdjustLightsource( Plustek_Device *dev ) DBG( _DBG_INFO2, "red_lamp_off = %u/%u/%u\n", min_rgb.Red ,hw->red_lamp_off, max_rgb.Red ); } - + DBG( _DBG_INFO2, "green_lamp_off = %u/%u/%u\n", min_rgb.Green, hw->green_lamp_off, max_rgb.Green ); - + if( m_ScanParam.bDataType == SCANDATATYPE_Color ) { DBG( _DBG_INFO2, "blue_lamp_off = %u/%u/%u\n", min_rgb.Blue, hw->blue_lamp_off, max_rgb.Blue ); @@ -528,7 +528,7 @@ cano_AdjustGain( Plustek_Device *dev ) DBG( _DBG_INFO, "cano_AdjustGain()\n" ); if( !usb_InCalibrationMode(dev)) { - if((dev->adj.rgain != -1) && + if((dev->adj.rgain != -1) && (dev->adj.ggain != -1) && (dev->adj.bgain != -1)) { setAdjGain( dev->adj.rgain, &dev->usbDev.a_bRegs[0x3b] ); setAdjGain( dev->adj.ggain, &dev->usbDev.a_bRegs[0x3c] ); @@ -559,11 +559,11 @@ cano_AdjustGain( Plustek_Device *dev ) DBG( _DBG_INFO2, "Pixels = %lu\n", m_ScanParam.Size.dwPixels ); DBG( _DBG_INFO2, "Bytes = %lu\n", m_ScanParam.Size.dwBytes ); DBG( _DBG_INFO2, "Origin.X = %u\n", m_ScanParam.Origin.x ); - + while( adj ) { m_ScanParam.dMCLK = dMCLK; - + if( !usb_SetScanParameters( dev, &m_ScanParam )) return SANE_FALSE; @@ -615,7 +615,7 @@ cano_AdjustGain( Plustek_Device *dev ) dwR = dwR / dwDiv; dwG = dwG / dwDiv; dwB = dwB / dwDiv; - + if(max_rgb.Red < dwR) max_rgb.Red = dwR; if(max_rgb.Green < dwG) @@ -764,7 +764,7 @@ cano_AdjustOffset( Plustek_Device *dev ) u_long *scanbuf = dev->scanning.pScanBuffer; HWDef *hw = &dev->usbDev.HwSetting; DCapsDef *scaps = &dev->usbDev.Caps; - + if( usb_IsEscPressed()) return SANE_FALSE; @@ -977,13 +977,13 @@ cano_AdjustDarkShading( Plustek_Device *dev, u_short cal_dpi ) /* average the n lines, compute reg values */ if( scan->sParam.bDataType == SCANDATATYPE_Color ) { - + stepW = m_ScanParam.Size.dwPhyPixels; if( usb_IsCISDevice(dev)) step = m_ScanParam.Size.dwPhyPixels + 1; else step = (m_ScanParam.Size.dwPhyPixels*3) + 1; - + for( i=0; ifCalibrated = SANE_TRUE; - + DBG( _DBG_INFO, "cano_DoCalibration() done\n" ); DBG( _DBG_INFO, "-------------------------\n" ); DBG( _DBG_INFO, "Static Gain:\n" ); diff --git a/backend/plustek-usbcalfile.c b/backend/plustek-usbcalfile.c index afea3f9..6f5a364 100644 --- a/backend/plustek-usbcalfile.c +++ b/backend/plustek-usbcalfile.c @@ -67,7 +67,7 @@ typedef struct { u_long blue_light_on; u_long blue_light_off; u_long green_pwm_duty; - + } LightCtrl; typedef struct { @@ -106,7 +106,7 @@ usb_ReadSpecLine( FILE *fp, char *id, char* res ) { char tmp[1024]; char *ptr; - + /* rewind file pointer */ if( 0 != fseek( fp, 0L, SEEK_SET)) { DBG( _DBG_ERROR, "fseek: %s\n", strerror(errno)); @@ -124,7 +124,7 @@ usb_ReadSpecLine( FILE *fp, char *id, char* res ) ptr = &tmp[strlen(id)]; if( '\0' == *ptr ) break; - + strcpy( res, ptr ); res[strlen(res)-1] = '\0'; return SANE_TRUE; @@ -176,7 +176,7 @@ usb_ReadOtherLines( FILE *fp, char *except ) /* we ignore the version line... */ if( 0 == strncmp( tmp, "version=", 8 )) continue; - + if( !ignore ) { if(0 != strncmp(tmp, except, strlen(except))) { @@ -225,9 +225,9 @@ usb_ReadSamples( FILE *fp, char *which, u_long *dim, u_short *buffer ) if( NULL != fgets( rb, 1024, fp )) { /* we ignore the version line... */ - if( 0 == strncmp( tmp, "version=", 8 )) + if( 0 == strncmp( tmp, "version=", 8 )) continue; - + p = tmp; if( !ignore && diml == 0) { if(0 == strncmp(tmp, which, strlen(which))) { @@ -271,7 +271,7 @@ usb_ReadSamples( FILE *fp, char *which, u_long *dim, u_short *buffer ) /* reached the end? */ if( *next == '\0' ) { - /* we probably have only parsed a part of a value + /* we probably have only parsed a part of a value * so we copy that back to the input buffer and * parse it the next time... */ @@ -372,7 +372,7 @@ usb_ReadAndSetCalData( Plustek_Device *dev ) FILE *fp; CalData cal; SANE_Bool ret; - + DBG( _DBG_INFO, "usb_ReadAndSetCalData()\n" ); if( usb_InCalibrationMode(dev)) { @@ -388,7 +388,7 @@ usb_ReadAndSetCalData( Plustek_Device *dev ) sprintf( tmp, "%s-coarse.cal", dev->calFile ); DBG( _DBG_INFO, "- Reading coarse calibration data from file\n"); DBG( _DBG_INFO, " %s\n", tmp ); - + fp = fopen( tmp, "r" ); if( NULL == fp ) { DBG( _DBG_ERROR, "File %s not found\n", tmp ); @@ -416,7 +416,7 @@ usb_ReadAndSetCalData( Plustek_Device *dev ) } usb_CreatePrefix( dev, pfx, SANE_TRUE ); - + ret = SANE_FALSE; if( usb_ReadSpecLine( fp, pfx, tmp )) { DBG( _DBG_INFO, "- Calibration data: %s\n", tmp ); @@ -445,7 +445,7 @@ usb_ReadAndSetCalData( Plustek_Device *dev ) fclose( fp ); DBG( _DBG_INFO, "usb_ReadAndSetCalData() done -> %u\n", ret ); - + return ret; } @@ -526,7 +526,7 @@ usb_SaveCalData( Plustek_Device *dev ) other_tmp = NULL; fp = fopen( fn, "r+" ); if( NULL != fp ) { - + if( usb_ReadSpecLine( fp, "version=", tmp )) { DBG( _DBG_INFO, "- Calibration file version: %s\n", tmp ); @@ -553,7 +553,7 @@ usb_SaveCalData( Plustek_Device *dev ) if( NULL == fp ) { DBG( _DBG_ERROR, "- Cannot create file %s\n", fn ); DBG( _DBG_ERROR, "- -> %s\n", strerror(errno)); - if( other_tmp ) + if( other_tmp ) free( other_tmp ); return; } @@ -603,7 +603,7 @@ usb_SaveFineCalData( Plustek_Device *dev, int dpi, other_tmp = NULL; fp = fopen( fn, "r+" ); if( NULL != fp ) { - + if( usb_ReadSpecLine( fp, "version=", tmp )) { DBG( _DBG_INFO, "- Calibration file version: %s\n", tmp ); @@ -664,7 +664,7 @@ usb_ReadFineCalData( Plustek_Device *dev, int dpi, char tmp[1024]; u_short version; FILE *fp; - + DBG( _DBG_INFO, "usb_ReadFineCalData()\n" ); if( usb_InCalibrationMode(dev)) { DBG( _DBG_INFO, "- we are in calibration mode!\n" ); diff --git a/backend/plustek-usbdevs.c b/backend/plustek-usbdevs.c index 4f53863..8698e54 100644 --- a/backend/plustek-usbdevs.c +++ b/backend/plustek-usbdevs.c @@ -115,7 +115,7 @@ * If you do not wish that, delete this exception notice. *
*/ - + /* the other stuff is included by plustek.c ...*/ #include "plustek-usb.h" @@ -146,11 +146,11 @@ static DCapsDef Cap0x07B3_0x0017_0 = }, { /* Negative */ {1004 + 55, 744 + 12}, /* DataOrigin (X: 7cm + 1.5cm, Y: 8mm + 5.5cm)*/ - + /* 533 blaustichig */ 537 /* hell */ /* 543 gruenstichig */ - + /*543*/, -1, /* ShadingOriginY (Y: 8mm + 3.8cm) */ {567, 414}, /* Size (X: 4.8cm, Y: 3.5cm) */ {150, 150} /* MinDpi */ @@ -332,7 +332,7 @@ static DCapsDef Cap0x07B3_0x0013_4 = {{1004 + 20, 744 - 20}, 543, -1, { 567, 414}, {150, 150}}, {{ 0, 95}, 0, -1, {2550, 3508}, { 50, 50}}, {1200, 1200}, - DEVCAPSFLAG_Positive + DEVCAPSFLAG_Negative, + DEVCAPSFLAG_Positive + DEVCAPSFLAG_Negative, SENSORORDER_rgb, 12, 4, kNEC3778, 0x03, _WAF_NONE, _NO_MIO }; @@ -844,7 +844,7 @@ static HWDef Hw0x07B3_0x0017_0 = {2, 7, 0, 1, 0, 0, 0, 0, 4, 0}, /* bReg_0x0f_Color [10] (0x0f to 0x18) */ {5, 23, 1, 3, 0, 0, 0, 12, 10, 22}, - + _GREEN_CH, /* bReg_0x26 color mode - bits 4 and 5 */ 0, /* bReg 0x27 color mode */ @@ -1102,9 +1102,9 @@ static HWDef Hw0x07B3_0x0013_0 = 0, 0x1e, 0xa8, - 0, + 0, 0xff, - 64, + 64, 20, 0x0d, 0x22, 0x82, 0x88, 0, 0, 0, @@ -1128,15 +1128,15 @@ static HWDef Hw0x07B3_0x0013_4 = {20, 4, 13, 16, 19, 22, 0, 0, 23, 11}, _GREEN_CH, 0, - 1, + 1, /* illumination mode settings (not used for CCD devices) */ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 }, 1, 13, - 62, - 320, - 10684, + 62, + 320, + 10684, 0, 16383, 0, @@ -1164,9 +1164,9 @@ static HWDef Hw0x07B3_0x000F_4 = { 1.1, 0.9, 0.0, 12, 12, - 600, - 2048, - 8, 8, + 600, + 2048, + 8, 8, 4095, 4095, 0x06, 0x30, 0x2f, 0x2a, {2, 7, 5, 6, 6, 7, 0, 0, 0, 5}, @@ -1259,7 +1259,7 @@ static HWDef Hw0x07B3_0x0017_4 = 8, 8, 4095, 4095, 0x06, 0x20, 0x2f, 0x2a, - {2, 7, 5, 6, 6, 7, 0, 0, 0, 5}, + {2, 7, 5, 6, 6, 7, 0, 0, 0, 5}, {20, 4, 13, 16, 19, 22, 0, 0, 23, 11}, _GREEN_CH, 0, @@ -1327,7 +1327,7 @@ static HWDef Hw0x07B3_0x0017_1 = 0, 0x1e, 0xa8, - 0, + 0, 0xff, 64, 20, @@ -1414,7 +1414,7 @@ static HWDef Hw0x07B3_0x0017_2 = 0, 16383, 3, - 0, + 0, 0x1e, 0xa8, 0, @@ -1498,10 +1498,10 @@ static HWDef Hw0x03F0_0x0505 = /* bReg_0x0f_Color[10] (0x0f to 0x18) */ { 0x08, 0x17, 0x00, 0x03, 0x08, 0x0b, 0x00, 0x00, 0x0a, 0x14 }, - + _GREEN_CH, /* bReg_0x26 color mode - bits 4 and 5 */ 0, /* bReg 0x27 color mode */ - + 1, /* bReg 0x29 illumination mode */ /* illumination mode settings (not used for CCD devices) */ @@ -1520,7 +1520,7 @@ static HWDef Hw0x03F0_0x0505 = 1, /* green lamp off (reg 0x32 + 0x33) */ 16383, /* blue lamp on (reg 0x34 + 0x35) */ 1, /* blue lamp off (reg 0x36 + 0x37) */ - + /* Misc */ 0x13, /* bReg_0x45 */ 0, /* wStepsAfterPaperSensor2 (0x4c & 0x4d) */ @@ -1566,7 +1566,7 @@ static HWDef Hw0x03F0_0x0605 = /* bReg_0x0f_Color[10] (0x0f to 0x18) */ { 0x08, 0x17, 0x00, 0x03, 0x08, 0x0b, 0x00, 0x00, 0x0a, 0x14 }, - + _GREEN_CH, /* bReg_0x26 color mode - bits 4 and 5 */ 0, /* bReg 0x27 color mode */ 1, /* bReg 0x29 illumination mode */ @@ -1587,7 +1587,7 @@ static HWDef Hw0x03F0_0x0605 = 1, /* green lamp off (reg 0x32 + 0x33) */ 16383, /* blue lamp on (reg 0x34 + 0x35) */ 1, /* blue lamp off (reg 0x36 + 0x37) */ - + /* Misc */ 0x13, /* bReg_0x45 */ 0, /* wStepsAfterPaperSensor2 (0x4c & 0x4d) */ @@ -1985,7 +1985,7 @@ static HWDef Hw0x1606_0x0060 = 0, /* test mode ADC Output CODE MSB (reg 0x5c) */ 0, /* test mode ADC Output CODE LSB (reg 0x5d) */ 0, /* test mode (reg 0x5e) */ - _LM9832, + _LM9832, MODEL_UMAX, 1.0 }; @@ -2019,7 +2019,7 @@ static HWDef Hw0x1606_0x0160 = _GREEN_CH, /* bReg_0x26 color mode - bits 4 and 5 */ 0x40, /* bReg 0x27 color mode */ 1, /* bReg 0x29 illumination mode */ - + /* illumination mode settings (not used for CCD devices) */ { 0, 0, 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 0, 0, 0 }, @@ -2807,7 +2807,7 @@ static SetDef Settings[] = {"0x1606-0x0050", &Cap0x1606_0x0060, &Hw0x1606_0x0060, "3400" }, {"0x1606-0x0060", &Cap0x1606_0x0060, &Hw0x1606_0x0060, "3400" }, {"0x1606-0x0160", &Cap0x1606_0x0160, &Hw0x1606_0x0160, "5400" }, - + /* COMPAQ... */ {"0x049F-0x001A", &Cap0x1606_0x0060, &Hw0x1606_0x0060, "S4-100" }, diff --git a/backend/plustek-usbhw.c b/backend/plustek-usbhw.c index a1dae68..05d3cc7 100644 --- a/backend/plustek-usbhw.c +++ b/backend/plustek-usbhw.c @@ -27,7 +27,7 @@ * - 0.45 - added function usb_AdjustLamps() to tweak CIS lamp settings * - fixed NULL pointer problem in lamp-off ISR * - added usb_AdjustCISLampSettings() - * - skipping warmup for CIS devices + * - skipping warmup for CIS devices * - 0.46 - fixed problem in usb_GetLampStatus for CIS devices, as we * read back reg[0x29] to wrong position * made it compile without itimer definitions @@ -46,7 +46,7 @@ * - 0.50 - added button support for Plustek/Genius devices * - changed behaviour of usb_IsScannerReady * - added special misc I/O setup for CIS devices (usb_ResetRegisters) - * - 0.51 - change usb_AdjustLamps() and use it now in usb_switchLamp() + * - 0.51 - change usb_AdjustLamps() and use it now in usb_switchLamp() * - added usb_Wait4ScanSample() and usb_InCalibrationMode() * - tweaked EjectPaper to work correctly with the supported sheet-fed * devices @@ -97,7 +97,7 @@ * If you do not wish that, delete this exception notice. *
*/ -#ifdef HAVE_SYS_TIME_H +#ifdef HAVE_SYS_TIME_H #include #endif @@ -228,7 +228,7 @@ static SANE_Bool usb_IsScannerReady( Plustek_Device *dev ) { u_char value; - double len; + double len; long timeout; struct timeval t; SANE_Status res; @@ -242,10 +242,10 @@ usb_IsScannerReady( Plustek_Device *dev ) if( len < 10 ) len = 10; - gettimeofday( &t, NULL); + gettimeofday( &t, NULL); timeout = t.tv_sec + len; - do { + do { res = usbio_ReadReg( dev->fd, 7, &value); if( res != SANE_STATUS_GOOD ) { sleep(1); @@ -262,14 +262,14 @@ usb_IsScannerReady( Plustek_Device *dev ) return SANE_FALSE; } else { - return SANE_TRUE; + return SANE_TRUE; } } } gettimeofday( &t, NULL); - + } while( t.tv_sec < timeout ); - + DBG( _DBG_ERROR, "Scanner not ready!!!\n" ); return SANE_FALSE; } @@ -382,10 +382,10 @@ usb_WaitPos( Plustek_Device *dev, u_long to, SANE_Bool stay ) if( maxf < 5.0 ) maxf = 5.0; DBG( _DBG_INFO2, ">>>> CURRENT MCLK_DIV = %u\n", mclk_div ); - DBG( _DBG_INFO2, ">>>> MCH = %u\n", mch ); - DBG( _DBG_INFO2, ">>>> FFS = %u\n", ffs ); - DBG( _DBG_INFO2, ">>>> HIGH-SPEED = %.3f (%.3f)\n", - speed, hw->dHighSpeed); + DBG( _DBG_INFO2, ">>>> MCH = %u\n", mch ); + DBG( _DBG_INFO2, ">>>> FFS = %u\n", ffs ); + DBG( _DBG_INFO2, ">>>> HIGH-SPEED = %.3f (%.3f)\n", + speed, hw->dHighSpeed); DBG( _DBG_INFO2, ">>>> MIN_FFS = %u (%.3f)\n", min_ffs, maxf); } @@ -407,7 +407,7 @@ usb_WaitPos( Plustek_Device *dev, u_long to, SANE_Bool stay ) break; if( min_ffs != 0xffff ) { - + fac = maxf/step; if( ffs ) { if((u_short)fac < ffs ) { @@ -432,7 +432,7 @@ usb_WaitPos( Plustek_Device *dev, u_long to, SANE_Bool stay ) if(ffs == min_ffs ) ffs = 0; } else { - + if( !stay ) { retval = SANE_TRUE; break; @@ -609,7 +609,7 @@ usb_ModuleMove( Plustek_Device *dev, u_char action, u_long dwStep ) } else { return SANE_TRUE; } - + retval = SANE_FALSE; /* start the sensor... */ @@ -633,9 +633,9 @@ usb_ModuleMove( Plustek_Device *dev, u_char action, u_long dwStep ) return SANE_TRUE; } - gettimeofday(&t2, NULL); + gettimeofday(&t2, NULL); if( t2.tv_sec > secs ) - break; + break; } } else if( action == MOVE_SkipPaperSensor ) { @@ -648,7 +648,7 @@ usb_ModuleMove( Plustek_Device *dev, u_char action, u_long dwStep ) return SANE_TRUE; } - gettimeofday(&t2, NULL); + gettimeofday(&t2, NULL); if( t2.tv_sec > secs ) break; } @@ -750,7 +750,7 @@ usb_ModuleToHome( Plustek_Device *dev, SANE_Bool fWait ) regs[0x57] = 16; } break; - + case MODEL_KaoHsiung: default: regs[0x56] = 64; @@ -822,7 +822,7 @@ usb_ModuleToHome( Plustek_Device *dev, SANE_Bool fWait ) if( hw->motorModel == MODEL_Tokyo600) { u_long dwSpeedUp = GetTickCount () + 250; - + /* while(GetTickCount () < dwSpeedUp) */ while((int)(dwSpeedUp - GetTickCount ()) > 0) { @@ -832,9 +832,9 @@ usb_ModuleToHome( Plustek_Device *dev, SANE_Bool fWait ) if (!value) return TRUE; } - wFastFeedStepSize = (WORD)(CRYSTAL_FREQ / + wFastFeedStepSize = (WORD)(CRYSTAL_FREQ / (6UL * 8UL * 1 * Device.HwSetting.dMaxMotorSpeed * 4 * - Device.HwSetting.wMotorDpi) * 60 / 78); + Device.HwSetting.wMotorDpi) * 60 / 78); regs[0x48] = (u_char)(wFastFeedStepSize >> 8); regs[0x49] = (u_char)(wFastFeedStepSize & 0xFF); WriteRegisters(0x48, ®s[0x48], 2); @@ -856,22 +856,22 @@ usb_MotorSelect( Plustek_Device *dev, SANE_Bool fADF ) if(!_IS_PLUSTEKMOTOR(hw->motorModel)) { return SANE_TRUE; } - + if( fADF ) { if( sCaps->bCCD == kNEC3778 ) { - + hw->wMotorDpi = 300; hw->dMaxMotorSpeed = 1.5; hw->dMaxMoveSpeed = 1.5; sCaps->OpticDpi.y = 600; } regs[0x5b] |= 0x80; - + } else { - + if( sCaps->bCCD == kNEC3778 ) { - + hw->wMotorDpi = 600; hw->dMaxMotorSpeed = 1.1; hw->dMaxMoveSpeed = 0.9; @@ -1131,7 +1131,7 @@ usb_GetLampStatus( Plustek_Device *dev ) } } - DBG( _DBG_INFO, "LAMP-STATUS: 0x%08x (%s)\n", + DBG( _DBG_INFO, "LAMP-STATUS: 0x%08x (%s)\n", iLampStatus, iLampStatus?"on":"off" ); return iLampStatus; } @@ -1278,7 +1278,7 @@ usb_LampOn( Plustek_Device *dev, SANE_Bool fOn, SANE_Bool fResetTimer ) if( fOn ) { if( iLampStatus != lampId ) { - + DBG( _DBG_INFO, "Switching Lamp on\n" ); /* here we might have to switch off the TPA/Main lamp before @@ -1292,7 +1292,7 @@ usb_LampOn( Plustek_Device *dev, SANE_Bool fOn, SANE_Bool fResetTimer ) } memset( ®s[0x29], 0, (0x37-0x29+1)); - + regs[0x29] = hw->bReg_0x29; if( !usb_switchLamp(dev, SANE_TRUE )) { @@ -1314,12 +1314,12 @@ usb_LampOn( Plustek_Device *dev, SANE_Bool fOn, SANE_Bool fResetTimer ) sanei_lm983x_write( dev->fd, 0x29, ®s[0x29], 0x37-0x29+1, SANE_TRUE ); if( lampId != dev->usbDev.currentLamp ) { - + dev->usbDev.currentLamp = lampId; - + if( fResetTimer ) { - - gettimeofday( &t, NULL ); + + gettimeofday( &t, NULL ); dev->usbDev.dwTicksLampOn = t.tv_sec; DBG( _DBG_INFO, "Warmup-Timer started\n" ); } @@ -1329,14 +1329,14 @@ usb_LampOn( Plustek_Device *dev, SANE_Bool fOn, SANE_Bool fResetTimer ) } else { int iStatusChange = iLampStatus & ~lampId; - + if( iStatusChange != iLampStatus ) { DBG( _DBG_INFO, "Switching Lamp off\n" ); - + memset( ®s[0x29], 0, 0x37-0x29+1 ); if( !usb_switchLamp(dev, SANE_FALSE )) { - + if( iStatusChange & DEV_LampReflection ) { regs[0x2e] = 16383 / 256; regs[0x2f] = 16383 % 256; @@ -1389,7 +1389,7 @@ usb_ResetRegisters( Plustek_Device *dev ) HWDef *hw = &dev->usbDev.HwSetting; u_char *regs = dev->usbDev.a_bRegs; - DBG( _DBG_INFO, "RESETTING REGISTERS(%i) - 0x%02x\n", + DBG( _DBG_INFO, "RESETTING REGISTERS(%i) - 0x%02x\n", dev->initialized, (int) sizeof(dev->usbDev.a_bRegs)); memset( regs, 0, sizeof(dev->usbDev.a_bRegs)); @@ -1462,7 +1462,7 @@ usb_ResetRegisters( Plustek_Device *dev ) } /** function which checks if we are already in home position or not. - * + * */ static SANE_Bool usb_SensorStatus( Plustek_Device *dev ) @@ -1486,7 +1486,7 @@ usb_SensorStatus( Plustek_Device *dev ) usbio_WriteReg( dev->fd, 0x07, 0 ); usbio_WriteReg( dev->fd, 0x07, 0x20 ); usbio_WriteReg( dev->fd, 0x07, 0 ); - + sanei_lm983x_write( dev->fd, 0x58, &hw->bReg_0x58, 0x5b-0x58+1, SANE_TRUE ); usbio_ReadReg( dev->fd, 2, &value ); @@ -1632,7 +1632,7 @@ usb_Wait4Warmup( Plustek_Device *dev ) DBG(_DBG_INFO,"Warmup: skipped for CIS devices\n" ); return SANE_TRUE; } - + if( dev->adj.warmup < 0 ) return SANE_TRUE; @@ -1699,7 +1699,7 @@ usb_HasTPA( Plustek_Device *dev ) usbio_WriteReg ( dev->fd, 0x58, dev->usbDev.HwSetting.bReg_0x58 ); usbio_WriteReg ( dev->fd, 0x5a, dev->usbDev.HwSetting.bReg_0x5a ); usbio_WriteReg ( dev->fd, 0x5b, dev->usbDev.HwSetting.bReg_0x5b ); - + usbio_ReadReg ( dev->fd, 0x02, &val ); DBG( _DBG_INFO, "REG[0x02] = 0x%02x\n", val ); @@ -1707,7 +1707,7 @@ usb_HasTPA( Plustek_Device *dev ) DBG( _DBG_INFO, "UMAX-TPA detected\n" ); dev->usbDev.ModelStr = model; return SANE_TRUE; - } else + } else DBG( _DBG_INFO, "UMAX-TPA NOT detected\n" ); if( dev->adj.enableTpa ) { @@ -1716,7 +1716,7 @@ usb_HasTPA( Plustek_Device *dev ) return SANE_TRUE; } } - } + } return SANE_FALSE; } @@ -1737,7 +1737,7 @@ usb_UpdateButtonStatus( Plustek_Scanner *s ) return SANE_FALSE; status = sanei_access_lock( dev->sane.name, 3 ); - if( SANE_STATUS_GOOD != status ) + if( SANE_STATUS_GOOD != status ) return SANE_FALSE; if( -1 == dev->fd ) { @@ -1754,7 +1754,7 @@ usb_UpdateButtonStatus( Plustek_Scanner *s ) mio[0] = dev->usbDev.HwSetting.bReg_0x59; mio[1] = dev->usbDev.HwSetting.bReg_0x5a; mio[2] = dev->usbDev.HwSetting.bReg_0x5b; - + usbio_ReadReg( dev->fd, 0x07, &val ); if( val == 0 ) { @@ -1814,7 +1814,7 @@ usb_UpdateButtonStatus( Plustek_Scanner *s ) } for( i = 0; i < 3; i++ ) { - + DBG( _DBG_INFO2, "Checking MISC IO[%u]=0x%02x\n", i, mio[i] ); mask = 0x01; @@ -1822,9 +1822,9 @@ usb_UpdateButtonStatus( Plustek_Scanner *s ) if((mio[i] & mask) == 0) { DBG( _DBG_INFO2, "* port %u configured as input," - " status: %s (%u)\n", (i*2)+j+1, + " status: %s (%u)\n", (i*2)+j+1, ((val & 1)?"PRESSED":"RELEASED"), (OPT_BUTTON_0 + bc)); - s->val[OPT_BUTTON_0 + bc].w = val & 1; + s->val[OPT_BUTTON_0 + bc].w = val & 1; bc++; } val >>= 1; diff --git a/backend/plustek-usbimg.c b/backend/plustek-usbimg.c index 41c0207..0c28491 100644 --- a/backend/plustek-usbimg.c +++ b/backend/plustek-usbimg.c @@ -254,7 +254,7 @@ static void usb_AverageColorWord( Plustek_Device *dev ) if((scan->sParam.bSource == SOURCE_Negative || scan->sParam.bSource == SOURCE_Transparency) && scan->sParam.PhyDpi.x > 800) { - + scan->Red.pcw[0].Colors[0] = _HILO2WORD(scan->Red.pcw[0].HiLo[0]) >> ls; scan->Green.pcw[0].Colors[0] = _HILO2WORD(scan->Green.pcw[0].HiLo[0]) >> ls; scan->Blue.pcw[0].Colors[0] = _HILO2WORD(scan->Blue.pcw[0].HiLo[0]) >> ls; @@ -334,7 +334,7 @@ static int usb_GetScaler( ScanDef *scan ) double ratio; ratio = (double)scan->sParam.UserDpi.x/ - (double)scan->sParam.PhyDpi.x; + (double)scan->sParam.PhyDpi.x; return (int)(1.0/ratio * _SCALER); } @@ -458,7 +458,7 @@ static void usb_ColorDuplicate16_2( Plustek_Device *dev ) ls = Shift; else ls = 0; - + for( dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) { if( swap ) { @@ -484,7 +484,7 @@ static void usb_ColorDuplicate16_2( Plustek_Device *dev ) */ static void usb_ColorDuplicatePseudo16( Plustek_Device *dev ) { - int next; + int next; u_short wR, wG, wB; u_long dw, pixels; ScanDef *scan = &dev->scanning; @@ -537,7 +537,7 @@ static void usb_ColorDuplicateGray( Plustek_Device *dev ) } switch(scan->fGrayFromColor) { - + case 1: for (dw = 0; dw < scan->sParam.Size.dwPixels; dw++, pixels += next) scan->UserBuf.pb[pixels] = scan->Red.pcb[dw].a_bColor[0]; @@ -761,7 +761,7 @@ static void usb_GrayDuplicate16( Plustek_Device *dev ) ls = Shift; else ls = 0; - + pwm = scan->Green.philo; for( pixels=scan->sParam.Size.dwPixels; pixels--; pwm++, dest += next ) { if( swap ) @@ -912,7 +912,7 @@ static void usb_ColorScaleGray( Plustek_Device *dev ) ScanDef *scan = &dev->scanning; usb_AverageColorByte( dev ); - + dw = scan->sParam.Size.dwPixels; if( scan->sParam.bSource == SOURCE_ADF ) { @@ -930,19 +930,19 @@ static void usb_ColorScaleGray( Plustek_Device *dev ) } izoom = usb_GetScaler( scan ); - + for( ddax = 0; dw; src++ ) { ddax -= _SCALER; while((ddax < 0) && (dw > 0)) { scan->UserBuf.pb[pixels] = src->a_bColor[0]; - + pixels += next; ddax += izoom; dw--; } - } + } } /** @@ -1189,7 +1189,7 @@ static void usb_ColorScale8( Plustek_Device *dev ) pixels = 0; } - izoom = usb_GetScaler( scan ); + izoom = usb_GetScaler( scan ); for( bitsput = 0, ddax = 0; dw; bitsput++ ) { @@ -1341,7 +1341,7 @@ static void usb_ColorScale16_2( Plustek_Device *dev ) while((ddax < 0) && (dw > 0)) { if( swap ) { - + tmp = *((HiLoDef*)&scan->Red.pw[bitsput]); scan->UserBuf.pw_rgb[pixels].Red = _HILO2WORD(tmp) >> ls; @@ -1384,7 +1384,7 @@ static void usb_ColorScalePseudo16( Plustek_Device *dev ) next = 1; pixels = 0; } - + izoom = usb_GetScaler( scan ); wR = (u_short)scan->Red.pcb[0].a_bColor[0]; @@ -1399,13 +1399,13 @@ static void usb_ColorScalePseudo16( Plustek_Device *dev ) scan->UserBuf.pw_rgb[pixels].Red = (wR + scan->Red.pcb[bitsput].a_bColor[0]) << bShift; - + scan->UserBuf.pw_rgb[pixels].Green = (wG + scan->Green.pcb[bitsput].a_bColor[0]) << bShift; - + scan->UserBuf.pw_rgb[pixels].Blue = (wB + scan->Blue.pcb[bitsput].a_bColor[0]) << bShift; - + pixels += next; ddax += izoom; dw--; @@ -1440,7 +1440,7 @@ static void usb_BWScale( Plustek_Device *dev ) } izoom = usb_GetScaler( scan ); - + memset( dest, 0, scan->dwBytesLine ); ddax = 0; dw = 0; @@ -1454,7 +1454,7 @@ static void usb_BWScale( Plustek_Device *dev ) tmp = src[(i>>3)]; if((dw>>3) < scan->sParam.Size.dwValidPixels ) { - + if( 0 != (tmp &= (1 << ((~(i & 0x7))&0x7)))) dest[dw>>3] |= (1 << ((~(dw & 0x7))&0x7)); } @@ -1495,7 +1495,7 @@ static void usb_BWScaleFromColor( Plustek_Device *dev ) d = j = 0; for( pixels = scan->sParam.Size.dwPixels; pixels; src++ ) { - + ddax -= _SCALER; while((ddax < 0) && (pixels > 0)) { @@ -1545,7 +1545,7 @@ static void usb_BWScaleFromColor_2( Plustek_Device *dev ) d = j = 0; for( pixels = scan->sParam.Size.dwPixels; pixels; src++ ) { - + ddax -= _SCALER; while((ddax < 0) && (pixels > 0)) { @@ -1583,7 +1583,7 @@ static void usb_GrayScale8( Plustek_Device *dev ) dest = scan->UserBuf.pb; next = 1; } - + izoom = usb_GetScaler( scan ); ddax = 0; @@ -1625,7 +1625,7 @@ static void usb_GrayScale16( Plustek_Device *dev ) next = 1; dest = scan->UserBuf.pw; } - + izoom = usb_GetScaler( scan ); ddax = 0; @@ -1711,7 +1711,7 @@ static void usb_GetImageProc( Plustek_Device *dev ) case SCANDATATYPE_Color: if (scan->sParam.bBitDepth > 8) { - if( usb_IsCISDevice(dev)){ + if( usb_IsCISDevice(dev)){ scan->pfnProcess = usb_ColorScale16_2; DBG( _DBG_INFO, "ImageProc is: ColorScale16_2\n" ); } else { @@ -1719,7 +1719,7 @@ static void usb_GetImageProc( Plustek_Device *dev ) DBG( _DBG_INFO, "ImageProc is: ColorScale16\n" ); } if (scan->fGrayFromColor) { - if( usb_IsCISDevice(dev)){ + if( usb_IsCISDevice(dev)){ scan->pfnProcess = usb_ColorScaleGray16_2; DBG( _DBG_INFO, "ImageProc is: ColorScaleGray16_2\n" ); } else { @@ -1730,7 +1730,7 @@ static void usb_GetImageProc( Plustek_Device *dev ) } else if (scan->dwFlag & SCANFLAG_Pseudo48) { scan->pfnProcess = usb_ColorScalePseudo16; DBG( _DBG_INFO, "ImageProc is: ColorScalePseudo16\n" ); - + } else if (scan->fGrayFromColor) { if( usb_IsCISDevice(dev)){ @@ -1752,7 +1752,7 @@ static void usb_GetImageProc( Plustek_Device *dev ) } } else { - if( usb_IsCISDevice(dev)){ + if( usb_IsCISDevice(dev)){ scan->pfnProcess = usb_ColorScale8_2; DBG( _DBG_INFO, "ImageProc is: ColorScale8_2\n" ); } else { @@ -1829,7 +1829,7 @@ static void usb_GetImageProc( Plustek_Device *dev ) } } } else { - if( usb_IsCISDevice(dev)){ + if( usb_IsCISDevice(dev)){ scan->pfnProcess = usb_ColorDuplicate8_2; DBG( _DBG_INFO, "ImageProc is: ColorDuplicate8_2\n" ); } else { @@ -1860,9 +1860,9 @@ static void usb_GetImageProc( Plustek_Device *dev ) break; } } - + if( scan->sParam.bBitDepth == 8 ) { - + if( scan->dwFlag & SCANFLAG_Pseudo48 ) { if( scan->dwFlag & SCANFLAG_RightAlign ) { bShift = 5; diff --git a/backend/plustek-usbio.c b/backend/plustek-usbio.c index cae0e0d..9677456 100644 --- a/backend/plustek-usbio.c +++ b/backend/plustek-usbio.c @@ -23,7 +23,7 @@ * - 0.47 - no changes * - 0.48 - cleanup * - 0.49 - no changes - * - 0.50 - usbio_DetectLM983x() now returns error if register + * - 0.50 - usbio_DetectLM983x() now returns error if register * could not be red * - usbio_ResetLM983x() checks for reg7 value before writing * - 0.51 - allow dumpRegs to be called without valid fd @@ -69,7 +69,7 @@ * If you do not wish that, delete this exception notice. *
*/ - + #include "../include/sane/sanei_usb.h" #include "../include/sane/sanei_lm983x.h" @@ -256,7 +256,7 @@ static SANE_Bool usbio_WriteReg( SANE_Int handle, for( i = 0; i < 100; i++ ) { sanei_lm983x_write_byte( handle, reg, value ); - + /* Flush register 0x02 when register 0x58 is written */ if( 0x58 == reg ) { _UIO( usbio_ReadReg( handle, 2, &data )); @@ -301,7 +301,7 @@ static SANE_Status usbio_DetectLM983x( SANE_Int fd, SANE_Byte *version ) sprintf( buf, "usbio_DetectLM983x: found " ); switch((SANE_Int)value ) { - + case 4: strcat( buf, "LM9832/3" ); break; case 3: strcat( buf, "LM9831" ); break; case 2: strcat( buf, "LM9830 --> unsupported!!!" ); diff --git a/backend/plustek-usbmap.c b/backend/plustek-usbmap.c index 1e54789..c979345 100644 --- a/backend/plustek-usbmap.c +++ b/backend/plustek-usbmap.c @@ -75,7 +75,7 @@ static void usb_MapAdjust( Plustek_Device *dev ) { int i, tabLen; double b, c, tmp; - + tabLen = _MAP_SIZE; /* adjust brightness (b) and contrast (c) using the function: @@ -125,11 +125,11 @@ static SANE_Bool usb_MapDownload( Plustek_Device *dev ) int i, threshold; SANE_Byte value; SANE_Bool fInverse = 0; - + DBG( _DBG_INFO, "usb_MapDownload()\n" ); /* the maps are have been already set */ - + /* do the brightness and contrast adjustment ... */ if( scanning->sParam.bDataType != SCANDATATYPE_BW ) usb_MapAdjust( dev ); @@ -141,7 +141,7 @@ static SANE_Bool usb_MapDownload( Plustek_Device *dev ) * into trouble elsewhere on CanoScan models using gray mode */ for( color = 0; color < 3; color++) { - + /* select color */ value = (color << 2)+2; @@ -161,13 +161,13 @@ static SANE_Bool usb_MapDownload( Plustek_Device *dev ) threshold = 0; if(threshold > (int)_MAP_SIZE) threshold = _MAP_SIZE; - + DBG(_DBG_INFO, "* Threshold is at %u brightness=%i\n", threshold, scanning->sParam.brightness ); for(i = 0; i < threshold; i++) a_bMap[color*_MAP_SIZE + i] = 0; - + for(i = threshold; i < _MAP_SIZE; i++) a_bMap[color*_MAP_SIZE + i] = 255; @@ -184,23 +184,23 @@ static SANE_Bool usb_MapDownload( Plustek_Device *dev ) } if( fInverse ) { - + u_char map[_MAP_SIZE]; u_char *pMap = a_bMap+color*_MAP_SIZE; - + DBG( _DBG_INFO, "* Inverting Map\n" ); - + for( i = 0; i < _MAP_SIZE; i++, pMap++ ) map[i] = ~*pMap; - + sanei_lm983x_write( dev->fd, 0x06, map, _MAP_SIZE, SANE_FALSE ); - + } else { DBG( _DBG_INFO, "* downloading map %u...\n", color ); sanei_lm983x_write( dev->fd, 0x06, a_bMap+color*_MAP_SIZE, _MAP_SIZE, SANE_FALSE ); } - + } /* for each color */ DBG( _DBG_INFO, "usb_MapDownload() done.\n" ); diff --git a/backend/plustek-usbscan.c b/backend/plustek-usbscan.c index c8824fc..bafc86a 100644 --- a/backend/plustek-usbscan.c +++ b/backend/plustek-usbscan.c @@ -595,7 +595,7 @@ usb_GetMCLKDiv( Plustek_Device *dev ) DBG( _DBG_INFO, "usb_GetMCLKDiv()\n" ); r = 8; /* line rate */ - if ((regs[0x26] & 7) == 0) + if ((regs[0x26] & 7) == 0) r = 24; /* pixel rate */ /* use high or low res min integration time */ @@ -606,7 +606,7 @@ usb_GetMCLKDiv( Plustek_Device *dev ) min_int_time /((double)1000. * r * m_wLineLength)); minmclk = _MAX(minmclk,MCLKDIV_SCALING); - maxmclk = (int)(32.5*MCLKDIV_SCALING + .5); + maxmclk = (int)(32.5*MCLKDIV_SCALING + .5); DBG(_DBG_INFO2,"- lower mclkdiv limit=%f\n",(double)minmclk/MCLKDIV_SCALING); DBG(_DBG_INFO2,"- upper mclkdiv limit=%f\n",(double)maxmclk/MCLKDIV_SCALING); @@ -622,7 +622,7 @@ usb_GetMCLKDiv( Plustek_Device *dev ) /* compute the horizontal dpi (pixels per inch) */ j = regs[0x9] & 0x7; - hdpi = ((j&1)*.5+1)*(j&2?2:1)*(j&4?4:1); + hdpi = ((j&1)*.5+1)*(j&2?2:1)*(j&4?4:1); pixelsperline = (int)((256*regs[0x24]+regs[0x25]-256*regs[0x22]-regs[0x23]) *pixelbits/(hdpi * 8)); @@ -644,7 +644,7 @@ usb_GetMCLKDiv( Plustek_Device *dev ) while (mclkdiv * hdpi < 6.*MCLKDIV_SCALING) { mclkdiv++; } - DBG( _DBG_INFO2, "- HIGHSPEED MCLK Divider = %u\n", + DBG( _DBG_INFO2, "- HIGHSPEED MCLK Divider = %u\n", mclkdiv/MCLKDIV_SCALING ); } @@ -690,7 +690,7 @@ usb_GetMCLKDivider( Plustek_Device *dev, ScanParam *pParam ) (m_dMCLKDivider * m_bCM * m_wLineLength / 6 * 9 / 10) * (1 + m_bIntTimeAdjust)) { m_bIntTimeAdjust++; - } + } if( hw->motorModel == MODEL_HuaLien && sCaps->bCCD == kNEC3799 && m_bIntTimeAdjust > bMaxITA) { @@ -730,7 +730,7 @@ usb_GetMCLKDivider( Plustek_Device *dev, ScanParam *pParam ) m_wStepSize, regs[0x46], regs[0x47] ); usb_GetDPD( dev ); } - + /* Compute maximum MCLK divider base on maximum integration time for * high lamp PWM, use equation 4 */ @@ -830,7 +830,7 @@ usb_GetLineLength( Plustek_Device *dev, ScanParam *param ) ctmode = (regs[0x0b] >> 3) & 3; /* cis tr timing mode */ - m_bLineRateColor = 1; + m_bLineRateColor = 1; if (afeop == 1 || afeop == 5) /* if 3 channel line or 1 channel mode b */ m_bLineRateColor = 3; @@ -845,7 +845,7 @@ usb_GetLineLength( Plustek_Device *dev, ScanParam *param ) b = 1; if( ctmode == 0 ) { /* CCD mode scanner*/ - + b = (ntr + 1) * ((2 * gbnd) + dur + 1); b += (1 - ntr) * en_tradj; } @@ -871,12 +871,12 @@ usb_GetLineLength( Plustek_Device *dev, ScanParam *param ) if( ctmode == 0 ) tr += m_bLineRateColor; } else { - + int le_phi, num_byteclk, num_mclkf, tr_fast_pix, extra_pix; - + /* Line color or gray mode */ if( afeop != 0 ) { - + le_phi = (tradj + 1) / 2 + 1 + 6; num_byteclk = ((le_phi + 8 * le + 8 * b + 4) / (8 * tradj)) + 1; @@ -893,7 +893,7 @@ usb_GetLineLength( Plustek_Device *dev, ScanParam *param ) tr_fast_pix = num_byteclk; extra_pix = (num_mclkf - le_phi) % (3 * 8); } - + tr = b + le + 4 + tr_fast_pix; if (extra_pix == 0) tr++; @@ -970,8 +970,8 @@ usb_GetMotorParam( Plustek_Device *dev, ScanParam *pParam ) } else if(pParam->PhyDpi.x <= 400) { - regs[0x56] = 8; - regs[0x57] = 48; + regs[0x56] = 8; + regs[0x57] = 48; } else if(pParam->PhyDpi.x <= 600) { @@ -1184,7 +1184,7 @@ usb_SetScanParameters( Plustek_Device *dev, ScanParam *pParam ) usb_GetScanRect ( dev, pParam ); usb_PresetStepSize( dev, pParam ); - + if( dev->caps.dwFlag & SFLAG_ADF ) { if( pParam->bCalibration == PARAM_Scan ) { @@ -1251,7 +1251,7 @@ usb_SetScanParameters( Plustek_Device *dev, ScanParam *pParam ) /* Compute the number of lines to scan using actual Y resolution */ usb_GetScanLinesAndSize( dev, pParam ); - + /* Pause limit should be bounded by total bytes to read * so that the chassis will not move too far. */ @@ -1316,7 +1316,7 @@ usb_SetScanParameters( Plustek_Device *dev, ScanParam *pParam ) _UIO(sanei_lm983x_write( dev->fd, 0x08, ®s[0x08], 0x7f - 0x08+1, SANE_TRUE)); usleep(100); - + if( !usbio_WriteReg( dev->fd, 0x07, 0 )) return SANE_FALSE; @@ -1363,7 +1363,7 @@ usb_ScanBegin( Plustek_Device *dev, SANE_Bool auto_park ) DBG( _DBG_INFO, "ScanBegin() - Cancel detected...\n" ); return SANE_FALSE; } - + _UIO(usbio_ReadReg( dev->fd, 0x01, &m_bOldScanData )); if( m_bOldScanData ) { @@ -1373,7 +1373,7 @@ usb_ScanBegin( Plustek_Device *dev, SANE_Bool auto_park ) DBG(_DBG_INFO,"Flushing cache - %lu bytes (bOldScanData=%u)\n", dwBytesToRead, m_bOldScanData ); - _UIO(sanei_lm983x_read( dev->fd, 0x00, pBuffer, + _UIO(sanei_lm983x_read( dev->fd, 0x00, pBuffer, dwBytesToRead, SANE_FALSE )); free( pBuffer ); @@ -1430,7 +1430,7 @@ usb_ScanEnd( Plustek_Device *dev ) usb_ModuleToHome( dev, SANE_FALSE ); } else if( SANE_TRUE == cancelRead ) { - + usb_ModuleToHome( dev, SANE_FALSE ); } return SANE_TRUE; @@ -1453,14 +1453,14 @@ usb_IsDataAvailableInDRAM( Plustek_Device *dev ) DBG( _DBG_INFO, "usb_IsDataAvailableInDRAM()\n" ); - gettimeofday( &t, NULL); + gettimeofday( &t, NULL); dwTicks = t.tv_sec + 30; for(;;) { _UIO( sanei_lm983x_read( dev->fd, 0x01, a_bBand, 3, SANE_FALSE )); - gettimeofday( &t, NULL); + gettimeofday( &t, NULL); if( t.tv_sec > dwTicks ) break; @@ -1468,7 +1468,7 @@ usb_IsDataAvailableInDRAM( Plustek_Device *dev ) DBG(_DBG_INFO,"usb_IsDataAvailableInDRAM() - Cancel detected...\n"); return SANE_FALSE; } - + /* It is not stable for read */ if((a_bBand[0] != a_bBand[1]) && (a_bBand[1] != a_bBand[2])) continue; @@ -1549,7 +1549,7 @@ usb_GetImageInfo( Plustek_Device *dev, ImgDef *pInfo, WinInfo *pSize ) case COLOR_TRUE48: pSize->dwBytes = pSize->dwPixels * 6UL; break; - + case COLOR_TRUE24: if( dev->scanning.fGrayFromColor > 7 ){ pSize->dwBytes = (pSize->dwPixels + 7UL) >> 3; @@ -1597,7 +1597,7 @@ usb_SaveImageInfo( Plustek_Device *dev, ImgDef *pInfo ) case COLOR_TRUE48: pParam->bBitDepth = 16; /* fall through... */ - + case COLOR_TRUE24: pParam->bDataType = SCANDATATYPE_Color; @@ -1638,7 +1638,7 @@ usb_SaveImageInfo( Plustek_Device *dev, ImgDef *pInfo ) * sheetfed device to avoid stripes in the resulting pictures */ if( usb_IsSheetFedDevice(dev)) { - + int step, div, org, xdpi; xdpi = usb_SetAsicDpiX( dev, pParam->UserDpi.x ); diff --git a/backend/plustek-usbshading.c b/backend/plustek-usbshading.c index 6d08dc7..98a28d9 100644 --- a/backend/plustek-usbshading.c +++ b/backend/plustek-usbshading.c @@ -282,9 +282,9 @@ static void usb_SetMCLK( Plustek_Device *dev, ScanParam *param ) HWDef *hw = &dev->usbDev.HwSetting; dMCLK = usb_GetMCLK( dev, param ); - param->dMCLK = dMCLK; + param->dMCLK = dMCLK; - DBG( _DBG_INFO, "SETMCLK[%u/%u]: %.3f\n", + DBG( _DBG_INFO, "SETMCLK[%u/%u]: %.3f\n", hw->motorModel, param->bDataType, dMCLK ); } @@ -314,14 +314,14 @@ static SANE_Bool usb_SetDarkShading( Plustek_Device *dev, u_char channel, /* Download offset coefficients */ if( SANE_STATUS_GOOD == res ) { - + res = sanei_lm983x_write( dev->fd, 0x06, (u_char*)coeff_buffer, wCount, SANE_FALSE ); if( SANE_STATUS_GOOD == res ) return SANE_TRUE; } } - + DBG( _DBG_ERROR, "usb_SetDarkShading() failed\n" ); return SANE_FALSE; } @@ -358,7 +358,7 @@ static SANE_Bool usb_SetWhiteShading( Plustek_Device *dev, u_char channel, return SANE_TRUE; } } - + DBG( _DBG_ERROR, "usb_SetWhiteShading() failed\n" ); return SANE_FALSE; } @@ -416,7 +416,7 @@ static void usb_GetSWOffsetGain( Plustek_Device *dev ) param->swGain[2] = 800; #endif break; - + case kNECSLIM: DBG( _DBG_INFO2, "kNECSLIM adjustments\n" ); if( param->PhyDpi.x <= 150 ) { @@ -651,11 +651,11 @@ static void usb_GetSWOffsetGain( Plustek_Device *dev ) param->swOffset[0] = -304; param->swOffset[1] = -304; param->swOffset[2] = -304; - param->swGain[0] = 910; - param->swGain[1] = 920; + param->swGain[0] = 910; + param->swGain[1] = 920; param->swGain[2] = 975; } - + if(param->bDataType == SCANDATATYPE_BW && param->PhyDpi.x <= 300) { param->swOffset[1] = 1000; @@ -703,7 +703,7 @@ static u_char usb_GetNewGain( Plustek_Device *dev, u_short wMax, int channel ) bGain = (u_char)dAmp + 32; } - + if( bGain > 0x3f ) { DBG( _DBG_INFO, "* GAIN Overflow!!!\n" ); bGain = 0x3f; @@ -734,7 +734,7 @@ static void setAdjGain( int gain, u_char *reg ) * @param l_off - * @return */ -static SANE_Bool adjLampSetting( Plustek_Device *dev, int channel, u_long max, +static SANE_Bool adjLampSetting( Plustek_Device *dev, int channel, u_long max, u_long ideal, u_short l_on, u_short *l_off ) { SANE_Bool adj = SANE_FALSE; @@ -796,7 +796,7 @@ static SANE_Bool usb_AdjustGain( Plustek_Device *dev, int fNegative ) DBG( _DBG_INFO, "#########################\n" ); DBG( _DBG_INFO, "usb_AdjustGain()\n" ); - if((dev->adj.rgain != -1) && + if((dev->adj.rgain != -1) && (dev->adj.ggain != -1) && (dev->adj.bgain != -1)) { setAdjGain( dev->adj.rgain, ®s[0x3b] ); setAdjGain( dev->adj.ggain, ®s[0x3c] ); @@ -871,7 +871,7 @@ TOGAIN: dumpPicInit(&m_ScanParam, tmp); dumpPic(tmp, (u_char*)scanbuf, m_ScanParam.Size.dwPhyBytes, 0); - + #ifdef SWAP_COARSE if(usb_HostSwap()) #endif @@ -913,7 +913,7 @@ TOGAIN: Gain_Hilight.Green = (u_short)(rgb.Green / 20UL); Gain_Hilight.Blue = (u_short)(rgb.Blue / 20UL); DBG(_DBG_INFO2, "MAX(R,G,B)= 0x%04x(%u), 0x%04x(%u), 0x%04x(%u)\n", - Gain_Hilight.Red, Gain_Hilight.Red, Gain_Hilight.Green, + Gain_Hilight.Red, Gain_Hilight.Red, Gain_Hilight.Green, Gain_Hilight.Green, Gain_Hilight.Blue, Gain_Hilight.Blue ); regs[0x3b] = usb_GetNewGain(dev,Gain_Hilight.Red, 0 ); @@ -945,7 +945,7 @@ TOGAIN: regs[0x3c] = regs[0x3d] = usb_GetNewGain(dev,Gain_Hilight.Green,1); } } else { - + if( m_ScanParam.bDataType == SCANDATATYPE_Color ) { RGBUShortDef max_rgb, min_rgb, tmp_rgb; @@ -1055,7 +1055,7 @@ TOGAIN: scanning->sParam.dMCLK = dMCLK = dMCLK - 0.5; regs[0x3b] = regs[0x3c] = regs[0x3d] = 1; - + adj = SANE_TRUE; } else if(((regs[0x3b] == 63) || (regs[0x3c] == 63) || @@ -1072,7 +1072,7 @@ TOGAIN: goto TOGAIN; } } - + } else { /* for MODEL KaoHsiung 1200 scanner multi-straight-line bug at @@ -1265,7 +1265,7 @@ static SANE_Bool usb_AdjustOffset( Plustek_Device *dev ) DBG( _DBG_INFO, "#########################\n" ); DBG( _DBG_INFO, "usb_AdjustOffset()\n" ); - if((dev->adj.rofs != -1) && + if((dev->adj.rofs != -1) && (dev->adj.gofs != -1) && (dev->adj.bofs != -1)) { regs[0x38] = (dev->adj.rofs & 0x3f); regs[0x39] = (dev->adj.gofs & 0x3f); @@ -1329,10 +1329,10 @@ static SANE_Bool usb_AdjustOffset( Plustek_Device *dev ) DBG( _DBG_ERROR, "usb_AdjustOffset() failed\n" ); return SANE_FALSE; } - + i = 0; - DBG( _DBG_INFO2, "S.dwPixels = %lu\n", m_ScanParam.Size.dwPixels ); + DBG( _DBG_INFO2, "S.dwPixels = %lu\n", m_ScanParam.Size.dwPixels ); DBG( _DBG_INFO2, "dwPixels = %lu\n", dwPixels ); DBG( _DBG_INFO2, "dwPhyBytes = %lu\n", m_ScanParam.Size.dwPhyBytes ); DBG( _DBG_INFO2, "dwPhyPixels = %lu\n", m_ScanParam.Size.dwPhyPixels ); @@ -1350,7 +1350,7 @@ static SANE_Bool usb_AdjustOffset( Plustek_Device *dev ) } sprintf( tmp, "coarse-off-%u.raw", i++ ); - + #ifdef SWAP_COARSE if(usb_HostSwap()) usb_Swap((u_short *)scanbuf, m_ScanParam.Size.dwPhyBytes ); @@ -1380,7 +1380,7 @@ static SANE_Bool usb_AdjustOffset( Plustek_Device *dev ) dwSum[1], dwSum[1] /dwPixels ); DBG( _DBG_INFO2, "BlueSum = %lu, ave = %lu\n", dwSum[2], dwSum[2] /dwPixels ); - + /* do averaging for each channel */ dwSum[0] /= dwPixels; dwSum[1] /= dwPixels; @@ -1422,7 +1422,7 @@ static SANE_Bool usb_AdjustOffset( Plustek_Device *dev ) regs[0x3a] = bExpect[2]; } else { - regs[0x38] = regs[0x39] = regs[0x3a] = bExpect[0]; + regs[0x38] = regs[0x39] = regs[0x3a] = bExpect[0]; } DBG( _DBG_INFO2, "REG[0x38] = %u\n", regs[0x38] ); @@ -1445,7 +1445,7 @@ static SANE_Bool usb_AdjustOffset( Plustek_Device *dev ) /** this function tries to find out some suitable values for the dark * fine calibration. If the device owns a black calibration strip - * the data is simply copied. If not, then the white strip is read + * the data is simply copied. If not, then the white strip is read * with the lamp switched off... */ static void usb_GetDarkShading( Plustek_Device *dev, u_short *pwDest, @@ -1527,7 +1527,7 @@ static void usb_GetDarkShading( Plustek_Device *dev, u_short *pwDest, for( dw = 0; dw < dwPixels; dw++ ) pwDest[dw] = (u_short)dwSum[dw & 1]; } else { - + /* Standard CCD */ /* do some averaging on the line */ @@ -1643,7 +1643,7 @@ static SANE_Bool usb_AdjustDarkShading( Plustek_Device *dev ) DBG( _DBG_ERROR, "usb_AdjustDarkShading() failed\n" ); return SANE_FALSE; } - + /* set illumination mode and switch lamp on again */ regs[0x29] = hw->bReg_0x29; @@ -1720,7 +1720,7 @@ static SANE_Bool usb_AdjustDarkShading( Plustek_Device *dev ) * @param hilight - defines the number of values to skip. * @param shading_lines - defines the overall number of shading lines. */ -static void usb_CalSortHighlight( Plustek_Device *dev, ScanParam *sp, +static void usb_CalSortHighlight( Plustek_Device *dev, ScanParam *sp, u_long hilight, u_long shading_lines ) { ScanDef *scan = &dev->scanning; @@ -1766,7 +1766,7 @@ static void usb_CalSortHighlight( Plustek_Device *dev, ScanParam *sp, /** function to remove the brightest values out of each row * @param dev - the almighty device structure. - * @param sp - is a pointer to the scanparam structure used for + * @param sp - is a pointer to the scanparam structure used for * scanning the shading lines. * @param hilight - defines the number of values to skip. * @param shading_lines - defines the overall number of shading lines. @@ -1822,7 +1822,7 @@ static void usb_procHighlightAndShadow( Plustek_Device *dev, ScanParam *sp, pg = pr + sp->Size.dwPhyPixels; pb = pg + sp->Size.dwPhyPixels; - memset(pr, 0, sp->Size.dwPhyPixels * 4UL * 3UL); + memset(pr, 0, sp->Size.dwPhyPixels * sizeof(*pr) * 3UL); /* Sort hilight */ usb_CalSortHighlight(dev, sp, hilight, shading_lines); @@ -1865,13 +1865,13 @@ static SANE_Bool usb_AdjustWhiteShading( Plustek_Device *dev ) u_short hilight, shadow; int i; SANE_Bool swap = usb_HostSwap(); - + if( scaps->workaroundFlag & _WAF_SKIP_FINE ) return SANE_TRUE; DBG( _DBG_INFO, "#########################\n" ); DBG( _DBG_INFO, "usb_AdjustWhiteShading()\n" ); - + m_pAvMono = (u_short*)scan->pScanBuffer; if( usb_IsEscPressed()) @@ -1904,7 +1904,7 @@ static SANE_Bool usb_AdjustWhiteShading( Plustek_Device *dev ) if( usb_IsCISDevice(dev) && m_ScanParam.bDataType == SCANDATATYPE_Color ) m_ScanParam.Size.dwBytes *= 3; - m_dwPixels = scan->sParam.Size.dwPixels * m_ScanParam.UserDpi.x / + m_dwPixels = scan->sParam.Size.dwPixels * m_ScanParam.UserDpi.x / scan->sParam.UserDpi.x; dw = (u_long)(hw->wDRAMSize - 196 /*192 KiB*/) * 1024UL; @@ -1950,7 +1950,7 @@ static SANE_Bool usb_AdjustWhiteShading( Plustek_Device *dev ) if( 0 == dwRead ) { dumpPicInit(&m_ScanParam, tmp); } - + dumpPic(tmp, (u_char*)pBuf + dwRead, m_ScanParam.Size.dwTotalBytes, 0); if( usb_ScanEnd( dev )) { @@ -1965,7 +1965,7 @@ static SANE_Bool usb_AdjustWhiteShading( Plustek_Device *dev ) } m_pSum = (u_long*)((u_char*)pBuf + m_ScanParam.Size.dwPhyBytes * shading_lines); - + /* * do some reordering on CIS based devices: * from RRRRRRR.... GGGGGGGG.... BBBBBBBBB, create RGB RGB RGB ... @@ -2017,7 +2017,7 @@ static SANE_Bool usb_AdjustWhiteShading( Plustek_Device *dev ) #ifdef SWAP_FINE if(usb_HostSwap()) { #endif - for( dw = 0; dw < m_dwPixels * m_ScanParam.bChannels; dw++ ) + for( dw = 0; dw < m_dwPixels * m_ScanParam.bChannels; dw++ ) pwDest[dw] = _HILO2WORD(pwSrce[dw]); #ifdef SWAP_FINE } else { @@ -2077,7 +2077,7 @@ static SANE_Bool usb_AdjustWhiteShading( Plustek_Device *dev ) pValue->Mono = 65535U; else pValue->Mono = (u_short)*pdw; - + if (pValue->Mono > 16384U) pValue->Mono = (u_short)(GAIN_Target * 16384U / pValue->Mono); else @@ -2153,7 +2153,7 @@ static SANE_Bool usb_AdjustWhiteShading( Plustek_Device *dev ) if( scan->sParam.bSource != SOURCE_Negative ) { for( dw = 0; dw < m_ScanParam.Size.dwPhyPixels; dw++) { - + pdw[dw] = pdw[dw] * 1000 /((shading_lines-hilight-shadow) * scan->sParam.swGain[1]); if( pdw[dw] > 65535U ) @@ -2172,7 +2172,7 @@ static SANE_Bool usb_AdjustWhiteShading( Plustek_Device *dev ) #endif _SWAP(pValue[dw].HiLo.bHi, pValue[dw].HiLo.bLo); } - + } else{ for( dw = 0; dw < m_ScanParam.Size.dwPhyPixels; dw++ ) { @@ -2200,17 +2200,17 @@ static void usb_ResizeWhiteShading( double dAmp, u_short *pwShading, int iGain ) { u_long dw, dwAmp; u_short w; - + DBG( _DBG_INFO2, "ResizeWhiteShading: dAmp=%.3f, iGain=%i\n", dAmp, iGain ); for( dw = 0; dw < m_ScanParam.Size.dwPhyPixels; dw++ ) { - + dwAmp = (u_long)(GAIN_Target * 0x4000 / (pwShading[dw] + 1) * dAmp) * iGain / 1000; if( dwAmp <= GAIN_Target) w = (u_short)dwAmp; - else + else w = GAIN_Target; #ifndef SWAP_FINE @@ -2252,14 +2252,14 @@ usb_PrepareCalibration( Plustek_Device *dev ) m_ScanParam.bDataType = SCANDATATYPE_Gray; usb_SetMCLK( dev, &m_ScanParam ); - + /* preset these registers offset/gain */ regs[0x38] = regs[0x39] = regs[0x3a] = 0; regs[0x3b] = regs[0x3c] = regs[0x3d] = 1; regs[0x45] &= ~0x10; - memset( a_wWhiteShading, 0, _SHADING_BUF ); - memset( a_wDarkShading, 0, _SHADING_BUF ); + memset( a_wWhiteShading, 0, _SHADING_BUF * sizeof(a_wWhiteShading[0]) ); + memset( a_wDarkShading, 0, _SHADING_BUF * sizeof(a_wDarkShading[0]) ); scan->skipCoarseCalib = SANE_FALSE; @@ -2319,7 +2319,7 @@ usb_SpeedTest( Plustek_Device *dev ) DBG( 1, "#########################\n" ); DBG( 1, "usb_SpeedTest(%d,%lu)\n", dev->initialized, dev->transferRate ); if( dev->transferRate != DEFAULT_RATE ) { - DBG( 1, "* skipped, using already detected speed: %lu Bytes/s\n", + DBG( 1, "* skipped, using already detected speed: %lu Bytes/s\n", dev->transferRate ); return SANE_TRUE; } @@ -2358,7 +2358,7 @@ usb_SpeedTest( Plustek_Device *dev ) DBG( _DBG_ERROR, "usb_SpeedTest() failed\n" ); return SANE_FALSE; } - if (!usb_IsDataAvailableInDRAM( dev )) + if (!usb_IsDataAvailableInDRAM( dev )) return SANE_FALSE; m_fFirst = SANE_FALSE; @@ -2377,7 +2377,7 @@ usb_SpeedTest( Plustek_Device *dev ) tr = ((double)m_ScanParam.Size.dwPhyBytes * _TLOOPS * 1000000.0)/r; dev->transferRate = (u_long)tr; - DBG( 1, "usb_SpeedTest() done - %u loops, %.4fus --> %.4f B/s, %lu\n", + DBG( 1, "usb_SpeedTest() done - %u loops, %.4fus --> %.4f B/s, %lu\n", _TLOOPS, r, tr, dev->transferRate ); return SANE_TRUE; } @@ -2459,7 +2459,7 @@ usb_AutoWarmup( Plustek_Device *dev ) thresh = _AUTO_TPA_THRESH; } end = start + len; - DBG( _DBG_INFO2, "Start=%lu, End=%lu, Len=%lu, Thresh=%li\n", + DBG( _DBG_INFO2, "Start=%lu, End=%lu, Len=%lu, Thresh=%li\n", start, end, len, thresh ); lastR = lastG = lastB = 0; @@ -2485,7 +2485,7 @@ usb_AutoWarmup( Plustek_Device *dev ) curR = curG = curB = 0; for( dw = start; dw < end; dw++ ) { - + if( usb_IsCISDevice(dev)) { curR += ((u_short*)scanbuf)[dw]; curG += ((u_short*)scanbuf)[dw+m_ScanParam.Size.dwPhyPixels+1]; @@ -2503,7 +2503,7 @@ usb_AutoWarmup( Plustek_Device *dev ) diffR = curR - lastR; lastR = curR; diffG = curG - lastG; lastG = curG; diffB = curB - lastB; lastB = curB; - DBG( _DBG_INFO2, "%i/%i-AVE(R,G,B)= %lu(%ld), %lu(%ld), %lu(%ld)\n", + DBG( _DBG_INFO2, "%i/%i-AVE(R,G,B)= %lu(%ld), %lu(%ld), %lu(%ld)\n", i, stable_count, curR, diffR, curG, diffG, curB, diffB ); /* we consider the lamp to be stable, @@ -2523,7 +2523,7 @@ usb_AutoWarmup( Plustek_Device *dev ) } DBG( _DBG_INFO, "usb_AutoWarmup() done - %u loops\n", i+1 ); - DBG( _DBG_INFO, "* AVE(R,G,B)= %lu(%ld), %lu(%ld), %lu(%ld)\n", + DBG( _DBG_INFO, "* AVE(R,G,B)= %lu(%ld), %lu(%ld), %lu(%ld)\n", curR, diffR, curG, diffG, curB, diffB ); return SANE_TRUE; } @@ -2608,8 +2608,8 @@ usb_DoCalibration( Plustek_Device *dev ) /* HEINER: Currently not clear why Plustek didn't use the ShadingOriginY * for all modes * It should be okay to remove this and reference to the ShadingOriginY - */ -#if 0 + */ +#if 0 if( scanning->sParam.bSource == SOURCE_Negative ) { DBG( _DBG_INFO, "DataOrigin.x=%u, DataOrigin.y=%u\n", @@ -2707,7 +2707,7 @@ usb_DoCalibration( Plustek_Device *dev ) Gain_Reg.Green = regs[0x3c]; Gain_Reg.Blue = regs[0x3d]; Gain_NegHilight = Gain_Hilight; - + DBG( _DBG_INFO, "MCLK = %.3f\n", dMCLK ); DBG( _DBG_INFO, "GainRed = %u\n", regs[0x3b] ); DBG( _DBG_INFO, "GainGreen = %u\n", regs[0x3c] ); @@ -2727,7 +2727,7 @@ usb_DoCalibration( Plustek_Device *dev ) if(!usb_AdjustGain( dev, 1 )) return _E_INTERNAL; - + regs[0x3b] = regs[0x3c] = regs[0x3d] = 1; DBG( _DBG_INFO, "Settings done, so start...\n" ); @@ -2763,7 +2763,7 @@ usb_DoCalibration( Plustek_Device *dev ) m_ScanParam.Size.dwPhyPixels*2, scanning->sParam.swGain[2]); } - usb_line_statistics( "White", a_wWhiteShading, + usb_line_statistics( "White", a_wWhiteShading, m_ScanParam.Size.dwPhyPixels, SANE_TRUE); break; @@ -2904,7 +2904,7 @@ usb_DoCalibration( Plustek_Device *dev ) */ hw->wLineEnd = 5384; if(scanning->sParam.bDataType == SCANDATATYPE_Color && - ((scanning->sParam.bBitDepth == 8 && + ((scanning->sParam.bBitDepth == 8 && (scanning->sParam.PhyDpi.x == 200 ||scanning->sParam.PhyDpi.x == 300)))) hw->wLineEnd = 7000; regs[0x20] = _HIBYTE(hw->wLineEnd); @@ -3127,8 +3127,8 @@ usb_DownloadShadingData( Plustek_Device *dev, u_char what ) if (scan->skipCoarseCalib) { DBG( _DBG_INFO, "...cleaning shading buffer\n" ); - memset( a_wWhiteShading, 0, _SHADING_BUF ); - memset( a_wDarkShading, 0, _SHADING_BUF ); + memset( a_wWhiteShading, 0, _SHADING_BUF * sizeof(a_wWhiteShading[0]) ); + memset( a_wDarkShading, 0, _SHADING_BUF * sizeof(a_wDarkShading[0]) ); regs[0x40] = 0x3f; regs[0x41] = 0xff; @@ -3161,7 +3161,7 @@ usb_DownloadShadingData( Plustek_Device *dev, u_char what ) } if( param->bDataType == SCANDATATYPE_Color ) { - get_ptrs(dev, a_wWhiteShading, + get_ptrs(dev, a_wWhiteShading, m_ScanParam.Size.dwPhyPixels, &r, &g, &b); usb_SetWhiteShading( dev, CHANNEL_red, r, diff --git a/backend/plustek.c b/backend/plustek.c index 062df37..e1d9e09 100644 --- a/backend/plustek.c +++ b/backend/plustek.c @@ -129,9 +129,9 @@ /** @mainpage * @verbinclude Plustek-USB.txt */ - + #ifdef _AIX -# include "../include/lalloca.h" +# include "../include/lalloca.h" #endif #include "../include/sane/config.h" @@ -239,9 +239,9 @@ static const SANE_String_Const source_list[] = static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 1 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(-100), /* minimum */ + SANE_FIX( 100), /* maximum */ + SANE_FIX( 1) /* quantization */ }; static const SANE_Range warmup_range = { -1, 999, 1 }; @@ -339,7 +339,7 @@ getScanMode( Plustek_Scanner *scanner ) { int mode; int scanmode; - + /* are we in TPA-mode? */ mode = scanner->val[OPT_MODE].w; if( scanner->val[OPT_EXT_MODE].w != 0 ) @@ -384,7 +384,7 @@ max_string_size (const SANE_String_Const strings[]) /** shutdown open pipes */ -static SANE_Status +static SANE_Status close_pipe( Plustek_Scanner *scanner ) { if( scanner->r_pipe >= 0 ) { @@ -550,7 +550,7 @@ reader_process( void *args ) (int)status, lerrn ); if( _E_ABORT == (int)status ) return SANE_STATUS_CANCELLED; - + if( lerrn == EBUSY ) return SANE_STATUS_DEVICE_BUSY; @@ -574,7 +574,7 @@ do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe ) if( sanei_thread_is_valid (scanner->reader_pid) ) { - DBG( _DBG_PROC, ">>>>>>>> killing reader_process <<<<<<<<\n" ); + DBG( _DBG_PROC, "---- killing reader_process ----\n" ); cancelRead = SANE_TRUE; scanner->calibrating = SANE_FALSE; @@ -604,7 +604,7 @@ do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe ) #endif } - scanner->reader_pid = -1; + sanei_thread_invalidate( scanner->reader_pid ); DBG( _DBG_PROC,"reader_process killed\n"); #ifndef HAVE_SETITIMER usb_StartLampTimer( scanner->hw ); @@ -746,7 +746,7 @@ init_options( Plustek_Scanner *s ) else s->opt[OPT_BIT_DEPTH].constraint.word_list = bpp_lm9832_list; s->val[OPT_BIT_DEPTH].w = 8; - + if (caps->workaroundFlag & _WAF_ONLY_8BIT) _DISABLE(OPT_BIT_DEPTH); @@ -851,7 +851,7 @@ init_options( Plustek_Scanner *s ) s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY); /* "Enhancement" group: */ - s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement"); + s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement"); s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; @@ -899,7 +899,7 @@ init_options( Plustek_Scanner *s ) s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(s->gamma_range); s->opt[OPT_GAMMA_VECTOR_B].size = s->gamma_length * sizeof(SANE_Word); - /* GAMMA stuff is disabled per default */ + /* GAMMA stuff is disabled per default */ _DISABLE(OPT_GAMMA_VECTOR); _DISABLE(OPT_GAMMA_VECTOR_R); _DISABLE(OPT_GAMMA_VECTOR_G); @@ -996,7 +996,7 @@ init_options( Plustek_Scanner *s ) s->opt[OPT_AFE_GROUP].desc = ""; s->opt[OPT_AFE_GROUP].type = SANE_TYPE_GROUP; s->opt[OPT_AFE_GROUP].cap = SANE_CAP_ADVANCED; - + s->opt[OPT_OVR_REDGAIN].name = "red-gain"; s->opt[OPT_OVR_REDGAIN].title = SANE_I18N("Red gain"); s->opt[OPT_OVR_REDGAIN].desc = SANE_I18N("Red gain value of the AFE"); @@ -1118,8 +1118,8 @@ init_options( Plustek_Scanner *s ) */ static void decodeUsbIDs( char *src, char **dest ) -{ - const char *name; +{ + const char *name; char *tmp = *dest; int len = strlen(_SECTION); @@ -1134,11 +1134,11 @@ decodeUsbIDs( char *src, char **dest ) if( '\0' == name[0] ) { DBG( _DBG_SANE_INIT, "next device uses autodetection\n" ); } else { - + u_short pi = 0, vi = 0; if( *name ) { - + name = sanei_config_get_string( name, &tmp ); if( tmp ) { vi = strtol( tmp, 0, 0 ); @@ -1208,7 +1208,7 @@ decodeVal( char *src, char *opt, int what, void *result, void *def ) free( tmp2 ); } } - free( tmp ); + free( tmp ); return SANE_TRUE; } else if( _FLOAT == what ) { @@ -1226,7 +1226,7 @@ decodeVal( char *src, char *opt, int what, void *result, void *def ) free( tmp2 ); } } - free( tmp ); + free( tmp ); return SANE_TRUE; } } @@ -1245,7 +1245,7 @@ decodeVal( char *src, char *opt, int what, void *result, void *def ) static SANE_Bool decodeDevName( char *src, char *dest ) { - char *tmp; + char *tmp; const char *name; if( 0 == strncmp( "device", src, 6 )) { @@ -1360,7 +1360,7 @@ attach( const char *dev_name, CnfDef *cnf, Plustek_Device **devp ) */ dev->res_list = (SANE_Int *) calloc((((dev->usbDev.Caps.OpticDpi.x*16)-_DEF_DPI)/25+1), - sizeof (SANE_Int)); + sizeof (SANE_Int)); if (NULL == dev->res_list) { DBG( _DBG_ERROR, "calloc failed: %s\n", strerror(errno)); @@ -1565,10 +1565,10 @@ sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) /* re-initialize the configuration structure */ init_config_struct( &config ); - + tmp = config.usbId; decodeUsbIDs( str, &tmp ); - + DBG( _DBG_SANE_INIT, "... next device\n" ); continue; @@ -1613,7 +1613,7 @@ sane_exit( void ) if( dev->calFile ) free( dev->calFile ); - + if( dev->res_list ) free( dev->res_list ); free( dev ); @@ -1807,7 +1807,7 @@ do_calibration( void *args ) continue; } } - + dev->scanning.dwFlag |= SCANFLAG_Calibration; if (SANE_STATUS_GOOD == local_sane_start(s, modes[scanmode])) { @@ -1937,7 +1937,7 @@ sane_control_option( SANE_Handle handle, SANE_Int option, strcpy ((char *) value, s->opt[option].constraint.string_list[s->val[option].w]); break; - + /* word array options: */ case OPT_GAMMA_VECTOR: DBG( _DBG_INFO, "Reading MASTER gamma.\n" ); @@ -2000,7 +2000,7 @@ sane_control_option( SANE_Handle handle, SANE_Int option, *(SANE_Word *)value = best; if( NULL != info ) { - if( v != best ) + if( v != best ) *info |= SANE_INFO_INEXACT; *info |= SANE_INFO_RELOAD_PARAMS; } @@ -2165,10 +2165,10 @@ sane_control_option( SANE_Handle handle, SANE_Int option, ((*(SANE_Word *)value) >> SANE_FIXED_SCALE_SHIFT); break; - case OPT_MODE: + case OPT_MODE: s->val[option].w = optval - s->opt[option].constraint.string_list; scanmode = getScanMode( s ); - + _ENABLE(OPT_CONTRAST); _ENABLE(OPT_BIT_DEPTH); _ENABLE(OPT_CUSTOM_GAMMA); @@ -2447,9 +2447,9 @@ local_sane_start(Plustek_Scanner *s, int scanmode ) } /* position and extent are always relative to 300 dpi */ - dpi_x = (double)dev->usbDev.Caps.OpticDpi.x; + dpi_x = (double)dev->usbDev.Caps.OpticDpi.x; dpi_y = (double)dev->usbDev.Caps.OpticDpi.x * 2; - + left = (int)(SANE_UNFIX (s->val[OPT_TL_X].w)*dpi_x/ (MM_PER_INCH*(dpi_x/300.0))); top = (int)(SANE_UNFIX (s->val[OPT_TL_Y].w)*dpi_y/ @@ -2504,7 +2504,7 @@ local_sane_start(Plustek_Scanner *s, int scanmode ) sinfo.siContrast = s->val[OPT_CONTRAST].w; memcpy( &sinfo.ImgDef, &crop.ImgDef, sizeof(ImgDef)); - + DBG( _DBG_SANE_INIT, "brightness %i, contrast %i\n", sinfo.siBrightness, sinfo.siContrast ); @@ -2628,7 +2628,7 @@ sane_start( SANE_Handle handle ) s->reader_pid = sanei_thread_begin( reader_process, s ); cancelRead = SANE_FALSE; - + if( !sanei_thread_is_valid (s->reader_pid) ) { DBG( _DBG_ERROR, "ERROR: could not start reader task\n" ); s->scanning = SANE_FALSE; @@ -2687,7 +2687,7 @@ sane_read( SANE_Handle handle, SANE_Byte *data, } } s->hw->transferRate = ipc.transferRate; - DBG( _DBG_INFO, "IPC: Transferrate = %lu Bytes/s\n", + DBG( _DBG_INFO, "IPC: Transferrate = %lu Bytes/s\n", ipc.transferRate ); } #endif @@ -2706,7 +2706,7 @@ sane_read( SANE_Handle handle, SANE_Byte *data, if( s->bytes_read == (unsigned long)(s->params.lines * s->params.bytes_per_line)) { sanei_thread_waitpid( s->reader_pid, 0 ); - s->reader_pid = -1; + sanei_thread_invalidate( s->reader_pid ); s->scanning = SANE_FALSE; drvclose( s->hw ); return close_pipe(s); @@ -2735,7 +2735,7 @@ sane_read( SANE_Handle handle, SANE_Byte *data, close_pipe(s); return s->exit_code; } - s->reader_pid = -1; + sanei_thread_invalidate( s->reader_pid ); s->scanning = SANE_FALSE; return close_pipe(s); } @@ -2773,7 +2773,7 @@ sane_set_io_mode( SANE_Handle handle, SANE_Bool non_blocking ) DBG( _DBG_ERROR, "ERROR: not supported !\n" ); return SANE_STATUS_UNSUPPORTED; } - + if( fcntl (s->r_pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) { DBG( _DBG_ERROR, "ERROR: could not set to non-blocking mode !\n" ); return SANE_STATUS_IO_ERROR; diff --git a/backend/plustek.conf.in b/backend/plustek.conf.in index e16823e..3d6f947 100644 --- a/backend/plustek.conf.in +++ b/backend/plustek.conf.in @@ -84,7 +84,7 @@ option negShadingY -1 option invertNegatives 0 # -# to disable the internal sensor speedup function, +# to disable the internal sensor speedup function, # 1 disables the feature # option disableSpeedup 0 @@ -180,5 +180,5 @@ device auto # # to define a new device, start with a new section: -# [usb] +# [usb] # diff --git a/backend/plustek.h b/backend/plustek.h index be657c1..cc38f13 100644 --- a/backend/plustek.h +++ b/backend/plustek.h @@ -283,7 +283,7 @@ typedef struct { int rofs; int gofs; int bofs; - + int rlampoff; /* for red lamp off setting (CIS-scanner) */ int glampoff; /* for green lamp off setting (CIS-scanner) */ int blampoff; /* for blue lamp off setting (CIS-scanner) */ @@ -408,7 +408,7 @@ typedef struct Plustek_Scanner /** for collecting configuration info... */ typedef struct { - + char devName[PATH_MAX]; char usbId[_MAX_ID_LEN]; diff --git a/backend/plustek_pp.c b/backend/plustek_pp.c index f48c3dc..551cf27 100644 --- a/backend/plustek_pp.c +++ b/backend/plustek_pp.c @@ -58,7 +58,7 @@ /** @mainpage * @verbinclude Plustek-PARPORT.txt */ - + #ifdef _AIX # include "../include/lalloca.h" /* MUST come first for AIX! */ #endif @@ -216,9 +216,9 @@ static const SANE_String_Const halftone_list[] = static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 1 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(-100), /* minimum */ + SANE_FIX( 100), /* maximum */ + SANE_FIX( 1) /* quantization */ }; /* @@ -304,17 +304,17 @@ static pModeParam getModeList( Plustek_Scanner *scanner ) if((_ASIC_IS_98003 == scanner->hw->caps.AsicID) || (_ASIC_IS_98001 == scanner->hw->caps.AsicID)) { - mp = mode_9800x_params; + mp = mode_9800x_params; } else { - mp = mode_params; - } + mp = mode_params; + } /* * the transparency/negative mode supports only GRAY/COLOR/COLOR32/COLOR48 */ if( 0 != scanner->val[OPT_EXT_MODE].w ) { mp = &mp[_TPAModeSupportMin]; - } + } return mp; } @@ -396,7 +396,7 @@ static int reader_process( void *args ) act.sa_handler = reader_process_sigterm_handler; sigaction( SIGTERM, &act, 0 ); - + data_length = scanner->params.lines * scanner->params.bytes_per_line; DBG( _DBG_PROC, "reader_process:" @@ -407,7 +407,7 @@ static int reader_process( void *args ) DBG( _DBG_FATAL, "NULL Pointer !!!!\n" ); return SANE_STATUS_IO_ERROR; } - + /* here we read all data from the driver... */ if( scanner->hw->readImage ) { @@ -419,7 +419,7 @@ static int reader_process( void *args ) status = scanner->hw->prepare( scanner->hw, buf ); - + if( 0 == status ) { for( line = 0; line < scanner->params.lines; line++ ) { @@ -442,7 +442,7 @@ static int reader_process( void *args ) (int)status, errno ); if( -9009 == (int)status ) return SANE_STATUS_CANCELLED; - + if( errno == EBUSY ) return SANE_STATUS_DEVICE_BUSY; @@ -473,14 +473,14 @@ static SANE_Status do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe ) if( sanei_thread_is_valid( scanner->reader_pid )) { - DBG( _DBG_PROC, ">>>>>>>> killing reader_process <<<<<<<<\n" ); + DBG( _DBG_PROC, "---- killing reader_process ----\n" ); /* tell the driver to stop scanning */ if( -1 != scanner->hw->fd ) { int_cnt = 1; scanner->hw->stopScan( scanner->hw, &int_cnt ); - } - + } + sigemptyset(&(act.sa_mask)); act.sa_flags = 0; @@ -494,19 +494,19 @@ static SANE_Status do_cancel( Plustek_Scanner *scanner, SANE_Bool closepipe ) alarm(10); res = sanei_thread_waitpid( scanner->reader_pid, 0 ); alarm(0); - + if( res != scanner->reader_pid ) { DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n"); - + /* do it the hard way...*/ #ifdef USE_PTHREAD sanei_thread_kill( scanner->reader_pid ); #else sanei_thread_sendsig( scanner->reader_pid, SIGKILL ); #endif - } + } - scanner->reader_pid = -1; + sanei_thread_invalidate( scanner->reader_pid ); DBG( _DBG_PROC,"reader_process killed\n"); } @@ -547,7 +547,7 @@ static void limitResolution( Plustek_Device *dev ) } else { dev->dpi_range.max = lens.rDpiY.wPhyMax; } - + dev->dpi_range.quant = 0; dev->x_range.min = 0; dev->x_range.max = SANE_FIX(dev->max_x); @@ -582,37 +582,37 @@ static SANE_Status initGammaSettings( Plustek_Scanner *s ) s->gamma_length = 256; } - + DBG( _DBG_INFO, "Presetting Gamma tables (len=%u)\n", s->gamma_length ); DBG( _DBG_INFO, "----------------------------------\n" ); - + /* * preset the gamma maps */ for( i = 0; i < 4; i++ ) { - + switch( i ) { case 1: gamma = s->hw->adj.rgamma; break; case 2: gamma = s->hw->adj.ggamma; break; case 3: gamma = s->hw->adj.bgamma; break; default: gamma = s->hw->adj.graygamma; break; - } - + } + for( j = 0; j < s->gamma_length; j++ ) { - + val = (s->gamma_range.max * pow((double) j / ((double)s->gamma_length - 1.0), 1.0 / gamma )); - + if( val > s->gamma_range.max ) val = s->gamma_range.max; - - s->gamma_table[i][j] = val; - } - } - + + s->gamma_table[i][j] = val; + } + } + return SANE_STATUS_GOOD; -} +} /** Check the gamma vectors we got back and limit if necessary * @param s - pointer to the scanner specific structure @@ -685,7 +685,7 @@ static SANE_Status init_options( Plustek_Scanner *s ) s->opt[OPT_EXT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; s->opt[OPT_EXT_MODE].constraint.string_list = ext_mode_list; s->val[OPT_EXT_MODE].w = 0; /* Normal */ - + /* halftone */ s->opt[OPT_HALFTONE].name = SANE_NAME_HALFTONE_PATTERN; s->opt[OPT_HALFTONE].title = SANE_TITLE_HALFTONE; @@ -790,14 +790,14 @@ static SANE_Status init_options( Plustek_Scanner *s ) s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY); /* "Enhancement" group: */ - s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement"); + s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement"); s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - + initGammaSettings( s ); - + /* grayscale gamma vector */ s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; @@ -842,12 +842,12 @@ static SANE_Status init_options( Plustek_Scanner *s ) s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(s->gamma_range); s->opt[OPT_GAMMA_VECTOR_B].size = s->gamma_length * sizeof(SANE_Word); - /* GAMMA stuff is disabled per default */ + /* GAMMA stuff is disabled per default */ s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; - + /* disable extended mode list for devices without TPA */ if( 0 == (s->hw->caps.dwFlag & SFLAG_TPA)) { s->opt[OPT_EXT_MODE].cap |= SANE_CAP_INACTIVE; @@ -856,7 +856,7 @@ static SANE_Status init_options( Plustek_Scanner *s ) /* disable custom gamma, if not supported by the driver... */ if( 0 == (s->hw->caps.dwFlag & SFLAG_CUSTOM_GAMMA)) { s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; - } + } return SANE_STATUS_GOOD; } @@ -885,18 +885,18 @@ static SANE_Bool decodeVal( char *src, char *opt, /* get the name of the option */ name = sanei_config_get_string( name, &tmp ); - if( tmp ) { + if( tmp ) { /* on success, compare wiht the given one */ if( 0 == strcmp( tmp, opt )) { - + DBG( _DBG_SANE_INIT, "Decoding option >%s<\n", opt ); if( _INT == what ) { - + /* assign the default value for this option... */ *((int*)result) = *((int*)def); - + if( *name ) { /* get the configuration value and decode it */ @@ -907,14 +907,14 @@ static SANE_Bool decodeVal( char *src, char *opt, free( tmp2 ); } } - free( tmp ); + free( tmp ); return SANE_TRUE; - + } else if( _FLOAT == what ) { - + /* assign the default value for this option... */ *((double*)result) = *((double*)def); - + if( *name ) { /* get the configuration value and decode it */ @@ -925,13 +925,13 @@ static SANE_Bool decodeVal( char *src, char *opt, free( tmp2 ); } } - free( tmp ); + free( tmp ); return SANE_TRUE; } - } + } free( tmp ); } - + return SANE_FALSE; } @@ -944,27 +944,27 @@ static SANE_Bool decodeVal( char *src, char *opt, */ static SANE_Bool decodeDevName( char *src, char *dest ) { - char *tmp; + char *tmp; const char *name; if( 0 == strncmp( "device", src, 6 )) { name = (const char*)&src[strlen("device")]; name = sanei_config_skip_whitespace( name ); - + DBG( _DBG_SANE_INIT, "Decoding device name >%s<\n", name ); - + if( *name ) { name = sanei_config_get_string( name, &tmp ); if( tmp ) { - + strcpy( dest, tmp ); free( tmp ); return SANE_TRUE; } - } + } } - + return SANE_FALSE; } @@ -1000,7 +1000,7 @@ static SANE_Status attach( const char *dev_name, pCnfDef cnf, /* assign all the stuff we need fo this device... */ memset(dev, 0, sizeof (*dev)); - + dev->fd = -1; dev->name = strdup(dev_name); /* hold it double to avoid */ dev->sane.name = dev->name; /* compiler warnings */ @@ -1067,7 +1067,7 @@ static SANE_Status attach( const char *dev_name, pCnfDef cnf, } else { dev->sane.model = ModelStr[0]; } - + DBG( _DBG_INFO, "Vendor : %s\n", dev->sane.vendor ); DBG( _DBG_INFO, "Model : %s\n", dev->sane.model ); DBG( _DBG_INFO, "Asic : 0x%02x\n", dev->caps.AsicID ); @@ -1140,7 +1140,7 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) DBG_INIT(); sanei_thread_init(); - + res = sanei_pp_init(); if( SANE_STATUS_GOOD != res ) { DBG( _DBG_ERROR, "Could not initialize Parport library!\n" ); @@ -1178,20 +1178,20 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) } while( sanei_config_read( str, sizeof(str), fp)) { - + DBG( _DBG_SANE_INIT, ">%s<\n", str ); if( str[0] == '#') /* ignore line comments */ continue; - + len = strlen(str); if( 0 == len ) continue; /* ignore empty lines */ /* check for options */ if( 0 == strncmp(str, "option", 6)) { - + int ival; - + ival = -1; decodeVal( str, "warmup", _INT, &config.adj.warmup, &ival); decodeVal( str, "lampOff", _INT, &config.adj.lampOff, &ival); @@ -1203,14 +1203,14 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) /* check for sections: */ } else if( 0 == strncmp( str, "[direct]", 8)) { - + /* new section, try and attach previous device */ if( config.devName[0] != '\0' ) attach( config.devName, &config, 0 ); - + /* re-initialize the configuration structure */ init_config_struct( &config, SANE_TRUE ); - continue; + continue; } else if( 0 == strncmp( str, "[kernel]", 8 )) { @@ -1221,11 +1221,11 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) /* re-initialize the configuration structure */ init_config_struct( &config, SANE_FALSE ); continue; - + } else if( SANE_TRUE == decodeDevName( str, config.devName )) { continue; } - + /* ignore other stuff... */ DBG( _DBG_SANE_INIT, "ignoring >%s<\n", str ); } @@ -1234,7 +1234,7 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) /* try to attach the last device in the config file... */ if( config.devName[0] != '\0' ) attach( config.devName, &config, 0 ); - + return SANE_STATUS_GOOD; } @@ -1328,7 +1328,7 @@ SANE_Status sane_open( SANE_String_Const devicename, SANE_Handle* handle ) if( !dev ) { memset( &config, 0, sizeof(CnfDef)); - + /* check if a valid parport-device is meant... */ status = attach( devicename, &config, &dev ); if( SANE_STATUS_GOOD != status ) @@ -1359,7 +1359,7 @@ SANE_Status sane_open( SANE_String_Const devicename, SANE_Handle* handle ) first_handle = s; *handle = s; - + return SANE_STATUS_GOOD; } @@ -1382,7 +1382,7 @@ void sane_close (SANE_Handle handle) if (!s) { DBG( _DBG_ERROR, "close: invalid handle %p\n", handle); - return; + return; } close_pipe( s ); @@ -1463,7 +1463,7 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, strcpy ((char *) value, s->opt[option].constraint.string_list[s->val[option].w]); break; - + /* word array options: */ case OPT_GAMMA_VECTOR: case OPT_GAMMA_VECTOR_R: @@ -1471,7 +1471,7 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, case OPT_GAMMA_VECTOR_B: memcpy( value, s->val[option].wa, s->opt[option].size ); break; - + default: return SANE_STATUS_INVAL; } @@ -1514,7 +1514,7 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, *(SANE_Word *)value = best; if( NULL != info ) { - if( v != best ) + if( v != best ) *info |= SANE_INFO_INEXACT; *info |= SANE_INFO_RELOAD_PARAMS; } @@ -1531,22 +1531,22 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, if( NULL != info ) *info |= SANE_INFO_RELOAD_PARAMS; break; - + case OPT_CUSTOM_GAMMA: s->val[option].w = *(SANE_Word *)value; if( NULL != info ) *info |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - mp = getModeList( s ); + mp = getModeList( s ); scanmode = mp[s->val[OPT_MODE].w].scanmode; s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; - + if( SANE_TRUE == s->val[option].w ) { - + if((scanmode == COLOR_256GRAY) || (scanmode == COLOR_GRAY16)) { s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; @@ -1554,20 +1554,20 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; - } - + } + } else { - + initGammaSettings( s ); - + if((scanmode == COLOR_256GRAY) || (scanmode == COLOR_GRAY16)) { s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; - } else { + } else { s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; - } + } } break; @@ -1587,7 +1587,7 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, } mp = getModeList( s ); - + if( mp[idx].scanmode != COLOR_HALFTONE ){ s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE; s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE; @@ -1601,16 +1601,16 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, if( mp[idx].scanmode == COLOR_BW ) { s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; - } - + } + s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; - + if( s->val[OPT_CUSTOM_GAMMA].w && !(s->opt[OPT_CUSTOM_GAMMA].cap & SANE_CAP_INACTIVE)) { - + if((mp[idx].scanmode == COLOR_256GRAY) || (mp[idx].scanmode == COLOR_GRAY16)) { s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; @@ -1677,7 +1677,7 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, } if( s->hw->caps.dwFlag & SFLAG_TPA ) { - + s->opt[OPT_MODE].constraint.string_list = &mode_9800x_list[_TPAModeSupportMin]; } else { @@ -1702,13 +1702,13 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, checkGammaSettings(s); if( NULL != info ) *info |= SANE_INFO_RELOAD_PARAMS; - break; + break; default: return SANE_STATUS_INVAL; } break; - + default: return SANE_STATUS_INVAL; @@ -1834,7 +1834,7 @@ SANE_Status sane_start( SANE_Handle handle ) s->hw->close( s->hw ); return SANE_STATUS_IO_ERROR; } - + result = s->hw->getLensInfo( s->hw, &lens ); if( result < 0 ) { DBG( _DBG_ERROR, "dev->getLensInfo() failed(%d)\n", result ); @@ -2084,7 +2084,7 @@ SANE_Status sane_read( SANE_Handle handle, SANE_Byte *data, if( s->bytes_read == (unsigned long)(s->params.lines * s->params.bytes_per_line)) { sanei_thread_waitpid( s->reader_pid, 0 ); - s->reader_pid = -1; + sanei_thread_invalidate( s->reader_pid ); drvclose( s->hw ); return close_pipe(s); } @@ -2112,7 +2112,7 @@ SANE_Status sane_read( SANE_Handle handle, SANE_Byte *data, close_pipe(s); return s->exit_code; } - s->reader_pid = -1; + sanei_thread_invalidate( s->reader_pid ); return close_pipe(s); } @@ -2148,9 +2148,9 @@ SANE_Status sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) DBG( _DBG_ERROR, "ERROR: not supported !\n" ); return SANE_STATUS_UNSUPPORTED; } - + if( fcntl (s->r_pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) { - DBG( _DBG_ERROR, "ERROR: can´t set to non-blocking mode !\n" ); + DBG( _DBG_ERROR, "ERROR: can´t set to non-blocking mode !\n" ); return SANE_STATUS_IO_ERROR; } diff --git a/backend/plustek_pp.conf.in b/backend/plustek_pp.conf.in index a000343..d357007 100644 --- a/backend/plustek_pp.conf.in +++ b/backend/plustek_pp.conf.in @@ -1,5 +1,5 @@ # Plustek-PP SANE Backend configuration file -# For use with Plustek parallel-port scanners +# For use with Plustek parallel-port scanners # # diff --git a/backend/pnm.c b/backend/pnm.c index ff4e2f2..1d1f4fd 100644 --- a/backend/pnm.c +++ b/backend/pnm.c @@ -2,7 +2,7 @@ Copyright (C) 1996, 1997 Andreas Beck Copyright (C) 2000, 2001 Michael Herder Copyright (C) 2001, 2002 Henning Meier-Geinitz - Copyright (C) 2008 Stéphane Voltz + Copyright (C) 2008 Stéphane Voltz This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -106,9 +106,9 @@ static const SANE_Word resbit_list[] = { 200, 210, 225, 240, 255, 270, 285, 300 }; static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 0 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(-100), /* minimum */ + SANE_FIX(100), /* maximum */ + SANE_FIX(0) /* quantization */ }; static const SANE_Range gamma_range = { 0, /* minimum */ diff --git a/backend/qcam.c b/backend/qcam.c index 0148bea..4c46fa7 100644 --- a/backend/qcam.c +++ b/backend/qcam.c @@ -1248,7 +1248,7 @@ init_options (QC_Scanner * s) int i; DBG (3, "init_options: enter\n"); - + memset (s->opt, 0, sizeof (s->opt)); memset (s->val, 0, sizeof (s->val)); @@ -1446,7 +1446,7 @@ init_options (QC_Scanner * s) s->val[OPT_SATURATION].w = 100; DBG (3, "init_options: exit\n"); - + return SANE_STATUS_GOOD; } @@ -1497,9 +1497,9 @@ sane_exit (void) { QC_Device *dev, *next; static const SANE_Device **devlist; - + DBG (5, "sane_exit: enter\n"); - + for (dev = first_dev; dev; dev = next) { next = dev->next; @@ -1510,7 +1510,7 @@ sane_exit (void) if (devlist) { free (devlist); devlist = NULL; - } + } DBG (5, "sane_exit: exit\n"); } @@ -1538,9 +1538,9 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) devlist[i++] = 0; *device_list = devlist; - + DBG (5, "sane_get_devices: exit\n"); - + return SANE_STATUS_GOOD; } @@ -1630,7 +1630,7 @@ sane_close (SANE_Handle handle) QC_Scanner *prev, *s; DBG (5, "sane_close: enter\n"); - + /* remove handle from list of open handles: */ prev = 0; for (s = first_handle; s; s = s->next) @@ -1666,9 +1666,9 @@ sane_close (SANE_Handle handle) close (s->read_fd); free (s); - + DBG (5, "sane_close: exit\n"); - + } const SANE_Option_Descriptor * @@ -1677,7 +1677,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) QC_Scanner *s = handle; DBG (5, "sane_get_option_descriptor: enter\n"); - + if ((unsigned) option >= NUM_OPTIONS) return 0; @@ -1698,7 +1698,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, int i; DBG (5, "sane_control_option: enter\n"); - + if (info) *info = 0; @@ -1866,7 +1866,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) size_t Bpp = 3; /* # of bytes per pixel */ DBG (5, "sane_get_parameters: enter\n"); - + if (!s->scanning) { /* Only compute new parameters when not scanning---allows @@ -1912,7 +1912,7 @@ sane_start (SANE_Handle handle) QC_Scan_Request req; DBG (5, "sane_start: enter\n"); - + if (s->scanning) return SANE_STATUS_DEVICE_BUSY; @@ -2099,7 +2099,7 @@ sane_start (SANE_Handle handle) s->deliver_eof = 0; DBG (5, "sane_start: exit\n"); - + return SANE_STATUS_GOOD; } @@ -2114,7 +2114,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, size_t len; DBG (5, "sane_read: enter\n"); - + *lenp = 0; if (s->deliver_eof) @@ -2177,7 +2177,7 @@ sane_cancel (SANE_Handle handle) SANE_Status status; DBG (5, "sane_cancel: enter\n"); - + was_scanning = s->scanning; s->scanning = SANE_FALSE; s->deliver_eof = 0; @@ -2239,7 +2239,7 @@ sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) QC_Scanner *s = handle; DBG (5, "sane_set_io_mode: enter\n"); - + if (!s->scanning) return SANE_STATUS_INVAL; diff --git a/backend/ricoh-scsi.c b/backend/ricoh-scsi.c index 72fd70b..73bd4fa 100644 --- a/backend/ricoh-scsi.c +++ b/backend/ricoh-scsi.c @@ -39,9 +39,9 @@ whether to permit this exception to apply to your modifications. If you do not wish that, delete this exception notice. */ -/* +/* $Id$ - This file implements the low-level scsi-commands. + This file implements the low-level scsi-commands. */ @@ -251,7 +251,7 @@ set_window (int fd, struct ricoh_window_data *rwd) static SANE_Status get_window (int fd, struct ricoh_window_data *rwd) { - + static struct scsi_window_cmd cmd; static size_t rwd_size; SANE_Status status; @@ -317,7 +317,7 @@ get_data_status (int fd, struct scsi_status_desc *dbs) status = sanei_scsi_cmd (fd, &cmd, sizeof (cmd), &ssd, &ssd_size); memcpy (dbs, &ssd.desc, sizeof(*dbs)); - if (status == SANE_STATUS_GOOD && + if (status == SANE_STATUS_GOOD && (((unsigned int) _3btol(ssd.len)) <= sizeof(*dbs) || _3btol(ssd.desc.filled) == 0)) { DBG (11, "get_data_status: busy\n"); status = SANE_STATUS_DEVICE_BUSY; diff --git a/backend/ricoh.c b/backend/ricoh.c index 88f33d1..58b3a53 100644 --- a/backend/ricoh.c +++ b/backend/ricoh.c @@ -41,7 +41,7 @@ /* $Id$ - This file implements a SANE backend for Ricoh flatbed scanners. + This file implements a SANE backend for Ricoh flatbed scanners. */ #include "../include/sane/config.h" @@ -187,7 +187,7 @@ attach (const char *devnam, Ricoh_Device ** devp) DBG (1, "attach: MODE_SELECT failed\n"); sanei_scsi_close (fd); return (SANE_STATUS_INVAL); - } + } #endif #if 0 @@ -510,7 +510,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) if (line[0] == '#') /* ignore line comments */ continue; len = strlen (line); - + if (!len) continue; /* ignore empty lines */ @@ -538,7 +538,7 @@ sane_exit (void) free ((void *) dev->sane.model); free (dev); } - + if (devlist) free (devlist); @@ -824,7 +824,7 @@ sane_start (SANE_Handle handle) s->brightness = s->val[OPT_BRIGHTNESS].w; s->contrast = s->val[OPT_CONTRAST].w; s->bpp = s->params.depth; - if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_LINEART) == 0) + if (strcmp (mode_str, SANE_VALUE_SCAN_MODE_LINEART) == 0) { s->image_composition = RICOH_BINARY_MONOCHROME; } @@ -849,11 +849,11 @@ sane_start (SANE_Handle handle) wbuf.image_comp = s->image_composition; /* if you throw the MRIF bit the brighness control reverses too */ /* so I reverse the reversal in software for symmetry's sake */ - if (wbuf.image_comp == RICOH_GRAYSCALE || wbuf.image_comp == RICOH_DITHERED_MONOCHROME) + if (wbuf.image_comp == RICOH_GRAYSCALE || wbuf.image_comp == RICOH_DITHERED_MONOCHROME) { - if (wbuf.image_comp == RICOH_GRAYSCALE) + if (wbuf.image_comp == RICOH_GRAYSCALE) wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x90; - if (wbuf.image_comp == RICOH_DITHERED_MONOCHROME) + if (wbuf.image_comp == RICOH_DITHERED_MONOCHROME) wbuf.mrif_filtering_gamma_id = (SANE_Byte) 0x10; wbuf.brightness = 256 - (SANE_Byte) s->brightness; if (is50) @@ -899,7 +899,7 @@ sane_start (SANE_Handle handle) if (status != SANE_STATUS_GOOD) { DBG (1, "GET WINDOW failed: %s\n", sane_strstatus (status)); - return (status); + return (status); } DBG (5, "xres=%d\n", _2btol(wbuf.x_res)); DBG (5, "yres=%d\n", _2btol(wbuf.y_res)); @@ -937,18 +937,18 @@ sane_start (SANE_Handle handle) { DBG (1, "GET DATA STATUS failed: %s\n", sane_strstatus (status)); return (status); - } + } s->bytes_to_read = s->params.bytes_per_line * s->params.lines; DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, " "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line, s->params.lines, (u_long) s->bytes_to_read, s->val[OPT_Y_RESOLUTION].w); - + s->scanning = SANE_TRUE; - DBG (11, "<< sane_start\n"); - return (SANE_STATUS_GOOD); + DBG (11, "<< sane_start\n"); + return (SANE_STATUS_GOOD); } SANE_Status @@ -963,7 +963,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, *len = 0; DBG (11, "sane_read: bytes left to read: %ld\n", (u_long) s->bytes_to_read); - + if (s->bytes_to_read == 0) { do_cancel (s); @@ -973,7 +973,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, if (!s->scanning) { DBG (11, "sane_read: scanning is false!\n"); return (do_cancel (s)); - } + } nread = max_len; if (nread > s->bytes_to_read) diff --git a/backend/ricoh.h b/backend/ricoh.h index f9bb36e..8771297 100644 --- a/backend/ricoh.h +++ b/backend/ricoh.h @@ -171,7 +171,7 @@ _4btol(SANE_Byte *bytes) return (rv); } -typedef enum +typedef enum { OPT_NUM_OPTS = 0, @@ -318,7 +318,7 @@ struct measurements_units_page { }; struct mode_pages { - SANE_Byte page_code; + SANE_Byte page_code; SANE_Byte parameter_length; SANE_Byte rest[6]; #if 0 diff --git a/backend/ricoh2.c b/backend/ricoh2.c new file mode 100644 index 0000000..8aa938e --- /dev/null +++ b/backend/ricoh2.c @@ -0,0 +1,971 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2018 Stanislav Yuzvinsky + Based on the work done by viruxx + + 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/sane/sane.h" +#include "../include/sane/sanei.h" +#include "../include/sane/sanei_usb.h" +#include "../include/sane/saneopts.h" +#include "../include/sane/sanei_backend.h" +#include "../include/sane/sanei_debug.h" + +#include "ricoh2_buffer.c" + +#define MAX_OPTION_STRING_SIZE 255 +#define MAX_LINE_SIZE 240 * 256 /* = 61440 */ +#define HEIGHT_PIXELS_300DPI 3508 +#define WIDTH_BYTES_300DPI 2560 +#define WIDTH_PIXELS_300DPI 2550 +#define INFO_SIZE (WIDTH_BYTES_300DPI - WIDTH_PIXELS_300DPI) +#define USB_TIMEOUT_MS 20000 +#define MAX_COMMAND_SIZE 64 + +#define CHECK_IF(x) if (!(x)) return SANE_STATUS_INVAL + +typedef enum +{ + OPT_NUM_OPTS = 0, + OPT_MODE, + OPT_RESOLUTION, + + /* must come last: */ + NUM_OPTIONS +} +Ricoh_Options; + +typedef enum +{ + SCAN_MODE_COLOR, + SCAN_MODE_GRAY +} +Scan_Mode; + + +typedef struct Ricoh2_Device { + struct Ricoh2_Device *next; + SANE_Device sane; + SANE_Bool active; + + /* options */ + SANE_Option_Descriptor opt[NUM_OPTIONS]; + Option_Value val[NUM_OPTIONS]; + + /* acquiring session */ + SANE_Int dn; + SANE_Bool cancelled; + Scan_Mode mode; + SANE_Int resolution; + SANE_Bool eof; + size_t bytes_to_read; + ricoh2_buffer *buffer; + +} +Ricoh2_Device; + +typedef struct Ricoh2_device_info { + SANE_Int product_id; + SANE_String_Const device_name; +} +Ricoh2_device_info; + +static Ricoh2_device_info supported_devices[] = { + { 0x042c, "Aficio SP100SU" }, + { 0x0438, "Aficio SG3100SNw" }, + { 0x0448, "Aficio SP111SU" } +}; + +static SANE_String_Const mode_list[] = { + SANE_VALUE_SCAN_MODE_COLOR, + SANE_VALUE_SCAN_MODE_GRAY, + NULL +}; +static SANE_String_Const default_mode = SANE_VALUE_SCAN_MODE_COLOR; + +static SANE_Int resolution_list[] = { + 2, 300, 600 +}; +static SANE_Int default_resolution = 300; + +static SANE_Bool initialized = SANE_FALSE; +static Ricoh2_Device *ricoh2_devices = NULL; +static const SANE_Device **sane_devices = NULL; +static SANE_Int num_devices = 0; + +static Ricoh2_Device * +lookup_handle(SANE_Handle handle) +{ + Ricoh2_Device *device; + + for (device = ricoh2_devices; device; device = device->next) + { + if (device == handle) + return device; + } + + return NULL; +} + +static SANE_String_Const get_model_by_productid(SANE_Int id) +{ + size_t i = 0; + for (; i < sizeof (supported_devices) / sizeof (supported_devices[0]); ++i) + { + if (supported_devices[i].product_id == id) + { + return supported_devices[i].device_name; + } + } + + return "Unidentified device"; +} + +static SANE_Status +attach (SANE_String_Const devname) +{ + SANE_Int dn = -1; + SANE_Status status = SANE_STATUS_GOOD; + Ricoh2_Device *device = NULL; + SANE_Int vendor, product; + + for (device = ricoh2_devices; device; device = device->next) + { + if (strcmp (device->sane.name, devname) == 0) + { + device->active = SANE_TRUE; + return SANE_STATUS_GOOD; + } + } + + device = (Ricoh2_Device *) malloc (sizeof (Ricoh2_Device)); + if (!device) + { + return SANE_STATUS_NO_MEM; + } + + DBG (8, "attach %s\n", devname); + status = sanei_usb_open (devname, &dn); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "attach: couldn't open device `%s': %s\n", devname, + sane_strstatus (status)); + return status; + } + + status = sanei_usb_get_vendor_product (dn, &vendor, &product); + if (status != SANE_STATUS_GOOD) + { + DBG (1, + "attach: couldn't get vendor and product ids of device `%s': %s\n", + devname, sane_strstatus (status)); + sanei_usb_close (dn); + return status; + } + + sanei_usb_close (dn); + device->sane.name = strdup (devname); + device->sane.vendor = "Ricoh"; + device->sane.model = get_model_by_productid (product); + device->sane.type = "flatbed scanner"; + device->active = SANE_TRUE; + device->buffer = NULL; + + device->next = ricoh2_devices; + ricoh2_devices = device; + + DBG (2, "Found device %s\n", device->sane.name); + ++num_devices; + + return SANE_STATUS_GOOD; +} + +static SANE_Status +init_options(Ricoh2_Device *dev) +{ + SANE_Option_Descriptor *od; + + DBG (8, "init_options: dev = %p\n", (void *) dev); + + /* number of options */ + od = &(dev->opt[OPT_NUM_OPTS]); + od->name = SANE_NAME_NUM_OPTIONS; + od->title = SANE_TITLE_NUM_OPTIONS; + od->desc = SANE_DESC_NUM_OPTIONS; + od->type = SANE_TYPE_INT; + od->unit = SANE_UNIT_NONE; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT; + od->constraint_type = SANE_CONSTRAINT_NONE; + od->constraint.range = 0; + dev->val[OPT_NUM_OPTS].w = NUM_OPTIONS; + + /* mode - sets the scan mode: Color, Gray */ + od = &(dev->opt[OPT_MODE]); + od->name = SANE_NAME_SCAN_MODE; + od->title = SANE_TITLE_SCAN_MODE; + od->desc = SANE_DESC_SCAN_MODE; + od->type = SANE_TYPE_STRING; + od->unit = SANE_UNIT_NONE; + od->size = MAX_OPTION_STRING_SIZE; + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->constraint_type = SANE_CONSTRAINT_STRING_LIST; + od->constraint.string_list = mode_list; + dev->val[OPT_MODE].s = malloc (od->size); + if (!dev->val[OPT_MODE].s) + return SANE_STATUS_NO_MEM; + strcpy (dev->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR); + + /* resolution */ + od = &(dev->opt[OPT_RESOLUTION]); + od->name = SANE_NAME_SCAN_RESOLUTION; + od->title = SANE_TITLE_SCAN_RESOLUTION; + od->desc = SANE_DESC_SCAN_RESOLUTION; + od->type = SANE_TYPE_INT; + od->unit = SANE_UNIT_DPI; + od->size = sizeof (SANE_Word); + od->cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + od->constraint_type = SANE_CONSTRAINT_WORD_LIST; + od->constraint.word_list = resolution_list; + dev->val[OPT_RESOLUTION].w = 300; + + return SANE_STATUS_GOOD; +} + +SANE_Status +sane_init (SANE_Int *vc, SANE_Auth_Callback __sane_unused__ cb) +{ + size_t i = 0; + + DBG_INIT (); + + DBG(8, ">sane_init\n"); + + sanei_usb_init (); + sanei_usb_set_timeout (USB_TIMEOUT_MS); + + num_devices = 0; + + for (; i < sizeof (supported_devices) / sizeof (supported_devices[0]); ++i) + { + sanei_usb_find_devices (0x5ca, supported_devices[i].product_id, attach); + } + + if (vc) + *vc = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0); + DBG(8, "sane_get_devices\n"); + + num_devices = 0; + sanei_usb_find_devices (0x5ca, 0x042c, attach); + sanei_usb_find_devices (0x5ca, 0x0448, attach); + + if (sane_devices) + free (sane_devices); + + sane_devices = (const SANE_Device **) malloc (sizeof (const SANE_Device *) + * (num_devices + 1)); + if (!sane_devices) + return SANE_STATUS_NO_MEM; + + for (device = ricoh2_devices; device; device = device->next) + if (device->active) + { + sane_devices[i++] = &(device->sane); + } + + sane_devices[i] = NULL; + *dl = sane_devices; + + DBG(2, "found %i devices\n", i); + DBG(8, "sane_open: devicename=\"%s\", handle=%p\n", name, + (void *) handle); + + CHECK_IF (initialized); + CHECK_IF (handle); + + /* walk the linked list of scanner device until there is a match + * with the device name */ + for (device = ricoh2_devices; device; device = device->next) + { + DBG (2, "sane_open: devname from list: %s\n", + device->sane.name); + if (strcmp (name, "") == 0 + || strcmp (name, "ricoh") == 0 + || strcmp (name, device->sane.name) == 0) + break; + } + + *handle = device; + + if (!device) + { + DBG (1, "sane_open: Not a Ricoh device\n"); + return SANE_STATUS_INVAL; + } + + status = init_options (device); + if (status != SANE_STATUS_GOOD) + return status; + + DBG (8, "= NUM_OPTIONS)) + return NULL; + + if (!(device = lookup_handle(handle))) + return NULL; + + if (device->opt[option].name) + { + DBG (8, ">sane_get_option_descriptor: name=%s\n", + device->opt[option].name); + } + + return &(device->opt[option]); +} + +SANE_Status +sane_control_option (SANE_Handle handle, + SANE_Int option, + SANE_Action action, + void *value, + SANE_Word *info) +{ + Ricoh2_Device *device; + SANE_Status status; + + DBG (8, + ">sane_control_option: handle=%p, opt=%d, act=%d, val=%p, info=%p\n", + (void *) handle, option, action, (void *) value, (void *) info); + + CHECK_IF (initialized); + device = lookup_handle (handle); + CHECK_IF (device); + CHECK_IF (value); + CHECK_IF (option >= 0 && option < NUM_OPTIONS); + CHECK_IF (device->opt[option].type != SANE_TYPE_GROUP); + + switch (action) + { + case SANE_ACTION_SET_AUTO: + CHECK_IF (SANE_OPTION_IS_SETTABLE (device->opt[option].cap)); + CHECK_IF (device->opt[option].cap & SANE_CAP_AUTOMATIC); + + switch (option) + { + case OPT_RESOLUTION: + DBG (2, + "Setting value to default value of '%d' for option '%s'\n", + default_resolution, + device->opt[option].name); + device->val[option].w = default_resolution; + break; + + case OPT_MODE: + DBG (2, + "Setting value to default value of '%s' for option '%s'\n", + (SANE_String_Const) default_mode, + device->opt[option].name); + strcpy (device->val[option].s, default_mode); + break; + + default: + return SANE_STATUS_INVAL; + } + break; + + case SANE_ACTION_SET_VALUE: + CHECK_IF (SANE_OPTION_IS_SETTABLE (device->opt[option].cap)); + + if (device->opt[option].type == SANE_TYPE_BOOL) + { + SANE_Bool bool_value = *(SANE_Bool *) value; + CHECK_IF (bool_value == SANE_TRUE || bool_value == SANE_FALSE); + } + + if (device->opt[option].constraint_type == SANE_CONSTRAINT_RANGE) + { + status = sanei_constrain_value (&(device->opt[option]), value, info); + CHECK_IF (status == SANE_STATUS_GOOD); + } + + + switch (option) + { + case OPT_RESOLUTION: + DBG (2, + "Setting value to '%d' for option '%s'\n", + *(SANE_Word *) value, + device->opt[option].name); + device->val[option].w = *(SANE_Word *) value; + break; + + case OPT_MODE: + DBG (2, + "Setting value to '%s' for option '%s'\n", + (SANE_String_Const)value, + device->opt[option].name); + strcpy (device->val[option].s, value); + break; + + default: + return SANE_STATUS_INVAL; + } + break; + + case SANE_ACTION_GET_VALUE: + + switch (option) + { + case OPT_NUM_OPTS: + case OPT_RESOLUTION: + *(SANE_Word *) value = device->val[option].w; + DBG (2, "Option value = %d (%s)\n", *(SANE_Word *) value, + device->opt[option].name); + break; + case OPT_MODE: + strcpy (value, device->val[option].s); + break; + default: + return SANE_STATUS_INVAL; + } + break; + + default: + return SANE_STATUS_INVAL; + } + + DBG (8, "val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_COLOR) == 0) + { + device->mode = SCAN_MODE_COLOR; + } + else + { + device->mode = SCAN_MODE_GRAY; + } + + /* resolution: 300 or 600dpi */ + device->resolution = device->val[OPT_RESOLUTION].w; +} + + +SANE_Status +sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) +{ + Ricoh2_Device *device; + + DBG (8, "sane_get_parameters: handle=%p, params=%p\n", (void *) handle, + (void *) params); + + CHECK_IF (initialized); + device = lookup_handle (handle); + CHECK_IF (device); + CHECK_IF (params); + + update_scan_params (device); + + params->format = + device->mode == SCAN_MODE_COLOR ? SANE_FRAME_RGB : SANE_FRAME_GRAY; + params->last_frame = SANE_TRUE; + + params->pixels_per_line = WIDTH_PIXELS_300DPI; + params->bytes_per_line = params->pixels_per_line; + params->lines = HEIGHT_PIXELS_300DPI; + params->depth = 8; + + if (device->resolution == 600) + { + params->bytes_per_line *= 2; + params->pixels_per_line *= 2; + params->lines *= 2; + } + + if (device->mode == SCAN_MODE_COLOR) + { + params->bytes_per_line *= 3; + } + + DBG (8, ">sane_get_parameters: format = %s bytes_per_line = %d " + "depth = %d " + "pixels_per_line = %d " + "lines = %d\n", + (params->format == SANE_FRAME_RGB ? "rgb" : "gray"), + params->bytes_per_line, + params->depth, + params->pixels_per_line, + params->lines); + + return SANE_STATUS_GOOD; +} + +typedef struct +{ + SANE_Byte *send_buffer; + size_t to_send; + SANE_Byte *receive_buffer; + size_t to_receive; +} +Send_Receive_Pair; + +static SANE_Status +send_receive (SANE_Int dn, Send_Receive_Pair *transfer) +{ + SANE_Status status; + size_t io_size; + SANE_Byte send_buffer[MAX_COMMAND_SIZE]; + + assert(transfer->to_send <= MAX_COMMAND_SIZE); + + memset(send_buffer, 0, MAX_COMMAND_SIZE); + + /* send a command */ + io_size = MAX_COMMAND_SIZE; + DBG (128, "sending a packet of size %lu\n", io_size); + memcpy (send_buffer, transfer->send_buffer, transfer->to_send); + status = sanei_usb_write_bulk (dn, send_buffer, &io_size); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "could not send packet: %s\n", sane_strstatus (status)); + return status; + } + + /* receive a result */ + io_size = transfer->to_receive; + DBG (128, "receiving a packet of size %lu\n", io_size); + if (io_size) + { + status = sanei_usb_read_bulk (dn, transfer->receive_buffer, &io_size); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "could not get a response for packet: %s\n", + sane_strstatus (status)); + return status; + } + if (io_size != transfer->to_receive) + { + DBG (1, "unexpected size of received packet: expected %lu, " + "received %lu\n", transfer->to_receive, io_size); + return SANE_STATUS_IO_ERROR; + } + } + return SANE_STATUS_GOOD; +} + +static SANE_Status +init_scan(SANE_Int dn, Scan_Mode mode, SANE_Int resolution) +{ + SANE_Status status = SANE_STATUS_GOOD; + SANE_Byte dummy_buffer[11]; /* the longest expected reply */ + size_t i; + + SANE_Byte urb_init[] = { 0x03, 0x09, 0x01 }; + SANE_Byte magic0[] = { 0x03, 0x0d, 0x0b }; + SANE_Byte magic1[] = { + 0x03, 0x0c, 0x11, 0x00, 0x00, 0x00, 0x01, 0x02, 0x05, + 0xff, 0x00, 0x00, 0x00, 0x00, 0xec, 0x13, 0x6c, 0x1b }; + SANE_Byte magic2[] = { 0x03, 0x0b, 0x08 }; + SANE_Byte magic3[] = { + 0x03, 0x08, 0x04, 0x00, 0x00, 0x00, 0x00, 0x50, 0x6d, 0x06, 0x01 }; + + Send_Receive_Pair transfer[] = + { + { urb_init, sizeof (urb_init), dummy_buffer, 1 }, + { magic0, sizeof (magic0), dummy_buffer, 11 }, + { magic1, sizeof (magic1), dummy_buffer, 0 }, + { magic2, sizeof (magic2), dummy_buffer, 8 }, + { magic3, sizeof (magic3), dummy_buffer, 0 } + }; + + if (resolution == 600) + magic1[6] = 0x02; + + if (mode == SCAN_MODE_COLOR) + magic1[7] = 0x03; + + for (i = 0; + i < sizeof (transfer) / sizeof (transfer[0]) + && (status == SANE_STATUS_GOOD); + ++i) + { + DBG (128, "sending initialization packet %zi\n", i); + status = send_receive (dn, transfer + i); + } + + return status; +} + +void +teardown_scan(SANE_Int dn) +{ + SANE_Byte cancel_command[] = { 0x03, 0x0a }; + SANE_Byte end_command[] = { 0x03, 0x09, 0x01 }; + SANE_Byte dummy_buffer; + Send_Receive_Pair transfer; + + DBG (128, "Sending cancel command\n"); + transfer.send_buffer = cancel_command; + transfer.to_send = sizeof (cancel_command); + transfer.receive_buffer = &dummy_buffer; + transfer.to_receive = 0; + send_receive (dn, &transfer); + + transfer.send_buffer = end_command; + transfer.to_send = sizeof (end_command); + transfer.receive_buffer = &dummy_buffer; + transfer.to_receive = 1; + send_receive (dn, &transfer); +} + +SANE_Status +sane_start (SANE_Handle handle) +{ + Ricoh2_Device *device; + SANE_Status status; + SANE_Int pixels_per_line; + SANE_Int resolution_factor = 1; + + DBG (8, ">sane_start: handle=%p\n", (void *) handle); + + CHECK_IF (initialized); + device = lookup_handle (handle); + CHECK_IF (device); + + update_scan_params (device); + device->cancelled = SANE_FALSE; + + status = sanei_usb_open (device->sane.name, &(device->dn)); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "could not open device %s: %s\n", + device->sane.name, sane_strstatus (status)); + return status; + } + + DBG (2, "usb device %s opened, device number is %d\n", + device->sane.name, device->dn); + + status = sanei_usb_claim_interface (device->dn, 0); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "could not claim interface 0: %s\n", + sane_strstatus (status)); + sanei_usb_close (device->dn); + return status; + } + + sanei_usb_set_endpoint (device->dn, + USB_DIR_OUT | USB_ENDPOINT_TYPE_BULK, + 0x03); + + sanei_usb_set_endpoint (device->dn, + USB_DIR_IN | USB_ENDPOINT_TYPE_BULK, + 0x85); + + status = sanei_usb_reset (device->dn); + if (status != SANE_STATUS_GOOD) + { + DBG (1, "could not reset device %s: %s\n", + device->sane.name, sane_strstatus (status)); + sanei_usb_close (device->dn); + return status; + } + + + status = init_scan (device->dn, device->mode, device->resolution); + if (status != SANE_STATUS_GOOD) + { + sanei_usb_close (device->dn); + return status; + } + + resolution_factor = device->resolution == 600 ? 2 : 1; + + pixels_per_line = WIDTH_PIXELS_300DPI * resolution_factor; + + device->bytes_to_read = + WIDTH_PIXELS_300DPI * resolution_factor + * HEIGHT_PIXELS_300DPI * resolution_factor + * (device->mode == SCAN_MODE_COLOR ? 3 : 1); + + device->buffer = + ricoh2_buffer_create (MAX_LINE_SIZE, + pixels_per_line, + INFO_SIZE * resolution_factor, + device->mode == SCAN_MODE_COLOR); + + DBG (8, "bytes_to_read); + + return SANE_STATUS_GOOD; +} + +SANE_Status +sane_read (SANE_Handle handle, + SANE_Byte *data, + SANE_Int maxlen, + SANE_Int *length) +{ + SANE_Byte read_next_command[] = { 0x03, 0x0E, 0x04, 0, 0, 0, 0, 240 }; + + Ricoh2_Device *device; + SANE_Status status; + Send_Receive_Pair transfer; + + DBG (16, ">sane_read: handle=%p, data=%p, maxlen = %d, length=%p\n", + (void *) handle, (void *) data, maxlen, (void *) length); + + CHECK_IF (initialized); + device = lookup_handle (handle); + CHECK_IF (device); + CHECK_IF (length); + CHECK_IF (maxlen); + + /* + EOF has already been reached before or acquisition process hasn't + been initiated at all + */ + if (device->bytes_to_read <= 0) + { + return SANE_STATUS_EOF; + } + + if (!ricoh2_buffer_get_bytes_remain (device->buffer)) + { + transfer.send_buffer = read_next_command; + transfer.to_send = sizeof (read_next_command); + transfer.receive_buffer = + ricoh2_buffer_get_internal_buffer (device->buffer); + transfer.to_receive = MAX_LINE_SIZE; + read_next_command[7] = transfer.to_receive / 256; + + DBG (128, "Receiving data of size %zi\n", transfer.to_receive); + + status = send_receive (device->dn, &transfer); + if (status != SANE_STATUS_GOOD) + { + device->bytes_to_read = 0; + return status; + } + } + + *length = ricoh2_buffer_get_data (device->buffer, + data, + min(maxlen, device->bytes_to_read)); + + device->bytes_to_read -= *length; + + DBG (128, + "Read length %d, left to read %lu\n", + *length, + device->bytes_to_read); + + DBG (128, + "%d bytes remain in the buffer\n", + ricoh2_buffer_get_bytes_remain(device->buffer)); + + /* we've just reached expected data size */ + if (device->bytes_to_read <= 0) + { + ricoh2_buffer_dispose(device->buffer); + device->buffer = NULL; + return SANE_STATUS_EOF; + } + + DBG (16, "sane_cancel: handle = %p\n", (void *) handle); + + if (!initialized) + return; + + if (!(device = lookup_handle (handle))) + return; + + if (device->cancelled) + return; + + device->cancelled = SANE_TRUE; + + teardown_scan (device->dn); + if (device->buffer) + { + ricoh2_buffer_dispose (device->buffer); + device->buffer = NULL; + } + + sanei_usb_close(device->dn); + + DBG (8, "sane_close\n"); + + if (!initialized) + return; + + device = lookup_handle (handle); + if (!device) + return; + + /* noop */ + + DBG (8, "sane_exit\n"); + + if (!initialized) + return; + + for (device = ricoh2_devices, next = device; device; device = next) + { + next = device->next; + free (device); + } + + if (sane_devices) + free (sane_devices); + + sanei_usb_exit (); + initialized = SANE_FALSE; + + DBG (8, " +#include +#include + +#include "../include/sane/sanei_debug.h" + +typedef struct ricoh2_buffer +{ + /* lifetime constants */ + SANE_Byte *data; + SANE_Int size; + SANE_Int pixels_per_line; + SANE_Int info_size; + SANE_Bool is_rgb; + + /* state */ + SANE_Int current_position; + SANE_Int remain_in_line; + +} +ricoh2_buffer; + +static ricoh2_buffer * +ricoh2_buffer_create (SANE_Int size, + SANE_Int pixels_per_line, + SANE_Int info_size, + SANE_Bool is_rgb) +{ + ricoh2_buffer *self; + assert (size > 0); + assert (pixels_per_line > 0); + assert (info_size >= 0); + + self = malloc (sizeof (ricoh2_buffer)); + if (!self) + return NULL; + + self->data = malloc (size); + if (!self->data) + { + free (self); + return NULL; + } + + self->size = size; + self->pixels_per_line = pixels_per_line; + self->info_size = info_size; + self->is_rgb = is_rgb; + + self->current_position = 0; + self->remain_in_line = pixels_per_line; + + + DBG (192, + "size = %d pixels_per_line = %d info_size = %d rgb? = %d pos = %d\n", + self->size, + self->pixels_per_line, + self->info_size, + self->is_rgb, + self->current_position); + + return self; +} + +/* destructor */ +static void +ricoh2_buffer_dispose (ricoh2_buffer *self) +{ + assert (self); + free (self->data); + free (self); +} + +static SANE_Byte * +ricoh2_buffer_get_internal_buffer (ricoh2_buffer *self) +{ + assert (self); + DBG (192, "engaging a buffer of size %d\n", self->size); + + self->current_position = 0; + self->remain_in_line = self->pixels_per_line; + + DBG (192, "remain in line = %d\n", self->remain_in_line); + + return self->data; +} + +static SANE_Int +ricoh2_buffer_get_bytes_remain (ricoh2_buffer *self) +{ + assert (self); + + DBG (192, + "bytes remain in the buffer %d\n", + self->size - self->current_position); + + return self->size - self->current_position; +} + +inline static SANE_Int +min (SANE_Int v1, SANE_Int v2) +{ + return v1 < v2 ? v1 : v2; +} + +static SANE_Int +ricoh2_buffer_get_data (ricoh2_buffer *self, + SANE_Byte *dest, + SANE_Int dest_size) +{ + SANE_Int actually_copied = 0; + SANE_Int pixels_to_copy; + SANE_Int bytes_per_pixel; + SANE_Int bytes_per_color; + SANE_Byte *src; + SANE_Byte *end; + + assert (self); + assert (dest); + assert (self->size > self->current_position); + + bytes_per_pixel = self->is_rgb ? 3 : 1; + bytes_per_color = self->pixels_per_line + self->info_size; + + DBG (192, + "trying to get %d bytes from the buffer, " + "while %d bytes in the line\n", + dest_size, + self->remain_in_line); + + for (pixels_to_copy = + min (dest_size / bytes_per_pixel, self->remain_in_line); + pixels_to_copy && self->size > self->current_position; + pixels_to_copy = + min (dest_size / bytes_per_pixel, self->remain_in_line)) + { + + DBG (192, + "providing %d bytes to the user (until the end of the line), " + "position in buffer is %d\n", + pixels_to_copy * bytes_per_pixel, + self->current_position); + + for (src = self->data + self->current_position, + end = src + pixels_to_copy; + src < end; + ++src) + { + *(dest++) = *(src); + if (bytes_per_pixel == 3) + { + *(dest++) = *(src + bytes_per_color); + *(dest++) = *(src + 2 * bytes_per_color); + } + } + + dest_size -= pixels_to_copy * bytes_per_pixel; + actually_copied += pixels_to_copy * bytes_per_pixel; + self->current_position += pixels_to_copy; + self->remain_in_line -= pixels_to_copy; + + // move to the next line + if (!self->remain_in_line) + { + self->current_position += self->info_size; + if (self->is_rgb) + self->current_position += 2 * bytes_per_color; + self->remain_in_line = self->pixels_per_line; + DBG (192, + "Line feed, new position is %d\n", + self->current_position); + } + + DBG (192, + "left in the buffer: %d\n", + self->size - self->current_position); + } + + /* invariant */ + assert (self->size >= self->current_position); + + return actually_copied; +} diff --git a/backend/rts8891.c b/backend/rts8891.c index 0eaff7b..93018ab 100644 --- a/backend/rts8891.c +++ b/backend/rts8891.c @@ -292,7 +292,7 @@ write_rgb_data (char *name, unsigned char *image, SANE_Int width, /** * Called by SANE initially. - * + * * From the SANE spec: * This function must be called before any other SANE function can be * called. The behavior of a SANE backend is undefined if this @@ -333,7 +333,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /** * Called by SANE to find out about supported devices. - * + * * From the SANE spec: * This function can be used to query the list of devices that are * available. If the function executes successfully, it stores a @@ -346,7 +346,7 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) * returned (devices directly attached to the machine that SANE is * running on). If it is false, the device list includes all remote * devices that are accessible to the SANE library. - * + * * SANE does not require that this function is called before a * sane_open() call is performed. A device name may be specified * explicitly by a user which would make it unnecessary and @@ -466,7 +466,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) " had only limited testing. Please be careful and \n"); DBG (DBG_error0, " report any failure/success to \n"); DBG (DBG_error0, - " sane-devel@lists.alioth.debian.org. Please provide as many\n"); + " sane-devel@alioth-lists.debian.net. Please provide as many\n"); DBG (DBG_error0, " details as possible, e.g. the exact name of your\n"); DBG (DBG_error0, " scanner and what does (not) work.\n"); @@ -908,7 +908,7 @@ get_option_value (Rts8891_Session * s, int option, void *val) /** * Gets or sets an option value. - * + * * From the SANE spec: * This function is used to set or inquire the current value of option * number n of the device represented by handle h. The manner in which @@ -919,7 +919,7 @@ get_option_value (Rts8891_Session * s, int option, void *val) * area pointed to by v must be big enough to hold the entire option * value (determined by member size in the corresponding option * descriptor). - * + * * The only exception to this rule is that when setting the value of a * string option, the string pointed to by argument v may be shorter * since the backend will stop reading the option value upon @@ -1388,8 +1388,8 @@ sane_start (SANE_Handle handle) /** * This function computes two set of parameters. The one for the SANE's standard - * and the other for the hardware. Among these parameters are the bit depth, total - * number of lines, total number of columns, extra line to read for data reordering... + * and the other for the hardware. Among these parameters are the bit depth, total + * number of lines, total number of columns, extra line to read for data reordering... */ static SANE_Status compute_parameters (Rts8891_Session * session) @@ -1666,7 +1666,7 @@ compute_parameters (Rts8891_Session * session) * completion of that request. Outside of that window, the returned * values are best-effort estimates of what the parameters will be * when sane_start() gets invoked. - * + * * Calling this function before a scan has actually started allows, * for example, to get an estimate of how big the scanned image will * be. The parameters passed to this function are the handle of the @@ -1693,7 +1693,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) /** * Called by SANE to read data. - * + * * From the SANE spec: * This function is used to read image data from the device * represented by handle h. Argument buf is a pointer to a memory @@ -1701,7 +1701,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) * returned is stored in *len. A backend must set this to zero when * the call fails (i.e., when a status other than SANE_STATUS_GOOD is * returned). - * + * * When the call succeeds, the number of bytes returned can be * anywhere in the range from 0 to maxlen bytes. */ @@ -2077,7 +2077,7 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, /** - * Cancels a scan. + * Cancels a scan. * * From the SANE spec: * This function is used to immediately or as quickly as possible @@ -2155,7 +2155,7 @@ sane_cancel (SANE_Handle handle) /** * Ends use of the session. - * + * * From the SANE spec: * This function terminates the association between the device handle * passed in argument h and the device it represents. If the device is @@ -2188,7 +2188,7 @@ sane_close (SANE_Handle handle) DBG (DBG_error, "close: invalid handle %p\n", handle); return; /* oops, not a handle we know about */ } - + dev=session->dev; /* cancel any active scan */ @@ -2202,7 +2202,7 @@ sane_close (SANE_Handle handle) rts8891_wait_for_home (dev, dev->regs); } set_lamp_brightness (dev, 0); - + if (prev) prev->next = session->next; @@ -2248,7 +2248,7 @@ sane_close (SANE_Handle handle) /** * Terminates the backend. - * + * * From the SANE spec: * This function must be called to terminate use of a backend. The * function will first close all device handles that still might be @@ -2408,8 +2408,8 @@ config_attach_rts8891 (SANEI_Config * config, const char *devname) return SANE_STATUS_INVAL; } - /* the devname has been processed and is ready to be used - * directly. Since the backend is an USB only one, we can + /* the devname has been processed and is ready to be used + * directly. Since the backend is an USB only one, we can * call sanei_usb_attach_matching_devices straight */ sanei_usb_attach_matching_devices (devname, attach_rts8891); @@ -2863,7 +2863,7 @@ init_options (struct Rts8891_Session *session) /** * average scanned rgb data, returns the global average. Each channel avearge is also - * returned. + * returned. */ static float average_area (int color, SANE_Byte * data, int width, int height, @@ -3028,7 +3028,7 @@ find_origin (struct Rts8891_Device *dev, SANE_Bool * changed) DBG (DBG_proc, "find_origin: start\n"); - /* check if head is at home + /* check if head is at home * once sensor is correctly set up, we are allways park here, * but in case sensor has just changed, we are not so we park head */ sanei_rts88xx_read_reg (dev->devnum, CONTROLER_REG, ®); @@ -3287,7 +3287,7 @@ find_origin (struct Rts8891_Device *dev, SANE_Bool * changed) dev->regs[0xe2] = 0x03; /* 0x01 */ - /* dev->regs[0xe5] = 0x0d; 0x1c + /* dev->regs[0xe5] = 0x0d; 0x1c dev->regs[0xe6] = 0x08; 0x10 080d=2061=1030*2+1 */ SET_DOUBLE (dev->regs, EXPOSURE_REG, 2061); } @@ -3326,7 +3326,7 @@ find_origin (struct Rts8891_Device *dev, SANE_Bool * changed) /** * This function detects the left margin (ie x offset of scanning area) by doing * a grey scan of the very beginning of the sensor and finding the start of the - * white area of calibration zone, which is start of usable pixels. + * white area of calibration zone, which is start of usable pixels. */ static SANE_Status find_margin (struct Rts8891_Device *dev) @@ -3390,7 +3390,7 @@ find_margin (struct Rts8891_Device *dev) dev->regs[0xd7] = 0x14; dev->regs[0xd8] = 0xf6; - dev->regs[0xda] = 0xa7; /* XXX STEF XXX à l'origine, pas 'bare' */ + dev->regs[0xda] = 0xa7; /* XXX STEF XXX à l'origine, pas 'bare' */ dev->regs[0xe2] = 0x01; @@ -3547,7 +3547,7 @@ initialize_device (struct Rts8891_Device *dev) } DBG (DBG_io, "initialize_device: lamp status=0x%02x\n", dev->regs[0x8e]); - /* sensor type the one for 4470c sold with XPA is slightly different + /* sensor type the one for 4470c sold with XPA is slightly different * than those sold bare, for this model we allways start with xpa type sensor, * and change it later if we detect black scans in find_origin(). In case the * attach function set up the sensor type, we don't modify it */ @@ -3694,10 +3694,7 @@ initialize_device (struct Rts8891_Device *dev) } #else /* FAST_INIT */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status +static SANE_Status init_registers (struct Rts8891_Device *dev) { int i; @@ -4233,7 +4230,7 @@ init_device (struct Rts8891_Device *dev) rts8891_write_all (dev->devnum, dev->regs, dev->reg_count); /* now we are writing and reading back from memory, it is surely a memory test since the written data - * don't look usefull at first glance + * don't look usefull at first glance */ reg = 0x06; sanei_rts88xx_write_reg (dev->devnum, 0x93, ®); @@ -4424,7 +4421,7 @@ init_device (struct Rts8891_Device *dev) sanei_rts88xx_write_reg (dev->devnum, CONTROLER_REG, ®); /* now we init nvram */ - /* this is highly dangerous and thus desactivated + /* this is highly dangerous and thus desactivated * in sanei_rts88xx_setup_nvram (HAZARDOUS_EXPERIMENT #define) */ sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd1); sanei_rts88xx_setup_nvram (dev->devnum, 21, nv_cmd2); @@ -4513,17 +4510,17 @@ static SANE_Status detect_device (struct Rts8891_Device *dev) { /* ---- 5 74945 bulk_out len 4 wrote 0x80 0xb0 0x00 0x01 ---- 6 74946 bulk_in len 1 read 0x80 ---- 7 74947 bulk_out len 4 wrote 0x80 0xb3 0x00 0x01 ---- 8 74948 bulk_in len 1 read 0x04 ---- 9 74949 bulk_out len 4 wrote 0x80 0xb1 0x00 0x01 ---- 10 74950 bulk_in len 1 read 0x00 ---- 11 74951 bulk_out len 5 wrote 0x88 0xb3 0x00 0x01 0x00 ---- 12 74952 bulk_out len 5 wrote 0x88 0xb3 0x00 0x01 0x00 ---- 13 74953 bulk_out len 4 wrote 0x80 0x00 0x00 0xf4 ---- 14 74954 bulk_in len 192 read 0xf5 0x41 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x70 0x00 0x00 0x00 0x00 0x60 0x1b 0xff 0x3e 0x00 0x00 0xff 0x3e 0x00 0x00 0x00 0x00 0x00 0x22 0x00 0x00 0x00 0x00 0x00 0xff 0x00 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x42 0x00 0x00 0x10 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x00 0x00 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x24 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x10 0x00 0x80 0x00 0x10 0x00 0x01 0x00 0x00 0x10 0x00 0x00 0x20 0x20 0x00 0x00 0x00 0x00 0x20 0x01 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x41 0x00 0x10 0x21 0x20 0x00 0x20 0x81 0x20 0x01 0x01 0x00 0x22 0x00 0x40 0x05 0x00 0x00 0x01 0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xcc 0x27 0x64 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 ---- 15 74955 bulk_in len 52 read 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x06 0x1b 0x10 0x7a 0x00 0x15 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +--- 5 74945 bulk_out len 4 wrote 0x80 0xb0 0x00 0x01 +--- 6 74946 bulk_in len 1 read 0x80 +--- 7 74947 bulk_out len 4 wrote 0x80 0xb3 0x00 0x01 +--- 8 74948 bulk_in len 1 read 0x04 +--- 9 74949 bulk_out len 4 wrote 0x80 0xb1 0x00 0x01 +--- 10 74950 bulk_in len 1 read 0x00 +--- 11 74951 bulk_out len 5 wrote 0x88 0xb3 0x00 0x01 0x00 +--- 12 74952 bulk_out len 5 wrote 0x88 0xb3 0x00 0x01 0x00 +--- 13 74953 bulk_out len 4 wrote 0x80 0x00 0x00 0xf4 +--- 14 74954 bulk_in len 192 read 0xf5 0x41 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x70 0x00 0x00 0x00 0x00 0x60 0x1b 0xff 0x3e 0x00 0x00 0xff 0x3e 0x00 0x00 0x00 0x00 0x00 0x22 0x00 0x00 0x00 0x00 0x00 0xff 0x00 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x42 0x00 0x00 0x10 0x00 0x00 0x00 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x00 0x00 0x18 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x20 0x24 0x04 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x10 0x00 0x80 0x00 0x10 0x00 0x01 0x00 0x00 0x10 0x00 0x00 0x20 0x20 0x00 0x00 0x00 0x00 0x20 0x01 0x00 0x02 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x41 0x00 0x10 0x21 0x20 0x00 0x20 0x81 0x20 0x01 0x01 0x00 0x22 0x00 0x40 0x05 0x00 0x00 0x01 0x1e 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0xcc 0x27 0x64 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x80 0x00 0x06 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 +--- 15 74955 bulk_in len 52 read 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x01 0x06 0x1b 0x10 0x7a 0x00 0x15 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x0f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 */ SANE_Status status = SANE_STATUS_GOOD; SANE_Byte control; @@ -4666,7 +4663,7 @@ dark_calibration (struct Rts8891_Device *dev, int mode, int light) dev->regs[0xd8] = 0x52; dev->regs[0xe2] = 0x1f; - /*dev->regs[0xe5] = 0x28; 28=40 + /*dev->regs[0xe5] = 0x28; 28=40 dev->regs[0xe6] = 0x00; */ SET_DOUBLE (dev->regs, EXPOSURE_REG, 40); @@ -4747,7 +4744,7 @@ dark_calibration (struct Rts8891_Device *dev, int mode, int light) dev->regs[0xf0] = 0xa8; /* 0x70 */ } - /* we loop scanning a 637 (1911 bytes) pixels wide area in color mode + /* we loop scanning a 637 (1911 bytes) pixels wide area in color mode * until each black average reaches the desired value */ sanei_rts88xx_set_status (dev->devnum, dev->regs, mode, light); do @@ -4858,7 +4855,7 @@ dark_calibration (struct Rts8891_Device *dev, int mode, int light) } /* - * do gain calibration. We do scans until averaged values of the area match + * do gain calibration. We do scans until averaged values of the area match * the target code. We're doing a dichotomy again. */ static SANE_Status @@ -4973,7 +4970,7 @@ gain_calibration (struct Rts8891_Device *dev, int mode, int light) dev->regs[0xd7] = 0x10; dev->regs[0xd8] = 0x52; dev->regs[0xe2] = 0x1f; - /* dev->regs[0xe5] = 0x28; 0028 -> 40 + /* dev->regs[0xe5] = 0x28; 0028 -> 40 dev->regs[0xe6] = 0x00; */ SET_DOUBLE (dev->regs, EXPOSURE_REG, 40); dev->regs[0xe7] = 0x75; @@ -5218,7 +5215,7 @@ gain_calibration (struct Rts8891_Device *dev, int mode, int light) /** * Do fine offset calibration. Scans are done with gains from gain calibration - * at 75 dpi regardless of the dpi of the final scan. We loop scanning a 637 + * at 75 dpi regardless of the dpi of the final scan. We loop scanning a 637 * (1911 bytes) pixels wide area in color mode until each black average * reaches the desired value (OFFSET_TARGET). */ @@ -5449,10 +5446,7 @@ offset_calibration (struct Rts8891_Device *dev, int mode, int light) * We scan a 637 pixels by 66 linesxoffset=24 , xend=661, pixels=637 y offset=1 , yend=67, lines =66 */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status +static SANE_Status setup_shading_calibration (struct Rts8891_Device *dev, int mode, int *light, int *status1, SANE_Byte * regs) { SANE_Status status = SANE_STATUS_GOOD; @@ -5532,7 +5526,7 @@ setup_shading_calibration (struct Rts8891_Device *dev, int mode, int *light, int /* regs[0xd3] = 0x02; 0x0e */ regs[0xd4] = 0x04; /* 0x10 */ regs[0xe2] = 0x02; /* 0x05 */ - /* regs[0xe5] = 0xbb; + /* regs[0xe5] = 0xbb; regs[0xe6] = 0x01; 1bb =443 */ exposure=443; } @@ -5739,7 +5733,7 @@ setup_shading_calibration (struct Rts8891_Device *dev, int mode, int *light, int regs[0x88] = 0x1b; regs[0x8d] = 0xde; - regs[0x8e] = 0x61; /* low nibble of 8e and 8d are proportional to + regs[0x8e] = 0x61; /* low nibble of 8e and 8d are proportional to the scanned width 1de => 5100 wide scan */ regs[0xc0] = 0xff; @@ -5826,7 +5820,7 @@ setup_shading_calibration (struct Rts8891_Device *dev, int mode, int *light, int regs[0x88] = 0x30; regs[0x8d] = 0xde; - regs[0x8e] = 0x61; /* low nibble of 8e and 8d are proportional to + regs[0x8e] = 0x61; /* low nibble of 8e and 8d are proportional to the scanned width 1de => 5100 wide scan */ regs[0xc0] = 0xff; regs[0xc1] = 0xff; @@ -5870,7 +5864,7 @@ setup_shading_calibration (struct Rts8891_Device *dev, int mode, int *light, int regs[0x87] = 0x00; regs[0x88] = 0x06; - regs[0x8d] = 0x00; + regs[0x8d] = 0x00; regs[0x8e] = 0x60; /* XXX STEF XXX */ regs[0xc0] = 0xf8; @@ -5895,7 +5889,7 @@ setup_shading_calibration (struct Rts8891_Device *dev, int mode, int *light, int regs[0xd3] = 0x0e; regs[0xd4] = 0x10; regs[0xd7] = 0x31; - + timing=0x0032; exposure=915; break; @@ -6109,8 +6103,8 @@ setup_shading_calibration (struct Rts8891_Device *dev, int mode, int *light, int } break; } - - /* apply computed settings */ + + /* apply computed settings */ SET_DOUBLE (regs, EXPOSURE_REG, exposure); SET_DOUBLE (regs, TIMING_REG, timing); SET_DOUBLE (regs, TIMING1_REG, timing+1); @@ -6167,8 +6161,8 @@ shading_calibration (struct Rts8891_Device *dev, SANE_Bool color, int mode, int "shading_calibration: failed to allocate memory for data\n"); return SANE_STATUS_NO_MEM; } - - /* set up registers */ + + /* set up registers */ status=setup_shading_calibration(dev, mode, &light, &status1, dev->regs); if (status != SANE_STATUS_GOOD) { @@ -6279,7 +6273,7 @@ fill_gamma (SANE_Byte * calibration, int *idx, SANE_Word * gamma) /* * build and send calibration data which contains gamma table and * shading correction coefficient - * + * */ static SANE_Status send_calibration_data (struct Rts8891_Session *session) @@ -6309,28 +6303,28 @@ send_calibration_data (struct Rts8891_Session *session) DBG (DBG_io, "send_calibration_data: size=%d\n", size); - /* + /* * FORMAT: - * 00 + * 00 * 512 bytes gamma table (256 16 bit entry) - * FF - * 00 + * FF + * 00 * 512 bytes gamma table (256 16 bit entry) - * FF - * 00 + * FF + * 00 * 512 bytes gamma table (256 16 bit entry) - * FF + * FF * 5400 max shading coefficients at 600 dpi repeated 3 times * overall size rounded at 32 bytes multiple * 675 CCD elements at 75 DPI. 16 bit per element. 1 or 3 channels. * there is a 0xFF marker at end of each coefficients row. - * a gamma table comes first + * a gamma table comes first * 75 DPI: 5600=1542+(675)*2*3+8 ->size rounded to 'upper 32' * 150 DPI: 9664=675*2*2*3=1542+(675*2)*2*3+22 * 17760 4 +18 * 33952 8 +10 * 65472+896=66368= 16 +26 - * + * * COEFFICIENT 16 bit value * first is 00, 0x40, 0x80 or 0xC0 => 10 significant bit * coeff*average=K => coeff=K/average @@ -6369,7 +6363,7 @@ send_calibration_data (struct Rts8891_Session *session) fill_gamma (calibration, &idx, gamma_b); /* compute calibration coefficients */ - /* real witdh != 675 --> 637 + /* real witdh != 675 --> 637 * shading data calibration starts at 1542. There are 3 rows of 16 bits values * first row is green calibration */ @@ -6404,7 +6398,7 @@ send_calibration_data (struct Rts8891_Session *session) green_code = atoi (getenv ("BLUE_CODE")); } - /* correction coefficient is target code divided by average scanned value + /* correction coefficient is target code divided by average scanned value * but it is put in a 16 bits number. Only 10 first bits are significants. */ /* first color component red data */ @@ -6511,7 +6505,7 @@ send_calibration_data (struct Rts8891_Session *session) } /* move at dev->model->min_ydpi dpi up to the scanning area. Which speeds - * up scanning + * up scanning */ static SANE_Status move_to_scan_area (struct Rts8891_Session *session) @@ -6554,10 +6548,7 @@ move_to_scan_area (struct Rts8891_Session *session) /* The windows driver is allways scanning in color, so we do the same. */ /* For now, the only mode that could be done would be 300 dpi gray scan, */ /* based on the register settings of find_origin() */ -#ifndef UNIT_TESTING -static -#endif -SANE_Status +static SANE_Status setup_scan_registers (struct Rts8891_Session *session, SANE_Byte *status1, SANE_Byte *status2, SANE_Byte *regs) { SANE_Status status = SANE_STATUS_GOOD; @@ -7130,7 +7121,7 @@ setup_scan_registers (struct Rts8891_Session *session, SANE_Byte *status1, SANE_ regs[0xef] = 0x00; regs[0xf0] = 0x00; regs[0x8d] = 0xf0; - regs[0x8e] = 0x60; /* low nibble of 8e and 8d are proportional to + regs[0x8e] = 0x60; /* low nibble of 8e and 8d are proportional to the scanned width 1de => 5100 wide scan */ regs[0xc0] = 0xff; @@ -7228,7 +7219,7 @@ setup_scan_registers (struct Rts8891_Session *session, SANE_Byte *status1, SANE_ regs[0x88] = 0x5a; regs[0x8d] = 0xde; - regs[0x8e] = 0x61; /* low nibble of 8e and 8d are proportional to + regs[0x8e] = 0x61; /* low nibble of 8e and 8d are proportional to the scanned width 1de => 5100 wide scan */ regs[0xc0] = 0xff; @@ -7275,7 +7266,7 @@ setup_scan_registers (struct Rts8891_Session *session, SANE_Byte *status1, SANE_ regs[0x3a] = 0x1b; regs[0x40] = 0x2c; /* 0x24 */ regs[0x50] = 0x00; /* 0x18 */ - + regs[0x64] = 0x01; /* 0x02 */ regs[0x65] = 0x20; /* 0x10 */ @@ -7421,7 +7412,7 @@ setup_scan_registers (struct Rts8891_Session *session, SANE_Byte *status1, SANE_ regs[0x88] = 0xae; regs[0x8d] = 0xbd; /* about twice the 600 dpi values */ - regs[0x8e] = 0x63; /* low nibble of 8e and 8d are proportional to + regs[0x8e] = 0x63; /* low nibble of 8e and 8d are proportional to the scanned width 3b5 => 10124 wide scan */ regs[0xc0] = 0xff; regs[0xc1] = 0xff; @@ -7716,7 +7707,7 @@ park_head (struct Rts8891_Device *dev, SANE_Bool wait) return status; } -/* update button status +/* update button status * button access is allowed during scan, which is usefull for 'cancel' button */ static SANE_Status diff --git a/backend/rts8891.h b/backend/rts8891.h index 5fbf8b5..fa3feb6 100644 --- a/backend/rts8891.h +++ b/backend/rts8891.h @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2007-2012 stef.dev@free.fr - + 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. + If you do not wish that, delete this exception notice. */ #ifndef RTS8891_H @@ -113,13 +113,13 @@ enum Rts8891_Option enum Rts8891_Configure_Option { CFG_MODEL_NUMBER = 0, /* first option number must be zero */ - CFG_SENSOR_NUMBER, + CFG_SENSOR_NUMBER, CFG_ALLOW_SHARING, NUM_CFG_OPTIONS /* MUST be last */ }; /** Scanner object. This struct holds informations usefull for - * the functions defined in SANE's standard. Informations closer + * the functions defined in SANE's standard. Informations closer * to the hardware are in the Rts8891_Device structure. There is * as many session structure than frontends using the scanner. */ diff --git a/backend/rts8891_devices.c b/backend/rts8891_devices.c index 151b283..a46f98b 100644 --- a/backend/rts8891_devices.c +++ b/backend/rts8891_devices.c @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2007-2012 stef.dev@free.fr - + 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. + If you do not wish that, delete this exception notice. */ diff --git a/backend/rts8891_low.c b/backend/rts8891_low.c index 917d514..4fc5666 100644 --- a/backend/rts8891_low.c +++ b/backend/rts8891_low.c @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2007-2013 stef.dev@free.fr - + 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. + If you do not wish that, delete this exception notice. */ /* this file contains all the low level functions needed for the higher level @@ -849,21 +849,21 @@ read_data (struct Rts8891_Session *session, SANE_Byte * dest, SANE_Int length) /** * set scanner idle before leaving xxx_quiet() -write_reg(0x33,1)=0x00 -write_reg(0x33,1)=0x00 -write_reg(0x36,1)=0x00 +write_reg(0x33,1)=0x00 +write_reg(0x33,1)=0x00 +write_reg(0x36,1)=0x00 prepare(); ------ -write_reg(LAMP_REG,1)=0x80 -write_reg(LAMP_REG,1)=0xad -read_reg(0x14,2)=0xf8 0x28 -write_reg(0x14,2)=0x78 0x28 -get_status()=0x20 0x3f -read_reg(0xb1,1)=0x00 -read_control()=0x00 +write_reg(LAMP_REG,1)=0x80 +write_reg(LAMP_REG,1)=0xad +read_reg(0x14,2)=0xf8 0x28 +write_reg(0x14,2)=0x78 0x28 +get_status()=0x20 0x3f +read_reg(0xb1,1)=0x00 +read_control()=0x00 reset_lamp()=(0x20,0x3f) -write_reg(LAMP_REG,1)=0x8d -write_reg(LAMP_REG,1)=0xad +write_reg(LAMP_REG,1)=0x8d +write_reg(LAMP_REG,1)=0xad */ /* vim: set sw=2 cino=>2se-1sn-1s{s^-1st0(0u0 smarttab expandtab: */ diff --git a/backend/rts8891_low.h b/backend/rts8891_low.h index a6df802..6b12316 100644 --- a/backend/rts8891_low.h +++ b/backend/rts8891_low.h @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2007-2012 stef.dev@free.fr - + 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. + If you do not wish that, delete this exception notice. */ #ifndef RTS8891_LOW_H @@ -80,7 +80,7 @@ typedef struct Rts8891_Device Rts8891_Device; #define SET_DOUBLE(regs,idx,value) regs[idx]=(SANE_Byte)((value)>>8); regs[idx-1]=(SANE_Byte)((value) & 0xff); -/* +/* * defines for RTS8891 registers name */ #define BUTTONS_REG2 0x1a @@ -128,7 +128,7 @@ typedef struct Rts8891_Model SANE_Int ld_shift_r; /* red */ SANE_Int ld_shift_g; /* green */ SANE_Int ld_shift_b; /* blue */ - + /* default sensor type */ SANE_Int sensor; diff --git a/backend/rts88xx_lib.c b/backend/rts88xx_lib.c index 8e921f2..f19ceef 100644 --- a/backend/rts88xx_lib.c +++ b/backend/rts88xx_lib.c @@ -123,7 +123,7 @@ sanei_rts88xx_set_scan_frequency (SANE_Byte * regs, int frequency) } /* - * read one register at given index + * read one register at given index */ SANE_Status sanei_rts88xx_read_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg) @@ -153,7 +153,7 @@ sanei_rts88xx_read_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg) } /* - * write one register at given index + * write one register at given index */ SANE_Status sanei_rts88xx_write_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg) @@ -200,7 +200,7 @@ sanei_rts88xx_write_regs (SANE_Int devnum, SANE_Int start, start, length, message); } - /* when writing several registers at a time, we avoid writing the 0xb3 register + /* when writing several registers at a time, we avoid writing the 0xb3 register * which is used to control the status of the scanner */ if ((start + length > 0xb3) && (length > 1)) { @@ -297,7 +297,7 @@ sanei_rts88xx_read_regs (SANE_Int devnum, SANE_Int start, } /* - * get status by reading registers 0x10 and 0x11 + * get status by reading registers 0x10 and 0x11 */ SANE_Status sanei_rts88xx_get_status (SANE_Int devnum, SANE_Byte * regs) @@ -310,7 +310,7 @@ sanei_rts88xx_get_status (SANE_Int devnum, SANE_Byte * regs) } /* - * set status by writing registers 0x10 and 0x11 + * set status by writing registers 0x10 and 0x11 */ SANE_Status sanei_rts88xx_set_status (SANE_Int devnum, SANE_Byte * regs, @@ -394,7 +394,7 @@ sanei_rts88xx_reset_lamp (SANE_Int devnum, SANE_Byte * regs) "sanei_rts88xx_reset_lamp: expected reg[0xda]=0xa7, got 0x%02x\n", reg); } - + /* store read value in shadow register */ regs[0xda] = reg; @@ -415,7 +415,7 @@ sanei_rts88xx_get_lcd (SANE_Int devnum, SANE_Byte * regs) } /* - * write to special control register CONTROL_REG=0xb3 + * write to special control register CONTROL_REG=0xb3 */ SANE_Status sanei_rts88xx_write_control (SANE_Int devnum, SANE_Byte value) diff --git a/backend/rts88xx_lib.h b/backend/rts88xx_lib.h index 71bd72a..fa7abbd 100644 --- a/backend/rts88xx_lib.h +++ b/backend/rts88xx_lib.h @@ -60,7 +60,7 @@ #define DBG_io2 7 /* io functions that are called very often */ #define DBG_data 8 /* log data sent and received */ -/* +/* * defines for registers name */ #define CONTROL_REG 0xb3 @@ -97,7 +97,7 @@ void sanei_rts88xx_set_scan_area (SANE_Byte * reg, SANE_Int ystart, SANE_Int xend); /* - * read one register at given index + * read one register at given index */ SANE_Status sanei_rts88xx_read_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg); @@ -109,7 +109,7 @@ SANE_Status sanei_rts88xx_read_data (SANE_Int devnum, SANE_Word * length, unsigned char *dest); /* - * write one register at given index + * write one register at given index */ SANE_Status sanei_rts88xx_write_reg (SANE_Int devnum, SANE_Int index, SANE_Byte * reg); @@ -127,17 +127,17 @@ SANE_Status sanei_rts88xx_read_regs (SANE_Int devnum, SANE_Int start, SANE_Byte * dest, SANE_Int length); /* - * get status by reading registers 0x10 and 0x11 + * get status by reading registers 0x10 and 0x11 */ SANE_Status sanei_rts88xx_get_status (SANE_Int devnum, SANE_Byte * regs); /* - * set status by writing registers 0x10 and 0x11 + * set status by writing registers 0x10 and 0x11 */ SANE_Status sanei_rts88xx_set_status (SANE_Int devnum, SANE_Byte * regs, SANE_Byte reg10, SANE_Byte reg11); /* - * get lamp status by reading registers 0x84 to 0x8d + * get lamp status by reading registers 0x84 to 0x8d */ SANE_Status sanei_rts88xx_get_lamp_status (SANE_Int devnum, SANE_Byte * regs); @@ -148,7 +148,7 @@ SANE_Status sanei_rts88xx_reset_lamp (SANE_Int devnum, SANE_Byte * regs); SANE_Status sanei_rts88xx_get_lcd (SANE_Int devnum, SANE_Byte * regs); /* - * write to special control register CONTROL_REG=0xb3 + * write to special control register CONTROL_REG=0xb3 */ SANE_Status sanei_rts88xx_write_control (SANE_Int devnum, SANE_Byte value); diff --git a/backend/s9036.c b/backend/s9036.c index 1b97f80..aa18df7 100644 --- a/backend/s9036.c +++ b/backend/s9036.c @@ -51,7 +51,7 @@ static S9036_Device *s9036_devices; /* sets loc_s bytes long value at offset loc in scsi command to value size */ -static void +static void set_size (Byte * loc, int loc_s, size_t size) { int i; @@ -62,7 +62,7 @@ set_size (Byte * loc, int loc_s, size_t size) } } -static long +static long reserve_unit (int fd) { const Byte scsi_reserve[] = @@ -73,7 +73,7 @@ reserve_unit (int fd) return sanei_scsi_cmd (fd, scsi_reserve, sizeof (scsi_reserve), 0, 0); } -static long +static long release_unit (int fd) { const Byte scsi_release[] = @@ -654,9 +654,9 @@ init_options (S9036_Scanner * s) static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 1 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(-100), /* minimum */ + SANE_FIX(100), /* maximum */ + SANE_FIX(1) /* quantization */ }; static const SANE_Range automatic_adjust_range = @@ -871,7 +871,7 @@ sane_exit (void) sane_close (dev->handle); free (dev); } - + if (devlist) free (devlist); } @@ -881,7 +881,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) { S9036_Device *dev; int i; - + local_only = local_only; /* silence compilation warnings */ if (devlist) @@ -1237,7 +1237,7 @@ sane_start (SANE_Handle handle) return SANE_STATUS_GOOD; } -static void +static void copy_buffer (S9036_Scanner * s, SANE_Byte ** buf, SANE_Int * max_len, SANE_Int * len) { @@ -1327,7 +1327,7 @@ SANE_Status sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) { handle = handle; /* silence compilation warnings */ - + DBG (1, "sane_set_io_mode(%d)\n", non_blocking); return (non_blocking == SANE_TRUE) ? diff --git a/backend/sceptre.c b/backend/sceptre.c index fa0da20..3670f3c 100644 --- a/backend/sceptre.c +++ b/backend/sceptre.c @@ -2,47 +2,47 @@ Copyright (C) 2002 Frank Zago (sane at zago dot net) Copyright (C) 2002 Other SANE contributors - + 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. + If you do not wish that, delete this exception notice. */ -/* +/* $Id$ Sceptre S1200 SCSI scanner (sometimes also called S120) */ @@ -366,7 +366,7 @@ sceptre_get_status (Sceptre_Scanner * dev, size_t * data_left) return (SANE_STATUS_GOOD); } -/* +/* * Adjust the rasters. This function is used during a color scan, * because the scanner does not present a format sane can interpret * directly. @@ -374,9 +374,9 @@ sceptre_get_status (Sceptre_Scanner * dev, size_t * data_left) * The scanner sends the colors by rasters (R then G then B), whereas * sane is waiting for a group of 3 bytes per color. To make things * funnier, the rasters are shifted. This shift factor depends on the - * resolution used. The format of those raster is: + * resolution used. The format of those raster is: * R...R RG...RG RGB...RGB BG...GB B...B - * + * * So this function reorders all that mess. It gets the input from * dev->buffer and write the output in dev->image. size_in the the * length of the valid data in dev->buffer. @@ -401,7 +401,7 @@ sceptre_adjust_raster (Sceptre_Scanner * dev, size_t size_in) return; } - /* + /* * The color coding is one line for each color (in the RGB order). * Recombine that stuff to create a RGB value for each pixel. */ @@ -411,7 +411,7 @@ sceptre_adjust_raster (Sceptre_Scanner * dev, size_t size_in) for (raster = 0; raster < nb_rasters; raster++) { - /* + /* * Find the color to which this raster belongs to. * 0 = red * 1 = green @@ -516,7 +516,7 @@ sceptre_adjust_raster (Sceptre_Scanner * dev, size_t size_in) DBG (DBG_proc, "sceptre_adjust_raster: exit\n"); } -/* SCSI sense handler. Callback for SANE. +/* SCSI sense handler. Callback for SANE. * * Since this scanner does not have REQUEST SENSE, it is always an * error if this function is called.*/ @@ -596,14 +596,14 @@ attach_scanner (const char *devicename, Sceptre_Scanner ** devp) dev->resolution_range.max = SANE_FIX (1200); dev->resolution_range.quant = SANE_FIX (1); - /* + /* * The S1200 has an area of 8.5 inches / 11.7 inches. (A4 like) * That's roughly 215*297 mm * The values are coded by * size in inch * 600 dpi. * The maximums are: * X: 8.5 inches * 600 = 5100 dots - * Y: 11.7 inches * 600 = 7020 + * Y: 11.7 inches * 600 = 7020 * (although the windows driver stops at 7019) * * The values are stored in mm. Inches sucks anyway. @@ -840,7 +840,7 @@ sceptre_init_options (Sceptre_Scanner * dev) /* Wait until the scanner is ready. * * The only reason I know the scanner is not ready is because it is - * moving the CCD. + * moving the CCD. */ static SANE_Status sceptre_wait_scanner (Sceptre_Scanner * dev) @@ -873,7 +873,7 @@ sceptre_wait_scanner (Sceptre_Scanner * dev) return (SANE_STATUS_IO_ERROR); } - /* Apparently the scanner returns only 2 values: + /* Apparently the scanner returns only 2 values: * 0x00 - ready * 0xff - not ready */ @@ -1067,7 +1067,7 @@ sceptre_fill_image (Sceptre_Scanner * dev) /* Copy the complete lines, plus the imcompletes * ones. We don't keep the real end of data used - * in image, so we copy the biggest possible. + * in image, so we copy the biggest possible. * * This is a no-op for non color images. */ @@ -1083,7 +1083,7 @@ sceptre_fill_image (Sceptre_Scanner * dev) return (status); } - /* + /* * Try to read the maximum number of bytes. */ size = data_left; @@ -1105,7 +1105,7 @@ sceptre_fill_image (Sceptre_Scanner * dev) if (size == 0) { - /* Probably reached the end of the buffer. + /* Probably reached the end of the buffer. * Check, just in case. */ assert (dev->image_end != 0); return (SANE_STATUS_GOOD); @@ -1163,7 +1163,7 @@ sceptre_fill_image (Sceptre_Scanner * dev) return (SANE_STATUS_GOOD); /* unreachable */ } -/* Copy from the raw buffer to the buffer given by the backend. +/* Copy from the raw buffer to the buffer given by the backend. * * len in input is the maximum length available in buf, and, in * output, is the length written into buf. @@ -1693,11 +1693,11 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) dev->width = dev->x_br - dev->x_tl; dev->length = dev->y_br - dev->y_tl; - /* + /* * Adjust the "X Resolution". The sceptre S1200 ignores the * Y-Resolution parameter in the windows block. X-Resolution * is used instead. However the limits are not the same for X - * (600 dpi) and Y (1200 dpi). + * (600 dpi) and Y (1200 dpi). */ x_dpi = dev->resolution; if (x_dpi > 600) @@ -1779,7 +1779,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) * 2n + [0.0 .. 2.0[ -> round to 2n * * Note: the rounding is often incorrect at high - * resolution (ag more than 300dpi) + * resolution (ag more than 300dpi) */ dev->params.lines = (dev->length * dev->resolution) / 600; dev->params.lines &= ~1; diff --git a/backend/sceptre.h b/backend/sceptre.h index 726c131..8ba5cd8 100644 --- a/backend/sceptre.h +++ b/backend/sceptre.h @@ -37,10 +37,10 @@ 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. + If you do not wish that, delete this exception notice. */ -/* +/* $Id$ */ @@ -269,8 +269,8 @@ enum Sceptre_Option /*--------------------------------------------------------------------------*/ -/* - * Scanner supported by this backend. +/* + * Scanner supported by this backend. */ struct scanners_supported { @@ -382,7 +382,7 @@ Sceptre_Scanner; /*--------------------------------------------------------------------------*/ -/* Debug levels. +/* Debug levels. * Should be common to all backends. */ #define DBG_error0 0 diff --git a/backend/scripts/pixma_gen_options.py b/backend/scripts/pixma_gen_options.py new file mode 100755 index 0000000..c4c75e0 --- /dev/null +++ b/backend/scripts/pixma_gen_options.py @@ -0,0 +1,389 @@ +#!/usr/bin/env python + +import sys,os,re + +class Error(Exception): + pass + + +class ParseError(Error): + def __init__(self, errline): + Error.__init__(self, errline) + + +class Struct: + pass + + +def createCNameMap(): + t = '' + for i in range(256): + if ((ord('A') <= i) and (i <= ord('Z'))) or \ + ((ord('a') <= i) and (i <= ord('z'))) or \ + ((ord('0') <= i) and (i <= ord('9'))): + t += chr(i) + else: + t += '_' + return t + + +def seekBegin(f): + while True: + line = f.readline() + if not line: + return False + if line.startswith('BEGIN SANE_Option_Descriptor'): + return True + + +def parseVerbatim(o, line): + words = line.split(None, 1) + if (len(words) < 2) or (words[1][0] != '@'): + return False + o[words[0]] = words[1] + return True + + +def parseLine_type(o, line): + words = line.split(None, 2) + otype = words[1] + o['type'] = 'SANE_TYPE_' + otype.upper() + if otype == 'group': + g.ngroups += 1 + oname = '_group_%d' % g.ngroups + o['size'] = 0 + else: + temp = words[2] + idx = temp.find('[') + if idx == -1: + oname = temp + o['size'] = 1 + else: + oname = temp[0:idx] + o['size'] = int(temp[idx+1:-1]) + o['name'] = oname + + +def parseLine_title(o, line): + o['title'] = line.split(None, 1)[1] + + +def parseLine_desc(o, line): + o['desc'] = line.split(None, 1)[1] + + +def parseLine_unit(o, line): + o['unit'] = 'SANE_UNIT_' + line.split(None, 1)[1].upper() + + +def parseLine_default(o, line): + o['default'] = line.split(None, 1)[1] + + +def parseLine_cap(o, line): + words = line.split() + o['cap'] = ['SANE_CAP_' + s.upper() for s in words[1:]] + + +def parseLine_constraint(o, line): + c = line.split(None,1)[1] + if c[0] == '{': + o['constraint'] = c[1:-1].split('|') + elif c[0] == '(': + o['constraint'] = tuple(c[1:-1].split(',')) + else: + sys.stderr.write('Ignored: %s\n' % line) + + +def parseLine_info(o, line): + words = line.split() + o['info'] = ['SANE_INFO_' + s.upper() for s in words[1:]] + +def parseLine_rem(o, line): + pass + +def normalize(o): + if 'cname' not in o: + cname = o['name'].translate(cnameMap) + o['cname'] = cname + else: + cname = o['cname'] + o['cname_opt'] = 'opt_' + cname + o['cname_con'] = 'constraint_' + cname + if 'title' not in o: + o['title'] = 'NO TITLE' + if 'desc' not in o: + o['desc'] = '@sod->title' % o + if 'unit' not in o: + o['unit'] = 'SANE_UNIT_NONE' + if 'constraint_type' not in o: + if 'constraint' not in o: + ct = 'SANE_CONSTRAINT_NONE' + elif isinstance(o['constraint'], list): + if o['type'] == 'SANE_TYPE_STRING': + ct = 'SANE_CONSTRAINT_STRING_LIST' + else: + ct = 'SANE_CONSTRAINT_WORD_LIST' + elif isinstance(o['constraint'], tuple): + ct = 'SANE_CONSTRAINT_RANGE' + elif isinstance(o['constraint'], str): + oc = o['constraint'] + if oc.startswith('@range'): + ct = 'SANE_CONSTRAINT_RANGE' + elif oc.startswith('@word_list'): + ct = 'SANE_CONSTRAINT_WORD_LIST' + elif oc.startswith('@string_list'): + ct = 'SANE_CONSTRAINT_STRING_LIST' + o['constraint_type'] = ct + return o + + +def parseFile(f): + if not seekBegin(f): + return None + options = [ { + 'name' : '', + 'cname' : 'opt_num_opts', + 'title' : '@SANE_TITLE_NUM_OPTIONS', + 'desc' : '@SANE_DESC_NUM_OPTIONS', + 'type' : 'SANE_TYPE_INT', + 'unit' : 'SANE_UNIT_NONE', + 'size' : 1, + 'cap' : ['SANE_CAP_SOFT_DETECT'], + 'constraint_type' : 'SANE_CONSTRAINT_NONE', + 'default' : '@w = ' + opt_prefix + 'last' + } ] + o = {} + while True: + line = f.readline() + if not line: + break + line = line.strip() + if not line: + continue + token = line.split(None, 1)[0].lower() + if token == 'end': + break + if token == 'type': + if 'name' in o: + options.append(o) + o = {} + funcName = 'parseLine_' + token + if funcName in globals(): + if not parseVerbatim(o, line): + func = globals()[funcName] + func(o, line) + else: + sys.stderr.write('Skip: %s\n' % line) + if 'name' in o: + options.append(o) + return [normalize(o) for o in options] + + +def genHeader(options): + print """ +typedef union { + SANE_Word w; + SANE_Int i; + SANE_Bool b; + SANE_Fixed f; + SANE_String s; + void *ptr; +} option_value_t; +""" + print 'typedef enum {' + for o in options: + print ' %(cname_opt)s,' % o + print ' ' + opt_prefix + 'last' + print '} option_t;' + print """ + +typedef struct { + SANE_Option_Descriptor sod; + option_value_t val,def; + SANE_Word info; +} option_descriptor_t; + + +struct pixma_sane_t; +static int build_option_descriptors(struct pixma_sane_t *ss); +""" + + +def genMinMaxRange(n, t, r): + if t == 'SANE_TYPE_FIXED': + r = ['SANE_FIX(%s)' % x for x in r] + print 'static const SANE_Range ' + n + ' = ' + print ' { ' + r[0] + ',' + r[1] + ',' + r[2] + ' };' + + +def genList(n, t, l): + if t == 'SANE_TYPE_INT': + etype = 'SANE_Word' + l = [str(len(l))] + l + elif t == 'SANE_TYPE_FIXED': + etype = 'SANE_Word' + l = [str(len(l))] + ['SANE_FIX(%s)' % x for x in l] + elif t == 'SANE_TYPE_STRING': + etype = 'SANE_String_Const' + l = ['SANE_I18N("%s")' % x for x in l] + ['NULL'] + print 'static const %s %s[%d] = {' % (etype, n, len(l)) + for x in l[0:-1]: + print '\t' + x + ',' + print '\t' + l[-1] + ' };' + + +def genConstraints(options): + for o in options: + if 'constraint' not in o: continue + c = o['constraint'] + oname = o['cname_con'] + otype = o['type'] + if isinstance(c, tuple): + genMinMaxRange(oname, otype, c) + elif isinstance(c, list): + genList(oname, otype, c) + print + +def buildCodeVerbatim(o): + for f in ('name', 'title', 'desc', 'type', 'unit', 'size', 'cap', + 'constraint_type', 'constraint', 'default'): + if (f not in o): continue + temp = o[f] + if (not isinstance(temp,str)) or \ + (len(temp) < 1) or (temp[0] != '@'): + continue + o['code_' + f] = temp[1:] + +def ccode(o): + buildCodeVerbatim(o) + if 'code_name' not in o: + o['code_name'] = '"' + o['name'] + '"' + for f in ('title', 'desc'): + cf = 'code_' + f + if cf in o: continue + o[cf] = 'SANE_I18N("' + o[f] + '")' + + for f in ('type', 'unit', 'constraint_type'): + cf = 'code_' + f + if cf in o: continue + o[cf] = o[f] + + if 'code_size' not in o: + otype = o['type'] + osize = o['size'] + if otype == 'SANE_TYPE_STRING': + code = str(osize + 1) + elif otype == 'SANE_TYPE_INT' or otype == 'SANE_TYPE_FIXED': + code = str(osize) + ' * sizeof(SANE_Word)' + elif otype == 'SANE_TYPE_BUTTON': + code = '0' + else: + code = 'sizeof(SANE_Word)' + o['code_size'] = code + + if ('code_cap' not in o) and ('cap' in o): + o['code_cap'] = reduce(lambda a,b: a+'|'+b, o['cap']) + else: + o['code_cap'] = '0' + + if ('code_info' not in o) and ('info' in o): + o['code_info'] = reduce(lambda a,b: a+'|'+b, o['info']) + else: + o['code_info'] = '0' + + if ('code_default' not in o) and ('default' in o): + odefault = o['default'] + otype = o['type'] + if odefault == '_MIN': + rhs = 'w = sod->constraint.range->min' + elif odefault == '_MAX': + rhs = 'w = sod->constraint.range->max' + elif otype in ('SANE_TYPE_INT', 'SANE_TYPE_BOOL'): + rhs = 'w = %(default)s' + elif otype == 'SANE_TYPE_FIXED': + rhs = 'w = SANE_FIX(%(default)s)' + elif otype == 'SANE_TYPE_STRING': + rhs = 's = SANE_I18N("%(default)s")' + o['code_default'] = rhs % o + if 'code_default' in o: + code = ' opt->def.%(code_default)s;\n' + if o['constraint_type'] != 'SANE_CONSTRAINT_STRING_LIST': + code += ' opt->val.%(code_default)s;\n' + else: + code += ' opt->val.w = find_string_in_list' \ + '(opt->def.s, sod->constraint.string_list);\n' + o['full_code_default'] = code % o + else: + o['full_code_default'] = '' + + if ('code_constraint' not in o) and ('constraint' in o): + ct = o['constraint_type'] + idx = len('SANE_CONSTRAINT_') + ctype = ct[idx:].lower() + if ctype == 'range': + rhs = '&%(cname_con)s' % o + else: + rhs = '%(cname_con)s' % o + o['code_constraint'] = ctype + ' = ' + rhs + if 'code_constraint' in o: + code = ' sod->constraint.%(code_constraint)s;\n' + o['full_code_constraint'] = code % o + else: + o['full_code_constraint'] = '' + + return o + +def genBuildOptions(options): + print """ +static +int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list) +{ + int i; + for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {} + return i; +} + +static +int build_option_descriptors(struct pixma_sane_t *ss) +{ + SANE_Option_Descriptor *sod; + option_descriptor_t *opt; + + memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX));""" + + for o in options: + o = ccode(o) + otype = o['type'] + code = '\n opt = &(OPT_IN_CTX[%(cname_opt)s]);\n' \ + ' sod = &opt->sod;\n' \ + ' sod->type = %(code_type)s;\n' \ + ' sod->title = %(code_title)s;\n' \ + ' sod->desc = %(code_desc)s;\n' + if otype != 'SANE_TYPE_GROUP': + code += ' sod->name = %(code_name)s;\n' \ + ' sod->unit = %(code_unit)s;\n' \ + ' sod->size = %(code_size)s;\n' \ + ' sod->cap = %(code_cap)s;\n' \ + ' sod->constraint_type = %(code_constraint_type)s;\n' \ + '%(full_code_constraint)s' \ + ' OPT_IN_CTX[%(cname_opt)s].info = %(code_info)s;\n' \ + '%(full_code_default)s' + sys.stdout.write(code % o) + print + print ' return 0;\n' + print '}' + print + +g = Struct() +g.ngroups = 0 +opt_prefix = 'opt_' +con_prefix = 'constraint_' +cnameMap = createCNameMap() +options = parseFile(sys.stdin) +print "/* Automatically generated from pixma_sane.c */" +if (len(sys.argv) == 2) and (sys.argv[1] == 'h'): + genHeader(options) +else: + genConstraints(options) + genBuildOptions(options) diff --git a/backend/sharp.c b/backend/sharp.c index 69f5000..b2807d7 100644 --- a/backend/sharp.c +++ b/backend/sharp.c @@ -2,7 +2,7 @@ Copyright (C) 1998, 1999 Kazuya Fukuda, Abel Deuring based on BYTEC GmbH Germany - Written by Helmut Koeberle previous Work on canon.c file from the + Written by Helmut Koeberle previous Work on canon.c file from the SANE package. This file is part of the SANE package. @@ -50,18 +50,18 @@ changes to version 0.31: - support for JX320 added (Thanks to Isaac Wilcox for providind the patch) - + Version 0.31 changes to version 0.30: - support for JX350 added (Thanks to Shuhei Tomita for providind the patch) - + changes to version 0.20 - support for the proposed extended open function in sanei_scsi.c added - support for ADF and FSU (transparency adapter) added - simple sense handler added - preview added - - added several missing statements "s->fd = -1;" after + - added several missing statements "s->fd = -1;" after "sanei_scsi_close(s->fd)" to error returns in sane_start(); - maximum scan sizes are read from the scanner, if a JX330 or JX250 is used. (this avoids the guessing of scan sizes for the JX330) @@ -69,7 +69,7 @@ - "Fixed gamma selection (1.0/2.2)", available for JX330 and JX610, is now implemented for the JX250 by downloading a gamma table - changed the calls to free() and strdup() in sane_control_option to - strcpy. + strcpy. (I don't like too frequent unchecked malloc()s and strdups :) Abel) - cleaned up some quirks in option handling, eg, that "threshold" was initially enabled, while the initial scan mode is "color" @@ -133,12 +133,12 @@ */ #define USE_CUSTOM_GAMMA #define USE_COLOR_THRESHOLD -/* enable a short list of some standard resolutions. XSane provides +/* enable a short list of some standard resolutions. XSane provides its own resolution list; therefore its is generally not reasonable to enable this list, if you mainly using XSane. But it might be handy if you are working with xscanimage */ -/* #define USE_RESOLUTION_LIST */ +/* #define USE_RESOLUTION_LIST */ /* enable separate specification of resolution in X and Y direction. XSane will show the Y-resolution at a quite different place than @@ -220,15 +220,15 @@ static SANE_String use_adf = "Automatic Document Feeder"; static SANE_String use_fsu = "Transparency Adapter"; static SANE_String use_simple = "Flatbed"; -/* auto selection of ADF and FSU, as described in the JX330 manual, - is a nice idea -- but I assume that the possible scan window - sizes depend not only for the JX250, but also for JX330 on the +/* auto selection of ADF and FSU, as described in the JX330 manual, + is a nice idea -- but I assume that the possible scan window + sizes depend not only for the JX250, but also for JX330 on the usage of ADF or FSU. Thus, the user might be able to select scan windows of an "illegal" size, which would have to be automatically - corrected, and I don't see, how the user could be informed about - this "window clipping". More important, I don't see, how the + corrected, and I don't see, how the user could be informed about + this "window clipping". More important, I don't see, how the frontend could be informed that the ADF is automatically enabled. - + Insert a "#define ALLOW_AUTO_SELECT_ADF", if you want to play with this feature. */ @@ -239,8 +239,8 @@ static SANE_String_Const use_auto = "AutoSelection"; #define HAVE_FSU 1 #define HAVE_ADF 2 -/* The follow #defines are used in SHARP_Scanner.adf_fsu_mode - and as indexes for the arrays x_ranges, y_ranges in SHARP_Device +/* The follow #defines are used in SHARP_Scanner.adf_fsu_mode + and as indexes for the arrays x_ranges, y_ranges in SHARP_Device */ #define SCAN_SIMPLE 0 #define SCAN_WITH_FSU 1 @@ -326,17 +326,17 @@ sense_handler(int __sane_unused__ fd, u_char *sense_buffer, void *s) { int sense_key; SHARP_Sense_Data *sdat = (SHARP_Sense_Data *) s; - + #define add_sense_code sense_buffer[12] #define add_sense_qual sense_buffer[13] memcpy(sdat->sb, sense_buffer, 16); - + DBG(10, "sense code: %02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n", - sense_buffer[0], sense_buffer[1], sense_buffer[2], sense_buffer[3], - sense_buffer[4], sense_buffer[5], sense_buffer[6], sense_buffer[7], - sense_buffer[8], sense_buffer[9], sense_buffer[10], sense_buffer[11], + sense_buffer[0], sense_buffer[1], sense_buffer[2], sense_buffer[3], + sense_buffer[4], sense_buffer[5], sense_buffer[6], sense_buffer[7], + sense_buffer[8], sense_buffer[9], sense_buffer[10], sense_buffer[11], sense_buffer[12], sense_buffer[13], sense_buffer[14], sense_buffer[15]); sense_key = sense_buffer[2] & 0x0F; @@ -394,7 +394,7 @@ sense_handler(int __sane_unused__ fd, u_char *sense_buffer, void *s) DBG(1, "scan head positioning error\n"); return SANE_STATUS_IO_ERROR; } - + } else if (sdat->model == JX250 || sdat->model == JX330 || sdat->model == JX350 || sdat->model == JX320) @@ -561,7 +561,7 @@ inquiry (int fd, void *inq_buf, size_t *inq_size) static SANE_Status mode_select_mud (int fd, int mud) { - static u_char cmd[6 + MODEPARAM_LEN] = + static u_char cmd[6 + MODEPARAM_LEN] = {MODE_SELECT6, 0x10, 0, 0, MODEPARAM_LEN, 0}; mode_select_param *mp; SANE_Status status; @@ -583,7 +583,7 @@ mode_select_mud (int fd, int mud) static SANE_Status mode_select_adf_fsu (int fd, int mode) { - static u_char cmd[6 + MODE_SUBDEV_LEN] = + static u_char cmd[6 + MODE_SUBDEV_LEN] = {MODE_SELECT6, 0x10, 0, 0, MODE_SUBDEV_LEN, 0}; mode_select_subdevice *mp; SANE_Status status; @@ -670,7 +670,7 @@ release_unit (int fd) #endif static SANE_Status -mode_sense (int fd, void *modeparam_buf, size_t * modeparam_size, +mode_sense (int fd, void *modeparam_buf, size_t * modeparam_size, int page) { static u_char cmd[6]; @@ -681,7 +681,7 @@ mode_sense (int fd, void *modeparam_buf, size_t * modeparam_size, cmd[0] = 0x1a; cmd[2] = page; cmd[4] = *modeparam_size; - status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), modeparam_buf, + status = sanei_scsi_cmd (fd, cmd, sizeof (cmd), modeparam_buf, modeparam_size); DBG (11, ">>\n"); @@ -740,7 +740,7 @@ send (int fd, SHARP_Send * ss) static SANE_Status set_window (int fd, window_param *wp, int len) { - static u_char cmd[10 + WINDOW_LEN] = + static u_char cmd[10 + WINDOW_LEN] = {SET_WINDOW, 0, 0, 0, 0, 0, 0, 0, 0, 0}; window_param *winp; SANE_Status status; @@ -775,17 +775,17 @@ get_window (int fd, void *buf, size_t * buf_size) #ifdef USE_FORK /* the following four functions serve simply the purpose - to avoid "over-optimised" code when reader_process and - read_data wait for the buffer to become ready. The simple - while-loops in these functions which check the buffer - status may be optimised so that the machine code only - operates with registers instead of using the variable - values stored in memory. (This is only a workaround - + to avoid "over-optimised" code when reader_process and + read_data wait for the buffer to become ready. The simple + while-loops in these functions which check the buffer + status may be optimised so that the machine code only + operates with registers instead of using the variable + values stored in memory. (This is only a workaround - it would be better to set a compiler pragma, which ensures that the program looks into the RAM in these while loops -- but unfortunately I could not find appropriate information - about this at least for gcc, not to speak about other - compilers... + about this at least for gcc, not to speak about other + compilers... Abel) */ @@ -795,7 +795,7 @@ cancel_requested(SHARP_Scanner *s) return s->rdr_ctl->cancel; } -static SANE_Status +static SANE_Status rdr_status(SHARP_Scanner *s) { return s->rdr_ctl->status; @@ -832,9 +832,9 @@ reader_process(SHARP_Scanner *s) DBG(11, "<< reader_process\n"); sigemptyset (&sigterm_set); - + bytes_to_queue = s->bytes_to_read; - + /* it seems that some carriage stops can be avoided with the JX-250, if the data of an integral number of scan lines is read with one SCSI command @@ -845,9 +845,9 @@ reader_process(SHARP_Scanner *s) else /* this is a really tiny buffer..*/ max_bytes_per_read = s->dev->info.bufsize; - + /* wait_ready(s->fd); */ - + if (s->dev->info.queued_reads <= s->dev->info.buffers) max_queue = s->dev->info.queued_reads; else @@ -869,16 +869,16 @@ reader_process(SHARP_Scanner *s) #ifdef QUEUEDEBUG DBG(2, "reader: req_enter...\n"); #endif - status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd), - bc->buffer, - &bc->used, + status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd), + bc->buffer, + &bc->used, &bc->qid); #ifdef QUEUEDEBUG DBG(2, "reader: req_enter ok\n"); #endif if (status != SANE_STATUS_GOOD) { - DBG(1, "reader_process: read command failed: %s", + DBG(1, "reader_process: read command failed: %s", sane_strstatus(status)); #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED sanei_scsi_req_flush_all_extended(s->fd); @@ -902,9 +902,9 @@ reader_process(SHARP_Scanner *s) waitindex = 0; cmdindex = i % s->dev->info.buffers; - while(s->bytes_to_read > 0) + while(s->bytes_to_read > 0) { - if (cancel_requested(s)) + if (cancel_requested(s)) { #ifdef QUEUEDEBUG DBG(2, "reader: flushing requests...\n"); @@ -925,7 +925,7 @@ reader_process(SHARP_Scanner *s) } bc = &s->rdr_ctl->buf_ctl[waitindex]; - if (bc->shm_status == SHM_BUSY) + if (bc->shm_status == SHM_BUSY) { #ifdef DEBUG { @@ -948,7 +948,7 @@ reader_process(SHARP_Scanner *s) DBG(2, "rd: data received %li.%06li\n", t.tv_sec, t.tv_usec); } #endif - if (status == SANE_STATUS_DEVICE_BUSY && retries) + if (status == SANE_STATUS_DEVICE_BUSY && retries) { bc->used = 0; retries--; @@ -958,7 +958,7 @@ reader_process(SHARP_Scanner *s) } else if (status != SANE_STATUS_GOOD) { - DBG(1, "reader_process: read command failed: %s\n", + DBG(1, "reader_process: read command failed: %s\n", sane_strstatus(status)); #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED sanei_scsi_req_flush_all_extended(s->fd); @@ -969,7 +969,7 @@ reader_process(SHARP_Scanner *s) s->rdr_ctl->running = 0; return 2; } - else + else { retries = MAX_RETRIES; } @@ -982,7 +982,7 @@ reader_process(SHARP_Scanner *s) /* memset(bc->buffer + bc->used, 0, bc->nreq - bc->used); */ bc->used = bc->nreq; /* bytes_to_queue += bc->nreq - bc->used; */ - DBG(1, "btr: %i btq: %i nreq: %i nrcv: %i\n", + DBG(1, "btr: %i btq: %i nreq: %i nrcv: %i\n", s->bytes_to_read, bytes_to_queue, bc->nreq, bc->used); #endif bc->start = 0; @@ -993,7 +993,7 @@ reader_process(SHARP_Scanner *s) waitindex = 0; } - + if (bytes_to_queue) { /* wait until the next buffer is completely read via read_data */ @@ -1028,11 +1028,11 @@ reader_process(SHARP_Scanner *s) cmd[6] = nread >> 16; cmd[7] = nread >> 8; cmd[8] = nread; - status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd), + status = sanei_scsi_req_enter (s->fd, cmd, sizeof (cmd), bc->buffer, &bc->used, &bc->qid); if (status != SANE_STATUS_GOOD) { - DBG(1, "reader_process: read command failed: %s", + DBG(1, "reader_process: read command failed: %s", sane_strstatus(status)); #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED sanei_scsi_req_flush_all_extended(s->fd); @@ -1046,13 +1046,13 @@ reader_process(SHARP_Scanner *s) bc->shm_status = SHM_BUSY; bc->nreq = nread; bytes_to_queue -= nread; - + cmdindex++; if (cmdindex == s->dev->info.buffers) cmdindex = 0; } - - if (cancel_requested(s)) + + if (cancel_requested(s)) { #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED sanei_scsi_req_flush_all_extended(s->fd); @@ -1066,7 +1066,7 @@ reader_process(SHARP_Scanner *s) return 1; } } - + DBG(1, "buffer full conditions: %i\n", full_count); DBG(11, " reader_process>>\n"); @@ -1079,7 +1079,7 @@ read_data (SHARP_Scanner *s, SANE_Byte *buf, size_t * buf_size) { size_t copysize, copied = 0; SHARP_shmem_ctl *bc; - + DBG(11, "<< read_data "); bc = &s->rdr_ctl->buf_ctl[s->read_buff]; @@ -1088,7 +1088,7 @@ read_data (SHARP_Scanner *s, SANE_Byte *buf, size_t * buf_size) { /* wait until the reader process delivers data or a scanner error occurs: */ while ( buf_status(bc) != SHM_FULL - && rdr_status(s) == SANE_STATUS_GOOD) + && rdr_status(s) == SANE_STATUS_GOOD) { usleep(10); /* could perhaps be longer. make this user configurable?? */ } @@ -1100,10 +1100,10 @@ read_data (SHARP_Scanner *s, SANE_Byte *buf, size_t * buf_size) } copysize = bc->used - bc->start; - + if (copysize > *buf_size - copied ) copysize = *buf_size - copied; - + memcpy(buf, &(bc->buffer[bc->start]), copysize); copied += copysize; @@ -1139,8 +1139,8 @@ read_data (SHARP_Scanner *s, SANE_Byte *buf, size_t * buf_size) /* sane_read_shuffled requires that read_data returns exactly *buf_size bytes, so it must be guaranteed here. - Further make sure that not more bytes are read in than - sanei_scsi_max_request_size allows, to avoid a failure + Further make sure that not more bytes are read in than + sanei_scsi_max_request_size allows, to avoid a failure of the read command */ while (remain > 0) @@ -1151,7 +1151,7 @@ read_data (SHARP_Scanner *s, SANE_Byte *buf, size_t * buf_size) cmd[6] = nread >> 16; cmd[7] = nread >> 8; cmd[8] = nread; - status = sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), + status = sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), &buf[*buf_size - remain], &nread); if (status == SANE_STATUS_DEVICE_BUSY && retries) { @@ -1164,7 +1164,7 @@ read_data (SHARP_Scanner *s, SANE_Byte *buf, size_t * buf_size) DBG(11, ">>\n"); return(status); } - else + else { retries = MAX_RETRIES; } @@ -1208,7 +1208,7 @@ wait_ready(int fd) sleep(3); } return (status); - + } /* ask the scanner for the maximum scan sizes with/without ADF and @@ -1220,7 +1220,7 @@ get_max_scan_size(int fd, SHARP_Device *dev, int mode) SANE_Status status; mode_sense_subdevice m_subdev; size_t buf_size; - + status = mode_select_adf_fsu(fd, mode); if (status != SANE_STATUS_GOOD) { @@ -1245,7 +1245,7 @@ get_max_scan_size(int fd, SHARP_Device *dev, int mode) (m_subdev.max_x[0] << 24) + (m_subdev.max_x[1] << 16) + (m_subdev.max_x[2] << 8) + m_subdev.max_x[3] - 1, dev->info.mud)); dev->info.tl_x_ranges[mode].quant = 0; - + dev->info.br_x_ranges[mode].min = SANE_FIX(PIX_TO_MM(1, dev->info.mud)); dev->info.br_x_ranges[mode].max = SANE_FIX(PIX_TO_MM( (m_subdev.max_x[0] << 24) + (m_subdev.max_x[1] << 16) + @@ -1261,19 +1261,19 @@ get_max_scan_size(int fd, SHARP_Device *dev, int mode) else /* The manual for the JX250 states on page 62 that the maximum value for tl_y in FSU mode is 13199, while the max value for - br_y is 13900, which is (probably -- I don't have a FSU) returned - by mode sense/subdevice page. Therefore, we cannot simply + br_y is 13900, which is (probably -- I don't have a FSU) returned + by mode sense/subdevice page. Therefore, we cannot simply decrement that value and store it as max(tl_y). */ dev->info.tl_y_ranges[mode].max = 13199; dev->info.tl_y_ranges[mode].quant = 0; - + dev->info.br_y_ranges[mode].min = SANE_FIX(PIX_TO_MM(1, dev->info.mud)); dev->info.br_y_ranges[mode].max = SANE_FIX(PIX_TO_MM( (m_subdev.max_y[0] << 24) + (m_subdev.max_y[1] << 16) + (m_subdev.max_y[2] << 8) + m_subdev.max_y[3], dev->info.mud)); dev->info.br_y_ranges[mode].quant = 0; - + return SANE_STATUS_GOOD; } @@ -1374,7 +1374,7 @@ attach (const char *devnam, SHARP_Device ** devp) } DBG (3, "attach: sending MODE SELECT\n"); - /* JX-610 probably supports only 25 MUD size + /* JX-610 probably supports only 25 MUD size JX-320 only supports 25 MUD size */ if (strncmp (inquiry_data + 16, "JX610", 5) == 0) @@ -1412,7 +1412,7 @@ attach (const char *devnam, SHARP_Device ** devp) model_name = (char*) inquiry_data + 16; dev->sane.model = strndup (model_name, 10); dev->sane.type = "flatbed scanner"; - + dev->sensedat.model = sensedat.model; DBG (5, "dev->sane.name = %s\n", dev->sane.name); @@ -1441,7 +1441,7 @@ attach (const char *devnam, SHARP_Device ** devp) dev->info.bmu = msp.bmu; dev->info.mud = (msp.mud[0] << 8) + msp.mud[1]; - + dev->info.adf_fsu_installed = 0; if (dev->sensedat.model == JX610) { @@ -1475,7 +1475,7 @@ attach (const char *devnam, SHARP_Device ** devp) } else { - /* ask the scanner, if ADF or FSU are installed, and ask for + /* ask the scanner, if ADF or FSU are installed, and ask for the maximum scan sizes with/without ADF and FSU. */ @@ -1489,23 +1489,23 @@ attach (const char *devnam, SHARP_Device ** devp) sanei_scsi_close (fd); return (SANE_STATUS_INVAL); } - + /* The JX330 manual is not very clear about the ADF- und FSU-Bits - returned by a JX320 and JX325 for the mode sense command: + returned by a JX320 and JX325 for the mode sense command: Are these bits set to zero or not? To be on the safe side, let's clear them. */ - + if ( strncmp(inquiry_data + 16, "JX320", 5) == 0 || strncmp(inquiry_data + 16, "JX325", 5) == 0) { m_subdev.f_mode_type = 0; m_subdev.a_mode_type = 0; } - + get_max_scan_size(fd, dev, SCAN_SIMPLE); - - if (m_subdev.a_mode_type & 0x03) + + if (m_subdev.a_mode_type & 0x03) { dev->info.adf_fsu_installed = HAVE_ADF; get_max_scan_size(fd, dev, SCAN_WITH_ADF); @@ -1516,7 +1516,7 @@ attach (const char *devnam, SHARP_Device ** devp) get_max_scan_size(fd, dev, SCAN_WITH_FSU); } - if ( dev->sensedat.model == JX320 + if ( dev->sensedat.model == JX320 || dev->sensedat.model == JX330 || dev->sensedat.model == JX350) { @@ -1540,7 +1540,7 @@ attach (const char *devnam, SHARP_Device ** devp) } } sanei_scsi_close (fd); - + dev->info.threshold_range.min = 1; dev->info.threshold_range.max = 255; dev->info.threshold_range.quant = 0; @@ -1616,12 +1616,12 @@ attach (const char *devnam, SHARP_Device ** devp) } /* Enabling / disabling of gamma options. - Depends on many user settable options, so lets put it into + Depends on many user settable options, so lets put it into one function to be called by init_options and by sane_control_option */ #ifdef USE_CUSTOM_GAMMA -static void +static void set_gamma_caps(SHARP_Scanner *s) { /* neither fixed nor custom gamma for line art modes */ @@ -1761,11 +1761,11 @@ clip_value (const SANE_Option_Descriptor * opt, void * value) /* make sure that enough memory is allocated for each string, so that the strcpy in sane_control_option / set value cannot - write behind the end of the allocated memory. + write behind the end of the allocated memory. */ static SANE_Status -init_string_option(SHARP_Scanner *s, SANE_String_Const name, - SANE_String_Const title, SANE_String_Const desc, +init_string_option(SHARP_Scanner *s, SANE_String_Const name, + SANE_String_Const title, SANE_String_Const desc, const SANE_String_Const *string_list, int option, int default_index) { int i; @@ -1869,7 +1869,7 @@ init_options (SHARP_Scanner * s) sourcename_index = i; s->dev->info.scansources[i++] = use_adf; } - else + else { if (default_source == SCAN_WITH_ADF) default_source = SCAN_SIMPLE; @@ -1893,7 +1893,7 @@ init_options (SHARP_Scanner * s) sourcename_index = i; s->dev->info.scansources[i++] = use_simple; s->dev->info.scansources[i] = 0; - + #if 0 s->opt[OPT_SCANSOURCE].name = SANE_NAME_SCAN_SOURCE; s->opt[OPT_SCANSOURCE].title = SANE_TITLE_SCAN_SOURCE; @@ -1927,7 +1927,7 @@ init_options (SHARP_Scanner * s) s->opt[OPT_PAPER].constraint.string_list = paper_list_jx610; s->val[OPT_PAPER].s = strdup (paper_list_jx610[1]); } - else + else { s->opt[OPT_PAPER].size = max_string_size (paper_list_jx330); s->opt[OPT_PAPER].constraint_type = SANE_CONSTRAINT_STRING_LIST; @@ -1975,10 +1975,10 @@ init_options (SHARP_Scanner * s) #ifdef USE_RESOLUTION_LIST if (s->dev->sensedat.model == JX610 || s->dev->sensedat.model == JX330 || s->dev->sensedat.model == JX350 || s->dev->sensedat.model == JX320) - init_string_option(s, "ResolutionList", "ResolutionList", "ResolutionList", + init_string_option(s, "ResolutionList", "ResolutionList", "ResolutionList", resolution_list_jx610, OPT_RESOLUTION_LIST, RESOLUTION_MAX_JX610); else - init_string_option(s, "ResolutionList", "ResolutionList", "ResolutionList", + init_string_option(s, "ResolutionList", "ResolutionList", "ResolutionList", resolution_list_jx250, OPT_RESOLUTION_LIST, RESOLUTION_MAX_JX250); #endif /* x resolution */ @@ -2050,7 +2050,7 @@ init_options (SHARP_Scanner * s) s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; s->opt[OPT_BR_Y].constraint.range = &s->dev->info.br_y_ranges[default_source]; - /* The FSU for JX250 allows a maximum scan length of 11.5 inch, + /* The FSU for JX250 allows a maximum scan length of 11.5 inch, which is less than the default value of 297 mm */ scalar = s->dev->info.y_default; @@ -2097,7 +2097,7 @@ init_options (SHARP_Scanner * s) #ifdef USE_COLOR_THRESHOLD s->opt[OPT_THRESHOLD_R].name = SANE_NAME_THRESHOLD "-red"; /* xxx the titles and decriptions are confusing: - "set white point (red)" + "set white point (red)" Any idea? maybe "threshold to get the red component on" */ s->opt[OPT_THRESHOLD_R].title = SANE_TITLE_THRESHOLD " (red)"; @@ -2153,7 +2153,7 @@ init_options (SHARP_Scanner * s) s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; s->val[OPT_PREVIEW].w = SANE_FALSE; - + #ifdef USE_CUSTOM_GAMMA /* custom-gamma table */ @@ -2241,14 +2241,14 @@ do_cancel (SHARP_Scanner * s) DBG(11, "stopping reader process\n"); s->rdr_ctl->cancel = 1; - while(reader_running(s) && count < 100) + while(reader_running(s) && count < 100) { usleep(100000); count++; }; if (reader_running(s)) { - /* be brutal... + /* be brutal... !! The waiting time of 10 seconds might be far too short !! if the resolution limit of the JX 250 is increased to !! to more than 400 dpi: for these (interpolated) resolutions, @@ -2299,13 +2299,13 @@ do_cancel (SHARP_Scanner * s) static SHARP_New_Device *new_devs = 0; static SHARP_New_Device *new_dev_pool = 0; -static SANE_Status +static SANE_Status attach_and_list(const char *devnam) { SANE_Status res; SHARP_Device *devp; SHARP_New_Device *np; - + res = attach(devnam, &devp); if (res == SANE_STATUS_GOOD) { @@ -2332,10 +2332,10 @@ static int bufsize[2] = {DEFAULT_BUFSIZE, DEFAULT_BUFSIZE}; static int queued_reads[2] = {DEFAULT_QUEUED_READS, DEFAULT_QUEUED_READS}; static int stop_on_fsu_error[2] = {COMPLAIN_ON_FSU_ERROR | COMPLAIN_ON_ADF_ERROR, COMPLAIN_ON_FSU_ERROR | COMPLAIN_ON_ADF_ERROR}; -static int default_scan_mode[2] = {-1, -1}; +static int default_scan_mode[2] = {-1, -1}; SANE_Status -sane_init (SANE_Int * version_code, +sane_init (SANE_Int * version_code, SANE_Auth_Callback __sane_unused__ authorize) { char devnam[PATH_MAX] = "/dev/scanner"; @@ -2347,7 +2347,7 @@ sane_init (SANE_Int * version_code, int opt_index = 0; int linecount = 0; #if 1 - SHARP_Device sd; + SHARP_Device sd; SHARP_Device *dp = &sd; #else SHARP_Device *dp; @@ -2443,7 +2443,7 @@ sane_init (SANE_Int * version_code, linecount); DBG(1, "%s\n", line); } - else + else queued_reads[opt_index] = i; } else if (strcmp(word, "stop_on_fsu_error") == 0) @@ -2458,8 +2458,8 @@ sane_init (SANE_Int * version_code, linecount); DBG(1, "%s\n", line); } - else - stop_on_fsu_error[opt_index] + else + stop_on_fsu_error[opt_index] = i ? COMPLAIN_ON_FSU_ERROR : 0; } else if (strcmp(word, "default_scan_source") == 0) @@ -2493,7 +2493,7 @@ sane_init (SANE_Int * version_code, { while (new_devs) { - if (buffers[1] >= 2) + if (buffers[1] >= 2) new_devs->dev->info.buffers = buffers[1]; else new_devs->dev->info.buffers = 2; @@ -2529,7 +2529,7 @@ sane_init (SANE_Int * version_code, while (new_devs) { - if (buffers[1] >= 2) + if (buffers[1] >= 2) new_devs->dev->info.buffers = buffers[1]; else new_devs->dev->info.buffers = 2; @@ -2574,7 +2574,7 @@ sane_exit (void) free ((void *) dev->sane.model); free (dev); } - + if (devlist) free(devlist); devlist = 0; @@ -2653,8 +2653,8 @@ sane_open (SANE_String_Const devnam, SANE_Handle * handle) s->fd = -1; s->dev = dev; - - s->buffer = 0; + + s->buffer = 0; #ifdef USE_CUSTOM_GAMMA for (i = 0; i < 4; ++i) for (j = 0; j < 256; ++j) @@ -2827,7 +2827,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, *info |= SANE_INFO_RELOAD_PARAMS; case OPT_NUM_OPTS: case OPT_THRESHOLD: - /* xxx theoretically, we could use OPT_THRESHOLD in + /* xxx theoretically, we could use OPT_THRESHOLD in bi-level color mode to adjust all three other threshold together. But this would require to set the bit SANE_INFO_RELOAD_OPTIONS in *info, and that @@ -2879,8 +2879,8 @@ sane_control_option (SANE_Handle handle, SANE_Int option, #endif s->opt[OPT_HALFTONE].cap |= SANE_CAP_INACTIVE; } - - if ( strcmp (val, M_LINEART) == 0 + + if ( strcmp (val, M_LINEART) == 0 || strcmp (val, M_GRAY) == 0) { s->opt[OPT_LIGHTCOLOR].cap &= ~SANE_CAP_INACTIVE; @@ -2889,7 +2889,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, { s->opt[OPT_LIGHTCOLOR].cap |= SANE_CAP_INACTIVE; } - + strcpy(s->val[option].s, val); #ifdef USE_CUSTOM_GAMMA set_gamma_caps(s); @@ -2926,19 +2926,19 @@ sane_control_option (SANE_Handle handle, SANE_Int option, else range_index = SCAN_SIMPLE; - s->opt[OPT_TL_X].constraint.range + s->opt[OPT_TL_X].constraint.range = &s->dev->info.tl_x_ranges[range_index]; clip_value (&s->opt[OPT_TL_X], &s->val[OPT_TL_X].w); - s->opt[OPT_TL_Y].constraint.range + s->opt[OPT_TL_Y].constraint.range = &s->dev->info.tl_y_ranges[range_index]; clip_value (&s->opt[OPT_TL_Y], &s->val[OPT_TL_Y].w); - s->opt[OPT_BR_X].constraint.range + s->opt[OPT_BR_X].constraint.range = &s->dev->info.br_x_ranges[range_index]; clip_value (&s->opt[OPT_BR_X], &s->val[OPT_BR_X].w); - s->opt[OPT_BR_Y].constraint.range + s->opt[OPT_BR_Y].constraint.range = &s->dev->info.br_y_ranges[range_index]; clip_value (&s->opt[OPT_BR_Y], &s->val[OPT_BR_Y].w); @@ -2994,11 +2994,11 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (info) *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; for (i = 0; s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]; i++) { - if (strcmp (val, + if (strcmp (val, s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]) == 0){ - s->val[OPT_X_RESOLUTION].w + s->val[OPT_X_RESOLUTION].w = atoi(s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]); - s->val[OPT_Y_RESOLUTION].w + s->val[OPT_Y_RESOLUTION].w = atoi(s->opt[OPT_RESOLUTION_LIST].constraint.string_list[i]); if (info) *info |= SANE_INFO_RELOAD_PARAMS; @@ -3055,7 +3055,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) scanning starts. */ memset (&s->params, 0, sizeof (s->params)); - width = MM_TO_PIX( SANE_UNFIX(s->val[OPT_BR_X].w) + width = MM_TO_PIX( SANE_UNFIX(s->val[OPT_BR_X].w) - SANE_UNFIX(s->val[OPT_TL_X].w), s->dev->info.mud); length = MM_TO_PIX( SANE_UNFIX(s->val[OPT_BR_Y].w) @@ -3077,14 +3077,14 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) /* if async reads are used, )ie. if USE_FORK is defined, this command may only be issued immediately after the - "start scan" command. Later calls will confuse the + "start scan" command. Later calls will confuse the read queue. */ if (!s->get_params_called) { wait_ready(s->fd); status = sanei_scsi_cmd (s->fd, cmd, sizeof (cmd), buf, &len); - + if (status != SANE_STATUS_GOOD) { do_cancel(s); @@ -3142,7 +3142,7 @@ sprint_gamma(Option_Value val, SANE_Byte *dst) { int i; SANE_Byte *p = dst; - + p += sprintf((char *) p, "%i", val.wa[0] > 255 ? 255 : val.wa[0]); /* val.wa[i] is over 255, so val.wa[i] is limitied to 255 */ for (i = 1; i < 256; i++) @@ -3155,17 +3155,17 @@ send_ascii_gamma_tables (SHARP_Scanner *s) { SANE_Status status; int i; - + DBG(11, "<< send_ascii_gamma_tables "); - + /* we need: 4 bytes for each gamma value (3 digits + delimiter) + 10 bytes for the command header i.e. 4 * 4 * 256 + 10 = 4106 bytes */ - + if (s->dev->info.bufsize < 4106) return SANE_STATUS_NO_MEM; - + memset(s->buffer, 0, 4106); i = sprint_gamma(s->val[OPT_GAMMA_VECTOR_R], &s->buffer[10]); @@ -3175,19 +3175,19 @@ send_ascii_gamma_tables (SHARP_Scanner *s) i += sprint_gamma(s->val[OPT_GAMMA_VECTOR_B], &s->buffer[10+i]); s->buffer[10+i++] = '/'; i += sprint_gamma(s->val[OPT_GAMMA_VECTOR], &s->buffer[10+i]); - + DBG(11, "%s\n", &s->buffer[10]); s->buffer[0] = SEND; s->buffer[2] = 0x03; s->buffer[7] = i >> 8; s->buffer[8] = i & 0xff; - + wait_ready(s->fd); status = sanei_scsi_cmd (s->fd, s->buffer, i+10, 0, 0); DBG(11, ">>\n"); - + return status; } #endif @@ -3197,29 +3197,29 @@ send_binary_g_table(SHARP_Scanner *s, SANE_Word *a, int dtq) { SANE_Status status; int i; - + DBG(11, "<< send_binary_g_table\n"); memset(s->buffer, 0, 522); - + s->buffer[0] = SEND; s->buffer[2] = 0x03; s->buffer[5] = dtq; s->buffer[7] = 2; s->buffer[8] = 0; - + for (i = 0; i < 256; i++) { s->buffer[2*i+11] = a[i] > 255 ? 255 : a[i]; } - + for (i = 0; i < 256; i += 16) { DBG(11, "%02x %02x %02x %02x %02x %02x %02x %02x " "%02x %02x %02x %02x %02x %02x %02x %02x\n", - a[i ], a[i+1], a[i+2], a[i+3], + a[i ], a[i+1], a[i+2], a[i+3], a[i+4], a[i+5], a[i+6], a[i+7], - a[i+8], a[i+9], a[i+10], a[i+11], + a[i+8], a[i+9], a[i+10], a[i+11], a[i+12], a[i+13], a[i+14], a[i+15]); } @@ -3236,19 +3236,19 @@ static SANE_Status send_binary_gamma_tables (SHARP_Scanner *s) { SANE_Status status; - + status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR].wa, 0x10); if (status != SANE_STATUS_GOOD) return status; - + status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_R].wa, 0x11); if (status != SANE_STATUS_GOOD) return status; - + status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_G].wa, 0x12); if (status != SANE_STATUS_GOOD) return status; - + status = send_binary_g_table(s, s->val[OPT_GAMMA_VECTOR_B].wa, 0x13); return status; @@ -3265,7 +3265,7 @@ send_gamma_tables (SHARP_Scanner *s) { return send_binary_gamma_tables(s); } - + } #endif @@ -3276,19 +3276,19 @@ send_threshold_data(SHARP_Scanner *s) SANE_Status status; SANE_Byte cmd[26] = {SEND, 0, 0x82, 0, 0, 0, 0, 0, 0, 0}; int len; - + memset(cmd, 0, sizeof(cmd)); - /* maximum string length: 3 bytes for each number (they are + /* maximum string length: 3 bytes for each number (they are restricted to the range 0..255), 3 '/' and the null-byte, total: 16 bytes. */ - len = sprintf((char *) &cmd[10], "%i/%i/%i/%i", + len = sprintf((char *) &cmd[10], "%i/%i/%i/%i", s->val[OPT_THRESHOLD_R].w, s->val[OPT_THRESHOLD_G].w, s->val[OPT_THRESHOLD_B].w, s->val[OPT_THRESHOLD].w); cmd[8] = len; - + wait_ready(s->fd); status = sanei_scsi_cmd(s->fd, cmd, len + 10, 0, 0); return status; @@ -3315,7 +3315,7 @@ sane_start (SANE_Handle handle) if (status != SANE_STATUS_GOOD) return status; - s->dev->sensedat.complain_on_errors + s->dev->sensedat.complain_on_errors = COMPLAIN_ON_ADF_ERROR | s->dev->info.complain_on_errors; #ifdef HAVE_SANEI_SCSI_OPEN_EXTENDED @@ -3324,11 +3324,11 @@ sane_start (SANE_Handle handle) s->dev->info.bufsize = 32 * 1024; { int bsize = s->dev->info.bufsize; - status = sanei_scsi_open_extended (s->dev->sane.name, &s->fd, + status = sanei_scsi_open_extended (s->dev->sane.name, &s->fd, &sense_handler, &s->dev->sensedat, &bsize); s->dev->info.bufsize = bsize; } - + if (status != SANE_STATUS_GOOD) { DBG (1, "open of %s failed: %s\n", @@ -3337,10 +3337,10 @@ sane_start (SANE_Handle handle) } /* make sure that we got at least 32 kB. Even then, the scan will be - awfully slow. - + awfully slow. + NOTE: If you need to decrease this value, remember that s->buffer - is used in send_ascii_gamma_tables (JX330/JX610) and in + is used in send_ascii_gamma_tables (JX330/JX610) and in send_binary_g_table (JX250/JX350). send_ascii_gamma_tables needs 4106 bytes, and send_binary_g_table needs 522 bytes. */ @@ -3351,13 +3351,13 @@ sane_start (SANE_Handle handle) return SANE_STATUS_NO_MEM; } #else - status = sanei_scsi_open(s->dev->sane.name, &s->fd, &sense_handler, + status = sanei_scsi_open(s->dev->sane.name, &s->fd, &sense_handler, &s->dev->sensedat); if (s->dev->info.wanted_bufsize < sanei_scsi_max_request_size) s->dev->info.bufsize = s->dev->info.wanted_bufsize; else s->dev->info.bufsize = sanei_scsi_max_request_size; - + if (status != SANE_STATUS_GOOD) { DBG (1, "open of %s failed: %s\n", @@ -3415,7 +3415,7 @@ sane_start (SANE_Handle handle) DBG (5, "start: TEST_UNIT_READY\n"); status = test_unit_ready (s->fd); - + if (status != SANE_STATUS_GOOD) { DBG (1, "TEST UNIT READY failed: %s\n", sane_strstatus (status)); @@ -3462,7 +3462,7 @@ sane_start (SANE_Handle handle) s->uly = MM_TO_PIX(SANE_UNFIX(s->val[OPT_TL_Y].w), s->dev->info.mud); s->threshold = s->val[OPT_THRESHOLD].w; s->bpp = s->params.depth; - + s->adf_fsu_mode = SCAN_SIMPLE; /* default: scan without ADF and FSU */ #ifdef ALLOW_AUTO_SELECT_ADF if (strcmp (adf_fsu, use_auto) == 0) @@ -3565,7 +3565,7 @@ sane_start (SANE_Handle handle) DBG (11, "EDGE EMPHASIS BLUR\n"); s->edge = 3; } - + s->lightcolor = 3; if (strcmp(lightcolor, LIGHT_GREEN) == 0) s->lightcolor = 0; @@ -3592,7 +3592,7 @@ sane_start (SANE_Handle handle) memset (&m_subdev, 0, sizeof (m_subdev)); buf_size = sizeof (m_subdev); status = mode_sense (s->fd, &m_subdev, &buf_size, 0x20); - DBG(11, "mode sense result a_mode: %x f_mode: %x\n", + DBG(11, "mode sense result a_mode: %x f_mode: %x\n", m_subdev.a_mode_type, m_subdev.f_mode_type); if (status != SANE_STATUS_GOOD) { @@ -3601,7 +3601,7 @@ sane_start (SANE_Handle handle) s->fd = -1; return (status); } - if (s->adf_fsu_mode == SCAN_WITH_ADF) + if (s->adf_fsu_mode == SCAN_WITH_ADF) s->adf_scan = 1; #ifdef ALLOW_AUTO_SELECT_ADF else if (s->adf_fsu_mode == SCAN_ADF_FSU_AUTO) @@ -3612,7 +3612,7 @@ sane_start (SANE_Handle handle) #endif } - + #ifdef USE_CUSTOM_GAMMA if (s->val[OPT_CUSTOM_GAMMA].w == SANE_FALSE) { @@ -3639,7 +3639,7 @@ sane_start (SANE_Handle handle) } else { - /* the JX250 does not support the "fixed gamma selection", + /* the JX250 does not support the "fixed gamma selection", therefore, lets calculate & send gamma values */ int i; @@ -3684,7 +3684,7 @@ sane_start (SANE_Handle handle) s->fd = -1; return (status); } - + #ifdef USE_COLOR_THRESHOLD status = send_threshold_data(s); if (status != SANE_STATUS_GOOD) @@ -3696,9 +3696,9 @@ sane_start (SANE_Handle handle) } #endif } - + memset (&wp, 0, sizeof (wp)); - /* every Sharp scanner seems to have a different + /* every Sharp scanner seems to have a different window descriptor block... */ if ( s->dev->sensedat.model == JX610 @@ -3714,7 +3714,7 @@ sane_start (SANE_Handle handle) { buf_size = sizeof (WDB) + sizeof(WDBX330) + sizeof(WDBX250); } - + wp.wpdh.wdl[0] = buf_size >> 8; wp.wpdh.wdl[1] = buf_size; wp.wdb.x_res[0] = s->xres >> 8; @@ -3780,7 +3780,7 @@ sane_start (SANE_Handle handle) DBG (5, "bpp=%d\n", wp.wdb.bpp); DBG (5, "rif_padding=%d\n", wp.wdb.rif_padding); DBG (5, "eletu=%d\n", wp.wdb.eletu); - + #if 0 { unsigned char *p = (unsigned char*) &wp.wdb; @@ -3890,7 +3890,7 @@ sane_start (SANE_Handle handle) #ifdef USE_FORK { size_t i; - for (i = 0; i < s->dev->info.buffers; i++) + for (i = 0; i < s->dev->info.buffers; i++) s->rdr_ctl->buf_ctl[i].shm_status = SHM_EMPTY; s->read_buff = 0; s->rdr_ctl->cancel = 0; @@ -3906,7 +3906,7 @@ sane_start (SANE_Handle handle) s->reader_pid); } #endif - if (s->reader_pid == 0) + if (s->reader_pid == 0) { sigset_t ignore_set; struct SIGACTION act; @@ -3927,9 +3927,9 @@ sane_start (SANE_Handle handle) do_cancel(s); return SANE_STATUS_NO_MEM; } - + #endif /* USE_FORK */ - + DBG (1, "%d pixels per line, %d bytes, %d lines high, total %lu bytes, " "dpi=%d\n", s->params.pixels_per_line, s->params.bytes_per_line, @@ -3939,7 +3939,7 @@ sane_start (SANE_Handle handle) s->buf_used = 0; s->buf_pos = 0; - if (s->cancel == SANE_TRUE) + if (s->cancel == SANE_TRUE) { do_cancel(s); DBG (10, ">>\n"); @@ -4008,14 +4008,14 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, DBG (10, "<< sane_read_shuffled "); *len = 0; - if (s->bytes_to_read == 0 && s->buf_pos == s->buf_used) + if (s->bytes_to_read == 0 && s->buf_pos == s->buf_used) { do_cancel (s); DBG (10, ">>\n"); return (SANE_STATUS_EOF); } - - if (!s->scanning) + + if (!s->scanning) { DBG (10, ">>\n"); return(do_cancel(s)); @@ -4026,14 +4026,14 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, transfer = s->buf_used - s->buf_pos; if (transfer > max_len) transfer = max_len; - + memcpy(dst_buf, &(s->buffer[s->buf_pos]), transfer); s->buf_pos += transfer; max_len -= transfer; *len = transfer; } - while (max_len > 0 && s->bytes_to_read > 0) + while (max_len > 0 && s->bytes_to_read > 0) { if (eight_bit_data) { @@ -4060,7 +4060,7 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, start_input = s->dev->info.bufsize - nread; } ntest = nread; - + #ifdef USE_FORK status = read_data (s, &(s->buffer[start_input]), &nread); #else @@ -4073,8 +4073,8 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, DBG (10, ">>\n"); return (SANE_STATUS_IO_ERROR); } - - if (nread != ntest) + + if (nread != ntest) { /* if this happens, something is wrong in the input buffer management... @@ -4082,8 +4082,8 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, DBG(1, "Warning: could not read an integral number of scan lines\n"); DBG(1, " image will be scrambled\n"); } - - + + s->buf_used = max_line * s->params.bytes_per_line; s->buf_pos = 0; s->bytes_to_read -= nread; @@ -4125,12 +4125,12 @@ sane_read_shuffled (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, } } } - + transfer = max_len; if (transfer > s->buf_used) transfer = s->buf_used; memcpy(&(dst_buf[*len]), s->buffer, transfer); - + max_len -= transfer; s->buf_pos += transfer; *len += transfer; @@ -4150,13 +4150,13 @@ sane_read (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, SANE_Status status; s->busy = SANE_TRUE; - if (s->cancel == SANE_TRUE) + if (s->cancel == SANE_TRUE) { do_cancel(s); *len = 0; return (SANE_STATUS_CANCELLED); } - + /* RGB scans with a JX 250 and bi-level color scans must be handled differently: */ if (s->image_composition <= 2) @@ -4167,7 +4167,7 @@ sane_read (SANE_Handle handle, SANE_Byte *dst_buf, SANE_Int max_len, status = sane_read_direct(handle, dst_buf, max_len, len); else status = sane_read_shuffled(handle, dst_buf, max_len, len, 1); - + s->busy = SANE_FALSE; if (s->cancel == SANE_TRUE) { @@ -4192,7 +4192,7 @@ sane_cancel (SANE_Handle handle) } SANE_Status -sane_set_io_mode (SANE_Handle __sane_unused__ handle, +sane_set_io_mode (SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ non_blocking) { DBG (10, "<< sane_set_io_mode"); @@ -4202,7 +4202,7 @@ sane_set_io_mode (SANE_Handle __sane_unused__ handle, } SANE_Status -sane_get_select_fd (SANE_Handle __sane_unused__ handle, +sane_get_select_fd (SANE_Handle __sane_unused__ handle, SANE_Int __sane_unused__ * fd) { DBG (10, "<< sane_get_select_fd"); diff --git a/backend/sharp.conf.in b/backend/sharp.conf.in index 0541240..eef72c4 100644 --- a/backend/sharp.conf.in +++ b/backend/sharp.conf.in @@ -9,7 +9,7 @@ # option readqueue: number of queued read requests. This is # with the current SANE version (1.01) only useful for # Linux, since queued read requests are not supported -# for other operating systems. +# for other operating systems. # # For Linux, a value of 2 is recommended, at least if a # JX-250 is used. Bigger values are only a waste of memory. @@ -22,8 +22,8 @@ # # option default_scan_source: valid values are "auto", "fsu", "adf" # and "flatbed". For "auto", the backend will enable an ADF or -# or FSU, if installed. -# +# or FSU, if installed. +# # global options: option buffers 4 option buffersize 131072 diff --git a/backend/sharp.h b/backend/sharp.h index 6797224..c5dad27 100644 --- a/backend/sharp.h +++ b/backend/sharp.h @@ -47,21 +47,21 @@ /* default values for configurable options. Though these options are only meaningful if USE_FORK is defined, - they are + they are DEFAULT_BUFFERS: number of buffers allocated as shared memory for the data transfer from reader_process to read_data. The minimum value is 2 DEFAULT_BUFSIZE: default size of one buffer. Must be greater than zero. - DEFAULT_QUEUED_READS: number of read requests queued by + DEFAULT_QUEUED_READS: number of read requests queued by sanei_scsi_req_enter. Since queued read requests - are currently only supported for Linux and + are currently only supported for Linux and DomainOS, this value should automatically be set dependent on the target OS... For Linux, 2 is the optimum; for DomainOS, I don't have any recommendation; other OS should use the value zero. - + The value for DEFAULT_BUFSIZE is probably too Linux-oriented... */ @@ -110,7 +110,7 @@ typedef enum OPT_LIGHTCOLOR, OPT_PREVIEW, -#ifdef USE_CUSTOM_GAMMA +#ifdef USE_CUSTOM_GAMMA OPT_GAMMA_VECTOR, OPT_GAMMA_VECTOR_R, OPT_GAMMA_VECTOR_G, @@ -123,7 +123,7 @@ SHARP_Option; #ifdef USE_FORK -/* status defines for a buffer: +/* status defines for a buffer: buffer not used / read request queued / buffer contains data */ #define SHM_EMPTY 0 @@ -150,7 +150,7 @@ typedef struct SHARP_rdr_ctl SHARP_rdr_ctl; #endif /* USE_FORK */ -typedef enum +typedef enum { /* JX250, JX330, JX350, JX610 are used as array indices, so the corresponding numbers should start at 0 @@ -187,8 +187,8 @@ typedef struct SHARP_Info int wanted_bufsize; size_t queued_reads; int complain_on_errors; - /* default scan mode: - -1 -> "automatic": Use the ADF, if installed, + /* default scan mode: + -1 -> "automatic": Use the ADF, if installed, else use the FSU, if installed. or: SCAN_ADF, SCAN_FSU, SCAN_SIMPLE */ @@ -201,14 +201,14 @@ SHARP_Info; typedef struct SHARP_Sense_Data { SHARP_Model model; - /* flag, if conditions like "paper jam" or "cover open" + /* flag, if conditions like "paper jam" or "cover open" are considered as an error. Should be 0 for attach, else a frontend might refuse to start, if the scanner returns these errors. */ int complain_on_errors; /* Linux returns only 16 bytes of sense data... */ - u_char sb[16]; + u_char sb[16]; } SHARP_Sense_Data; @@ -222,7 +222,7 @@ typedef struct SHARP_Device } SHARP_Device; -typedef struct SHARP_New_Device +typedef struct SHARP_New_Device { struct SHARP_Device *dev; struct SHARP_New_Device *next; @@ -292,7 +292,7 @@ typedef struct WPDH { u_char wpdh[6]; u_char wdl[2]; -} +} WPDH; typedef struct WDB @@ -325,7 +325,7 @@ typedef struct WDB SANE_Byte lightness_g[2]; SANE_Byte lightness_b[2]; SANE_Byte lightness_bw[2]; - + } WDB; diff --git a/backend/sm3600-color.c b/backend/sm3600-color.c index 9b3c540..2e42ada 100644 --- a/backend/sm3600-color.c +++ b/backend/sm3600-color.c @@ -171,7 +171,7 @@ TState StartScanColor(TInstance *this) this->state.cyTotalPath = this->param.y/2-(2*this->state.ySensorSkew)*600/this->param.res; DoJog(this,this->state.cyTotalPath); INST_ASSERT(); - this->state.cyTotalPath += + this->state.cyTotalPath += (this->state.cyPixel+2*this->state.ySensorSkew) *600/this->param.res; /* for jogging back */ @@ -214,7 +214,7 @@ TState StartScanColor(TInstance *this) RegWrite(this,R_SLEN, 2, this->state.cyWindow+ (2*this->state.ySensorSkew)*600/this->param.res); - this->state.szOrder=ORDER_BRG; + this->state.szOrder=ORDER_BRG; RegWrite(this,R_CCAL, 3, this->calibration.rgbBias); INST_ASSERT(); /* 0xBBGGRR */ switch (this->param.res) { @@ -294,7 +294,7 @@ TState StartScanColor(TInstance *this) } /* calculate and prepare intermediate line transfer buffer */ - + this->state.cchLineOut=3*this->state.cxPixel; this->state.pchLineOut = malloc(this->state.cchLineOut); if (!this->state.pchLineOut) @@ -310,4 +310,3 @@ TState StartScanColor(TInstance *this) this->state.bScanning = true; return SANE_STATUS_GOOD; } - diff --git a/backend/sm3600-gray.c b/backend/sm3600-gray.c index d9fda86..c5efe55 100644 --- a/backend/sm3600-gray.c +++ b/backend/sm3600-gray.c @@ -204,7 +204,7 @@ static TState ReadNextGrayLine(PTInstance this) { int iWrite; int iDot; - unsigned char chBits; + unsigned char chBits; int iRead; /* read position in raw line */ int nInterpolator; @@ -328,7 +328,7 @@ TState StartScanGray(TInstance *this) DoJog(this,this->state.cyTotalPath); INST_ASSERT(); this->state.cyTotalPath += this->param.cy/2; /* for jogging back */ - + /* regular scan is asynchronously, that is, the scanning is issued, and the driver does bulk reads, @@ -370,7 +370,7 @@ TState StartScanGray(TInstance *this) this->state.cchLineOut=(this->mode==gray) ? this->state.cxPixel : (this->state.cxPixel+7)/8; - + this->state.pchLineOut = malloc(this->state.cchLineOut); if (!this->state.pchLineOut) return FreeState(this,SetError(this, @@ -386,4 +386,3 @@ TState StartScanGray(TInstance *this) this->state.bScanning = true; return SANE_STATUS_GOOD; } - diff --git a/backend/sm3600-homerun.c b/backend/sm3600-homerun.c index fe647ef..b77a76e 100644 --- a/backend/sm3600-homerun.c +++ b/backend/sm3600-homerun.c @@ -67,7 +67,7 @@ typedef enum { ltHome, ltUnknown, ltBed, ltError } TLineType; static unsigned char auchRegsSingleLine[]={ 0x00 /*0x01*/, 0x00 /*0x02*/, 0x3F /*0x03*/, - 0xB4 /*!!0x04!!*/, 0x14 /*!!0x05!!*/, 0,0, + 0xB4 /*!!0x04!!*/, 0x14 /*!!0x05!!*/, 0,0, 0x00 /*0x08*/, 0x3F /*!!0x09!!*/, 1,0, 0x6D /*0x0C*/, @@ -119,7 +119,7 @@ static TLineType GetLineType(TInstance *this) RegWrite(this,R_CTL, 1, 0x59); /* #2496[062.5] */ RegWrite(this,R_CTL, 1, 0xD9); /* #2497[062.5] */ i=WaitWhileScanning(this,5); if (i) return i; - + cchBulk=MAX_PIXEL_PER_SCANLINE; /* cchBulk=RegRead(this,R_STAT, 2); @@ -298,7 +298,7 @@ TState DoCalibration(TInstance *this) case sm3750: default: yStart=100; /* 54 is perimeter */ - cStripes=MAX_CALIB_STRIPES; + cStripes=MAX_CALIB_STRIPES; cyGap=10; break; } /* switch */ @@ -359,7 +359,7 @@ TState DoCalibration(TInstance *this) this->calibration.achStripeY[i]=(unsigned char) ((2*(int)auchHanning[i]+auchHanning[i-1]+auchHanning[i+1])/4); #endif - + DoJog(this,-yStart-cStripes*cyGap); INST_ASSERT(); this->calibration.bCalibrated=true; @@ -496,4 +496,3 @@ TState DoJog(TInstance *this, int nDistance) usleep(100); return WaitWhileBusy(this,1000); /* thanks Mattias Ellert */ } - diff --git a/backend/sm3600-scanusb.c b/backend/sm3600-scanusb.c index 3ca9a8a..7ae90d3 100644 --- a/backend/sm3600-scanusb.c +++ b/backend/sm3600-scanusb.c @@ -61,7 +61,7 @@ TransferControlMsg() static int TransferControlMsg(TInstance *this, int nReqType, - int nRequest, + int nRequest, int nValue, int nIndex, void *pBuffer, @@ -302,7 +302,7 @@ int BulkRead(TInstance *this, FILE *fhOut, unsigned int cchBulk) { int cchChunk; int cchReal; - + cchChunk=cchBulk; if (cchChunk>0x1000) cchChunk=0x1000; @@ -366,7 +366,7 @@ int BulkReadBuffer(TInstance *this, { int cchChunk; int cchReal; - + cchChunk=cchBulk; if (cchChunk>0x1000) cchChunk=0x1000; @@ -391,7 +391,7 @@ int BulkReadBuffer(TInstance *this, ); } dprintf(DEBUG_COMM,"writing %d bytes\n",cchRead); - + if (!rc && puchBufferOut) memcpy(puchBufferOut,pchBuffer,cchRead); free(pchBuffer); @@ -440,4 +440,3 @@ unsigned int RegRead(TInstance *this, int iRegister, int cch) SetError(this,SANE_STATUS_IO_ERROR,"error during register read"); return 0; } - diff --git a/backend/sm3600-scanutil.c b/backend/sm3600-scanutil.c index 62ba0f1..022984e 100644 --- a/backend/sm3600-scanutil.c +++ b/backend/sm3600-scanutil.c @@ -97,7 +97,7 @@ int SetError(TInstance *this, int nError, const char *szFormat, ...) if (this->nErrorState) return 0; /* do not overwrite error state */ this->nErrorState=nError; this->szErrorReason=malloc(500); - + if (szFormat!=NULL && this->szErrorReason) { va_start(ap,szFormat); @@ -200,7 +200,7 @@ TState CancelScan(TInstance *this) usleep(200); DoReset(this); EndScan(this); /* and step back! */ - + DBG(DEBUG_JUNK,"cs4: %d\n",(int)this->nErrorState); bCanceled=this->state.bCanceled; this->state.bCanceled=false; /* re-enable Origination! */ diff --git a/backend/sm3600.c b/backend/sm3600.c index 908e8be..6e411c3 100644 --- a/backend/sm3600.c +++ b/backend/sm3600.c @@ -180,7 +180,7 @@ InitOptions(TInstance *this) Some hints: *every* field needs a constraint, elseway there will be a warning. */ - + switch (iOpt) { case optCount: @@ -353,8 +353,8 @@ RegisterSaneDev (TModel model, SANE_String_Const szName) return SANE_STATUS_GOOD; } - -static SANE_Status + +static SANE_Status sm_usb_attach (SANE_String_Const dev_name) { int fd; @@ -398,9 +398,9 @@ sane_init (SANE_Int *version_code, SANE_Auth_Callback authCB) } pdevFirst=NULL; - + sanei_usb_init(); - for (i = 0; aScanners[i].idProduct; i++) + for (i = 0; aScanners[i].idProduct; i++) { sanei_usb_find_devices(SCANNER_VENDOR, aScanners[i].idProduct, sm_usb_attach); } @@ -417,7 +417,7 @@ sane_exit (void) /* free all bound resources and instances */ while (pinstFirst) sane_close((SANE_Handle)pinstFirst); /* free all resources */ - + /* free all device descriptors */ for (dev = pdevFirst; dev; dev = pNext) { @@ -511,7 +511,7 @@ sane_close (SANE_Handle handle) if (p==this) break; pParent=p; } - + if (!p) { DBG(1,"invalid handle in close()\n"); @@ -545,7 +545,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int iOpt) SANE_Status sane_control_option (SANE_Handle handle, SANE_Int iOpt, - SANE_Action action, void *pVal, + SANE_Action action, void *pVal, SANE_Int *pnInfo) { SANE_Word cap; @@ -562,7 +562,7 @@ sane_control_option (SANE_Handle handle, SANE_Int iOpt, return SANE_STATUS_INVAL; cap=this->aoptDesc[iOpt].cap; - + switch (action) { @@ -699,7 +699,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters *p) p->depth=1; p->bytes_per_line=(p->pixels_per_line+7)/8; break; - } + } DBG(DEBUG_INFO,"getting parameters (%d,%d)...\n",p->bytes_per_line,p->lines); return SANE_STATUS_GOOD; } diff --git a/backend/snapscan-data.c b/backend/snapscan-data.c index 1fd1a53..6a20499 100644 --- a/backend/snapscan-data.c +++ b/backend/snapscan-data.c @@ -41,14 +41,14 @@ If you do not wish that, delete this exception notice. This file contains static calibration data for the Benq 5150C scanner. - Once it is known how calibration for this scanner works this file + Once it is known how calibration for this scanner works this file becomes obsolete. */ /* $Id$ SANE SnapScan backend */ - + static const SANE_Byte calibration_data_5150[] = { 0x78,0x01,0xcc,0x47,0xca,0x53,0xcd,0x4a,0xd0,0x57,0xd5,0x46,0xda,0x56,0xdd,0x49, diff --git a/backend/snapscan-mutex.c b/backend/snapscan-mutex.c index ad0538a..72b8fe1 100644 --- a/backend/snapscan-mutex.c +++ b/backend/snapscan-mutex.c @@ -1,8 +1,8 @@ /* Mutex implementation for SnapScan backend - + Copyright (C) 2000, 2004 Henrik Johansson, Oliver Schwartz - + 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 @@ -38,7 +38,7 @@ 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.*/ - + #if defined __BEOS__ #include @@ -122,14 +122,14 @@ static unsigned int snapscani_bernstein(const unsigned char* str) { unsigned int hash = 5381; /* some arbitrary number */ int c; - + while (*str) { - c = *str++; + c = *str++; hash = ((hash << 5) + hash) + c; } return hash; -} +} static int snapscani_mutex_open(snapscan_mutex_t* sem_id, const char* dev) { diff --git a/backend/snapscan-options.c b/backend/snapscan-options.c index 52fee81..3ef85ae 100644 --- a/backend/snapscan-options.c +++ b/backend/snapscan-options.c @@ -232,23 +232,23 @@ static const SANE_Range focus_range = static const SANE_Range brightness_range = { - -400 << SANE_FIXED_SCALE_SHIFT, - 400 << SANE_FIXED_SCALE_SHIFT, - 1 << SANE_FIXED_SCALE_SHIFT + SANE_FIX(-400), + SANE_FIX(400), + SANE_FIX(1) }; static const SANE_Range contrast_range = { - -100 << SANE_FIXED_SCALE_SHIFT, - 400 << SANE_FIXED_SCALE_SHIFT, - 1 << SANE_FIXED_SCALE_SHIFT + SANE_FIX(-100), + SANE_FIX(400), + SANE_FIX(1) }; static const SANE_Range positive_percent_range = { - 0 << SANE_FIXED_SCALE_SHIFT, - 100 << SANE_FIXED_SCALE_SHIFT, - 1 << SANE_FIXED_SCALE_SHIFT + SANE_FIX(0), + SANE_FIX(100), + SANE_FIX(1) }; static void control_options(SnapScan_Scanner *pss); diff --git a/backend/snapscan-scsi.c b/backend/snapscan-scsi.c index 861ff32..b6e43a1 100644 --- a/backend/snapscan-scsi.c +++ b/backend/snapscan-scsi.c @@ -80,9 +80,9 @@ static SnapScan_Model snapscani_get_model_id(char* model_str, int fd, SnapScan_B if ((bus_type == USB) && (sanei_usb_get_vendor_product(fd, &vendor_id, &product_id) == SANE_STATUS_GOOD)) { - DBG(DL_MINOR_INFO, + DBG(DL_MINOR_INFO, "%s: looking up scanner for ID 0x%04x,0x%04x.\n", - me, vendor_id, product_id); + me, vendor_id, product_id); for (i = 0; i < known_usb_scanners; i++) { if ((usb_scanners[i].vendor_id == vendor_id) && @@ -1320,7 +1320,7 @@ static SANE_Status wait_scanner_ready (SnapScan_Scanner *pss) else { /* This seems to happen for Epson scanners. Return - SANE_STATUS_GOOD and hope the scanner accepts the + SANE_STATUS_GOOD and hope the scanner accepts the next command... */ DBG (DL_CALL_TRACE, "%s: No timeout specified, returning immediately\n", me); return SANE_STATUS_GOOD; diff --git a/backend/snapscan-sources.c b/backend/snapscan-sources.c index dc78394..e8bbb90 100644 --- a/backend/snapscan-sources.c +++ b/backend/snapscan-sources.c @@ -238,7 +238,7 @@ typedef struct static SANE_Int FDSource_remaining (Source *pself) { - FDSource *ps = (FDSource *) pself; + FDSource *ps = (FDSource *) pself; return ps->bytes_remaining; } @@ -660,19 +660,19 @@ static SANE_Status create_Expander (SnapScan_Scanner *pss, return status; } -/* +/* This filter implements a fix for scanners that have some columns of pixels offset. Currently it only shifts every other column starting with the first one down ch_offset pixels. - + The Deinterlacer detects if data is in SANE RGB frame format (3 bytes/pixel) or in Grayscale (1 byte/pixel). - + The first ch_offset lines of data in the output are fudged so that even indexed add odd indexed pixels will have the same value. This is necessary because - the real pixel values of the columns that are shifted down are not + the real pixel values of the columns that are shifted down are not in the data for the first ch_offset lines. A better way to handle this would be to - scan in ch_offset extra lines of data, but I haven't figured out how to do this + scan in ch_offset extra lines of data, but I haven't figured out how to do this yet. */ @@ -707,7 +707,7 @@ static SANE_Status Deinterlacer_get (Source *pself, SANE_Byte *pbuf, SANE_Int *p SANE_Int remaining = *plen; SANE_Int org_len = *plen; char *me = "Deinterlacer_get"; - + DBG(DL_DATA_TRACE, "%s: remaining=%d, pself->remaining=%d, ch_ndata=%d, ch_pos=%d\n", me, remaining, pself->remaining(pself), ps->ch_ndata, ps->ch_pos); @@ -784,8 +784,8 @@ static SANE_Status Deinterlacer_get (Source *pself, SANE_Byte *pbuf, SANE_Int *p *pbuf = ps->ch_buf[(ps->ch_pos + (ps->ch_line_size)) % ps->ch_size]; }else{ /* Use data from the next pixel for even indexed pixels - if we are on the first few lines. - TODO: also we will overread the buffer if the buffer read ended + if we are on the first few lines. + TODO: also we will overread the buffer if the buffer read ended on the first pixel. */ if (ps->ch_pos % (ps->ch_line_size) == 0 ) *pbuf = ps->ch_buf[ps->ch_pos+ps->ch_bytes_per_pixel]; @@ -807,7 +807,7 @@ static SANE_Status Deinterlacer_get (Source *pself, SANE_Byte *pbuf, SANE_Int *p } *plen -= remaining; - + DBG(DL_DATA_TRACE, "%s: Request=%d, remaining=%d, read=%d, TXSource_rem=%d, bytes_rem=%lu\n", me, @@ -815,7 +815,7 @@ static SANE_Status Deinterlacer_get (Source *pself, SANE_Byte *pbuf, SANE_Int *p pself->remaining(pself), *plen, TxSource_remaining(pself), - (u_long) ps->pss->bytes_remaining); + (u_long) ps->pss->bytes_remaining); return status; } @@ -859,7 +859,7 @@ static SANE_Status Deinterlacer_init (Deinterlacer *pself, break; } pself->ch_line_size = TxSource_bytesPerLine((Source *) pself); - /* We need at least ch_offset+1 lines of buffer in order + /* We need at least ch_offset+1 lines of buffer in order to shift up ch_offset pixels. */ pself->ch_size = pself->ch_line_size * (pself->ch_offset + 1); pself->ch_buf = (SANE_Byte *) malloc(pself->ch_size); @@ -1216,10 +1216,10 @@ static SANE_Status create_source_chain (SnapScan_Scanner *pss, { case MD_COLOUR: status = create_RGBRouter (pss, *pps, pps); - /* We only have the interlace probelms on - some scanners like the Epson Perfection 2480/2580 + /* We only have the interlace probelms on + some scanners like the Epson Perfection 2480/2580 at 2400 dpi. */ - if (status == SANE_STATUS_GOOD && + if (status == SANE_STATUS_GOOD && ((pss->pdev->model == PERFECTION2480 && pss->res == 2400) || (pss->pdev->model == PERFECTION3490 && pss->res == 3200) || (pss->pdev->model == PRISA5000E && pss->res == 1200))) @@ -1229,7 +1229,7 @@ static SANE_Status create_source_chain (SnapScan_Scanner *pss, status = create_Expander (pss, *pps, pps); if (status == SANE_STATUS_GOOD) status = create_RGBRouter (pss, *pps, pps); - if (status == SANE_STATUS_GOOD && + if (status == SANE_STATUS_GOOD && ((pss->pdev->model == PERFECTION2480 && pss->res == 2400) || (pss->pdev->model == PERFECTION3490 && pss->res == 3200) || (pss->pdev->model == PRISA5000E && pss->res == 1200))) diff --git a/backend/snapscan-sources.h b/backend/snapscan-sources.h index a5ed3df..595b48b 100644 --- a/backend/snapscan-sources.h +++ b/backend/snapscan-sources.h @@ -1,48 +1,48 @@ /* sane - Scanner Access Now Easy. - + Copyright (C) 1997, 1998 Franck Schnefra, Michel Roelofs, Emmanuel Blot, Mikko Tyolajarvi, David Mosberger-Tang, Wolfgang Goeller, Petter Reinholdtsen, Gary Plewa, Sebastien Sable, Oliver Schwartz and Kevin Charter - + 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. - + This file is a component of the implementation of a backend for many of the AGFA SnapScan and Acer Vuego/Prisa flatbed scanners. */ diff --git a/backend/snapscan-usb.c b/backend/snapscan-usb.c index ec6a53e..116f9db 100644 --- a/backend/snapscan-usb.c +++ b/backend/snapscan-usb.c @@ -1,8 +1,8 @@ /* Snapscan 1212U modifications for the Snapscan SANE backend - + Copyright (C) 2000 Henrik Johansson - + Henrik Johansson (henrikjo@post.urfors.se) This program is free software; you can redistribute it and/or @@ -43,7 +43,7 @@ This file implements USB equivalents to the SCSI routines used by the Snapscan backend. - + History 0.1 2000-02-01 @@ -174,7 +174,7 @@ static SANE_Status snapscani_usb_open(const char *dev, int *fdp, usb_sense_handler=sense_handler; usb_pss = pss; urb_counters->read_urbs = 0; - urb_counters->write_urbs = 0; + urb_counters->write_urbs = 0; return sanei_usb_open(dev, fdp); } @@ -182,13 +182,13 @@ static SANE_Status snapscani_usb_open(const char *dev, int *fdp, static void snapscani_usb_close(int fd) { static const char me[] = "snapscani_usb_close"; SANE_Word vendor_id, product_id; - + DBG (DL_CALL_TRACE, "%s(%d)\n", me, fd); DBG (DL_DATA_TRACE,"1st read %ld write %ld\n", urb_counters->read_urbs, urb_counters->write_urbs); - + /* Check if URB counting is needed. If yes, ensure the number of sent and received URBs is even. - Odd number of URBs only cause problems with libusb and certain + Odd number of URBs only cause problems with libusb and certain scanner models. On other scanner models, sending additional commands seems to cause problems (e.g. 1212u_2). If sanei_usb_get_vendor_product returns an error there's probably no @@ -197,12 +197,12 @@ static void snapscani_usb_close(int fd) { if (sanei_usb_get_vendor_product(fd, &vendor_id, &product_id) == SANE_STATUS_GOOD) { /* Exclude 1212u_2 */ - if (!((vendor_id == USB_VENDOR_AGFA) && (product_id == USB_PRODUCT_1212U2))) + if (!((vendor_id == USB_VENDOR_AGFA) && (product_id == USB_PRODUCT_1212U2))) { if ((urb_counters->read_urbs & 0x01) && (urb_counters->write_urbs & 0x01)) { char cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; - + snapscani_usb_cmd (fd, cmd, sizeof (cmd), NULL, 0); } else if (urb_counters->read_urbs & 0x01) @@ -211,7 +211,7 @@ static void snapscani_usb_close(int fd) { char cmd[] = {TEST_UNIT_READY, 0, 0, 0, 0, 0}; char cmd2[] = {INQUIRY, 0, 0, 0, 120, 0}; char data[120]; - + read_bytes = 120; snapscani_usb_cmd (fd, cmd2, sizeof (cmd2), data, &read_bytes); snapscani_usb_cmd (fd, cmd, sizeof (cmd), NULL, 0); @@ -221,11 +221,11 @@ static void snapscani_usb_close(int fd) { size_t read_bytes; char cmd[] = {INQUIRY, 0, 0, 0, 120, 0}; char data[120]; - + read_bytes = 120; snapscani_usb_cmd (fd, cmd, sizeof (cmd), data, &read_bytes); } - DBG (DL_DATA_TRACE,"2nd read %ld write %ld\n", urb_counters->read_urbs, + DBG (DL_DATA_TRACE,"2nd read %ld write %ld\n", urb_counters->read_urbs, urb_counters->write_urbs); } } @@ -302,7 +302,7 @@ static SANE_Status usb_read(SANE_Int fd, void *buf, size_t n) { DBG (DL_MAJOR_ERROR, "%s Only %lu bytes read\n",me, (u_long) bytes_read); status = SANE_STATUS_IO_ERROR; } - urb_counters->read_urbs += ((63 + bytes_read) / 64); + urb_counters->read_urbs += ((63 + bytes_read) / 64); DBG(DL_DATA_TRACE, "%s: reading: %s\n",me,usb_debug_data(dbgmsg,buf,n)); DBG(DL_DATA_TRACE, "Read %lu bytes\n", (u_long) bytes_read); return status; @@ -521,7 +521,7 @@ static SANE_Status snapscani_usb_shm_init(void) } memset(urb_counters, 0, shm_size); return SANE_STATUS_GOOD; - + } static void snapscani_usb_shm_exit(void) @@ -546,7 +546,7 @@ static SANE_Status snapscani_usb_shm_init(void) strerror (errno)); return SANE_STATUS_NO_MEM; } - + shm_area = shmat (shm_id, NULL, 0); if (shm_area == (void *) -1) { @@ -555,7 +555,7 @@ static SANE_Status snapscani_usb_shm_init(void) shmctl (shm_id, IPC_RMID, NULL); return SANE_STATUS_NO_MEM; } - + if (shmctl (shm_id, IPC_RMID, NULL) == -1) { DBG (DL_MAJOR_ERROR, "snapscani_usb_shm_init: cannot remove shared memory segment id: %s\n", @@ -653,4 +653,3 @@ static void snapscani_usb_shm_exit(void) * - Change copyright notice * * */ - diff --git a/backend/snapscan.c b/backend/snapscan.c index c88537b..b93f1f7 100644 --- a/backend/snapscan.c +++ b/backend/snapscan.c @@ -1286,7 +1286,7 @@ static SANE_Status start_reader (SnapScan_Scanner *pss) pss->nonblocking = SANE_FALSE; pss->rpipe[0] = pss->rpipe[1] = -1; - pss->child = -1; + sanei_thread_initialize (pss->child); if (pipe (pss->rpipe) != -1) { @@ -1812,7 +1812,7 @@ SANE_Status sane_read (SANE_Handle h, if (sanei_thread_is_valid (pss->child)) { sanei_thread_waitpid (pss->child, 0); /* ensure no zombies */ - pss->child = -1; + sanei_thread_invalidate (pss->child); } release_unit (pss); close_scanner (pss); @@ -1871,7 +1871,7 @@ void sane_cancel (SANE_Handle h) /* signal the reader, if any */ if (sanei_thread_is_valid (pss->child)) { - DBG( DL_INFO, ">>>>>>>> killing reader_process <<<<<<<<\n" ); + DBG( DL_INFO, "---- killing reader_process ----\n" ); sigemptyset(&(act.sa_mask)); act.sa_flags = 0; @@ -1904,7 +1904,7 @@ void sane_cancel (SANE_Handle h) sanei_thread_sendsig( pss->child, SIGKILL ); #endif } - pss->child = -1; + sanei_thread_invalidate( pss->child ); DBG( DL_INFO,"reader_process killed\n"); } release_unit (pss); diff --git a/backend/sp15c-scsi.h b/backend/sp15c-scsi.h index 4babc8b..13553a2 100644 --- a/backend/sp15c-scsi.h +++ b/backend/sp15c-scsi.h @@ -1,7 +1,6 @@ #ifndef SP15C_SCSI_H #define SP15C_SCSI_H -static const char RCSid_sh[] = "$Header$"; /* sane - Scanner Access Now Easy. This file is part of the SANE package. diff --git a/backend/sp15c.c b/backend/sp15c.c index 0cabed8..20b2c80 100644 --- a/backend/sp15c.c +++ b/backend/sp15c.c @@ -1,4 +1,3 @@ -static const char RCSid[] = "$Header$"; /* sane - Scanner Access Now Easy. This file is part of the SANE package. @@ -313,7 +312,7 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) { struct sp15c *dev; int i; - + local_only = local_only; /* silence compilation warnings */ DBG (10, "sane_get_devices\n"); @@ -392,7 +391,7 @@ sane_open (SANE_String_Const name, SANE_Handle * handle) SANE_Status sane_set_io_mode (SANE_Handle h, SANE_Bool non_blocking) { - h = h; + h = h; non_blocking = non_blocking; /* silence compilation warnings */ DBG (10, "sane_set_io_mode\n"); @@ -989,7 +988,7 @@ sane_exit (void) free (dev->buffer); free (dev); } - + if (devlist) free (devlist); } /* sane_exit */ @@ -1322,7 +1321,7 @@ static SANE_Status sp15c_do_inquiry (struct sp15c *s) { static SANE_Status ret; - + DBG (10, "do_inquiry\n"); memset (s->buffer, '\0', 256); /* clear buffer */ @@ -1606,7 +1605,7 @@ sp15c_free_scanner (struct sp15c *s) if (ret) return ret; #endif - + wait_scanner (s); ret = do_scsi_cmd (s->sfd, release_unitB.cmd, release_unitB.size, NULL, 0); @@ -1626,7 +1625,7 @@ sp15c_free_scanner (struct sp15c *s) * GOOD * RESERVE UNIT * GOOD - * + * * It is then responsible for installing appropriate signal handlers * to call emergency_give_scanner() if user aborts. */ @@ -1647,7 +1646,7 @@ sp15c_grab_scanner (struct sp15c *s) return 0; } /* sp15c_grab_scanner */ -/* +/* * wait_scanner spins until TEST_UNIT_READY returns 0 (GOOD) * returns 0 on success, * returns -1 on error or timeout @@ -1770,7 +1769,7 @@ do_cancel (struct sp15c *scanner) sanei_thread_kill (scanner->reader_pid); DBG (50, "wait for scanner to stop\n"); sanei_thread_waitpid (scanner->reader_pid, &exit_status); - scanner->reader_pid = -1; + sanei_thread_invalidate (scanner->reader_pid); } if (scanner->sfd >= 0) @@ -1788,7 +1787,7 @@ static void swap_res (struct sp15c *s) { s = s; /* silence compilation warnings */ - + /* for the time being, do nothing */ } /* swap_res */ @@ -1820,7 +1819,7 @@ sp15c_set_window_param (struct sp15c *s, int prescan) int active_buffer_size; prescan = prescan; /* silence compilation warnings */ - + wait_scanner (s); DBG (10, "set_window_param\n"); memset (buffer_r, '\0', WDB_size_max); /* clear buffer */ @@ -1979,7 +1978,7 @@ reader_process (void *data) DBG (10, "reader_process started\n"); - if (sanei_thread_is_forked ()) + if (sanei_thread_is_forked ()) close (scanner->pipe); sigfillset (&ignore_set); diff --git a/backend/sp15c.h b/backend/sp15c.h index e078316..f4b0b7f 100644 --- a/backend/sp15c.h +++ b/backend/sp15c.h @@ -1,7 +1,6 @@ #ifndef SP15C_H #define SP15C_H -static const char RCSid_h[] = "$Header$"; /* sane - Scanner Access Now Easy. This file is part of the SANE package. diff --git a/backend/st400.c b/backend/st400.c index b8ee6d1..16c7f9f 100644 --- a/backend/st400.c +++ b/backend/st400.c @@ -1201,7 +1201,7 @@ sane_cancel( SANE_Handle handle ) #if 0 st400_stop_scan(dev->fd); #endif - if( st400_light_delay ) + if( st400_light_delay ) st400_light_off(dev->fd); st400_release(dev->fd); sanei_scsi_close(dev->fd); diff --git a/backend/stubs.c b/backend/stubs.c index 3fb5ce3..a8afd3e 100644 --- a/backend/stubs.c +++ b/backend/stubs.c @@ -5,6 +5,10 @@ /* Now define the wrappers (we could use aliases here, but go for robustness for now...: */ +#ifdef __cplusplus +extern "C" { +#endif + SANE_Status sane_init (SANE_Int *vc, SANE_Auth_Callback cb) { @@ -83,3 +87,7 @@ sane_exit (void) { ENTRY(exit) (); } + +#ifdef __cplusplus +} // extern "C" +#endif diff --git a/backend/stv680.c b/backend/stv680.c index 15a8472..8d2fda3 100644 --- a/backend/stv680.c +++ b/backend/stv680.c @@ -2,10 +2,10 @@ Copyright (C) 2004 - 2006 Gerard Klaver - The teco2 and gl646 backend (Frank Zago) are used as a template for + The teco2 and gl646 backend (Frank Zago) are used as a template for this backend. - For the usb commands and bayer decoding parts of the following + For the usb commands and bayer decoding parts of the following program are used: The pencam2 program (GNU GPL license 2) @@ -13,22 +13,22 @@ The libgphoto2 (camlib stv0680) (GNU GPL license 2) The stv680.c/.h kernel module (GNU GPL license 2) - For the stv680_add_text routine the add_text routine and font_6x11.h file + For the stv680_add_text routine the add_text routine and font_6x11.h file are taken from the webcam.c file, part of xawtv program, (c) 1998-2002 Gerd Knorr (GNU GPL license 2). 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, @@ -54,7 +54,7 @@ . . - sane_start() : start image acquisition . . - sane_get_parameters() : returns actual scan parameters . . - sane_read() : read image data (from pipe) - . . (sane_read called multiple times; + . . (sane_read called multiple times; . . after sane_read returns EOF) . . go back to sane_start() if more frames desired . . - sane_cancel() : cancel operation @@ -559,7 +559,7 @@ stv680_identify_vidcam (Stv680_Vidcam * dev) "stv680_vidcam_init: STV680 FAILED to set configure\n"); return status; } - */ + */ sizer = 0x02; status = sanei_usb_control_msg (dev->fd, 0xc1, 0x88, 0x5678, 0, sizer, @@ -1180,7 +1180,7 @@ stv680_fill_image (Stv680_Vidcam * dev) /* i = stv_sndctrl (0, dev, 0x80, 0, &window, 0x02); *//* Get Last Error */ /* DBG (DBG_proc, "STV(i): last error: %i, command = 0x%x", window[0], window[1]); return -1; */ -/* +/* } return 0; */ @@ -1315,9 +1315,9 @@ stv680_bayer_unshuffle (Stv680_Vidcam * dev, SANE_Byte * buf, size_t * size) } /* for y */ /****** gamma correction plus hardcoded white balance */ - /* Correction values red[], green[], blue[], are generated by - (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1scan_mode == STV680_COLOR_RGB || dev->scan_mode == STV680_COLOR_RGB_TEXT) diff --git a/backend/stv680.h b/backend/stv680.h index e08976b..a4f5fbe 100644 --- a/backend/stv680.h +++ b/backend/stv680.h @@ -2,10 +2,10 @@ Copyright (C) 2004 -2006 Gerard Klaver (gerard at gkall dot hobby dot nl) - The teco2 and gl646 backend (Frank Zago) are used as a template for + The teco2 and gl646 backend (Frank Zago) are used as a template for this backend. - - For the usb commands and bayer decoding parts of the following + + For the usb commands and bayer decoding parts of the following program are used: The pencam2 program (GNU GPL license 2) @@ -13,7 +13,7 @@ The libgphoto2 (camlib stv0680) (GNU GPL license 2) The stv680.c/.h kernel module (GNU GPL license 2) - For the stv680_add_text routine the add_text routine and font_6x11.h file + For the stv680_add_text routine the add_text routine and font_6x11.h file are taken from the webcam.c file, part of xawtv program, (c) 1998-2002 Gerd Knorr (GNU GPL license 2). @@ -36,7 +36,7 @@ --------------------------------------------------------------------- */ -/* +/* $Id$ update 20-04-2006*/ @@ -94,8 +94,8 @@ enum Stv680_Option /*--------------------------------------------------------------------------*/ -/* - * Video Camera supported by this backend. +/* + * Video Camera supported by this backend. */ struct vidcam_hardware { @@ -207,7 +207,7 @@ Stv680_Vidcam; /*--------------------------------------------------------------------------*/ -/* Debug levels. +/* Debug levels. * Should be common to all backends. */ #define DBG_error0 0 diff --git a/backend/tamarack.c b/backend/tamarack.c index 6fc259f..feb9ee1 100644 --- a/backend/tamarack.c +++ b/backend/tamarack.c @@ -23,8 +23,8 @@ exception gives you, Please do contact me, and we'll work something out. - R.E.Wolff@BitWizard.nl - tel: +31-152137555 + R.E.Wolff@BitWizard.nl + tel: +31-152137555 fax: +31-152138217 This file implements a SANE backend for Tamarack flatbed scanners. */ @@ -92,16 +92,18 @@ static const SANE_String_Const mode_list[] = }; +#if 0 static const SANE_Range u8_range = { 0, /* minimum */ 255, /* maximum */ 0 /* quantization */ }; +#endif /* David used " 100 << SANE_FIXED_SCALE_SHIFT ". This assumes that - * it is implemented that way. I want to hide the datatype. + * it is implemented that way. I want to hide the datatype. */ static const SANE_Range percentage_range = { @@ -111,7 +113,7 @@ static const SANE_Range percentage_range = }; /* David used " 100 << SANE_FIXED_SCALE_SHIFT ". This assumes that - * it is implemented that way. I want to hide the datatype. + * it is implemented that way. I want to hide the datatype. */ static const SANE_Range abs_percentage_range = { @@ -139,7 +141,7 @@ static const uint8_t stop[] = static const uint8_t get_status[] = { - TAMARACK_SCSI_GET_DATA_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, + TAMARACK_SCSI_GET_DATA_STATUS, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00 }; @@ -250,17 +252,17 @@ attach (const char *devname, Tamarack_Device **devp) mfg = strdup (result+8); DBG(1, "attach: Inquiry gives mfg=%s, model=%s.\n", mfg, model); - + if (strcmp (mfg, "TAMARACK") != 0) { DBG(1, "attach: device doesn't look like a Tamarack scanner " "(result[0]=%#02x)\n", result[0]); return SANE_STATUS_INVAL; } - + dev = malloc (sizeof (*dev)); if (!dev) return SANE_STATUS_NO_MEM; - + memset (dev, 0, sizeof (*dev)); dev->sane.name = strdup (devname); @@ -333,7 +335,7 @@ scan_area_and_windows (Tamarack_Scanner *s) memset (&dwp,'\0',sizeof (dwp)); dwp.dwph.opc = TAMARACK_SCSI_AREA_AND_WINDOWS; - set_triple (dwp.dwph.len,8 + sizeof (dwp.wdb)); + set_triple (dwp.dwph.len,8 + sizeof (dwp.wdb)); set_double (dwp.wdh.wpll, sizeof (dwp.wdb)); @@ -343,7 +345,7 @@ scan_area_and_windows (Tamarack_Scanner *s) set_quad (dwp.wdb.ulx, (int) (47.2 * SANE_UNFIX (s->val[OPT_TL_X].w))); set_quad (dwp.wdb.uly, (int) (47.2 * SANE_UNFIX (s->val[OPT_TL_Y].w))); - set_quad (dwp.wdb.width, + set_quad (dwp.wdb.width, (int) (47.2 * SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w))); set_quad (dwp.wdb.length, (int) (47.2 * SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w))); @@ -357,7 +359,7 @@ scan_area_and_windows (Tamarack_Scanner *s) case THRESHOLDED: dwp.wdb.bpp = 1; dwp.wdb.image_comp = 0; - dwp.wdb.thresh = 1 + 2.55 * (SANE_UNFIX (s->val[OPT_THRESHOLD].w)); + dwp.wdb.thresh = 1 + 2.55 * (SANE_UNFIX (s->val[OPT_THRESHOLD].w)); break; case DITHERED: dwp.wdb.bpp = 1; @@ -375,7 +377,7 @@ scan_area_and_windows (Tamarack_Scanner *s) DBG(1, "Invalid mode. %d\n", s->mode); return SANE_STATUS_INVAL; } - DBG(1, "bright, thresh, contrast = %d(%5.1f), %d, %d(%5.1f)\n", + DBG(1, "bright, thresh, contrast = %d(%5.1f), %d, %d(%5.1f)\n", dwp.wdb.brightness, SANE_UNFIX (s->val[OPT_BRIGHTNESS].w), dwp.wdb.thresh , dwp.wdb.contrast , SANE_UNFIX (s->val[OPT_CONTRAST].w)); @@ -399,7 +401,7 @@ mode_select (Tamarack_Scanner *s) struct tamarack_page page; } c; - memset (&c, '\0', sizeof (c)); + memset (&c, '\0', sizeof (c)); c.cmd.opc = TAMARACK_SCSI_MODE_SELECT; c.cmd.pad0[0] = 0x10; /* Suddenly the pad bytes are no long pad... */ c.cmd.pad0[1] = 0; @@ -412,7 +414,7 @@ mode_select (Tamarack_Scanner *s) case THRESHOLDED: case DITHERED: case GREYSCALE: - c.page.masks = 0x80; + c.page.masks = 0x80; break; case TRUECOLOR: c.page.masks = 0x40 >> s->pass; @@ -431,7 +433,7 @@ start_scan (Tamarack_Scanner *s) struct command_header cmd; unsigned char winid[1]; } c; - + memset (&c,'\0',sizeof (c)); c.cmd.opc = TAMARACK_SCSI_START_STOP; c.cmd.len = sizeof (c.winid); @@ -442,9 +444,9 @@ start_scan (Tamarack_Scanner *s) static SANE_Status stop_scan (Tamarack_Scanner *s) -{ +{ /* XXX I don't think a TAMARACK can stop in mid-scan. Just stop - sending it requests for data.... + sending it requests for data.... */ return sanei_scsi_cmd (s->fd, stop, sizeof (stop), 0, 0); } @@ -477,7 +479,7 @@ do_cancel (Tamarack_Scanner *s) /* ensure child knows it's time to stop: */ sanei_thread_kill (s->reader_pid); sanei_thread_waitpid (s->reader_pid, &exit_status); - s->reader_pid = -1; + sanei_thread_invalidate (s->reader_pid); } if (s->fd >= 0) @@ -526,10 +528,10 @@ get_image_status (Tamarack_Scanner *s) result, &len); if ((status != SANE_STATUS_GOOD) && (status != SANE_STATUS_DEVICE_BUSY)) return status; - - s->params.bytes_per_line = + + s->params.bytes_per_line = result[ 8] | (result[ 7] << 8) | (result[6] << 16); - s->params.lines = + s->params.lines = result[11] | (result[10] << 8) | (result[9] << 16); switch (s->mode) { @@ -855,7 +857,7 @@ reader_process (void *scanner) if (!lines_per_buffer) return 2; /* resolution is too high */ - /* Limit the size of a single transfer to one inch. + /* Limit the size of a single transfer to one inch. XXX Add a stripsize option. */ if (lines_per_buffer > SANE_UNFIX (s->val[OPT_RESOLUTION].w)) lines_per_buffer = SANE_UNFIX (s->val[OPT_RESOLUTION].w); @@ -877,14 +879,14 @@ reader_process (void *scanner) return 3; } DBG(3, "reader_process: read %d lines\n", lines_per_buffer); - + if ((s->mode == TRUECOLOR) || (s->mode == GREYSCALE)) { fwrite (data, lines_per_buffer, bpl, fp); } else { /* in singlebit mode, the scanner returns 1 for black. ;-( --DM */ /* Hah! Same for Tamarack... -- REW */ int i; - + for (i = 0; i < lines_per_buffer * bpl; ++i) fputc (~data[i], fp); } @@ -929,10 +931,10 @@ sane_init (SANE_Int *version_code, SANE_Auth_Callback authorize) if (dev_name[0] == '#') /* ignore line comments */ continue; len = strlen (dev_name); - + if (!len) continue; /* ignore empty lines */ - + sanei_config_attach_matching_devices (dev_name, attach_one); } fclose (fp); @@ -951,7 +953,7 @@ sane_exit (void) free ((void *) dev->sane.model); free (dev); } - + if (devlist) free (devlist); } @@ -1063,7 +1065,7 @@ const SANE_Option_Descriptor * sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) { Tamarack_Scanner *s = handle; - + if ((unsigned) option >= NUM_OPTIONS) return 0; return s->opt + option; @@ -1151,7 +1153,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, status = constrain_value (s, option, val, info); if (status != SANE_STATUS_GOOD) return status; - + switch (option) { /* (mostly) side-effect-free word options: */ @@ -1235,7 +1237,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, #endif - if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0) + if (strcmp (val, SANE_VALUE_SCAN_MODE_LINEART) == 0) s->opt[OPT_THRESHOLD].cap &= ~SANE_CAP_INACTIVE; else { s->opt[OPT_BRIGHTNESS].cap &= ~SANE_CAP_INACTIVE; @@ -1271,10 +1273,10 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) if (!s->scanning) { double width, height, dpi; - + memset (&s->params, 0, sizeof (s->params)); - + width = SANE_UNFIX (s->val[OPT_BR_X].w - s->val[OPT_TL_X].w); height = SANE_UNFIX (s->val[OPT_BR_Y].w - s->val[OPT_TL_Y].w); dpi = SANE_UNFIX (s->val[OPT_RESOLUTION].w); @@ -1284,7 +1286,7 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) scanning starts. */ if (dpi > 0.0 && width > 0.0 && height > 0.0) { double dots_per_mm = dpi / MM_PER_INCH; - + s->params.pixels_per_line = width * dots_per_mm; s->params.lines = height * dots_per_mm; } @@ -1308,14 +1310,14 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters *params) } s->params.last_frame = (s->mode != TRUECOLOR) || (s->pass == 2); - + if (params) *params = s->params; DBG(1, "Got parameters: format:%d, ppl: %d, bpl:%d, depth:%d, " - "last %d pass %d\n", - s->params.format, s->params.pixels_per_line, - s->params.bytes_per_line, s->params.depth, + "last %d pass %d\n", + s->params.format, s->params.pixels_per_line, + s->params.bytes_per_line, s->params.depth, s->params.last_frame, s->pass); return SANE_STATUS_GOOD; } @@ -1349,7 +1351,7 @@ sane_start (SANE_Handle handle) s->params.last_frame = SANE_TRUE; } } - + status = sanei_scsi_open (s->hw->sane.name, &s->fd, sense_handler, 0); if (status != SANE_STATUS_GOOD) { DBG(1, "open: open of %s failed: %s\n", @@ -1374,7 +1376,7 @@ sane_start (SANE_Handle handle) status = mode_select (s); if (status != SANE_STATUS_GOOD) goto stop_scanner_and_return; - + s->scanning = SANE_TRUE; status = start_scan (s); @@ -1417,7 +1419,7 @@ sane_read (SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE_Int *len) if (!s->scanning) return do_cancel (s); - + if (nread < 0) { if (errno == EAGAIN) { return SANE_STATUS_GOOD; @@ -1474,4 +1476,3 @@ sane_get_select_fd (SANE_Handle handle, SANE_Int *fd) *fd = s->pipe; return SANE_STATUS_GOOD; } - diff --git a/backend/tamarack.conf.in b/backend/tamarack.conf.in index 4c5ae7d..52f24d0 100644 --- a/backend/tamarack.conf.in +++ b/backend/tamarack.conf.in @@ -1,3 +1,2 @@ scsi TAMARACK /dev/scanner - diff --git a/backend/tamarack.h b/backend/tamarack.h index 65697ac..3b1e1c5 100644 --- a/backend/tamarack.h +++ b/backend/tamarack.h @@ -167,11 +167,11 @@ Tamarack_Scanner; #define TAMARACK_SCSI_TEST_UNIT_READY 0x00 #define TAMARACK_SCSI_INQUIRY 0x12 -#define TAMARACK_SCSI_MODE_SELECT 0x15 +#define TAMARACK_SCSI_MODE_SELECT 0x15 #define TAMARACK_SCSI_START_STOP 0x1b #define TAMARACK_SCSI_AREA_AND_WINDOWS 0x24 #define TAMARACK_SCSI_READ_SCANNED_DATA 0x28 -#define TAMARACK_SCSI_GET_DATA_STATUS 0x34 +#define TAMARACK_SCSI_GET_DATA_STATUS 0x34 /* The structures that you have to send to the tamarack to get it to @@ -190,7 +190,7 @@ struct win_desc_block { unsigned char yres[2]; unsigned char ulx[4]; unsigned char uly[4]; - unsigned char width[4]; + unsigned char width[4]; unsigned char length[4]; unsigned char brightness; unsigned char thresh; @@ -209,7 +209,7 @@ struct win_desc_block { struct command_header { unsigned char opc; - unsigned char pad0[3]; + unsigned char pad0[3]; unsigned char len; unsigned char pad1; }; @@ -217,7 +217,7 @@ struct command_header { struct command_header_10 { unsigned char opc; - unsigned char pad0[5]; + unsigned char pad0[5]; unsigned char len[3]; unsigned char pad1; }; diff --git a/backend/teco1.c b/backend/teco1.c index 2a13201..136f537 100644 --- a/backend/teco1.c +++ b/backend/teco1.c @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002 Frank Zago (sane at zago dot net) - + 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. + If you do not wish that, delete this exception notice. */ /* @@ -190,16 +190,16 @@ static const struct scanners_supported scanners[] = { 99 }, - {6, "TECO VM4540", - TECO_VM4540, - "Relisys", "RELI 4816", - {1, 1600, 1}, /* resolution */ - 400, 1600, /* max x and Y resolution */ - 1, /* color 1 pass */ - 256, /* number of bytes per gamma color */ - 99 /* number of bytes in a window */ + {6, "TECO VM4540", + TECO_VM4540, + "Relisys", "RELI 4816", + {1, 1600, 1}, /* resolution */ + 400, 1600, /* max x and Y resolution */ + 1, /* color 1 pass */ + 256, /* number of bytes per gamma color */ + 99 /* number of bytes in a window */ }, - + {6, "TECO VM4542", TECO_VM4542, "Relisys", "RELI 4830", @@ -1240,7 +1240,7 @@ teco_init_options (Teco_Scanner * dev) (SANE_String_Const *) scan_mode_list[0], NULL); } -/* +/* * Wait until the scanner is ready. */ static SANE_Status @@ -1295,7 +1295,7 @@ teco_fill_image (Teco_Scanner * dev) while (dev->real_bytes_left) { - /* + /* * Try to read the maximum number of bytes. */ size = 0; @@ -1318,7 +1318,7 @@ teco_fill_image (Teco_Scanner * dev) if (size == 0) { - /* Probably reached the end of the buffer. + /* Probably reached the end of the buffer. * Check, just in case. */ assert (dev->image_end != 0); return (SANE_STATUS_GOOD); @@ -1389,7 +1389,7 @@ teco_fill_image (Teco_Scanner * dev) return (SANE_STATUS_GOOD); /* unreachable */ } -/* Copy from the raw buffer to the buffer given by the backend. +/* Copy from the raw buffer to the buffer given by the backend. * * len in input is the maximum length available in buf, and, in * output, is the length written into buf. diff --git a/backend/teco1.h b/backend/teco1.h index 1b5fecb..528613f 100644 --- a/backend/teco1.h +++ b/backend/teco1.h @@ -38,10 +38,10 @@ 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. + If you do not wish that, delete this exception notice. */ -/* +/* $Id$ */ @@ -253,8 +253,8 @@ enum Teco_Option /*--------------------------------------------------------------------------*/ -/* - * Scanner supported by this backend. +/* + * Scanner supported by this backend. */ struct scanners_supported { @@ -363,7 +363,7 @@ Teco_Scanner; /*--------------------------------------------------------------------------*/ -/* Debug levels. +/* Debug levels. * Should be common to all backends. */ #define DBG_error0 0 diff --git a/backend/teco2.c b/backend/teco2.c index 9bc8bf4..a104189 100644 --- a/backend/teco2.c +++ b/backend/teco2.c @@ -4,42 +4,42 @@ Copyright (C) 2003-2008 Gerard Klaver (gerard at gkall dot hobby dot nl) 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. + If you do not wish that, delete this exception notice. */ /* @@ -61,7 +61,7 @@ changed use of %d to %ld (when bytes values are displayed) update 2005/03/04, use of __sane_unused__ update 2005/07/29. Removed using teco_request_sense (dev) routine for VM3564 - update 2008/01/12, Update teco_request_sense routine due to no + update 2008/01/12, Update teco_request_sense routine due to no init value for size. */ @@ -317,10 +317,6 @@ static const struct dpi_color_adjust vm6586_dpi_color_adjust[] = { {0, 0, 0, 0, 0, 0} }; -static const struct dpi_color_adjust default_dpi_color_adjust[1] = { - {0, 0, 1, 2, 0, 0} -}; - /* For all scanners. Must be reasonable (eg. between 50 and 300) and * appear in the ...._dpi_color_adjust list of all supported scanners. */ #define DEF_RESOLUTION 150 @@ -1129,17 +1125,17 @@ teco_wait_for_data (Teco_Scanner * dev) /* Do the calibration stuff. Get 12 or 8 lines of data. Each pixel is coded * in 6 bytes (2 per color) or 3 bytes (3564 and 356A). To do the calibration, * allocates an array big enough for one line, read the 12 or 8 lines of calibration, - * subtract the highest and lowest value and do a average. + * subtract the highest and lowest value and do a average. * The input line is 1 raster for each color. However * the output line is interlaced (ie RBG for the first pixel, then RGB * for the second, and so on...). The output line are the value to use - * to compensate for the white point. + * to compensate for the white point. * There is two algorithms: * * The range goes from 0 to 0xfff, and the average is 0x800. So if * the average input is 0x700, the output value for that dot must be * 0x1000-0x700=0x900. - * + * * and * * the calibration needs to be a multiplication factor, to @@ -1169,7 +1165,7 @@ teco_do_calibration (Teco_Scanner * dev) colsub1_0 = 0; colsub1_1 = 0; colsub1_2 = 0; - + DBG (DBG_proc, "teco_do_calibration: enter\n"); /* Get default calibration algorithm. */ @@ -1251,7 +1247,7 @@ teco_do_calibration (Teco_Scanner * dev) memset (tmp_max_buf, 0x0000, tmp_max_buf_size); break; } - + if ((tmp_buf == NULL) || (tmp_min_buf == NULL) || (tmp_max_buf == NULL)) { DBG (DBG_proc, "teco_do_calibration: not enough memory (%ld bytes)\n", @@ -1362,29 +1358,29 @@ teco_do_calibration (Teco_Scanner * dev) tmp_min_buf[3 * j + 0] = dev->buffer[3 * j + 0]; } /* get highest value */ - if (tmp_max_buf[3 * j + 0] < dev->buffer[3 * j + 0]) + if (tmp_max_buf[3 * j + 0] < dev->buffer[3 * j + 0]) { tmp_max_buf[3 * j + 0] = dev->buffer[3 * j + 0]; } tmp_buf[3 * j + 1] += dev->buffer[3 * j + 1]; /* get lowest value */ - if (tmp_min_buf[3 * j + 1] >> dev->buffer[3 * j + 1]) + if (tmp_min_buf[3 * j + 1] >> dev->buffer[3 * j + 1]) { tmp_min_buf[3 * j + 1] = dev->buffer[3 * j + 1]; } /* get hightest value */ - if (tmp_max_buf[3 * j + 1] < dev->buffer[3 * j + 1]) + if (tmp_max_buf[3 * j + 1] < dev->buffer[3 * j + 1]) { tmp_max_buf[3 * j + 1] = dev->buffer[3 * j + 1]; } tmp_buf[3 * j + 2] += dev->buffer[3 * j + 2]; /* get lowest value */ - if (tmp_min_buf[3 * j + 2] >> dev->buffer[3 * j + 2]) + if (tmp_min_buf[3 * j + 2] >> dev->buffer[3 * j + 2]) { tmp_min_buf[3 * j + 2] = dev->buffer[3 * j + 2]; } /* get highest value */ - if (tmp_max_buf[3 * j + 2] < dev->buffer[3 * j + 2]) + if (tmp_max_buf[3 * j + 2] < dev->buffer[3 * j + 2]) { tmp_max_buf[3 * j + 2] = dev->buffer[3 * j + 2]; } @@ -1404,7 +1400,7 @@ teco_do_calibration (Teco_Scanner * dev) /* hexdump (DBG_info2, "calibration before average:", tmp_buf, tmp_buf_size); */ /* hexdump (DBG_info2, "calibration before average min value:", tmp_min_buf, tmp_min_buf_size); */ /* hexdump (DBG_info2, "calibration before average max value:", tmp_max_buf, tmp_max_buf_size); */ - + /* Do the average. Since we got 12 or 8 lines, divide all values by 10 or 6 * and create the final calibration value that compensates for the * white values read. */ @@ -1419,28 +1415,28 @@ teco_do_calibration (Teco_Scanner * dev) for (j = 0; j < dev->def->cal_length; j++) { /* subtract lowest and highest value */ - tmp_buf[j] = tmp_buf[j] - (tmp_min_buf[j] + tmp_max_buf[j]); - tmp_buf[j + dev->def->cal_length] = tmp_buf[j + dev->def->cal_length] - - (tmp_min_buf[j + dev->def->cal_length] - + tmp_max_buf[j + dev->def->cal_length]); - tmp_buf[j + 2 * dev->def->cal_length] = tmp_buf[j + 2 * dev->def->cal_length] - - (tmp_min_buf[j + 2 * dev->def->cal_length] - + tmp_max_buf[j + 2 *dev->def->cal_length]); + tmp_buf[j] = tmp_buf[j] - (tmp_min_buf[j] + tmp_max_buf[j]); + tmp_buf[j + dev->def->cal_length] = tmp_buf[j + dev->def->cal_length] + - (tmp_min_buf[j + dev->def->cal_length] + + tmp_max_buf[j + dev->def->cal_length]); + tmp_buf[j + 2 * dev->def->cal_length] = tmp_buf[j + 2 * dev->def->cal_length] + - (tmp_min_buf[j + 2 * dev->def->cal_length] + + tmp_max_buf[j + 2 *dev->def->cal_length]); /* sequence colors first color row one then two and last three */ - if (cal_algo == 1) + if (cal_algo == 1) { tmp_buf[j] = (colsub1_0 * (dev->def->cal_lines - 2)) / tmp_buf[j]; - tmp_buf[j + dev->def->cal_length] = (colsub1_1 * (dev->def->cal_lines - 2)) + tmp_buf[j + dev->def->cal_length] = (colsub1_1 * (dev->def->cal_lines - 2)) / tmp_buf[j + dev->def->cal_length]; - tmp_buf[j + 2 * dev->def->cal_length] = (colsub1_2 * (dev->def->cal_lines - 2)) + tmp_buf[j + 2 * dev->def->cal_length] = (colsub1_2 * (dev->def->cal_lines - 2)) / tmp_buf[j + 2 * dev->def->cal_length]; } - else + else { tmp_buf[j] = colsub0_0 - (tmp_buf[j] / (dev->def->cal_lines - 2)); - tmp_buf[j + dev->def->cal_length] = colsub0_1 - (tmp_buf[j + dev->def->cal_length] + tmp_buf[j + dev->def->cal_length] = colsub0_1 - (tmp_buf[j + dev->def->cal_length] / (dev->def->cal_lines - 2)); - tmp_buf[j + 2 * dev->def->cal_length] = colsub0_2 + tmp_buf[j + 2 * dev->def->cal_length] = colsub0_2 - (tmp_buf[j + 2 * dev->def->cal_length] / (dev->def->cal_lines - 2)); } } @@ -1450,7 +1446,7 @@ teco_do_calibration (Teco_Scanner * dev) { if (cal_algo == 1) tmp_buf[j] = (colsub1_1 * dev->def->cal_lines) / tmp_buf[j]; - else + else tmp_buf[j] = colsub0_1 - (tmp_buf[j] / dev->def->cal_lines); } break; */ @@ -1531,10 +1527,10 @@ teco_request_sense (Teco_Scanner * dev) /* size = 0; */ DBG (DBG_proc, "teco_request_sense: enter\n"); - + size = sizeof (buf); MKSCSI_REQUEST_SENSE (cdb, size); - + /*size = cdb.data[5]; hexdump (DBG_info2, "teco_request_sense", cdb.data, cdb.len); @@ -1545,7 +1541,7 @@ teco_request_sense (Teco_Scanner * dev) NULL, 0, buf, &size); hexdump (DBG_info2, "teco_request_sense:", buf, size); - + DBG (DBG_proc, "teco_request_sense: exit, status=%d\n", status); return (status); @@ -2083,7 +2079,7 @@ teco_init_options (Teco_Scanner * dev) dev->opt[OPT_WHITE_LEVEL_G].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_WHITE_LEVEL_G].constraint.range = &green_level_range; dev->val[OPT_WHITE_LEVEL_G].w = 32; /* to get middle value */ - + /* blue level calibration manual correction */ dev->opt[OPT_WHITE_LEVEL_B].name = SANE_NAME_WHITE_LEVEL_B; dev->opt[OPT_WHITE_LEVEL_B].title = SANE_TITLE_WHITE_LEVEL_B; @@ -2093,14 +2089,14 @@ teco_init_options (Teco_Scanner * dev) dev->opt[OPT_WHITE_LEVEL_B].constraint_type = SANE_CONSTRAINT_RANGE; dev->opt[OPT_WHITE_LEVEL_B].constraint.range = &blue_level_range; dev->val[OPT_WHITE_LEVEL_B].w = 32; /* to get middle value */ - + /* Lastly, set the default scan mode. This might change some * values previously set here. */ sane_control_option (dev, OPT_MODE, SANE_ACTION_SET_VALUE, (SANE_String_Const *) scan_mode_list[0], NULL); } -/* +/* * Wait until the scanner is ready. */ static SANE_Status @@ -2136,7 +2132,7 @@ teco_wait_scanner (Teco_Scanner * dev) return (SANE_STATUS_IO_ERROR); } -/* +/* * Adjust the rasters. This function is used during a color scan, * because the scanner does not present a format sane can interpret * directly. @@ -2147,7 +2143,7 @@ teco_wait_scanner (Teco_Scanner * dev) * * The order of the color is dependant on each scanners. Also the same * scanner can change the order depending on the resolution. - * + * * For instance, the VM6586 at 300dpi has a color shift of 2 lines. The rasters sent are: * starts with two blue rasters - BB, * then red in added - BRBR @@ -2156,7 +2152,7 @@ teco_wait_scanner (Teco_Scanner * dev) * and finaly only green stays - GG * * Overall there is the same number of RGB rasters. - * The VM3575 is a variant (when factor_x is 0). It does not keep the same order, + * The VM3575 is a variant (when factor_x is 0). It does not keep the same order, * but reverses it, eg: * BB RBRB GRB... GRGR GG * (ie it adds the new color in front of the previous one, instead of after). @@ -2192,7 +2188,7 @@ teco_adjust_raster (Teco_Scanner * dev, size_t size_in) return; } - /* + /* * The color coding is one line for each color (in the RGB order). * Recombine that stuff to create a RGB value for each pixel. */ @@ -2202,7 +2198,7 @@ teco_adjust_raster (Teco_Scanner * dev, size_t size_in) for (raster = 0; raster < nb_rasters; raster++) { - /* + /* * Find the color and the line which this raster belongs to. */ line = 0; @@ -2365,7 +2361,7 @@ teco_fill_image (Teco_Scanner * dev) /* Copy the complete lines, plus the incompletes * ones. We don't keep the real end of data used - * in image, so we copy the biggest possible. + * in image, so we copy the biggest possible. * * This is a no-op for non color images. */ @@ -2376,7 +2372,7 @@ teco_fill_image (Teco_Scanner * dev) while (dev->real_bytes_left) { - /* + /* * Try to read the maximum number of bytes. */ size = dev->real_bytes_left; @@ -2398,7 +2394,7 @@ teco_fill_image (Teco_Scanner * dev) if (size == 0) { - /* Probably reached the end of the buffer. + /* Probably reached the end of the buffer. * Check, just in case. */ assert (dev->image_end != 0); return (SANE_STATUS_GOOD); @@ -2446,7 +2442,7 @@ teco_fill_image (Teco_Scanner * dev) return (SANE_STATUS_GOOD); /* unreachable */ } -/* Copy from the raw buffer to the buffer given by the backend. +/* Copy from the raw buffer to the buffer given by the backend. * * len in input is the maximum length available in buf, and, in * output, is the length written into buf. diff --git a/backend/teco2.conf.in b/backend/teco2.conf.in index a012e56..f5db0bb 100644 --- a/backend/teco2.conf.in +++ b/backend/teco2.conf.in @@ -1,5 +1,5 @@ # VM3564 RELISYS AVEC II S3 scanner -scsi "RELISYS" "AVEC II S3" +scsi "RELISYS" "AVEC II S3" # VM356A Primax Jewel 4800 scanner scsi "Primax" "Jewel" @@ -13,7 +13,7 @@ scsi "RELISYS" "AVEC Super 3" # VM3575 Relisys SCORPIO Super 3 # VM3575 Mustek ScanMagic 4830S # VM6586 Relisys SCORPIO Pro-S -scsi "" "Flatbed Scanner" +scsi "" "Flatbed Scanner" # VM656A Relisys APOLLO Express 6 scsi "RELISYS" "APOLLO Express 6" diff --git a/backend/teco2.h b/backend/teco2.h index 9975f03..ead4525 100644 --- a/backend/teco2.h +++ b/backend/teco2.h @@ -39,10 +39,10 @@ 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. + If you do not wish that, delete this exception notice. */ -/* +/* $Id$ */ @@ -307,8 +307,8 @@ enum Teco_Option /*--------------------------------------------------------------------------*/ -/* - * Scanner supported by this backend. +/* + * Scanner supported by this backend. */ struct scanners_supported { @@ -434,7 +434,7 @@ Teco_Scanner; /*--------------------------------------------------------------------------*/ -/* Debug levels. +/* Debug levels. * Should be common to all backends. */ #define DBG_error0 0 diff --git a/backend/teco3.c b/backend/teco3.c index e66d95d..b58312a 100644 --- a/backend/teco3.c +++ b/backend/teco3.c @@ -1,44 +1,44 @@ /* sane - Scanner Access Now Easy. Copyright (C) 2002 Frank Zago (sane at zago dot net) - + 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. + If you do not wish that, delete this exception notice. */ /* @@ -629,7 +629,7 @@ get_filled_data_length (Teco_Scanner * dev, size_t * to_read) if (dev->buffer[17] == 0x07) { /* There is no RAM extension present. The colors will - * be shifted and the backend will need to fix that. + * be shifted and the backend will need to fix that. */ dev->does_color_shift = 1; } @@ -1065,7 +1065,7 @@ teco_init_options (Teco_Scanner * dev) (SANE_String_Const *) scan_mode_list[0], NULL); } -/* +/* * Wait until the scanner is ready. */ static SANE_Status @@ -1101,7 +1101,7 @@ teco_wait_scanner (Teco_Scanner * dev) return (SANE_STATUS_IO_ERROR); } -/* +/* * Get the sense */ static SANE_Status @@ -1125,19 +1125,19 @@ teco_query_sense (Teco_Scanner * dev) return (status); } -/* +/* * Adjust the rasters. This function is used during a color scan, * because the scanner does not present a format sane can interpret * directly. * * The scanner sends the colors by rasters (B then G then R), whereas * sane is waiting for a group of 3 bytes per color. To make things - * funnier, the rasters are shifted. The format of those raster is: + * funnier, the rasters are shifted. The format of those raster is: * BGR...BGR * * For a proper scan, the first 2 R and 1 G, and the last 1 G and 2 B * must be ignored. (TODO) - * + * * So this function reorders all that mess. It gets the input from * dev->buffer and write the output in dev->image. size_in the the * length of the valid data in dev->buffer. */ @@ -1169,7 +1169,7 @@ teco_adjust_raster (Teco_Scanner * dev, size_t size_in) return; } - /* + /* * The color coding is one line for each color (in the RGB order). * Recombine that stuff to create a RGB value for each pixel. */ @@ -1179,7 +1179,7 @@ teco_adjust_raster (Teco_Scanner * dev, size_t size_in) for (raster = 0; raster < nb_rasters; raster++) { - /* + /* * Find the color to which this raster belongs to. */ line = 0; @@ -1295,7 +1295,7 @@ teco_fill_image (Teco_Scanner * dev) /* Copy the complete lines, plus the incompletes * ones. We don't keep the real end of data used - * in image, so we copy the biggest possible. + * in image, so we copy the biggest possible. */ if (dev->scan_mode == TECO_COLOR) { @@ -1313,13 +1313,13 @@ teco_fill_image (Teco_Scanner * dev) if (dev->raster_ahead + dev->image_end + dev->params.bytes_per_line > dev->image_size) { - /* Probably reached the end of the buffer. + /* Probably reached the end of the buffer. * Check, just in case. */ assert (dev->image_end != 0); return (SANE_STATUS_GOOD); } - /* + /* * Try to read the maximum number of bytes. */ size = 0; @@ -1346,7 +1346,7 @@ teco_fill_image (Teco_Scanner * dev) if (size == 0) { - /* Probably reached the end of the buffer. + /* Probably reached the end of the buffer. * Check, just in case. */ assert (dev->image_end != 0); return (SANE_STATUS_GOOD); @@ -1401,7 +1401,7 @@ teco_fill_image (Teco_Scanner * dev) return (SANE_STATUS_GOOD); /* unreachable */ } -/* Copy from the raw buffer to the buffer given by the backend. +/* Copy from the raw buffer to the buffer given by the backend. * * len in input is the maximum length available in buf, and, in * output, is the length written into buf. diff --git a/backend/teco3.h b/backend/teco3.h index 64e894d..4c0e1af 100644 --- a/backend/teco3.h +++ b/backend/teco3.h @@ -38,10 +38,10 @@ 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. + If you do not wish that, delete this exception notice. */ -/* +/* $Id$ */ @@ -267,8 +267,8 @@ enum Teco_Option /*--------------------------------------------------------------------------*/ -/* - * Scanner supported by this backend. +/* + * Scanner supported by this backend. */ struct scanners_supported { @@ -391,7 +391,7 @@ Teco_Scanner; /*--------------------------------------------------------------------------*/ -/* Debug levels. +/* Debug levels. * Should be common to all backends. */ #define DBG_error0 0 diff --git a/backend/test-picture.c b/backend/test-picture.c index e2d81ce..46407dc 100644 --- a/backend/test-picture.c +++ b/backend/test-picture.c @@ -36,7 +36,7 @@ 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. + If you do not wish that, delete this exception notice. This file implements test picture functions for the test backend. */ diff --git a/backend/test.c b/backend/test.c index 2ca5b3b..3ead456 100644 --- a/backend/test.c +++ b/backend/test.c @@ -1375,7 +1375,7 @@ finish_pass (Test_Device * test_device) DBG (2, "finish_pass: reader process terminated with status: %s\n", sane_strstatus (status)); } - test_device->reader_pid = -1; + sanei_thread_invalidate (test_device->reader_pid); } /* this happens when running in thread context... */ if (test_device->reader_fds >= 0) @@ -1641,7 +1641,7 @@ sane_init (SANE_Int * __sane_unused__ version_code, SANE_Auth_Callback __sane_un test_device->eof = SANE_FALSE; test_device->scanning = SANE_FALSE; test_device->cancelled = SANE_FALSE; - test_device->reader_pid = -1; + sanei_thread_initialize (test_device->reader_pid); test_device->pipe = -1; DBG (4, "sane_init: new device: `%s' is a %s %s %s\n", test_device->sane.name, test_device->sane.vendor, @@ -2521,7 +2521,7 @@ sane_start (SANE_Handle handle) { test_device->number_of_scans++; DBG (3, "sane_start: scanning page %d\n", test_device->number_of_scans); - + if ((strcmp (test_device->val[opt_scan_source].s, "Automatic Document Feeder") == 0) && (((test_device->number_of_scans) % 11) == 0)) { diff --git a/backend/u12-ccd.c b/backend/u12-ccd.c index 3f1ad77..fdbb54e 100644 --- a/backend/u12-ccd.c +++ b/backend/u12-ccd.c @@ -483,7 +483,7 @@ static void fnCCDInitWolfson3799( U12_Device *dev ) } } -/** +/** */ static void fnCCDInitWolfson548( U12_Device *dev ) { @@ -788,7 +788,7 @@ static void fnDACDarkWolfson( U12_Device *dev, ShadingVarDef *sTbl, if ((short) w < 0) w = 0; - + if( w != (u_short)dev->shade.DarkDAC.bColors[dwCh] ) { dev->shade.DarkDAC.bColors [dwCh] = (SANE_Byte)w; dev->shade.fStop = SANE_FALSE; @@ -926,7 +926,7 @@ static void u12ccd_InitCCDandDAC( U12_Device *dev, SANE_Bool shading ) DBG( _DBG_INFO, "* DAC: Samsung 1224\n" ); switch( dev->CCDID ) { - + case _CCD_3797: DBG( _DBG_INFO, "* CCD-3797\n" ); pDAC_CCD = ShadingVar3797; diff --git a/backend/u12-hw.c b/backend/u12-hw.c index e21c78a..fb81ee6 100644 --- a/backend/u12-hw.c +++ b/backend/u12-hw.c @@ -216,7 +216,7 @@ static void u12hw_InitiateComponentModel( U12_Device *dev ) dev->regs.RD_MotorDriverType |= _MOTORR_WEAK; /* } */ } - + /** */ static SANE_Status u12hw_InitAsic( U12_Device *dev, SANE_Bool shading ) @@ -259,7 +259,7 @@ static SANE_Status u12hw_InitAsic( U12_Device *dev, SANE_Bool shading ) if( dev->shade.intermediate & _ScanMode_Mono ) dev->regs.RD_Model1Control += _SCAN_GRAYTYPE; - DBG( _DBG_INFO, "* MotorDrvType = 0x%02x\n", dev->regs.RD_MotorDriverType); + DBG( _DBG_INFO, "* MotorDrvType = 0x%02x\n", dev->regs.RD_MotorDriverType); DBG( _DBG_INFO, "* Model1Cntrl = 0x%02x\n", dev->regs.RD_Model1Control ); #if 0 @@ -383,7 +383,7 @@ static void u12hw_SetupPreviewCondition( U12_Device *dev ) dev->scan.dwMaxReadFifo += (dev->DataInf.dwAsicBytesPerPlane / 2); - if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) + if( dev->DataInf.wPhyDataType > COLOR_256GRAY ) dev->scan.bFifoSelect = REG_BFIFOOFFSET; else dev->scan.bFifoSelect = REG_GFIFOOFFSET; @@ -714,7 +714,7 @@ static SANE_Status u12hw_Memtest( U12_Device *dev ) u12io_DataToRegister( dev, REG_WIDTHPIXELHI, 5 ); memset( buf, 0, _TEST_SIZE ); - + dev->regs.RD_ModeControl = _ModeReadMappingMem; u12io_ReadData( dev, buf, _TEST_SIZE ); @@ -793,7 +793,7 @@ static void u12hw_CancelSequence( U12_Device *dev ) { int c = 0; SANE_Byte rb[6]; - + DBG( _DBG_INFO, "u12hw_CancelSequence()\n" ); u12motor_PositionModuleToHome( dev ); @@ -888,7 +888,7 @@ static void usb_LampTimerIrq( int sig ) } else if( tmp & _TPALAMP_ON ) { DBG( _DBG_INFO, "* TPA lamp is ON\n" ); } - + u12io_DataToRegister( dev_xxx, REG_SCANCONTROL, 0 ); u12io_CloseScanPath( dev_xxx ); } diff --git a/backend/u12-hwdef.h b/backend/u12-hwdef.h index ac86cf5..43ea64f 100644 --- a/backend/u12-hwdef.h +++ b/backend/u12-hwdef.h @@ -224,7 +224,7 @@ #define _MotorHFullStepH 0x00 #define _MotorHHalfStep 0x04 #define _MotorHQuarterStep 0x08 -#define _MotorPowerEnable 0x40 +#define _MotorPowerEnable 0x40 #define _MotorHHomeStop 0x80 #define _DIR_FW 1 @@ -269,7 +269,7 @@ #define _AGFA_PCB 0x1f /* Register RegModelControl (Addr: 0x1f) */ -#define _HOME_SENSOR_POLARITY 0x01 +#define _HOME_SENSOR_POLARITY 0x01 #define _LED_CONTROL 0x02 #define _LED_ACTIVITY 0x04 #define _MODEL_DPI200 0x00 @@ -393,7 +393,7 @@ #define _DEFAULT_LINESCANTIME 96 -#define _LINE_TIMEOUT (_SECOND * 5 ) +#define _LINE_TIMEOUT (_SECOND * 5 ) /** for mirroring parts of the 98003 ASIC register set @@ -439,7 +439,7 @@ typedef struct svd SANE_Byte Reserved; } ShadingVarDef; -typedef struct +typedef struct { ShadingVarDef *pCcdDac; ColorByte DarkDAC; diff --git a/backend/u12-if.c b/backend/u12-if.c index be213b4..91a8c1f 100644 --- a/backend/u12-if.c +++ b/backend/u12-if.c @@ -68,7 +68,7 @@ typedef struct { #define _PLUSTEK_VENID 0x07B3 #define _KYE_VENID 0x0458 - + /** to allow different vendors... */ static TabDef u12Vendors[] = { @@ -148,7 +148,7 @@ static void u12if_shutdown( U12_Device *dev ) DBG( _DBG_INFO, "Shutdown called (dev->fd=%d, %s)\n", dev->fd, dev->sane.name ); if( SANE_STATUS_GOOD == sanei_usb_open( dev->sane.name, &handle )) { - + dev->fd = handle; u12io_OpenScanPath( dev ); @@ -234,7 +234,7 @@ static SANE_Bool usbDev_autodetect( SANE_Word *vendor, SANE_Word *product ) { int i; SANE_Word p, v; - + DBG( _DBG_INFO, "Autodetection...\n" ); for( i = 0; NULL != u12Devices[i].name; i++ ) { @@ -310,7 +310,7 @@ static int u12if_open( U12_Device *dev ) */ free( dev->name ); dev->name = strdup( USB_devname ); - dev->sane.name = dev->name; + dev->sane.name = dev->name; } else { @@ -329,7 +329,7 @@ static int u12if_open( U12_Device *dev ) DBG(_DBG_INFO,"Vendor ID=0x%04X, Product ID=0x%04X\n",vendor,product); if( dev->usbId[0] != '\0' ) { - + if( 0 != strcmp( dev->usbId, devStr )) { DBG( _DBG_ERROR, "Specified Vendor and Product ID " "doesn't match with the ones\n" @@ -340,7 +340,7 @@ static int u12if_open( U12_Device *dev ) } else { sprintf( dev->usbId, "0x%04X-0x%04X", vendor, product ); was_empty = SANE_TRUE; - } + } } else { @@ -397,7 +397,7 @@ static int u12if_open( U12_Device *dev ) if( dev->Tpa ) dev->sane.model = "UT12"; } - + dev->initialized = SANE_TRUE; return handle; } @@ -413,7 +413,7 @@ static int u12if_close( U12_Device *dev ) return 0; } -/** +/** */ static SANE_Status u12if_getCaps( U12_Device *dev ) { @@ -459,7 +459,7 @@ static SANE_Status u12if_getCaps( U12_Device *dev ) dev->res_list_size++; dev->res_list[dev->res_list_size - 1] = (SANE_Int)cntr; } - + return SANE_STATUS_GOOD; } @@ -500,7 +500,7 @@ static SANE_Status u12if_stopScan( U12_Device *dev ) static SANE_Status u12if_prepare( U12_Device *dev ) { SANE_Status res; - + DBG( _DBG_INFO, "u12if_prepare()\n" ); u12motor_ToHomePosition( dev, SANE_TRUE ); @@ -514,11 +514,11 @@ static SANE_Status u12if_prepare( U12_Device *dev ) return res; u12image_PrepareScaling( dev ); - + u12motor_ForceToLeaveHomePos( dev ); if( dev->DataInf.dwScanFlag & _SCANDEF_PREVIEW ) u12hw_SetupPreviewCondition( dev ); - else + else u12hw_SetupScanningCondition( dev ); res = u12motor_WaitForPositionY( dev ); diff --git a/backend/u12-image.c b/backend/u12-image.c index 1d9acda..df721db 100644 --- a/backend/u12-image.c +++ b/backend/u12-image.c @@ -217,7 +217,7 @@ static void fnColor42( U12_Device *dev, void *pb, void *img, u_long len ) { u_short *src; RGBUShortDef *dest; - + register u_long i; _VAR_NOT_USED( len ); @@ -317,7 +317,7 @@ u12image_GetPhysDPI( U12_Device *dev, ImgDef *img, SANE_Bool fDpiX ) return img->xyDpi.x; } else { - + if( img->xyDpi.y > dev->dpi_max_y ) return dev->dpi_max_y; else @@ -374,7 +374,7 @@ static void u12image_GetImageInfo( U12_Device *dev, ImgDef *image ) switch( image->wDataType ) { - case COLOR_BW: + case COLOR_BW: dev->scan.DataProcess = fnDataDirect; dev->DataInf.wPhyDataType = COLOR_BW; dev->shade.intermediate = _ScanMode_Mono; @@ -407,7 +407,7 @@ static void u12image_GetImageInfo( U12_Device *dev, ImgDef *image ) /* raus mit einem von beiden!!!!*/ dev->DataInf.dwAppBytesPerLine = dev->DataInf.dwAppPhyBytesPerLine; - + DBG( _DBG_INFO, "AppLinesPerArea = %lu\n", dev->DataInf.dwAppLinesPerArea ); DBG( _DBG_INFO, "AppPixelsPerLine = %lu\n", dev->DataInf.dwAppPixelsPerLine ); DBG( _DBG_INFO, "AppPhyBytesPerLine = %lu\n", dev->DataInf.dwAppPhyBytesPerLine ); @@ -418,7 +418,7 @@ static void u12image_GetImageInfo( U12_Device *dev, ImgDef *image ) DBG( _DBG_INFO, "Physical Bytes = %lu\n", dev->DataInf.dwPhysBytesPerLine ); } -/** +/** */ static int imageSetupScanSettings( U12_Device *dev, ImgDef *img ) { @@ -483,7 +483,7 @@ static SANE_Status u12image_SetupScanSettings( U12_Device *dev, ImgDef *img ) wPreviewScanned = 0; dev->scan.dpiIdx = 0; dev->scan.negScan = negScan; - + imageSetupScanSettings( dev, img ); if( !(dev->DataInf.dwScanFlag & _SCANDEF_TPA )) { @@ -816,7 +816,7 @@ static void u12image_PrepareScaling( U12_Device *dev ) dev->DataInf.xyAppDpi.x, dev->dpi_max_x ); if( dev->DataInf.xyAppDpi.x > dev->dpi_max_x ) { - + dev->scaleBuf = malloc( dev->DataInf.dwAppBytesPerLine ); ratio = (double)dev->DataInf.xyAppDpi.x/(double)dev->dpi_max_x; @@ -837,7 +837,7 @@ static void u12image_PrepareScaling( U12_Device *dev ) } else { DBG( _DBG_INFO, "u12image_PrepareScaling: DISABLED\n" ); - } + } } /** scaling picture data in x-direction, using a DDA algorithm diff --git a/backend/u12-io.c b/backend/u12-io.c index cd65b72..3c5bcb8 100644 --- a/backend/u12-io.c +++ b/backend/u12-io.c @@ -182,7 +182,7 @@ gl640WriteControl(int fd, GL640_Request req, u_char * data, unsigned int size) /* ind */ 0, /* len */ size, /* dat */ data); - + if( status != SANE_STATUS_GOOD ) { DBG( _DBG_ERROR, "gl640WriteControl error\n"); } @@ -507,7 +507,7 @@ static SANE_Status u12io_DataToRegs( U12_Device *dev, SANE_Byte *buf, int len ) return SANE_STATUS_GOOD; } -/** write data to the DAC +/** write data to the DAC */ static void u12io_DataRegisterToDAC( U12_Device *dev, SANE_Byte reg, SANE_Byte val ) @@ -619,7 +619,7 @@ static SANE_Bool u12io_IsConnected( U12_Device *dev ) dev->mode = mode ; } return SANE_FALSE; - } + } u12io_SwitchToEPPMode( dev ); DBG( _DBG_INFO, "* Scanner is connected!\n" ); @@ -693,7 +693,7 @@ static SANE_Status u12io_DownloadScanStates( U12_Device *dev ) dev->scanStates, _SCANSTATE_BYTES )); bulk_setup_data[1] = 0x11; -/* FIXME: refreshState probably always FALSE */ +/* FIXME: refreshState probably always FALSE */ if( dev->scan.refreshState ) { u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE ); @@ -724,7 +724,7 @@ static void u12io_PutOnAllRegisters( U12_Device *dev ) c = 0; rb = buf; - + *(rb++) = REG_MODECONTROL; *(rb++) = dev->regs.RD_ModeControl; c++; @@ -780,7 +780,7 @@ static u_long u12io_GetFifoLength( U12_Device *dev ) DBG( _DBG_READ, "Using cached FIFO len\n" ); memcpy( data, cacheLen, 13 ); u12io_ResetFifoLen(); - + } else { memset( bulk_setup_data, 0, 8 ); diff --git a/backend/u12-motor.c b/backend/u12-motor.c index c3d5120..5f28236 100644 --- a/backend/u12-motor.c +++ b/backend/u12-motor.c @@ -91,7 +91,7 @@ static void u12motor_Force16Steps( U12_Device *dev, int dir ) static void u12motor_ModuleFreeRun( U12_Device *dev, u_long steps ) { SANE_Byte rb[6]; - + rb[0] = REG_MOTORFREERUNCOUNT1; rb[1] = _HIBYTE(steps); rb[2] = REG_MOTORFREERUNCOUNT0; rb[3] = _LOBYTE(steps); rb[4] = REG_MOTORFREERUNTRIGGER; rb[5] = 0; @@ -124,7 +124,7 @@ static SANE_Status u12motor_PositionYProc( U12_Device *dev, u_long steps ) if( u12io_IsEscPressed()) { DBG( _DBG_INFO, "* CANCEL detected!\n" ); return SANE_STATUS_CANCELLED; - } + } } while( !u12io_CheckTimer( &timer )); DBG( _DBG_INFO, "u12motor_PositionYProc() - done\n" ); @@ -289,7 +289,7 @@ static SANE_Status u12motor_ModuleToHome( U12_Device *dev ) res = u12motor_PositionYProc( dev, 40 ); if( SANE_STATUS_GOOD != res ) return res; - + res = u12motor_BackToHomeSensor( dev ); if( SANE_STATUS_GOOD != res ) return res; @@ -382,7 +382,7 @@ static SANE_Status u12motor_WaitForPositionY( U12_Device *dev ) while(( u12io_GetExtendedStatus( dev ) & _STILL_FREE_RUNNING) && !u12io_CheckTimer(&timer)); - u12io_DataToRegister( dev, REG_MODECONTROL, _ModeScan ); + u12io_DataToRegister( dev, REG_MODECONTROL, _ModeScan ); } else { u12motor_PositionYProc( dev, dwBeginY ); u12io_RegisterToScanner( dev, REG_REFRESHSCANSTATE ); @@ -425,7 +425,7 @@ static SANE_Status u12motor_GotoShadingPosition( U12_Device *dev ) SANE_Byte rb[20]; SANE_Status res; int c; - + DBG( _DBG_INFO, "u12motor_GotoShadingPosition()\n" ); res = u12motor_ModuleToHome( dev ); if( SANE_STATUS_GOOD == res ) diff --git a/backend/u12-scanner.h b/backend/u12-scanner.h index be0c200..c2e9cc8 100644 --- a/backend/u12-scanner.h +++ b/backend/u12-scanner.h @@ -61,7 +61,7 @@ typedef double TimerDef; #define _DODELAY(msecs) u12io_udelay(1000*msecs) /*{ int i; for( i = msecs; i--; ) _DO_UDELAY(1000); }*/ #else -#define _DODELAY(msecs) +#define _DODELAY(msecs) #endif /* ModuleStates */ diff --git a/backend/u12-shading.c b/backend/u12-shading.c index e31c7ee..76cc690 100644 --- a/backend/u12-shading.c +++ b/backend/u12-shading.c @@ -795,7 +795,7 @@ static SANE_Status u12shading_DoCalibration( U12_Device *dev ) SANE_Byte bScanControl, rb[20]; SANE_Status res; int c; - + DBG( _DBG_INFO, "u12shading_DoCalibration()\n" ); /** before getting the shading data, (re)init the ASIC @@ -847,7 +847,7 @@ static SANE_Status u12shading_DoCalibration( U12_Device *dev ) res = u12shading_AdjustRGBGain( dev ); if( SANE_STATUS_GOOD != res ) return res; - + res = u12shadingAdjustDark( dev ); if( SANE_STATUS_GOOD != res ) return res; diff --git a/backend/u12.c b/backend/u12.c index 083d9f3..57e1f63 100644 --- a/backend/u12.c +++ b/backend/u12.c @@ -161,9 +161,9 @@ static const SANE_String_Const src_list[] = static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 1 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(-100), /* minimum */ + SANE_FIX( 100), /* maximum */ + SANE_FIX( 1) /* quantization */ }; /* authorization stuff */ @@ -307,7 +307,7 @@ static int reader_process( void *args ) struct SIGACTION act; sigset_t ignore_set; SANE_Status status; - + U12_Scanner *scanner = (U12_Scanner *)args; if( sanei_thread_is_forked()) { @@ -348,11 +348,11 @@ static int reader_process( void *args ) DBG( _DBG_FATAL, "NULL Pointer !!!!\n" ); return SANE_STATUS_IO_ERROR; } - + /* here we read all data from the scanner... */ buf = scanner->buf; status = u12if_prepare( scanner->hw ); - + if( SANE_STATUS_GOOD == status ) { for( line = 0; line < scanner->params.lines; line++ ) { @@ -393,7 +393,7 @@ static SANE_Status do_cancel( U12_Scanner *scanner, SANE_Bool closepipe ) if( sanei_thread_is_valid (scanner->reader_pid) ) { - DBG( _DBG_PROC, ">>>>>>>> killing reader_process <<<<<<<<\n" ); + DBG( _DBG_PROC, "---- killing reader_process ----\n" ); cancelRead = SANE_TRUE; @@ -413,7 +413,7 @@ static SANE_Status do_cancel( U12_Scanner *scanner, SANE_Bool closepipe ) if( res != scanner->reader_pid ) { DBG( _DBG_PROC,"sanei_thread_waitpid() failed !\n"); - + /* do it the hard way...*/ #ifdef USE_PTHREAD sanei_thread_kill( scanner->reader_pid ); @@ -421,7 +421,7 @@ static SANE_Status do_cancel( U12_Scanner *scanner, SANE_Bool closepipe ) sanei_thread_sendsig( scanner->reader_pid, SIGKILL ); #endif } - scanner->reader_pid = -1; + sanei_thread_invalidate( scanner->reader_pid ); DBG( _DBG_PROC, "reader_process killed\n"); if( scanner->hw->fd >= 0 ) { @@ -589,12 +589,12 @@ static SANE_Status init_options( U12_Scanner *s ) s->val[OPT_BR_Y].w = SANE_FIX(_DEFAULT_BRY); /* "Enhancement" group: */ - s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement"); + s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N("Enhancement"); s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; s->opt[OPT_ENHANCEMENT_GROUP].cap = 0; s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - + u12map_InitGammaSettings( s->hw ); /* grayscale gamma vector */ @@ -641,7 +641,7 @@ static SANE_Status init_options( U12_Scanner *s ) s->opt[OPT_GAMMA_VECTOR_B].constraint.range = &(s->hw->gamma_range); s->opt[OPT_GAMMA_VECTOR_B].size = s->hw->gamma_length * sizeof(SANE_Word); - /* GAMMA stuff is disabled per default */ + /* GAMMA stuff is disabled per default */ s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; @@ -661,8 +661,8 @@ static SANE_Status init_options( U12_Scanner *s ) * @param dest - pointer to a string to receive the USB ID */ static void decodeUsbIDs( char *src, char **dest ) -{ - const char *name; +{ + const char *name; char *tmp = *dest; int len = strlen(_SECTION); @@ -677,11 +677,11 @@ static void decodeUsbIDs( char *src, char **dest ) if( '\0' == name[0] ) { DBG( _DBG_SANE_INIT, "next device uses autodetection\n" ); } else { - + u_short pi = 0, vi = 0; if( *name ) { - + name = sanei_config_get_string( name, &tmp ); if( tmp ) { vi = strtol( tmp, 0, 0 ); @@ -691,7 +691,7 @@ static void decodeUsbIDs( char *src, char **dest ) name = sanei_config_skip_whitespace( name ); if( *name ) { - + name = sanei_config_get_string( name, &tmp ); if( tmp ) { pi = strtol( tmp, 0, 0 ); @@ -733,14 +733,14 @@ static SANE_Bool decodeVal( char *src, char *opt, /* on success, compare wiht the given one */ if( 0 == strcmp( tmp, opt )) { - + DBG( _DBG_SANE_INIT, "Decoding option >%s<\n", opt ); if( _INT == what ) { - + /* assign the default value for this option... */ *((int*)result) = *((int*)def); - + if( *name ) { /* get the configuration value and decode it */ @@ -751,14 +751,14 @@ static SANE_Bool decodeVal( char *src, char *opt, free( tmp2 ); } } - free( tmp ); + free( tmp ); return SANE_TRUE; - + } else if( _FLOAT == what ) { - + /* assign the default value for this option... */ *((double*)result) = *((double*)def); - + if( *name ) { /* get the configuration value and decode it */ @@ -769,13 +769,13 @@ static SANE_Bool decodeVal( char *src, char *opt, free( tmp2 ); } } - free( tmp ); + free( tmp ); return SANE_TRUE; } - } + } free( tmp ); } - + return SANE_FALSE; } @@ -788,27 +788,27 @@ static SANE_Bool decodeVal( char *src, char *opt, */ static SANE_Bool decodeDevName( char *src, char *dest ) { - char *tmp; + char *tmp; const char *name; if( 0 == strncmp( "device", src, 6 )) { name = (const char*)&src[strlen("device")]; name = sanei_config_skip_whitespace( name ); - + DBG( _DBG_SANE_INIT, "Decoding device name >%s<\n", name ); - + if( *name ) { name = sanei_config_get_string( name, &tmp ); if( tmp ) { - + strcpy( dest, tmp ); free( tmp ); return SANE_TRUE; } - } + } } - + return SANE_FALSE; } @@ -842,7 +842,7 @@ static SANE_Status attach( const char *dev_name, /* assign all the stuff we need fo this device... */ memset(dev, 0, sizeof (*dev)); - + dev->fd = -1; dev->name = strdup(dev_name); /* hold it double to avoid */ dev->sane.name = dev->name; /* compiler warnings */ @@ -855,7 +855,7 @@ static SANE_Status attach( const char *dev_name, show_cnf( cnf ); strncpy( dev->usbId, cnf->usbId, _MAX_ID_LEN ); - + /* go ahead and open the scanner device */ handle = u12if_open( dev ); if( handle < 0 ) { @@ -939,7 +939,7 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) first_handle = NULL; num_devices = 0; - /* initialize the configuration structure */ + /* initialize the configuration structure */ init_config_struct( &config ); if( version_code != NULL ) @@ -953,26 +953,26 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) } while( sanei_config_read( str, sizeof(str), fp)) { - + DBG( _DBG_SANE_INIT, ">%s<\n", str ); if( str[0] == '#') /* ignore line comments */ continue; - + len = strlen(str); if( 0 == len ) continue; /* ignore empty lines */ /* check for options */ if( 0 == strncmp(str, "option", 6)) { - + int ival; double dval; - + ival = -1; decodeVal( str, "warmup", _INT, &config.adj.warmup, &ival); decodeVal( str, "lampOff", _INT, &config.adj.lampOff, &ival); decodeVal( str, "lOffOnEnd", _INT, &config.adj.lampOffOnEnd,&ival); - + ival = 0; dval = 1.5; @@ -984,9 +984,9 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) /* check for sections: */ } else if( 0 == strncmp( str, _SECTION, strlen(_SECTION))) { - + char *tmp; - + /* new section, try and attach previous device */ if( config.devName[0] != '\0' ) { attach( config.devName, &config, 0 ); @@ -996,20 +996,20 @@ SANE_Status sane_init( SANE_Int *version_code, SANE_Auth_Callback authorize ) " ignored!\n" ); } } - + /* re-initialize the configuration structure */ init_config_struct( &config ); - + tmp = config.usbId; decodeUsbIDs( str, &tmp ); - + DBG( _DBG_SANE_INIT, "... next device\n" ); - continue; + continue; } else if( SANE_TRUE == decodeDevName( str, config.devName )) { continue; } - + /* ignore other stuff... */ DBG( _DBG_SANE_INIT, "ignoring >%s<\n", str ); } @@ -1107,7 +1107,7 @@ SANE_Status sane_open( SANE_String_Const devicename, SANE_Handle* handle ) if( !dev ) { memset( &config, 0, sizeof(CnfDef)); - + status = attach( devicename, &config, &dev ); if( SANE_STATUS_GOOD != status ) return status; @@ -1137,7 +1137,7 @@ SANE_Status sane_open( SANE_String_Const devicename, SANE_Handle* handle ) first_handle = s; *handle = s; - + return SANE_STATUS_GOOD; } @@ -1201,7 +1201,7 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, int idx; #endif int scanmode; - + if ( s->scanning ) return SANE_STATUS_DEVICE_BUSY; @@ -1306,7 +1306,7 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, if( NULL != info ) *info |= SANE_INFO_RELOAD_PARAMS; break; - + case OPT_CUSTOM_GAMMA: s->val[option].w = *(SANE_Word *)value; if( NULL != info ) @@ -1325,26 +1325,26 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; if( SANE_TRUE == s->val[option].w ) { - + if( scanmode == COLOR_256GRAY ) { s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; } else { s->opt[OPT_GAMMA_VECTOR_R].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap &= ~SANE_CAP_INACTIVE; - } - + } + } else { - + u12map_InitGammaSettings( s->hw ); - + if( scanmode == COLOR_256GRAY ) { s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; - } else { + } else { s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; - } + } } break; @@ -1355,26 +1355,26 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, break; #ifdef ALL_MODES - case OPT_MODE: + case OPT_MODE: idx = (optval - mode_list); mp = getModeList( s ); - + s->opt[OPT_CONTRAST].cap &= ~SANE_CAP_INACTIVE; s->opt[OPT_CUSTOM_GAMMA].cap &= ~SANE_CAP_INACTIVE; if( mp[idx].scanmode == COLOR_BW ) { s->opt[OPT_CONTRAST].cap |= SANE_CAP_INACTIVE; s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; - } - + } + s->opt[OPT_GAMMA_VECTOR].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_R].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_G].cap |= SANE_CAP_INACTIVE; s->opt[OPT_GAMMA_VECTOR_B].cap |= SANE_CAP_INACTIVE; - + if( s->val[OPT_CUSTOM_GAMMA].w && !(s->opt[OPT_CUSTOM_GAMMA].cap & SANE_CAP_INACTIVE)) { - + if( mp[idx].scanmode == COLOR_256GRAY ) { s->opt[OPT_GAMMA_VECTOR].cap &= ~SANE_CAP_INACTIVE; } else { @@ -1595,7 +1595,7 @@ SANE_Status sane_start( SANE_Handle handle ) u12if_close( dev ); return SANE_STATUS_IO_ERROR; } - + /* All ready to go. Set image def and see what the scanner * says for crop info. */ @@ -1728,9 +1728,9 @@ SANE_Status sane_start( SANE_Handle handle ) s->r_pipe = fds[0]; s->w_pipe = fds[1]; s->reader_pid = sanei_thread_begin( reader_process, s ); - + cancelRead = SANE_FALSE; - + if( !sanei_thread_is_valid (s->reader_pid) ) { DBG( _DBG_ERROR, "ERROR: could not start reader task\n" ); s->scanning = SANE_FALSE; @@ -1743,7 +1743,7 @@ SANE_Status sane_start( SANE_Handle handle ) close( s->w_pipe ); s->w_pipe = -1; } - + DBG( _DBG_SANE_INIT, "sane_start done\n" ); return SANE_STATUS_GOOD; } @@ -1773,7 +1773,7 @@ SANE_Status sane_read( SANE_Handle handle, SANE_Byte *data, if( s->bytes_read == (unsigned long)(s->params.lines * s->params.bytes_per_line)) { sanei_thread_waitpid( s->reader_pid, 0 ); - s->reader_pid = -1; + sanei_thread_invalidate( s->reader_pid ); drvClose( s->hw ); return drvClosePipes(s); } @@ -1801,7 +1801,7 @@ SANE_Status sane_read( SANE_Handle handle, SANE_Byte *data, drvClosePipes(s); return s->exit_code; } - s->reader_pid = -1; + sanei_thread_invalidate( s->reader_pid ); return drvClosePipes(s); } @@ -1837,9 +1837,9 @@ SANE_Status sane_set_io_mode( SANE_Handle handle, SANE_Bool non_blocking ) DBG( _DBG_ERROR, "ERROR: not supported !\n" ); return SANE_STATUS_UNSUPPORTED; } - + if( fcntl (s->r_pipe, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) { - DBG( _DBG_ERROR, "ERROR: can´t set to non-blocking mode !\n" ); + DBG( _DBG_ERROR, "ERROR: can´t set to non-blocking mode !\n" ); return SANE_STATUS_IO_ERROR; } diff --git a/backend/u12.conf.in b/backend/u12.conf.in index c5457cb..baeea79 100644 --- a/backend/u12.conf.in +++ b/backend/u12.conf.in @@ -63,5 +63,5 @@ device auto # # to define a new device, start with a new section: -# [usb] +# [usb] # diff --git a/backend/u12.h b/backend/u12.h index 5d18c96..41b19b9 100644 --- a/backend/u12.h +++ b/backend/u12.h @@ -72,7 +72,7 @@ typedef union #define _MEASURE_BASE 300UL #define _DEF_DPI 50 -/** the default image +/** the default image */ #define _DEFAULT_TLX 0 #define _DEFAULT_TLY 0 @@ -184,7 +184,7 @@ typedef struct { double graygamma; /* for adjusting scan-area */ - long upNormal; + long upNormal; long upPositive; long upNegative; long leftNormal; @@ -240,7 +240,7 @@ typedef struct u12d SANE_Int res_list_size; /* resolution values */ ScannerCaps caps; /* caps reported by the driver */ AdjDef adj; /* for driver adjustment */ - + char usbId[_MAX_ID_LEN];/* to keep Vendor and product */ /* ID string (from conf) file */ /* our gamma tables */ @@ -322,7 +322,7 @@ typedef struct u12s /** for collecting configuration info... */ typedef struct { - + char devName[PATH_MAX]; char usbId[_MAX_ID_LEN]; diff --git a/backend/umax-scanner.c b/backend/umax-scanner.c index 21f24ce..03bca0e 100644 --- a/backend/umax-scanner.c +++ b/backend/umax-scanner.c @@ -1,7 +1,7 @@ /* -------------------------------------------------------------------- */ /* umax-scanner.c: scanner-definiton file for UMAX scanner driver. - + (C) 1997-2004 Oliver Rauch This program is free software; you can redistribute it and/or @@ -39,7 +39,7 @@ 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. - + */ /* -------------------------------------------------------------------- */ @@ -95,9 +95,9 @@ static char *scanner_str[] = "UMAX ", "Astra 600S ", "UMAX ", "Astra 610S ", "UMAX ", "Astra 1200S ", - "UMAX ", "Astra 1220S ", - "UMAX ", "Astra 2100S ", - "UMAX ", "Astra 2200 ", + "UMAX ", "Astra 1220S ", + "UMAX ", "Astra 2100S ", + "UMAX ", "Astra 2200 ", "UMAX ", "Astra 2400S ", /* "UMAX ", "Astra 6400 ", */ /* this is a firewire scanner */ /* "UMAX ", "Astra 6450 ", */ /* this is a firewire scanner */ @@ -124,8 +124,8 @@ static char *scanner_str[] = "HDM ", "LS4H1S ", /* Linoscan 1400 */ "Nikon ", "AX-110 ", /* is a Vista S6E */ "Nikon ", "AX-210 ", /* is a Supervista S12 */ - "KYE ", "ColorPage-HR5 ", - "EPSON ", "Perfection600 ", + "KYE ", "ColorPage-HR5 ", + "EPSON ", "Perfection600 ", "ESCORT ", "Galleria 600S ", /* is an Astra 600S */ "EDGE ", "KTX-9600US ", /* may be an Astra 1220S */ "TriGem ", "PowerScanII ", /* is a Supervista S12 */ @@ -133,4 +133,3 @@ static char *scanner_str[] = }; /* ==================================================================== */ - diff --git a/backend/umax-scanner.h b/backend/umax-scanner.h index 6c9a93a..da10b7b 100644 --- a/backend/umax-scanner.h +++ b/backend/umax-scanner.h @@ -1,7 +1,7 @@ /* -------------------------------------------------------------------- */ /* umax-scanner.h: scanner-definiton header-file for UMAX scanner driver. - + (C) 1997-2002 Oliver Rauch This program is free software; you can redistribute it and/or @@ -39,7 +39,7 @@ 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. - + */ /* -------------------------------------------------------------------- */ @@ -58,4 +58,3 @@ typedef struct } inquiry_blk; #endif - diff --git a/backend/umax-scsidef.h b/backend/umax-scsidef.h index f192e2c..ddb04bb 100644 --- a/backend/umax-scsidef.h +++ b/backend/umax-scsidef.h @@ -287,9 +287,9 @@ static scsiblk inquiry = { inquiryC, sizeof(inquiryC) }; #define get_inquiry_0x65(in) in[0x65] #define get_inquiry_gib(in) in[0x66] -#define get_inquiry_gib_8bpp(in) getbitfield(in + 0x66, 1, 0) +#define get_inquiry_gib_8bpp(in) getbitfield(in + 0x66, 1, 0) #define get_inquiry_gib_9bpp(in) getbitfield(in + 0x66, 1, 1) -#define get_inquiry_gib_10bpp(in) getbitfield(in + 0x66, 1, 2) +#define get_inquiry_gib_10bpp(in) getbitfield(in + 0x66, 1, 2) #define get_inquiry_gib_12bpp(in) getbitfield(in + 0x66, 1, 3) #define get_inquiry_gib_14bpp(in) getbitfield(in + 0x66, 1, 4) #define get_inquiry_gib_16bpp(in) getbitfield(in + 0x66, 1, 5) @@ -301,9 +301,9 @@ static scsiblk inquiry = { inquiryC, sizeof(inquiryC) }; #define get_inquiry_0x67(in) in[0x67] #define get_inquiry_gob(in) in[0x68] -#define get_inquiry_gob_8bpp(in) getbitfield(in + 0x68, 1, 0) +#define get_inquiry_gob_8bpp(in) getbitfield(in + 0x68, 1, 0) #define get_inquiry_gob_9bpp(in) getbitfield(in + 0x68, 1, 1) -#define get_inquiry_gob_10bpp(in) getbitfield(in + 0x68, 1, 2) +#define get_inquiry_gob_10bpp(in) getbitfield(in + 0x68, 1, 2) #define get_inquiry_gob_12bpp(in) getbitfield(in + 0x68, 1, 3) #define get_inquiry_gob_14bpp(in) getbitfield(in + 0x68, 1, 4) #define get_inquiry_gob_16bpp(in) getbitfield(in + 0x68, 1, 5) @@ -653,7 +653,7 @@ static unsigned char window_descriptor_blockC[] = # define WD_calibration_lineart 0x0f # define WD_calibration_dither 0x0e # define WD_calibration_gray 0x0d -# define WD_calibration_rgb 0x0a +# define WD_calibration_rgb 0x0a # define WD_calibration_ignore 0x09 /* 0x3a */ 0x01, /* Color Sequence, Color Ordering Support */ @@ -722,7 +722,7 @@ static scsiblk window_descriptor_block = { window_descriptor_blockC, sizeof(wind /* --------------------------------------------------------------------------------------------------------- */ - + #define set_WDB_length(length) (window_descriptor_block.size = (length)) #define WPDB_OFF(b) (b + set_window.size) @@ -744,7 +744,7 @@ static scsiblk scan = { scanC, sizeof(scanC) - 3 }; #define set_SC_quality(sb, val) setbitfield(sb + 0x05, 1, 5, val) #define set_SC_adf(sb, val) setbitfield(sb + 0x05, 1, 6, val) #define set_SC_preview(sb, val) setbitfield(sb + 0x05, 1, 7, val) -#define set_SC_wid(sb, n, val) sb[0x05 + n] = val +#define set_SC_wid(sb, n, val) sb[0x05 + n] = val /* --------------------------------------------------------------------------------------------------------- */ @@ -907,12 +907,12 @@ static scsiblk request_sense = { request_senseC, sizeof(request_senseC) }; #define get_RS_filemark(b) getbitfield(b + 0x02, 1, 7) #define get_RS_EOM(b) getbitfield(b + 0x02, 1, 6) #define get_RS_ILI(b) getbitfield(b + 0x02, 1, 5) -#define get_RS_sense_key(b) getbitfield(b + 0x02, 0x0f, 0) -#define get_RS_information(b) getnbyte(b+0x03, 4) +#define get_RS_sense_key(b) getbitfield(b + 0x02, 0x0f, 0) +#define get_RS_information(b) getnbyte(b+0x03, 4) #define get_RS_additional_length(b) b[0x07] #define get_RS_ASC(b) b[0x0c] #define get_RS_ASCQ(b) b[0x0d] -#define get_RS_SKSV(b) getbitfield(b+0x0f,1,7) /* valid */ +#define get_RS_SKSV(b) getbitfield(b+0x0f,1,7) /* valid */ #define get_RS_CD(b) getbitfield(b+0x0f,1,6) /* 1=CDB */ #define get_RS_field_pointer(b) getnbyte(b+0x10, 2) diff --git a/backend/umax-uc1200s.c b/backend/umax-uc1200s.c index 97e5416..5569a2b 100644 --- a/backend/umax-uc1200s.c +++ b/backend/umax-uc1200s.c @@ -2,7 +2,7 @@ /* ------------------------------------------------------------------------- */ /* umax-uc1200s.c: inquiry for UMAX scanner uc1200s - + (C) 1997-2002 Oliver Rauch This program is free software; you can redistribute it and/or @@ -59,13 +59,13 @@ static unsigned char UC1200S_INQUIRY[] = /* 28 - 29 reserved */ 0x00, 0x00, -/* 2a - 35 exposure times */ +/* 2a - 35 exposure times */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 - 37 reserved */ +/* 36 - 37 reserved */ 0x00, 0x00, /* 38 - 5f scsi reserved */ @@ -78,7 +78,7 @@ static unsigned char UC1200S_INQUIRY[] = /* 60 -62 scanner capability*/ 0x2f, 0x0c, - 0x07, + 0x07, /* 63 reserved */ 0x00, @@ -151,7 +151,7 @@ static unsigned char UC1200S_INQUIRY[] = /* 8a-8b dor max scan width in 0.01 inch */ 0x00, 0x00, - + /* 8c-8d dor max scan length in 0.01 inch */ 0x00, 0x00, diff --git a/backend/umax-uc1200se.c b/backend/umax-uc1200se.c index defe65a..f1e8e31 100644 --- a/backend/umax-uc1200se.c +++ b/backend/umax-uc1200se.c @@ -2,7 +2,7 @@ /* ------------------------------------------------------------------------- */ /* umax-uc1200se.c: inquiry for UMAX scanner uc1200se - + (C) 1998-2002 Oliver Rauch This program is free software; you can redistribute it and/or @@ -59,13 +59,13 @@ static unsigned char UC1200SE_INQUIRY[] = /* 28 - 29 reserved */ 0x00, 0x00, -/* 2a - 35 exposure times */ +/* 2a - 35 exposure times */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 - 37 reserved */ +/* 36 - 37 reserved */ 0x00, 0x00, /* 38 - 5f scsi reserved */ @@ -78,7 +78,7 @@ static unsigned char UC1200SE_INQUIRY[] = /* 60 -62 scanner capability*/ 0x3e, 0x0c, - 0x03, + 0x03, /* 63 reserved */ 0x00, @@ -151,7 +151,7 @@ static unsigned char UC1200SE_INQUIRY[] = /* 8a-8b dor max scan width in 0.01 inch */ 0x00, 0x00, - + /* 8c-8d dor max scan length in 0.01 inch */ 0x00, 0x00, diff --git a/backend/umax-uc1260.c b/backend/umax-uc1260.c index 7743cd4..4de9170 100644 --- a/backend/umax-uc1260.c +++ b/backend/umax-uc1260.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ /* umax-uc1260.c: inquiry for UMAX scanner uc1260 - + (C) 1997-2002 Oliver Rauch This program is free software; you can redistribute it and/or @@ -58,13 +58,13 @@ static unsigned char UC1260_INQUIRY[] = /* 28 - 29 reserved */ 0x00, 0x00, -/* 2a - 35 exposure times */ +/* 2a - 35 exposure times */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 - 37 reserved */ +/* 36 - 37 reserved */ 0x00, 0x00, /* 38 - 5f scsi reserved */ @@ -75,9 +75,9 @@ static unsigned char UC1260_INQUIRY[] = 00, 00, 00, 00, 00, 00, 00, 00, /* 60 -62 scanner capability*/ - 0x31, + 0x31, 0x0c, - 0x07, + 0x07, /* 63 reserved */ 0x00, @@ -151,7 +151,7 @@ static unsigned char UC1260_INQUIRY[] = /* 8a-8b dor max scan width in 0.01 inch */ 0x00, 0x00, - + /* 8c-8d dor max scan length in 0.01 inch */ 0x00, 0x00, diff --git a/backend/umax-uc630.c b/backend/umax-uc630.c index 0fbc59f..440064c 100644 --- a/backend/umax-uc630.c +++ b/backend/umax-uc630.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ /* umax-uc630.c: inquiry for UMAX scanner uc630 - + (C) 1997-2002 Oliver Rauch This program is free software; you can redistribute it and/or @@ -58,13 +58,13 @@ static unsigned char UC630_INQUIRY[] = /* 28 - 29 reserved */ 0x00, 0x00, -/* 2a - 35 exposure times */ +/* 2a - 35 exposure times */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 - 37 reserved */ +/* 36 - 37 reserved */ 0x00, 0x00, /* 38 - 5f scsi reserved */ @@ -77,7 +77,7 @@ static unsigned char UC630_INQUIRY[] = /* 60 -62 scanner capability */ 0xfd, 0x80, - 0x03, + 0x03, /* 63 reserved */ 0x00, @@ -150,7 +150,7 @@ static unsigned char UC630_INQUIRY[] = /* 8a-8b dor max scan width in 0.01 inch */ 0x00, 0x00, - + /* 8c-8d dor max scan length in 0.01 inch */ 0x00, 0x00, @@ -192,4 +192,3 @@ static inquiry_blk inquiry_uc630 = { "UC630 ", UC630_INQUIRY, UC630_INQUIRY_LEN }; - diff --git a/backend/umax-uc840.c b/backend/umax-uc840.c index 8f430fe..0592c95 100644 --- a/backend/umax-uc840.c +++ b/backend/umax-uc840.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ /* umax-uc840.c: inquiry for UMAX scanner uc840 - + (C) 1997-2002 Oliver Rauch This program is free software; you can redistribute it and/or @@ -58,13 +58,13 @@ static unsigned char UC840_INQUIRY[] = /* 28 - 29 reserved */ 0x00, 0x00, -/* 2a - 35 exposure times */ +/* 2a - 35 exposure times */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 - 37 reserved */ +/* 36 - 37 reserved */ 0x00, 0x00, /* 38 - 5f scsi reserved */ @@ -77,13 +77,13 @@ static unsigned char UC840_INQUIRY[] = /* 60 -62 scanner capability*/ 0xfd, 0x8c, /* 0xbc ? */ - 0x03, + 0x03, /* 63 reserved */ 0x00, /* 64 gamma */ - 0xa1, + 0xa1, /* 65 reserved */ 0x00, @@ -150,7 +150,7 @@ static unsigned char UC840_INQUIRY[] = /* 8a-8b dor max scan width in 0.01 inch */ 0x00, 0x00, - + /* 8c-8d dor max scan length in 0.01 inch */ 0x00, 0x00, @@ -192,4 +192,3 @@ static inquiry_blk inquiry_uc840 = { "UC840 ", UC840_INQUIRY, UC840_INQUIRY_LEN }; - diff --git a/backend/umax-ug630.c b/backend/umax-ug630.c index 0a584b2..3a339fc 100644 --- a/backend/umax-ug630.c +++ b/backend/umax-ug630.c @@ -1,7 +1,7 @@ /* ------------------------------------------------------------------------- */ /* umax-ug630.c: inquiry for UMAX scanner ug630 - + (C) 1997-2002 Oliver Rauch This program is free software; you can redistribute it and/or @@ -58,13 +58,13 @@ static unsigned char UG630_INQUIRY[] = /* 28 - 29 reserved */ 0x00, 0x00, -/* 2a - 35 exposure times */ +/* 2a - 35 exposure times */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 - 37 reserved */ +/* 36 - 37 reserved */ 0x00, 0x00, /* 38 - 5f scsi reserved */ @@ -150,7 +150,7 @@ static unsigned char UG630_INQUIRY[] = /* 8a-8b dor max scan width in 0.01 inch */ 0x00, 0x00, - + /* 8c-8d dor max scan length in 0.01 inch */ 0x00, 0x00, @@ -192,4 +192,3 @@ static inquiry_blk inquiry_ug630 = { "UG630 ", UG630_INQUIRY, UG630_INQUIRY_LEN }; - diff --git a/backend/umax-ug80.c b/backend/umax-ug80.c index b9d1d42..2e31d61 100644 --- a/backend/umax-ug80.c +++ b/backend/umax-ug80.c @@ -1,9 +1,9 @@ /* ------------------------------------------------------------------------- */ /* umax-ug80.c: inquiry for UMAX scanner ug80 - + (C) 1998-2002 Oliver Rauch - + Thanks to Andreas Hofmeister for his help! @@ -61,13 +61,13 @@ static unsigned char UG80_INQUIRY[] = /* 28 - 29 reserved */ 0x00, 0x00, -/* 2a - 35 exposure times */ +/* 2a - 35 exposure times */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -/* 36 - 37 reserved */ +/* 36 - 37 reserved */ 0x00, 0x00, /* 38 - 5f scsi reserved */ @@ -153,7 +153,7 @@ static unsigned char UG80_INQUIRY[] = /* 8a-8b dor max scan width in 0.01 inch */ 0x00, 0x00, - + /* 8c-8d dor max scan length in 0.01 inch */ 0x00, 0x00, @@ -195,4 +195,3 @@ static inquiry_blk inquiry_ug80 = { "UG80 ",UG80_INQUIRY,UG80_INQUIRY_LEN, }; - diff --git a/backend/umax-usb.c b/backend/umax-usb.c index c26aeae..75f4739 100644 --- a/backend/umax-usb.c +++ b/backend/umax-usb.c @@ -2,7 +2,7 @@ /* sane - Scanner Access Now Easy. - umax-usb.c + umax-usb.c (C) 2001-2002 Frank Zago @@ -77,7 +77,7 @@ static u_char cdb_sizes[8] = { /* Sends a CDB to the scanner. Also sends the parameters and receives * the data, if necessary. When this function returns with a - * SANE_STATUS_GOOD, the SCSI command has been completed. + * SANE_STATUS_GOOD, the SCSI command has been completed. * * Note: I don't know about deferred commands. */ @@ -88,7 +88,7 @@ static SANE_Status sanei_umaxusb_cmd(int fd, const void *src, size_t src_size, v size_t param_size = src_size - cmd_size; const char * param_ptr = ((const char *) src) + cmd_size; size_t tmp_len; - + DBG(DBG_info, "Sending SCSI cmd 0x%02x cdb len %ld, param len %ld, result len %ld\n", ((const unsigned char *)src)[0], (long)cmd_size, (long)param_size, dst_size? (long)*dst_size:(long)0); /* This looks like some kind of pre-initialization. */ @@ -100,7 +100,7 @@ static SANE_Status sanei_umaxusb_cmd(int fd, const void *src, size_t src_size, v sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x16); sanei_pv8630_flush_buffer(fd); sanei_pv8630_prep_bulkwrite(fd, cmd_size); - + tmp_len = cmd_size; sanei_pv8630_bulkwrite(fd, src, &tmp_len); sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf8, 0xff, 1000); @@ -118,19 +118,19 @@ static SANE_Status sanei_umaxusb_cmd(int fd, const void *src, size_t src_size, v } return(SANE_STATUS_IO_ERROR); } - + /* Send the parameters and check they've been received OK. */ if (param_size) { sanei_pv8630_flush_buffer(fd); sanei_pv8630_prep_bulkwrite(fd, param_size); - + tmp_len = param_size; sanei_pv8630_bulkwrite(fd, param_ptr, &tmp_len); sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xf8, 0xff, 1000); - + sanei_pv8630_flush_buffer(fd); sanei_pv8630_prep_bulkread(fd, 1); - + result = 0xA5; /* to be sure */ tmp_len = 1; sanei_pv8630_bulkread(fd, &result, &tmp_len); @@ -174,7 +174,7 @@ static SANE_Status sanei_umaxusb_cmd(int fd, const void *src, size_t src_size, v sanei_pv8630_wait_byte(fd, PV8630_RSTATUS, 0xd0, 0xff, 1000); DBG(DBG_info, " SCSI command successfully executed\n"); - + return(SANE_STATUS_GOOD); } @@ -214,12 +214,12 @@ static SANE_Status pv8630_init_umaxusb_scanner(int fd) sanei_pv8630_write_byte(fd, PV8630_RMODE, 0x16); DBG(DBG_info, "PV8630 initialized\n"); - + return(SANE_STATUS_GOOD); } -/* +/* * SCSI functions for the emulation. * * The following functions emulate their sanei_scsi_* counterpart. @@ -227,7 +227,7 @@ static SANE_Status pv8630_init_umaxusb_scanner(int fd) */ -/* +/* * sanei_umaxusb_req_wait() and sanei_umaxusb_req_enter() * * I don't know if it is possible to queue the reads to the @@ -255,7 +255,7 @@ sanei_umaxusb_req_wait (void *id) return(SANE_STATUS_GOOD); } -/* Open the device. +/* Open the device. */ static SANE_Status sanei_umaxusb_open (const char *dev, int *fdp, @@ -290,16 +290,16 @@ sanei_umaxusb_open (const char *dev, int *fdp, *fdp = -1; return SANE_STATUS_UNSUPPORTED; } - - /* It's a good scanner. Initialize it. + + /* It's a good scanner. Initialize it. * * Note: pv8630_init_umaxusb_scanner() is for the UMAX * 2200. Other UMAX scanner might need a different * initialization routine. */ - pv8630_init_umaxusb_scanner(*fdp); + pv8630_init_umaxusb_scanner(*fdp); } - + return(SANE_STATUS_GOOD); } @@ -318,7 +318,3 @@ sanei_umaxusb_close (int fd) { sanei_usb_close(fd); } - - - - diff --git a/backend/umax.c b/backend/umax.c index 22fa2d3..94f8aa4 100644 --- a/backend/umax.c +++ b/backend/umax.c @@ -2,7 +2,7 @@ /* sane - Scanner Access Now Easy. - umax.c + umax.c (C) 1997-2007 Oliver Rauch @@ -106,7 +106,7 @@ in ADF mode this is done often: #ifndef SANE_I18N #define SANE_I18N(text) text -#endif +#endif /* ------------------------------------------------------------ INCLUDES ----------------------------------- */ @@ -275,16 +275,16 @@ static const SANE_Range u8_range = static const SANE_Range percentage_range = { - -100 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 1 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX(-100), /* minimum */ + SANE_FIX( 100), /* maximum */ + SANE_FIX( 1) /* quantization */ }; static const SANE_Range percentage_range_100 = { - 0 << SANE_FIXED_SCALE_SHIFT, /* minimum */ - 100 << SANE_FIXED_SCALE_SHIFT, /* maximum */ - 0 << SANE_FIXED_SCALE_SHIFT /* quantization */ + SANE_FIX( 0), /* minimum */ + SANE_FIX(100), /* maximum */ + SANE_FIX( 0) /* quantization */ }; static int num_devices = 0; @@ -377,7 +377,7 @@ static void umax_print_inquiry(Umax_Device *dev) if (dev->inquiry_len<=0x8e) { DBG(DBG_inquiry, "Inquiry block is unexpected short, should be at least 147 bytes\n"); - } + } DBG(DBG_inquiry,"\n"); DBG(DBG_inquiry,"ISO Version (reserved).......: %d\n", get_inquiry_iso_version(inquiry_block)); @@ -668,7 +668,7 @@ static void umax_print_inquiry(Umax_Device *dev) DBG(DBG_inquiry,"FB maximum scan length....................: %2.2f inch\n", dev->inquiry_fb_length); /* ---------- */ - + /* 0x7a - 0x81 */ if (dev->inquiry_len<=0x81) { @@ -679,9 +679,9 @@ static void umax_print_inquiry(Umax_Device *dev) DBG(DBG_inquiry,"UTA (transparency-mode):\n"); DBG(DBG_inquiry,"UTA x-original point......................: %2.2f inch\n", dev->inquiry_uta_x_off); DBG(DBG_inquiry,"UTA y-original point......................: %2.2f inch\n", dev->inquiry_uta_y_off); - DBG(DBG_inquiry,"UTA maximum scan width....................: %2.2f inch\n", dev->inquiry_uta_width); + DBG(DBG_inquiry,"UTA maximum scan width....................: %2.2f inch\n", dev->inquiry_uta_width); DBG(DBG_inquiry,"UTA maximum scan length...................: %2.2f inch\n", dev->inquiry_uta_length); - + /* ---------- */ /* 0x82-0x85 */ @@ -743,7 +743,7 @@ static void umax_print_inquiry(Umax_Device *dev) } DBG(DBG_inquiry,"lamp warmup maximum time..................: %d sec\n", dev->inquiry_max_warmup_time); - + /* 0x92 0x93 */ if (dev->inquiry_len<=0x93) { @@ -861,7 +861,7 @@ static SANE_Status sense_handler(int scsi_fd, unsigned char *result, void *arg) asc_ascq = (int)(256 * asc + ascq); len = 7 + get_RS_additional_length(result); - if ( get_RS_error_code(result) != 0x70 ) + if ( get_RS_error_code(result) != 0x70 ) { DBG(DBG_error, "invalid sense key error code (%d)\n", get_RS_error_code(result)); @@ -1318,18 +1318,18 @@ static void umax_order_line(Umax_Device *dev, unsigned char *source) { color = dev->CCD_color[1 + ((dev->pixelline_opt_res - CCD_distance) % 2)]; /* color 1,2 */ } - else if (dev->pixelline_opt_res < length * 3 - CCD_distance * 3) + else if (dev->pixelline_opt_res < length * 3 - CCD_distance * 3) { color = dev->CCD_color[3 + (dev->pixelline_opt_res % 3)]; /* color 3,4,5 */ } - else if (dev->pixelline_opt_res < length * 3 - CCD_distance) + else if (dev->pixelline_opt_res < length * 3 - CCD_distance) { color = dev->CCD_color[6 + ((dev->pixelline_opt_res - length*3 + CCD_distance*3) % 2)]; /* color 6,7 */ } - else + else { color = dev->CCD_color[8]; /* color 8 */ - } + } } while(umax_forget_line(dev, color) != 0); /* until found correct line */ umax_order_line_to_pixel(dev, source, color); @@ -1393,7 +1393,7 @@ static SANE_Status umax_scsi_cmd(Umax_Device *dev, const void *src, size_t src_s static SANE_Status umax_scsi_open_extended(const char *devicename, Umax_Device *dev, SANEI_SCSI_Sense_Handler handler, void *handler_arg, int *buffersize) { - switch (dev->connection_type) + switch (dev->connection_type) { case SANE_UMAX_SCSI: return sanei_scsi_open_extended(devicename, &dev->sfd, handler, handler_arg, buffersize); @@ -1449,7 +1449,7 @@ static void umax_scsi_close(Umax_Device *dev) dev->sfd=-1; break; #endif - } + } } /* ------------------------------------------------------------ UMAX SCSI REQ ENTER ------------------------ */ @@ -1583,7 +1583,7 @@ static SANE_Status umax_get_data_buffer_status(Umax_Device *dev) if (status) { DBG(DBG_error, "umax_get_data_buffer_status: command returned status %s\n", sane_strstatus(status)); - } + } return status; } @@ -1599,12 +1599,12 @@ static void umax_do_request_sense(Umax_Device *dev) SANE_Status status; DBG(DBG_proc, "do_request_sense\n"); - set_RS_allocation_length(request_sense.cmd, rs_return_block_size); + set_RS_allocation_length(request_sense.cmd, rs_return_block_size); status = umax_scsi_cmd(dev, request_sense.cmd, request_sense.size, dev->buffer[0], &size); if (status) { DBG(DBG_error, "umax_do_request_sense: command returned status %s\n", sane_strstatus(status)); - } + } } @@ -1663,7 +1663,7 @@ static int umax_grab_scanner(Umax_Device *dev) if (status) { DBG(DBG_error, "umax_grab_scanner: command returned status %s\n", sane_strstatus(status)); - } + } else { DBG(DBG_info, "scanner reserved\n"); @@ -1681,7 +1681,7 @@ static int umax_reposition_scanner(Umax_Device *dev) int status; int pause; - pause = dev->pause_after_reposition + dev->pause_for_moving * (dev->upper_left_y + dev->scanlength) / + pause = dev->pause_after_reposition + dev->pause_for_moving * (dev->upper_left_y + dev->scanlength) / ( (dev->inquiry_fb_length * dev->y_coordinate_base) ); DBG(DBG_info2, "trying to reposition scanner ...\n"); @@ -1724,7 +1724,7 @@ static int umax_give_scanner(Umax_Device *dev) if (status) { DBG(DBG_error, "umax_give_scanner: command returned status %s\n", sane_strstatus(status)); - } + } else { DBG(DBG_info, "scanner released\n"); @@ -1760,7 +1760,7 @@ static void umax_send_gamma_data(Umax_Device *dev, void *gamma_data, int color) DBG(DBG_error, "ERROR: gamma download not available\n"); return; } - + memcpy(dev->buffer[0], send.cmd, send.size); /* send */ set_S_datatype_code(dev->buffer[0], S_datatype_gamma); /* gamma curve */ @@ -1790,7 +1790,7 @@ static void umax_send_gamma_data(Umax_Device *dev, void *gamma_data, int color) if (status) { DBG(DBG_error, "umax_send_gamma_data(DCF=0, one color): command returned status %s\n", sane_strstatus(status)); - } + } } else /* three colors */ { @@ -1816,7 +1816,7 @@ static void umax_send_gamma_data(Umax_Device *dev, void *gamma_data, int color) if (status) { DBG(DBG_error, "umax_send_gamma_data(DCF=0, RGB): command returned status %s\n", sane_strstatus(status)); - } + } } } else if (dev->inquiry_gamma_DCF == 1) /* gamma format type 1 */ @@ -1839,7 +1839,7 @@ static void umax_send_gamma_data(Umax_Device *dev, void *gamma_data, int color) if (status) { DBG(DBG_error, "umax_send_gamma_data(DCF=1): command returned status %s\n", sane_strstatus(status)); - } + } } else if (dev->inquiry_gamma_DCF == 2) /* gamma format type 2 */ { @@ -1904,7 +1904,7 @@ static void umax_send_gamma_data(Umax_Device *dev, void *gamma_data, int color) if (status) { DBG(DBG_error, "umax_send_gamma_data(DCF=2): command returned status %s\n", sane_strstatus(status)); - } + } } else { @@ -1937,7 +1937,7 @@ static void umax_send_data(Umax_Device *dev, void *data, int size, int datatype) if (status) { DBG(DBG_error, "umax_send_data: command returned status %s\n", sane_strstatus(status)); - } + } } @@ -2037,7 +2037,7 @@ static int umax_read_data(Umax_Device *dev, size_t length, int datatype) { DBG(DBG_error, "umax_read_data: command returned status %s\n", sane_strstatus(status)); return -1; - } + } return length; } @@ -2082,7 +2082,7 @@ static int umax_read_image_data(Umax_Device *dev, unsigned int length) static int umax_correct_light(int light, int analog_gamma_byte) /* correct highlight/shadow if analog gamma is set */ -{ +{ double analog_gamma; analog_gamma=analog_gamma_table[analog_gamma_byte]; return( (int) 255 * pow( ((double) light)/255.0 , (1.0/analog_gamma) )+.5 ); @@ -2121,7 +2121,7 @@ static SANE_Status umax_set_window_param(Umax_Device *dev) set_WD_brightness(buffer_r, dev->brightness); /* brightness, only halftone */ set_WD_threshold(buffer_r, dev->threshold); /* threshold, only lineart */ set_WD_contrast(buffer_r, dev->contrast); /* contrast, only halftone */ - + /* scanmode, preset to LINEART */ set_WD_composition(buffer_r, WD_comp_lineart); /* image composition */ /* = (scan-mode) */ @@ -2136,16 +2136,16 @@ static SANE_Status umax_set_window_param(Umax_Device *dev) set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_r, dev->analog_gamma_r)); /* scan options */ - set_WD_gamma(buffer_r, dev->digital_gamma_r); /* set digital gamma */ - set_WD_module(buffer_r, dev->module); /* flatbed or transparency */ - set_WD_CBHS(buffer_r, dev->cbhs_range); /* 50 or 255 */ + set_WD_gamma(buffer_r, dev->digital_gamma_r); /* set digital gamma */ + set_WD_module(buffer_r, dev->module); /* flatbed or transparency */ + set_WD_CBHS(buffer_r, dev->cbhs_range); /* 50 or 255 */ set_WD_FF(buffer_r, dev->fix_focus_position); /* fix focus position */ set_WD_RMIF(buffer_r, dev->reverse_multi); /* reverse color-values */ set_WD_FDC(buffer_r, dev->lens_cal_in_doc_pos); /* lens calibration in document position */ set_WD_PF(buffer_r, dev->disable_pre_focus); /* disable pre focus */ set_WD_LCL(buffer_r, dev->holder_focus_pos_0mm); /* 0.6mm <-> 0.0mm holder focus position */ set_WD_HBT(buffer_r, dev->low_byte_first); /* set byte order for 16 bit scanners */ - set_WD_DOR(buffer_r, dev->dor); /* double-resolution-mode */ + set_WD_DOR(buffer_r, dev->dor); /* double-resolution-mode */ set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_r); /* scan exposure time */ set_WD_calibration_exposure_level(buffer_r, dev->exposure_time_calibration_r);/* calibration exposure time */ @@ -2217,7 +2217,7 @@ static SANE_Status umax_set_window_param(Umax_Device *dev) if (dev->do_color_ordering != 0) { - set_WD_line_arrangement(buffer_r, WD_line_arrengement_by_driver); + set_WD_line_arrangement(buffer_r, WD_line_arrengement_by_driver); if (dev->CCD_distance == 0) { @@ -2248,17 +2248,17 @@ static SANE_Status umax_set_window_param(Umax_Device *dev) set_WD_analog_gamma(buffer_g, dev->analog_gamma_g); set_WD_analog_gamma(buffer_b, dev->analog_gamma_b); - /* set highlight in dependence of analog gamma */ + /* set highlight in dependence of analog gamma */ set_WD_highlight(buffer_r, umax_correct_light(dev->highlight_r, dev->analog_gamma_r)); set_WD_highlight(buffer_g, umax_correct_light(dev->highlight_g, dev->analog_gamma_g)); set_WD_highlight(buffer_b, umax_correct_light(dev->highlight_b, dev->analog_gamma_b)); - /* set shadow in dependence of analog gamma */ + /* set shadow in dependence of analog gamma */ set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_r, dev->analog_gamma_r)); set_WD_shadow(buffer_g, umax_correct_light(dev->shadow_g, dev->analog_gamma_g)); set_WD_shadow(buffer_b, umax_correct_light(dev->shadow_b, dev->analog_gamma_b)); - set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_r); /* set scan exposure times */ + set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_r); /* set scan exposure times */ set_WD_scan_exposure_level(buffer_g, dev->exposure_time_scan_g); set_WD_scan_exposure_level(buffer_b, dev->exposure_time_scan_b); @@ -2291,7 +2291,7 @@ static SANE_Status umax_set_window_param(Umax_Device *dev) set_WD_gamma(buffer_r, dev->digital_gamma_r); set_WD_analog_gamma(buffer_r, dev->analog_gamma_r); set_WD_highlight(buffer_r, umax_correct_light(dev->highlight_r, dev->analog_gamma_r)); - set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_r, dev->analog_gamma_r)); + set_WD_shadow(buffer_r, umax_correct_light(dev->shadow_r, dev->analog_gamma_r)); set_WD_scan_exposure_level(buffer_r, dev->exposure_time_scan_r); set_WD_calibration_exposure_level(buffer_r, dev->exposure_time_calibration_r); break; @@ -2344,10 +2344,10 @@ static SANE_Status umax_set_window_param(Umax_Device *dev) if (status) { DBG(DBG_error, "umax_set_window_param: command returned status %s\n", sane_strstatus(status)); - } + } else { - DBG(DBG_info, "window(s) set\n"); + DBG(DBG_info, "window(s) set\n"); } return status; @@ -2372,7 +2372,7 @@ static void umax_do_inquiry(Umax_Device *dev) if (status) { DBG(DBG_error, "umax_do_inquiry: command returned status %s\n", sane_strstatus(status)); - } + } size = get_inquiry_additional_length(dev->buffer[0]) + 5; @@ -2381,7 +2381,7 @@ static void umax_do_inquiry(Umax_Device *dev) if (status) { DBG(DBG_error, "umax_do_inquiry: command returned status %s\n", sane_strstatus(status)); - } + } } @@ -2419,7 +2419,7 @@ static SANE_Status umax_start_scan(Umax_Device *dev) set_SC_quality(scan.cmd, dev->quality); /* 1=qual, 0=fast */ set_SC_adf( scan.cmd, dev->adf); /* ADF, 0=off, 1=use */ set_SC_preview(scan.cmd, dev->preview); /* 1=preview */ - + set_SC_wid(scan.cmd, 1, 0); /* Window-Identifier */ set_SC_xfer_length(scan.cmd, size); /* following Bytes */ @@ -2430,7 +2430,7 @@ static SANE_Status umax_start_scan(Umax_Device *dev) if (status) { DBG(DBG_error, "umax_start_scan: command returned status %s\n", sane_strstatus(status)); - } + } return status; } @@ -2485,7 +2485,7 @@ static SANE_Status umax_do_calibration(Umax_Device *dev) if (dev->calibration_width_offset > -99999) /* driver or user (umax.conf) define an offset */ { - width = width + dev->calibration_width_offset; + width = width + dev->calibration_width_offset; DBG(DBG_warning," Using calibration width offset of %d\n", dev->calibration_width_offset); } @@ -2515,7 +2515,7 @@ static SANE_Status umax_do_calibration(Umax_Device *dev) { if (dev->calibration_width_offset_batch > -99999) /* driver or user (umax.conf) define an offset for batch scanning */ { - width = width + dev->calibration_width_offset_batch; + width = width + dev->calibration_width_offset_batch; DBG(DBG_warning," Using calibration width offset for batch scanning of %d\n", dev->calibration_width_offset_batch); } } @@ -2523,7 +2523,7 @@ static SANE_Status umax_do_calibration(Umax_Device *dev) { if (dev->calibration_width_offset > -99999) /* driver or user (umax.conf) define an offset */ { - width = width + dev->calibration_width_offset; + width = width + dev->calibration_width_offset; DBG(DBG_warning," Using calibration width offset of %d\n", dev->calibration_width_offset); } } @@ -2705,7 +2705,7 @@ static void umax_do_new_inquiry(Umax_Device *dev, size_t size) /* call in if (status) { DBG(DBG_error, "umax_do_new_inquiry: command returned status %s\n", sane_strstatus(status)); - } + } } @@ -3154,7 +3154,7 @@ static int umax_identify_scanner(Umax_Device *dev) { *pp-- = '\0'; } - + pp = &version[4]; while (*pp == ' ') { @@ -3172,12 +3172,12 @@ static int umax_identify_scanner(Umax_Device *dev) while (strncmp("END_OF_LIST", scanner_str[2*i], 11) != 0) /* Now identify full supported scanners */ { if (!strncmp(vendor, scanner_str[2*i], strlen(scanner_str[2*i])) ) - { + { if (!strncmp(product, scanner_str[2*i+1], strlen(scanner_str[2*i+1])) ) { umax_correct_inquiry(dev, vendor, product, version); return 0; - } + } } i++; } @@ -3199,7 +3199,7 @@ static int umax_identify_scanner(Umax_Device *dev) "If you already use the most recent umax-backend version\n" "then please contact me: Oliver.Rauch@rauch-domain.de\n"); - return 0; + return 0; } else /* inquiry-data not complete */ if (!strncmp(vendor, "UMAX ", 5)) /* test UMAX-scanners with short inquiry */ @@ -3210,7 +3210,7 @@ static int umax_identify_scanner(Umax_Device *dev) for(i=0; i < known_inquiry; i++) { inq_data = *inquiry_table[i]; - if (!strncmp(product, inq_data.scanner, strlen(inq_data.scanner))) + if (!strncmp(product, inq_data.scanner, strlen(inq_data.scanner))) { DBG(DBG_warning, "inquiry-block-length: %d\n", get_inquiry_additional_length(dev->buffer[0])+5); DBG(DBG_warning, "using driver-internal inquiry-data for this scanner!\n"); @@ -3222,7 +3222,7 @@ static int umax_identify_scanner(Umax_Device *dev) set_inquiry_sc_uta(dev->buffer[0], get_inquiry_transavail(dev->buffer[0])); /* transparancy available ? */ set_inquiry_sc_adf(dev->buffer[0], get_inquiry_scanmode(dev->buffer[0])); /* automatic document feeder available ? */ - set_inquiry_length(dev->buffer[0], inq_data.inquiry_len); + set_inquiry_length(dev->buffer[0], inq_data.inquiry_len); umax_correct_inquiry(dev, vendor, product, version); return 0; /* ok */ @@ -3268,7 +3268,7 @@ static void umax_trim_rowbufsize(Umax_Device *dev) /* ------------------------------------------------------------ UMAX CALCULATE EXPOSURE TIME --------------- */ - + static void umax_calculate_exposure_time(Umax_Device *dev, int def, int *value) { int level; @@ -3285,7 +3285,7 @@ static void umax_calculate_exposure_time(Umax_Device *dev, int def, int *value) } } - + /* ------------------------------------------------------------ UMAX CHECK VALUES -------------------------- */ @@ -3306,7 +3306,7 @@ static int umax_check_values(Umax_Device *dev) /* --------------------------------- uta --------------------------------- */ - if (dev->uta != 0) + if (dev->uta != 0) { dev->module = WD_module_transparency; if ( (dev->inquiry_uta == 0) || (dev->inquiry_transavail == 0) ) @@ -3318,7 +3318,7 @@ static int umax_check_values(Umax_Device *dev) /* --------------------------------- adf --------------------------------- */ - if (dev->adf != 0) + if (dev->adf != 0) { if (dev->inquiry_adf == 0) { @@ -3334,7 +3334,7 @@ static int umax_check_values(Umax_Device *dev) if (dev->inquiry_dor == 0) { DBG(DBG_error, "ERROR: double optical resolution not supported by scanner\n"); - return(1); + return(1); } } @@ -3522,7 +3522,7 @@ static int umax_check_values(Umax_Device *dev) if (dev->wdb_len <= 0) { - dev->wdb_len = dev->inquiry_wdb_len; + dev->wdb_len = dev->inquiry_wdb_len; if (dev->wdb_len <= 0) { DBG(DBG_error,"ERROR: wdb-length not given\n"); @@ -3668,7 +3668,7 @@ static int umax_check_values(Umax_Device *dev) } /* ---------------------------- speed and smear ------------------------- */ - + if (dev->slow == 1) { dev->WD_speed = WD_speed_slow; @@ -3684,7 +3684,7 @@ static int umax_check_values(Umax_Device *dev) } /* ---------------------- test bits per pixel --------------------------- */ - + if ( ( (dev->inquiry_GIB | 1) & dev->gamma_input_bits_code) == 0 ) { DBG(DBG_warning,"WARNING: selected gamma input bits not supported, gamma ignored\n"); @@ -3697,7 +3697,7 @@ static int umax_check_values(Umax_Device *dev) DBG(DBG_error,"ERROR: selected bits per pixel not supported\n"); return(1); } - + /* ----------------------- scan mode dependencies ------------------------ */ switch(dev->colormode) @@ -3706,7 +3706,7 @@ static int umax_check_values(Umax_Device *dev) case RGB_LINEART: /* ---------- RGB_LINEART ----------- */ dev->use_exposure_time_min = dev->inquiry_exposure_time_l_min; - if (dev->module == WD_module_flatbed) + if (dev->module == WD_module_flatbed) { dev->use_exposure_time_def_r = dev->inquiry_exposure_time_l_fb_def; } @@ -3725,7 +3725,7 @@ static int umax_check_values(Umax_Device *dev) case HALFTONE: /* ----------- HALFTONE------------ */ case RGB_HALFTONE: /* --------- RGB_HALFTONE---------- */ dev->use_exposure_time_min = dev->inquiry_exposure_time_h_min; - if (dev->module == WD_module_flatbed) + if (dev->module == WD_module_flatbed) { dev->use_exposure_time_def_r = dev->inquiry_exposure_time_h_fb_def; } @@ -3744,7 +3744,7 @@ static int umax_check_values(Umax_Device *dev) case GRAYSCALE: /* ---------- GRAYSCALE ------------- */ dev->use_exposure_time_min = dev->inquiry_exposure_time_g_min; - if (dev->module == WD_module_flatbed) + if (dev->module == WD_module_flatbed) { dev->use_exposure_time_def_r = dev->inquiry_exposure_time_g_fb_def; } @@ -3762,7 +3762,7 @@ static int umax_check_values(Umax_Device *dev) case RGB: /* ----------------- COLOR ---------- */ dev->use_exposure_time_min = dev->inquiry_exposure_time_c_min; - if (dev->module == WD_module_flatbed) + if (dev->module == WD_module_flatbed) { dev->use_exposure_time_def_r = dev->inquiry_exposure_time_c_fb_def_r; dev->use_exposure_time_def_g = dev->inquiry_exposure_time_c_fb_def_g; @@ -3838,7 +3838,7 @@ static int umax_check_values(Umax_Device *dev) dev->CCD_color[1] = CCD_color_blue; dev->CCD_color[2] = CCD_color_red; - + dev->CCD_color[3] = CCD_color_blue; dev->CCD_color[4] = CCD_color_green; dev->CCD_color[5] = CCD_color_red; @@ -3893,13 +3893,13 @@ static int umax_check_values(Umax_Device *dev) dev->CCD_color[6] = CCD_color_green; dev->CCD_color[7] = CCD_color_blue; - + dev->CCD_color[8] = CCD_color_green; break; default: dev->CCD_color[0] = CCD_color_green; - + dev->CCD_color[1] = CCD_color_blue; dev->CCD_color[2] = CCD_color_green; @@ -3915,12 +3915,12 @@ static int umax_check_values(Umax_Device *dev) DBG(DBG_info,"scanner uses color-line-ordering with CCD-distance of %d lines\n", dev->CCD_distance); } else - { + { DBG(DBG_error,"ERROR: color-ordering-type not supported \n"); return(1); } } - else + else { DBG(DBG_info,"using three pass scanning mode\n"); dev->three_pass=1; @@ -3971,7 +3971,7 @@ static void umax_get_inquiry_values(Umax_Device *dev) dev->inquiry_highlight_min = 1; /* minimum value for h */ dev->inquiry_highlight_max = 50; /* maximum value for h */ dev->inquiry_shadow_min = 0; /* minimum value for s */ - dev->inquiry_shadow_max = 49; /* maximum value for s */ + dev->inquiry_shadow_max = 49; /* maximum value for s */ } get_inquiry_vendor( (char *)inquiry_block, dev->vendor); dev->vendor[8] ='\0'; @@ -4161,7 +4161,7 @@ static void umax_get_inquiry_values(Umax_Device *dev) if (dev->inquiry_len<=0x9d) { return; - } + } dev->inquiry_CCD_line_distance = get_inquiry_CCD_line_distance(inquiry_block); return; @@ -4185,7 +4185,7 @@ static int umax_calculate_analog_gamma(double value) while (value>analog_gamma_table[gamma]) { gamma++; - } + } if (gamma) { @@ -4194,7 +4194,7 @@ static int umax_calculate_analog_gamma(double value) gamma--; } } - + return(gamma); } @@ -4211,7 +4211,7 @@ static void umax_output_image_data(Umax_Device *dev, FILE *fp, unsigned int data for (i=0; ibuffer[bufnr][i]; + old = dev->buffer[bufnr][i]; new = 0; for (j=0; j<8; j++) /* reverse bit order of 1 byte */ { @@ -4463,11 +4463,11 @@ static void umax_initialize_values(Umax_Device *dev) /* called each time b dev->pixelline_optic[0] = 1; dev->pixelline_optic[1] = 1; dev->pixelline_optic[2] = 1; - dev->pixelline_max = 0; - dev->pixelline_opt_res = 0; - dev->pixelline_read = 0; - dev->pixelline_written = 0; - dev->CCD_distance = 0; + dev->pixelline_max = 0; + dev->pixelline_opt_res = 0; + dev->pixelline_read = 0; + dev->pixelline_written = 0; + dev->CCD_distance = 0; dev->calib_lines = 0; /* request calibration lines */ dev->do_calibration = 0; /* no calibration by driver */ @@ -4497,7 +4497,7 @@ static void umax_init(Umax_Device *dev) /* umax_init is called once while else /* SANE_UMAX_USB, USB does not support command queueing */ { DBG(DBG_info2, "setting request_scsi_maxqueue = 1 for USB connection\n"); - dev->request_scsi_maxqueue = 1; + dev->request_scsi_maxqueue = 1; } dev->request_preview_lines = umax_preview_lines; @@ -4578,7 +4578,7 @@ static void umax_init(Umax_Device *dev) /* umax_init is called once while dev->inquiry_highlight_min = 1; /* minimum value for h */ dev->inquiry_highlight_max = 255; /* maximum value for h */ dev->inquiry_shadow_min = 0; /* minimum value for s */ - dev->inquiry_shadow_max = 254; /* maximum value for s */ + dev->inquiry_shadow_max = 254; /* maximum value for s */ dev->inquiry_quality_ctrl = 0; dev->inquiry_preview = 0; dev->inquiry_lamp_ctrl = 0; @@ -4686,7 +4686,7 @@ static SANE_Status do_cancel(Umax_Scanner *scanner) DBG(DBG_sane_info, "do_cancel: reader_process terminated with status: %s\n", sane_strstatus(status)); } - scanner->reader_pid = -1; + sanei_thread_invalidate (scanner->reader_pid); if (scanner->device->pixelbuffer != NULL) /* pixelbuffer exists? */ { @@ -4870,7 +4870,7 @@ static SANE_Status attach_scanner(const char *devicename, Umax_Device **devp, in dev->sane.name = dev->devicename; dev->sane.vendor = dev->vendor; dev->sane.model = dev->product; - dev->sane.type = "flatbed scanner"; + dev->sane.type = "flatbed scanner"; if (strcmp(dev->sane.model,"PSD ") == 0) { @@ -5001,7 +5001,7 @@ static int reader_process(void *data) /* executed as a child process or as threa if (!fp) { return SANE_STATUS_IO_ERROR; - } + } DBG(DBG_sane_info,"reader_process: starting to READ data\n"); @@ -5076,17 +5076,17 @@ static SANE_Status init_options(Umax_Scanner *scanner) if (scanner->device->inquiry_color) { -/* +/* if (scanner->device->inquiry_lineart) { scan_mode_list[++scan_modes]= COLOR_LINEART_STR; } - if (scanner->device->inquiry_halftone) + if (scanner->device->inquiry_halftone) { scan_mode_list[++scan_modes]= COLOR_HALFTONE_STR; } */ - scan_mode_list[++scan_modes]= COLOR_STR; + scan_mode_list[++scan_modes]= COLOR_STR; } - scan_mode_list[scan_modes + 1] = 0; + scan_mode_list[scan_modes + 1] = 0; { int i=0; @@ -5104,7 +5104,7 @@ static SANE_Status init_options(Umax_Scanner *scanner) source_list[i] = 0; } - + /* scan mode */ scanner->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; scanner->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; @@ -5124,7 +5124,7 @@ static SANE_Status init_options(Umax_Scanner *scanner) scanner->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; scanner->opt[OPT_SOURCE].constraint.string_list = source_list; scanner->val[OPT_SOURCE].s = (SANE_Char*)strdup(source_list[0]); - + /* x-resolution */ scanner->opt[OPT_X_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; scanner->opt[OPT_X_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; @@ -5906,7 +5906,7 @@ static SANE_Status init_options(Umax_Scanner *scanner) sane_control_option(scanner, OPT_MODE, SANE_ACTION_SET_VALUE, (SANE_String *) scan_mode_list[scan_modes], NULL ); - + return SANE_STATUS_GOOD; } @@ -5944,7 +5944,7 @@ static SANE_Status umax_test_configure_option(const char *option_str, char *test errno = 0; value = strtol(value_str, &end_ptr, 10); - if (end_ptr == value_str || errno) + if (end_ptr == value_str || errno) { DBG(DBG_error, "ERROR: invalid value \"%s\" for option %s in %s\n", value_str, test_name, UMAX_CONFIG_FILE); } @@ -6013,7 +6013,7 @@ SANE_Status sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize) #endif fp = sanei_config_open(UMAX_CONFIG_FILE); - if (!fp) + if (!fp) { /* no config-file: try /dev/scanner and /dev/usbscanner. */ attach_scanner("/dev/scanner", 0, SANE_UMAX_SCSI); @@ -6308,7 +6308,7 @@ void sane_close(SANE_Handle handle) prev = scanner; } - + if (!scanner) { DBG(DBG_error, "ERROR: sane_close: invalid handle %p\n", handle); @@ -6318,7 +6318,7 @@ void sane_close(SANE_Handle handle) if (scanner->scanning) /* stop scan if still scanning */ { do_cancel(handle); - } + } if (scanner->device->lamp_control_available) /* lamp state can be controlled by driver */ { @@ -6380,7 +6380,7 @@ static void umax_set_max_geometry(Umax_Scanner *scanner) scanner->device->y_range.max = SANE_FIX( (scanner->device->inquiry_dor_y_off + scanner->device->inquiry_dor_length) * MM_PER_INCH); scanner->device->x_dpi_range.max = SANE_FIX(scanner->device->inquiry_dor_x_res); - scanner->device->y_dpi_range.max = SANE_FIX(scanner->device->inquiry_dor_y_res); + scanner->device->y_dpi_range.max = SANE_FIX(scanner->device->inquiry_dor_y_res); } else if ( (strcmp(scanner->val[OPT_SOURCE].s, FLB_STR) == 0) || (strcmp(scanner->val[OPT_SOURCE].s, ADF_STR) == 0) ) { @@ -6390,7 +6390,7 @@ static void umax_set_max_geometry(Umax_Scanner *scanner) scanner->device->y_range.max = SANE_FIX(scanner->device->inquiry_fb_length * MM_PER_INCH); scanner->device->x_dpi_range.max = SANE_FIX(scanner->device->inquiry_x_res); - scanner->device->y_dpi_range.max = SANE_FIX(scanner->device->inquiry_y_res); + scanner->device->y_dpi_range.max = SANE_FIX(scanner->device->inquiry_y_res); } else if (strcmp(scanner->val[OPT_SOURCE].s, UTA_STR) == 0) { @@ -6400,7 +6400,7 @@ static void umax_set_max_geometry(Umax_Scanner *scanner) scanner->device->y_range.max = SANE_FIX( ( scanner->device->inquiry_uta_y_off + scanner->device->inquiry_uta_length) * MM_PER_INCH); scanner->device->x_dpi_range.max = SANE_FIX(scanner->device->inquiry_x_res); - scanner->device->y_dpi_range.max = SANE_FIX(scanner->device->inquiry_y_res); + scanner->device->y_dpi_range.max = SANE_FIX(scanner->device->inquiry_y_res); } DBG(DBG_info,"x_range = [%f .. %f]\n", SANE_UNFIX(scanner->device->x_range.min), SANE_UNFIX(scanner->device->x_range.max)); @@ -6414,7 +6414,7 @@ static void umax_set_max_geometry(Umax_Scanner *scanner) { scanner->val[OPT_TL_X].w = scanner->device->x_range.min; } - + if (scanner->val[OPT_TL_Y].w < scanner->device->y_range.min) { scanner->val[OPT_TL_Y].w = scanner->device->y_range.min; @@ -6424,7 +6424,7 @@ static void umax_set_max_geometry(Umax_Scanner *scanner) { scanner->val[OPT_BR_X].w = scanner->device->x_range.max; } - + if (scanner->val[OPT_BR_Y].w > scanner->device->y_range.max) { scanner->val[OPT_BR_Y].w = scanner->device->y_range.max; @@ -6528,7 +6528,7 @@ SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action case OPT_MANUAL_PRE_FOCUS: case OPT_FIX_FOCUS_POSITION: case OPT_LENS_CALIBRATION_DOC_POS: - case OPT_HOLDER_FOCUS_POS_0MM: + case OPT_HOLDER_FOCUS_POS_0MM: case OPT_LAMP_OFF_AT_EXIT: case OPT_SELECT_LAMP_DENSITY: *(SANE_Word *) val = scanner->val[option].w; @@ -6645,7 +6645,7 @@ SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action case OPT_MANUAL_PRE_FOCUS: case OPT_FIX_FOCUS_POSITION: case OPT_LENS_CALIBRATION_DOC_POS: - case OPT_HOLDER_FOCUS_POS_0MM: + case OPT_HOLDER_FOCUS_POS_0MM: case OPT_LAMP_OFF_AT_EXIT: scanner->val[option].w = *(SANE_Word *) val; return SANE_STATUS_GOOD; @@ -6663,7 +6663,7 @@ SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action } DBG(DBG_info,"sane_control_option: set DOR = %d\n", scanner->val[option].w); - umax_set_max_geometry(scanner); + umax_set_max_geometry(scanner); } return SANE_STATUS_GOOD; } @@ -6895,7 +6895,7 @@ SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action case OPT_CUSTOM_GAMMA: { w = *(SANE_Word *) val; - if (w == scanner->val[OPT_CUSTOM_GAMMA].w) { return SANE_STATUS_GOOD; } + if (w == scanner->val[OPT_CUSTOM_GAMMA].w) { return SANE_STATUS_GOOD; } scanner->val[OPT_CUSTOM_GAMMA].w = w; if (w) /* use custom_gamma_table */ @@ -6944,7 +6944,7 @@ SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action *info |=SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; } - scanner->opt[OPT_NEGATIVE].cap |= SANE_CAP_INACTIVE; + scanner->opt[OPT_NEGATIVE].cap |= SANE_CAP_INACTIVE; scanner->opt[OPT_BIT_DEPTH].cap |= SANE_CAP_INACTIVE; @@ -7025,7 +7025,7 @@ SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action if (scanner->val[OPT_SELECT_EXPOSURE_TIME].w == SANE_TRUE) { - scanner->opt[OPT_CAL_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE; + scanner->opt[OPT_CAL_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE; scanner->opt[OPT_SCAN_EXPOS_TIME].cap &= ~SANE_CAP_INACTIVE; } @@ -7062,7 +7062,7 @@ SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, SANE_Action if (scanner->device->inquiry_reverse_multi) { - scanner->opt[OPT_NEGATIVE].cap &= ~SANE_CAP_INACTIVE; + scanner->opt[OPT_NEGATIVE].cap &= ~SANE_CAP_INACTIVE; } if (scanner->device->inquiry_gamma_dwload) @@ -7285,9 +7285,9 @@ SANE_Status sane_start(SANE_Handle handle) DBG(DBG_sane_init,"sane_start\n"); - /* Initialize reader_pid to invalid so a subsequent error and following call - * to do_cancel() won't trip over it. */ - scanner->reader_pid = -1; + /* Invalidate reader_pid so a subsequent error and following call to + * do_cancel() won't trip over it. */ + sanei_thread_invalidate(scanner->reader_pid); mode = scanner->val[OPT_MODE].s; @@ -7452,11 +7452,11 @@ SANE_Status sane_start(SANE_Handle handle) scanner->device->analog_gamma_b = umax_calculate_analog_gamma(SANE_UNFIX(scanner->val[OPT_ANALOG_GAMMA].w)); scanner->device->highlight_r = - scanner->device->highlight_g = + scanner->device->highlight_g = scanner->device->highlight_b = P_100_TO_255(scanner->val[OPT_HIGHLIGHT].w); scanner->device->shadow_r = - scanner->device->shadow_g = + scanner->device->shadow_g = scanner->device->shadow_b = P_100_TO_255(scanner->val[OPT_SHADOW].w); if (scanner->val[OPT_SELECT_EXPOSURE_TIME].w == SANE_TRUE) @@ -7634,7 +7634,7 @@ SANE_Status sane_start(SANE_Handle handle) } scanner->params.bytes_per_line = scanner->device->row_len; - scanner->params.pixels_per_line = scanner->device->width_in_pixels; + scanner->params.pixels_per_line = scanner->device->width_in_pixels; scanner->params.lines = scanner->device->length_in_pixels; @@ -7825,7 +7825,7 @@ SANE_Status sane_start(SANE_Handle handle) scanner->device->halftone = WD_halftone_download; } /* end of send halftonepattern */ #endif - + } /* ------------ end of first call -------------- */ @@ -7990,7 +7990,7 @@ SANE_Status sane_start(SANE_Handle handle) return SANE_STATUS_IO_ERROR; } - scanner->pipe_read_fd = fds[0]; + scanner->pipe_read_fd = fds[0]; scanner->pipe_write_fd = fds[1]; /* start reader_process, deponds on OS if fork() or threads are used */ @@ -8067,7 +8067,7 @@ SANE_Status sane_read(SANE_Handle handle, SANE_Byte *buf, SANE_Int max_len, SANE scanner->pipe_read_fd = -1; } - return SANE_STATUS_EOF; + return SANE_STATUS_EOF; } return SANE_STATUS_GOOD; @@ -8104,8 +8104,8 @@ SANE_Status sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking) if (fcntl(scanner->pipe_read_fd, F_SETFL, non_blocking ? O_NONBLOCK : 0) < 0) { return SANE_STATUS_IO_ERROR; - } - return SANE_STATUS_GOOD; + } + return SANE_STATUS_GOOD; } diff --git a/backend/umax.conf.in b/backend/umax.conf.in index a57cf53..06b2750 100644 --- a/backend/umax.conf.in +++ b/backend/umax.conf.in @@ -17,7 +17,7 @@ # 0 = handle as device busy # 1 = handle as ok # 2 = handle as i/o error -# 3 = ignore bad error code - continue sense handler, +# 3 = ignore bad error code - continue sense handler, #option handle-bad-sense-error 0 # define if a request sense command shall be executed @@ -43,7 +43,7 @@ # define if the calibration shall be done for selected scanarea or for each ccd pixel # -1 = automatically set by driver - if known # 0 = disabled -# 1 = enabled +# 1 = enabled #option calibration-full-ccd 1 # define if an offset of the calculate calibration with has to be used @@ -54,7 +54,7 @@ # -1 = disabled # 0 = not set # 1 = 1 byte/pixel, -# 2 = 2 bytes/pixel +# 2 = 2 bytes/pixel #option calibration-bytes-pixel -1 # define if scanner uses the same exposure times for red, green and blue @@ -66,18 +66,18 @@ # define if shading data shall be inverted befor sending it back to the scanner # -1 = automatically set by driver - if known # 0 = disabled -# 1 = enabled +# 1 = enabled #option invert-shading-data 0 # define if the scanner supports lamp control commands # 0 = automatically set by driver - if known -# 1 = enabled +# 1 = enabled #option lamp-control-available 0 # define how 16 bit gamma data is padded # -1 = automatically set by driver - if known # 0 = gamma data is msb padded -# 1 = gamma data is lsb padded +# 1 = gamma data is lsb padded #option gamma-lsb-padded 0 # define connection type of following devices @@ -114,4 +114,3 @@ option connection-type 1 # usb device list option connection-type 2 /dev/usbscanner - diff --git a/backend/umax.h b/backend/umax.h index 682e58b..e6b83fd 100644 --- a/backend/umax.h +++ b/backend/umax.h @@ -1,7 +1,7 @@ /* --------------------------------------------------------------------------------------------------------- */ /* umax.h - headerfile for SANE-backend for umax scanners - + (C) 1997-2002 Oliver Rauch This program is free software; you can redistribute it and/or @@ -39,7 +39,7 @@ 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. - + */ /* --------------------------------------------------------------------------------------------------------- */ @@ -58,7 +58,7 @@ /* #define SANE_UMAX_DEBUG_S12 */ /* #define UMAX_CALIBRATION_MODE_SELECTABLE */ - + /* --------------------------------------------------------------------------------------------------------- */ #define SANE_UMAX_SCSI_MAXQUEUE 8 @@ -269,7 +269,7 @@ typedef struct Umax_Device double inquiry_dor_y_off; /* double resolution y offset in inches */ int inquiry_exposure_adj; /* 1 if exposure adjust is supported */ - int inquiry_exposure_time_step_unit; /* exposure time unit in micro sec */ + int inquiry_exposure_time_step_unit; /* exposure time unit in micro sec */ int inquiry_exposure_time_max; /* exposure time maximum */ int inquiry_exposure_time_l_min; /* exposure tine minimum for lineart */ int inquiry_exposure_time_l_fb_def; /* exposure time default for lineart/flatbed */ diff --git a/backend/umax1220u-common.c b/backend/umax1220u-common.c index 43a4a6f..e14dfea 100644 --- a/backend/umax1220u-common.c +++ b/backend/umax1220u-common.c @@ -7,7 +7,7 @@ Parts copyright (C) 2006 Patrick Lessard 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 @@ -66,7 +66,7 @@ #include #include -/* +/* * The backend performs test scans in order to calibrate * the CCD and to find the zero location. If you would like * to look at those scans, define DEBUG_CALIBRATION to have diff --git a/backend/umax1220u.c b/backend/umax1220u.c index 79b8c92..30c9e86 100644 --- a/backend/umax1220u.c +++ b/backend/umax1220u.c @@ -376,7 +376,7 @@ optionTopLeftYCallback (SANE_Option * option, SANE_Handle handle, This option controls the bot-right-x corner of the scan */ -static SANE_Fixed optionBotRightXValue +static SANE_Fixed optionBotRightXValue = SANE_FIX (UMAX_MAX_WIDTH * MM_IN_INCH / 600); static SANE_Option_Descriptor optionBotRightXDescriptor = { diff --git a/backend/umax_pp.c b/backend/umax_pp.c index 0f7ce4e..b1121ef 100644 --- a/backend/umax_pp.c +++ b/backend/umax_pp.c @@ -1,5 +1,5 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2001-2012 Stéphane Voltz + Copyright (C) 2001-2012 Stéphane Voltz This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -41,10 +41,10 @@ This file implements a SANE backend for Umax PP flatbed scanners. */ /* CREDITS: - Started by being a mere copy of mustek_pp - by Jochen Eisinger - then evolved in its own thing - + Started by being a mere copy of mustek_pp + by Jochen Eisinger + then evolved in its own thing + support for the 610P has been made possible thank to an hardware donation from William Stuart */ diff --git a/backend/umax_pp.conf.in b/backend/umax_pp.conf.in index e7e9fd4..f220f1f 100644 --- a/backend/umax_pp.conf.in +++ b/backend/umax_pp.conf.in @@ -39,19 +39,19 @@ option buffer 2097152 # valid values are 610, 1220, 1600 and 2000 # # by default, no model, we rely on autodetection -# in case you have black or 'inverted' scans, +# in case you have black or 'inverted' scans, # you may override detection by providing the # model number #option astra 1220 # DEVICES # -# specify the port your scanner is connected to. +# specify the port your scanner is connected to. # # the value 'auto' will make the backend find the correct value # by itself, it will scan ppdev, ppi device, then hardware address # 'safe-auto' will do the same but won't do direct hardware access -# on linux systems, you may provide the device name of the ppdev character +# on linux systems, you may provide the device name of the ppdev character # device : /dev/parport0, /dev/parport1, ...... # # on *BSD, you may provide the device name of the ppi device: /dev/ppi0, diff --git a/backend/umax_pp.h b/backend/umax_pp.h index dbedab8..c8ffdfa 100644 --- a/backend/umax_pp.h +++ b/backend/umax_pp.h @@ -1,5 +1,5 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2001-2012 Stéphane Voltz + Copyright (C) 2001-2012 Stéphane Voltz This file is part of the SANE package. This program is free software; you can redistribute it and/or diff --git a/backend/umax_pp_low.c b/backend/umax_pp_low.c index 1e38aba..c5d9a93 100644 --- a/backend/umax_pp_low.c +++ b/backend/umax_pp_low.c @@ -1,5 +1,5 @@ /** - Copyright (C) 2001-2012 Stéphane Voltz + Copyright (C) 2001-2012 Stéphane Voltz This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -297,7 +297,7 @@ sanei_outb (unsigned int port, unsigned char value) static void sanei_insb (unsigned int port, unsigned char *addr, unsigned long count) { - int i; + unsigned int i; for (i = 0; i < count; i++) addr[i] = sanei_inb (port); @@ -306,7 +306,7 @@ sanei_insb (unsigned int port, unsigned char *addr, unsigned long count) static void sanei_insl (unsigned int port, unsigned char *addr, unsigned long count) { - int i; + unsigned int i; for (i = 0; i < count * 4; i++) addr[i] = sanei_inb (port); @@ -316,7 +316,7 @@ static void sanei_outsb (unsigned int port, const unsigned char *addr, unsigned long count) { - int i; + unsigned int i; for (i = 0; i < count; i++) sanei_outb (port, addr[i]); @@ -326,7 +326,7 @@ static void sanei_outsl (unsigned int port, const unsigned char *addr, unsigned long count) { - int i; + unsigned int i; for (i = 0; i < count * 4; i++) sanei_outb (port, addr[i]); @@ -865,7 +865,7 @@ sanei_parport_find_device (void) else { #ifdef HAVE_LINUX_PPDEV_H - /* on kernel < 2.4.23, you have to CLAIM the device + /* on kernel < 2.4.23, you have to CLAIM the device * to check it really exists * we may hang if another program already claimed it */ @@ -926,13 +926,22 @@ sanei_parport_find_device (void) int sanei_umax_pp_initPort (int port, char *name) { - int fd, ectr; +#ifndef IO_SUPPORT_MISSING +# ifdef HAVE_LINUX_PPDEV_H int found = 0; -#if ((defined HAVE_IOPERM)||(defined HAVE_MACHINE_CPUFUNC_H)||(defined HAVE_LINUX_PPDEV_H)) + int fd; int mode, modes, rc; -#endif -#ifdef HAVE_LINUX_PPDEV_H +# ifdef PPGETMODES char strmodes[160]; +# endif +# endif +# ifdef HAVE_DEV_PPBUS_PP_H + int found = 0; + int fd; +# endif +# ifdef HAVE_IOPERM + int ectr; +# endif #endif /* since this function must be called before */ @@ -1793,8 +1802,8 @@ sanei_umax_pp_setauto (int autoset) } #ifdef HAVE_LINUX_PPDEV_H -/* set to the parallel port needed using ppdev - * returns 1 if ok, 0 else +/* set to the parallel port needed using ppdev + * returns 1 if ok, 0 else */ static int ppdev_set_mode (int mode) @@ -2807,7 +2816,7 @@ ECPregisterRead (int reg) Outb (CONTROL, 0x4); - /* ECP FIFO mode, interrupt bit, dma disabled, + /* ECP FIFO mode, interrupt bit, dma disabled, service bit, fifo full=0, fifo empty=0 */ ECPFifoMode (); /*Outb (ECR, 0x60); */ if (waitFifoEmpty () == 0) @@ -2825,12 +2834,12 @@ ECPregisterRead (int reg) } breg = Inb (ECR); - /* byte mode, interrupt bit, dma disabled, + /* byte mode, interrupt bit, dma disabled, service bit, fifo full=0, fifo empty=0 */ byteMode (); /*Outb (ECR, 0x20); */ Outb (CONTROL, 0x20); /* data reverse */ - /* ECP FIFO mode, interrupt bit, dma disabled, + /* ECP FIFO mode, interrupt bit, dma disabled, service bit, fifo full=0, fifo empty=0 */ ECPFifoMode (); /*Outb (ECR, 0x60); */ if (waitFifoNotEmpty () == 0) @@ -2859,9 +2868,9 @@ EPPregisterRead (int reg) #ifdef HAVE_LINUX_PPDEV_H int fd, mode, rc; unsigned char breg, bval; + int value; #endif int control; - int value; #ifdef HAVE_LINUX_PPDEV_H @@ -2910,7 +2919,7 @@ EPPregisterRead (int reg) control = Inb (CONTROL); control = (control & 0x1F) | 0x20; Outb (CONTROL, control); - value = Inb (EPPDATA); + Inb (EPPDATA); control = Inb (CONTROL); control = control & 0x1F; Outb (CONTROL, control); @@ -2943,9 +2952,8 @@ registerRead (int reg) static void ECPregisterWrite (int reg, int value) { - unsigned char breg; - #ifdef HAVE_LINUX_PPDEV_H + unsigned char breg; int rc, fd; fd = sanei_umax_pp_getparport (); @@ -2963,12 +2971,12 @@ ECPregisterWrite (int reg, int value) } #endif - /* standard mode, interrupt bit, dma disabled, + /* standard mode, interrupt bit, dma disabled, service bit, fifo full=0, fifo empty=0 */ compatMode (); Outb (CONTROL, 0x04); /* reset ? */ - /* ECP FIFO mode, interrupt bit, dma disabled, + /* ECP FIFO mode, interrupt bit, dma disabled, service bit, fifo full=0, fifo empty=0 */ ECPFifoMode (); /*Outb (ECR, 0x60); */ if (waitFifoEmpty () == 0) @@ -2977,7 +2985,7 @@ ECPregisterWrite (int reg, int value) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (DATA, reg); if (waitFifoEmpty () == 0) @@ -2986,7 +2994,7 @@ ECPregisterWrite (int reg, int value) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (ECPDATA, value); if (waitFifoEmpty () == 0) @@ -2995,7 +3003,7 @@ ECPregisterWrite (int reg, int value) __FILE__, __LINE__); return; } - breg = Inb (ECR); + Inb (ECR); Outb (CONTROL, 0x04); byteMode (); return; @@ -3429,8 +3437,8 @@ ECPbufferWrite (int size, unsigned char *source) } breg = Inb (ECR); - /* block transfer direction - * 0x80 means from scanner to PC, 0xC0 means PC to scanner + /* block transfer direction + * 0x80 means from scanner to PC, 0xC0 means PC to scanner */ Outb (DATA, 0xC0); @@ -4957,7 +4965,7 @@ sendWord (int *cmd) /******************************************************************************/ /* ringScanner: returns 1 if scanner present, else 0 */ /******************************************************************************/ -/* +/* * in fact this function is really close to CPP macro in * /usr/src/linux/drivers/block/paride/epat.c ..... * we have almost CPP(8) @@ -6005,7 +6013,7 @@ initScanner610p (int recover) return 1; } - /* here we do re-homing + /* here we do re-homing * since it is first probe or recover */ /* move forward */ CMDSYNC (0xC2); @@ -6096,7 +6104,7 @@ initScanner610p (int recover) /* 1: OK 2: homing happened 3: scanner busy - 0: init failed + 0: init failed init transport layer init scanner @@ -6308,13 +6316,13 @@ sanei_umax_pp_initScanner (int recover) } -/* +/* 1: OK 2: failed, try again - 0: init failed + 0: init failed initialize the transport layer - + */ static int @@ -6400,13 +6408,13 @@ initTransport610p (void) return 1; } -/* +/* 1: OK 2: failed, try again - 0: init failed + 0: init failed initialize the transport layer - + */ static int @@ -6605,13 +6613,13 @@ initTransport1220P (int recover) /* ECP OK !! */ return 1; } -/* +/* 1: OK 2: failed, try again - 0: init failed + 0: init failed initialize the transport layer - + */ int @@ -6643,7 +6651,7 @@ probe610p (int recover) return 0; } - /* make sure we won't try 1220/200P later + /* make sure we won't try 1220/200P later * since we got here, we have a 610, and in any case * NOT a 1220P/2000P, since no EPAT present */ sanei_umax_pp_setastra (610); @@ -6660,7 +6668,7 @@ probe610p (int recover) } - /* + /* * try PS2 mode * returns 1 on success, 0 on failure */ @@ -7018,7 +7026,7 @@ probeECP (unsigned char *dest) * inb ECR,35 */ /* routine A */ - breg = Inb (CONTROL); /* 0x04 évidemment! */ + breg = Inb (CONTROL); /* 0x04 évidemment! */ breg = Inb (ECR); breg = Inb (ECR); breg = Inb (ECR); @@ -8617,9 +8625,9 @@ EPPcmdGetBuffer610p (int cmd, int len, unsigned char *buffer) int word[5]; int count, needed, max; #ifdef HAVE_LINUX_PPDEV_H - int fd, mode, rc; + int fd, mode, rc, wait; #endif - int loop, wait, remain; + int loop, remain; /* first we set length and channel */ /* compute word */ @@ -8702,7 +8710,6 @@ EPPcmdGetBuffer610p (int cmd, int len, unsigned char *buffer) else remain = 4; loop = (needed - remain) / 2; - wait = 0; DBG (32, "EPPcmdGetBuffer610p: %d loops to do \n", loop); status = 0x20; @@ -8742,6 +8749,7 @@ EPPcmdGetBuffer610p (int cmd, int len, unsigned char *buffer) /* there is one form for full CCD width reads, and another for other reads */ #ifdef HAVE_LINUX_PPDEV_H + wait = 0; /* check we have ppdev working */ fd = sanei_umax_pp_getparport (); if (fd > 0) @@ -9368,7 +9376,7 @@ cmdGetBlockBuffer (int cmd, int len, int window, unsigned char *buffer) return read; } -/* +/* * encodes DC offsets: must be in [0..0x0F] range */ static void @@ -9387,7 +9395,7 @@ decodeDC (int *motor) } -/* +/* * encodes VGA : must be in [0..0x0F] range */ static void @@ -9402,10 +9410,10 @@ encodeVGA (int vgaRed, int vgaGreen, int vgaBlue, int *motor) { motor[10] = (vgaGreen << 4) | vgaBlue; motor[11] = (motor[11] & 0xF0) | vgaRed; - /* ancien - F00: vert + /* ancien + F00: vert 0F0: bleu - 00F: rouge + 00F: rouge motor[10] = (vgaRed << 4) | vgaGreen; motor[11] = (motor[11] & 0xF0) | vgaBlue; */ } @@ -9693,7 +9701,7 @@ bloc8Decode (int *op) static int completionWait (void) { - /* for 610P, wait and sync is done while + /* for 610P, wait and sync is done while * reading data from the scanner */ CMDSYNC (0x40); usleep (100000); @@ -9893,7 +9901,7 @@ evalGain (int sum, int count) avg = (float) (sum) / (float) (count); pct = 100.0 - (avg * 100.0) / targetCode; gn = (int) (pct / 0.57); - + /* give gain for dark areas a boost */ #ifdef UMAX_PP_DANGEROUS_EXPERIMENT if(getenv("AREA")!=NULL) @@ -9907,7 +9915,7 @@ evalGain (int sum, int count) pct = gn; avg = exp((-pct)/area)*coeff+cnst; gn = gn * avg; - + /* bound checking : there are sightings of >127 values being negative */ if (gn < 0) gn = 0; @@ -9985,7 +9993,7 @@ computeCalibrationData (int color, int width, unsigned char *source, /* move head by the distance given using precision or not */ -/* 0: failed +/* 0: failed 1: success */ static int move (int distance, int precision, unsigned char *buffer) @@ -10437,11 +10445,11 @@ shadingCalibration1220p (int color, /* get calibration data */ /* if (sanei_umax_pp_getauto ()) - { auto settings doesn't use offset + { auto settings doesn't use offset offset = 0x000; } else - { manual settings + { manual settings gain = 0x777; offset = 0x000; } @@ -10743,7 +10751,7 @@ sanei_umax_pp_scan (int x, int y, int width, int height, int dpi, int color, read += len; } - /* in color mode we have to fill the 'reserve' area + /* in color mode we have to fill the 'reserve' area * so that we can reorder data lines */ while ((read - dataoffset < reserve) && (!gCancel)) { @@ -10823,8 +10831,8 @@ sanei_umax_pp_scan (int x, int y, int width, int height, int dpi, int color, } } /* copy tail lines for next block */ - /* memcpy (buffer, - * (buffer + reserve) + (hp * bpl - reserve), + /* memcpy (buffer, + * (buffer + reserve) + (hp * bpl - reserve), * reserve + remain); */ memcpy (buffer, buffer + hp * bpl, reserve + remain); break; @@ -11194,8 +11202,8 @@ sanei_umax_pp_startScan (int x, int y, int width, int height, int dpi, th = (height * dpi) / hwdpi; tw = (width * xdpi) / hwdpi; - /* corrects y to match exact scan area start - * and lets room for a leading zone so that + /* corrects y to match exact scan area start + * and lets room for a leading zone so that * we can reorder data */ switch (sanei_umax_pp_getastra ()) { @@ -11476,7 +11484,7 @@ sanei_umax_pp_startScan (int x, int y, int width, int height, int dpi, /* 3 ccd lines + 3 gamma tables + end tag */ if (sanei_umax_pp_getastra () <= 610) { - /* XXX STEF XXX : there is a 4 pixels shift to the right + /* XXX STEF XXX : there is a 4 pixels shift to the right * the first shading correction value applies to the forth * pixel of scan (at 300 dpi), we allready shift to the left * when doing shadingCalibration, but now we have to move coeffs @@ -11504,7 +11512,7 @@ sanei_umax_pp_startScan (int x, int y, int width, int height, int dpi, return 1; } -/* +/* * check the scanner model. Return 1220 for * a 1220P, or 2000 for a 2000P. * and 610 for a 610p @@ -11728,7 +11736,7 @@ loadDefaultTables (void) } /* set and reread first table */ - /* since 1660P seems to have another type of CCD + /* since 1660P seems to have another type of CCD * this table is not sent/needed */ err = 0; @@ -11829,7 +11837,7 @@ loadDefaultTables (void) return rc; } -/* inquire scanner status +/* inquire scanner status * O: failure * 1: OK * 2: first scanner init, needs re-homing @@ -12070,7 +12078,7 @@ offsetCalibration1220p (int color, int *offRed, int *offGreen, int *offBlue) * computes DC offset to have black pixel really black out of * CCD ie black gives 0 * 610P doesn't implement method described in LM9811 datasheet - * but scan a black line with decreasing offsets until the + * but scan a black line with decreasing offsets until the * scanned data reach a 'good black level'. * returns 1 and DC offsets in the corresponding vars on success . * On failure, returns 0. @@ -12247,7 +12255,7 @@ offsetCalibration610p (int color, int *offRed, int *offGreen, int *offBlue) return 1; } -/* +/* * generic offset calibration function */ static int @@ -12339,7 +12347,7 @@ coarseGainCalibration610p (int color, int dcRed, int dcGreen, int dcBlue, /* move back to desired area */ MOVE (-69, PRECISION_OFF, NULL); - /* first scan : taking a reference full width scan to + /* first scan : taking a reference full width scan to * find usable full width of the CCD */ *vgaRed = 0x08; diff --git a/backend/umax_pp_low.h b/backend/umax_pp_low.h index 7cef9dd..5e986c0 100644 --- a/backend/umax_pp_low.h +++ b/backend/umax_pp_low.h @@ -1,5 +1,5 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2001-2012 Stéphane Voltz + Copyright (C) 2001-2012 Stéphane Voltz This file is part of the SANE package. This program is free software; you can redistribute it and/or diff --git a/backend/umax_pp_mid.c b/backend/umax_pp_mid.c index ee8d98d..5f9fd5e 100644 --- a/backend/umax_pp_mid.c +++ b/backend/umax_pp_mid.c @@ -1,5 +1,5 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2001-2012 Stéphane Voltz + Copyright (C) 2001-2012 Stéphane Voltz This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -131,7 +131,7 @@ unlock_parport (void) -/* +/* * * This function recognize the scanner model by sending an image * filter command. 1220P will use it as is, but 2000P will return diff --git a/backend/umax_pp_mid.h b/backend/umax_pp_mid.h index 32245c6..5903a45 100644 --- a/backend/umax_pp_mid.h +++ b/backend/umax_pp_mid.h @@ -1,5 +1,5 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2001-2012 Stéphane Voltz + Copyright (C) 2001-2012 Stéphane Voltz This file is part of the SANE package. This program is free software; you can redistribute it and/or @@ -87,7 +87,7 @@ extern int sanei_umax_pp_attach (int port, char *name); extern int sanei_umax_pp_model (int port, int *model); -/* +/* if on=1 -> lights scanner lamp if on=0 -> lights off scanner lamp @@ -116,7 +116,7 @@ extern int sanei_umax_pp_open (int port, char *name); -/* +/* release any ressource acquired during open since there may be only one scanner, no port parameter */ @@ -145,9 +145,9 @@ extern int sanei_umax_pp_cancel (void); gain value is 256*red_gain+16*green_gain+blue_gain if gain is given (ie <> 0), auto gain will not be performed - - returns UMAX1220P_OK on success, or one of the error above + + returns UMAX1220P_OK on success, or one of the error above if successful, rbpp holds bytes/pixel, rth the height and rtw the width of scanned area expressed in pixels */ @@ -159,7 +159,7 @@ extern int sanei_umax_pp_start (int x, int y, int width, int height, int dpi, /* reads one block of data from scanner returns UMAX1220P_OK on success, or UMAX1220P_READ_FAILED on error it also sets internal cancel flag on error - + len if the length of the block needed window if the width in pixels of the scanned area dpi is the resolution, it is used to choose the best read method diff --git a/backend/v4l-frequencies.h b/backend/v4l-frequencies.h index 646120e..e926e7c 100644 --- a/backend/v4l-frequencies.h +++ b/backend/v4l-frequencies.h @@ -3,7 +3,7 @@ * * Nathan Laredo (laredo@broked.net) * - * Frequencies are given in kHz + * Frequencies are given in kHz */ #define NTSC_AUDIO_CARRIER 4500 #define PAL_AUDIO_CARRIER_I 6000 @@ -16,7 +16,7 @@ containing 8 bits frame sync, 5 bits control, 11 bits additional data, and 704 bits audio data. The bit rate is reduced by transmitting only 10 bits plus parity of each 14 bit sample, the largest sample in a frame determines - which 10 bits are transmitted. The parity bits for audio samples also + which 10 bits are transmitted. The parity bits for audio samples also specify the scaling factor used for that channel during that frame. The companeded audio data is interleaved to reduce the influence of dropouts and the whole frame except for sync bits is scrambled for spectrum shaping. diff --git a/backend/v4l.c b/backend/v4l.c index 1e032c7..006e7f7 100644 --- a/backend/v4l.c +++ b/backend/v4l.c @@ -653,7 +653,7 @@ sane_open (SANE_String_Const devname, SANE_Handle * handle) DBG (5, "sane_open: x=%d, y=%d, width=%d, height=%d\n", s->window.x, s->window.y, s->window.width, s->window.height); - /* already done in sane_start + /* already done in sane_start if (-1 == v4l1_ioctl (v4lfd, VIDIOCGMBUF, &mbuf)) DBG (1, "sane_open: can't ioctl VIDIOCGMBUF (no Fbuffer?)\n"); */ diff --git a/backend/v4l.h b/backend/v4l.h index 6aee586..e6673d0 100644 --- a/backend/v4l.h +++ b/backend/v4l.h @@ -73,7 +73,7 @@ struct video_picture #define VIDEO_PALETTE_HI240 2 /* High 240 cube (BT848) */ #define VIDEO_PALETTE_RGB565 3 /* 565 16 bit RGB */ #define VIDEO_PALETTE_RGB24 4 /* 24bit RGB */ -#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ +#define VIDEO_PALETTE_RGB32 5 /* 32bit RGB */ #define VIDEO_PALETTE_RGB555 6 /* 555 15bit RGB */ #define VIDEO_PALETTE_YUV422 7 /* YUV422 capture */ #define VIDEO_PALETTE_YUYV 8 @@ -112,7 +112,7 @@ struct video_mbuf int frames; /* Frames */ int offsets[VIDEO_MAX_FRAME]; }; - + struct video_mmap { unsigned int frame; /* Frame (0 - n) for double buffer */ @@ -130,7 +130,7 @@ struct video_channel #define VIDEO_VC_AUDIO 2 /* Channel has audio */ __u16 type; #define VIDEO_TYPE_TV 1 -#define VIDEO_TYPE_CAMERA 2 +#define VIDEO_TYPE_CAMERA 2 __u16 norm; /* Norm set by channel */ }; diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index 8b8c895..b7fcbee 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -206,9 +206,13 @@ static int isSupportedDevice(struct device __sane_unused__ *dev) { #ifdef HAVE_LIBJPEG /* Checking device which supports JPEG Lossy compression for color scanning*/ - if (dev->compressionTypes & (1 << 6)) + if (dev->compressionTypes & (1 << 6)) { + /* blacklist malfunctioning device(s) */ + if (!strncmp(dev->sane.model, "SCX-4500W", 9) || + !strncmp(dev->sane.model, "M288x", 5)) + return 0; return 1; - else + } else return 0; #else return 0; diff --git a/backend/xerox_mfp.conf.in b/backend/xerox_mfp.conf.in index b17c7d7..39bf669 100644 --- a/backend/xerox_mfp.conf.in +++ b/backend/xerox_mfp.conf.in @@ -196,6 +196,12 @@ usb 0x04e8 0x3466 #Samsung C460 Series usb 0x04e8 0x3468 +#Samsung M2070 Series +usb 0x04e8 0x3469 + +#Samsung C1860FW +usb 0x04e8 0x346b + #Samsung M458x Series usb 0x04e8 0x346f @@ -208,6 +214,9 @@ usb 0x04e8 0x3477 #Samsung K401 Series usb 0x04e8 0x3478 +#Samsung C480W +usb 0x04e8 0x347e + #Samsung K3250 Series usb 0x04e8 0x3481 @@ -245,4 +254,3 @@ usb 0x413c 0x5124 #Dell 1235cn (clone of Samsung CLX-3175) usb 0x413c 0x5310 - -- cgit v1.2.3 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/.gitignore | 3 +- backend/Makefile.am | 154 +- backend/agfafocus.c | 1 + backend/apple.c | 3 +- backend/artec.c | 8 +- backend/artec_eplus48u.c | 2 +- backend/as6e.c | 28 +- backend/avision.c | 2 +- backend/avision.h | 2 +- backend/canon-sane.c | 4 +- backend/canon.c | 2 +- backend/canon630u-common.c | 4 +- backend/canon_dr.c | 35 +- backend/dc25.c | 2 +- backend/dll.c | 90 +- backend/dll.conf.in | 15 +- backend/epjitsu.c | 13 +- backend/epson2.c | 5 +- backend/epsonds.c | 5 +- backend/escl.conf.in | 17 + backend/escl/escl.c | 777 +++ backend/escl/escl.h | 171 + backend/escl/escl_capabilities.c | 377 ++ backend/escl/escl_devices.c | 185 + backend/escl/escl_jpeg.c | 230 + backend/escl/escl_newjob.c | 241 + backend/escl/escl_png.c | 193 + backend/escl/escl_reset.c | 75 + backend/escl/escl_scan.c | 99 + backend/escl/escl_status.c | 176 + backend/escl/escl_tiff.c | 119 + backend/fujitsu.c | 10 +- backend/fujitsu.conf.in | 3 + backend/genesys.cc | 7580 ---------------------------- backend/genesys.conf.in | 19 +- backend/genesys.h | 250 - backend/genesys/buffer.cpp | 102 + backend/genesys/buffer.h | 89 + backend/genesys/calibration.h | 108 + backend/genesys/command_set.h | 166 + backend/genesys/conv.cpp | 238 + backend/genesys/conv.h | 69 + backend/genesys/device.cpp | 272 + backend/genesys/device.h | 387 ++ backend/genesys/enums.cpp | 131 + backend/genesys/enums.h | 530 ++ backend/genesys/error.cpp | 215 + backend/genesys/error.h | 199 + backend/genesys/fwd.h | 132 + backend/genesys/genesys.cpp | 6172 ++++++++++++++++++++++ backend/genesys/genesys.h | 258 + backend/genesys/gl124.cpp | 2269 +++++++++ backend/genesys/gl124.h | 205 + backend/genesys/gl124_registers.h | 316 ++ backend/genesys/gl646.cpp | 3436 +++++++++++++ backend/genesys/gl646.h | 521 ++ backend/genesys/gl646_registers.h | 176 + backend/genesys/gl841.cpp | 4010 +++++++++++++++ backend/genesys/gl841.h | 130 + backend/genesys/gl841_registers.h | 269 + backend/genesys/gl843.cpp | 3060 +++++++++++ backend/genesys/gl843.h | 139 + backend/genesys/gl843_registers.h | 382 ++ backend/genesys/gl846.cpp | 2098 ++++++++ backend/genesys/gl846.h | 218 + backend/genesys/gl846_registers.h | 351 ++ backend/genesys/gl847.cpp | 2140 ++++++++ backend/genesys/gl847.h | 206 + backend/genesys/gl847_registers.h | 333 ++ backend/genesys/image.cpp | 204 + backend/genesys/image.h | 87 + backend/genesys/image_buffer.cpp | 203 + backend/genesys/image_buffer.h | 129 + backend/genesys/image_pipeline.cpp | 839 +++ backend/genesys/image_pipeline.h | 572 +++ backend/genesys/image_pixel.cpp | 509 ++ backend/genesys/image_pixel.h | 144 + backend/genesys/low.cpp | 1994 ++++++++ backend/genesys/low.h | 525 ++ backend/genesys/motor.cpp | 180 + backend/genesys/motor.h | 177 + backend/genesys/register.h | 537 ++ backend/genesys/register_cache.h | 92 + backend/genesys/row_buffer.h | 214 + backend/genesys/scanner_interface.cpp | 52 + backend/genesys/scanner_interface.h | 112 + backend/genesys/scanner_interface_usb.cpp | 515 ++ backend/genesys/scanner_interface_usb.h | 98 + backend/genesys/sensor.cpp | 160 + backend/genesys/sensor.h | 470 ++ backend/genesys/serialize.cpp | 0 backend/genesys/serialize.h | 150 + backend/genesys/settings.cpp | 142 + backend/genesys/settings.h | 328 ++ backend/genesys/static_init.cpp | 70 + backend/genesys/static_init.h | 88 + backend/genesys/status.cpp | 66 + backend/genesys/status.h | 68 + backend/genesys/tables_frontend.cpp | 653 +++ backend/genesys/tables_gpo.cpp | 415 ++ backend/genesys/tables_model.cpp | 2958 +++++++++++ backend/genesys/tables_motor.cpp | 325 ++ backend/genesys/tables_motor_profile.cpp | 380 ++ backend/genesys/tables_sensor.cpp | 3668 ++++++++++++++ backend/genesys/test_scanner_interface.cpp | 229 + backend/genesys/test_scanner_interface.h | 122 + backend/genesys/test_settings.cpp | 106 + backend/genesys/test_settings.h | 70 + backend/genesys/test_usb_device.cpp | 141 + backend/genesys/test_usb_device.h | 85 + backend/genesys/usb_device.cpp | 147 + backend/genesys/usb_device.h | 118 + backend/genesys/utilities.h | 180 + backend/genesys_conv.cc | 474 -- backend/genesys_conv_hlp.cc | 345 -- backend/genesys_devices.cc | 5165 ------------------- backend/genesys_error.cc | 115 - backend/genesys_error.h | 202 - backend/genesys_gl124.cc | 3592 ------------- backend/genesys_gl124.h | 489 -- backend/genesys_gl646.cc | 4911 ------------------ backend/genesys_gl646.h | 594 --- backend/genesys_gl841.cc | 5624 --------------------- backend/genesys_gl841.h | 265 - backend/genesys_gl843.cc | 4415 ---------------- backend/genesys_gl843.h | 472 -- backend/genesys_gl846.cc | 3393 ------------- backend/genesys_gl846.h | 498 -- backend/genesys_gl847.cc | 3517 ------------- backend/genesys_gl847.h | 510 -- backend/genesys_low.cc | 2059 -------- backend/genesys_low.h | 2042 -------- backend/genesys_sanei.cc | 140 - backend/genesys_sanei.h | 97 - backend/genesys_serialize.cc | 0 backend/genesys_serialize.h | 144 - backend/gt68xx.c | 32 +- backend/hp-option.h | 2 +- backend/hp-scl.c | 4 +- backend/hp3900_config.c | 2 +- backend/hp3900_debug.c | 6 +- backend/hp3900_rts8822.c | 92 +- backend/hp3900_sane.c | 5 +- backend/hp3900_usb.c | 6 +- backend/hpsj5s.c | 9 +- backend/ibm.c | 10 +- backend/kodakaio.c | 5 +- backend/kvs1025_opt.c | 2 +- backend/kvs20xx_opt.c | 2 +- backend/kvs40xx.c | 9 +- backend/kvs40xx_opt.c | 18 +- backend/magicolor.c | 5 +- backend/microtek.c | 1 + backend/mustek_pp.c | 40 - backend/mustek_usb2_transparent.c | 2 +- backend/nec.c | 4 + backend/niash.c | 1 + backend/pieusb_buffer.h | 4 + backend/pieusb_specific.c | 6 +- backend/pixma.c | 2168 -------- backend/pixma.conf.in | 9 +- backend/pixma.h | 502 -- backend/pixma/pixma.c | 2166 ++++++++ backend/pixma/pixma.h | 506 ++ backend/pixma/pixma_bjnp.c | 2645 ++++++++++ backend/pixma/pixma_bjnp.h | 201 + backend/pixma/pixma_bjnp_private.h | 384 ++ backend/pixma/pixma_common.c | 1187 +++++ backend/pixma/pixma_common.h | 232 + backend/pixma/pixma_imageclass.c | 985 ++++ backend/pixma/pixma_io.h | 186 + backend/pixma/pixma_io_sanei.c | 556 ++ backend/pixma/pixma_mp150.c | 1817 +++++++ backend/pixma/pixma_mp730.c | 846 ++++ backend/pixma/pixma_mp750.c | 972 ++++ backend/pixma/pixma_mp800.c | 2434 +++++++++ backend/pixma/pixma_rename.h | 105 + backend/pixma/pixma_sane_options.c | 362 ++ backend/pixma/pixma_sane_options.h | 51 + backend/pixma/scripts/pixma_gen_options.py | 389 ++ backend/pixma_bjnp.c | 2558 ---------- backend/pixma_bjnp.h | 203 - backend/pixma_bjnp_private.h | 382 -- backend/pixma_common.c | 1187 ----- backend/pixma_common.h | 232 - backend/pixma_imageclass.c | 979 ---- backend/pixma_io.h | 186 - backend/pixma_io_sanei.c | 593 --- backend/pixma_mp150.c | 2013 -------- backend/pixma_mp730.c | 848 ---- backend/pixma_mp750.c | 970 ---- backend/pixma_mp810.c | 2388 --------- backend/pixma_rename.h | 105 - backend/pixma_sane_options.c | 362 -- backend/pixma_sane_options.h | 51 - backend/plustek-pp_motor.c | 1 + backend/plustek-usb.c | 14 +- backend/plustek-usbcal.c | 2 +- backend/plustek.c | 13 +- backend/plustek_pp.c | 2 +- backend/ricoh.c | 10 +- backend/ricoh2.c | 9 +- backend/ricoh2_buffer.c | 5 + backend/s9036.c | 1 + backend/sane_strstatus.c | 2 +- backend/scripts/pixma_gen_options.py | 389 -- backend/sharp.c | 1 + backend/sm3600.c | 8 +- backend/snapscan-options.c | 4 +- backend/stv680.c | 12 +- backend/umax_pp.c | 47 +- backend/umax_pp_low.c | 31 +- backend/umax_pp_low.h | 2 +- backend/umax_pp_mid.c | 2 +- backend/umax_pp_mid.h | 2 +- backend/xerox_mfp.c | 42 +- backend/xerox_mfp.h | 4 +- 217 files changed, 66881 insertions(+), 63361 deletions(-) create mode 100644 backend/escl.conf.in create mode 100644 backend/escl/escl.c create mode 100644 backend/escl/escl.h create mode 100644 backend/escl/escl_capabilities.c create mode 100644 backend/escl/escl_devices.c create mode 100644 backend/escl/escl_jpeg.c create mode 100644 backend/escl/escl_newjob.c create mode 100644 backend/escl/escl_png.c create mode 100644 backend/escl/escl_reset.c create mode 100644 backend/escl/escl_scan.c create mode 100644 backend/escl/escl_status.c create mode 100644 backend/escl/escl_tiff.c delete mode 100644 backend/genesys.cc delete mode 100644 backend/genesys.h create mode 100644 backend/genesys/buffer.cpp create mode 100644 backend/genesys/buffer.h create mode 100644 backend/genesys/calibration.h create mode 100644 backend/genesys/command_set.h create mode 100644 backend/genesys/conv.cpp create mode 100644 backend/genesys/conv.h create mode 100644 backend/genesys/device.cpp create mode 100644 backend/genesys/device.h create mode 100644 backend/genesys/enums.cpp create mode 100644 backend/genesys/enums.h create mode 100644 backend/genesys/error.cpp create mode 100644 backend/genesys/error.h create mode 100644 backend/genesys/fwd.h create mode 100644 backend/genesys/genesys.cpp create mode 100644 backend/genesys/genesys.h create mode 100644 backend/genesys/gl124.cpp create mode 100644 backend/genesys/gl124.h create mode 100644 backend/genesys/gl124_registers.h create mode 100644 backend/genesys/gl646.cpp create mode 100644 backend/genesys/gl646.h create mode 100644 backend/genesys/gl646_registers.h create mode 100644 backend/genesys/gl841.cpp create mode 100644 backend/genesys/gl841.h create mode 100644 backend/genesys/gl841_registers.h create mode 100644 backend/genesys/gl843.cpp create mode 100644 backend/genesys/gl843.h create mode 100644 backend/genesys/gl843_registers.h create mode 100644 backend/genesys/gl846.cpp create mode 100644 backend/genesys/gl846.h create mode 100644 backend/genesys/gl846_registers.h create mode 100644 backend/genesys/gl847.cpp create mode 100644 backend/genesys/gl847.h create mode 100644 backend/genesys/gl847_registers.h create mode 100644 backend/genesys/image.cpp create mode 100644 backend/genesys/image.h create mode 100644 backend/genesys/image_buffer.cpp create mode 100644 backend/genesys/image_buffer.h create mode 100644 backend/genesys/image_pipeline.cpp create mode 100644 backend/genesys/image_pipeline.h create mode 100644 backend/genesys/image_pixel.cpp create mode 100644 backend/genesys/image_pixel.h create mode 100644 backend/genesys/low.cpp create mode 100644 backend/genesys/low.h create mode 100644 backend/genesys/motor.cpp create mode 100644 backend/genesys/motor.h create mode 100644 backend/genesys/register.h create mode 100644 backend/genesys/register_cache.h create mode 100644 backend/genesys/row_buffer.h create mode 100644 backend/genesys/scanner_interface.cpp create mode 100644 backend/genesys/scanner_interface.h create mode 100644 backend/genesys/scanner_interface_usb.cpp create mode 100644 backend/genesys/scanner_interface_usb.h create mode 100644 backend/genesys/sensor.cpp create mode 100644 backend/genesys/sensor.h create mode 100644 backend/genesys/serialize.cpp create mode 100644 backend/genesys/serialize.h create mode 100644 backend/genesys/settings.cpp create mode 100644 backend/genesys/settings.h create mode 100644 backend/genesys/static_init.cpp create mode 100644 backend/genesys/static_init.h create mode 100644 backend/genesys/status.cpp create mode 100644 backend/genesys/status.h create mode 100644 backend/genesys/tables_frontend.cpp create mode 100644 backend/genesys/tables_gpo.cpp create mode 100644 backend/genesys/tables_model.cpp create mode 100644 backend/genesys/tables_motor.cpp create mode 100644 backend/genesys/tables_motor_profile.cpp create mode 100644 backend/genesys/tables_sensor.cpp create mode 100644 backend/genesys/test_scanner_interface.cpp create mode 100644 backend/genesys/test_scanner_interface.h create mode 100644 backend/genesys/test_settings.cpp create mode 100644 backend/genesys/test_settings.h create mode 100644 backend/genesys/test_usb_device.cpp create mode 100644 backend/genesys/test_usb_device.h create mode 100644 backend/genesys/usb_device.cpp create mode 100644 backend/genesys/usb_device.h create mode 100644 backend/genesys/utilities.h delete mode 100644 backend/genesys_conv.cc delete mode 100644 backend/genesys_conv_hlp.cc delete mode 100644 backend/genesys_devices.cc delete mode 100644 backend/genesys_error.cc delete mode 100644 backend/genesys_error.h delete mode 100644 backend/genesys_gl124.cc delete mode 100644 backend/genesys_gl124.h delete mode 100644 backend/genesys_gl646.cc delete mode 100644 backend/genesys_gl646.h delete mode 100644 backend/genesys_gl841.cc delete mode 100644 backend/genesys_gl841.h delete mode 100644 backend/genesys_gl843.cc delete mode 100644 backend/genesys_gl843.h delete mode 100644 backend/genesys_gl846.cc delete mode 100644 backend/genesys_gl846.h delete mode 100644 backend/genesys_gl847.cc delete mode 100644 backend/genesys_gl847.h delete mode 100644 backend/genesys_low.cc delete mode 100644 backend/genesys_low.h delete mode 100644 backend/genesys_sanei.cc delete mode 100644 backend/genesys_sanei.h delete mode 100644 backend/genesys_serialize.cc delete mode 100644 backend/genesys_serialize.h delete mode 100644 backend/pixma.c delete mode 100644 backend/pixma.h create mode 100644 backend/pixma/pixma.c create mode 100644 backend/pixma/pixma.h create mode 100644 backend/pixma/pixma_bjnp.c create mode 100644 backend/pixma/pixma_bjnp.h create mode 100644 backend/pixma/pixma_bjnp_private.h create mode 100644 backend/pixma/pixma_common.c create mode 100644 backend/pixma/pixma_common.h create mode 100644 backend/pixma/pixma_imageclass.c create mode 100644 backend/pixma/pixma_io.h create mode 100644 backend/pixma/pixma_io_sanei.c create mode 100644 backend/pixma/pixma_mp150.c create mode 100644 backend/pixma/pixma_mp730.c create mode 100644 backend/pixma/pixma_mp750.c create mode 100644 backend/pixma/pixma_mp800.c create mode 100644 backend/pixma/pixma_rename.h create mode 100644 backend/pixma/pixma_sane_options.c create mode 100644 backend/pixma/pixma_sane_options.h create mode 100755 backend/pixma/scripts/pixma_gen_options.py delete mode 100644 backend/pixma_bjnp.c delete mode 100644 backend/pixma_bjnp.h delete mode 100644 backend/pixma_bjnp_private.h delete mode 100644 backend/pixma_common.c delete mode 100644 backend/pixma_common.h delete mode 100644 backend/pixma_imageclass.c delete mode 100644 backend/pixma_io.h delete mode 100644 backend/pixma_io_sanei.c delete mode 100644 backend/pixma_mp150.c delete mode 100644 backend/pixma_mp730.c delete mode 100644 backend/pixma_mp750.c delete mode 100644 backend/pixma_mp810.c delete mode 100644 backend/pixma_rename.h delete mode 100644 backend/pixma_sane_options.c delete mode 100644 backend/pixma_sane_options.h delete mode 100755 backend/scripts/pixma_gen_options.py (limited to 'backend') diff --git a/backend/.gitignore b/backend/.gitignore index 6ebfbd5..6276e61 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,5 +1,6 @@ *-s.c -*-s.cc +*-s.cpp *.conf +.dirstamp dll-preload.c dll-preload.h diff --git a/backend/Makefile.am b/backend/Makefile.am index 44d1e17..1dc1a58 100644 --- a/backend/Makefile.am +++ b/backend/Makefile.am @@ -17,7 +17,12 @@ DIST_LIBS_LDFLAGS = $(AM_LDFLAGS) -rpath '$(libdir)' -version-number $(V_MAJOR): LIBTOOL += --silent FIRMWARE_DIRS = artec_eplus48u gt68xx snapscan epjitsu +# Needed by most backends as they add sane_strstatus.lo to their list +# of libraries to link with via libsane_${BACKEND}_la_LIBADD. Due to +# the implicit dependency, automake does not notice the need to clean +# up the dependency tracking file. EXTRA_DIST = sane_strstatus.c +CLEANFILES = $(DEPDIR)/sane_strstatus.Plo all: becfg @@ -29,7 +34,7 @@ EXTRA_DIST += stubs.c $(AM_V_at)rm -f $@ $(AM_V_at)$(LN_S) $(srcdir)/stubs.c $@ -%-s.cc: $(srcdir)/stubs.c +%-s.cpp: $(srcdir)/stubs.c $(AM_V_at)rm -f $@ $(AM_V_at)$(LN_S) $(srcdir)/stubs.c $@ @@ -63,8 +68,8 @@ BACKEND_CONFS= abaton.conf agfafocus.conf apple.conf artec.conf \ canon_pp.conf cardscan.conf coolscan2.conf coolscan3.conf \ coolscan.conf dc210.conf dc240.conf dc25.conf \ dell1600n_net.conf dmc.conf epjitsu.conf epson2.conf \ - epson.conf epsonds.conf fujitsu.conf genesys.conf gphoto2.conf \ - gt68xx.conf hp3900.conf hp4200.conf hp5400.conf \ + epson.conf epsonds.conf escl.conf fujitsu.conf genesys.conf \ + gphoto2.conf gt68xx.conf hp3900.conf hp4200.conf hp5400.conf \ hp.conf hpsj5s.conf hs2p.conf ibm.conf kodak.conf kodakaio.conf\ kvs1025.conf \ leo.conf lexmark.conf ma1509.conf magicolor.conf \ @@ -133,7 +138,7 @@ uninstall-hook: rmdir $(DESTDIR)$(datadir)/sane/$${dir} ; \ done -CLEANFILES = $(BACKEND_CONFS) $(be_convenience_libs) +CLEANFILES += $(BACKEND_CONFS) $(be_convenience_libs) clean-local: find . -type l -name \*-s.c | xargs rm -f @@ -156,7 +161,7 @@ be_convenience_libs = libabaton.la libagfafocus.la \ libcoolscan2.la libcoolscan3.la libdc25.la \ libdc210.la libdc240.la libdell1600n_net.la \ libdmc.la libdll.la libdll_preload.la libepjitsu.la libepson.la \ - libepson2.la libepsonds.la libfujitsu.la libgenesys.la \ + libepson2.la libepsonds.la libescl.la libfujitsu.la libgenesys.la \ libgphoto2_i.la libgt68xx.la libhp.la \ libhp3500.la libhp3900.la libhp4200.la \ libhp5400.la libhp5590.la libhpljm1005.la \ @@ -189,8 +194,8 @@ be_dlopen_libs = libsane-abaton.la libsane-agfafocus.la \ libsane-coolscan2.la libsane-coolscan3.la libsane-dc25.la \ libsane-dc210.la libsane-dc240.la libsane-dell1600n_net.la \ libsane-dmc.la libsane-epjitsu.la libsane-epson.la \ - libsane-epson2.la libsane-epsonds.la libsane-fujitsu.la libsane-genesys.la \ - libsane-gphoto2.la libsane-gt68xx.la libsane-hp.la \ + libsane-epson2.la libsane-epsonds.la libsane-escl.la libsane-fujitsu.la \ + libsane-genesys.la libsane-gphoto2.la libsane-gt68xx.la libsane-hp.la \ libsane-hp3500.la libsane-hp3900.la libsane-hp4200.la \ libsane-hp5400.la libsane-hp5590.la libsane-hpljm1005.la \ libsane-hpsj5s.la libsane-hs2p.la libsane-ibm.la libsane-kodak.la libsane-kodakaio.la\ @@ -219,7 +224,7 @@ lib_LTLIBRARIES = libsane.la sanelibdir = $(libdir)/sane sanelib_LTLIBRARIES = $(BACKEND_LIBS_ENABLED) libsane-dll.la -COMMON_LIBS = ../lib/liblib.la +COMMON_LIBS = ../lib/liblib.la $(XML_LIBS) # Each backend should define a convenience library that compiles # all related files within backend directory. General guideline @@ -252,7 +257,7 @@ libagfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus nodist_libsane_agfafocus_la_SOURCES = agfafocus-s.c libsane_agfafocus_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=agfafocus libsane_agfafocus_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_agfafocus_la_LIBADD = $(COMMON_LIBS) libagfafocus.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_agfafocus_la_LIBADD = $(COMMON_LIBS) libagfafocus.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += agfafocus.conf.in libapple_la_SOURCES = apple.c apple.h @@ -279,7 +284,7 @@ libartec_eplus48u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=artec_eplus48u nodist_libsane_artec_eplus48u_la_SOURCES = artec_eplus48u-s.c libsane_artec_eplus48u_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=artec_eplus48u libsane_artec_eplus48u_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_artec_eplus48u_la_LIBADD = $(COMMON_LIBS) libartec_eplus48u.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMEG_LIBS) +libsane_artec_eplus48u_la_LIBADD = $(COMMON_LIBS) libartec_eplus48u.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMEG_LIBS) EXTRA_DIST += artec_eplus48u.conf.in libas6e_la_SOURCES = as6e.c as6e.h @@ -296,7 +301,7 @@ libavision_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=avision nodist_libsane_avision_la_SOURCES = avision-s.c libsane_avision_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=avision libsane_avision_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_avision_la_LIBADD = $(COMMON_LIBS) libavision.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_avision_la_LIBADD = $(COMMON_LIBS) libavision.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += avision.conf.in libbh_la_SOURCES = bh.c bh.h @@ -363,7 +368,7 @@ libcoolscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan nodist_libsane_coolscan_la_SOURCES = coolscan-s.c libsane_coolscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=coolscan libsane_coolscan_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_coolscan_la_LIBADD = $(COMMON_LIBS) libcoolscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_coolscan_la_LIBADD = $(COMMON_LIBS) libcoolscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += coolscan.conf.in libcoolscan2_la_SOURCES = coolscan2.c @@ -429,6 +434,21 @@ libsane_dmc_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_dmc_la_LIBADD = $(COMMON_LIBS) libdmc.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(RESMGR_LIBS) EXTRA_DIST += dmc.conf.in +if have_libavahi +if have_libcurl +if have_libxml2 +libescl_la_SOURCES = escl/escl.c escl/escl_capabilities.c escl/escl_devices.c escl/escl.h escl/escl_newjob.c escl/escl_reset.c escl/escl_scan.c escl/escl_status.c escl/escl_jpeg.c escl/escl_png.c escl/escl_tiff.c +libescl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl + +nodist_libsane_escl_la_SOURCES = escl-s.c +libsane_escl_la_CPPFLAGS = $(AM_CPPFLAGS) $(JPEG_CFLAGS) $(PNG_CFLAGS) $(TIFF_CFLAGS) $(XML_CFLAGS) $(libcurl_CFLAGS) $(AVAHI_CFLAGS) -DBACKEND_NAME=escl +libsane_escl_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) +libsane_escl_la_LIBADD = $(COMMON_LIBS) libescl.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo $(JPEG_LIBS) $(PNG_LIBS) $(TIFF_LIBS) $(XML_LIBS) $(libcurl_LIBS) $(AVAHI_LIBS) +endif +endif +endif +EXTRA_DIST += escl.conf.in + libepjitsu_la_SOURCES = epjitsu.c epjitsu.h epjitsu-cmd.h libepjitsu_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=epjitsu @@ -480,22 +500,56 @@ libsane_fujitsu_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_fujitsu_la_LIBADD = $(COMMON_LIBS) libfujitsu.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_magic.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(RESMGR_LIBS) EXTRA_DIST += fujitsu.conf.in -libgenesys_la_SOURCES = genesys.cc genesys.h genesys_sanei.h genesys_sanei.cc genesys_error.h genesys_error.cc \ - genesys_serialize.h \ - genesys_gl646.cc genesys_gl646.h genesys_gl841.cc genesys_gl841.h \ - genesys_gl843.cc genesys_gl843.h genesys_gl846.cc genesys_gl846.h \ - genesys_gl847.cc genesys_gl847.h genesys_gl124.cc genesys_gl124.h \ - genesys_low.cc genesys_low.h +libgenesys_la_SOURCES = genesys/genesys.cpp genesys/genesys.h \ + genesys/buffer.h genesys/buffer.cpp \ + genesys/calibration.h \ + genesys/command_set.h \ + genesys/conv.h genesys/conv.cpp \ + genesys/device.h genesys/device.cpp \ + genesys/enums.h genesys/enums.cpp \ + genesys/error.h genesys/error.cpp \ + genesys/fwd.h \ + genesys/gl646.cpp genesys/gl646.h genesys/gl646_registers.h \ + genesys/gl124.cpp genesys/gl124.h genesys/gl124_registers.h \ + genesys/gl841.cpp genesys/gl841.h genesys/gl841_registers.h \ + genesys/gl843.cpp genesys/gl843.h genesys/gl843_registers.h \ + genesys/gl846.cpp genesys/gl846.h genesys/gl846_registers.h \ + genesys/gl847.cpp genesys/gl847.h genesys/gl847_registers.h \ + genesys/row_buffer.h \ + genesys/image_buffer.h genesys/image_buffer.cpp \ + genesys/image_pipeline.h genesys/image_pipeline.cpp \ + genesys/image_pixel.h genesys/image_pixel.cpp \ + genesys/image.h genesys/image.cpp \ + genesys/motor.h genesys/motor.cpp \ + genesys/register.h \ + genesys/register_cache.h \ + genesys/scanner_interface.h genesys/scanner_interface.cpp \ + genesys/scanner_interface_usb.h genesys/scanner_interface_usb.cpp \ + genesys/sensor.h genesys/sensor.cpp \ + genesys/settings.h genesys/settings.cpp \ + genesys/serialize.h \ + genesys/static_init.h genesys/static_init.cpp \ + genesys/status.h genesys/status.cpp \ + genesys/tables_frontend.cpp \ + genesys/tables_gpo.cpp \ + genesys/tables_model.cpp \ + genesys/tables_motor.cpp \ + genesys/tables_motor_profile.cpp \ + genesys/tables_sensor.cpp \ + genesys/test_scanner_interface.h genesys/test_scanner_interface.cpp \ + genesys/test_settings.h genesys/test_settings.cpp \ + genesys/test_usb_device.h genesys/test_usb_device.cpp \ + genesys/usb_device.h genesys/usb_device.cpp \ + genesys/low.cpp genesys/low.h \ + genesys/utilities.h libgenesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys -nodist_libsane_genesys_la_SOURCES = genesys-s.cc +nodist_libsane_genesys_la_SOURCES = genesys-s.cpp libsane_genesys_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=genesys libsane_genesys_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_genesys_la_LIBADD = $(COMMON_LIBS) libgenesys.la ../sanei/sanei_magic.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(USB_LIBS) $(RESMGR_LIBS) EXTRA_DIST += genesys.conf.in -# TODO: Why are this distributed but not compiled? -EXTRA_DIST += genesys_conv.cc genesys_conv_hlp.cc genesys_devices.cc libgphoto2_i_la_SOURCES = gphoto2.c gphoto2.h libgphoto2_i_la_CPPFLAGS = $(AM_CPPFLAGS) $(GPHOTO2_CPPFLAGS) -DBACKEND_NAME=gphoto2 @@ -523,7 +577,7 @@ libhp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp nodist_libsane_hp_la_SOURCES = hp-s.c libsane_hp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp libsane_hp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp_la_LIBADD = $(COMMON_LIBS) libhp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pio.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_hp_la_LIBADD = $(COMMON_LIBS) libhp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pio.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += hp.conf.in # TODO: These should be moved to ../docs/hp; don't belong here. EXTRA_DIST += hp.README hp.TODO @@ -534,7 +588,7 @@ libhp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500 nodist_libsane_hp3500_la_SOURCES = hp3500-s.c libsane_hp3500_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3500 libsane_hp3500_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_hp3500_la_LIBADD = $(COMMON_LIBS) libhp3500.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) libhp3900_la_SOURCES = hp3900.c libhp3900_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=hp3900 @@ -726,7 +780,7 @@ libmicrotek2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=microtek2 nodist_libsane_microtek2_la_SOURCES = microtek2-s.c libsane_microtek2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=microtek2 libsane_microtek2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_microtek2_la_LIBADD = $(COMMON_LIBS) libmicrotek2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_microtek2_la_LIBADD = $(COMMON_LIBS) libmicrotek2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += microtek2.conf.in libmustek_la_SOURCES = mustek.c mustek.h @@ -735,7 +789,7 @@ libmustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek nodist_libsane_mustek_la_SOURCES = mustek-s.c libsane_mustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek libsane_mustek_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_mustek_la_LIBADD = $(COMMON_LIBS) libmustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pa4s2.lo $(IEEE1284_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_mustek_la_LIBADD = $(COMMON_LIBS) libmustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pa4s2.lo $(IEEE1284_LIBS) $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += mustek.conf.in # TODO: Why are these distributed but not compiled? EXTRA_DIST += mustek_scsi_pp.c mustek_scsi_pp.h @@ -768,7 +822,7 @@ libmustek_usb2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb2 nodist_libsane_mustek_usb2_la_SOURCES = mustek_usb2-s.c libsane_mustek_usb2_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=mustek_usb2 libsane_mustek_usb2_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_mustek_usb2_la_LIBADD = $(COMMON_LIBS) libmustek_usb2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(PTHREAD_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_mustek_usb2_la_LIBADD = $(COMMON_LIBS) libmustek_usb2.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo $(MATH_LIB) $(PTHREAD_LIBS) $(USB_LIBS) $(RESMGR_LIBS) # TODO: Why are these distributed but not compiled? EXTRA_DIST += mustek_usb2_asic.c mustek_usb2_asic.h mustek_usb2_high.c mustek_usb2_high.h mustek_usb2_reflective.c mustek_usb2_transparent.c @@ -806,7 +860,7 @@ libpie_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pie nodist_libsane_pie_la_SOURCES = pie-s.c libsane_pie_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pie libsane_pie_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pie_la_LIBADD = $(COMMON_LIBS) libpie.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_pie_la_LIBADD = $(COMMON_LIBS) libpie.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += pie.conf.in libpieusb_la_SOURCES = pieusb.h pieusb_buffer.c pieusb_buffer.h pieusb_scancmd.c pieusb_scancmd.h pieusb_specific.c pieusb_specific.h pieusb_usb.c pieusb_usb.h pieusb.c @@ -815,7 +869,7 @@ libpieusb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pieusb nodist_libsane_pieusb_la_SOURCES = pieusb-s.c libsane_pieusb_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pieusb libsane_pieusb_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pieusb_la_LIBADD = $(COMMON_LIBS) libpieusb.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_ir.lo ../sanei/sanei_magic.lo $(PTHREAD_LIBS) $(RESMGR_LIBS) $(USB_LIBS) $(MATH_LIB) +libsane_pieusb_la_LIBADD = $(COMMON_LIBS) libpieusb.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_scsi.lo ../sanei/sanei_thread.lo ../sanei/sanei_usb.lo ../sanei/sanei_ir.lo ../sanei/sanei_magic.lo $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) $(USB_LIBS) $(MATH_LIB) EXTRA_DIST += pieusb.conf.in libp5_la_SOURCES = p5.c p5.h p5_device.h @@ -835,16 +889,30 @@ libsane_pint_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pint libsane_pint_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) libsane_pint_la_LIBADD = $(COMMON_LIBS) libpint.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo -libpixma_la_SOURCES = pixma.c pixma.h pixma_io_sanei.c pixma_io.h pixma_common.c pixma_common.h pixma_mp150.c pixma_mp730.c pixma_mp750.c pixma_mp810.c pixma_imageclass.c pixma_bjnp.c pixma_bjnp.h pixma_bjnp_private.h pixma_rename.h +libpixma_la_SOURCES = pixma/pixma.c \ + pixma/pixma.h \ + pixma/pixma_io_sanei.c \ + pixma/pixma_io.h \ + pixma/pixma_common.c \ + pixma/pixma_common.h \ + pixma/pixma_mp150.c \ + pixma/pixma_mp730.c \ + pixma/pixma_mp750.c \ + pixma/pixma_mp800.c \ + pixma/pixma_imageclass.c \ + pixma/pixma_bjnp.c \ + pixma/pixma_bjnp.h \ + pixma/pixma_bjnp_private.h \ + pixma/pixma_rename.h libpixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma nodist_libsane_pixma_la_SOURCES = pixma-s.c libsane_pixma_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=pixma libsane_pixma_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_pixma_la_LIBADD = $(COMMON_LIBS) libpixma.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(SANEI_SANEI_JPEG_LO) $(JPEG_LIBS) $(MATH_LIB) $(SOCKET_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += pixma.conf.in -# TODO: Why are these distributed but not compiled? -EXTRA_DIST += pixma_sane_options.c pixma_sane_options.h +# included in pixma.c +EXTRA_DIST += pixma/pixma_sane_options.c pixma/pixma_sane_options.h libplustek_la_SOURCES = plustek.c plustek.h libplustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek @@ -852,7 +920,7 @@ libplustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek nodist_libsane_plustek_la_SOURCES = plustek-s.c libsane_plustek_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek libsane_plustek_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_plustek_la_LIBADD = $(COMMON_LIBS) libplustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_plustek_la_LIBADD = $(COMMON_LIBS) libplustek.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo $(MATH_LIB) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += plustek.conf.in EXTRA_DIST += plustek-usb.c plustek-usb.h plustek-usbcal.c plustek-usbcalfile.c plustek-usbdevs.c plustek-usbhw.c plustek-usbimg.c plustek-usbio.c plustek-usbmap.c plustek-usbscan.c plustek-usbshading.c @@ -862,7 +930,7 @@ libplustek_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek_pp nodist_libsane_plustek_pp_la_SOURCES = plustek_pp-s.c libsane_plustek_pp_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=plustek_pp libsane_plustek_pp_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_plustek_pp_la_LIBADD = $(COMMON_LIBS) libplustek_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(IEEE1284_LIBS) $(PTHREAD_LIBS) +libsane_plustek_pp_la_LIBADD = $(COMMON_LIBS) libplustek_pp.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(IEEE1284_LIBS) $(SANEI_THREAD_LIBS) EXTRA_DIST += plustek_pp.conf.in # TODO: Why are these distributed but not compiled? EXTRA_DIST += plustek-pp_dac.c plustek-pp_dbg.h plustek-pp_detect.c plustek-pp_genericio.c plustek-pp_hwdefs.h plustek-pp_image.c plustek-pp_io.c plustek-pp_map.c plustek-pp_misc.c plustek-pp_models.c plustek-pp_motor.c plustek-pp_p12.c plustek-pp_p12ccd.c plustek-pp_p48xx.c plustek-pp_p9636.c plustek-pp_procfs.c plustek-pp_procs.h plustek-pp_ptdrv.c plustek-pp_scale.c plustek-pp_scan.h plustek-pp_scandata.h plustek-pp_sysdep.h plustek-pp_tpa.c plustek-pp_types.h plustek-pp_wrapper.c @@ -969,7 +1037,7 @@ libsnapscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=snapscan nodist_libsane_snapscan_la_SOURCES = snapscan-s.c libsane_snapscan_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=snapscan libsane_snapscan_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_snapscan_la_LIBADD = $(COMMON_LIBS) libsnapscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_snapscan_la_LIBADD = $(COMMON_LIBS) libsnapscan.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += snapscan.conf.in # TODO: Why are these distributed but not compiled? EXTRA_DIST += snapscan-data.c snapscan-mutex.c snapscan-options.c snapscan-scsi.c snapscan-sources.c snapscan-sources.h snapscan-usb.c snapscan-usb.h @@ -980,7 +1048,7 @@ libsp15c_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sp15c nodist_libsane_sp15c_la_SOURCES = sp15c-s.c libsane_sp15c_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=sp15c libsane_sp15c_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_sp15c_la_LIBADD = $(COMMON_LIBS) libsp15c.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_sp15c_la_LIBADD = $(COMMON_LIBS) libsp15c.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += sp15c.conf.in libst400_la_SOURCES = st400.c st400.h @@ -1007,7 +1075,7 @@ libtamarack_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=tamarack nodist_libsane_tamarack_la_SOURCES = tamarack-s.c libsane_tamarack_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=tamarack libsane_tamarack_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_tamarack_la_LIBADD = $(COMMON_LIBS) libtamarack.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_tamarack_la_LIBADD = $(COMMON_LIBS) libtamarack.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += tamarack.conf.in libtest_la_SOURCES = test.c test.h @@ -1016,7 +1084,7 @@ libtest_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=test nodist_libsane_test_la_SOURCES = test-s.c libsane_test_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=test libsane_test_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_test_la_LIBADD = $(COMMON_LIBS) libtest.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_thread.lo $(PTHREAD_LIBS) +libsane_test_la_LIBADD = $(COMMON_LIBS) libtest.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_thread.lo $(SANEI_THREAD_LIBS) EXTRA_DIST += test.conf.in # TODO: Why are these distributed but not compiled? EXTRA_DIST += test-picture.c @@ -1054,7 +1122,7 @@ libu12_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=u12 nodist_libsane_u12_la_SOURCES = u12-s.c libsane_u12_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=u12 libsane_u12_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_u12_la_LIBADD = $(COMMON_LIBS) libu12.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_u12_la_LIBADD = $(COMMON_LIBS) libu12.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo $(MATH_LIB) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += u12.conf.in # TODO: Why are these distributed but not compiled? EXTRA_DIST += u12-ccd.c u12-hw.c u12-hwdef.h u12-if.c u12-image.c u12-io.c u12-map.c u12-motor.c u12-scanner.h u12-shading.c u12-tpa.c @@ -1065,7 +1133,7 @@ libumax_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax nodist_libsane_umax_la_SOURCES = umax-s.c libsane_umax_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=umax libsane_umax_la_LDFLAGS = $(DIST_SANELIBS_LDFLAGS) -libsane_umax_la_LIBADD = $(COMMON_LIBS) libumax.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +libsane_umax_la_LIBADD = $(COMMON_LIBS) libumax.la ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo ../sanei/sanei_config2.lo sane_strstatus.lo ../sanei/sanei_usb.lo ../sanei/sanei_thread.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo $(MATH_LIB) $(SCSI_LIBS) $(USB_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) EXTRA_DIST += umax.conf.in # TODO: Why are these distributed but not compiled? EXTRA_DIST += umax-scanner.c umax-scanner.h umax-scsidef.h umax-uc1200s.c umax-uc1200se.c umax-uc1260.c umax-uc630.c umax-uc840.c umax-ug630.c umax-ug80.c umax-usb.c @@ -1110,8 +1178,10 @@ EXTRA_DIST += xerox_mfp.conf.in libdll_preload_la_SOURCES = dll.c libdll_preload_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll -DENABLE_PRELOAD +libdll_preload_la_LIBADD = ../sanei/sanei_usb.lo $(USB_LIBS) $(XML_LIBS) libdll_la_SOURCES = dll.c libdll_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll +libdll_la_LIBADD = ../sanei/sanei_usb.lo $(USB_LIBS) $(XML_LIBS) BUILT_SOURCES = dll-preload.h CLEANFILES += dll-preload.h @@ -1142,13 +1212,13 @@ EXTRA_DIST += dll.aliases # what backends are preloaded. It should include what is needed by # those backends that are actually preloaded. if preloadable_backends_enabled -PRELOADABLE_BACKENDS_LIBS = ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(PTHREAD_LIBS) $(RESMGR_LIBS) +PRELOADABLE_BACKENDS_LIBS = ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(LIBV4L_LIBS) $(MATH_LIB) $(IEEE1284_LIBS) $(TIFF_LIBS) $(JPEG_LIBS) $(GPHOTO2_LIBS) $(SOCKET_LIBS) $(USB_LIBS) $(AVAHI_LIBS) $(SCSI_LIBS) $(SANEI_THREAD_LIBS) $(RESMGR_LIBS) $(XML_LIBS) PRELOADABLE_BACKENDS_DEPS = ../sanei/sanei_config2.lo ../sanei/sanei_usb.lo ../sanei/sanei_scsi.lo ../sanei/sanei_pv8630.lo ../sanei/sanei_pp.lo ../sanei/sanei_thread.lo ../sanei/sanei_lm983x.lo ../sanei/sanei_access.lo ../sanei/sanei_net.lo ../sanei/sanei_wire.lo ../sanei/sanei_codec_bin.lo ../sanei/sanei_pa4s2.lo ../sanei/sanei_ab306.lo ../sanei/sanei_pio.lo ../sanei/sanei_tcp.lo ../sanei/sanei_udp.lo ../sanei/sanei_magic.lo $(SANEI_SANEI_JPEG_LO) endif nodist_libsane_la_SOURCES = dll-s.c libsane_la_CPPFLAGS = $(AM_CPPFLAGS) -DBACKEND_NAME=dll libsane_la_LDFLAGS = $(DIST_LIBS_LDFLAGS) -libsane_la_LIBADD = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo $(PRELOADABLE_BACKENDS_LIBS) $(DL_LIBS) +libsane_la_LIBADD = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo $(PRELOADABLE_BACKENDS_LIBS) $(DL_LIBS) $(XML_LIBS) # WARNING: Automake is getting this wrong so have to do it ourselves. libsane_la_DEPENDENCIES = $(COMMON_LIBS) $(PRELOADABLE_BACKENDS_ENABLED) libdll_preload.la sane_strstatus.lo ../sanei/sanei_init_debug.lo ../sanei/sanei_constrain_value.lo ../sanei/sanei_config.lo $(PRELOADABLE_BACKENDS_DEPS) diff --git a/backend/agfafocus.c b/backend/agfafocus.c index 0b59d2d..8177f38 100644 --- a/backend/agfafocus.c +++ b/backend/agfafocus.c @@ -1485,6 +1485,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_BR_Y: if (info) *info |= SANE_INFO_RELOAD_PARAMS; + // fall through case OPT_SHARPEN: case OPT_EXPOSURE: case OPT_ATTENUATION_RED: diff --git a/backend/apple.c b/backend/apple.c index 167f6ea..980edb4 100644 --- a/backend/apple.c +++ b/backend/apple.c @@ -2064,7 +2064,8 @@ sane_control_option (SANE_Handle handle, SANE_Int option, v2 = SANE_UNFIX (f); DBG (FLOW_CONTROL, "Value %g (Fixed)\n", (action == SANE_ACTION_GET_VALUE) ? v1 : v2); - } + break; + } default: DBG (FLOW_CONTROL, "Value %u (Int).\n", (action == SANE_ACTION_GET_VALUE) diff --git a/backend/artec.c b/backend/artec.c index 2ba8d6d..395b4f1 100644 --- a/backend/artec.c +++ b/backend/artec.c @@ -1999,8 +1999,8 @@ attach (const char *devname, ARTEC_Device ** devp) DBG (6, "Found BlackWidow BW4800SP scanner, setting up like AT3\n"); /* setup the vendor and product to mimic the Artec/Ultima AT3 */ - strncpy (result + 8, "ULTIMA", 6); - strncpy (result + 16, "AT3 ", 16); + memcpy (result + 8, "ULTIMA", 6); + memcpy (result + 16, "AT3 ", 16); } /* @@ -2013,8 +2013,8 @@ attach (const char *devname, ARTEC_Device ** devp) DBG (6, "Found Plustek 19200S scanner, setting up like AM12S\n"); /* setup the vendor and product to mimic the Artec/Ultima AM12S */ - strncpy (result + 8, "ULTIMA", 6); - strncpy (result + 16, "AM12S ", 16); + memcpy (result + 8, "ULTIMA", 6); + memcpy (result + 16, "AM12S ", 16); } /* diff --git a/backend/artec_eplus48u.c b/backend/artec_eplus48u.c index 0e81b06..c5eb225 100644 --- a/backend/artec_eplus48u.c +++ b/backend/artec_eplus48u.c @@ -2956,7 +2956,7 @@ init_options (Artec48U_Scanner * s) SANE_I18N ("If enabled, only the shading correction is " "performed during calibration. The default values " "for gain, offset and exposure time, " - "either build-in or from the configuration file, " + "either built-in or from the configuration file, " "are used."); s->opt[OPT_CALIBRATE_SHADING].type = SANE_TYPE_BOOL; s->opt[OPT_CALIBRATE_SHADING].unit = SANE_UNIT_NONE; diff --git a/backend/as6e.c b/backend/as6e.c index 37a6d3b..47d8c90 100644 --- a/backend/as6e.c +++ b/backend/as6e.c @@ -797,7 +797,6 @@ check_for_driver (const char *devname) struct stat statbuf; mode_t modes; char *path; - char fullname[NAMESIZE]; char dir[NAMESIZE]; int count = 0, offset = 0, valid; @@ -806,7 +805,6 @@ check_for_driver (const char *devname) return 0; while (path[count] != '\0') { - memset (fullname, '\0', sizeof (fullname)); memset (dir, '\0', sizeof (dir)); valid = 1; while ((path[count] != ':') && (path[count] != '\0')) @@ -819,19 +817,19 @@ check_for_driver (const char *devname) count++; } if (valid == 1) - { - /* use sizeof(fullname)-1 to make sure there is at least one padded null byte */ - strncpy (fullname, dir, sizeof(fullname)-1); - /* take into account that fullname already contains non-null bytes */ - strncat (fullname, "/", sizeof(fullname)-strlen(fullname)-1); - strncat (fullname, devname, sizeof(fullname)-strlen(fullname)-1); - if (!stat (fullname, &statbuf)) - { - modes = statbuf.st_mode; - if (S_ISREG (modes)) - return (1); /* found as6edriver */ - } - } + { + char fullname[NAMESIZE]; + int len = snprintf(fullname, sizeof(fullname), "%s/%s", dir, devname); + if ((len > 0) && (len <= (int)sizeof(fullname))) + { + if (!stat (fullname, &statbuf)) + { + modes = statbuf.st_mode; + if (S_ISREG (modes)) + return (1); /* found as6edriver */ + } + } + } if (path[count] == '\0') return (0); /* end of path --no driver found */ count++; diff --git a/backend/avision.c b/backend/avision.c index e9f0145..55b5f4f 100644 --- a/backend/avision.c +++ b/backend/avision.c @@ -7921,7 +7921,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle *handle) However, I was told Cygwin (et al.) takes care of it. */ strncpy(s->duplex_rear_fname, "/tmp/avision-rear-XXXXXX", PATH_MAX); - if (! mktemp(s->duplex_rear_fname) ) { + if (! mkstemp(s->duplex_rear_fname) ) { DBG (1, "sane_open: failed to generate temporary fname for duplex scans\n"); return SANE_STATUS_NO_MEM; } diff --git a/backend/avision.h b/backend/avision.h index 3f42ff6..58552c0 100644 --- a/backend/avision.h +++ b/backend/avision.h @@ -780,7 +780,7 @@ typedef struct acceleration_info #define SANE_NAME_DUPLEX "duplex" #define SANE_TITLE_DUPLEX SANE_I18N("Duplex scan") -#define SANE_DESC_DUPLEX SANE_I18N("Duplex scan provide a scan of the front and back side of the document") +#define SANE_DESC_DUPLEX SANE_I18N("Duplex scan provides a scan of the front and back side of the document") #ifdef AVISION_ENHANCED_SANE #warning "Compiled Avision backend will violate the SANE standard" diff --git a/backend/canon-sane.c b/backend/canon-sane.c index 5d9ec99..cd75719 100644 --- a/backend/canon-sane.c +++ b/backend/canon-sane.c @@ -1125,9 +1125,9 @@ sane_start (SANE_Handle handle) if (thistmpfile != NULL) { - if (mktemp(thistmpfile) == 0) + if (!mkstemp(thistmpfile)) { - DBG(1, "mktemp(thistmpfile) is failed\n"); + DBG(1, "mkstemp(thistmpfile) is failed\n"); return (SANE_STATUS_INVAL); } } diff --git a/backend/canon.c b/backend/canon.c index ad738e8..4a5a2a2 100644 --- a/backend/canon.c +++ b/backend/canon.c @@ -457,7 +457,7 @@ sense_handler (int scsi_fd, u_char * result, void *arg) status = SANE_STATUS_UNSUPPORTED; break; case 0x8002: - sense_str = SANE_I18N("option not connect"); + sense_str = SANE_I18N("option not correct"); status = SANE_STATUS_UNSUPPORTED; break; default: diff --git a/backend/canon630u-common.c b/backend/canon630u-common.c index 27c34ff..5cd0fcf 100644 --- a/backend/canon630u-common.c +++ b/backend/canon630u-common.c @@ -939,7 +939,7 @@ plugin_cal (CANON_Handle * s) { DBG (1, "No temp filename!\n"); s->fname = strdup ("/tmp/cal.XXXXXX"); - mktemp (s->fname); + mkstemp (s->fname); } s->width = 2551; s->height = 75; @@ -1583,7 +1583,7 @@ CANON_start_scan (CANON_Handle * scanner) /* choose a temp file name for scan data */ scanner->fname = strdup ("/tmp/scan.XXXXXX"); - if (!mktemp (scanner->fname)) + if (!mkstemp (scanner->fname)) return SANE_STATUS_IO_ERROR; /* calibrate if needed */ diff --git a/backend/canon_dr.c b/backend/canon_dr.c index 64aec31..f6cd5d4 100644 --- a/backend/canon_dr.c +++ b/backend/canon_dr.c @@ -3,7 +3,7 @@ This file is part of the SANE package, and implements a SANE backend for various Canon DR-series scanners. - Copyright (C) 2008-2016 m. allan noah + Copyright (C) 2008-2019 m. allan noah Yabarana Corp. www.yabarana.com provided significant funding EvriChart, Inc. www.evrichart.com provided funding and loaned equipment @@ -338,6 +338,8 @@ - initial support for P-150 v57 2019-02-24, manuarg - complete support for X-10, including hardware cropping + v58 2019-11-10, MAN + - adjust wait_scanner to set runRS only as a last resort, bug #154 SANE FLOW DIAGRAM @@ -388,7 +390,7 @@ #include "canon_dr.h" #define DEBUG 1 -#define BUILD 57 +#define BUILD 58 /* values for SANE_DEBUG_CANON_DR env var: - errors 5 @@ -7584,6 +7586,24 @@ wait_scanner(struct scanner *s) NULL, NULL ); + if (ret != SANE_STATUS_GOOD) { + DBG(5,"WARNING: Brain-dead scanner. Hitting with stick.\n"); + ret = do_cmd ( + s, 0, 1, + cmd, cmdLen, + NULL, 0, + NULL, NULL + ); + } + if (ret != SANE_STATUS_GOOD) { + DBG(5,"WARNING: Brain-dead scanner. Hitting with stick again.\n"); + ret = do_cmd ( + s, 0, 1, + cmd, cmdLen, + NULL, 0, + NULL, NULL + ); + } // some scanners (such as DR-F120) are OK but will not respond to commands // when in sleep mode. By checking the sense it wakes them up. if (ret != SANE_STATUS_GOOD) { @@ -7596,7 +7616,16 @@ wait_scanner(struct scanner *s) ); } if (ret != SANE_STATUS_GOOD) { - DBG(5,"WARNING: Brain-dead scanner. Hitting with stick instead.\n"); + DBG(5,"WARNING: Brain-dead scanner. Hitting with stick a third time.\n"); + ret = do_cmd ( + s, 0, 1, + cmd, cmdLen, + NULL, 0, + NULL, NULL + ); + } + if (ret != SANE_STATUS_GOOD) { + DBG(5,"WARNING: Brain-dead scanner. Hitting with stick a fourth time.\n"); ret = do_cmd ( s, 0, 1, cmd, cmdLen, diff --git a/backend/dc25.c b/backend/dc25.c index 3bb81f5..6188608 100644 --- a/backend/dc25.c +++ b/backend/dc25.c @@ -2030,7 +2030,7 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) if (tmpname == NULL) { tmpname = tmpnamebuf; - if (mktemp (tmpname) == NULL) + if (!mkstemp (tmpname)) { DBG (1, "Unable to make temp file %s\n", tmpname); return SANE_STATUS_INVAL; diff --git a/backend/dll.c b/backend/dll.c index 8f0983d..73ffde4 100644 --- a/backend/dll.c +++ b/backend/dll.c @@ -89,6 +89,20 @@ posix_dlsym (void *handle, const char *func) } # pragma GCC diagnostic pop + /* Similar to the above, GCC also warns about conversion between + pointers to functions. The ISO C standard says that invoking a + converted pointer to a function whose type is not compatible with + the pointed-to type, the behavior is undefined. Although GCC is + correct to warn about this, the dll backend has been using these + conversions without issues for a very long time already. + + Rather than push/pop around every use, which would get very ugly + real fast, ignore this particular warning for the remainder of + the file. + */ +# pragma GCC diagnostic ignored "-Wpragmas" /* backward compatibility */ +# pragma GCC diagnostic ignored "-Wcast-function-type" + /* Older versions of dlopen() don't define RTLD_NOW and RTLD_LAZY. They all seem to use a mode of 1 to indicate RTLD_NOW and some do not support RTLD_LAZY at all. Hence, unless defined, we define @@ -139,6 +153,8 @@ posix_dlsym (void *handle, const char *func) #define DLL_CONFIG_FILE "dll.conf" #define DLL_ALIASES_FILE "dll.aliases" +#include "../include/sane/sanei_usb.h" + enum SANE_Ops { OP_INIT = 0, @@ -797,7 +813,8 @@ read_dlld (void) DIR *dlld; struct dirent *dllconf; struct stat st; - char conffile[PATH_MAX], dlldir[PATH_MAX]; + char dlldir[PATH_MAX]; + char conffile[PATH_MAX + strlen("/") + NAME_MAX]; size_t len, plen; const char *dir_list; char *copy, *next, *dir; @@ -849,7 +866,7 @@ read_dlld (void) || (dllconf->d_name[len-1] == '#')) continue; - snprintf (conffile, PATH_MAX, "%s/%s", dlldir, dllconf->d_name); + snprintf (conffile, sizeof(conffile), "%s/%s", dlldir, dllconf->d_name); DBG (5, "sane_init/read_dlld: considering %s\n", conffile); @@ -1177,18 +1194,73 @@ sane_open (SANE_String_Const full_name, SANE_Handle * meta_handle) } dev_name = strchr (full_name, ':'); + + int is_fakeusb = 0, is_fakeusbdev = 0, is_fakeusbout = 0; + if (dev_name) { - be_name = strndup(full_name, dev_name - full_name); - ++dev_name; /* skip colon */ + is_fakeusb = strncmp(full_name, "fakeusb", dev_name - full_name) == 0 && + dev_name - full_name == 7; + is_fakeusbdev = strncmp(full_name, "fakeusbdev", dev_name - full_name) == 0 && + dev_name - full_name == 10; + is_fakeusbout = strncmp(full_name, "fakeusbout", dev_name - full_name) == 0 && + dev_name - full_name == 10; + } + + if (is_fakeusb || is_fakeusbdev) + { + ++dev_name; // skip colon + status = sanei_usb_testing_enable_replay(dev_name, is_fakeusbdev); + if (status != SANE_STATUS_GOOD) + return status; + + be_name = sanei_usb_testing_get_backend(); + if (be_name == NULL) + { + DBG (0, "%s: unknown backend for testing\n", __func__); + return SANE_STATUS_ACCESS_DENIED; + } } else { - /* if no colon interpret full_name as the backend name; an empty - backend device name will cause us to open the first device of - that backend. */ - be_name = strdup(full_name); - dev_name = ""; + char* fakeusbout_path = NULL; + if (is_fakeusbout) + { + ++dev_name; // skip colon + + const char* path_end = strchr(dev_name, ':'); + if (path_end == NULL) + { + DBG (0, "%s: the device name does not contain path\n", __func__); + return SANE_STATUS_INVAL; + } + fakeusbout_path = strndup(dev_name, path_end - dev_name); + + full_name = path_end + 1; // skip colon + dev_name = strchr(full_name, ':'); + } + + if (dev_name) + { + be_name = strndup(full_name, dev_name - full_name); + ++dev_name; /* skip colon */ + } + else + { + /* if no colon interpret full_name as the backend name; an empty + backend device name will cause us to open the first device of + that backend. */ + be_name = strdup(full_name); + dev_name = ""; + } + + if (is_fakeusbout) + { + status = sanei_usb_testing_enable_record(fakeusbout_path, be_name); + free(fakeusbout_path); + if (status != SANE_STATUS_GOOD) + return status; + } } if (!be_name) diff --git a/backend/dll.conf.in b/backend/dll.conf.in index 8d459ab..92091cb 100644 --- a/backend/dll.conf.in +++ b/backend/dll.conf.in @@ -11,10 +11,10 @@ net abaton agfafocus apple -avision artec artec_eplus48u as6e +avision bh canon canon630u @@ -24,33 +24,35 @@ cardscan coolscan #coolscan2 coolscan3 -#dc25 #dc210 #dc240 +#dc25 dell1600n_net dmc epjitsu #epson epson2 epsonds +escl fujitsu -#gphoto2 genesys +#gphoto2 gt68xx hp -hp3900 -hpsj5s hp3500 +hp3900 hp4200 hp5400 hp5590 hpljm1005 +hpsj5s hs2p ibm kodak kodakaio kvs1025 kvs20xx +kvs40xx leo lexmark ma1509 @@ -66,6 +68,7 @@ nec niash #p5 pie +pieusb pint pixma plustek @@ -91,7 +94,7 @@ teco3 #test u12 umax -#umax_pp umax1220u +#umax_pp v4l xerox_mfp diff --git a/backend/epjitsu.c b/backend/epjitsu.c index bee4310..714bc0b 100644 --- a/backend/epjitsu.c +++ b/backend/epjitsu.c @@ -349,10 +349,21 @@ sane_get_devices (const SANE_Device *** device_list, SANE_Bool local_only) continue; if ((strncmp ("firmware", lp, 8) == 0) && isspace (lp[8])) { + size_t firmware_len; + lp += 8; lp = sanei_config_skip_whitespace (lp); DBG (15, "sane_get_devices: firmware '%s'\n", lp); - strncpy((char *)global_firmware_filename,lp,PATH_MAX); + + firmware_len = strlen(lp); + if (firmware_len > sizeof(global_firmware_filename) - 1) + { + DBG (5, "sane_get_devices: firmware file too long. ignoring '%s'\n", lp); + } + else + { + strcpy((char *)global_firmware_filename, lp); + } } else if ((strncmp ("usb", lp, 3) == 0) && isspace (lp[3])) { DBG (15, "sane_get_devices: looking for '%s'\n", lp); diff --git a/backend/epson2.c b/backend/epson2.c index f119018..e6f6786 100644 --- a/backend/epson2.c +++ b/backend/epson2.c @@ -1889,12 +1889,11 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) case OPT_BR_X: case OPT_BR_Y: - sval->w = *((SANE_Word *) value); - if (SANE_UNFIX(sval->w) == 0) { + if (SANE_UNFIX(*((SANE_Word *) value)) == 0) { DBG(17, "invalid br-x or br-y\n"); return SANE_STATUS_INVAL; } - /* passthru */ + // fall through case OPT_TL_X: case OPT_TL_Y: sval->w = *((SANE_Word *) value); diff --git a/backend/epsonds.c b/backend/epsonds.c index d402f58..ff5d681 100644 --- a/backend/epsonds.c +++ b/backend/epsonds.c @@ -1050,12 +1050,11 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) case OPT_BR_X: case OPT_BR_Y: - sval->w = *((SANE_Word *) value); - if (SANE_UNFIX(sval->w) == 0) { + if (SANE_UNFIX(*((SANE_Word *) value)) == 0) { DBG(17, " invalid br-x or br-y\n"); return SANE_STATUS_INVAL; } - /* passthru */ + // fall through case OPT_TL_X: case OPT_TL_Y: sval->w = *((SANE_Word *) value); diff --git a/backend/escl.conf.in b/backend/escl.conf.in new file mode 100644 index 0000000..2aa6257 --- /dev/null +++ b/backend/escl.conf.in @@ -0,0 +1,17 @@ +# escl.conf -- ESCL configuration +# Lines starting with a # or a ; are comments. Comments must be on a +# line of their own. End-of-line comments are not supported. +# Explanation : if you can't detect your device but it's an eSCL device, modify this escl conf' file to use your device. +# -> uncomment the lines below, from '[device]' to 'port'. +# -> put your device name instead of 'EPSON X'. +# -> put your type of protocol instead of 'https' : http or https. +# -> put your device ip instead of '123.456.789.10'. +# -> put the port that you use instead of '88'. +# For example, the lines below are for one device, but if you have several devices to use, you can duplicate the lines below as many times as you have devices. + +#[device] + +#model EPSON X +#type https +#ip 123.456.789.10 +#port 88 diff --git a/backend/escl/escl.c b/backend/escl/escl.c new file mode 100644 index 0000000..8df6c5c --- /dev/null +++ b/backend/escl/escl.c @@ -0,0 +1,777 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#include "escl.h" + +#include +#include +#include + +#include + +#include + +#include "../include/sane/saneopts.h" +#include "../include/sane/sanei.h" +#include "../include/sane/sanei_backend.h" +#include "../include/sane/sanei_config.h" + +#define min(A,B) (((A)<(B)) ? (A) : (B)) +#define max(A,B) (((A)>(B)) ? (A) : (B)) +#define INPUT_BUFFER_SIZE 4096 + +static const SANE_Device **devlist = NULL; +static ESCL_Device *list_devices_primary = NULL; +static int num_devices = 0; + +typedef struct Handled { + struct Handled *next; + SANE_String_Const name; + char *result; + ESCL_ScanParam param; + SANE_Option_Descriptor opt[NUM_OPTIONS]; + Option_Value val[NUM_OPTIONS]; + capabilities_t *scanner; + SANE_Range x_range; + SANE_Range y_range; + SANE_Bool cancel; + SANE_Bool write_scan_data; + SANE_Bool decompress_scan_data; + SANE_Bool end_read; + SANE_Parameters ps; +} escl_sane_t; + +/** + * \fn static SANE_Status escl_add_in_list(ESCL_Device *current) + * \brief Function that adds all the element needed to my list : + * the port number, the model name, the ip address, and the type of url (http/https). + * Moreover, this function counts the number of devices found. + * + * \return SANE_STATUS_GOOD if everything is OK. + */ +static SANE_Status +escl_add_in_list(ESCL_Device *current) +{ + ++num_devices; + current->next = list_devices_primary; + list_devices_primary = current; + return (SANE_STATUS_GOOD); +} + +/** + * \fn SANE_Status escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type) + * \brief Function that browses my list ('for' loop) and returns the "escl_add_in_list" function to + * adds all the element needed to my list : + * the port number, the model name, the ip address and the type of the url (http / https). + * + * \return escl_add_in_list(current) + */ +SANE_Status +escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type) +{ + ESCL_Device *current = NULL; + DBG (10, "escl_device_add\n"); + for (current = list_devices_primary; current; current = current->next) { + if (strcmp(current->ip_address, ip_address) == 0 && current->port_nb == port_nb + && strcmp(current->type, type) == 0) + return (SANE_STATUS_GOOD); + } + current = malloc(sizeof(*current)); + if (current == NULL) + return (SANE_STATUS_NO_MEM); + memset(current, 0, sizeof(*current)); + current->port_nb = port_nb; + current->model_name = strdup(model_name); + current->ip_address = strdup(ip_address); + current->type = strdup(type); + return escl_add_in_list(current); +} + +/** + * \fn static inline size_t max_string_size(const SANE_String_Const strings[]) + * \brief Function that browses the string ('for' loop) and counts the number of character in the string. + * --> this allows to know the maximum size of the string. + * + * \return max_size + 1 (the size max) + */ +static inline size_t +max_string_size(const SANE_String_Const strings[]) +{ + size_t max_size = 0; + int i = 0; + + for (i = 0; strings[i]; ++i) { + size_t size = strlen (strings[i]); + if (size > max_size) + max_size = size; + } + return (max_size + 1); +} + +/** + * \fn static SANE_Device *convertFromESCLDev(ESCL_Device *cdev) + * \brief Function that checks if the url of the received scanner is secured or not (http / https). + * --> if the url is not secured, our own url will be composed like "http://'ip':'port'". + * --> else, our own url will be composed like "https://'ip':'port'". + * AND, it's in this function that we gather all the informations of the url (that were in our list) : + * the model_name, the port, the ip, and the type of url. + * SO, leaving this function, we have in memory the complete url. + * + * \return sdev (structure that contains the elements of the url) + */ +static SANE_Device * +convertFromESCLDev(ESCL_Device *cdev) +{ + SANE_Device *sdev = (SANE_Device*) calloc(1, sizeof(SANE_Device)); + char tmp[PATH_MAX] = { 0 }; + + if (strcmp(cdev->type, "_uscan._tcp") == 0 || strcmp(cdev->type, "http") == 0) + snprintf(tmp, sizeof(tmp), "http://%s:%d", cdev->ip_address, cdev->port_nb); + else + snprintf(tmp, sizeof(tmp), "https://%s:%d", cdev->ip_address, cdev->port_nb); + DBG( 1, "Escl add device : %s\n", tmp); + sdev->name = strdup(tmp); + sdev->model = strdup(cdev->model_name); + sdev->vendor = strdup("ESCL"); + sdev->type = strdup("flatbed scanner"); + return (sdev); +} + +/** + * \fn SANE_Status sane_init(SANE_Int *version_code, SANE_Auth_Callback authorize) + * \brief Function that's called before any other SANE function ; it's the first SANE function called. + * --> this function checks the SANE config. and can check the authentication of the user if + * 'authorize' value is more than SANE_TRUE. + * In this case, it will be necessary to define an authentication method. + * + * \return SANE_STATUS_GOOD (everything is OK) + */ +SANE_Status +sane_init(SANE_Int *version_code, SANE_Auth_Callback __sane_unused__ authorize) +{ + DBG_INIT(); + DBG (10, "escl sane_init\n"); + SANE_Status status = SANE_STATUS_GOOD; + curl_global_init(CURL_GLOBAL_ALL); + if (version_code != NULL) + *version_code = SANE_VERSION_CODE(1, 0, 0); + if (status != SANE_STATUS_GOOD) + return (status); + return (SANE_STATUS_GOOD); +} + +/** + * \fn void sane_exit(void) + * \brief Function that must be called to terminate use of a backend. + * This function will first close all device handles that still might be open. + * --> by freeing all the elements of my list. + * After this function, no function other than 'sane_init' may be called. + */ +void +sane_exit(void) +{ + DBG (10, "escl sane_exit\n"); + ESCL_Device *next = NULL; + + while (list_devices_primary != NULL) { + next = list_devices_primary->next; + free(list_devices_primary); + list_devices_primary = next; + } + if (devlist) + free (devlist); + list_devices_primary = NULL; + devlist = NULL; + curl_global_cleanup(); +} + +/** + * \fn static SANE_Status attach_one_config(SANEI_Config *config, const char *line) + * \brief Function that implements a configuration file to the user : + * if the user can't detect some devices, he will be able to force their detection with this config' file to use them. + * Thus, this function parses the config' file to use the device of the user with the information below : + * the type of protocol (http/https), the ip, the port number, and the model name. + * + * \return escl_add_in_list(escl_device) if the parsing worked, SANE_STATUS_GOOD otherwise. + */ +static SANE_Status +attach_one_config(SANEI_Config __sane_unused__ *config, const char *line) +{ + int port = 0; + static int count = 0; + static ESCL_Device *escl_device = NULL; + + if (strncmp(line, "[device]", 8) == 0) { + count = 0; + escl_device = (ESCL_Device*)calloc(1, sizeof(ESCL_Device)); + } + if (strncmp(line, "ip", 2) == 0) { + const char *ip_space = sanei_config_skip_whitespace(line + 2); + if (escl_device != NULL && ip_space != NULL) { + count++; + escl_device->ip_address = strdup(ip_space); + } + } + if (sscanf(line, "port %i", &port) == 1 && port != 0) { + const char *port_space = sanei_config_skip_whitespace(line + 4); + if (escl_device != NULL && port_space != NULL) { + count++; + escl_device->port_nb = port; + } + } + if (strncmp(line, "model", 5) == 0) { + const char *model_space = sanei_config_skip_whitespace(line + 5); + if (escl_device != NULL && model_space != NULL) { + count++; + escl_device->model_name = strdup(model_space); + } + } + if (strncmp(line, "type", 4) == 0) { + const char *type_space = sanei_config_skip_whitespace(line + 4); + if (escl_device != NULL && type_space != NULL) { + count++; + escl_device->type = strdup(type_space); + } + } + if (count == 4) + return (escl_add_in_list(escl_device)); + return (SANE_STATUS_GOOD); +} + +/** + * \fn SANE_Status sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only) + * \brief Function that searches for connected devices and places them in our 'device_list'. ('for' loop) + * If the attribute 'local_only' is worth SANE_FALSE, we only returns the connected devices locally. + * + * \return SANE_STATUS_GOOD if devlist != NULL ; SANE_STATUS_NO_MEM otherwise. + */ +SANE_Status +sane_get_devices(const SANE_Device ***device_list, SANE_Bool local_only) +{ + if (local_only) /* eSCL is a network-only protocol */ + return (device_list ? SANE_STATUS_GOOD : SANE_STATUS_INVAL); + + DBG (10, "escl sane_get_devices\n"); + ESCL_Device *dev = NULL; + static const SANE_Device **devlist = 0; + SANE_Status status; + + if (device_list == NULL) + return (SANE_STATUS_INVAL); + status = sanei_configure_attach(ESCL_CONFIG_FILE, NULL, attach_one_config); + if (status != SANE_STATUS_GOOD) + return (status); + escl_devices(&status); + if (status != SANE_STATUS_GOOD) + return (status); + if (devlist) + free(devlist); + devlist = (const SANE_Device **) calloc (num_devices + 1, sizeof (devlist[0])); + if (devlist == NULL) + return (SANE_STATUS_NO_MEM); + int i = 0; + for (dev = list_devices_primary; i < num_devices; dev = dev->next) { + SANE_Device *s_dev = convertFromESCLDev(dev); + devlist[i] = s_dev; + i++; + } + devlist[i] = 0; + *device_list = devlist; + return (devlist) ? SANE_STATUS_GOOD : SANE_STATUS_NO_MEM; +} + +/** + * \fn static SANE_Status init_options(SANE_String_Const name, escl_sane_t *s) + * \brief Function thzt initializes all the needed options of the received scanner + * (the resolution / the color / the margins) thanks to the informations received with + * the 'escl_capabilities' function, called just before. + * + * \return status (if everything is OK, status = SANE_STATUS_GOOD) + */ +static SANE_Status +init_options(SANE_String_Const name, escl_sane_t *s) +{ + DBG (10, "escl init_options\n"); + SANE_Status status = SANE_STATUS_GOOD; + int i = 0; + + if (name == NULL) + return (SANE_STATUS_INVAL); + memset (s->opt, 0, sizeof (s->opt)); + memset (s->val, 0, sizeof (s->val)); + for (i = 0; i < NUM_OPTIONS; ++i) { + s->opt[i].size = sizeof (SANE_Word); + s->opt[i].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } + s->x_range.min = 0; + s->x_range.max = s->scanner->MaxWidth - s->scanner->MinWidth; + s->x_range.quant = 1; + s->y_range.min = 0; + s->y_range.max = s->scanner->MaxHeight - s->scanner->MinHeight; + s->y_range.quant = 1; + s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; + s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; + s->val[OPT_NUM_OPTS].w = NUM_OPTIONS; + + s->opt[OPT_MODE_GROUP].title = SANE_TITLE_SCAN_MODE; + s->opt[OPT_MODE_GROUP].desc = ""; + s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_MODE_GROUP].cap = 0; + s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; + s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; + s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; + s->opt[OPT_MODE].type = SANE_TYPE_STRING; + s->opt[OPT_MODE].unit = SANE_UNIT_NONE; + s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->opt[OPT_MODE].constraint.string_list = s->scanner->ColorModes; + s->val[OPT_MODE].s = (char *)strdup(s->scanner->ColorModes[0]); + s->opt[OPT_MODE].size = max_string_size(s->scanner->ColorModes); + s->scanner->default_color = (char *)strdup(s->scanner->ColorModes[0]); + + s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; + s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; + s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; + s->opt[OPT_RESOLUTION].constraint.word_list = s->scanner->SupportedResolutions; + s->val[OPT_RESOLUTION].w = s->scanner->SupportedResolutions[1]; + s->scanner->default_resolution = s->scanner->SupportedResolutions[1]; + + s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; + s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; + s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; + s->opt[OPT_PREVIEW].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT; + s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; + s->val[OPT_PREVIEW].w = SANE_FALSE; + + s->opt[OPT_GRAY_PREVIEW].name = SANE_NAME_GRAY_PREVIEW; + s->opt[OPT_GRAY_PREVIEW].title = SANE_TITLE_GRAY_PREVIEW; + s->opt[OPT_GRAY_PREVIEW].desc = SANE_DESC_GRAY_PREVIEW; + s->opt[OPT_GRAY_PREVIEW].type = SANE_TYPE_BOOL; + s->val[OPT_GRAY_PREVIEW].w = SANE_FALSE; + + s->opt[OPT_GEOMETRY_GROUP].title = SANE_TITLE_GEOMETRY; + s->opt[OPT_GEOMETRY_GROUP].desc = ""; + s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; + s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; + s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; + s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; + s->opt[OPT_TL_X].unit = SANE_UNIT_PIXEL; + s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_TL_X].constraint.range = &s->x_range; + s->val[OPT_TL_X].w = s->scanner->RiskyLeftMargin; + + s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; + s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; + s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; + s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; + s->opt[OPT_TL_Y].unit = SANE_UNIT_PIXEL; + s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_TL_Y].constraint.range = &s->y_range; + s->val[OPT_TL_Y].w = s->scanner->RiskyTopMargin; + + s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; + s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; + s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; + s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; + s->opt[OPT_BR_X].unit = SANE_UNIT_PIXEL; + s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BR_X].constraint.range = &s->x_range; + s->val[OPT_BR_X].w = s->scanner->MaxWidth; + + s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; + s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; + s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; + s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; + s->opt[OPT_BR_Y].unit = SANE_UNIT_PIXEL; + s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BR_Y].constraint.range = &s->y_range; + s->val[OPT_BR_Y].w = s->scanner->MaxHeight; + return (status); +} + +/** + * \fn SANE_Status sane_open(SANE_String_Const name, SANE_Handle *h) + * \brief Function that establishes a connection with the device named by 'name', + * and returns a 'handler' using 'SANE_Handle *h', representing it. + * Thus, it's this function that calls the 'escl_status' function firstly, + * then the 'escl_capabilities' function, and, after, the 'init_options' function. + * + * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +sane_open(SANE_String_Const name, SANE_Handle *h) +{ + DBG (10, "escl sane_open\n"); + SANE_Status status; + escl_sane_t *handler = NULL; + + if (name == NULL) + return (SANE_STATUS_INVAL); + status = escl_status(name); + if (status != SANE_STATUS_GOOD) + return (status); + handler = (escl_sane_t *)calloc(1, sizeof(escl_sane_t)); + if (handler == NULL) + return (SANE_STATUS_NO_MEM); + handler->name = strdup(name); + handler->scanner = escl_capabilities(name, &status); + if (status != SANE_STATUS_GOOD) + return (status); + status = init_options(name, handler); + if (status != SANE_STATUS_GOOD) + return (status); + handler->ps.depth = 8; + handler->ps.last_frame = SANE_TRUE; + handler->ps.format = SANE_FRAME_RGB; + handler->ps.pixels_per_line = handler->val[OPT_BR_X].w; + handler->ps.lines = handler->val[OPT_BR_Y].w; + handler->ps.bytes_per_line = handler->ps.pixels_per_line * 3; + status = sane_get_parameters(handler, 0); + if (status != SANE_STATUS_GOOD) + return (status); + handler->cancel = SANE_FALSE; + handler->write_scan_data = SANE_FALSE; + handler->decompress_scan_data = SANE_FALSE; + handler->end_read = SANE_FALSE; + *h = handler; + return (status); +} + +/** + * \fn void sane_cancel(SANE_Handle h) + * \brief Function that's used to, immediately or as quickly as possible, cancel the currently + * pending operation of the device represented by 'SANE_Handle h'. + * This functions calls the 'escl_scanner' functions, that resets the scan operations. + */ +void +sane_cancel(SANE_Handle h) +{ + DBG (10, "escl sane_cancel\n"); + escl_sane_t *handler = h; + if (handler->scanner->tmp) + { + fclose(handler->scanner->tmp); + handler->scanner->tmp = NULL; + } + handler->cancel = SANE_TRUE; + escl_scanner(handler->name, handler->result); +} + +/** + * \fn void sane_close(SANE_Handle h) + * \brief Function that closes the communication with the device represented by 'SANE_Handle h'. + * This function must release the resources that were allocated to the opening of 'h'. + */ +void +sane_close(SANE_Handle h) +{ + DBG (10, "escl sane_close\n"); + if (h != NULL) { + free(h); + h = NULL; + } +} + +/** + * \fn const SANE_Option_Descriptor *sane_get_option_descriptor(SANE_Handle h, SANE_Int n) + * \brief Function that retrieves a descriptor from the n number option of the scanner + * represented by 'h'. + * The descriptor remains valid until the machine is closed. + * + * \return s->opt + n + */ +const SANE_Option_Descriptor * +sane_get_option_descriptor(SANE_Handle h, SANE_Int n) +{ + DBG (10, "escl sane_get_option_descriptor\n"); + escl_sane_t *s = h; + + if ((unsigned) n >= NUM_OPTIONS || n < 0) + return (0); + return (s->opt + n); +} + +/** + * \fn SANE_Status sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int *i) + * \brief Function that defines the actions to perform for the 'n' option of the machine, + * represented by 'h', if the action is 'a'. + * There are 3 types of possible actions : + * --> SANE_ACTION_GET_VALUE: 'v' must be used to provide the value of the option. + * --> SANE_ACTION_SET_VALUE: The option must take the 'v' value. + * --> SANE_ACTION_SET_AUTO: The backend or machine must affect the option with an appropriate value. + * Moreover, the parameter 'i' is used to provide additional information about the state of + * 'n' option if SANE_ACTION_SET_VALUE has been performed. + * + * \return SANE_STATUS_GOOD if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL + */ +SANE_Status +sane_control_option(SANE_Handle h, SANE_Int n, SANE_Action a, void *v, SANE_Int *i) +{ + DBG (10, "escl sane_control_option\n"); + escl_sane_t *handler = h; + + if (i) + *i = 0; + if (n >= NUM_OPTIONS || n < 0) + return (SANE_STATUS_INVAL); + if (a == SANE_ACTION_GET_VALUE) { + switch (n) { + case OPT_NUM_OPTS: + case OPT_RESOLUTION: + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + case OPT_PREVIEW: + case OPT_GRAY_PREVIEW: + *(SANE_Word *) v = handler->val[n].w; + break; + case OPT_MODE: + strcpy (v, handler->val[n].s); + break; + case OPT_MODE_GROUP: + default: + break; + } + return (SANE_STATUS_GOOD); + } + if (a == SANE_ACTION_SET_VALUE) { + switch (n) { + case OPT_TL_X: + case OPT_TL_Y: + case OPT_BR_X: + case OPT_BR_Y: + case OPT_PREVIEW: + case OPT_GRAY_PREVIEW: + handler->val[n].w = *(SANE_Word *) v; + if (i && handler->val[n].w != *(SANE_Word *) v) + *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; + handler->val[n].w = *(SANE_Word *) v; + break; + case OPT_RESOLUTION: + handler->val[n].w = *(SANE_Word *) v; + if (i) + *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; + break; + case OPT_MODE: + if (handler->val[n].s) + free (handler->val[n].s); + handler->val[n].s = strdup (v); + if (i) + *i |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS | SANE_INFO_INEXACT; + break; + default: + break; + } + } + return (SANE_STATUS_GOOD); +} + +/** + * \fn SANE_Status sane_start(SANE_Handle h) + * \brief Function that initiates aquisition of an image from the device represented by handle 'h'. + * This function calls the "escl_newjob" function and the "escl_scan" function. + * + * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +sane_start(SANE_Handle h) +{ + DBG (10, "escl sane_start\n"); + SANE_Status status = SANE_STATUS_GOOD; + escl_sane_t *handler = h; + int w = 0; + int he = 0; + int bps = 0; + + if (handler->name == NULL) + return (SANE_STATUS_INVAL); + handler->cancel = SANE_FALSE; + handler->write_scan_data = SANE_FALSE; + handler->decompress_scan_data = SANE_FALSE; + handler->end_read = SANE_FALSE; + handler->scanner->height = handler->val[OPT_BR_Y].w; + handler->scanner->width = handler->val[OPT_BR_X].w; + handler->scanner->pos_x = handler->val[OPT_TL_X].w; + handler->scanner->pos_y = handler->val[OPT_TL_Y].w; + if(handler->scanner->default_color) + free(handler->scanner->default_color); + if (handler->val[OPT_PREVIEW].w == SANE_TRUE) + { + int i = 0, val = 9999;; + if (handler->val[OPT_GRAY_PREVIEW].w == SANE_TRUE || + !strncasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY, 3)) + handler->scanner->default_color = strdup("Grayscale8"); + else + handler->scanner->default_color = strdup("RGB24"); + for (i = 1; i < handler->scanner->SupportedResolutionsSize; i++) + { + if (val > handler->scanner->SupportedResolutions[i]) + val = handler->scanner->SupportedResolutions[i]; + } + handler->scanner->default_resolution = val; + } + else + { + handler->scanner->default_resolution = handler->val[OPT_RESOLUTION].w; + if (!strncasecmp(handler->val[OPT_MODE].s, SANE_VALUE_SCAN_MODE_GRAY, 3)) + handler->scanner->default_color = strdup("Grayscale8"); + else + handler->scanner->default_color = strdup("RGB24"); + } + handler->result = escl_newjob(handler->scanner, handler->name, &status); + if (status != SANE_STATUS_GOOD) + return (status); + status = escl_scan(handler->scanner, handler->name, handler->result); + if (status != SANE_STATUS_GOOD) + return (status); + if (!strcmp(handler->scanner->default_format, "image/jpeg")) + { + status = get_JPEG_data(handler->scanner, &w, &he, &bps); + } + else if (!strcmp(handler->scanner->default_format, "image/png")) + { + status = get_PNG_data(handler->scanner, &w, &he, &bps); + } + else if (!strcmp(handler->scanner->default_format, "image/tiff")) + { + status = get_TIFF_data(handler->scanner, &w, &he, &bps); + } + else + return SANE_STATUS_INVAL; + + if (status != SANE_STATUS_GOOD) + return (status); + handler->ps.depth = 8; + handler->ps.pixels_per_line = w; + handler->ps.lines = he; + handler->ps.bytes_per_line = w * bps; + handler->ps.last_frame = SANE_TRUE; + handler->ps.format = SANE_FRAME_RGB; + return (status); +} + +/** + * \fn SANE_Status sane_get_parameters(SANE_Handle h, SANE_Parameters *p) + * \brief Function that retrieves the device parameters represented by 'h' and stores them in 'p'. + * This function is normally used after "sane_start". + * It's in this function that we choose to assign the default color. (Color or Monochrome) + * + * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +sane_get_parameters(SANE_Handle h, SANE_Parameters *p) +{ + DBG (10, "escl sane_get_parameters\n"); + SANE_Status status = SANE_STATUS_GOOD; + escl_sane_t *handler = h; + + if (status != SANE_STATUS_GOOD) + return (status); + if (p != NULL) { + p->depth = 8; + p->last_frame = SANE_TRUE; + p->format = SANE_FRAME_RGB; + p->pixels_per_line = handler->ps.pixels_per_line; + p->lines = handler->ps.lines; + p->bytes_per_line = handler->ps.bytes_per_line; + } + return (status); +} + + +/** + * \fn SANE_Status sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len) + * \brief Function that's used to read image data from the device represented by handle 'h'. + * The argument 'buf' is a pointer to a memory area that is at least 'maxlen' bytes long. + * The number of bytes returned is stored in '*len'. + * --> When the call succeeds, the number of bytes returned can be anywhere in the range from 0 to 'maxlen' bytes. + * + * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *len) +{ + DBG (10, "escl sane_read\n"); + escl_sane_t *handler = h; + SANE_Status status = SANE_STATUS_GOOD; + long readbyte; + + if (!handler | !buf | !len) + return (SANE_STATUS_INVAL); + if (handler->cancel) + return (SANE_STATUS_CANCELLED); + if (!handler->write_scan_data) + handler->write_scan_data = SANE_TRUE; + if (!handler->decompress_scan_data) { + if (status != SANE_STATUS_GOOD) + return (status); + handler->decompress_scan_data = SANE_TRUE; + } + if (handler->scanner->img_data == NULL) + return (SANE_STATUS_INVAL); + if (!handler->end_read) { + readbyte = min((handler->scanner->img_size - handler->scanner->img_read), maxlen); + memcpy(buf, handler->scanner->img_data + handler->scanner->img_read, readbyte); + handler->scanner->img_read = handler->scanner->img_read + readbyte; + *len = readbyte; + if (handler->scanner->img_read == handler->scanner->img_size) + handler->end_read = SANE_TRUE; + else if (handler->scanner->img_read > handler->scanner->img_size) { + *len = 0; + handler->end_read = SANE_TRUE; + free(handler->scanner->img_data); + handler->scanner->img_data = NULL; + return (SANE_STATUS_INVAL); + } + } + else { + *len = 0; + free(handler->scanner->img_data); + handler->scanner->img_data = NULL; + return (SANE_STATUS_EOF); + } + return (SANE_STATUS_GOOD); +} + +SANE_Status +sane_get_select_fd(SANE_Handle __sane_unused__ h, SANE_Int __sane_unused__ *fd) +{ + return (SANE_STATUS_UNSUPPORTED); +} + +SANE_Status +sane_set_io_mode(SANE_Handle __sane_unused__ handle, SANE_Bool __sane_unused__ non_blocking) +{ + return (SANE_STATUS_UNSUPPORTED); +} diff --git a/backend/escl/escl.h b/backend/escl/escl.h new file mode 100644 index 0000000..82910bd --- /dev/null +++ b/backend/escl/escl.h @@ -0,0 +1,171 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + + +#ifndef __ESCL_H__ +#define __ESCL_H__ + +#include "../include/sane/config.h" + +#if !(HAVE_LIBCURL && defined(WITH_AVAHI) && defined(HAVE_LIBXML2)) +#error "The escl backend requires libcurl, libavahi and libxml2" +#endif + +#ifndef HAVE_LIBJPEG +/* FIXME: Make JPEG support optional. + Support for PNG and PDF is to be added later but currently only + JPEG is supported. Absence of JPEG support makes the backend a + no-op at present. + */ +#error "The escl backend currently requires libjpeg" +#endif + +#include "../include/sane/sane.h" + +#include + +#ifndef BACKEND_NAME +#define BACKEND_NAME escl +#endif + +#define DEBUG_NOT_STATIC +#include "../include/sane/sanei_debug.h" + +#ifndef DBG_LEVEL +#define DBG_LEVEL PASTE(sanei_debug_, BACKEND_NAME) +#endif +#ifndef NDEBUG +# define DBGDUMP(level, buf, size) \ + do { if (DBG_LEVEL >= (level)) sanei_escl_dbgdump(buf, size); } while (0) +#else +# define DBGDUMP(level, buf, size) +#endif + +#define ESCL_CONFIG_FILE "escl.conf" + +typedef struct { + int p1_0; + int p2_0; + int p3_3; + int DocumentType; + int p4_0; + int p5_0; + int p6_1; + int reserve[11]; +} ESCL_SCANOPTS; + + +typedef struct ESCL_Device { + struct ESCL_Device *next; + + char *model_name; + int port_nb; + char *ip_address; + char *type; +} ESCL_Device; + +typedef struct capabilities +{ + int height; + int width; + int pos_x; + int pos_y; + SANE_String default_color; + SANE_String default_format; + SANE_Int default_resolution; + int MinWidth; + int MaxWidth; + int MinHeight; + int MaxHeight; + int MaxScanRegions; + SANE_String_Const *ColorModes; + int ColorModesSize; + SANE_String_Const *ContentTypes; + int ContentTypesSize; + SANE_String_Const *DocumentFormats; + int DocumentFormatsSize; + SANE_Int *SupportedResolutions; + int SupportedResolutionsSize; + SANE_String_Const *SupportedIntents; + int SupportedIntentsSize; + SANE_String_Const SupportedIntentDefault; + int MaxOpticalXResolution; + int RiskyLeftMargin; + int RiskyRightMargin; + int RiskyTopMargin; + int RiskyBottomMargin; + FILE *tmp; + unsigned char *img_data; + long img_size; + long img_read; + int format_ext; +} capabilities_t; + +typedef struct { + int XRes; + int YRes; + int Left; + int Top; + int Right; + int Bottom; + int ScanMode; + int ScanMethod; + ESCL_SCANOPTS opts; +} ESCL_ScanParam; + + +enum +{ + OPT_NUM_OPTS = 0, + OPT_MODE_GROUP, + OPT_MODE, + OPT_RESOLUTION, + OPT_PREVIEW, + OPT_GRAY_PREVIEW, + + OPT_GEOMETRY_GROUP, + OPT_TL_X, + OPT_TL_Y, + OPT_BR_X, + OPT_BR_Y, + NUM_OPTIONS +}; + +ESCL_Device *escl_devices(SANE_Status *status); +SANE_Status escl_device_add(int port_nb, const char *model_name, char *ip_address, char *type); +SANE_Status escl_status(SANE_String_Const name); +capabilities_t *escl_capabilities(SANE_String_Const name, SANE_Status *status); +char *escl_newjob(capabilities_t *scanner, SANE_String_Const name, SANE_Status *status); +SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name, char *result); +void escl_scanner(SANE_String_Const name, char *result); + +// JPEG +SANE_Status get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps); + +// PNG +SANE_Status get_PNG_data(capabilities_t *scanner, int *w, int *h, int *bps); + +// TIFF +SANE_Status get_TIFF_data(capabilities_t *scanner, int *w, int *h, int *bps); + +#endif diff --git a/backend/escl/escl_capabilities.c b/backend/escl/escl_capabilities.c new file mode 100644 index 0000000..690ff1e --- /dev/null +++ b/backend/escl/escl_capabilities.c @@ -0,0 +1,377 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include +#include +#include + +#include +#include + +#include "../include/sane/saneopts.h" + +struct cap +{ + char *memory; + size_t size; +}; + +/** + * \fn static SANE_String_Const convert_elements(SANE_String_Const str) + * \brief Function that converts the 'color modes' of the scanner (color/gray) to be understood by SANE. + * + * \return SANE_VALUE_SCAN_MODE_GRAY / SANE_VALUE_SCAN_MODE_COLOR ; NULL otherwise + */ +static SANE_String_Const +convert_elements(SANE_String_Const str) +{ + if (strcmp(str, "Grayscale8") == 0) + return (SANE_VALUE_SCAN_MODE_GRAY); + else if (strcmp(str, "RGB24") == 0) + return (SANE_VALUE_SCAN_MODE_COLOR); + return (NULL); +} + +/** + * \fn static SANE_String_Const *char_to_array(SANE_String_Const *tab, int *tabsize, SANE_String_Const mode, int good_array) + * \brief Function that creates the character arrays to put inside : + * the 'color modes', the 'content types', the 'document formats' and the 'supported intents'. + * + * \return board (the allocated array) + */ +static SANE_String_Const * +char_to_array(SANE_String_Const *tab, int *tabsize, SANE_String_Const mode, int good_array) +{ + SANE_String_Const *board = NULL; + int i = 0; + SANE_String_Const convert = NULL; + + if (mode == NULL) + return (tab); + if (good_array != 0) { + convert = convert_elements(mode); + if (convert == NULL) + return (tab); + } + else + convert = mode; + for (i = 0; i < (*tabsize); i++) { + if (strcmp(tab[i], convert) == 0) + return (tab); + } + (*tabsize)++; + if (*tabsize == 1) + board = (SANE_String_Const *)malloc(sizeof(SANE_String_Const) * (*tabsize) + 1); + else + board = (SANE_String_Const *)realloc(tab, sizeof(SANE_String_Const) * (*tabsize) + 1); + board[*tabsize - 1] = (SANE_String_Const)strdup(convert); + board[*tabsize] = NULL; + return (board); +} + +/** + * \fn static SANE_Int *int_to_array(SANE_Int *tab, int *tabsize, int cont) + * \brief Function that creates the integer array to put inside the 'supported resolutions'. + * + * \return board (the allocated array) + */ +static SANE_Int * +int_to_array(SANE_Int *tab, int *tabsize, int cont) +{ + SANE_Int *board = NULL; + int i = 0; + + for (i = 0; i < (*tabsize); i++) { + if (tab[i] == cont) + return (tab); + } + (*tabsize)++; + if (*tabsize == 1) { + (*tabsize)++; + board = malloc(sizeof(SANE_Int *) * (*tabsize) + 1); + } + else + board = realloc(tab, sizeof(SANE_Int *) * (*tabsize) + 1); + board[0] = *tabsize - 1; + board[*tabsize - 1] = cont; + board[*tabsize] = -1; + return (board); +} + +/** + * \fn static size_t memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp) + * \brief Callback function that stocks in memory the content of the scanner capabilities. + * + * \return realsize (size of the content needed -> the scanner capabilities) + */ +static size_t +memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct cap *mem = (struct cap *)userp; + + char *str = realloc(mem->memory, mem->size + realsize + 1); + if (str == NULL) { + fprintf(stderr, "not enough memory (realloc returned NULL)\n"); + return (0); + } + mem->memory = str; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size = mem->size + realsize; + mem->memory[mem->size] = 0; + return (realsize); +} + +/** + * \fn static int find_nodes_c(xmlNode *node) + * \brief Function that browses the xml file and parses it, to find the xml children node. + * --> to recover the scanner capabilities. + * + * \return 0 if a xml child node is found, 1 otherwise + */ +static int +find_nodes_c(xmlNode *node) +{ + xmlNode *child = node->children; + + while (child) { + if (child->type == XML_ELEMENT_NODE) + return (0); + child = child->next; + } + return (1); +} + +/** + * \fn static int find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner) + * \brief Function that searchs in the xml file if a scanner capabilitie stocked + * in one of the created array (character/integer array) is found. + * + * \return 0 + */ +static int +find_valor_of_array_variables(xmlNode *node, capabilities_t *scanner) +{ + const char *name = (const char *)node->name; + if (strcmp(name, "ColorMode") == 0) + scanner->ColorModes = char_to_array(scanner->ColorModes, &scanner->ColorModesSize, (SANE_String_Const)xmlNodeGetContent(node), 1); + else if (strcmp(name, "ContentType") == 0) + scanner->ContentTypes = char_to_array(scanner->ContentTypes, &scanner->ContentTypesSize, (SANE_String_Const)xmlNodeGetContent(node), 0); + else if (strcmp(name, "DocumentFormat") == 0) + { + int i = 0; + scanner->DocumentFormats = char_to_array(scanner->DocumentFormats, &scanner->DocumentFormatsSize, (SANE_String_Const)xmlNodeGetContent(node), 0); + for(; i < scanner->DocumentFormatsSize; i++) + { + if (scanner->default_format == NULL && !strcmp(scanner->DocumentFormats[i], "image/jpeg")) + { + scanner->default_format = strdup("image/jpeg"); + } +#if(defined HAVE_LIBPNG) + else if(!strcmp(scanner->DocumentFormats[i], "image/png") && (scanner->default_format == NULL || strcmp(scanner->default_format, "image/tiff"))) + { + if (scanner->default_format) + free(scanner->default_format); + scanner->default_format = strdup("image/png"); + } +#endif +#if(defined HAVE_TIFFIO_H) + else if(!strcmp(scanner->DocumentFormats[i], "image/tiff")) + { + if (scanner->default_format) + free(scanner->default_format); + scanner->default_format = strdup("image/tiff"); + } +#endif + } + fprintf(stderr, "Capability : [%s]\n", scanner->default_format); + } + else if (strcmp(name, "DocumentFormatExt") == 0) + scanner->format_ext = 1; + else if (strcmp(name, "Intent") == 0) + scanner->SupportedIntents = char_to_array(scanner->SupportedIntents, &scanner->SupportedIntentsSize, (SANE_String_Const)xmlNodeGetContent(node), 0); + else if (strcmp(name, "XResolution") == 0) + scanner->SupportedResolutions = int_to_array(scanner->SupportedResolutions, &scanner->SupportedResolutionsSize, atoi((const char *)xmlNodeGetContent(node))); + return (0); +} + +/** + * \fn static int find_value_of_int_variables(xmlNode *node, capabilities_t *scanner) + * \brief Function that searchs in the xml file if a integer scanner capabilitie is found. + * The integer scanner capabilities that are interesting are : + * MinWidth, MaxWidth, MaxHeight, MinHeight, MaxScanRegions, MaxOpticalXResolution, + * RiskyLeftMargin, RiskyRightMargin, RiskyTopMargin, RiskyBottomMargin. + * + * \return 0 + */ +static int +find_value_of_int_variables(xmlNode *node, capabilities_t *scanner) +{ + int MaxWidth = 0; + int MaxHeight = 0; + const char *name = (const char *)node->name; + + if (strcmp(name, "MinWidth") == 0) + scanner->MinWidth = atoi((const char*)xmlNodeGetContent(node)); + else if (strcmp(name, "MaxWidth") == 0) { + MaxWidth = atoi((const char*)xmlNodeGetContent(node)); + if (scanner->MaxWidth == 0 || MaxWidth < scanner->MaxWidth) + scanner->MaxWidth = atoi((const char *)xmlNodeGetContent(node)); + } + else if (strcmp(name, "MinHeight") == 0) + scanner->MinHeight = atoi((const char*)xmlNodeGetContent(node)); + else if (strcmp(name, "MaxHeight") == 0) { + MaxHeight = atoi((const char*)xmlNodeGetContent(node)); + if (scanner->MaxHeight == 0 || MaxHeight < scanner->MaxHeight) + scanner->MaxHeight = atoi((const char *)xmlNodeGetContent(node)); + } + else if (strcmp(name, "MaxScanRegions") == 0) + scanner->MaxScanRegions = atoi((const char *)xmlNodeGetContent(node)); + else if (strcmp(name, "MaxOpticalXResolution") == 0) + scanner->MaxOpticalXResolution = atoi((const char *)xmlNodeGetContent(node)); + else if (strcmp(name, "RiskyLeftMargin") == 0) + scanner->RiskyLeftMargin = atoi((const char *)xmlNodeGetContent(node)); + else if (strcmp(name, "RiskyRightMargin") == 0) + scanner->RiskyRightMargin = atoi((const char *)xmlNodeGetContent(node)); + else if (strcmp(name, "RiskyTopMargin") == 0) + scanner->RiskyTopMargin = atoi((const char *)xmlNodeGetContent(node)); + else if (strcmp(name, "RiskyBottomMargin") == 0) + scanner->RiskyBottomMargin = atoi((const char *)xmlNodeGetContent(node)); + find_valor_of_array_variables(node, scanner); + return (0); +} + +/** + * \fn static int find_true_variables(xmlNode *node, capabilities_t *scanner) + * \brief Function that searchs in the xml file if we find a scanner capabilitie stocked + * in one of the created array (character/integer array), + * or, if we find a integer scanner capabilitie. + * + * \return 0 + */ +static int +find_true_variables(xmlNode *node, capabilities_t *scanner) +{ + const char *name = (const char *)node->name; + if (strcmp(name, "MinWidth") == 0 || + strcmp(name, "MaxWidth") == 0 || + strcmp(name, "MinHeight") == 0 || + strcmp(name, "MaxHeight") == 0 || + strcmp(name, "MaxScanRegions") == 0 || + strcmp(name, "ColorMode") == 0 || + strcmp(name, "ContentType") == 0 || + strcmp(name, "DocumentFormat") == 0 || + strcmp(name, "XResolution") == 0 || + strcmp(name, "Intent") == 0 || + strcmp(name, "MaxOpticalXResolution") == 0 || + strcmp(name, "RiskyLeftMargin") == 0 || + strcmp(name, "RiskyRightMargin") == 0 || + strcmp(name, "RiskyTopMargin") == 0 || + strcmp(name, "RiskyBottomMargin") == 0 || + strcmp(name, "DocumentFormatExt") == 0) + find_value_of_int_variables(node, scanner); + return (0); +} + +/** + * \fn static int print_xml_c(xmlNode *node, capabilities_t *scanner) + * \brief Function that browses the xml file, node by node. + * + * \return 0 + */ +static int +print_xml_c(xmlNode *node, capabilities_t *scanner) +{ + while (node) { + if (node->type == XML_ELEMENT_NODE) { + if (find_nodes_c(node)) + find_true_variables(node, scanner); + } + print_xml_c(node->children, scanner); + node = node->next; + } + return (0); +} + +/** + * \fn capabilities_t *escl_capabilities(SANE_String_Const name, SANE_Status *status) + * \brief Function that finally recovers all the capabilities of the scanner, using curl. + * This function is called in the 'sane_open' function and it's the equivalent of + * the following curl command : "curl http(s)://'ip':'port'/eSCL/ScannerCapabilities". + * + * \return scanner (the structure that stocks all the capabilities elements) + */ +capabilities_t * +escl_capabilities(SANE_String_Const name, SANE_Status *status) +{ + capabilities_t *scanner = (capabilities_t*)calloc(1, sizeof(capabilities_t)); + CURL *curl_handle = NULL; + struct cap *var = NULL; + xmlDoc *data = NULL; + xmlNode *node = NULL; + const char *scanner_capabilities = "/eSCL/ScannerCapabilities"; + char tmp[PATH_MAX] = { 0 }; + + *status = SANE_STATUS_GOOD; + if (name == NULL) + *status = SANE_STATUS_NO_MEM; + var = (struct cap *)calloc(1, sizeof(struct cap)); + if (var == NULL) + *status = SANE_STATUS_NO_MEM; + var->memory = malloc(1); + var->size = 0; + curl_handle = curl_easy_init(); + strcpy(tmp, name); + strcat(tmp, scanner_capabilities); + DBG( 1, "Get Capabilities : %s\n", tmp); + curl_easy_setopt(curl_handle, CURLOPT_URL, tmp); + if (strncmp(name, "https", 5) == 0) { + DBG( 1, "Ignoring safety certificates, use https\n"); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + } + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_c); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var); + if (curl_easy_perform(curl_handle) != CURLE_OK) { + DBG( 1, "The scanner didn't respond.\n"); + *status = SANE_STATUS_INVAL; + } + data = xmlReadMemory(var->memory, var->size, "file.xml", NULL, 0); + if (data == NULL) + *status = SANE_STATUS_NO_MEM; + node = xmlDocGetRootElement(data); + if (node == NULL) + *status = SANE_STATUS_NO_MEM; + print_xml_c(node, scanner); + xmlFreeDoc(data); + xmlCleanupParser(); + xmlMemoryDump(); + curl_easy_cleanup(curl_handle); + free(var->memory); + return (scanner); +} diff --git a/backend/escl/escl_devices.c b/backend/escl/escl_devices.c new file mode 100644 index 0000000..7ecbe31 --- /dev/null +++ b/backend/escl/escl_devices.c @@ -0,0 +1,185 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include "../include/sane/sanei.h" + +static AvahiSimplePoll *simple_poll = NULL; + +/** + * \fn static void resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED + * AvahiIfIndex interface, AVAHI_GCC_UNUSED AvahiProtocol protocol, + * AvahiResolverEvent event, const char *name, + * const char *type, const char *domain, const char *host_name, + * const AvahiAddress *address, uint16_t port, + * AvahiStringList *txt, AvahiLookupResultFlags flags, + * void *userdata) + * \brief Callback function that will check if the selected scanner follows the escl + * protocol or not. + */ +static void +resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface, + AVAHI_GCC_UNUSED AvahiProtocol protocol, + AvahiResolverEvent event, const char *name, + const char __sane_unused__ *type, + const char __sane_unused__ *domain, + const char __sane_unused__ *host_name, + const AvahiAddress *address, uint16_t port, AvahiStringList *txt, + AvahiLookupResultFlags __sane_unused__ flags, + void __sane_unused__ *userdata) +{ + char a[AVAHI_ADDRESS_STR_MAX], *t; + assert(r); + switch (event) { + case AVAHI_RESOLVER_FAILURE: + break; + case AVAHI_RESOLVER_FOUND: + avahi_address_snprint(a, sizeof(a), address); + t = avahi_string_list_to_string(txt); + if (strstr(t, "\"rs=eSCL\"") || strstr(t, "\"rs=/eSCL\"")) + escl_device_add(port, name, a, (char*)type); + } +} + +/** + * \fn static void browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, + * AvahiProtocol protocol, AvahiBrowserEvent event, const char *name, + * const char *type, const char *domain, + * AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, void* userdata) + * \brief Callback function that will browse tanks to 'avahi' the scanners + * connected in network. + */ +static void +browse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface, + AvahiProtocol protocol, AvahiBrowserEvent event, + const char *name, const char *type, + const char *domain, + AVAHI_GCC_UNUSED AvahiLookupResultFlags flags, + void* userdata) +{ + AvahiClient *c = userdata; + assert(b); + switch (event) { + case AVAHI_BROWSER_FAILURE: + avahi_simple_poll_quit(simple_poll); + return; + case AVAHI_BROWSER_NEW: + if (!(avahi_service_resolver_new(c, interface, protocol, name, + type, domain, + AVAHI_PROTO_UNSPEC, 0, + resolve_callback, c))) + break; + case AVAHI_BROWSER_REMOVE: + break; + case AVAHI_BROWSER_ALL_FOR_NOW: + case AVAHI_BROWSER_CACHE_EXHAUSTED: + if (event != AVAHI_BROWSER_CACHE_EXHAUSTED) + avahi_simple_poll_quit(simple_poll); + break; + } +} + +/** + * \fn static void client_callback(AvahiClient *c, AvahiClientState state, + * AVAHI_GCC_UNUSED void *userdata) + * \brief Callback Function that quit if it doesn't find a connected scanner, + * possible thanks the "Hello Protocol". + * --> Waiting for a answer by the scanner to continue the avahi process. + */ +static void +client_callback(AvahiClient *c, AvahiClientState state, + AVAHI_GCC_UNUSED void *userdata) +{ + assert(c); + if (state == AVAHI_CLIENT_FAILURE) + avahi_simple_poll_quit(simple_poll); +} + +/** + * \fn ESCL_Device *escl_devices(SANE_Status *status) + * \brief Function that calls all the avahi functions and then, recovers the + * connected eSCL devices. + * This function is called in the 'sane_get_devices' function. + * + * \return NULL (the eSCL devices found) + */ +ESCL_Device * +escl_devices(SANE_Status *status) +{ + AvahiClient *client = NULL; + AvahiServiceBrowser *sb = NULL; + int error; + + *status = SANE_STATUS_GOOD; + if (!(simple_poll = avahi_simple_poll_new())) { + DBG( 1, "Failed to create simple poll object.\n"); + *status = SANE_STATUS_INVAL; + goto fail; + } + client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, + client_callback, NULL, &error); + if (!client) { + DBG( 1, "Failed to create client: %s\n", avahi_strerror(error)); + *status = SANE_STATUS_INVAL; + goto fail; + } + if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, "_uscan._tcp", + NULL, 0, browse_callback, client))) { + DBG( 1, "Failed to create service browser: %s\n", + avahi_strerror(avahi_client_errno(client))); + *status = SANE_STATUS_INVAL; + goto fail; + } + if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, + AVAHI_PROTO_UNSPEC, + "_uscans._tcp", NULL, 0, + browse_callback, client))) { + DBG( 1, "Failed to create service browser: %s\n", + avahi_strerror(avahi_client_errno(client))); + *status = SANE_STATUS_INVAL; + goto fail; + } + avahi_simple_poll_loop(simple_poll); +fail: + if (sb) + avahi_service_browser_free(sb); + if (client) + avahi_client_free(client); + if (simple_poll) + avahi_simple_poll_free(simple_poll); + return (NULL); +} diff --git a/backend/escl/escl_jpeg.c b/backend/escl/escl_jpeg.c new file mode 100644 index 0000000..d6287ef --- /dev/null +++ b/backend/escl/escl_jpeg.c @@ -0,0 +1,230 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include "../include/sane/sanei.h" + +#include +#include +#include + +#if(defined HAVE_LIBJPEG) +# include +#endif + +#include + +#define INPUT_BUFFER_SIZE 4096 + +#if(defined HAVE_LIBJPEG) +struct my_error_mgr +{ + struct jpeg_error_mgr errmgr; + jmp_buf escape; +}; + +typedef struct +{ + struct jpeg_source_mgr pub; + FILE *ctx; + unsigned char buffer[INPUT_BUFFER_SIZE]; +} my_source_mgr; + +/** + * \fn static boolean fill_input_buffer(j_decompress_ptr cinfo) + * \brief Called in the "skip_input_data" function. + * + * \return TRUE (everything is OK) + */ +static boolean +fill_input_buffer(j_decompress_ptr cinfo) +{ + my_source_mgr *src = (my_source_mgr *) cinfo->src; + int nbytes = 0; + + nbytes = fread(src->buffer, 1, INPUT_BUFFER_SIZE, src->ctx); + if (nbytes <= 0) { + src->buffer[0] = (unsigned char) 0xFF; + src->buffer[1] = (unsigned char) JPEG_EOI; + nbytes = 2; + } + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + return (TRUE); +} + +/** + * \fn static void skip_input_data(j_decompress_ptr cinfo, long num_bytes) + * \brief Called in the "jpeg_RW_src" function. + */ +static void +skip_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + my_source_mgr *src = (my_source_mgr *) cinfo->src; + + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) src->pub.fill_input_buffer(cinfo); + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + +static void +term_source(j_decompress_ptr __sane_unused__ cinfo) +{ + return; +} + +static void +init_source(j_decompress_ptr __sane_unused__ cinfo) +{ + return; +} + +/** + * \fn static void jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx) + * \brief Called in the "escl_sane_decompressor" function. + */ +static void +jpeg_RW_src(j_decompress_ptr cinfo, FILE *ctx) +{ + my_source_mgr *src; + + if (cinfo->src == NULL) { + cinfo->src = (struct jpeg_source_mgr *)(*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_PERMANENT, sizeof(my_source_mgr)); + src = (my_source_mgr *) cinfo->src; + } + src = (my_source_mgr *) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; + src->pub.term_source = term_source; + src->ctx = ctx; + src->pub.bytes_in_buffer = 0; + src->pub.next_input_byte = NULL; +} + +static void +my_error_exit(j_common_ptr cinfo) +{ + struct my_error_mgr *err = (struct my_error_mgr *)cinfo->err; + + longjmp(err->escape, 1); +} + +static void +output_no_message(j_common_ptr __sane_unused__ cinfo) +{ +} + +/** + * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) + * \brief Function that aims to decompress the jpeg image to SANE be able to read the image. + * This function is called in the "sane_read" function. + * + * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +get_JPEG_data(capabilities_t *scanner, int *w, int *h, int *bps) +{ + int start = 0; + struct jpeg_decompress_struct cinfo; + JSAMPROW rowptr[1]; + unsigned char *surface = NULL; + struct my_error_mgr jerr; + int lineSize = 0; + + if (scanner->tmp == NULL) + return (SANE_STATUS_INVAL); + fseek(scanner->tmp, SEEK_SET, 0); + start = ftell(scanner->tmp); + cinfo.err = jpeg_std_error(&jerr.errmgr); + jerr.errmgr.error_exit = my_error_exit; + jerr.errmgr.output_message = output_no_message; + if (setjmp(jerr.escape)) { + jpeg_destroy_decompress(&cinfo); + if (surface != NULL) + free(surface); + DBG( 1, "Escl Jpeg : Error reading jpeg\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + jpeg_create_decompress(&cinfo); + jpeg_RW_src(&cinfo, scanner->tmp); + jpeg_read_header(&cinfo, TRUE); + cinfo.out_color_space = JCS_RGB; + cinfo.quantize_colors = FALSE; + jpeg_calc_output_dimensions(&cinfo); + surface = malloc(cinfo.output_width * cinfo.output_height * cinfo.output_components); + if (surface == NULL) { + jpeg_destroy_decompress(&cinfo); + fseek(scanner->tmp, start, SEEK_SET); + DBG( 1, "Escl Jpeg : Memory allocation problem\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_NO_MEM); + } + lineSize = cinfo.output_width * cinfo.output_components; + jpeg_start_decompress(&cinfo); + while (cinfo.output_scanline < cinfo.output_height) { + rowptr[0] = (JSAMPROW)surface + (lineSize * cinfo.output_scanline); + jpeg_read_scanlines(&cinfo, rowptr, (JDIMENSION) 1); + } + scanner->img_data = surface; + scanner->img_size = lineSize * cinfo.output_height; + scanner->img_read = 0; + *w = cinfo.output_width; + *h = cinfo.output_height; + *bps = cinfo.output_components; + jpeg_finish_decompress(&cinfo); + jpeg_destroy_decompress(&cinfo); + fclose(scanner->tmp); + scanner->tmp = NULL; + return (SANE_STATUS_GOOD); +} +#else + +SANE_Status +get_JPEG_data(capabilities_t __sane_unused__ *scanner, + int __sane_unused__ *w, + int __sane_unused__ *h, + int __sane_unused__ *bps) +{ + return (SANE_STATUS_INVAL); +} + +#endif diff --git a/backend/escl/escl_newjob.c b/backend/escl/escl_newjob.c new file mode 100644 index 0000000..279b9df --- /dev/null +++ b/backend/escl/escl_newjob.c @@ -0,0 +1,241 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include +#include +#include + +#include + +#ifdef PATH_MAX +# undef PATH_MAX +#endif + +#define PATH_MAX 4096 + +struct uploading +{ + const char *read_data; + size_t size; +}; + +struct downloading +{ + char *memory; + size_t size; +}; + +static const char settings[] = + "" \ + "" \ + " 2.0" \ + " " \ + " " \ + " escl:ThreeHundredthsOfInches" \ + " %d" \ + " %d" \ + " %d" \ + " %d" \ + " " \ + " " \ + " %s" \ + "%s" \ + " %s" \ + " %d" \ + " %d" \ + " Platen" \ + ""; + +static char formatExtJPEG[] = + " image/jpeg"; + +static char formatExtPNG[] = + " image/png"; + +static char formatExtTIFF[] = + " image/tiff"; + +/** + * \fn static size_t download_callback(void *str, size_t size, size_t nmemb, void *userp) + * \brief Callback function that stocks in memory the content of the 'job'. Example below : + * "Trying 192.168.14.150... + * TCP_NODELAY set + * Connected to 192.168.14.150 (192.168.14.150) port 80 + * POST /eSCL/ScanJobs HTTP/1.1 + * Host: 192.168.14.150 + * User-Agent: curl/7.55.1 + * Accept: / + * Content-Length: 605 + * Content-Type: application/x-www-form-urlencoded + * upload completely sent off: 605 out of 605 bytes + * < HTTP/1.1 201 Created + * < MIME-Version: 1.0 + * < Location: http://192.168.14.150/eSCL/ScanJobs/22b54fd0-027b-1000-9bd0-f4a99726e2fa + * < Content-Length: 0 + * < Connection: close + * < + * Closing connection 0" + * + * \return realsize (size of the content needed -> the 'job') + */ +static size_t +download_callback(void *str, size_t size, size_t nmemb, void *userp) +{ + struct downloading *download = (struct downloading *)userp; + size_t realsize = size * nmemb; + char *content = realloc(download->memory, download->size + realsize + 1); + + if (content == NULL) { + DBG( 1, "Not enough memory (realloc returned NULL)\n"); + return (0); + } + download->memory = content; + memcpy(&(download->memory[download->size]), str, realsize); + download->size = download->size + realsize; + download->memory[download->size] = 0; + return (realsize); +} + +/** + * \fn char *escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *status) + * \brief Function that, using curl, uploads the data (composed by the scanner capabilities) to the + * server to download the 'job' and recover the 'new job' (char *result), in LOCATION. + * This function is called in the 'sane_start' function and it's the equivalent of the + * following curl command : "curl -v POST -d cap.xml http(s)://'ip':'port'/eSCL/ScanJobs". + * + * \return result (the 'new job', situated in LOCATION) + */ +char * +escl_newjob (capabilities_t *scanner, SANE_String_Const name, SANE_Status *status) +{ + CURL *curl_handle = NULL; + struct uploading *upload = NULL; + struct downloading *download = NULL; + const char *scan_jobs = "/eSCL/ScanJobs"; + char cap_data[PATH_MAX] = { 0 }; + char job_cmd[PATH_MAX] = { 0 }; + char *location = NULL; + char *result = NULL; + char *temporary = NULL; + char *f_ext = ""; + char *format_ext = NULL; + + *status = SANE_STATUS_GOOD; + if (name == NULL || scanner == NULL) { + *status = SANE_STATUS_NO_MEM; + DBG( 1, "Create NewJob : the name or the scan are invalid.\n"); + return (NULL); + } + upload = (struct uploading *)calloc(1, sizeof(struct uploading)); + if (upload == NULL) { + *status = SANE_STATUS_NO_MEM; + DBG( 1, "Create NewJob : memory allocation failure\n"); + return (NULL); + } + download = (struct downloading *)calloc(1, sizeof(struct downloading)); + if (download == NULL) { + free(upload); + DBG( 1, "Create NewJob : memory allocation failure\n"); + *status = SANE_STATUS_NO_MEM; + return (NULL); + } + curl_handle = curl_easy_init(); + if (scanner->format_ext == 1) + { + if (!strcmp(scanner->default_format, "image/jpeg")) + format_ext = formatExtJPEG; + else if (!strcmp(scanner->default_format, "image/png")) + format_ext = formatExtPNG; + else if (!strcmp(scanner->default_format, "image/tiff")) + format_ext = formatExtTIFF; + else + format_ext = f_ext; + } + else + format_ext = f_ext; + DBG( 1, "Create NewJob : %s\n", scanner->default_format); + if (curl_handle != NULL) { + snprintf(cap_data, sizeof(cap_data), settings, scanner->height, scanner->width, 0, 0, scanner->default_format, + format_ext, + scanner->default_color, scanner->default_resolution, scanner->default_resolution); + DBG( 1, "Create NewJob : %s\n", cap_data); + upload->read_data = strdup(cap_data); + upload->size = strlen(cap_data); + download->memory = malloc(1); + download->size = 0; + strcpy(job_cmd, name); + strcat(job_cmd, scan_jobs); + curl_easy_setopt(curl_handle, CURLOPT_URL, job_cmd); + if (strncmp(name, "https", 5) == 0) { + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + } + curl_easy_setopt(curl_handle, CURLOPT_POST, 1L); + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, upload->read_data); + curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDSIZE, upload->size); + curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, download_callback); + curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, (void *)download); + if (curl_easy_perform(curl_handle) != CURLE_OK) { + DBG( 1, "Create NewJob : the scanner responded incorrectly.\n"); + *status = SANE_STATUS_INVAL; + } + else { + if (download->memory != NULL) { + if (strstr(download->memory, "Location:")) { + temporary = strrchr(download->memory, '/'); + if (temporary != NULL) { + location = strchr(temporary, '\r'); + if (location == NULL) + location = strchr(temporary, '\n'); + else { + *location = '\0'; + result = strdup(temporary); + } + DBG( 1, "Create NewJob : %s\n", result); + } + free(download->memory); + } + else { + DBG( 1, "Create NewJob : The creation of the failed job\n"); + *status = SANE_STATUS_INVAL; + } + } + else { + *status = SANE_STATUS_NO_MEM; + DBG( 1, "Create NewJob : The creation of the failed job\n"); + return (NULL); + } + } + curl_easy_cleanup(curl_handle); + } + if (upload != NULL) + free(upload); + if (download != NULL) + free(download); + return (result); +} diff --git a/backend/escl/escl_png.c b/backend/escl/escl_png.c new file mode 100644 index 0000000..18f6f35 --- /dev/null +++ b/backend/escl/escl_png.c @@ -0,0 +1,193 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include "../include/sane/sanei.h" + +#include +#include +#include + +#if(defined HAVE_LIBPNG) +#include +#endif + +#include + + +#if(defined HAVE_LIBPNG) + +/** + * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) + * \brief Function that aims to decompress the png image to SANE be able to read the image. + * This function is called in the "sane_read" function. + * + * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +get_PNG_data(capabilities_t *scanner, int *w, int *h, int *components) +{ + unsigned int width = 0; /* largeur */ + unsigned int height = 0; /* hauteur */ + int bps = 3; /* composantes d'un texel */ + unsigned char *texels = NULL; /* données de l'image */ + unsigned int i = 0; + png_byte magic[8]; + + // read magic number + fread (magic, 1, sizeof (magic), scanner->tmp); + // check for valid magic number + if (!png_check_sig (magic, sizeof (magic))) + { + DBG( 1, "Escl Png : PNG error is not a valid PNG image!\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + // create a png read struct + png_structp png_ptr = png_create_read_struct + (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + { + DBG( 1, "Escl Png : PNG error create a png read struct\n"); + if (scanner->tmp) + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + // create a png info struct + png_infop info_ptr = png_create_info_struct (png_ptr); + if (!info_ptr) + { + DBG( 1, "Escl Png : PNG error create a png info struct\n"); + png_destroy_read_struct (&png_ptr, NULL, NULL); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + // initialize the setjmp for returning properly after a libpng + // error occured + if (setjmp (png_jmpbuf (png_ptr))) + { + png_destroy_read_struct (&png_ptr, &info_ptr, NULL); + if (texels) + free (texels); + fprintf(stderr,"PNG read error.\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + DBG( 1, "Escl Png : PNG read error.\n"); + return (SANE_STATUS_INVAL); + } + // setup libpng for using standard C fread() function + // with our FILE pointer + png_init_io (png_ptr, scanner->tmp); + // tell libpng that we have already read the magic number + png_set_sig_bytes (png_ptr, sizeof (magic)); + + // read png info + png_read_info (png_ptr, info_ptr); + + int bit_depth, color_type; + // get some usefull information from header + bit_depth = png_get_bit_depth (png_ptr, info_ptr); + color_type = png_get_color_type (png_ptr, info_ptr); + // convert index color images to RGB images + if (color_type == PNG_COLOR_TYPE_PALETTE) + png_set_palette_to_rgb (png_ptr); + else if (color_type != PNG_COLOR_TYPE_RGB && color_type != PNG_COLOR_TYPE_RGB_ALPHA) + { + fprintf(stderr,"PNG format not supported.\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + if (color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bps = 4; + else + bps = 3; + if (png_get_valid (png_ptr, info_ptr, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha (png_ptr); + if (bit_depth == 16) + png_set_strip_16 (png_ptr); + else if (bit_depth < 8) + png_set_packing (png_ptr); + // update info structure to apply transformations + png_read_update_info (png_ptr, info_ptr); + // retrieve updated information + png_get_IHDR (png_ptr, info_ptr, + (png_uint_32*)(&width), + (png_uint_32*)(&height), + &bit_depth, &color_type, + NULL, NULL, NULL); + + *w = (int)width; + *h = (int)height; + *components = bps; + // we can now allocate memory for storing pixel data + texels = (unsigned char *)malloc (sizeof (unsigned char) * width + * height * bps); + png_bytep *row_pointers; + // setup a pointer array. Each one points at the begening of a row. + row_pointers = (png_bytep *)malloc (sizeof (png_bytep) * height); + for (i = 0; i < height; ++i) + { + row_pointers[i] = (png_bytep)(texels + + ((height - (i + 1)) * width * bps)); + } + // read pixel data using row pointers + png_read_image (png_ptr, row_pointers); + // we don't need row pointers anymore + scanner->img_data = texels; + scanner->img_size = (int)(width * height * bps); + scanner->img_read = 0; + free (row_pointers); + fclose(scanner->tmp); + scanner->tmp = NULL; + return (SANE_STATUS_GOOD); +} +#else + +SANE_Status +get_PNG_data(capabilities_t __sane_unused__ *scanner, + int __sane_unused__ *w, + int __sane_unused__ *h, + int __sane_unused__ *bps) +{ + return (SANE_STATUS_INVAL); +} + +#endif diff --git a/backend/escl/escl_reset.c b/backend/escl/escl_reset.c new file mode 100644 index 0000000..7722d89 --- /dev/null +++ b/backend/escl/escl_reset.c @@ -0,0 +1,75 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include +#include + +#include + +/** + * \fn void escl_scanner(SANE_String_Const name, char *result) + * \brief Function that resets the scanner after each scan, using curl. + * This function is called in the 'sane_cancel' function. + */ +void +escl_scanner(SANE_String_Const name, char *result) +{ + CURL *curl_handle = NULL; + const char *scan_jobs = "/eSCL/ScanJobs"; + const char *scanner_start = "/NextDocument"; + char scan_cmd[PATH_MAX] = { 0 }; + int i = 0; + long answer = 0; + + if (name == NULL || result == NULL) + return; +CURL_CALL: + curl_handle = curl_easy_init(); + if (curl_handle != NULL) { + strcpy(scan_cmd, name); + strcat(scan_cmd, scan_jobs); + strcat(scan_cmd, result); + strcat(scan_cmd, scanner_start); + curl_easy_setopt(curl_handle, CURLOPT_URL, scan_cmd); + DBG( 1, "Reset Job : %s.\n", scan_cmd); + if (strncmp(name, "https", 5) == 0) { + DBG( 1, "Ignoring safety certificates, use https\n"); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + } + if (curl_easy_perform(curl_handle) == CURLE_OK) { + curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &answer); + if (i < 3 && answer == 503) { + curl_easy_cleanup(curl_handle); + i++; + goto CURL_CALL; + } + } + curl_easy_cleanup(curl_handle); + } +} diff --git a/backend/escl/escl_scan.c b/backend/escl/escl_scan.c new file mode 100644 index 0000000..8f077a1 --- /dev/null +++ b/backend/escl/escl_scan.c @@ -0,0 +1,99 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include +#include +#include + +#include + +#include "../include/sane/sanei.h" + +/** + * \fn static size_t write_callback(void *str, size_t size, size_t nmemb, void *userp) + * \brief Callback function that writes the image scanned into the temporary file. + * + * \return to_write (the result of the fwrite fonction) + */ +static size_t +write_callback(void *str, size_t size, size_t nmemb, void *userp) +{ + size_t to_write = fwrite(str, size, nmemb, (FILE *)userp); + + return (to_write); +} + +/** + * \fn SANE_Status escl_scan(capabilities_t *scanner, SANE_String_Const name, char *result) + * \brief Function that, after recovering the 'new job', scans the image writed in the + * temporary file, using curl. + * This function is called in the 'sane_start' function and it's the equivalent of + * the following curl command : "curl -s http(s)://'ip:'port'/eSCL/ScanJobs/'new job'/NextDocument > image.jpg". + * + * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +escl_scan(capabilities_t __sane_unused__ *scanner, SANE_String_Const name, char *result) +{ + CURL *curl_handle = NULL; + const char *scan_jobs = "/eSCL/ScanJobs"; + const char *scanner_start = "/NextDocument"; + char scan_cmd[PATH_MAX] = { 0 }; + SANE_Status status = SANE_STATUS_GOOD; + + if (name == NULL) + return (SANE_STATUS_NO_MEM); + curl_handle = curl_easy_init(); + if (curl_handle != NULL) { + strcpy(scan_cmd, name); + strcat(scan_cmd, scan_jobs); + strcat(scan_cmd, result); + strcat(scan_cmd, scanner_start); + curl_easy_setopt(curl_handle, CURLOPT_URL, scan_cmd); + DBG( 1, "Scan : %s.\n", scan_cmd); + if (strncmp(name, "https", 5) == 0) { + DBG( 1, "Ignoring safety certificates, use https\n"); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + } + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_callback); + scanner->tmp = tmpfile(); + if (scanner->tmp != NULL) { + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, scanner->tmp); + if (curl_easy_perform(curl_handle) != CURLE_OK) { + status = SANE_STATUS_INVAL; + } + else + curl_easy_cleanup(curl_handle); + fseek(scanner->tmp, 0, SEEK_SET); + } + else + status = SANE_STATUS_NO_MEM; + } + return (status); +} diff --git a/backend/escl/escl_status.c b/backend/escl/escl_status.c new file mode 100644 index 0000000..68b51dc --- /dev/null +++ b/backend/escl/escl_status.c @@ -0,0 +1,176 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include +#include +#include + +#include +#include + +struct idle +{ + char *memory; + size_t size; +}; + +/** + * \fn static size_t memory_callback_s(void *contents, size_t size, size_t nmemb, void *userp) + * \brief Callback function that stocks in memory the content of the scanner status. + * + * \return realsize (size of the content needed -> the scanner status) + */ +static size_t +memory_callback_s(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct idle *mem = (struct idle *)userp; + + char *str = realloc(mem->memory, mem->size + realsize + 1); + if (str == NULL) { + DBG(1, "not enough memory (realloc returned NULL)\n"); + return (0); + } + mem->memory = str; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size = mem->size + realsize; + mem->memory[mem->size] = 0; + return (realsize); +} + +/** + * \fn static int find_nodes_s(xmlNode *node) + * \brief Function that browses the xml file and parses it, to find the xml children node. + * --> to recover the scanner status. + * + * \return 0 if a xml child node is found, 1 otherwise + */ +static int +find_nodes_s(xmlNode *node) +{ + xmlNode *child = node->children; + + while (child) { + if (child->type == XML_ELEMENT_NODE) + return (0); + child = child->next; + } + return (1); +} + +/** + * \fn static void print_xml_s(xmlNode *node, SANE_Status *status) + * \brief Function that browses the xml file, node by node. + * If the node 'State' is found, we are expecting to found in this node the 'Idle' + * content (if the scanner is ready to use) and then 'status' = SANE_STATUS_GOOD. + * Otherwise, this means that the scanner isn't ready to use. + */ +static void +print_xml_s(xmlNode *node, SANE_Status *status) +{ + int x = 0; + + while (node) { + if (node->type == XML_ELEMENT_NODE) { + if (find_nodes_s(node)) { + if (strcmp((const char *)node->name, "State") == 0) + x = 1; + } + if (x == 1 && strcmp((const char *)xmlNodeGetContent(node), "Idle") == 0) + *status = SANE_STATUS_GOOD; + } + print_xml_s(node->children, status); + node = node->next; + } +} + +/** + * \fn SANE_Status escl_status(SANE_String_Const name) + * \brief Function that finally recovers the scanner status ('Idle', or not), using curl. + * This function is called in the 'sane_open' function and it's the equivalent of + * the following curl command : "curl http(s)://'ip':'port'/eSCL/ScannerStatus". + * + * \return status (if everything is OK, status = SANE_STATUS_GOOD, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +escl_status(SANE_String_Const name) +{ + SANE_Status status; + CURL *curl_handle = NULL; + struct idle *var = NULL; + xmlDoc *data = NULL; + xmlNode *node = NULL; + const char *scanner_status = "/eSCL/ScannerStatus"; + char tmp[PATH_MAX] = { 0 }; + + if (name == NULL) + return (SANE_STATUS_NO_MEM); + var = (struct idle*)calloc(1, sizeof(struct idle)); + if (var == NULL) + return (SANE_STATUS_NO_MEM); + var->memory = malloc(1); + var->size = 0; + curl_handle = curl_easy_init(); + strcpy(tmp, name); + strcat(tmp, scanner_status); + curl_easy_setopt(curl_handle, CURLOPT_URL, tmp); + DBG( 1, "Get Status : %s.\n", tmp); + if (strncmp(name, "https", 5) == 0) { + DBG( 1, "Ignoring safety certificates, use https\n"); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + } + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_s); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var); + if (curl_easy_perform(curl_handle) != CURLE_OK) { + DBG( 1, "The scanner didn't respond.\n"); + status = SANE_STATUS_INVAL; + goto clean_data; + } + data = xmlReadMemory(var->memory, var->size, "file.xml", NULL, 0); + if (data == NULL) { + status = SANE_STATUS_NO_MEM; + goto clean_data; + } + node = xmlDocGetRootElement(data); + if (node == NULL) { + status = SANE_STATUS_NO_MEM; + goto clean; + } + status = SANE_STATUS_DEVICE_BUSY; + print_xml_s(node, &status); +clean: + xmlFreeDoc(data); +clean_data: + xmlCleanupParser(); + xmlMemoryDump(); + curl_easy_cleanup(curl_handle); + free(var->memory); + free(var); + return (status); +} diff --git a/backend/escl/escl_tiff.c b/backend/escl/escl_tiff.c new file mode 100644 index 0000000..52aec20 --- /dev/null +++ b/backend/escl/escl_tiff.c @@ -0,0 +1,119 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Touboul Nathane + Copyright (C) 2019 Thierry HUCHARD + + This file is part of the SANE package. + + SANE 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 3 of the License, or (at your + option) any later version. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + This file implements a SANE backend for eSCL scanners. */ + +#define DEBUG_DECLARE_ONLY +#include "../include/sane/config.h" + +#include "escl.h" + +#include "../include/sane/sanei.h" + +#include +#include +#include +#include + +#if(defined HAVE_TIFFIO_H) +#include +#endif + +#include + + +#if(defined HAVE_TIFFIO_H) + +/** + * \fn SANE_Status escl_sane_decompressor(escl_sane_t *handler) + * \brief Function that aims to decompress the png image to SANE be able to read the image. + * This function is called in the "sane_read" function. + * + * \return SANE_STATUS_GOOD (if everything is OK, otherwise, SANE_STATUS_NO_MEM/SANE_STATUS_INVAL) + */ +SANE_Status +get_TIFF_data(capabilities_t *scanner, int *w, int *h, int *components) +{ + TIFF* tif = NULL; + uint32 width = 0; /* largeur */ + uint32 height = 0; /* hauteur */ + unsigned char *raster = NULL; /* données de l'image */ + int bps = 4; + uint32 npixels = 0; + + lseek(fileno(scanner->tmp), 0, SEEK_SET); + tif = TIFFFdOpen(fileno(scanner->tmp), "temp", "r"); + if (!tif) { + DBG( 1, "Escl Tiff : Can not open, or not a TIFF file.\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + + TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width); + TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height); + npixels = width * height; + raster = (unsigned char*) malloc(npixels * sizeof (uint32)); + if (raster != NULL) + { + DBG( 1, "Escl Tiff : Memory allocation problem.\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + + if (!TIFFReadRGBAImage(tif, width, height, (uint32 *)raster, 0)) + { + DBG( 1, "Escl Tiff : Problem reading image data.\n"); + if (scanner->tmp) { + fclose(scanner->tmp); + scanner->tmp = NULL; + } + return (SANE_STATUS_INVAL); + } + *w = (int)width; + *h = (int)height; + *components = bps; + // we don't need row pointers anymore + scanner->img_data = raster; + scanner->img_size = (int)(width * height * bps); + scanner->img_read = 0; + TIFFClose(tif); + fclose(scanner->tmp); + scanner->tmp = NULL; + return (SANE_STATUS_GOOD); +} +#else + +SANE_Status +get_TIFF_data(capabilities_t __sane_unused__ *scanner, + int __sane_unused__ *w, + int __sane_unused__ *h, + int __sane_unused__ *bps) +{ + return (SANE_STATUS_INVAL); +} + +#endif diff --git a/backend/fujitsu.c b/backend/fujitsu.c index 3ac4c8e..5dc466c 100644 --- a/backend/fujitsu.c +++ b/backend/fujitsu.c @@ -6,7 +6,7 @@ Copyright (C) 2000 Randolph Bentson Copyright (C) 2001 Frederik Ramm Copyright (C) 2001-2004 Oliver Schirrmeister - Copyright (C) 2003-2016 m. allan noah + Copyright (C) 2003-2019 m. allan noah JPEG output and low memory usage support funded by: Archivista GmbH, www.archivista.ch @@ -603,6 +603,8 @@ v134 2019-02-23, MAN - rewrite init_vpd for scanners which fail to report overscan correctly + v135 2019-11-10, MAN + - set has_MS_lamp=0 for fi-72x0, bug #134 SANE FLOW DIAGRAM @@ -2404,6 +2406,8 @@ init_model (struct fujitsu *s) else if (strstr (s->model_name,"fi-7280") || strstr (s->model_name,"fi-7260")){ + /* locks up scanner if we try to auto detect */ + s->has_MS_lamp = 0; /* weirdness */ /* these machines have longer max paper at lower res */ @@ -4377,7 +4381,7 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) if(option==OPT_TOP){ opt->name = "top-edge"; opt->title = SANE_I18N ("Top edge"); - opt->desc = SANE_I18N ("Paper is pulled partly into adf"); + opt->desc = SANE_I18N ("Paper is pulled partly into ADF"); opt->type = SANE_TYPE_BOOL; opt->unit = SANE_UNIT_NONE; if (s->has_cmd_hw_status || s->ghs_in_rs) @@ -6935,7 +6939,7 @@ sane_start (SANE_Handle handle) else{ ret = scanner_control(s, SC_function_adf); if (ret != SANE_STATUS_GOOD) { - DBG (5, "sane_start: ERROR: cannot control adf, ignoring\n"); + DBG (5, "sane_start: ERROR: cannot control ADF, ignoring\n"); } } diff --git a/backend/fujitsu.conf.in b/backend/fujitsu.conf.in index cb33f15..4f2b1a9 100644 --- a/backend/fujitsu.conf.in +++ b/backend/fujitsu.conf.in @@ -252,3 +252,6 @@ usb 0x04c5 0x1521 #fi-7700S usb 0x04c5 0x1522 + +#ScanSnap iX1500 +usb 0x04c5 0x159f diff --git a/backend/genesys.cc b/backend/genesys.cc deleted file mode 100644 index 0368e21..0000000 --- a/backend/genesys.cc +++ /dev/null @@ -1,7580 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003, 2004 Henning Meier-Geinitz - Copyright (C) 2004, 2005 Gerhard Jaeger - Copyright (C) 2004-2016 Stéphane Voltz - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2006 Laurent Charpentier - Copyright (C) 2007 Luke - Copyright (C) 2010 Chris Berry and Michael Rickmann - for Plustek Opticbook 3600 support - - Dynamic rasterization code was taken from the epjistsu backend by - m. allan noah - - Software processing for deskew, crop and dspeckle are inspired by allan's - noah work in the fujitsu backend - - 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. -*/ - -/* - * SANE backend for Genesys Logic GL646/GL841/GL842/GL843/GL846/GL847/GL124 based scanners - */ - -#define DEBUG_NOT_STATIC - -#include "genesys.h" -#include "genesys_sanei.h" -#include "../include/sane/sanei_config.h" -#include "../include/sane/sanei_magic.h" -#include "genesys_devices.cc" - -#include -#include -#include -#include -#include - -StaticInit> s_scanners; -StaticInit> s_sane_devices; -StaticInit> s_sane_devices_ptrs; -StaticInit> s_devices; - -static SANE_String_Const mode_list[] = { - SANE_VALUE_SCAN_MODE_COLOR, - SANE_VALUE_SCAN_MODE_GRAY, - /* SANE_TITLE_HALFTONE, currently unused */ - SANE_VALUE_SCAN_MODE_LINEART, - 0 -}; - -static SANE_String_Const color_filter_list[] = { - SANE_I18N ("Red"), - SANE_I18N ("Green"), - SANE_I18N ("Blue"), - 0 -}; - -static SANE_String_Const cis_color_filter_list[] = { - SANE_I18N ("Red"), - SANE_I18N ("Green"), - SANE_I18N ("Blue"), - SANE_I18N ("None"), - 0 -}; - -static SANE_String_Const source_list[] = { - SANE_I18N (STR_FLATBED), - SANE_I18N (STR_TRANSPARENCY_ADAPTER), - 0 -}; - -static const char* source_list_infrared[] = { - SANE_I18N(STR_FLATBED), - SANE_I18N(STR_TRANSPARENCY_ADAPTER), - SANE_I18N(STR_TRANSPARENCY_ADAPTER_INFRARED), - 0 -}; - -static SANE_Range swdespeck_range = { - 1, - 9, - 1 -}; - -static SANE_Range time_range = { - 0, /* minimum */ - 60, /* maximum */ - 0 /* quantization */ -}; - -static const SANE_Range u12_range = { - 0, /* minimum */ - 4095, /* maximum */ - 0 /* quantization */ -}; - -static const SANE_Range u14_range = { - 0, /* minimum */ - 16383, /* maximum */ - 0 /* quantization */ -}; - -static const SANE_Range u16_range = { - 0, /* minimum */ - 65535, /* maximum */ - 0 /* quantization */ -}; - -static const SANE_Range percentage_range = { - SANE_FIX (0), /* minimum */ - SANE_FIX (100), /* maximum */ - SANE_FIX (1) /* quantization */ -}; - -static const SANE_Range threshold_curve_range = { - 0, /* minimum */ - 127, /* maximum */ - 1 /* quantization */ -}; - -/** - * range for brightness and contrast - */ -static const SANE_Range enhance_range = { - -100, /* minimum */ - 100, /* maximum */ - 1 /* quantization */ -}; - -/** - * range for expiration time - */ -static const SANE_Range expiration_range = { - -1, /* minimum */ - 30000, /* maximum */ - 1 /* quantization */ -}; - -Genesys_Sensor& sanei_genesys_find_sensor_any_for_write(Genesys_Device* dev) -{ - for (auto& sensor : *s_sensors) { - if (dev->model->ccd_type == sensor.sensor_id) { - return sensor; - } - } - throw std::runtime_error("Given device does not have sensor defined"); -} - -const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev) -{ - for (const auto& sensor : *s_sensors) { - if (dev->model->ccd_type == sensor.sensor_id) { - return sensor; - } - } - throw std::runtime_error("Given device does not have sensor defined"); -} - -const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, int dpi, - ScanMethod scan_method) -{ - for (const auto& sensor : *s_sensors) { - if (dev->model->ccd_type == sensor.sensor_id && - (sensor.min_resolution == -1 || dpi >= sensor.min_resolution) && - (sensor.max_resolution == -1 || dpi <= sensor.max_resolution) && - sensor.method == scan_method) { - return sensor; - } - } - throw std::runtime_error("Given device does not have sensor defined"); -} - -Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, int dpi, - ScanMethod scan_method) -{ - for (auto& sensor : *s_sensors) { - if (dev->model->ccd_type == sensor.sensor_id && - (sensor.min_resolution == -1 || dpi >= sensor.min_resolution) && - (sensor.max_resolution == -1 || dpi <= sensor.max_resolution) && - sensor.method == scan_method) { - return sensor; - } - } - throw std::runtime_error("Given device does not have sensor defined"); -} - - -void -sanei_genesys_init_structs (Genesys_Device * dev) -{ - unsigned int i, gpo_ok = 0, motor_ok = 0; - bool fe_ok = false; - - /* initialize the GPO data stuff */ - for (i = 0; i < sizeof (Gpo) / sizeof (Genesys_Gpo); i++) - { - if (dev->model->gpo_type == Gpo[i].gpo_id) - { - dev->gpo = Gpo[i]; - gpo_ok = 1; - } - } - - /* initialize the motor data stuff */ - for (i = 0; i < sizeof (Motor) / sizeof (Genesys_Motor); i++) - { - if (dev->model->motor_type == Motor[i].motor_id) - { - dev->motor = Motor[i]; - motor_ok = 1; - } - } - - for (const auto& frontend : *s_frontends) { - if (dev->model->dac_type == frontend.fe_id) { - dev->frontend_initial = frontend; - fe_ok = true; - break; - } - } - - /* sanity check */ - if (motor_ok == 0 || gpo_ok == 0 || !fe_ok) - { - DBG(DBG_error0, "%s: bad description(s) for fe/gpo/motor=%d/%d/%d\n", __func__, - dev->model->ccd_type, dev->model->gpo_type, dev->model->motor_type); - } - - /* set up initial line distance shift */ - dev->ld_shift_r = dev->model->ld_shift_r; - dev->ld_shift_g = dev->model->ld_shift_g; - dev->ld_shift_b = dev->model->ld_shift_b; -} - -/* main function for slope creation */ -/** - * This function generates a slope table using the given slope - * truncated at the given exposure time or step count, whichever comes first. - * The reached step time is then stored in final_exposure and used for the rest - * of the table. The summed time of the acceleration steps is returned, and the - * number of accerelation steps is put into used_steps. - * - * @param slope_table Table to write to - * @param max_steps Size of slope_table in steps - * @param use_steps Maximum number of steps to use for acceleration - * @param stop_at Minimum step time to use - * @param vstart Start step time of default slope - * @param vend End step time of default slope - * @param steps Step count of default slope - * @param g Power for default slope - * @param used_steps Final number of steps is stored here - * @param vfinal Final step time is stored here - * @return Time for acceleration - * @note All times in pixel time. Correction for other motor timings is not - * done. - */ -SANE_Int -sanei_genesys_generate_slope_table (uint16_t * slope_table, - unsigned int max_steps, - unsigned int use_steps, - uint16_t stop_at, - uint16_t vstart, - uint16_t vend, - unsigned int steps, - double g, - unsigned int *used_steps, - unsigned int *vfinal) -{ - double t; - SANE_Int sum = 0; - unsigned int i; - unsigned int c = 0; - uint16_t t2; - unsigned int dummy; - unsigned int _vfinal; - if (!used_steps) - used_steps = &dummy; - if (!vfinal) - vfinal = &_vfinal; - - DBG(DBG_proc, "%s: table size: %d\n", __func__, max_steps); - - DBG(DBG_proc, "%s: stop at time: %d, use %d steps max\n", __func__, stop_at, use_steps); - - DBG(DBG_proc, "%s: target slope: vstart: %d, vend: %d, steps: %d, g: %g\n", __func__, vstart, - vend, steps, g); - - sum = 0; - c = 0; - *used_steps = 0; - - if (use_steps < 1) - use_steps = 1; - - if (stop_at < vstart) - { - t2 = vstart; - for (i = 0; i < steps && i < use_steps - 1 && i < max_steps; i++, c++) - { - t = pow (((double) i) / ((double) (steps - 1)), g); - t2 = vstart * (1 - t) + t * vend; - if (t2 < stop_at) - break; - *slope_table++ = t2; - /* DBG (DBG_io, "slope_table[%3d] = %5d\n", c, t2); */ - sum += t2; - } - if (t2 > stop_at) - { - DBG(DBG_warn, "Can not reach target speed(%d) in %d steps.\n", stop_at, use_steps); - DBG(DBG_warn, "Expect image to be distorted. Ignore this if only feeding.\n"); - } - *vfinal = t2; - *used_steps += i; - max_steps -= i; - } - else - *vfinal = stop_at; - - for (i = 0; i < max_steps; i++, c++) - { - *slope_table++ = *vfinal; - /* DBG (DBG_io, "slope_table[%3d] = %5d\n", c, *vfinal); */ - } - - (*used_steps)++; - sum += *vfinal; - - DBG(DBG_proc, "%s: returns sum=%d, used %d steps, completed\n", __func__, sum, *used_steps); - - return sum; -} - -/* Generate slope table for motor movement */ -/** - * This function generates a slope table using the slope from the motor struct - * truncated at the given exposure time or step count, whichever comes first. - * The reached step time is then stored in final_exposure and used for the rest - * of the table. The summed time of the acceleration steps is returned, and the - * number of accerelation steps is put into used_steps. - * - * @param dev Device struct - * @param slope_table Table to write to - * @param max_step Size of slope_table in steps - * @param use_steps Maximum number of steps to use for acceleration - * @param step_type Generate table for this step_type. 0=>full, 1=>half, - * 2=>quarter - * @param exposure_time Minimum exposure time of a scan line - * @param yres Resolution of a scan line - * @param used_steps Final number of steps is stored here - * @param final_exposure Final step time is stored here - * @param power_mode Power mode (related to the Vref used) of the motor - * @return Time for acceleration - * @note all times in pixel time - */ -SANE_Int -sanei_genesys_create_slope_table3 (Genesys_Device * dev, - uint16_t * slope_table, - int max_step, - unsigned int use_steps, - int step_type, - int exposure_time, - double yres, - unsigned int *used_steps, - unsigned int *final_exposure, - int power_mode) -{ - unsigned int sum_time = 0; - unsigned int vtarget; - unsigned int vend; - unsigned int vstart; - unsigned int vfinal; - - DBG(DBG_proc, "%s: step_type = %d, exposure_time = %d, yres = %g, power_mode = %d\n", __func__, - step_type, exposure_time, yres, power_mode); - - /* final speed */ - vtarget = (exposure_time * yres) / dev->motor.base_ydpi; - - vstart = dev->motor.slopes[power_mode][step_type].maximum_start_speed; - vend = dev->motor.slopes[power_mode][step_type].maximum_speed; - - vtarget >>= step_type; - if (vtarget > 65535) - vtarget = 65535; - - vstart >>= step_type; - if (vstart > 65535) - vstart = 65535; - - vend >>= step_type; - if (vend > 65535) - vend = 65535; - - sum_time = sanei_genesys_generate_slope_table (slope_table, - max_step, - use_steps, - vtarget, - vstart, - vend, - dev->motor.slopes[power_mode][step_type].minimum_steps << step_type, - dev->motor.slopes[power_mode][step_type].g, - used_steps, - &vfinal); - - if (final_exposure) - *final_exposure = (vfinal * dev->motor.base_ydpi) / yres; - - DBG(DBG_proc, "%s: returns sum_time=%d, completed\n", __func__, sum_time); - - return sum_time; -} - - -/* alternate slope table creation function */ -/* the hardcoded values (g and vstart) will go in a motor struct */ -static SANE_Int -genesys_create_slope_table2 (Genesys_Device * dev, - uint16_t * slope_table, int steps, - int step_type, int exposure_time, - SANE_Bool same_speed, double yres, - int power_mode) -{ - double t, g; - SANE_Int sum = 0; - int vstart, vend; - int i; - - DBG(DBG_proc, "%s: %d steps, step_type = %d, " - "exposure_time = %d, same_speed = %d, yres = %.2f, power_mode = %d\n", __func__, steps, - step_type, exposure_time, same_speed, yres, power_mode); - - /* start speed */ - if (dev->model->motor_type == MOTOR_5345) - { - if (yres < dev->motor.base_ydpi / 6) - vstart = 2500; - else - vstart = 2000; - } - else - { - if (steps == 2) - vstart = exposure_time; - else if (steps == 3) - vstart = 2 * exposure_time; - else if (steps == 4) - vstart = 1.5 * exposure_time; - else if (steps == 120) - vstart = 1.81674 * exposure_time; - else - vstart = exposure_time; - } - - /* final speed */ - vend = (exposure_time * yres) / (dev->motor.base_ydpi * (1 << step_type)); - - /* - type=1 : full - type=2 : half - type=4 : quarter - vend * type * base_ydpi / exposure = yres - */ - - /* acceleration */ - switch (steps) - { - case 255: - /* test for special case: fast moving slope */ - /* todo: a 'fast' boolean parameter should be better */ - if (vstart == 2000) - g = 0.2013; - else - g = 0.1677; - break; - case 120: - g = 0.5; - break; - case 67: - g = 0.5; - break; - case 64: - g = 0.2555; - break; - case 44: - g = 0.5; - break; - case 4: - g = 0.5; - break; - case 3: - g = 1; - break; - case 2: - vstart = vend; - g = 1; - break; - default: - g = 0.2635; - } - - /* if same speed, no 'g' */ - sum = 0; - if (same_speed) - { - for (i = 0; i < 255; i++) - { - slope_table[i] = vend; - sum += slope_table[i]; - DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); - } - } - else - { - for (i = 0; i < steps; i++) - { - t = pow (((double) i) / ((double) (steps - 1)), g); - slope_table[i] = vstart * (1 - t) + t * vend; - DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); - sum += slope_table[i]; - } - for (i = steps; i < 255; i++) - { - slope_table[i] = vend; - DBG (DBG_io, "slope_table[%3d] = %5d\n", i, slope_table[i]); - sum += slope_table[i]; - } - } - - DBG(DBG_proc, "%s: returns sum=%d, completed\n", __func__, sum); - - return sum; -} - -/* Generate slope table for motor movement */ -/* todo: check details */ -SANE_Int -sanei_genesys_create_slope_table (Genesys_Device * dev, - uint16_t * slope_table, int steps, - int step_type, int exposure_time, - SANE_Bool same_speed, double yres, - int power_mode) -{ - double t; - double start_speed; - double g; - uint32_t time_period; - int sum_time = 0; - int i, divider; - int same_step; - - if (dev->model->motor_type == MOTOR_5345 - || dev->model->motor_type == MOTOR_HP2300 - || dev->model->motor_type == MOTOR_HP2400) - return genesys_create_slope_table2 (dev, slope_table, steps, - step_type, exposure_time, - same_speed, yres, power_mode); - - DBG(DBG_proc, "%s: %d steps, step_type = %d, exposure_time = %d, same_speed =%d\n", __func__, - steps, step_type, exposure_time, same_speed); - DBG(DBG_proc, "%s: yres = %.2f\n", __func__, yres); - - g = 0.6; - start_speed = 0.01; - same_step = 4; - divider = 1 << step_type; - - time_period = - (uint32_t) (yres * exposure_time / dev->motor.base_ydpi /*MOTOR_GEAR */ ); - if ((time_period < 2000) && (same_speed)) - same_speed = SANE_FALSE; - - time_period = time_period / divider; - - if (same_speed) - { - for (i = 0; i < steps; i++) - { - slope_table[i] = (uint16_t) time_period; - sum_time += time_period; - - DBG (DBG_io, "slope_table[%d] = %d\n", i, time_period); - } - DBG(DBG_info, "%s: returns sum_time=%d, completed\n", __func__, sum_time); - return sum_time; - } - - if (time_period > MOTOR_SPEED_MAX * 5) - { - g = 1.0; - start_speed = 0.05; - same_step = 2; - } - else if (time_period > MOTOR_SPEED_MAX * 4) - { - g = 0.8; - start_speed = 0.04; - same_step = 2; - } - else if (time_period > MOTOR_SPEED_MAX * 3) - { - g = 0.7; - start_speed = 0.03; - same_step = 2; - } - else if (time_period > MOTOR_SPEED_MAX * 2) - { - g = 0.6; - start_speed = 0.02; - same_step = 3; - } - - if (dev->model->motor_type == MOTOR_ST24) - { - steps = 255; - switch ((int) yres) - { - case 2400: - g = 0.1672; - start_speed = 1.09; - break; - case 1200: - g = 1; - start_speed = 6.4; - break; - case 600: - g = 0.1672; - start_speed = 1.09; - break; - case 400: - g = 0.2005; - start_speed = 20.0 / 3.0 /*7.5 */ ; - break; - case 300: - g = 0.253; - start_speed = 2.182; - break; - case 150: - g = 0.253; - start_speed = 4.367; - break; - default: - g = 0.262; - start_speed = 7.29; - } - same_step = 1; - } - - if (steps <= same_step) - { - time_period = - (uint32_t) (yres * exposure_time / - dev->motor.base_ydpi /*MOTOR_GEAR */ ); - time_period = time_period / divider; - - if (time_period > 65535) - time_period = 65535; - - for (i = 0; i < same_step; i++) - { - slope_table[i] = (uint16_t) time_period; - sum_time += time_period; - - DBG (DBG_io, "slope_table[%d] = %d\n", i, time_period); - } - - DBG(DBG_proc, "%s: returns sum_time=%d, completed\n", __func__, sum_time); - return sum_time; - } - - for (i = 0; i < steps; i++) - { - double j = ((double) i) - same_step + 1; /* start from 1/16 speed */ - - if (j <= 0) - t = 0; - else - t = pow (j / (steps - same_step), g); - - time_period = /* time required for full steps */ - (uint32_t) (yres * exposure_time / - dev->motor.base_ydpi /*MOTOR_GEAR */ * - (start_speed + (1 - start_speed) * t)); - - time_period = time_period / divider; - if (time_period > 65535) - time_period = 65535; - - slope_table[i] = (uint16_t) time_period; - sum_time += time_period; - - DBG (DBG_io, "slope_table[%d] = %d\n", i, slope_table[i]); - } - - DBG(DBG_proc, "%s: returns sum_time=%d, completed\n", __func__, sum_time); - - return sum_time; -} - -/** @brief computes gamma table - * Generates a gamma table of the given length within 0 and the given - * maximum value - * @param gamma_table gamma table to fill - * @param size size of the table - * @param maximum value allowed for gamma - * @param gamma_max maximum gamma value - * @param gamma gamma to compute values - * @return a gamma table filled with the computed values - * */ -void -sanei_genesys_create_gamma_table (std::vector& gamma_table, int size, - float maximum, float gamma_max, float gamma) -{ - gamma_table.clear(); - gamma_table.resize(size, 0); - - int i; - float value; - - DBG(DBG_proc, "%s: size = %d, ""maximum = %g, gamma_max = %g, gamma = %g\n", __func__, size, - maximum, gamma_max, gamma); - for (i = 0; i < size; i++) - { - value = gamma_max * pow ((float) i / size, 1.0 / gamma); - if (value > maximum) - value = maximum; - gamma_table[i] = value; - } - DBG(DBG_proc, "%s: completed\n", __func__); -} - -void sanei_genesys_create_default_gamma_table(Genesys_Device* dev, - std::vector& gamma_table, float gamma) -{ - int size = 0; - int max = 0; - if (dev->model->asic_type == GENESYS_GL646) { - if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) { - size = 16384; - } else { - size = 4096; - } - max = size - 1; - } else { - size = 256; - max = 65535; - } - sanei_genesys_create_gamma_table(gamma_table, size, max, max, gamma); -} - -/* computes the exposure_time on the basis of the given vertical dpi, - the number of pixels the ccd needs to send, - the step_type and the corresponding maximum speed from the motor struct */ -/* - Currently considers maximum motor speed at given step_type, minimum - line exposure needed for conversion and led exposure time. - - TODO: Should also consider maximum transfer rate: ~6.5MB/s. - Note: The enhance option of the scanners does _not_ help. It only halves - the amount of pixels transfered. - */ -SANE_Int -sanei_genesys_exposure_time2 (Genesys_Device * dev, float ydpi, - int step_type, int endpixel, - int exposure_by_led, int power_mode) -{ - int exposure_by_ccd = endpixel + 32; - int exposure_by_motor = - (dev->motor.slopes[power_mode][step_type].maximum_speed - * dev->motor.base_ydpi) / ydpi; - - int exposure = exposure_by_ccd; - - if (exposure < exposure_by_motor) - exposure = exposure_by_motor; - - if (exposure < exposure_by_led && dev->model->is_cis) - exposure = exposure_by_led; - - DBG(DBG_info, "%s: ydpi=%d, step=%d, endpixel=%d led=%d, power=%d => exposure=%d\n", __func__, - (int)ydpi, step_type, endpixel, exposure_by_led, power_mode, exposure); - return exposure; -} - -/* computes the exposure_time on the basis of the given horizontal dpi */ -/* we will clean/simplify it by using constants from a future motor struct */ -SANE_Int -sanei_genesys_exposure_time (Genesys_Device * dev, Genesys_Register_Set * reg, - int xdpi) -{ - if (dev->model->motor_type == MOTOR_5345) - { - if (dev->model->cmd_set->get_filter_bit (reg)) - { - /* monochrome */ - switch (xdpi) - { - case 600: - return 8500; - case 500: - case 400: - case 300: - case 250: - case 200: - case 150: - return 5500; - case 100: - return 6500; - case 50: - return 12000; - default: - return 11000; - } - } - else - { - /* color scan */ - switch (xdpi) - { - case 300: - case 250: - case 200: - return 5500; - case 50: - return 12000; - default: - return 11000; - } - } - } - else if (dev->model->motor_type == MOTOR_HP2400) - { - if (dev->model->cmd_set->get_filter_bit (reg)) - { - /* monochrome */ - switch (xdpi) - { - case 200: - return 7210; - default: - return 11111; - } - } - else - { - /* color scan */ - switch (xdpi) - { - case 600: - return 8751; /*11902; 19200 */ - default: - return 11111; - } - } - } - else if (dev->model->motor_type == MOTOR_HP2300) - { - if (dev->model->cmd_set->get_filter_bit (reg)) - { - /* monochrome */ - switch (xdpi) - { - case 600: - return 8699; /* 3200; */ - case 300: - return 3200; /*10000;, 3200 -> too dark */ - case 150: - return 4480; /* 3200 ???, warmup needs 4480 */ - case 75: - return 5500; - default: - return 11111; - } - } - else - { - /* color scan */ - switch (xdpi) - { - case 600: - return 8699; - case 300: - return 4349; - case 150: - case 75: - return 4480; - default: - return 11111; - } - } - } - return 11000; -} - - - -/* Sends a block of shading information to the scanner. - The data is placed at address 0x0000 for color mode, gray mode and - unconditionally for the following CCD chips: HP2300, HP2400 and HP5345 - In the other cases (lineart, halftone on ccd chips not mentioned) the - addresses are 0x2a00 for dpihw==0, 0x5500 for dpihw==1 and 0xa800 for - dpihw==2. //Note: why this? - - The data needs to be of size "size", and in little endian byte order. - */ -static SANE_Status -genesys_send_offset_and_shading (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * data, - int size) -{ - int dpihw; - int start_address; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s: (size = %d)\n", __func__, size); - - /* ASIC higher than gl843 doesn't have register 2A/2B, so we route to - * a per ASIC shading data loading function if available. - * It is also used for scanners using SHDAREA */ - if(dev->model->cmd_set->send_shading_data!=NULL) - { - status=dev->model->cmd_set->send_shading_data(dev, sensor, data, size); - DBGCOMPLETED; - return status; - } - - /* gl646, gl84[123] case */ - dpihw = dev->reg.get8(0x05) >> 6; - - /* TODO invert the test so only the 2 models behaving like that are - * tested instead of adding all the others */ - /* many scanners send coefficient for lineart/gray like in color mode */ - if ((dev->settings.scan_mode == ScanColorMode::LINEART || - dev->settings.scan_mode == ScanColorMode::HALFTONE) - && dev->model->ccd_type != CCD_PLUSTEK3800 - && dev->model->ccd_type != CCD_KVSS080 - && dev->model->ccd_type != CCD_G4050 - && dev->model->ccd_type != CCD_CS4400F - && dev->model->ccd_type != CCD_CS8400F - && dev->model->ccd_type != CCD_CS8600F - && dev->model->ccd_type != CCD_DSMOBILE600 - && dev->model->ccd_type != CCD_XP300 - && dev->model->ccd_type != CCD_DP665 - && dev->model->ccd_type != CCD_DP685 - && dev->model->ccd_type != CIS_CANONLIDE80 - && dev->model->ccd_type != CCD_ROADWARRIOR - && dev->model->ccd_type != CCD_HP2300 - && dev->model->ccd_type != CCD_HP2400 - && dev->model->ccd_type != CCD_HP3670 - && dev->model->ccd_type != CCD_5345) /* lineart, halftone */ - { - if (dpihw == 0) /* 600 dpi */ - start_address = 0x02a00; - else if (dpihw == 1) /* 1200 dpi */ - start_address = 0x05500; - else if (dpihw == 2) /* 2400 dpi */ - start_address = 0x0a800; - else /* reserved */ - return SANE_STATUS_INVAL; - } - else /* color */ - start_address = 0x00; - - status = sanei_genesys_set_buffer_address (dev, start_address); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send shading table: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/* ? */ -SANE_Status -sanei_genesys_init_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, - int pixels_per_line) -{ - SANE_Status status = SANE_STATUS_GOOD; - int channels; - int i; - - /* these models don't need to init shading data due to the use of specific send shading data - function */ - if (dev->model->ccd_type==CCD_KVSS080 - || dev->model->ccd_type==CCD_G4050 - || dev->model->ccd_type==CCD_CS4400F - || dev->model->ccd_type==CCD_CS8400F - || dev->model->cmd_set->send_shading_data!=NULL) - return SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (pixels_per_line = %d)\n", __func__, pixels_per_line); - - // BUG: GRAY shouldn't probably be in the if condition below. Discovered when refactoring - if (dev->settings.scan_mode == ScanColorMode::GRAY || - dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - channels = 3; - } else { - channels = 1; - } - - // 16 bit black, 16 bit white - std::vector shading_data(pixels_per_line * 4 * channels, 0); - - uint8_t* shading_data_ptr = shading_data.data(); - - for (i = 0; i < pixels_per_line * channels; i++) - { - *shading_data_ptr++ = 0x00; /* dark lo */ - *shading_data_ptr++ = 0x00; /* dark hi */ - *shading_data_ptr++ = 0x00; /* white lo */ - *shading_data_ptr++ = 0x40; /* white hi -> 0x4000 */ - } - - status = genesys_send_offset_and_shading (dev, sensor, - shading_data.data(), - pixels_per_line * 4 * channels); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send shading data: %s\n", __func__, - sane_strstatus (status)); - } - - DBGCOMPLETED; - return status; -} - - -/* Find the position of the reference point: - takes gray level 8 bits data and find - first CCD usable pixel and top of scanning area */ -SANE_Status -sanei_genesys_search_reference_point (Genesys_Device * dev, Genesys_Sensor& sensor, - uint8_t * data, - int start_pixel, int dpi, int width, - int height) -{ - int x, y; - int current, left, top = 0; - int size, count; - int level = 80; /* edge threshold level */ - - /*sanity check */ - if ((width < 3) || (height < 3)) - return SANE_STATUS_INVAL; - - /* transformed image data */ - size = width * height; - std::vector image(size, 0); - - /* laplace filter to denoise picture */ - memcpy(image.data(), data, size); // to initialize unprocessed part of the image buffer - for (y = 1; y < height - 1; y++) - for (x = 1; x < width - 1; x++) - { - image[y * width + x] = - (data[(y - 1) * width + x + 1] + 2 * data[(y - 1) * width + x] + - data[(y - 1) * width + x - 1] + 2 * data[y * width + x + 1] + - 4 * data[y * width + x] + 2 * data[y * width + x - 1] + - data[(y + 1) * width + x + 1] + 2 * data[(y + 1) * width + x] + - data[(y + 1) * width + x - 1]) / 16; - } - - memcpy (data, image.data(), size); - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl_laplace.pnm", image.data(), 8, 1, width, height); - - /* apply X direction sobel filter - -1 0 1 - -2 0 2 - -1 0 1 - and finds threshold level - */ - level = 0; - for (y = 2; y < height - 2; y++) - for (x = 2; x < width - 2; x++) - { - current = - data[(y - 1) * width + x + 1] - data[(y - 1) * width + x - 1] + - 2 * data[y * width + x + 1] - 2 * data[y * width + x - 1] + - data[(y + 1) * width + x + 1] - data[(y + 1) * width + x - 1]; - if (current < 0) - current = -current; - if (current > 255) - current = 255; - image[y * width + x] = current; - if (current > level) - level = current; - } - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl_xsobel.pnm", image.data(), 8, 1, width, height); - - /* set up detection level */ - level = level / 3; - - /* find left black margin first - todo: search top before left - we average the result of N searches */ - left = 0; - count = 0; - for (y = 2; y < 11; y++) - { - x = 8; - while ((x < width / 2) && (image[y * width + x] < level)) - { - image[y * width + x] = 255; - x++; - } - count++; - left += x; - } - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl_detected-xsobel.pnm", image.data(), 8, 1, width, height); - left = left / count; - - /* turn it in CCD pixel at full sensor optical resolution */ - sensor.CCD_start_xoffset = start_pixel + (left * sensor.optical_res) / dpi; - - /* find top edge by detecting black strip */ - /* apply Y direction sobel filter - -1 -2 -1 - 0 0 0 - 1 2 1 - */ - level = 0; - for (y = 2; y < height - 2; y++) - for (x = 2; x < width - 2; x++) - { - current = - -data[(y - 1) * width + x + 1] - 2 * data[(y - 1) * width + x] - - data[(y - 1) * width + x - 1] + data[(y + 1) * width + x + 1] + - 2 * data[(y + 1) * width + x] + data[(y + 1) * width + x - 1]; - if (current < 0) - current = -current; - if (current > 255) - current = 255; - image[y * width + x] = current; - if (current > level) - level = current; - } - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl_ysobel.pnm", image.data(), 8, 1, width, height); - - /* set up detection level */ - level = level / 3; - - /* search top of horizontal black stripe : TODO yet another flag */ - if (dev->model->ccd_type == CCD_5345 - && dev->model->motor_type == MOTOR_5345) - { - top = 0; - count = 0; - for (x = width / 2; x < width - 1; x++) - { - y = 2; - while ((y < height) && (image[x + y * width] < level)) - { - image[y * width + x] = 255; - y++; - } - count++; - top += y; - } - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl_detected-ysobel.pnm", image.data(), 8, 1, width, height); - top = top / count; - - /* bottom of black stripe is of fixed witdh, this hardcoded value - * will be moved into device struct if more such values are needed */ - top += 10; - dev->model->y_offset_calib = SANE_FIX ((top * MM_PER_INCH) / dpi); - DBG(DBG_info, "%s: black stripe y_offset = %f mm \n", __func__, - SANE_UNFIX (dev->model->y_offset_calib)); - } - - /* find white corner in dark area : TODO yet another flag */ - if ((dev->model->ccd_type == CCD_HP2300 - && dev->model->motor_type == MOTOR_HP2300) - || (dev->model->ccd_type == CCD_HP2400 - && dev->model->motor_type == MOTOR_HP2400) - || (dev->model->ccd_type == CCD_HP3670 - && dev->model->motor_type == MOTOR_HP3670)) - { - top = 0; - count = 0; - for (x = 10; x < 60; x++) - { - y = 2; - while ((y < height) && (image[x + y * width] < level)) - y++; - top += y; - count++; - } - top = top / count; - dev->model->y_offset_calib = SANE_FIX ((top * MM_PER_INCH) / dpi); - DBG(DBG_info, "%s: white corner y_offset = %f mm\n", __func__, - SANE_UNFIX (dev->model->y_offset_calib)); - } - - DBG(DBG_proc, "%s: CCD_start_xoffset = %d, left = %d, top = %d\n", __func__, - sensor.CCD_start_xoffset, left, top); - - return SANE_STATUS_GOOD; -} - - -void -sanei_genesys_calculate_zmode2 (SANE_Bool two_table, - uint32_t exposure_time, - uint16_t * slope_table, - int reg21, - int move, int reg22, uint32_t * z1, - uint32_t * z2) -{ - int i; - int sum; - DBG(DBG_info, "%s: two_table=%d\n", __func__, two_table); - - /* acceleration total time */ - sum = 0; - for (i = 0; i < reg21; i++) - sum += slope_table[i]; - - /* compute Z1MOD */ - /* c=sum(slope_table;reg21) - d=reg22*cruising speed - Z1MOD=(c+d) % exposure_time */ - *z1 = (sum + reg22 * slope_table[reg21 - 1]) % exposure_time; - - /* compute Z2MOD */ - /* a=sum(slope_table;reg21), b=move or 1 if 2 tables */ - /* Z2MOD=(a+b) % exposure_time */ - if (!two_table) - sum = sum + (move * slope_table[reg21 - 1]); - else - sum = sum + slope_table[reg21 - 1]; - *z2 = sum % exposure_time; -} - - -/* huh? */ -/* todo: double check */ -/* Z1 and Z2 seem to be a time to synchronize with clock or a phase correction */ -/* steps_sum is the result of create_slope_table */ -/* last_speed is the last entry of the slope_table */ -/* feedl is registers 3d,3e,3f */ -/* fastfed is register 02 bit 3 */ -/* scanfed is register 1f */ -/* fwdstep is register 22 */ -/* tgtime is register 6c bit 6+7 >> 6 */ - -void -sanei_genesys_calculate_zmode (uint32_t exposure_time, - uint32_t steps_sum, uint16_t last_speed, - uint32_t feedl, uint8_t fastfed, - uint8_t scanfed, uint8_t fwdstep, - uint8_t tgtime, uint32_t * z1, uint32_t * z2) -{ - uint8_t exposure_factor; - - exposure_factor = pow (2, tgtime); /* todo: originally, this is always 2^0 ! */ - - /* Z1 is for buffer-full backward forward moving */ - *z1 = - exposure_factor * ((steps_sum + fwdstep * last_speed) % exposure_time); - - /* Z2 is for acceleration before scan */ - if (fastfed) /* two curve mode */ - { - *z2 = - exposure_factor * ((steps_sum + scanfed * last_speed) % - exposure_time); - } - else /* one curve mode */ - { - *z2 = - exposure_factor * ((steps_sum + feedl * last_speed) % exposure_time); - } -} - - -static uint8_t genesys_adjust_gain(double* applied_multi, double multi, uint8_t gain) -{ - double voltage, original_voltage; - uint8_t new_gain = 0; - - DBG(DBG_proc, "%s: multi=%f, gain=%d\n", __func__, multi, gain); - - voltage = 0.5 + gain * 0.25; - original_voltage = voltage; - - voltage *= multi; - - new_gain = (uint8_t) ((voltage - 0.5) * 4); - if (new_gain > 0x0e) - new_gain = 0x0e; - - voltage = 0.5 + (new_gain) * 0.25; - - *applied_multi = voltage / original_voltage; - - DBG(DBG_proc, "%s: orig voltage=%.2f, new voltage=%.2f, *applied_multi=%f, new_gain=%d\n", - __func__, original_voltage, voltage, *applied_multi, new_gain); - - return new_gain; -} - - -/* todo: is return status necessary (unchecked?) */ -static SANE_Status -genesys_average_white (Genesys_Device * dev, Genesys_Sensor& sensor, int channels, int channel, - uint8_t * data, int size, int *max_average) -{ - int gain_white_ref, sum, range; - int average; - int i; - - DBG(DBG_proc, "%s: channels=%d, channel=%d, size=%d\n", __func__, channels, channel, size); - - range = size / 50; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) /* transparency mode */ - gain_white_ref = sensor.fau_gain_white_ref * 256; - else - gain_white_ref = sensor.gain_white_ref * 256; - - if (range < 1) - range = 1; - - size = size / (2 * range * channels); - - data += (channel * 2); - - *max_average = 0; - - while (size--) - { - sum = 0; - for (i = 0; i < range; i++) - { - sum += (*data); - sum += *(data + 1) * 256; - data += (2 * channels); /* byte based */ - } - - average = (sum / range); - if (average > *max_average) - *max_average = average; - } - - DBG(DBG_proc, "%s: max_average=%d, gain_white_ref = %d, finished\n", __func__, *max_average, - gain_white_ref); - - if (*max_average >= gain_white_ref) - return SANE_STATUS_INVAL; - - return SANE_STATUS_GOOD; -} - -/* todo: understand, values are too high */ -static int -genesys_average_black (Genesys_Device * dev, int channel, - uint8_t * data, int pixels) -{ - int i; - int sum; - int pixel_step; - - DBG(DBG_proc, "%s: channel=%d, pixels=%d\n", __func__, channel, pixels); - - sum = 0; - - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - data += (channel * 2); - pixel_step = 3 * 2; - } - else - { - pixel_step = 2; - } - - for (i = 0; i < pixels; i++) - { - sum += *data; - sum += *(data + 1) * 256; - - data += pixel_step; - } - - DBG(DBG_proc, "%s = %d\n", __func__, sum / pixels); - - return (int) (sum / pixels); -} - - -/* todo: check; it works but the lines 1, 2, and 3 are too dark even with the - same offset and gain settings? */ -static SANE_Status genesys_coarse_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) -{ - int size; - int black_pixels; - int white_average; - int channels; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t offset[4] = { 0xa0, 0x00, 0xa0, 0x40 }; /* first value isn't used */ - uint16_t white[12], dark[12]; - int i, j; - - DBG(DBG_info, "%s (scan_mode = %d)\n", __func__, static_cast(dev->settings.scan_mode)); - - black_pixels = sensor.black_pixels - * dev->settings.xres / sensor.optical_res; - - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - DBG(DBG_info, "channels %d y_size %d xres %d\n", channels, dev->model->y_size, - dev->settings.xres); - size = - channels * 2 * SANE_UNFIX (dev->model->y_size) * dev->settings.xres / - 25.4; - /* 1 1 mm 1/inch inch/mm */ - - std::vector calibration_data(size); - std::vector all_data(size * 4, 1); - - status = dev->model->cmd_set->set_fe(dev, sensor, AFE_INIT); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); - return status; - } - - dev->frontend.set_gain(0, 2); - dev->frontend.set_gain(1, 2); - dev->frontend.set_gain(2, 2); // TODO: ? was 2 - dev->frontend.set_offset(0, offset[0]); - dev->frontend.set_offset(1, offset[0]); - dev->frontend.set_offset(2, offset[0]); - - for (i = 0; i < 4; i++) /* read 4 lines */ - { - if (i < 3) /* first 3 lines */ - { - dev->frontend.set_offset(0, offset[i]); - dev->frontend.set_offset(1, offset[i]); - dev->frontend.set_offset(2, offset[i]); - } - - if (i == 1) /* second line */ - { - double applied_multi; - double gain_white_ref; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) /* Transparency */ - gain_white_ref = sensor.fau_gain_white_ref * 256; - else - gain_white_ref = sensor.gain_white_ref * 256; - /* white and black are defined downwards */ - - uint8_t gain0 = genesys_adjust_gain(&applied_multi, - gain_white_ref / (white[0] - dark[0]), - dev->frontend.get_gain(0)); - uint8_t gain1 = genesys_adjust_gain(&applied_multi, - gain_white_ref / (white[1] - dark[1]), - dev->frontend.get_gain(1)); - uint8_t gain2 = genesys_adjust_gain(&applied_multi, - gain_white_ref / (white[2] - dark[2]), - dev->frontend.get_gain(2)); - // FIXME: looks like overwritten data. Are the above calculations doing - // anything at all? - dev->frontend.set_gain(0, gain0); - dev->frontend.set_gain(1, gain1); - dev->frontend.set_gain(2, gain2); - dev->frontend.set_gain(0, 2); - dev->frontend.set_gain(1, 2); - dev->frontend.set_gain(2, 2); - - status = - sanei_genesys_fe_write_data(dev, 0x28, dev->frontend.get_gain(0)); - if (status != SANE_STATUS_GOOD) /* todo: this was 0x28 + 3 ? */ - { - DBG(DBG_error, "%s: Failed to write gain[0]: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_fe_write_data(dev, 0x29, dev->frontend.get_gain(1)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to write gain[1]: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_fe_write_data(dev, 0x2a, dev->frontend.get_gain(2)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to write gain[2]: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - if (i == 3) /* last line */ - { - double x, y, rate; - - for (j = 0; j < 3; j++) - { - - x = - (double) (dark[(i - 2) * 3 + j] - - dark[(i - 1) * 3 + j]) * 254 / (offset[i - 1] / 2 - - offset[i - 2] / 2); - y = x - x * (offset[i - 1] / 2) / 254 - dark[(i - 1) * 3 + j]; - rate = (x - DARK_VALUE - y) * 254 / x + 0.5; - - uint8_t curr_offset = static_cast(rate); - - if (curr_offset > 0x7f) { - curr_offset = 0x7f; - } - curr_offset <<= 1; - dev->frontend.set_offset(j, curr_offset); - } - } - status = - sanei_genesys_fe_write_data(dev, 0x20, dev->frontend.get_offset(0)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to write offset[0]: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_fe_write_data(dev, 0x21, dev->frontend.get_offset(1)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to write offset[1]: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_fe_write_data(dev, 0x22, dev->frontend.get_offset(2)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to write offset[2]: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_info, - "%s: doing scan: gain: %d/%d/%d, offset: %d/%d/%d\n", __func__, - dev->frontend.get_gain(0), - dev->frontend.get_gain(1), - dev->frontend.get_gain(2), - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - - status = - dev->model->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_read_data_from_scanner (dev, calibration_data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - std::memcpy(all_data.data() + i * size, calibration_data.data(), size); - if (i == 3) /* last line */ - { - std::vector all_data_8(size * 4 / 2); - unsigned int count; - - for (count = 0; count < (unsigned int) (size * 4 / 2); count++) - all_data_8[count] = all_data[count * 2 + 1]; - status = - sanei_genesys_write_pnm_file("gl_coarse.pnm", all_data_8.data(), 8, channels, size / 6, 4); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - status = dev->model->cmd_set->end_scan(dev, &dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - for (j = 0; j < 3; j++) - { - genesys_average_white (dev, sensor, 3, j, calibration_data.data(), size, - &white_average); - white[i * 3 + j] = white_average; - dark[i * 3 + j] = - genesys_average_black (dev, j, calibration_data.data(), - black_pixels); - DBG(DBG_info, "%s: white[%d]=%d, black[%d]=%d\n", __func__, - i * 3 + j, white[i * 3 + j], i * 3 + j, dark[i * 3 + j]); - } - } - else /* one color-component modes */ - { - genesys_average_white (dev, sensor, 1, 0, calibration_data.data(), size, - &white_average); - white[i * 3 + 0] = white[i * 3 + 1] = white[i * 3 + 2] = - white_average; - dark[i * 3 + 0] = dark[i * 3 + 1] = dark[i * 3 + 2] = - genesys_average_black (dev, 0, calibration_data.data(), black_pixels); - } - - if (i == 3) - { - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - /* todo: huh? */ - dev->dark[0] = - (uint16_t) (1.6925 * dark[i * 3 + 0] + 0.1895 * 256); - dev->dark[1] = - (uint16_t) (1.4013 * dark[i * 3 + 1] + 0.3147 * 256); - dev->dark[2] = - (uint16_t) (1.2931 * dark[i * 3 + 2] + 0.1558 * 256); - } - else /* one color-component modes */ - { - switch (dev->settings.color_filter) - { - case ColorFilter::RED: - default: - dev->dark[0] = - (uint16_t) (1.6925 * dark[i * 3 + 0] + - (1.1895 - 1.0) * 256); - dev->dark[1] = dev->dark[2] = dev->dark[0]; - break; - - case ColorFilter::GREEN: - dev->dark[1] = - (uint16_t) (1.4013 * dark[i * 3 + 1] + - (1.3147 - 1.0) * 256); - dev->dark[0] = dev->dark[2] = dev->dark[1]; - break; - - case ColorFilter::BLUE: - dev->dark[2] = - (uint16_t) (1.2931 * dark[i * 3 + 2] + - (1.1558 - 1.0) * 256); - dev->dark[0] = dev->dark[1] = dev->dark[2]; - break; - } - } - } - } /* for (i = 0; i < 4; i++) */ - - DBG(DBG_info, "%s: final: gain: %d/%d/%d, offset: %d/%d/%d\n", __func__, - dev->frontend.get_gain(0), - dev->frontend.get_gain(1), - dev->frontend.get_gain(2), - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - DBGCOMPLETED; - - return status; -} - -/* Averages image data. - average_data and calibration_data are little endian 16 bit words. - */ -static void -genesys_average_data (uint8_t * average_data, - uint8_t * calibration_data, - uint32_t lines, - uint32_t pixel_components_per_line) -{ - uint32_t x, y; - uint32_t sum; - - for (x = 0; x < pixel_components_per_line; x++) - { - sum = 0; - for (y = 0; y < lines; y++) - { - sum += calibration_data[(x + y * pixel_components_per_line) * 2]; - sum += - calibration_data[(x + y * pixel_components_per_line) * 2 + - 1] * 256; - } - sum /= lines; - *average_data++ = sum & 255; - *average_data++ = sum / 256; - } -} - -/** - * scans a white area with motor and lamp off to get the per CCD pixel offset - * that will be used to compute shading coefficient - * @param dev scanner's device - * @return SANE_STATUS_GOOD if OK, else an error - */ -static SANE_Status -genesys_dark_shading_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - size_t size; - uint32_t pixels_per_line; - uint8_t channels; - SANE_Bool motor; - - DBGSTART; - - /* end pixel - start pixel */ - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; - dev->average_size = channels * 2 * out_pixels_per_line; - - dev->dark_average_data.clear(); - dev->dark_average_data.resize(dev->average_size); - - // FIXME: the current calculation is likely incorrect on non-GENESYS_GL843 implementations, - // but this needs checking - if (dev->calib_total_bytes_to_read > 0) { - size = dev->calib_total_bytes_to_read; - } else if (dev->model->asic_type == GENESYS_GL843) { - size = channels * 2 * pixels_per_line * dev->calib_lines; - } else { - size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); - } - - std::vector calibration_data(size); - - motor=SANE_TRUE; - if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) - { - motor=SANE_FALSE; - } - - /* turn off motor and lamp power for flatbed scanners, but not for sheetfed scanners - * because they have a calibration sheet with a sufficient black strip */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, false); - sanei_genesys_set_motor_power(dev->calib_reg, motor); - } - else - { - sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true); - sanei_genesys_set_motor_power(dev->calib_reg, motor); - } - - status = - dev->model->cmd_set->bulk_write_register(dev, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - // wait some time to let lamp to get dark - sanei_genesys_sleep_ms(200); - - status = dev->model->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_read_data_from_scanner (dev, calibration_data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = dev->model->cmd_set->end_scan(dev, &dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - std::fill(dev->dark_average_data.begin(), - dev->dark_average_data.begin() + dev->calib_pixels_offset * channels, - 0x00); - - genesys_average_data(dev->dark_average_data.data() + dev->calib_pixels_offset * channels, - calibration_data.data(), - dev->calib_lines, pixels_per_line * channels); - - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file("gl_black_shading.pnm", calibration_data.data(), 16, - channels, pixels_per_line, dev->calib_lines); - sanei_genesys_write_pnm_file("gl_black_average.pnm", dev->dark_average_data.data(), 16, - channels, out_pixels_per_line, 1); - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/* - * this function builds dummy dark calibration data so that we can - * compute shading coefficient in a clean way - * todo: current values are hardcoded, we have to find if they - * can be computed from previous calibration data (when doing offset - * calibration ?) - */ -static SANE_Status -genesys_dummy_dark_shading (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - uint32_t pixels_per_line; - uint8_t channels; - uint32_t x, skip, xend; - int dummy1, dummy2, dummy3; /* dummy black average per channel */ - - DBGSTART; - - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; - - dev->average_size = channels * 2 * out_pixels_per_line; - dev->dark_average_data.clear(); - dev->dark_average_data.resize(dev->average_size, 0); - - /* we average values on 'the left' where CCD pixels are under casing and - give darkest values. We then use these as dummy dark calibration */ - if (dev->settings.xres <= sensor.optical_res / 2) - { - skip = 4; - xend = 36; - } - else - { - skip = 4; - xend = 68; - } - if (dev->model->ccd_type==CCD_G4050 - || dev->model->ccd_type==CCD_CS4400F - || dev->model->ccd_type==CCD_CS8400F - || dev->model->ccd_type==CCD_KVSS080) - { - skip = 2; - xend = sensor.black_pixels; - } - - /* average each channels on half left margin */ - dummy1 = 0; - dummy2 = 0; - dummy3 = 0; - - for (x = skip + 1; x <= xend; x++) - { - dummy1 += - dev->white_average_data[channels * 2 * x] + - 256 * dev->white_average_data[channels * 2 * x + 1]; - if (channels > 1) - { - dummy2 += - (dev->white_average_data[channels * 2 * x + 2] + - 256 * dev->white_average_data[channels * 2 * x + 3]); - dummy3 += - (dev->white_average_data[channels * 2 * x + 4] + - 256 * dev->white_average_data[channels * 2 * x + 5]); - } - } - - dummy1 /= (xend - skip); - if (channels > 1) - { - dummy2 /= (xend - skip); - dummy3 /= (xend - skip); - } - DBG(DBG_proc, "%s: dummy1=%d, dummy2=%d, dummy3=%d \n", __func__, dummy1, dummy2, dummy3); - - /* fill dark_average */ - for (x = 0; x < out_pixels_per_line; x++) - { - dev->dark_average_data[channels * 2 * x] = dummy1 & 0xff; - dev->dark_average_data[channels * 2 * x + 1] = dummy1 >> 8; - if (channels > 1) - { - dev->dark_average_data[channels * 2 * x + 2] = dummy2 & 0xff; - dev->dark_average_data[channels * 2 * x + 3] = dummy2 >> 8; - dev->dark_average_data[channels * 2 * x + 4] = dummy3 & 0xff; - dev->dark_average_data[channels * 2 * x + 5] = dummy3 >> 8; - } - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -genesys_white_shading_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - size_t size; - uint32_t pixels_per_line; - uint8_t channels; - SANE_Bool motor; - - DBG(DBG_proc, "%s (lines = %d)\n", __func__, (unsigned int)dev->calib_lines); - - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; - - dev->white_average_data.clear(); - dev->white_average_data.resize(channels * 2 * out_pixels_per_line); - - // FIXME: the current calculation is likely incorrect on non-GENESYS_GL843 implementations, - // but this needs checking - if (dev->calib_total_bytes_to_read > 0) { - size = dev->calib_total_bytes_to_read; - } else if (dev->model->asic_type == GENESYS_GL843) { - size = channels * 2 * pixels_per_line * dev->calib_lines; - } else { - size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); - } - - std::vector calibration_data(size); - - motor=SANE_TRUE; - if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) - { - motor=SANE_FALSE; - } - - // turn on motor and lamp power - sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true); - sanei_genesys_set_motor_power(dev->calib_reg, motor); - - /* if needed, go back before doing next scan */ - if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) - { - /* rewind keeps registers and slopes table intact from previous - scan but is not available on all supported chipsets (or may - cause scan artifacts, see #7) */ - status = (dev->model->cmd_set->rewind - ? dev->model->cmd_set->rewind (dev) - : dev->model->cmd_set->slow_back_home (dev, SANE_TRUE)); - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) - { - dev->model->cmd_set->move_to_ta(dev); - } - } - - status = - dev->model->cmd_set->bulk_write_register(dev, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) - sanei_genesys_sleep_ms(500); // make sure lamp is bright again - - status = dev->model->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_read_data_from_scanner (dev, calibration_data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = dev->model->cmd_set->end_scan(dev, &dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl_white_shading.pnm", calibration_data.data(), 16, - channels, pixels_per_line, dev->calib_lines); - - std::fill(dev->dark_average_data.begin(), - dev->dark_average_data.begin() + dev->calib_pixels_offset * channels, - 0x00); - - genesys_average_data (dev->white_average_data.data() + dev->calib_pixels_offset * channels, - calibration_data.data(), dev->calib_lines, - pixels_per_line * channels); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl_white_average.pnm", dev->white_average_data.data(), 16, - channels, out_pixels_per_line, 1); - - /* in case we haven't done dark calibration, build dummy data from white_average */ - if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) - { - status = genesys_dummy_dark_shading(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do dummy dark shading calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) - { - status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); - } - - DBGCOMPLETED; - - return status; -} - -/* This calibration uses a scan over the calibration target, comprising a - * black and a white strip. (So the motor must be on.) - */ -static SANE_Status -genesys_dark_white_shading_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - size_t size; - uint32_t pixels_per_line; - uint8_t *average_white, *average_dark; - uint8_t channels; - unsigned int x; - int y; - uint32_t dark, white, dark_sum, white_sum, dark_count, white_count, col, - dif; - SANE_Bool motor; - - - DBG(DBG_proc, "%s: (lines = %d)\n", __func__, (unsigned int)dev->calib_lines); - - pixels_per_line = dev->calib_pixels; - channels = dev->calib_channels; - - uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; - - dev->average_size = channels * 2 * out_pixels_per_line; - - dev->white_average_data.clear(); - dev->white_average_data.resize(dev->average_size); - - dev->dark_average_data.clear(); - dev->dark_average_data.resize(dev->average_size); - - if (dev->calib_total_bytes_to_read > 0) - size = dev->calib_total_bytes_to_read; - else - size = channels * 2 * pixels_per_line * dev->calib_lines; - - std::vector calibration_data(size); - - motor=SANE_TRUE; - if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) - { - motor=SANE_FALSE; - } - - // turn on motor and lamp power - sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true); - sanei_genesys_set_motor_power(dev->calib_reg, motor); - - status = - dev->model->cmd_set->bulk_write_register(dev, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = dev->model->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, SANE_FALSE); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_read_data_from_scanner (dev, calibration_data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = dev->model->cmd_set->end_scan(dev, &dev->calib_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - if (dev->model->is_cis) - { - sanei_genesys_write_pnm_file("gl_black_white_shading.pnm", calibration_data.data(), - 16, 1, pixels_per_line*channels, - dev->calib_lines); - } - else - { - sanei_genesys_write_pnm_file("gl_black_white_shading.pnm", calibration_data.data(), - 16, channels, pixels_per_line, - dev->calib_lines); - } - } - - - std::fill(dev->dark_average_data.begin(), - dev->dark_average_data.begin() + dev->calib_pixels_offset * channels, - 0x00); - std::fill(dev->white_average_data.begin(), - dev->white_average_data.begin() + dev->calib_pixels_offset * channels, - 0x00); - - average_white = dev->white_average_data.data() + dev->calib_pixels_offset * channels; - average_dark = dev->dark_average_data.data() + dev->calib_pixels_offset * channels; - - for (x = 0; x < pixels_per_line * channels; x++) - { - dark = 0xffff; - white = 0; - - for (y = 0; y < (int)dev->calib_lines; y++) - { - col = calibration_data[(x + y * pixels_per_line * channels) * 2]; - col |= - calibration_data[(x + y * pixels_per_line * channels) * 2 + - 1] << 8; - - if (col > white) - white = col; - if (col < dark) - dark = col; - } - - dif = white - dark; - - dark = dark + dif / 8; - white = white - dif / 8; - - dark_count = 0; - dark_sum = 0; - - white_count = 0; - white_sum = 0; - - for (y = 0; y < (int)dev->calib_lines; y++) - { - col = calibration_data[(x + y * pixels_per_line * channels) * 2]; - col |= - calibration_data[(x + y * pixels_per_line * channels) * 2 + - 1] << 8; - - if (col >= white) - { - white_sum += col; - white_count++; - } - if (col <= dark) - { - dark_sum += col; - dark_count++; - } - - } - - dark_sum /= dark_count; - white_sum /= white_count; - - *average_dark++ = dark_sum & 255; - *average_dark++ = dark_sum >> 8; - - *average_white++ = white_sum & 255; - *average_white++ = white_sum >> 8; - } - - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file("gl_white_average.pnm", - dev->white_average_data.data(), 16, channels, - out_pixels_per_line, 1); - sanei_genesys_write_pnm_file("gl_dark_average.pnm", - dev->dark_average_data.data(), 16, channels, - out_pixels_per_line, 1); - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/* computes one coefficient given bright-dark value - * @param coeff factor giving 1.00 gain - * @param target desired target code - * @param value brght-dark value - * */ -static unsigned int -compute_coefficient (unsigned int coeff, unsigned int target, unsigned int value) -{ - int result; - - if (value > 0) - { - result = (coeff * target) / value; - if (result >= 65535) - { - result = 65535; - } - } - else - { - result = coeff; - } - return result; -} - -/** @brief compute shading coefficients for LiDE scanners - * The dark/white shading is actually performed _after_ reducing - * resolution via averaging. only dark/white shading data for what would be - * first pixel at full resolution is used. - * - * scanner raw input to output value calculation: - * o=(i-off)*(gain/coeff) - * - * from datasheet: - * off=dark_average - * gain=coeff*bright_target/(bright_average-dark_average) - * works for dark_target==0 - * - * what we want is these: - * bright_target=(bright_average-off)*(gain/coeff) - * dark_target=(dark_average-off)*(gain/coeff) - * leading to - * off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) - * gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff - * - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param pixels_per_line number of pixels per line - * @param words_per_color memory words per color channel - * @param channels number of color channels (actually 1 or 3) - * @param o shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not (GAIN4 bit) - * @param target_bright value of the white target code - * @param target_dark value of the black target code -*/ -static void -compute_averaged_planar (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int words_per_color, - unsigned int channels, - unsigned int o, - unsigned int coeff, - unsigned int target_bright, - unsigned int target_dark) -{ - unsigned int x, i, j, br, dk, res, avgpixels, basepixels, val; - unsigned int fill,factor; - - DBG(DBG_info, "%s: pixels=%d, offset=%d\n", __func__, pixels_per_line, o); - - /* initialize result */ - memset (shading_data, 0xff, words_per_color * 3 * 2); - - /* - strangely i can write 0x20000 bytes beginning at 0x00000 without overwriting - slope tables - which begin at address 0x10000(for 1200dpi hw mode): - memory is organized in words(2 bytes) instead of single bytes. explains - quite some things - */ -/* - another one: the dark/white shading is actually performed _after_ reducing - resolution via averaging. only dark/white shading data for what would be - first pixel at full resolution is used. - */ -/* - scanner raw input to output value calculation: - o=(i-off)*(gain/coeff) - - from datasheet: - off=dark_average - gain=coeff*bright_target/(bright_average-dark_average) - works for dark_target==0 - - what we want is these: - bright_target=(bright_average-off)*(gain/coeff) - dark_target=(dark_average-off)*(gain/coeff) - leading to - off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) - gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff - */ - res = dev->settings.xres; - - if (sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres) > 1) - { - res *= 2; - } - - /* this should be evenly dividable */ - basepixels = sensor.optical_res / res; - - /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ - if (basepixels < 1) - avgpixels = 1; - else if (basepixels < 6) - avgpixels = basepixels; - else if (basepixels < 8) - avgpixels = 6; - else if (basepixels < 10) - avgpixels = 8; - else if (basepixels < 12) - avgpixels = 10; - else if (basepixels < 15) - avgpixels = 12; - else - avgpixels = 15; - - /* LiDE80 packs shading data */ - if(dev->model->ccd_type != CIS_CANONLIDE80) - { - factor=1; - fill=avgpixels; - } - else - { - factor=avgpixels; - fill=1; - } - - DBG(DBG_info, "%s: averaging over %d pixels\n", __func__, avgpixels); - DBG(DBG_info, "%s: packing factor is %d\n", __func__, factor); - DBG(DBG_info, "%s: fill length is %d\n", __func__, fill); - - for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) - { - if ((x + o) * 2 * 2 + 3 > words_per_color * 2) - break; - - for (j = 0; j < channels; j++) - { - - dk = 0; - br = 0; - for (i = 0; i < avgpixels; i++) - { - /* dark data */ - dk += - (dev->dark_average_data[(x + i + - pixels_per_line * j) * - 2] | - (dev->dark_average_data - [(x + i + pixels_per_line * j) * 2 + 1] << 8)); - - /* white data */ - br += - (dev->white_average_data[(x + i + - pixels_per_line * j) * - 2] | - (dev->white_average_data - [(x + i + pixels_per_line * j) * 2 + 1] << 8)); - } - - br /= avgpixels; - dk /= avgpixels; - - if (br * target_dark > dk * target_bright) - val = 0; - else if (dk * target_bright - br * target_dark > - 65535 * (target_bright - target_dark)) - val = 65535; - else - { - val = (dk * target_bright - br * target_dark) / (target_bright - target_dark); - } - - /*fill all pixels, even if only the last one is relevant*/ - for (i = 0; i < fill; i++) - { - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j] = val & 0xff; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = val >> 8; - } - - val = br - dk; - - if (65535 * val > (target_bright - target_dark) * coeff) - { - val = (coeff * (target_bright - target_dark)) / val; - } - else - { - val = 65535; - } - - /*fill all pixels, even if only the last one is relevant*/ - for (i = 0; i < fill; i++) - { - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = val & 0xff; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = val >> 8; - } - } - - /* fill remaining channels */ - for (j = channels; j < 3; j++) - { - for (i = 0; i < fill; i++) - { - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j ] = shading_data[(x/factor + o + i) * 2 * 2 ]; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = shading_data[(x/factor + o + i) * 2 * 2 + 1]; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = shading_data[(x/factor + o + i) * 2 * 2 + 2]; - shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = shading_data[(x/factor + o + i) * 2 * 2 + 3]; - } - } - } -} - -/** - * Computes shading coefficient using formula in data sheet. 16bit data values - * manipulated here are little endian. For now we assume deletion scanning type - * and that there is always 3 channels. - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param pixels_per_line number of pixels per line - * @param channels number of color channels (actually 1 or 3) - * @param cmat color transposition matrix - * @param offset shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not - * @param target value of the target code - */ -static void -compute_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int channels, - unsigned int cmat[3], - int offset, - unsigned int coeff, - unsigned int target) -{ - uint8_t *ptr; /* contain 16bit words in little endian */ - unsigned int x, c; - unsigned int val, br, dk; - unsigned int start, end; - - DBG(DBG_io, "%s: pixels_per_line=%d, coeff=0x%04x\n", __func__, pixels_per_line, coeff); - - /* compute start & end values depending of the offset */ - if (offset < 0) - { - start = -1 * offset; - end = pixels_per_line; - } - else - { - start = 0; - end = pixels_per_line - offset; - } - - for (c = 0; c < channels; c++) - { - for (x = start; x < end; x++) - { - /* TODO if channels=1 , use filter to know the base addr */ - ptr = shading_data + 4 * ((x + offset) * channels + cmat[c]); - - /* dark data */ - dk = dev->dark_average_data[x * 2 * channels + c * 2]; - dk += 256 * dev->dark_average_data[x * 2 * channels + c * 2 + 1]; - - /* white data */ - br = dev->white_average_data[x * 2 * channels + c * 2]; - br += 256 * dev->white_average_data[x * 2 * channels + c * 2 + 1]; - - /* compute coeff */ - val=compute_coefficient(coeff,target,br-dk); - - /* assign it */ - ptr[0] = dk & 255; - ptr[1] = dk / 256; - ptr[2] = val & 0xff; - ptr[3] = val / 256; - - } - } -} - -/** - * Computes shading coefficient using formula in data sheet. 16bit data values - * manipulated here are little endian. Data is in planar form, ie grouped by - * lines of the same color component. - * @param dev scanner's device - * @param shading_data memory area where to store the computed shading coefficients - * @param factor averaging factor when the calibration scan is done at a higher resolution - * than the final scan - * @param pixels_per_line number of pixels per line - * @param words_per_color total number of shading data words for one color element - * @param channels number of color channels (actually 1 or 3) - * @param cmat transcoding matrix for color channel order - * @param offset shading coefficients left offset - * @param coeff 4000h or 2000h depending on fast scan mode or not - * @param target white target value - */ -static void -compute_planar_coefficients (Genesys_Device * dev, - uint8_t * shading_data, - unsigned int factor, - unsigned int pixels_per_line, - unsigned int words_per_color, - unsigned int channels, - unsigned int cmat[3], - unsigned int offset, - unsigned int coeff, - unsigned int target) -{ - uint8_t *ptr; /* contains 16bit words in little endian */ - uint32_t x, c, i; - uint32_t val, dk, br; - - DBG(DBG_io, "%s: factor=%d, pixels_per_line=%d, words=0x%X, coeff=0x%04x\n", __func__, factor, - pixels_per_line, words_per_color, coeff); - for (c = 0; c < channels; c++) - { - /* shading data is larger than pixels_per_line so offset can be neglected */ - for (x = 0; x < pixels_per_line; x+=factor) - { - /* x2 because of 16 bit values, and x2 since one coeff for dark - * and another for white */ - ptr = shading_data + words_per_color * cmat[c] * 2 + (x + offset) * 4; - - dk = 0; - br = 0; - - /* average case */ - for(i=0;idark_average_data[((x+i) + pixels_per_line * c) * 2 + 1]; - dk += dev->dark_average_data[((x+i) + pixels_per_line * c) * 2]; - br += - 256 * dev->white_average_data[((x+i) + pixels_per_line * c) * 2 + 1]; - br += dev->white_average_data[((x+i) + pixels_per_line * c) * 2]; - } - dk /= factor; - br /= factor; - - val = compute_coefficient (coeff, target, br - dk); - - /* we duplicate the information to have calibration data at optical resolution */ - for (i = 0; i < factor; i++) - { - ptr[0 + 4 * i] = dk & 255; - ptr[1 + 4 * i] = dk / 256; - ptr[2 + 4 * i] = val & 0xff; - ptr[3 + 4 * i] = val / 256; - } - } - } - /* in case of gray level scan, we duplicate shading information on all - * three color channels */ - if(channels==1) - { - memcpy(shading_data+cmat[1]*2*words_per_color, - shading_data+cmat[0]*2*words_per_color, - words_per_color*2); - memcpy(shading_data+cmat[2]*2*words_per_color, - shading_data+cmat[0]*2*words_per_color, - words_per_color*2); - } -} - -static void -compute_shifted_coefficients (Genesys_Device * dev, - const Genesys_Sensor& sensor, - uint8_t * shading_data, - unsigned int pixels_per_line, - unsigned int channels, - unsigned int cmat[3], - int offset, - unsigned int coeff, - unsigned int target_dark, - unsigned int target_bright, - unsigned int patch_size) /* contigous extent */ -{ - unsigned int x, avgpixels, basepixels, i, j, val1, val2; - unsigned int br_tmp [3], dk_tmp [3]; - uint8_t *ptr = shading_data + offset * 3 * 4; /* contain 16bit words in little endian */ - unsigned int patch_cnt = offset * 3; /* at start, offset of first patch */ - - x = dev->settings.xres; - if (sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres) > 1) - x *= 2; /* scanner is using half-ccd mode */ - basepixels = sensor.optical_res / x; /*this should be evenly dividable */ - - /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ - if (basepixels < 1) - avgpixels = 1; - else if (basepixels < 6) - avgpixels = basepixels; - else if (basepixels < 8) - avgpixels = 6; - else if (basepixels < 10) - avgpixels = 8; - else if (basepixels < 12) - avgpixels = 10; - else if (basepixels < 15) - avgpixels = 12; - else - avgpixels = 15; - DBG(DBG_info, "%s: pixels_per_line=%d, coeff=0x%04x, averaging over %d pixels\n", __func__, - pixels_per_line, coeff, avgpixels); - - for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) { - memset (&br_tmp, 0, sizeof(br_tmp)); - memset (&dk_tmp, 0, sizeof(dk_tmp)); - - for (i = 0; i < avgpixels; i++) { - for (j = 0; j < channels; j++) { - br_tmp[j] += (dev->white_average_data[((x + i) * channels + j) * 2] | - (dev->white_average_data[((x + i) * channels + j) * 2 + 1] << 8)); - dk_tmp[i] += (dev->dark_average_data[((x + i) * channels + j) * 2] | - (dev->dark_average_data[((x + i) * channels + j) * 2 + 1] << 8)); - } - } - for (j = 0; j < channels; j++) { - br_tmp[j] /= avgpixels; - dk_tmp[j] /= avgpixels; - - if (br_tmp[j] * target_dark > dk_tmp[j] * target_bright) - val1 = 0; - else if (dk_tmp[j] * target_bright - br_tmp[j] * target_dark > 65535 * (target_bright - target_dark)) - val1 = 65535; - else - val1 = (dk_tmp[j] * target_bright - br_tmp[j] * target_dark) / (target_bright - target_dark); - - val2 = br_tmp[j] - dk_tmp[j]; - if (65535 * val2 > (target_bright - target_dark) * coeff) - val2 = (coeff * (target_bright - target_dark)) / val2; - else - val2 = 65535; - - br_tmp[j] = val1; - dk_tmp[j] = val2; - } - for (i = 0; i < avgpixels; i++) { - for (j = 0; j < channels; j++) { - * ptr++ = br_tmp[ cmat[j] ] & 0xff; - * ptr++ = br_tmp[ cmat[j] ] >> 8; - * ptr++ = dk_tmp[ cmat[j] ] & 0xff; - * ptr++ = dk_tmp[ cmat[j] ] >> 8; - patch_cnt++; - if (patch_cnt == patch_size) { - patch_cnt = 0; - val1 = cmat[2]; - cmat[2] = cmat[1]; - cmat[1] = cmat[0]; - cmat[0] = val1; - } - } - } - } -} - -static SANE_Status -genesys_send_shading_coefficient(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t pixels_per_line; - uint8_t channels; - int o; - unsigned int length; /**> number of shading calibration data words */ - unsigned int factor; - unsigned int cmat[3]; /**> matrix of color channels */ - unsigned int coeff, target_code, words_per_color = 0; - - DBGSTART; - - pixels_per_line = dev->calib_pixels + dev->calib_pixels_offset; - channels = dev->calib_channels; - - /* we always build data for three channels, even for gray - * we make the shading data such that each color channel data line is contiguous - * to the next one, which allow to write the 3 channels in 1 write - * during genesys_send_shading_coefficient, some values are words, other bytes - * hence the x2 factor */ - switch (dev->reg.get8(0x05) >> 6) - { - /* 600 dpi */ - case 0: - words_per_color = 0x2a00; - break; - /* 1200 dpi */ - case 1: - words_per_color = 0x5500; - break; - /* 2400 dpi */ - case 2: - words_per_color = 0xa800; - break; - /* 4800 dpi */ - case 3: - words_per_color = 0x15000; - break; - } - - /* special case, memory is aligned on 0x5400, this has yet to be explained */ - /* could be 0xa800 because sensor is truly 2400 dpi, then halved because - * we only set 1200 dpi */ - if(dev->model->ccd_type==CIS_CANONLIDE80) - { - words_per_color = 0x5400; - } - - length = words_per_color * 3 * 2; - - /* allocate computed size */ - // contains 16bit words in little endian - std::vector shading_data(length, 0); - - /* TARGET/(Wn-Dn) = white gain -> ~1.xxx then it is multiplied by 0x2000 - or 0x4000 to give an integer - Wn = white average for column n - Dn = dark average for column n - */ - if (dev->model->cmd_set->get_gain4_bit(&dev->calib_reg)) - coeff = 0x4000; - else - coeff = 0x2000; - - /* compute avg factor */ - if(dev->settings.xres>sensor.optical_res) - { - factor=1; - } - else - { - factor=sensor.optical_res/dev->settings.xres; - } - - /* for GL646, shading data is planar if REG01_FASTMOD is set and - * chunky if not. For now we rely on the fact that we know that - * each sensor is used only in one mode. Currently only the CIS_XP200 - * sets REG01_FASTMOD. - */ - - /* TODO setup a struct in genesys_devices that - * will handle these settings instead of having this switch growing up */ - cmat[0] = 0; - cmat[1] = 1; - cmat[2] = 2; - switch (dev->model->ccd_type) - { - case CCD_XP300: - case CCD_ROADWARRIOR: - case CCD_DP665: - case CCD_DP685: - case CCD_DSMOBILE600: - target_code = 0xdc00; - o = 4; - compute_planar_coefficients (dev, - shading_data.data(), - factor, - pixels_per_line, - words_per_color, - channels, - cmat, - o, - coeff, - target_code); - break; - case CIS_XP200: - target_code = 0xdc00; - o = 2; - cmat[0] = 2; /* red is last */ - cmat[1] = 0; /* green is first */ - cmat[2] = 1; /* blue is second */ - compute_planar_coefficients (dev, - shading_data.data(), - 1, - pixels_per_line, - words_per_color, - channels, - cmat, - o, - coeff, - target_code); - break; - case CCD_HP2300: - target_code = 0xdc00; - o = 2; - if(dev->settings.xres<=sensor.optical_res/2) - { - o = o - sensor.dummy_pixel / 2; - } - compute_coefficients (dev, - shading_data.data(), - pixels_per_line, - 3, - cmat, - o, - coeff, - target_code); - break; - case CCD_5345: - target_code = 0xe000; - o = 4; - if(dev->settings.xres<=sensor.optical_res/2) - { - o = o - sensor.dummy_pixel; - } - compute_coefficients (dev, - shading_data.data(), - pixels_per_line, - 3, - cmat, - o, - coeff, - target_code); - break; - case CCD_HP3670: - case CCD_HP2400: - target_code = 0xe000; - /* offset is cksel dependent, but we can't use this in common code */ - if(dev->settings.xres<=300) - { - o = -10; /* OK for <=300 */ - } - else if(dev->settings.xres<=600) - { - o = -6; /* ok at 600 */ - } - else - { - o = +2; - } - compute_coefficients (dev, - shading_data.data(), - pixels_per_line, - 3, - cmat, - o, - coeff, - target_code); - break; - case CCD_KVSS080: - case CCD_PLUSTEK3800: - case CCD_G4050: - case CCD_CS4400F: - case CCD_CS8400F: - case CCD_CS8600F: - target_code = 0xe000; - o = 0; - compute_coefficients (dev, - shading_data.data(), - pixels_per_line, - 3, - cmat, - o, - coeff, - target_code); - break; - case CIS_CANONLIDE700: - case CIS_CANONLIDE100: - case CIS_CANONLIDE200: - case CIS_CANONLIDE110: - case CIS_CANONLIDE120: - case CIS_CANONLIDE210: - case CIS_CANONLIDE220: - /* TODO store this in a data struct so we avoid - * growing this switch */ - switch(dev->model->ccd_type) - { - case CIS_CANONLIDE110: - case CIS_CANONLIDE120: - case CIS_CANONLIDE210: - case CIS_CANONLIDE220: - target_code = 0xf000; - break; - case CIS_CANONLIDE700: - target_code = 0xc000; /* from experimentation */ - break; - default: - target_code = 0xdc00; - } - words_per_color=pixels_per_line*2; - length = words_per_color * 3 * 2; - shading_data.clear(); - shading_data.resize(length, 0); - compute_planar_coefficients (dev, - shading_data.data(), - 1, - pixels_per_line, - words_per_color, - channels, - cmat, - 0, - coeff, - target_code); - break; - case CCD_CANONLIDE35: - compute_averaged_planar (dev, sensor, - shading_data.data(), - pixels_per_line, - words_per_color, - channels, - 4, - coeff, - 0xe000, - 0x0a00); - break; - case CIS_CANONLIDE80: - compute_averaged_planar (dev, sensor, - shading_data.data(), - pixels_per_line, - words_per_color, - channels, - 0, - coeff, - 0xe000, - 0x0800); - break; - case CCD_PLUSTEK_3600: - compute_shifted_coefficients (dev, sensor, - shading_data.data(), - pixels_per_line, - channels, - cmat, - 12, /* offset */ - coeff, - 0x0001, /* target_dark */ - 0xf900, /* target_bright */ - 256); /* patch_size: contigous extent */ - break; - default: - DBG (DBG_error, "%s: sensor %d not supported\n", __func__, dev->model->ccd_type); - return SANE_STATUS_UNSUPPORTED; - break; - } - - /* do the actual write of shading calibration data to the scanner */ - status = genesys_send_offset_and_shading (dev, sensor, shading_data.data(), length); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to send shading data: %s\n", __func__, - sane_strstatus (status)); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** - * search calibration cache list for an entry matching required scan. - * If one is found, set device calibration with it - * @param dev scanner's device - * @return false if no matching cache entry has been - * found, true if one has been found and used. - */ -static bool -genesys_restore_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) -{ - DBGSTART; - - /* if no cache or no function to evaluate cache entry ther can be no match */ - if (!dev->model->cmd_set->is_compatible_calibration - || dev->calibration_cache.empty()) - return false; - - /* we walk the link list of calibration cache in search for a - * matching one */ - for (auto& cache : dev->calibration_cache) - { - if (dev->model->cmd_set->is_compatible_calibration(dev, sensor, &cache, SANE_FALSE)) - { - dev->frontend = cache.frontend; - /* we don't restore the gamma fields */ - sensor.exposure = cache.sensor.exposure; - - dev->average_size = cache.average_size; - dev->calib_pixels = cache.calib_pixels; - dev->calib_channels = cache.calib_channels; - - dev->dark_average_data = cache.dark_average_data; - dev->white_average_data = cache.white_average_data; - - if(dev->model->cmd_set->send_shading_data==NULL) - { - TIE(genesys_send_shading_coefficient(dev, sensor)); - } - - DBG(DBG_proc, "%s: restored\n", __func__); - return true; - } - } - DBG(DBG_proc, "%s: completed(nothing found)\n", __func__); - return false; -} - - -static SANE_Status -genesys_save_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - - DBGSTART; - - if (!dev->model->cmd_set->is_compatible_calibration) - return SANE_STATUS_UNSUPPORTED; - - auto found_cache_it = dev->calibration_cache.end(); - for (auto cache_it = dev->calibration_cache.begin(); cache_it != dev->calibration_cache.end(); - cache_it++) - { - if (dev->model->cmd_set->is_compatible_calibration(dev, sensor, &*cache_it, SANE_TRUE)) - { - found_cache_it = cache_it; - break; - } - } - - /* if we found on overridable cache, we reuse it */ - if (found_cache_it == dev->calibration_cache.end()) - { - /* create a new cache entry and insert it in the linked list */ - dev->calibration_cache.push_back(Genesys_Calibration_Cache()); - found_cache_it = std::prev(dev->calibration_cache.end()); - } - - found_cache_it->average_size = dev->average_size; - - found_cache_it->dark_average_data = dev->dark_average_data; - found_cache_it->white_average_data = dev->white_average_data; - - found_cache_it->used_setup = dev->current_setup; - found_cache_it->frontend = dev->frontend; - found_cache_it->sensor = sensor; - - found_cache_it->calib_pixels = dev->calib_pixels; - found_cache_it->calib_channels = dev->calib_channels; - -#ifdef HAVE_SYS_TIME_H - gettimeofday(&time,NULL); - found_cache_it->last_calibration = time.tv_sec; -#endif - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * does the calibration process for a flatbed scanner - * - offset calibration - * - gain calibration - * - shading calibration - * @param dev device to calibrate - * @return SANE_STATUS_GOOD if everything when all right, else the error code. - */ -static SANE_Status -genesys_flatbed_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t pixels_per_line; - int yres; - - DBG(DBG_info, "%s\n", __func__); - - yres = sensor.optical_res; - if (dev->settings.yres <= sensor.optical_res / 2) - yres /= 2; - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - yres = 1200; - - /* do offset calibration if needed */ - if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) - { - status = dev->model->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: offset calibration failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* since all the registers are set up correctly, just use them */ - status = dev->model->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, yres); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: coarse gain calibration: %s\n", __func__, sane_strstatus(status)); - return status; - } - - } - else - /* since we have 2 gain calibration proc, skip second if first one was - used. */ - { - status = dev->model->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send calibration registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - status = genesys_coarse_calibration(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do coarse gain calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - } - - if (dev->model->is_cis) - { - /* the afe now sends valid data for doing led calibration */ - status = dev->model->cmd_set->led_calibration(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: led calibration failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* calibrate afe again to match new exposure */ - if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) - { - status = dev->model->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: offset calibration failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* since all the registers are set up correctly, just use them */ - - status = dev->model->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, yres); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: coarse gain calibration: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - else - /* since we have 2 gain calibration proc, skip second if first one was - used. */ - { - status = dev->model->cmd_set->init_regs_for_coarse_calibration(dev, sensor, - dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send calibration registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - status = genesys_coarse_calibration(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do static calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - } - - /* we always use sensor pixel number when the ASIC can't handle multi-segments sensor */ - if (!(dev->model->flags & GENESYS_FLAG_SIS_SENSOR)) - { - pixels_per_line = (SANE_UNFIX (dev->model->x_size) * dev->settings.xres) / MM_PER_INCH; - } - else - { - pixels_per_line = sensor.sensor_pixels; - } - - /* send default shading data */ - status = sanei_genesys_init_shading_data(dev, sensor, pixels_per_line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to init shading process: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { - RIE(dev->model->cmd_set->move_to_ta(dev)); - } - - /* shading calibration */ - status = dev->model->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send shading registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - if (dev->model->flags & GENESYS_FLAG_DARK_WHITE_CALIBRATION) - { - status = genesys_dark_white_shading_calibration (dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do dark+white shading calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - else - { - if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) - { - status = genesys_dark_shading_calibration(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do dark shading calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - status = genesys_white_shading_calibration (dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do white shading calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - if(dev->model->cmd_set->send_shading_data==NULL) - { - status = genesys_send_shading_coefficient(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send shading calibration coefficients: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - DBG(DBG_info, "%s: completed\n", __func__); - - return SANE_STATUS_GOOD; -} - -/** - * Does the calibration process for a sheetfed scanner - * - offset calibration - * - gain calibration - * - shading calibration - * During calibration a predefined calibration sheet with specific black and white - * areas is used. - * @param dev device to calibrate - * @return SANE_STATUS_GOOD if everything when all right, else the error code. - */ -static SANE_Status genesys_sheetfed_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool forward = SANE_TRUE; - int xres; - - DBGSTART; - if (dev->model->cmd_set->search_strip == NULL) - { - DBG(DBG_error, "%s: no strip searching function available\n", __func__); - return SANE_STATUS_UNSUPPORTED; - } - - /* first step, load document */ - status = dev->model->cmd_set->load_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to load document: %s\n", __func__, sane_strstatus(status)); - return status; - } - - - DBG(DBG_info, "%s\n", __func__); - - /* led, offset and gain calibration are influenced by scan - * settings. So we set it to sensor resolution */ - xres = sensor.optical_res; - dev->settings.xres = sensor.optical_res; - /* XP200 needs to calibrate a full and half sensor's resolution */ - if (dev->model->ccd_type == CIS_XP200 - && dev->settings.xres <= sensor.optical_res / 2) - dev->settings.xres /= 2; - - /* the afe needs to sends valid data even before calibration */ - - /* go to a white area */ - try { - status = dev->model->cmd_set->search_strip(dev, sensor, forward, SANE_FALSE); - if (status != SANE_STATUS_GOOD) { - DBG(DBG_error, "%s: failed to find white strip: %s\n", __func__, - sane_strstatus(status)); - dev->model->cmd_set->eject_document (dev); - return status; - } - } catch (...) { - dev->model->cmd_set->eject_document(dev); - throw; - } - - if (dev->model->is_cis) - { - status = dev->model->cmd_set->led_calibration(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: led calibration failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - /* calibrate afe */ - if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) - { - status = dev->model->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: offset calibration failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* since all the registers are set up correctly, just use them */ - - status = dev->model->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, xres); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: coarse gain calibration: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - else - /* since we have 2 gain calibration proc, skip second if first one was - used. */ - { - status = dev->model->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send calibration registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - status = genesys_coarse_calibration(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do static calibration: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - /* search for a full width black strip and then do a 16 bit scan to - * gather black shading data */ - if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) - { - /* seek black/white reverse/forward */ - try { - status = dev->model->cmd_set->search_strip(dev, sensor, forward, SANE_TRUE); - if (status != SANE_STATUS_GOOD) { - DBG(DBG_error, "%s: failed to find black strip: %s\n", __func__, - sane_strstatus(status)); - dev->model->cmd_set->eject_document(dev); - return status; - } - } catch (...) { - dev->model->cmd_set->eject_document(dev); - throw; - } - - status = dev->model->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do set up registers for shading calibration: %s\n", - __func__, sane_strstatus(status)); - return status; - } - try { - status = genesys_dark_shading_calibration(dev, sensor); - if (status != SANE_STATUS_GOOD) { - dev->model->cmd_set->eject_document(dev); - DBG(DBG_error, "%s: failed to do dark shading calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } catch (...) { - dev->model->cmd_set->eject_document(dev); - throw; - } - forward = SANE_FALSE; - } - - - /* go to a white area */ - try { - status = dev->model->cmd_set->search_strip(dev, sensor, forward, SANE_FALSE); - if (status != SANE_STATUS_GOOD) { - DBG(DBG_error, "%s: failed to find white strip: %s\n", __func__, - sane_strstatus(status)); - dev->model->cmd_set->eject_document (dev); - return status; - } - } catch (...) { - dev->model->cmd_set->eject_document (dev); - throw; - } - - status = dev->model->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do set up registers for shading calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - try { - status = genesys_white_shading_calibration(dev, sensor); - if (status != SANE_STATUS_GOOD) { - dev->model->cmd_set->eject_document(dev); - DBG(DBG_error, "%s: failed eject target: %s\n", __func__, sane_strstatus(status)); - return status; - } - } catch (...) { - dev->model->cmd_set->eject_document (dev); - throw; - } - - /* in case we haven't black shading data, build it from black pixels - * of white calibration */ - if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) - { - dev->dark_average_data.clear(); - dev->dark_average_data.resize(dev->average_size, 0x0f); - /* XXX STEF XXX - * with black point in white shading, build an average black - * pixel and use it to fill the dark_average - * dev->calib_pixels - (sensor.sensor_pixels * dev->settings.xres) / sensor.optical_res, - dev->calib_lines, - */ - } - - /* send the shading coefficient when doing whole line shading - * but not when using SHDAREA like GL124 */ - if(dev->model->cmd_set->send_shading_data==NULL) - { - status = genesys_send_shading_coefficient(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send shading calibration coefficients: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - /* save the calibration data */ - genesys_save_calibration (dev, sensor); - - /* and finally eject calibration sheet */ - status = dev->model->cmd_set->eject_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to eject document: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* resotre settings */ - dev->settings.xres = xres; - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * does the calibration process for a device - * @param dev device to calibrate - */ -static SANE_Status -genesys_scanner_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) -{ - if (dev->model->is_sheetfed == SANE_FALSE) - { - return genesys_flatbed_calibration (dev, sensor); - } - return genesys_sheetfed_calibration(dev, sensor); -} - -/* unused function kept in case it may be usefull in the futur */ -#if 0 -static SANE_Status -genesys_wait_not_moving (Genesys_Device * dev, int mseconds) -{ - uint8_t value; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s: waiting %d mseconds for motor to stop\n", __func__, mseconds); - while (mseconds > 0) - { - RIE (sanei_genesys_get_status (dev, &value)); - - if (dev->model->cmd_set->test_motor_flag_bit (value)) - { - sanei_genesys_sleep_ms(100); - mseconds -= 100; - DBG(DBG_io, "%s: motor is moving, %d mseconds to go\n", __func__, mseconds); - } - else - { - DBG(DBG_info, "%s: motor is not moving, exiting\n", __func__); - return SANE_STATUS_GOOD; - } - - } - DBG(DBG_error, "%s: motor is still moving, timeout exceeded\n", __func__); - return SANE_STATUS_DEVICE_BUSY; -} -#endif - - -/* ------------------------------------------------------------------------ */ -/* High level (exported) functions */ -/* ------------------------------------------------------------------------ */ - -/* - * wait lamp to be warm enough by scanning the same line until - * differences between two scans are below a threshold - */ -static SANE_Status -genesys_warmup_lamp (Genesys_Device * dev) -{ - int seconds = 0; - int pixel; - int channels, total_size; - double first_average = 0; - double second_average = 0; - int difference = 255; - int empty, lines = 3; - SANE_Status status = SANE_STATUS_IO_ERROR; - - DBGSTART; - - /* check if the current chipset implements warmup */ - if(dev->model->cmd_set->init_regs_for_warmup==NULL) - { - DBG(DBG_error,"%s: init_regs_for_warmup not implemented\n", __func__); - return status; - } - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - dev->model->cmd_set->init_regs_for_warmup(dev, sensor, &dev->reg, &channels, &total_size); - std::vector first_line(total_size); - std::vector second_line(total_size); - - do - { - DBG(DBG_info, "%s: one more loop\n", __func__); - RIE(dev->model->cmd_set->begin_scan(dev, sensor, &dev->reg, SANE_FALSE)); - do - { - sanei_genesys_test_buffer_empty (dev, &empty); - } - while (empty); - - try { - status = sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); - if (status != SANE_STATUS_GOOD) { - RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); - } - } catch (...) { - RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); - } - - RIE(dev->model->cmd_set->end_scan(dev, &dev->reg, SANE_TRUE)); - - sanei_genesys_sleep_ms(1000); - seconds++; - - RIE(dev->model->cmd_set->begin_scan(dev, sensor, &dev->reg, SANE_FALSE)); - do - { - sanei_genesys_test_buffer_empty (dev, &empty); - sanei_genesys_sleep_ms(100); - } - while (empty); - RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); - RIE(dev->model->cmd_set->end_scan(dev, &dev->reg, SANE_TRUE)); - - /* compute difference between the two scans */ - for (pixel = 0; pixel < total_size; pixel++) - { - /* 16 bit data */ - if (dev->model->cmd_set->get_bitset_bit(&dev->reg)) - { - first_average += (first_line[pixel] + first_line[pixel + 1] * 256); - second_average += (second_line[pixel] + second_line[pixel + 1] * 256); - pixel++; - } - else - { - first_average += first_line[pixel]; - second_average += second_line[pixel]; - } - } - if (dev->model->cmd_set->get_bitset_bit(&dev->reg)) - { - first_average /= pixel; - second_average /= pixel; - difference = fabs (first_average - second_average); - DBG(DBG_info, "%s: average = %.2f, diff = %.3f\n", __func__, - 100 * ((second_average) / (256 * 256)), - 100 * (difference / second_average)); - - if (second_average > (100 * 256) - && (difference / second_average) < 0.002) - break; - } - else - { - first_average /= pixel; - second_average /= pixel; - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file("gl_warmup1.pnm", first_line.data(), 8, channels, - total_size / (lines * channels), lines); - sanei_genesys_write_pnm_file("gl_warmup2.pnm", second_line.data(), 8, channels, - total_size / (lines * channels), lines); - } - DBG(DBG_info, "%s: average 1 = %.2f, average 2 = %.2f\n", __func__, first_average, - second_average); - /* if delta below 15/255 ~= 5.8%, lamp is considred warm enough */ - if (fabs (first_average - second_average) < 15 - && second_average > 55) - break; - } - - /* sleep another second before next loop */ - sanei_genesys_sleep_ms(1000); - seconds++; - } - while (seconds < WARMUP_TIME); - - if (seconds >= WARMUP_TIME) - { - DBG(DBG_error, "%s: warmup timed out after %d seconds. Lamp defective?\n", __func__, seconds); - status = SANE_STATUS_IO_ERROR; - } - else - { - DBG(DBG_info, "%s: warmup succeeded after %d seconds\n", __func__, seconds); - } - - DBGCOMPLETED; - - return status; -} - - -/* High-level start of scanning */ -static SANE_Status -genesys_start_scan (Genesys_Device * dev, SANE_Bool lamp_off) -{ - SANE_Status status = SANE_STATUS_GOOD; - unsigned int steps, expected; - SANE_Bool empty; - - DBGSTART; - - /* since not all scanners are set ot wait for head to park - * we check we are not still parking before starting a new scan */ - if (dev->parking == SANE_TRUE) - { - status = sanei_genesys_wait_for_home (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to wait for head to park: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - /* disable power saving*/ - status = dev->model->cmd_set->save_power (dev, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to disable power saving mode: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* wait for lamp warmup : until a warmup for TRANSPARENCY is designed, skip - * it when scanning from XPA. */ - if (!(dev->model->flags & GENESYS_FLAG_SKIP_WARMUP) - && (dev->settings.scan_method == ScanMethod::FLATBED)) - { - RIE (genesys_warmup_lamp (dev)); - } - - /* set top left x and y values by scanning the internals if flatbed scanners */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - /* do the geometry detection only once */ - if ((dev->model->flags & GENESYS_FLAG_SEARCH_START) - && (dev->model->y_offset_calib == 0)) - { - status = dev->model->cmd_set->search_start_position (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to search start position: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - dev->parking = SANE_FALSE; - status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to move scanhead to home position: %s\n", __func__, - sane_strstatus(status)); - return status; - } - dev->scanhead_position_in_steps = 0; - } - else - { - /* Go home */ - /* TODO: check we can drop this since we cannot have the - scanner's head wandering here */ - dev->parking = SANE_FALSE; - status = dev->model->cmd_set->slow_back_home (dev, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to move scanhead to home position: %s\n", __func__, - sane_strstatus(status)); - return status; - } - dev->scanhead_position_in_steps = 0; - } - } - - /* move to calibration area for transparency adapter */ - if ((dev->settings.scan_method == ScanMethod::TRANSPARENCY) - && dev->model->cmd_set->move_to_ta != NULL) - { - status=dev->model->cmd_set->move_to_ta(dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to move to start of transparency adapter: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - /* load document if needed (for sheetfed scanner for instance) */ - if (dev->model->is_sheetfed == SANE_TRUE - && dev->model->cmd_set->load_document != NULL) - { - status = dev->model->cmd_set->load_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to load document: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - auto& sensor = sanei_genesys_find_sensor_for_write(dev, dev->settings.xres, - dev->settings.scan_method); - - /* send gamma tables. They have been set to device or user value - * when setting option value */ - status = dev->model->cmd_set->send_gamma_table(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to init gamma table: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* try to use cached calibration first */ - if (!genesys_restore_calibration (dev, sensor)) - { - /* calibration : sheetfed scanners can't calibrate before each scan */ - /* and also those who have the NO_CALIBRATION flag */ - if (!(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) - &&dev->model->is_sheetfed == SANE_FALSE) - { - status = genesys_scanner_calibration(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do scanner calibration: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - genesys_save_calibration (dev, sensor); - } - else - { - DBG(DBG_warn, "%s: no calibration done\n", __func__); - } - } - - /* build look up table for dynamic lineart */ - if(dev->settings.dynamic_lineart==SANE_TRUE) - { - status = sanei_genesys_load_lut(dev->lineart_lut, 8, 8, 50, 205, - dev->settings.threshold_curve, - dev->settings.threshold-127); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to build lut\n", __func__); - return status; - } - } - - if (dev->model->cmd_set->wait_for_motor_stop) { - dev->model->cmd_set->wait_for_motor_stop(dev); - } - - if (dev->model->cmd_set->needs_home_before_init_regs_for_scan && - dev->model->cmd_set->needs_home_before_init_regs_for_scan(dev) && - dev->model->cmd_set->slow_back_home) - { - RIE(dev->model->cmd_set->slow_back_home(dev, SANE_TRUE)); - } - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { - RIE(dev->model->cmd_set->move_to_ta(dev)); - } - - status = dev->model->cmd_set->init_regs_for_scan(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do init registers for scan: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* no lamp during scan */ - if(lamp_off == SANE_TRUE) - { - sanei_genesys_set_lamp_power(dev, sensor, dev->reg, false); - } - - /* GL124 is using SHDAREA, so we have to wait for scan to be set up before - * sending shading data */ - if( (dev->model->cmd_set->send_shading_data!=NULL) - && !(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - status = genesys_send_shading_coefficient(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send shading calibration coefficients: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - /* now send registers for scan */ - status = - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers, status = %d\n", __func__, status); - return status; - } - - /* start effective scan */ - status = dev->model->cmd_set->begin_scan(dev, sensor, &dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - - /*do we really need this? the valid data check should be sufficent -- pierre*/ - /* waits for head to reach scanning position */ - expected = dev->reg.get8(0x3d) * 65536 - + dev->reg.get8(0x3e) * 256 - + dev->reg.get8(0x3f); - do - { - // wait some time between each test to avoid overloading USB and CPU - sanei_genesys_sleep_ms(100); - status = sanei_genesys_read_feed_steps (dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to read feed steps: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - while (steps < expected); - - /* wait for buffers to be filled */ - do - { - RIE (sanei_genesys_test_buffer_empty (dev, &empty)); - } - while (empty); - - /* when doing one or two-table movement, let the motor settle to scanning speed */ - /* and scanning start before reading data */ -/* the valid data check already waits until the scanner delivers data. this here leads to unnecessary buffer full conditions in the scanner. - if (dev->model->cmd_set->get_fast_feed_bit (dev->reg)) - sanei_genesys_sleep_ms(1000); - else - sanei_genesys_sleep_ms(500); -*/ - /* then we wait for at least one word of valid scan data - - this is also done in sanei_genesys_read_data_from_scanner -- pierre */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - do - { - sanei_genesys_sleep_ms(100); - status = sanei_genesys_read_valid_words (dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read valid words: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - while (steps < 1); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* this is _not_ a ringbuffer. - if we need a block which does not fit at the end of our available data, - we move the available data to the beginning. - */ - -void Genesys_Buffer::alloc(size_t size) -{ - buffer_.resize(size); - avail_ = 0; - pos_ = 0; -} - -void Genesys_Buffer::clear() -{ - buffer_.clear(); - avail_ = 0; - pos_ = 0; -} - -void Genesys_Buffer::reset() -{ - avail_ = 0; - pos_ = 0; -} - -uint8_t* Genesys_Buffer::get_write_pos(size_t size) -{ - if (avail_ + size > buffer_.size()) - return nullptr; - if (pos_ + avail_ + size > buffer_.size()) - { - std::memmove(buffer_.data(), buffer_.data() + pos_, avail_); - pos_ = 0; - } - return buffer_.data() + pos_ + avail_; -} - -uint8_t* Genesys_Buffer::get_read_pos() -{ - return buffer_.data() + pos_; -} - -void Genesys_Buffer::produce(size_t size) -{ - if (size > buffer_.size() - avail_) - throw std::runtime_error("buffer size exceeded"); - avail_ += size; -} - -void Genesys_Buffer::consume(size_t size) -{ - if (size > avail_) - throw std::runtime_error("no more data in buffer"); - avail_ -= size; - pos_ += size; -} - - -#include "genesys_conv.cc" - -static SANE_Status accurate_line_read(Genesys_Device * dev, - Genesys_Buffer& buffer) -{ - buffer.reset(); - - SANE_Status status = SANE_STATUS_GOOD; - status = dev->model->cmd_set->bulk_read_data(dev, 0x45, buffer.get_write_pos(buffer.size()), - buffer.size()); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, (u_long) buffer.size(), - sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - - buffer.produce(buffer.size()); - return status; -} - -/** @brief fill buffer while reducing vertical resolution - * This function fills a read buffer with scanned data from a sensor - * which puts odd and even pixels in 2 different data segment. So a complete - * must be read and bytes interleaved to get usable by the other stages - * of the backend - */ -static SANE_Status -genesys_fill_line_interp_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, size_t size) -{ - size_t count; - SANE_Status status = SANE_STATUS_GOOD; - - /* fill buffer if needed */ - if (dev->oe_buffer.avail() == 0) - { - status = accurate_line_read(dev, dev->oe_buffer); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, - (u_long) dev->oe_buffer.size(), sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - } - - /* copy size bytes of data, copying from a line when line count matches */ - count = 0; - while (count < size) - { - /* line counter */ - /* dev->line_interp holds the number of lines scanned for one line of data sent */ - if(((dev->line_count/dev->current_setup.channels) % dev->line_interp)==0) - { - /* copy pixel when line matches */ - work_buffer_dst[count] = dev->oe_buffer.get_read_pos()[dev->cur]; - count++; - } - - /* always update pointer so we skip uncopied data */ - dev->cur++; - - /* go to next line if needed */ - if (dev->cur == dev->len) - { - dev->oe_buffer.set_pos(dev->oe_buffer.pos() + dev->bpl); - dev->cur = 0; - dev->line_count++; - } - - /* read a new buffer if needed */ - if (dev->oe_buffer.pos() >= dev->oe_buffer.avail()) - { - status = accurate_line_read(dev, dev->oe_buffer); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, - (u_long) dev->oe_buffer.size(), sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - } - } - - return SANE_STATUS_GOOD; -} - -/** @brief fill buffer for segmented sensors - * This function fills a read buffer with scanned data from a sensor segmented - * in several parts (multi-lines sensors). Data of the same valid area is read - * back to back and must be interleaved to get usable by the other stages - * of the backend - */ -static SANE_Status -genesys_fill_segmented_buffer (Genesys_Device * dev, uint8_t *work_buffer_dst, size_t size) -{ - size_t count; - SANE_Status status = SANE_STATUS_GOOD; - int depth,i,n,k; - - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART && dev->settings.dynamic_lineart==SANE_FALSE) - depth = 1; - - /* fill buffer if needed */ - if (dev->oe_buffer.avail() == 0) - { - status = accurate_line_read(dev, dev->oe_buffer); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, - (u_long) dev->oe_buffer.size(), sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - } - - /* copy size bytes of data, copying from a subwindow of each line - * when last line of buffer is exhausted, read another one */ - count = 0; - while (count < size) - { - if (depth==1) { - while (dev->cur < dev->len && count < size) { - for (n=0; nsegnb; n++) { - work_buffer_dst[count+n] = 0; - } - /* interleaving is at bit level */ - for (i=0;i<8;i++) { - k=count+(i*dev->segnb)/8; - for (n=0;nsegnb;n++) { - work_buffer_dst[k] = work_buffer_dst[k] << 1; - if ((dev->oe_buffer.get_read_pos()[dev->cur + dev->skip + dev->dist*dev->order[n]])&(128>>i)) { - work_buffer_dst[k] |= 1; - } - } - } - - /* update counter and pointer */ - count += dev->segnb; - dev->cur++; - } - } - if (depth==8) { - while (dev->cur < dev->len && count < size) { - for (n=0;nsegnb;n++) { - work_buffer_dst[count+n] = dev->oe_buffer.get_read_pos()[dev->cur + dev->skip + dev->dist*dev->order[n]]; - } - /* update counter and pointer */ - count += dev->segnb; - dev->cur++; - } - } - if (depth==16) { - while (dev->cur < dev->len && count < size) { - for (n=0;nsegnb;n++) { - work_buffer_dst[count+n*2] = dev->oe_buffer.get_read_pos()[dev->cur + dev->skip + dev->dist*dev->order[n]]; - work_buffer_dst[count+n*2+1] = dev->oe_buffer.get_read_pos()[dev->cur + dev->skip + dev->dist*dev->order[n] + 1]; - } - /* update counter and pointer */ - count += dev->segnb*2; - dev->cur+=2; - } - } - - /* go to next line if needed */ - if (dev->cur == dev->len) - { - dev->oe_buffer.set_pos(dev->oe_buffer.pos() + dev->bpl); - dev->cur = 0; - } - - /* read a new buffer if needed */ - if (dev->oe_buffer.pos() >= dev->oe_buffer.avail()) - { - status = accurate_line_read(dev, dev->oe_buffer); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, - (u_long) dev->oe_buffer.size(), sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - } - } - - return SANE_STATUS_GOOD; -} - -/** - * - */ -static SANE_Status -genesys_fill_read_buffer (Genesys_Device * dev) -{ - size_t size; - size_t space; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t *work_buffer_dst; - - DBGSTART; - - /* for sheetfed scanner, we must check is document is shorter than - * the requested scan */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = dev->model->cmd_set->detect_document_end (dev); - if (status != SANE_STATUS_GOOD) - return status; - } - - space = dev->read_buffer.size() - dev->read_buffer.avail(); - - work_buffer_dst = dev->read_buffer.get_write_pos(space); - - size = space; - - /* never read an odd number. exception: last read - the chip internal counter does not count half words. */ - size &= ~1; - /* Some setups need the reads to be multiples of 256 bytes */ - size &= ~0xff; - - if (dev->read_bytes_left < size) - { - size = dev->read_bytes_left; - /*round up to a multiple of 256 bytes */ - size += (size & 0xff) ? 0x100 : 0x00; - size &= ~0xff; - } - - /* early out if our remaining buffer capacity is too low */ - if (size == 0) - return SANE_STATUS_GOOD; - - DBG(DBG_io, "%s: reading %lu bytes\n", __func__, (u_long) size); - - /* size is already maxed to our needs. for most models bulk_read_data - will read as much data as requested. */ - - /* due to sensors and motors, not all data can be directly used. It - * may have to be read from another intermediate buffer and then processed. - * There are currently 3 intermediate stages: - * - handling of odd/even sensors - * - handling of line interpolation for motors that can't have low - * enough dpi - * - handling of multi-segments sensors - * - * This is also the place where full duplex data will be handled. - */ - if (dev->line_interp>0) - { - /* line interpolation */ - status = genesys_fill_line_interp_buffer (dev, work_buffer_dst, size); - } - else if (dev->segnb>1) - { - /* multi-segment sensors processing */ - status = genesys_fill_segmented_buffer (dev, work_buffer_dst, size); - } - else /* regular case with no extra copy */ - { - status = dev->model->cmd_set->bulk_read_data (dev, 0x45, work_buffer_dst, size); - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read %lu bytes (%s)\n", __func__, (u_long) size, - sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - - if (size > dev->read_bytes_left) - size = dev->read_bytes_left; - - dev->read_bytes_left -= size; - - dev->read_buffer.produce(size); - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -/* this function does the effective data read in a manner that suits - the scanner. It does data reordering and resizing if need. - It also manages EOF and I/O errors, and line distance correction. - */ -static SANE_Status -genesys_read_ordered_data (Genesys_Device * dev, SANE_Byte * destination, - size_t * len) -{ - SANE_Status status = SANE_STATUS_GOOD; - size_t bytes, extra; - unsigned int channels, depth, src_pixels; - unsigned int ccd_shift[12], shift_count; - uint8_t *work_buffer_src; - uint8_t *work_buffer_dst; - unsigned int dst_lines; - unsigned int step_1_mode; - unsigned int needs_reorder; - unsigned int needs_ccd; - unsigned int needs_shrink; - unsigned int needs_reverse; - Genesys_Buffer *src_buffer; - Genesys_Buffer *dst_buffer; - - DBGSTART; - if (dev->read_active != SANE_TRUE) - { - DBG(DBG_error, "%s: read not active!\n", __func__); - *len = 0; - return SANE_STATUS_INVAL; - } - - DBG(DBG_info, "%s: ", __func__); - debug_dump(DBG_info, dev->current_setup); - - /* prepare conversion */ - /* current settings */ - channels = dev->current_setup.channels; - depth = dev->current_setup.depth; - - src_pixels = dev->current_setup.pixels; - - needs_reorder = 1; - if (channels != 3 && depth != 16) - needs_reorder = 0; -#ifndef WORDS_BIGENDIAN - if (channels != 3 && depth == 16) - needs_reorder = 0; - if (channels == 3 && depth == 16 && !dev->model->is_cis && - dev->model->line_mode_color_order == COLOR_ORDER_RGB) - needs_reorder = 0; -#endif - if (channels == 3 && depth == 8 && !dev->model->is_cis && - dev->model->line_mode_color_order == COLOR_ORDER_RGB) - needs_reorder = 0; - - needs_ccd = dev->current_setup.max_shift > 0; - needs_shrink = dev->settings.pixels != src_pixels; - needs_reverse = depth == 1; - - DBG(DBG_info, "%s: using filters:%s%s%s%s\n", __func__, - needs_reorder ? " reorder" : "", - needs_ccd ? " ccd" : "", - needs_shrink ? " shrink" : "", - needs_reverse ? " reverse" : ""); - - DBG(DBG_info, "%s: frontend requested %lu bytes\n", __func__, (u_long) * len); - - DBG(DBG_info, "%s: bytes_to_read=%lu, total_bytes_read=%lu\n", __func__, - (u_long) dev->total_bytes_to_read, (u_long) dev->total_bytes_read); - /* is there data left to scan */ - if (dev->total_bytes_read >= dev->total_bytes_to_read) - { - DBG(DBG_proc, "%s: nothing more to scan: EOF\n", __func__); - *len = 0; - - /* issue park command immediatly in case scanner can handle it - * so we save time */ - if (dev->model->is_sheetfed == SANE_FALSE - && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) - && dev->parking == SANE_FALSE) - { - dev->model->cmd_set->slow_back_home (dev, SANE_FALSE); - dev->parking = SANE_TRUE; - } - return SANE_STATUS_EOF; - } - - DBG(DBG_info, "%s: %lu lines left by output\n", __func__, - ((dev->total_bytes_to_read - dev->total_bytes_read) * 8UL) / - (dev->settings.pixels * channels * depth)); - DBG(DBG_info, "%s: %lu lines left by input\n", __func__, - ((dev->read_bytes_left + dev->read_buffer.avail()) * 8UL) / - (src_pixels * channels * depth)); - - if (channels == 1) - { - ccd_shift[0] = 0; - ccd_shift[1] = dev->current_setup.stagger; - shift_count = 2; - } - else - { - ccd_shift[0] = - ((dev->ld_shift_r * dev->settings.yres) / - dev->motor.base_ydpi); - ccd_shift[1] = - ((dev->ld_shift_g * dev->settings.yres) / - dev->motor.base_ydpi); - ccd_shift[2] = - ((dev->ld_shift_b * dev->settings.yres) / - dev->motor.base_ydpi); - - ccd_shift[3] = ccd_shift[0] + dev->current_setup.stagger; - ccd_shift[4] = ccd_shift[1] + dev->current_setup.stagger; - ccd_shift[5] = ccd_shift[2] + dev->current_setup.stagger; - - shift_count = 6; - } - - -/* convert data */ -/* - 0. fill_read_buffer --------------- read_buffer ---------------------- - 1a). (opt)uncis (assumes color components to be laid out - planar) - 1b). (opt)reverse_RGB (assumes pixels to be BGR or BBGGRR)) --------------- lines_buffer ---------------------- - 2a). (opt)line_distance_correction (assumes RGB or RRGGBB) - 2b). (opt)unstagger (assumes pixels to be depth*channels/8 - bytes long, unshrinked) -------------- shrink_buffer --------------------- - 3. (opt)shrink_lines (assumes component separation in pixels) --------------- out_buffer ----------------------- - 4. memcpy to destination (for lineart with bit reversal) -*/ -/*FIXME: for lineart we need sub byte addressing in buffers, or conversion to - bytes at 0. and back to bits at 4. -Problems with the first approach: - - its not clear how to check if we need to output an incomplete byte - because it is the last one. - */ -/*FIXME: add lineart support for gl646. in the meantime add logic to convert - from gray to lineart at the end? would suffer the above problem, - total_bytes_to_read and total_bytes_read help in that case. - */ - - status = genesys_fill_read_buffer (dev); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: genesys_fill_read_buffer failed\n", __func__); - return status; - } - - src_buffer = &(dev->read_buffer); - -/* maybe reorder components/bytes */ - if (needs_reorder) - { -/*not implemented for depth == 1.*/ - if (depth == 1) - { - DBG(DBG_error, "Can't reorder single bit data\n"); - return SANE_STATUS_INVAL; - } - - dst_buffer = &(dev->lines_buffer); - - work_buffer_src = src_buffer->get_read_pos(); - bytes = src_buffer->avail(); - -/*how many bytes can be processed here?*/ -/*we are greedy. we work as much as possible*/ - if (bytes > dst_buffer->size() - dst_buffer->avail()) - bytes = dst_buffer->size() - dst_buffer->avail(); - - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - bytes = (dst_lines * src_pixels * channels * depth) / 8; - - work_buffer_dst = dst_buffer->get_write_pos(bytes); - - DBG(DBG_info, "%s: reordering %d lines\n", __func__, dst_lines); - - if (dst_lines != 0) - { - - if (channels == 3) - { - step_1_mode = 0; - - if (depth == 16) - step_1_mode |= 1; - - if (dev->model->is_cis) - step_1_mode |= 2; - - if (dev->model->line_mode_color_order == COLOR_ORDER_BGR) - step_1_mode |= 4; - - switch (step_1_mode) - { - case 1: /* RGB, chunky, 16 bit */ -#ifdef WORDS_BIGENDIAN - status = - genesys_reorder_components_endian_16 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, 3); - break; -#endif /*WORDS_BIGENDIAN */ - case 0: /* RGB, chunky, 8 bit */ - status = SANE_STATUS_GOOD; - break; - case 2: /* RGB, cis, 8 bit */ - status = - genesys_reorder_components_cis_8 (work_buffer_src, - work_buffer_dst, - dst_lines, src_pixels); - break; - case 3: /* RGB, cis, 16 bit */ - status = - genesys_reorder_components_cis_16 (work_buffer_src, - work_buffer_dst, - dst_lines, src_pixels); - break; - case 4: /* BGR, chunky, 8 bit */ - status = - genesys_reorder_components_bgr_8 (work_buffer_src, - work_buffer_dst, - dst_lines, src_pixels); - break; - case 5: /* BGR, chunky, 16 bit */ - status = - genesys_reorder_components_bgr_16 (work_buffer_src, - work_buffer_dst, - dst_lines, src_pixels); - break; - case 6: /* BGR, cis, 8 bit */ - status = - genesys_reorder_components_cis_bgr_8 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels); - break; - case 7: /* BGR, cis, 16 bit */ - status = - genesys_reorder_components_cis_bgr_16 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels); - break; - } - } - else - { -#ifdef WORDS_BIGENDIAN - if (depth == 16) - { - status = - genesys_reorder_components_endian_16 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, 1); - } - else - { - status = SANE_STATUS_GOOD; - } -#else /*!WORDS_BIGENDIAN */ - status = SANE_STATUS_GOOD; -#endif /*WORDS_BIGENDIAN */ - } - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to convert byte ordering(%s)\n", __func__, - sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - - dst_buffer->produce(bytes); - src_buffer->consume(bytes); - } - src_buffer = dst_buffer; - } - -/* maybe reverse effects of ccd layout */ - if (needs_ccd) - { -/*should not happen with depth == 1.*/ - if (depth == 1) - { - DBG(DBG_error, "Can't reverse ccd for single bit data\n"); - return SANE_STATUS_INVAL; - } - - dst_buffer = &(dev->shrink_buffer); - - work_buffer_src = src_buffer->get_read_pos(); - bytes = src_buffer->avail(); - - extra = - (dev->current_setup.max_shift * src_pixels * channels * depth) / 8; - -/*extra bytes are reserved, and should not be consumed*/ - if (bytes < extra) - bytes = 0; - else - bytes -= extra; - -/*how many bytes can be processed here?*/ -/*we are greedy. we work as much as possible*/ - if (bytes > dst_buffer->size() - dst_buffer->avail()) - bytes = dst_buffer->size() - dst_buffer->avail(); - - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - bytes = (dst_lines * src_pixels * channels * depth) / 8; - - work_buffer_dst = dst_buffer->get_write_pos(bytes); - - DBG(DBG_info, "%s: un-ccd-ing %d lines\n", __func__, dst_lines); - - if (dst_lines != 0) - { - - if (depth == 8) - status = genesys_reverse_ccd_8 (work_buffer_src, work_buffer_dst, - dst_lines, - src_pixels * channels, - ccd_shift, shift_count); - else - status = genesys_reverse_ccd_16 (work_buffer_src, work_buffer_dst, - dst_lines, - src_pixels * channels, - ccd_shift, shift_count); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to reverse ccd effects(%s)\n", __func__, - sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - - dst_buffer->produce(bytes); - src_buffer->consume(bytes); - } - src_buffer = dst_buffer; - } - -/* maybe shrink(or enlarge) lines */ - if (needs_shrink) - { - - dst_buffer = &(dev->out_buffer); - - work_buffer_src = src_buffer->get_read_pos(); - bytes = src_buffer->avail(); - -/*lines in input*/ - dst_lines = (bytes * 8) / (src_pixels * channels * depth); - - /* how many lines can be processed here? */ - /* we are greedy. we work as much as possible */ - bytes = dst_buffer->size() - dst_buffer->avail(); - - if (dst_lines > (bytes * 8) / (dev->settings.pixels * channels * depth)) - dst_lines = (bytes * 8) / (dev->settings.pixels * channels * depth); - - bytes = (dst_lines * dev->settings.pixels * channels * depth) / 8; - - work_buffer_dst = dst_buffer->get_write_pos(bytes); - - DBG(DBG_info, "%s: shrinking %d lines\n", __func__, dst_lines); - - if (dst_lines != 0) - { - if (depth == 1) - status = genesys_shrink_lines_1 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, - dev->settings.pixels, - channels); - else if (depth == 8) - status = genesys_shrink_lines_8 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, - dev->settings.pixels, channels); - else - status = genesys_shrink_lines_16 (work_buffer_src, - work_buffer_dst, - dst_lines, - src_pixels, - dev->settings.pixels, channels); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to shrink lines(%s)\n", __func__, sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - - /* we just consumed this many bytes*/ - bytes = (dst_lines * src_pixels * channels * depth) / 8; - src_buffer->consume(bytes); - - /* we just created this many bytes*/ - bytes = (dst_lines * dev->settings.pixels * channels * depth) / 8; - dst_buffer->produce(bytes); - } - src_buffer = dst_buffer; - } - - /* move data to destination */ - bytes = src_buffer->avail(); - if (bytes > *len) - bytes = *len; - work_buffer_src = src_buffer->get_read_pos(); - - if (needs_reverse) - { - status = genesys_reverse_bits (work_buffer_src, destination, bytes); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to reverse bits(%s)\n", __func__, sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - *len = bytes; - } - else - { - memcpy (destination, work_buffer_src, bytes); - *len = bytes; - } - - /* avoid signaling some extra data because we have treated a full block - * on the last block */ - if (dev->total_bytes_read + *len > dev->total_bytes_to_read) - *len = dev->total_bytes_to_read - dev->total_bytes_read; - - /* count bytes sent to frontend */ - dev->total_bytes_read += *len; - - src_buffer->consume(bytes); - - /* end scan if all needed data have been read */ - if(dev->total_bytes_read >= dev->total_bytes_to_read) - { - dev->model->cmd_set->end_scan(dev, &dev->reg, SANE_TRUE); - if (dev->model->is_sheetfed == SANE_TRUE) - { - dev->model->cmd_set->eject_document (dev); - } - } - - DBG(DBG_proc, "%s: completed, %lu bytes read\n", __func__, (u_long) bytes); - return SANE_STATUS_GOOD; -} - - - -/* ------------------------------------------------------------------------ */ -/* Start of higher level functions */ -/* ------------------------------------------------------------------------ */ - -static size_t -max_string_size (const SANE_String_Const strings[]) -{ - size_t size, max_size = 0; - SANE_Int i; - - for (i = 0; strings[i]; ++i) - { - size = strlen (strings[i]) + 1; - if (size > max_size) - max_size = size; - } - return max_size; -} - -static SANE_Status -calc_parameters (Genesys_Scanner * s) -{ - SANE_Status status = SANE_STATUS_GOOD; - double tl_x = 0, tl_y = 0, br_x = 0, br_y = 0; - - tl_x = SANE_UNFIX(s->pos_top_left_x); - tl_y = SANE_UNFIX(s->pos_top_left_y); - br_x = SANE_UNFIX(s->pos_bottom_right_x); - br_y = SANE_UNFIX(s->pos_bottom_right_y); - - s->params.last_frame = SANE_TRUE; /* only single pass scanning supported */ - - if (s->mode == SANE_VALUE_SCAN_MODE_GRAY || s->mode == SANE_VALUE_SCAN_MODE_LINEART) { - s->params.format = SANE_FRAME_GRAY; - } else { - s->params.format = SANE_FRAME_RGB; - } - - if (s->mode == SANE_VALUE_SCAN_MODE_LINEART) { - s->params.depth = 1; - } else { - s->params.depth = s->bit_depth; - } - - s->dev->settings.depth = s->bit_depth; - - /* interpolation */ - s->dev->settings.disable_interpolation = s->disable_interpolation; - - // FIXME: use correct sensor - const auto& sensor = sanei_genesys_find_sensor_any(s->dev); - - // hardware settings - if (s->resolution > sensor.optical_res && s->dev->settings.disable_interpolation) { - s->dev->settings.xres = sensor.optical_res; - } else { - s->dev->settings.xres = s->resolution; - } - s->dev->settings.yres = s->resolution; - - s->params.lines = ((br_y - tl_y) * s->dev->settings.yres) / MM_PER_INCH; - s->params.pixels_per_line = ((br_x - tl_x) * s->resolution) / MM_PER_INCH; - - /* we need an even pixels number - * TODO invert test logic or generalize behaviour across all ASICs */ - if ((s->dev->model->flags & GENESYS_FLAG_SIS_SENSOR) - || s->dev->model->asic_type == GENESYS_GL847 - || s->dev->model->asic_type == GENESYS_GL124 - || s->dev->model->asic_type == GENESYS_GL845 - || s->dev->model->asic_type == GENESYS_GL846 - || s->dev->model->asic_type == GENESYS_GL843) - { - if (s->dev->settings.xres <= 1200) - s->params.pixels_per_line = (s->params.pixels_per_line/4)*4; - else - s->params.pixels_per_line = (s->params.pixels_per_line/16)*16; - } - - /* corner case for true lineart for sensor with several segments - * or when xres is doubled to match yres */ - if (s->dev->settings.xres >= 1200 - && ( s->dev->model->asic_type == GENESYS_GL124 - || s->dev->model->asic_type == GENESYS_GL847 - || s->dev->current_setup.xres < s->dev->current_setup.yres - ) - ) - { - s->params.pixels_per_line = (s->params.pixels_per_line/16)*16; - } - - s->params.bytes_per_line = s->params.pixels_per_line; - if (s->params.depth > 8) - { - s->params.depth = 16; - s->params.bytes_per_line *= 2; - } - else if (s->params.depth == 1) - { - s->params.bytes_per_line /= 8; - /* round down pixel number - really? rounding down means loss of at most 7 pixels! -- pierre */ - s->params.pixels_per_line = 8 * s->params.bytes_per_line; - } - - if (s->params.format == SANE_FRAME_RGB) { - s->params.bytes_per_line *= 3; - } - - if (s->mode == SANE_VALUE_SCAN_MODE_COLOR) { - s->dev->settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - } else if (s->mode == SANE_VALUE_SCAN_MODE_GRAY) { - s->dev->settings.scan_mode = ScanColorMode::GRAY; - } else if (s->mode == SANE_TITLE_HALFTONE) { - s->dev->settings.scan_mode = ScanColorMode::HALFTONE; - } else { /* Lineart */ - s->dev->settings.scan_mode = ScanColorMode::LINEART; - } - - if (s->source == STR_FLATBED) { - s->dev->settings.scan_method = ScanMethod::FLATBED; - } else if (s->source == STR_TRANSPARENCY_ADAPTER) { - s->dev->settings.scan_method = ScanMethod::TRANSPARENCY; - } else if (s->source == STR_TRANSPARENCY_ADAPTER_INFRARED) { - s->dev->settings.scan_method = ScanMethod::TRANSPARENCY_INFRARED; - } - - s->dev->settings.lines = s->params.lines; - s->dev->settings.pixels = s->params.pixels_per_line; - s->dev->settings.tl_x = tl_x; - s->dev->settings.tl_y = tl_y; - - // threshold setting - s->dev->settings.threshold = 2.55 * (SANE_UNFIX(s->threshold)); - - // color filter - if (s->color_filter == "Red") { - s->dev->settings.color_filter = ColorFilter::RED; - } else if (s->color_filter == "Green") { - s->dev->settings.color_filter = ColorFilter::GREEN; - } else if (s->color_filter == "Blue") { - s->dev->settings.color_filter = ColorFilter::BLUE; - } else { - s->dev->settings.color_filter = ColorFilter::NONE; - } - - // true gray - if (s->color_filter == "None") { - s->dev->settings.true_gray = 1; - } else { - s->dev->settings.true_gray = 0; - } - - /* dynamic lineart */ - s->dev->settings.dynamic_lineart = SANE_FALSE; - s->dev->settings.threshold_curve=0; - if (!s->disable_dynamic_lineart && s->dev->settings.scan_mode == ScanColorMode::LINEART) { - s->dev->settings.dynamic_lineart = SANE_TRUE; - } - - /* hardware lineart works only when we don't have interleave data - * for GL847 scanners, ie up to 600 DPI, then we have to rely on - * dynamic_lineart */ - if(s->dev->settings.xres > 600 - && s->dev->model->asic_type==GENESYS_GL847 - && s->dev->settings.scan_mode == ScanColorMode::LINEART) - { - s->dev->settings.dynamic_lineart = SANE_TRUE; - } - - // threshold curve for dynamic rasterization - s->dev->settings.threshold_curve = s->threshold_curve; - - /* some digital processing requires the whole picture to be buffered */ - /* no digital processing takes place when doing preview, or when bit depth is - * higher than 8 bits */ - if ((s->swdespeck || s->swcrop || s->swdeskew || s->swderotate ||(SANE_UNFIX(s->swskip)>0)) - && (!s->preview) - && (s->bit_depth <= 8)) - { - s->dev->buffer_image=SANE_TRUE; - } - else - { - s->dev->buffer_image=SANE_FALSE; - } - - /* brigthness and contrast only for for 8 bit scans */ - if(s->bit_depth <= 8) - { - s->dev->settings.contrast = (s->contrast * 127) / 100; - s->dev->settings.brightness = (s->brightness * 127) / 100; - } - else - { - s->dev->settings.contrast=0; - s->dev->settings.brightness=0; - } - - /* cache expiration time */ - s->dev->settings.expiration_time = s->expiration_time; - - return status; -} - - -static SANE_Status -create_bpp_list (Genesys_Scanner * s, SANE_Int * bpp) -{ - int count; - - for (count = 0; bpp[count] != 0; count++) - ; - s->bpp_list[0] = count; - for (count = 0; bpp[count] != 0; count++) - { - s->bpp_list[s->bpp_list[0] - count] = bpp[count]; - } - return SANE_STATUS_GOOD; -} - -/** @brief this function initialize a gamma vector based on the ASIC: - * Set up a default gamma table vector based on device description - * gl646: 12 or 14 bits gamma table depending on GENESYS_FLAG_14BIT_GAMMA - * gl84x: 16 bits - * gl12x: 16 bits - * @param scanner pointer to scanner session to get options - * @param option option number of the gamma table to set - */ -static void -init_gamma_vector_option (Genesys_Scanner * scanner, int option) -{ - /* the option is inactive until the custom gamma control - * is enabled */ - scanner->opt[option].type = SANE_TYPE_INT; - scanner->opt[option].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED; - scanner->opt[option].unit = SANE_UNIT_NONE; - scanner->opt[option].constraint_type = SANE_CONSTRAINT_RANGE; - if (scanner->dev->model->asic_type == GENESYS_GL646) - { - if ((scanner->dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) != 0) - { - scanner->opt[option].size = 16384 * sizeof (SANE_Word); - scanner->opt[option].constraint.range = &u14_range; - } - else - { /* 12 bits gamma tables */ - scanner->opt[option].size = 4096 * sizeof (SANE_Word); - scanner->opt[option].constraint.range = &u12_range; - } - } - else - { /* other asics have 16 bits words gamma table */ - scanner->opt[option].size = 256 * sizeof (SANE_Word); - scanner->opt[option].constraint.range = &u16_range; - } -} - -/** - * allocate a geometry range - * @param size maximum size of the range - * @return a pointer to a valid range or NULL - */ -static SANE_Range *create_range(SANE_Fixed size) -{ -SANE_Range *range=NULL; - - range=(SANE_Range *)malloc(sizeof(SANE_Range)); - if(range!=NULL) - { - range->min = SANE_FIX (0.0); - range->max = size; - range->quant = SANE_FIX (0.0); - } - return range; -} - -/** @brief generate calibration cache file nam - * Generates the calibration cache file name to use. - * Tries to store the chache in $HOME/.sane or - * then fallbacks to $TMPDIR or TMP. The filename - * uses the model name if only one scanner is plugged - * else is uses the device name when several identical - * scanners are in use. - * @param currdev current scanner device - * @return an allocated string containing a file name - */ -static char *calibration_filename(Genesys_Device *currdev) -{ - char *tmpstr; - char *ptr; - char filename[80]; - unsigned int count; - unsigned int i; - - /* allocate space for result */ - tmpstr = (char*) malloc(PATH_MAX); - if(tmpstr==NULL) - { - return NULL; - } - - /* first compute the DIR where we can store cache: - * 1 - home dir - * 2 - $TMPDIR - * 3 - $TMP - * 4 - tmp dir - * 5 - temp dir - * 6 - then resort to current dir - */ - ptr = getenv ("HOME"); - if(ptr==NULL) - { - ptr = getenv ("USERPROFILE"); - } - if(ptr==NULL) - { - ptr = getenv ("TMPDIR"); - } - if(ptr==NULL) - { - ptr = getenv ("TMP"); - } - - /* now choose filename: - * 1 - if only one scanner, name of the model - * 2 - if several scanners of the same model, use device name, - * replacing special chars - */ - count=0; - /* count models of the same names if several scanners attached */ - if(s_devices->size() > 1) { - for (const auto& dev : *s_devices) { - if (dev.model->model_id == currdev->model->model_id) { - count++; - } - } - } - if(count>1) - { - snprintf(filename,sizeof(filename),"%s.cal",currdev->file_name); - for(i=0;imodel->name); - } - - /* build final final name : store dir + filename */ - if (NULL == ptr) - { - snprintf (tmpstr, PATH_MAX, "%s", filename); - } - else - { -#ifdef HAVE_MKDIR - /* make sure .sane directory exists in existing store dir */ - snprintf (tmpstr, PATH_MAX, "%s%c.sane", ptr, PATH_SEP); - mkdir(tmpstr,0700); -#endif - snprintf (tmpstr, PATH_MAX, "%s%c.sane%c%s", ptr, PATH_SEP, PATH_SEP, filename); - } - - DBG(DBG_info, "%s: calibration filename >%s<\n", __func__, tmpstr); - - return tmpstr; -} - - -static SANE_Status -init_options (Genesys_Scanner * s) -{ - SANE_Int option, count, min_dpi; - SANE_Status status = SANE_STATUS_GOOD; - SANE_Word *dpi_list; - Genesys_Model *model = s->dev->model; - SANE_Range *x_range, *y_range; - - DBGSTART; - - memset (s->opt, 0, sizeof (s->opt)); - - for (option = 0; option < NUM_OPTIONS; ++option) - { - s->opt[option].size = sizeof (SANE_Word); - s->opt[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - } - s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; - s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; - s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; - s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; - s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; - - /* "Mode" group: */ - s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode"); - s->opt[OPT_MODE_GROUP].desc = ""; - s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_MODE_GROUP].size = 0; - s->opt[OPT_MODE_GROUP].cap = 0; - s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - /* scan mode */ - s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; - s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; - s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; - s->opt[OPT_MODE].type = SANE_TYPE_STRING; - s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; - s->opt[OPT_MODE].size = max_string_size (mode_list); - s->opt[OPT_MODE].constraint.string_list = mode_list; - s->mode = SANE_VALUE_SCAN_MODE_GRAY; - - /* scan source */ - s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; - s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; - s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; - s->opt[OPT_SOURCE].type = SANE_TYPE_STRING; - s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; - s->opt[OPT_SOURCE].size = max_string_size (source_list); - s->opt[OPT_SOURCE].constraint.string_list = source_list; - s->source = STR_FLATBED; - if (model->flags & GENESYS_FLAG_HAS_UTA) - { - ENABLE (OPT_SOURCE); - if (model->flags & GENESYS_FLAG_HAS_UTA_INFRARED) { - s->opt[OPT_SOURCE].size = max_string_size(source_list_infrared); - s->opt[OPT_SOURCE].constraint.string_list = source_list_infrared; - } - } - else - { - DISABLE (OPT_SOURCE); - } - - /* preview */ - s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; - s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; - s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; - s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; - s->opt[OPT_PREVIEW].unit = SANE_UNIT_NONE; - s->opt[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE; - s->preview = false; - - /* bit depth */ - s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; - s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; - s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; - s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT; - s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; - s->opt[OPT_BIT_DEPTH].size = sizeof (SANE_Word); - s->opt[OPT_BIT_DEPTH].constraint.word_list = 0; - s->opt[OPT_BIT_DEPTH].constraint.word_list = s->bpp_list; - create_bpp_list (s, model->bpp_gray_values); - s->bit_depth = 8; - if (s->opt[OPT_BIT_DEPTH].constraint.word_list[0] < 2) - DISABLE (OPT_BIT_DEPTH); - - /* resolution */ - min_dpi=200000; - for (count = 0; model->xdpi_values[count] != 0; count++) - { - if(model->xdpi_values[count]xdpi_values[count]; - } - } - dpi_list = (SANE_Word*) malloc((count + 1) * sizeof(SANE_Word)); - if (!dpi_list) - return SANE_STATUS_NO_MEM; - dpi_list[0] = count; - for (count = 0; model->xdpi_values[count] != 0; count++) - dpi_list[count + 1] = model->xdpi_values[count]; - s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; - s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; - s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; - s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; - s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; - s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; - s->opt[OPT_RESOLUTION].constraint.word_list = dpi_list; - s->resolution = min_dpi; - - /* "Geometry" group: */ - s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry"); - s->opt[OPT_GEOMETRY_GROUP].desc = ""; - s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_GEOMETRY_GROUP].size = 0; - s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - x_range=create_range(model->x_size); - if(x_range==NULL) - { - return SANE_STATUS_NO_MEM; - } - - y_range=create_range(model->y_size); - if(y_range==NULL) - { - return SANE_STATUS_NO_MEM; - } - - /* top-left x */ - s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; - s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; - s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; - s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; - s->opt[OPT_TL_X].unit = SANE_UNIT_MM; - s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_TL_X].constraint.range = x_range; - s->pos_top_left_x = 0; - - /* top-left y */ - s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; - s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; - s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; - s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; - s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; - s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_TL_Y].constraint.range = y_range; - s->pos_top_left_y = 0; - - /* bottom-right x */ - s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; - s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; - s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; - s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; - s->opt[OPT_BR_X].unit = SANE_UNIT_MM; - s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_BR_X].constraint.range = x_range; - s->pos_bottom_right_x = x_range->max; - - /* bottom-right y */ - s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; - s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; - s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; - s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; - s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; - s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_BR_Y].constraint.range = y_range; - s->pos_bottom_right_y = y_range->max; - - /* "Enhancement" group: */ - s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement"); - s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; - s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_ENHANCEMENT_GROUP].size = 0; - s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - /* custom-gamma table */ - s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA; - s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA; - s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA; - s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL; - s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_ADVANCED; - s->custom_gamma = false; - - /* grayscale gamma vector */ - s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; - s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; - s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR; - init_gamma_vector_option (s, OPT_GAMMA_VECTOR); - - /* red gamma vector */ - s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R; - s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R; - s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R; - init_gamma_vector_option (s, OPT_GAMMA_VECTOR_R); - - /* green gamma vector */ - s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G; - s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G; - s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G; - init_gamma_vector_option (s, OPT_GAMMA_VECTOR_G); - - /* blue gamma vector */ - s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B; - s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B; - s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B; - init_gamma_vector_option (s, OPT_GAMMA_VECTOR_B); - - /* currently, there are only gamma table options in this group, - * so if the scanner doesn't support gamma table, disable the - * whole group */ - if (!(model->flags & GENESYS_FLAG_CUSTOM_GAMMA)) - { - s->opt[OPT_ENHANCEMENT_GROUP].cap |= SANE_CAP_INACTIVE; - s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; - DBG(DBG_info, "%s: custom gamma disabled\n", __func__); - } - - /* software base image enhancements, these are consuming as many - * memory than used by the full scanned image and may fail at high - * resolution - */ - /* software deskew */ - s->opt[OPT_SWDESKEW].name = "swdeskew"; - s->opt[OPT_SWDESKEW].title = "Software deskew"; - s->opt[OPT_SWDESKEW].desc = "Request backend to rotate skewed pages digitally"; - s->opt[OPT_SWDESKEW].type = SANE_TYPE_BOOL; - s->opt[OPT_SWDESKEW].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->swdeskew = false; - - /* software deskew */ - s->opt[OPT_SWDESPECK].name = "swdespeck"; - s->opt[OPT_SWDESPECK].title = "Software despeck"; - s->opt[OPT_SWDESPECK].desc = "Request backend to remove lone dots digitally"; - s->opt[OPT_SWDESPECK].type = SANE_TYPE_BOOL; - s->opt[OPT_SWDESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->swdespeck = false; - - /* software despeckle radius */ - s->opt[OPT_DESPECK].name = "despeck"; - s->opt[OPT_DESPECK].title = "Software despeckle diameter"; - s->opt[OPT_DESPECK].desc = "Maximum diameter of lone dots to remove from scan"; - s->opt[OPT_DESPECK].type = SANE_TYPE_INT; - s->opt[OPT_DESPECK].unit = SANE_UNIT_NONE; - s->opt[OPT_DESPECK].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_DESPECK].constraint.range = &swdespeck_range; - s->opt[OPT_DESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED | SANE_CAP_INACTIVE; - s->despeck = 1; - - /* crop by software */ - s->opt[OPT_SWCROP].name = "swcrop"; - s->opt[OPT_SWCROP].title = SANE_I18N ("Software crop"); - s->opt[OPT_SWCROP].desc = SANE_I18N ("Request backend to remove border from pages digitally"); - s->opt[OPT_SWCROP].type = SANE_TYPE_BOOL; - s->opt[OPT_SWCROP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->opt[OPT_SWCROP].unit = SANE_UNIT_NONE; - s->swcrop = false; - - /* Software blank page skip */ - s->opt[OPT_SWSKIP].name = "swskip"; - s->opt[OPT_SWSKIP].title = SANE_I18N ("Software blank skip percentage"); - s->opt[OPT_SWSKIP].desc = SANE_I18N("Request driver to discard pages with low numbers of dark pixels"); - s->opt[OPT_SWSKIP].type = SANE_TYPE_FIXED; - s->opt[OPT_SWSKIP].unit = SANE_UNIT_PERCENT; - s->opt[OPT_SWSKIP].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_SWSKIP].constraint.range = &(percentage_range); - s->opt[OPT_SWSKIP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->swskip = 0; // disable by default - - /* Software Derotate */ - s->opt[OPT_SWDEROTATE].name = "swderotate"; - s->opt[OPT_SWDEROTATE].title = SANE_I18N ("Software derotate"); - s->opt[OPT_SWDEROTATE].desc = SANE_I18N("Request driver to detect and correct 90 degree image rotation"); - s->opt[OPT_SWDEROTATE].type = SANE_TYPE_BOOL; - s->opt[OPT_SWDEROTATE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; - s->opt[OPT_SWDEROTATE].unit = SANE_UNIT_NONE; - s->swderotate = false; - - /* Software brightness */ - s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; - s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; - s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; - s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; - s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; - s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_BRIGHTNESS].constraint.range = &(enhance_range); - s->opt[OPT_BRIGHTNESS].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - s->brightness = 0; // disable by default - - /* Sowftware contrast */ - s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; - s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; - s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; - s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; - s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; - s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_CONTRAST].constraint.range = &(enhance_range); - s->opt[OPT_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; - s->contrast = 0; // disable by default - - /* "Extras" group: */ - s->opt[OPT_EXTRAS_GROUP].title = SANE_I18N ("Extras"); - s->opt[OPT_EXTRAS_GROUP].desc = ""; - s->opt[OPT_EXTRAS_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_EXTRAS_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_EXTRAS_GROUP].size = 0; - s->opt[OPT_EXTRAS_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - /* BW threshold */ - s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD; - s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; - s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; - s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED; - s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; - s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_THRESHOLD].constraint.range = &percentage_range; - s->threshold = SANE_FIX(50); - - /* BW threshold curve */ - s->opt[OPT_THRESHOLD_CURVE].name = "threshold-curve"; - s->opt[OPT_THRESHOLD_CURVE].title = SANE_I18N ("Threshold curve"); - s->opt[OPT_THRESHOLD_CURVE].desc = SANE_I18N ("Dynamic threshold curve, from light to dark, normally 50-65"); - s->opt[OPT_THRESHOLD_CURVE].type = SANE_TYPE_INT; - s->opt[OPT_THRESHOLD_CURVE].unit = SANE_UNIT_NONE; - s->opt[OPT_THRESHOLD_CURVE].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_THRESHOLD_CURVE].constraint.range = &threshold_curve_range; - s->threshold_curve = 50; - - /* dynamic linart */ - s->opt[OPT_DISABLE_DYNAMIC_LINEART].name = "disable-dynamic-lineart"; - s->opt[OPT_DISABLE_DYNAMIC_LINEART].title = SANE_I18N ("Disable dynamic lineart"); - s->opt[OPT_DISABLE_DYNAMIC_LINEART].desc = - SANE_I18N ("Disable use of a software adaptive algorithm to generate lineart relying instead on hardware lineart."); - s->opt[OPT_DISABLE_DYNAMIC_LINEART].type = SANE_TYPE_BOOL; - s->opt[OPT_DISABLE_DYNAMIC_LINEART].unit = SANE_UNIT_NONE; - s->opt[OPT_DISABLE_DYNAMIC_LINEART].constraint_type = SANE_CONSTRAINT_NONE; - s->disable_dynamic_lineart = false; - - /* fastmod is required for hw lineart to work */ - if ((s->dev->model->asic_type == GENESYS_GL646) - &&(s->dev->model->motor_type != MOTOR_XP200)) - { - s->opt[OPT_DISABLE_DYNAMIC_LINEART].cap = SANE_CAP_INACTIVE; - } - - /* disable_interpolation */ - s->opt[OPT_DISABLE_INTERPOLATION].name = "disable-interpolation"; - s->opt[OPT_DISABLE_INTERPOLATION].title = - SANE_I18N ("Disable interpolation"); - s->opt[OPT_DISABLE_INTERPOLATION].desc = - SANE_I18N - ("When using high resolutions where the horizontal resolution is smaller " - "than the vertical resolution this disables horizontal interpolation."); - s->opt[OPT_DISABLE_INTERPOLATION].type = SANE_TYPE_BOOL; - s->opt[OPT_DISABLE_INTERPOLATION].unit = SANE_UNIT_NONE; - s->opt[OPT_DISABLE_INTERPOLATION].constraint_type = SANE_CONSTRAINT_NONE; - s->disable_interpolation = false; - - /* color filter */ - s->opt[OPT_COLOR_FILTER].name = "color-filter"; - s->opt[OPT_COLOR_FILTER].title = SANE_I18N ("Color filter"); - s->opt[OPT_COLOR_FILTER].desc = - SANE_I18N - ("When using gray or lineart this option selects the used color."); - s->opt[OPT_COLOR_FILTER].type = SANE_TYPE_STRING; - s->opt[OPT_COLOR_FILTER].constraint_type = SANE_CONSTRAINT_STRING_LIST; - /* true gray not yet supported for GL847 and GL124 scanners */ - if(!model->is_cis || model->asic_type==GENESYS_GL847 || model->asic_type==GENESYS_GL124) - { - s->opt[OPT_COLOR_FILTER].size = max_string_size (color_filter_list); - s->opt[OPT_COLOR_FILTER].constraint.string_list = color_filter_list; - s->color_filter = s->opt[OPT_COLOR_FILTER].constraint.string_list[1]; - } - else - { - s->opt[OPT_COLOR_FILTER].size = max_string_size (cis_color_filter_list); - s->opt[OPT_COLOR_FILTER].constraint.string_list = cis_color_filter_list; - /* default to "None" ie true gray */ - s->color_filter = s->opt[OPT_COLOR_FILTER].constraint.string_list[3]; - } - - /* no support for color filter for cis+gl646 scanners */ - if (model->asic_type == GENESYS_GL646 && model->is_cis) - { - DISABLE (OPT_COLOR_FILTER); - } - - /* calibration store file name */ - s->opt[OPT_CALIBRATION_FILE].name = "calibration-file"; - s->opt[OPT_CALIBRATION_FILE].title = SANE_I18N ("Calibration file"); - s->opt[OPT_CALIBRATION_FILE].desc = SANE_I18N ("Specify the calibration file to use"); - s->opt[OPT_CALIBRATION_FILE].type = SANE_TYPE_STRING; - s->opt[OPT_CALIBRATION_FILE].unit = SANE_UNIT_NONE; - s->opt[OPT_CALIBRATION_FILE].size = PATH_MAX; - s->opt[OPT_CALIBRATION_FILE].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; - s->opt[OPT_CALIBRATION_FILE].constraint_type = SANE_CONSTRAINT_NONE; - s->calibration_file.clear(); - /* disable option if ran as root */ -#ifdef HAVE_GETUID - if(geteuid()==0) - { - DISABLE (OPT_CALIBRATION_FILE); - } -#endif - - /* expiration time for calibration cache entries */ - s->opt[OPT_EXPIRATION_TIME].name = "expiration-time"; - s->opt[OPT_EXPIRATION_TIME].title = SANE_I18N ("Calibration cache expiration time"); - s->opt[OPT_EXPIRATION_TIME].desc = SANE_I18N ("Time (in minutes) before a cached calibration expires. " - "A value of 0 means cache is not used. A negative value means cache never expires."); - s->opt[OPT_EXPIRATION_TIME].type = SANE_TYPE_INT; - s->opt[OPT_EXPIRATION_TIME].unit = SANE_UNIT_NONE; - s->opt[OPT_EXPIRATION_TIME].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_EXPIRATION_TIME].constraint.range = &expiration_range; - s->expiration_time = 60; // 60 minutes by default - - /* Powersave time (turn lamp off) */ - s->opt[OPT_LAMP_OFF_TIME].name = "lamp-off-time"; - s->opt[OPT_LAMP_OFF_TIME].title = SANE_I18N ("Lamp off time"); - s->opt[OPT_LAMP_OFF_TIME].desc = - SANE_I18N - ("The lamp will be turned off after the given time (in minutes). " - "A value of 0 means, that the lamp won't be turned off."); - s->opt[OPT_LAMP_OFF_TIME].type = SANE_TYPE_INT; - s->opt[OPT_LAMP_OFF_TIME].unit = SANE_UNIT_NONE; - s->opt[OPT_LAMP_OFF_TIME].constraint_type = SANE_CONSTRAINT_RANGE; - s->opt[OPT_LAMP_OFF_TIME].constraint.range = &time_range; - s->lamp_off_time = 15; // 15 minutes - - /* turn lamp off during scan */ - s->opt[OPT_LAMP_OFF].name = "lamp-off-scan"; - s->opt[OPT_LAMP_OFF].title = SANE_I18N ("Lamp off during scan"); - s->opt[OPT_LAMP_OFF].desc = SANE_I18N ("The lamp will be turned off during scan. "); - s->opt[OPT_LAMP_OFF].type = SANE_TYPE_BOOL; - s->opt[OPT_LAMP_OFF].unit = SANE_UNIT_NONE; - s->opt[OPT_LAMP_OFF].constraint_type = SANE_CONSTRAINT_NONE; - s->lamp_off = false; - - s->opt[OPT_SENSOR_GROUP].title = SANE_TITLE_SENSORS; - s->opt[OPT_SENSOR_GROUP].desc = SANE_DESC_SENSORS; - s->opt[OPT_SENSOR_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_SENSOR_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_SENSOR_GROUP].size = 0; - s->opt[OPT_SENSOR_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - s->opt[OPT_SCAN_SW].name = SANE_NAME_SCAN; - s->opt[OPT_SCAN_SW].title = SANE_TITLE_SCAN; - s->opt[OPT_SCAN_SW].desc = SANE_DESC_SCAN; - s->opt[OPT_SCAN_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_SCAN_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_SCAN_SW) - s->opt[OPT_SCAN_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_SCAN_SW].cap = SANE_CAP_INACTIVE; - - /* SANE_NAME_FILE is not for buttons */ - s->opt[OPT_FILE_SW].name = "file"; - s->opt[OPT_FILE_SW].title = SANE_I18N ("File button"); - s->opt[OPT_FILE_SW].desc = SANE_I18N ("File button"); - s->opt[OPT_FILE_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_FILE_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_FILE_SW) - s->opt[OPT_FILE_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_FILE_SW].cap = SANE_CAP_INACTIVE; - - s->opt[OPT_EMAIL_SW].name = SANE_NAME_EMAIL; - s->opt[OPT_EMAIL_SW].title = SANE_TITLE_EMAIL; - s->opt[OPT_EMAIL_SW].desc = SANE_DESC_EMAIL; - s->opt[OPT_EMAIL_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_EMAIL_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_EMAIL_SW) - s->opt[OPT_EMAIL_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_EMAIL_SW].cap = SANE_CAP_INACTIVE; - - s->opt[OPT_COPY_SW].name = SANE_NAME_COPY; - s->opt[OPT_COPY_SW].title = SANE_TITLE_COPY; - s->opt[OPT_COPY_SW].desc = SANE_DESC_COPY; - s->opt[OPT_COPY_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_COPY_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_COPY_SW) - s->opt[OPT_COPY_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_COPY_SW].cap = SANE_CAP_INACTIVE; - - s->opt[OPT_PAGE_LOADED_SW].name = SANE_NAME_PAGE_LOADED; - s->opt[OPT_PAGE_LOADED_SW].title = SANE_TITLE_PAGE_LOADED; - s->opt[OPT_PAGE_LOADED_SW].desc = SANE_DESC_PAGE_LOADED; - s->opt[OPT_PAGE_LOADED_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_PAGE_LOADED_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_PAGE_LOADED_SW) - s->opt[OPT_PAGE_LOADED_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_PAGE_LOADED_SW].cap = SANE_CAP_INACTIVE; - - /* OCR button */ - s->opt[OPT_OCR_SW].name = "ocr"; - s->opt[OPT_OCR_SW].title = SANE_I18N ("OCR button"); - s->opt[OPT_OCR_SW].desc = SANE_I18N ("OCR button"); - s->opt[OPT_OCR_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_OCR_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_OCR_SW) - s->opt[OPT_OCR_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_OCR_SW].cap = SANE_CAP_INACTIVE; - - /* power button */ - s->opt[OPT_POWER_SW].name = "power"; - s->opt[OPT_POWER_SW].title = SANE_I18N ("Power button"); - s->opt[OPT_POWER_SW].desc = SANE_I18N ("Power button"); - s->opt[OPT_POWER_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_POWER_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_POWER_SW) - s->opt[OPT_POWER_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_POWER_SW].cap = SANE_CAP_INACTIVE; - - /* extra button */ - s->opt[OPT_EXTRA_SW].name = "extra"; - s->opt[OPT_EXTRA_SW].title = SANE_I18N ("Extra button"); - s->opt[OPT_EXTRA_SW].desc = SANE_I18N ("Extra button"); - s->opt[OPT_EXTRA_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_EXTRA_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_EXTRA_SW) - s->opt[OPT_EXTRA_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_EXTRA_SW].cap = SANE_CAP_INACTIVE; - - /* calibration needed */ - s->opt[OPT_NEED_CALIBRATION_SW].name = "need-calibration"; - s->opt[OPT_NEED_CALIBRATION_SW].title = SANE_I18N ("Need calibration"); - s->opt[OPT_NEED_CALIBRATION_SW].desc = SANE_I18N ("The scanner needs calibration for the current settings"); - s->opt[OPT_NEED_CALIBRATION_SW].type = SANE_TYPE_BOOL; - s->opt[OPT_NEED_CALIBRATION_SW].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_CALIBRATE) - s->opt[OPT_NEED_CALIBRATION_SW].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; - else - s->opt[OPT_NEED_CALIBRATION_SW].cap = SANE_CAP_INACTIVE; - - /* button group */ - s->opt[OPT_BUTTON_GROUP].title = SANE_I18N ("Buttons"); - s->opt[OPT_BUTTON_GROUP].desc = ""; - s->opt[OPT_BUTTON_GROUP].type = SANE_TYPE_GROUP; - s->opt[OPT_BUTTON_GROUP].cap = SANE_CAP_ADVANCED; - s->opt[OPT_BUTTON_GROUP].size = 0; - s->opt[OPT_BUTTON_GROUP].constraint_type = SANE_CONSTRAINT_NONE; - - /* calibrate button */ - s->opt[OPT_CALIBRATE].name = "calibrate"; - s->opt[OPT_CALIBRATE].title = SANE_I18N ("Calibrate"); - s->opt[OPT_CALIBRATE].desc = - SANE_I18N ("Start calibration using special sheet"); - s->opt[OPT_CALIBRATE].type = SANE_TYPE_BUTTON; - s->opt[OPT_CALIBRATE].unit = SANE_UNIT_NONE; - if (model->buttons & GENESYS_HAS_CALIBRATE) - s->opt[OPT_CALIBRATE].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED | - SANE_CAP_AUTOMATIC; - else - s->opt[OPT_CALIBRATE].cap = SANE_CAP_INACTIVE; - - /* clear calibration cache button */ - s->opt[OPT_CLEAR_CALIBRATION].name = "clear-calibration"; - s->opt[OPT_CLEAR_CALIBRATION].title = SANE_I18N ("Clear calibration"); - s->opt[OPT_CLEAR_CALIBRATION].desc = SANE_I18N ("Clear calibration cache"); - s->opt[OPT_CLEAR_CALIBRATION].type = SANE_TYPE_BUTTON; - s->opt[OPT_CLEAR_CALIBRATION].unit = SANE_UNIT_NONE; - s->opt[OPT_CLEAR_CALIBRATION].size = 0; - s->opt[OPT_CLEAR_CALIBRATION].constraint_type = SANE_CONSTRAINT_NONE; - s->opt[OPT_CLEAR_CALIBRATION].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; - - /* force calibration cache button */ - s->opt[OPT_FORCE_CALIBRATION].name = "force-calibration"; - s->opt[OPT_FORCE_CALIBRATION].title = SANE_I18N("Force calibration"); - s->opt[OPT_FORCE_CALIBRATION].desc = SANE_I18N("Force calibration ignoring all and any calibration caches"); - s->opt[OPT_FORCE_CALIBRATION].type = SANE_TYPE_BUTTON; - s->opt[OPT_FORCE_CALIBRATION].unit = SANE_UNIT_NONE; - s->opt[OPT_FORCE_CALIBRATION].size = 0; - s->opt[OPT_FORCE_CALIBRATION].constraint_type = SANE_CONSTRAINT_NONE; - s->opt[OPT_FORCE_CALIBRATION].cap = - SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; - - RIE (calc_parameters (s)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Bool present; - -// this function is passed to C API, it must not throw -static SANE_Status -check_present (SANE_String_Const devname) noexcept -{ - present=SANE_TRUE; - DBG(DBG_io, "%s: %s detected.\n", __func__, devname); - return SANE_STATUS_GOOD; -} - -static SANE_Status -attach (SANE_String_Const devname, Genesys_Device ** devp, SANE_Bool may_wait) -{ - DBG_HELPER(dbg); - - Genesys_Device *dev = 0; - unsigned int i; - - - DBG(DBG_proc, "%s: start: devp %s NULL, may_wait = %d\n", __func__, devp ? "!=" : "==", may_wait); - - if (devp) - *devp = 0; - - if (!devname) - { - DBG(DBG_error, "%s: devname == NULL\n", __func__); - return SANE_STATUS_INVAL; - } - - for (auto& dev : *s_devices) { - if (strcmp(dev.file_name, devname) == 0) { - if (devp) - *devp = &dev; - DBG(DBG_info, "%s: device `%s' was already in device list\n", __func__, devname); - return SANE_STATUS_GOOD; - } - } - - DBG(DBG_info, "%s: trying to open device `%s'\n", __func__, devname); - - UsbDevice usb_dev; - - usb_dev.open(devname); - DBG(DBG_info, "%s: device `%s' successfully opened\n", __func__, devname); - - int vendor, product; - usb_dev.get_vendor_product(vendor, product); - - /* KV-SS080 is an auxiliary device which requires a master device to be here */ - if(vendor == 0x04da && product == 0x100f) - { - present=SANE_FALSE; - sanei_usb_find_devices (vendor, 0x1006, check_present); - sanei_usb_find_devices (vendor, 0x1007, check_present); - sanei_usb_find_devices (vendor, 0x1010, check_present); - if (present == SANE_FALSE) { - throw SaneException("master device not present"); - } - } - - bool found_dev = false; - for (i = 0; i < MAX_SCANNERS && genesys_usb_device_list[i].model != 0; i++) - { - if (vendor == genesys_usb_device_list[i].vendor && - product == genesys_usb_device_list[i].product) - { - found_dev = true; - break; - } - } - - if (!found_dev) { - DBG(DBG_error, "%s: vendor 0x%xd product 0x%xd is not supported by this backend\n", __func__, - vendor, product); - return SANE_STATUS_INVAL; - } - - char* new_devname = strdup (devname); - if (!new_devname) { - return SANE_STATUS_NO_MEM; - } - - s_devices->emplace_back(); - dev = &s_devices->back(); - dev->file_name = new_devname; - - dev->model = genesys_usb_device_list[i].model; - dev->vendorId = genesys_usb_device_list[i].vendor; - dev->productId = genesys_usb_device_list[i].product; - dev->usb_mode = 0; /* i.e. unset */ - dev->already_initialized = SANE_FALSE; - - DBG(DBG_info, "%s: found %s flatbed scanner %s at %s\n", __func__, dev->model->vendor, - dev->model->model, dev->file_name); - - if (devp) { - *devp = dev; - } - - usb_dev.close(); - return SANE_STATUS_GOOD; -} - -static SANE_Status -attach_one_device_impl(SANE_String_Const devname) -{ - Genesys_Device *dev; - SANE_Status status = SANE_STATUS_GOOD; - - RIE (attach (devname, &dev, SANE_FALSE)); - - return SANE_STATUS_GOOD; -} - -static SANE_Status attach_one_device(SANE_String_Const devname) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return attach_one_device_impl(devname); - }); -} - -/* configuration framework functions */ - -// this function is passed to C API, it must not throw -static SANE_Status -config_attach_genesys(SANEI_Config __sane_unused__ *config, const char *devname) noexcept -{ - /* the devname has been processed and is ready to be used - * directly. Since the backend is an USB only one, we can - * call sanei_usb_attach_matching_devices straight */ - sanei_usb_attach_matching_devices (devname, attach_one_device); - - return SANE_STATUS_GOOD; -} - -/* probes for scanner to attach to the backend */ -static SANE_Status -probe_genesys_devices (void) -{ - SANEI_Config config; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - /* set configuration options structure : no option for this backend */ - config.descriptors = NULL; - config.values = NULL; - config.count = 0; - - /* generic configure and attach function */ - status = sanei_configure_attach (GENESYS_CONFIG_FILE, &config, - config_attach_genesys); - - DBG(DBG_info, "%s: %d devices currently attached\n", __func__, (int) s_devices->size()); - - DBGCOMPLETED; - - return status; -} - -/** - * This should be changed if one of the substructures of - Genesys_Calibration_Cache change, but it must be changed if there are - changes that don't change size -- at least for now, as we store most - of Genesys_Calibration_Cache as is. -*/ -static const char* CALIBRATION_IDENT = "sane_genesys"; -static const int CALIBRATION_VERSION = 2; - -bool read_calibration(std::istream& str, Genesys_Device::Calibration& calibration, - const std::string& path) -{ - std::string ident; - serialize(str, ident); - - if (ident != CALIBRATION_IDENT) { - DBG(DBG_info, "%s: Incorrect calibration file '%s' header\n", __func__, path.c_str()); - return false; - } - - size_t version; - serialize(str, version); - - if (version != CALIBRATION_VERSION) { - DBG(DBG_info, "%s: Incorrect calibration file '%s' version\n", __func__, path.c_str()); - return false; - } - - calibration.clear(); - serialize(str, calibration); - return true; -} - -/** - * reads previously cached calibration data - * from file defined in dev->calib_file - */ -static bool sanei_genesys_read_calibration(Genesys_Device::Calibration& calibration, - const std::string& path) -{ - DBG_HELPER(dbg); - - std::ifstream str; - str.open(path); - if (!str.is_open()) { - DBG(DBG_info, "%s: Cannot open %s\n", __func__, path.c_str()); - return false; - } - - return read_calibration(str, calibration, path); -} - -void write_calibration(std::ostream& str, Genesys_Device::Calibration& calibration) -{ - std::string ident = CALIBRATION_IDENT; - serialize(str, ident); - size_t version = CALIBRATION_VERSION; - serialize(str, version); - serialize_newline(str); - serialize(str, calibration); -} - -static void write_calibration(Genesys_Device::Calibration& calibration, const std::string& path) -{ - DBG_HELPER(dbg); - - std::ofstream str; - str.open(path); - if (!str.is_open()) { - throw SaneException("Cannot open calibration for writing"); - } - write_calibration(str, calibration); -} - -/** @brief buffer scanned picture - * In order to allow digital processing, we must be able to put all the - * scanned picture in a buffer. - */ -static SANE_Status -genesys_buffer_image(Genesys_Scanner *s) -{ - SANE_Status status = SANE_STATUS_GOOD; - size_t maximum; /**> maximum bytes size of the scan */ - size_t len; /**> length of scanned data read */ - size_t total; /**> total of butes read */ - size_t size; /**> size of image buffer */ - size_t read_size; /**> size of reads */ - int lines; /** number of lines of the scan */ - Genesys_Device *dev = s->dev; - - /* compute maximum number of lines for the scan */ - if (s->params.lines > 0) - { - lines = s->params.lines; - } - else - { - lines = - (SANE_UNFIX (dev->model->y_size) * dev->settings.yres) / MM_PER_INCH; - } - DBG(DBG_info, "%s: buffering %d lines of %d bytes\n", __func__, lines, - s->params.bytes_per_line); - - /* maximum bytes to read */ - maximum = s->params.bytes_per_line * lines; - if(s->dev->settings.dynamic_lineart==SANE_TRUE) - { - maximum *= 8; - } - - /* initial size of the read buffer */ - size = - ((2048 * 2048) / s->params.bytes_per_line) * s->params.bytes_per_line; - - /* read size */ - read_size = size / 2; - - dev->img_buffer.resize(size); - - /* loop reading data until we reach maximum or EOF */ - total = 0; - while (total < maximum && status != SANE_STATUS_EOF) - { - len = size - maximum; - if (len > read_size) - { - len = read_size; - } - - status = genesys_read_ordered_data(dev, dev->img_buffer.data() + total, &len); - if (status != SANE_STATUS_EOF && status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: %s buffering failed\n", __func__, sane_strstatus(status)); - return status; - } - total += len; - - /* do we need to enlarge read buffer ? */ - if (total + read_size > size && status != SANE_STATUS_EOF) - { - size += read_size; - dev->img_buffer.resize(size); - } - } - - /* since digital processing is going to take place, - * issue head parking command so that the head move while - * computing so we can save time - */ - if (dev->model->is_sheetfed == SANE_FALSE && - dev->parking == SANE_FALSE) - { - dev->model->cmd_set->slow_back_home (dev, dev->model->flags & GENESYS_FLAG_MUST_WAIT); - dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); - } - - /* in case of dynamic lineart, we have buffered gray data which - * must be converted to lineart first */ - if(s->dev->settings.dynamic_lineart==SANE_TRUE) - { - total/=8; - std::vector lineart(total); - - genesys_gray_lineart (dev, - dev->img_buffer.data(), - lineart.data(), - dev->settings.pixels, - (total*8)/dev->settings.pixels, - dev->settings.threshold); - dev->img_buffer = lineart; - } - - /* update counters */ - dev->total_bytes_to_read = total; - dev->total_bytes_read = 0; - - /* update params */ - s->params.lines = total / s->params.bytes_per_line; - if (DBG_LEVEL >= DBG_io2) - { - sanei_genesys_write_pnm_file("gl_unprocessed.pnm", dev->img_buffer.data(), s->params.depth, - s->params.format==SANE_FRAME_RGB ? 3 : 1, - s->params.pixels_per_line, s->params.lines); - } - - return SANE_STATUS_GOOD; -} - -/* -------------------------- SANE API functions ------------------------- */ - -SANE_Status -sane_init_impl(SANE_Int * version_code, SANE_Auth_Callback authorize) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG_INIT (); - DBG(DBG_init, "SANE Genesys backend version %d.%d from %s\n", - SANE_CURRENT_MAJOR, V_MINOR, PACKAGE_STRING); -#ifdef HAVE_LIBUSB - DBG(DBG_init, "SANE Genesys backend built with libusb-1.0\n"); -#endif -#ifdef HAVE_LIBUSB_LEGACY - DBG(DBG_init, "SANE Genesys backend built with libusb\n"); -#endif - - if (version_code) - *version_code = SANE_VERSION_CODE (SANE_CURRENT_MAJOR, V_MINOR, 0); - - DBG(DBG_proc, "%s: authorize %s null\n", __func__, authorize ? "!=" : "=="); - - /* init usb use */ - sanei_usb_init (); - - /* init sanei_magic */ - sanei_magic_init(); - - s_scanners.init(); - s_devices.init(); - s_sane_devices.init(); - s_sane_devices_ptrs.init(); - genesys_init_sensor_tables(); - genesys_init_frontend_tables(); - - DBG(DBG_info, "%s: %s endian machine\n", __func__, -#ifdef WORDS_BIGENDIAN - "big" -#else - "little" -#endif - ); - - /* cold-plug case :detection of allready connected scanners */ - status = probe_genesys_devices (); - - DBGCOMPLETED; - - return status; -} - - -extern "C" SANE_Status sane_init(SANE_Int * version_code, SANE_Auth_Callback authorize) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_init_impl(version_code, authorize); - }); -} - -void -sane_exit_impl(void) -{ - DBGSTART; - - sanei_usb_exit(); - - run_functions_at_backend_exit(); - - DBGCOMPLETED; -} - -void sane_exit() -{ - catch_all_exceptions(__func__, [](){ sane_exit_impl(); }); -} - -SANE_Status -sane_get_devices_impl(const SANE_Device *** device_list, SANE_Bool local_only) -{ - DBG(DBG_proc, "%s: start: local_only = %s\n", __func__, - local_only == SANE_TRUE ? "true" : "false"); - - /* hot-plug case : detection of newly connected scanners */ - sanei_usb_scan_devices (); - probe_genesys_devices (); - - s_sane_devices->clear(); - s_sane_devices_ptrs->clear(); - s_sane_devices->reserve(s_devices->size()); - s_sane_devices_ptrs->reserve(s_devices->size() + 1); - - for (auto dev_it = s_devices->begin(); dev_it != s_devices->end();) { - present = SANE_FALSE; - sanei_usb_find_devices(dev_it->vendorId, dev_it->productId, check_present); - if (present) { - s_sane_devices->emplace_back(); - auto& sane_device = s_sane_devices->back(); - sane_device.name = dev_it->file_name; - sane_device.vendor = dev_it->model->vendor; - sane_device.model = dev_it->model->model; - sane_device.type = "flatbed scanner"; - s_sane_devices_ptrs->push_back(&sane_device); - dev_it++; - } else { - dev_it = s_devices->erase(dev_it); - } - } - s_sane_devices_ptrs->push_back(nullptr); - - *((SANE_Device ***)device_list) = s_sane_devices_ptrs->data(); - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -SANE_Status sane_get_devices(const SANE_Device *** device_list, SANE_Bool local_only) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_get_devices_impl(device_list, local_only); - }); -} - -SANE_Status -sane_open_impl(SANE_String_Const devicename, SANE_Handle * handle) -{ - DBG_HELPER(dbg); - Genesys_Device *dev = nullptr; - SANE_Status status = SANE_STATUS_GOOD; - char *tmpstr; - - DBG(DBG_proc, "%s: devicename = `%s')\n", __func__, devicename); - - /* devicename="" or devicename="genesys" are default values that use - * first available device - */ - if (devicename[0] && strcmp ("genesys", devicename) != 0) - { - /* search for the given devicename in the device list */ - for (auto& d : *s_devices) { - if (strcmp(d.file_name, devicename) == 0) { - dev = &d; - break; - } - } - - if (!dev) - { - DBG(DBG_info, "%s: couldn't find `%s' in devlist, trying attach\n", __func__, devicename); - RIE (attach (devicename, &dev, SANE_TRUE)); - } - else - DBG(DBG_info, "%s: found `%s' in devlist\n", __func__, dev->model->name); - } - else - { - // empty devicename or "genesys" -> use first device - if (!s_devices->empty()) { - dev = &s_devices->front(); - devicename = dev->file_name; - DBG(DBG_info, "%s: empty devicename, trying `%s'\n", __func__, devicename); - } - } - - if (!dev) - return SANE_STATUS_INVAL; - - if (dev->model->flags & GENESYS_FLAG_UNTESTED) - { - DBG(DBG_error0, "WARNING: Your scanner is not fully supported or at least \n"); - DBG(DBG_error0, " had only limited testing. Please be careful and \n"); - DBG(DBG_error0, " report any failure/success to \n"); - DBG(DBG_error0, " sane-devel@alioth-lists.debian.net. Please provide as many\n"); - DBG(DBG_error0, " details as possible, e.g. the exact name of your\n"); - DBG(DBG_error0, " scanner and what does (not) work.\n"); - } - - dbg.vstatus("open device '%s'", dev->file_name); - dev->usb_dev.open(dev->file_name); - dbg.clear(); - - - s_scanners->push_back(Genesys_Scanner()); - auto* s = &s_scanners->back(); - - s->dev = dev; - s->scanning = SANE_FALSE; - s->dev->parking = SANE_FALSE; - s->dev->read_active = SANE_FALSE; - s->dev->force_calibration = 0; - s->dev->line_interp = 0; - s->dev->line_count = 0; - s->dev->segnb = 0; - s->dev->binary=NULL; - - *handle = s; - - if (!dev->already_initialized) - sanei_genesys_init_structs (dev); - - RIE (init_options (s)); - - if (sanei_genesys_init_cmd_set (s->dev) != SANE_STATUS_GOOD) - { - DBG(DBG_error0, "This device doesn't have a valid command set!!\n"); - return SANE_STATUS_IO_ERROR; - } - - // FIXME: we create sensor tables for the sensor, this should happen when we know which sensor - // we will select - RIE (dev->model->cmd_set->init(dev)); - - /* some hardware capabilities are detected through sensors */ - RIE (s->dev->model->cmd_set->update_hardware_sensors (s)); - - /* here is the place to fetch a stored calibration cache */ - if (s->dev->force_calibration == 0) - { - tmpstr=calibration_filename(s->dev); - s->calibration_file = tmpstr; - s->dev->calib_file = tmpstr; - DBG(DBG_info, "%s: Calibration filename set to:\n", __func__); - DBG(DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file.c_str()); - free(tmpstr); - - catch_all_exceptions(__func__, [&]() - { - sanei_genesys_read_calibration(s->dev->calibration_cache, s->dev->calib_file); - }); - } - - return SANE_STATUS_GOOD; -} - -SANE_Status sane_open(SANE_String_Const devicename, SANE_Handle* handle) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_open_impl(devicename, handle); - }); -} - -void -sane_close_impl(SANE_Handle handle) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - /* remove handle from list of open handles: */ - auto it = s_scanners->end(); - for (auto it2 = s_scanners->begin(); it2 != s_scanners->end(); it2++) - { - if (&*it2 == handle) { - it = it2; - break; - } - } - if (it == s_scanners->end()) - { - DBG(DBG_error, "%s: invalid handle %p\n", __func__, handle); - return; /* oops, not a handle we know about */ - } - - Genesys_Scanner* s = &*it; - - /* eject document for sheetfed scanners */ - if (s->dev->model->is_sheetfed == SANE_TRUE) - { - s->dev->model->cmd_set->eject_document (s->dev); - } - else - { - /* in case scanner is parking, wait for the head - * to reach home position */ - if(s->dev->parking==SANE_TRUE) - { - status = sanei_genesys_wait_for_home (s->dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to wait for head to park: %s\n", __func__, - sane_strstatus(status)); - } - } - } - - /* enable power saving before leaving */ - status = s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to enable power saving mode: %s\n", __func__, - sane_strstatus(status)); - } - - // here is the place to store calibration cache - if (s->dev->force_calibration == 0) { - catch_all_exceptions(__func__, [&](){ write_calibration(s->dev->calibration_cache, - s->dev->calib_file); }); - } - - s->dev->already_initialized = SANE_FALSE; - - /* for an handful of bytes .. */ - free ((void *)(size_t)s->opt[OPT_RESOLUTION].constraint.word_list); - free ((void *)(size_t)s->opt[OPT_TL_X].constraint.range); - free ((void *)(size_t)s->opt[OPT_TL_Y].constraint.range); - - s->dev->clear(); - - /* LAMP OFF : same register across all the ASICs */ - sanei_genesys_write_register (s->dev, 0x03, 0x00); - - catch_all_exceptions(__func__, [&](){ s->dev->usb_dev.clear_halt(); }); - - // we need this to avoid these ASIC getting stuck in bulk writes - catch_all_exceptions(__func__, [&](){ s->dev->usb_dev.reset(); }); - - // not freeing s->dev because it's in the dev list - catch_all_exceptions(__func__, [&](){ s->dev->usb_dev.close(); }); - - s_scanners->erase(it); - - DBGCOMPLETED; -} - -void sane_close(SANE_Handle handle) -{ - catch_all_exceptions(__func__, [=]() - { - sane_close_impl(handle); - }); -} - -const SANE_Option_Descriptor * -sane_get_option_descriptor_impl(SANE_Handle handle, SANE_Int option) -{ - Genesys_Scanner *s = (Genesys_Scanner*) handle; - - if ((unsigned) option >= NUM_OPTIONS) - return 0; - DBG(DBG_io2, "%s: option = %s (%d)\n", __func__, s->opt[option].name, option); - return s->opt + option; -} - - -const SANE_Option_Descriptor * -sane_get_option_descriptor(SANE_Handle handle, SANE_Int option) -{ - const SANE_Option_Descriptor* ret = NULL; - catch_all_exceptions(__func__, [&]() - { - ret = sane_get_option_descriptor_impl(handle, option); - }); - return ret; -} - -/* gets an option , called by sane_control_option */ -static SANE_Status -get_option_value (Genesys_Scanner * s, int option, void *val) -{ - unsigned int i; - SANE_Word* table = nullptr; - std::vector gamma_table; - unsigned option_size = 0; - SANE_Status status = SANE_STATUS_GOOD; - - // FIXME: we should pick correct sensor here - const Genesys_Sensor& sensor = sanei_genesys_find_sensor_any(s->dev); - - switch (option) - { - /* geometry */ - case OPT_TL_X: - *reinterpret_cast(val) = s->pos_top_left_x; - break; - case OPT_TL_Y: - *reinterpret_cast(val) = s->pos_top_left_y; - break; - case OPT_BR_X: - *reinterpret_cast(val) = s->pos_bottom_right_x; - break; - case OPT_BR_Y: - *reinterpret_cast(val) = s->pos_bottom_right_y; - break; - /* word options: */ - case OPT_NUM_OPTS: - *reinterpret_cast(val) = NUM_OPTIONS; - break; - case OPT_RESOLUTION: - *reinterpret_cast(val) = s->resolution; - break; - case OPT_BIT_DEPTH: - *reinterpret_cast(val) = s->bit_depth; - break; - case OPT_PREVIEW: - *reinterpret_cast(val) = s->preview; - break; - case OPT_THRESHOLD: - *reinterpret_cast(val) = s->threshold; - break; - case OPT_THRESHOLD_CURVE: - *reinterpret_cast(val) = s->threshold_curve; - break; - case OPT_DISABLE_DYNAMIC_LINEART: - *reinterpret_cast(val) = s->disable_dynamic_lineart; - break; - case OPT_DISABLE_INTERPOLATION: - *reinterpret_cast(val) = s->disable_interpolation; - break; - case OPT_LAMP_OFF: - *reinterpret_cast(val) = s->lamp_off; - break; - case OPT_LAMP_OFF_TIME: - *reinterpret_cast(val) = s->lamp_off_time; - break; - case OPT_SWDESKEW: - *reinterpret_cast(val) = s->swdeskew; - break; - case OPT_SWCROP: - *reinterpret_cast(val) = s->swcrop; - break; - case OPT_SWDESPECK: - *reinterpret_cast(val) = s->swdespeck; - break; - case OPT_SWDEROTATE: - *reinterpret_cast(val) = s->swderotate; - break; - case OPT_SWSKIP: - *reinterpret_cast(val) = s->swskip; - break; - case OPT_DESPECK: - *reinterpret_cast(val) = s->despeck; - break; - case OPT_CONTRAST: - *reinterpret_cast(val) = s->contrast; - break; - case OPT_BRIGHTNESS: - *reinterpret_cast(val) = s->brightness; - break; - case OPT_EXPIRATION_TIME: - *reinterpret_cast(val) = s->expiration_time; - break; - case OPT_CUSTOM_GAMMA: - *reinterpret_cast(val) = s->custom_gamma; - break; - - /* string options: */ - case OPT_MODE: - std::strcpy(reinterpret_cast(val), s->mode.c_str()); - break; - case OPT_COLOR_FILTER: - std::strcpy(reinterpret_cast(val), s->color_filter.c_str()); - break; - case OPT_CALIBRATION_FILE: - std::strcpy(reinterpret_cast(val), s->calibration_file.c_str()); - break; - case OPT_SOURCE: - std::strcpy(reinterpret_cast(val), s->source.c_str()); - break; - - /* word array options */ - case OPT_GAMMA_VECTOR: - table = (SANE_Word *) val; - if (s->color_filter == "Red") { - gamma_table = get_gamma_table(s->dev, sensor, GENESYS_RED); - } else if (s->color_filter == "Blue") { - gamma_table = get_gamma_table(s->dev, sensor, GENESYS_BLUE); - } else { - gamma_table = get_gamma_table(s->dev, sensor, GENESYS_GREEN); - } - option_size = s->opt[option].size / sizeof (SANE_Word); - if (gamma_table.size() != option_size) { - throw std::runtime_error("The size of the gamma tables does not match"); - } - for (i = 0; i < option_size; i++) { - table[i] = gamma_table[i]; - } - break; - case OPT_GAMMA_VECTOR_R: - table = (SANE_Word *) val; - gamma_table = get_gamma_table(s->dev, sensor, GENESYS_RED); - option_size = s->opt[option].size / sizeof (SANE_Word); - if (gamma_table.size() != option_size) { - throw std::runtime_error("The size of the gamma tables does not match"); - } - for (i = 0; i < option_size; i++) { - table[i] = gamma_table[i]; - } - break; - case OPT_GAMMA_VECTOR_G: - table = (SANE_Word *) val; - gamma_table = get_gamma_table(s->dev, sensor, GENESYS_GREEN); - option_size = s->opt[option].size / sizeof (SANE_Word); - if (gamma_table.size() != option_size) { - throw std::runtime_error("The size of the gamma tables does not match"); - } - for (i = 0; i < option_size; i++) { - table[i] = gamma_table[i]; - } - break; - case OPT_GAMMA_VECTOR_B: - table = (SANE_Word *) val; - gamma_table = get_gamma_table(s->dev, sensor, GENESYS_BLUE); - option_size = s->opt[option].size / sizeof (SANE_Word); - if (gamma_table.size() != option_size) { - throw std::runtime_error("The size of the gamma tables does not match"); - } - for (i = 0; i < option_size; i++) { - table[i] = gamma_table[i]; - } - break; - /* sensors */ - case OPT_SCAN_SW: - case OPT_FILE_SW: - case OPT_EMAIL_SW: - case OPT_COPY_SW: - case OPT_PAGE_LOADED_SW: - case OPT_OCR_SW: - case OPT_POWER_SW: - case OPT_EXTRA_SW: - RIE (s->dev->model->cmd_set->update_hardware_sensors (s)); - *(SANE_Bool *) val = s->buttons[genesys_option_to_button(option)].read(); - break; - case OPT_NEED_CALIBRATION_SW: - /* scanner needs calibration for current mode unless a matching - * calibration cache is found */ - *(SANE_Bool *) val = SANE_TRUE; - for (auto& cache : s->dev->calibration_cache) - { - if (s->dev->model->cmd_set->is_compatible_calibration(s->dev, sensor, &cache, SANE_FALSE)) - { - *(SANE_Bool *) val = SANE_FALSE; - } - } - break; - default: - DBG(DBG_warn, "%s: can't get unknown option %d\n", __func__, option); - } - return status; -} - -/** @brief set calibration file value - * Set calibration file value. Load new cache values from file if it exists, - * else creates the file*/ -static void set_calibration_value(Genesys_Scanner* s, const char* val) -{ - DBG_HELPER(dbg); - - std::string new_calib_path = val; - Genesys_Device::Calibration new_calibration; - - bool is_calib_success = false; - catch_all_exceptions(__func__, [&]() - { - is_calib_success = sanei_genesys_read_calibration(new_calibration, new_calib_path); - }); - - if (!is_calib_success) { - return; - } - - s->dev->calibration_cache = std::move(new_calibration); - s->dev->calib_file = new_calib_path; - s->calibration_file = new_calib_path; - DBG(DBG_info, "%s: Calibration filename set to '%s':\n", __func__, new_calib_path.c_str()); -} - -/* sets an option , called by sane_control_option */ -static SANE_Status -set_option_value (Genesys_Scanner * s, int option, void *val, - SANE_Int * myinfo) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Word *table; - unsigned int i; - SANE_Range *x_range, *y_range; - unsigned option_size = 0; - - // FIXME: we should modify device-specific sensor - auto& sensor = sanei_genesys_find_sensor_any_for_write(s->dev); - - switch (option) - { - case OPT_TL_X: - s->pos_top_left_x = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_TL_Y: - s->pos_top_left_y = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_BR_X: - s->pos_bottom_right_x = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_BR_Y: - s->pos_bottom_right_y = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_RESOLUTION: - s->resolution = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_THRESHOLD: - s->threshold = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_THRESHOLD_CURVE: - s->threshold_curve = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_DISABLE_DYNAMIC_LINEART: - s->disable_dynamic_lineart = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_SWCROP: - s->swcrop = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_SWDESKEW: - s->swdeskew = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_DESPECK: - s->despeck = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_SWDEROTATE: - s->swderotate = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_SWSKIP: - s->swskip = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_DISABLE_INTERPOLATION: - s->disable_interpolation = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_LAMP_OFF: - s->lamp_off = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_PREVIEW: - s->preview = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_BRIGHTNESS: - s->brightness = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_CONTRAST: - s->contrast = *reinterpret_cast(val); - RIE (calc_parameters(s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS; - break; - case OPT_SWDESPECK: - s->swdespeck = *reinterpret_cast(val); - if (s->swdespeck) { - ENABLE(OPT_DESPECK); - } else { - DISABLE(OPT_DESPECK); - } - RIE (calc_parameters (s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - /* software enhancement functions only apply to 8 or 1 bits data */ - case OPT_BIT_DEPTH: - s->bit_depth = *reinterpret_cast(val); - if(s->bit_depth>8) - { - DISABLE(OPT_SWDESKEW); - DISABLE(OPT_SWDESPECK); - DISABLE(OPT_SWCROP); - DISABLE(OPT_DESPECK); - DISABLE(OPT_SWDEROTATE); - DISABLE(OPT_SWSKIP); - DISABLE(OPT_CONTRAST); - DISABLE(OPT_BRIGHTNESS); - } - else - { - ENABLE(OPT_SWDESKEW); - ENABLE(OPT_SWDESPECK); - ENABLE(OPT_SWCROP); - ENABLE(OPT_DESPECK); - ENABLE(OPT_SWDEROTATE); - ENABLE(OPT_SWSKIP); - ENABLE(OPT_CONTRAST); - ENABLE(OPT_BRIGHTNESS); - } - RIE (calc_parameters (s)); - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - case OPT_SOURCE: - if (s->source != reinterpret_cast(val)) { - s->source = reinterpret_cast(val); - - // change geometry constraint to the new source value - if (s->source == STR_FLATBED) - { - x_range=create_range(s->dev->model->x_size); - y_range=create_range(s->dev->model->y_size); - } - else - { - x_range=create_range(s->dev->model->x_size_ta); - y_range=create_range(s->dev->model->y_size_ta); - } - if(x_range==NULL || y_range==NULL) - { - return SANE_STATUS_NO_MEM; - } - - /* assign new values */ - free((void *)(size_t)s->opt[OPT_TL_X].constraint.range); - free((void *)(size_t)s->opt[OPT_TL_Y].constraint.range); - s->opt[OPT_TL_X].constraint.range = x_range; - s->pos_top_left_x = 0; - s->opt[OPT_TL_Y].constraint.range = y_range; - s->pos_top_left_y = 0; - s->opt[OPT_BR_X].constraint.range = x_range; - s->pos_bottom_right_x = x_range->max; - s->opt[OPT_BR_Y].constraint.range = y_range; - s->pos_bottom_right_y = y_range->max; - - /* signals reload */ - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - } - break; - case OPT_MODE: - s->mode = reinterpret_cast(val); - - if (s->mode == SANE_VALUE_SCAN_MODE_LINEART) - { - ENABLE (OPT_THRESHOLD); - ENABLE (OPT_THRESHOLD_CURVE); - DISABLE (OPT_BIT_DEPTH); - if (s->dev->model->asic_type != GENESYS_GL646 || !s->dev->model->is_cis) - { - ENABLE (OPT_COLOR_FILTER); - } - ENABLE (OPT_DISABLE_DYNAMIC_LINEART); - } - else - { - DISABLE (OPT_THRESHOLD); - DISABLE (OPT_THRESHOLD_CURVE); - DISABLE (OPT_DISABLE_DYNAMIC_LINEART); - if (s->mode == SANE_VALUE_SCAN_MODE_GRAY) - { - if (s->dev->model->asic_type != GENESYS_GL646 || !s->dev->model->is_cis) - { - ENABLE (OPT_COLOR_FILTER); - } - create_bpp_list (s, s->dev->model->bpp_gray_values); - } - else - { - DISABLE (OPT_COLOR_FILTER); - create_bpp_list (s, s->dev->model->bpp_color_values); - } - if (s->bpp_list[0] < 2) - DISABLE (OPT_BIT_DEPTH); - else - ENABLE (OPT_BIT_DEPTH); - } - RIE (calc_parameters (s)); - - /* if custom gamma, toggle gamma table options according to the mode */ - if (s->custom_gamma) - { - if (s->mode == SANE_VALUE_SCAN_MODE_COLOR) - { - DISABLE (OPT_GAMMA_VECTOR); - ENABLE (OPT_GAMMA_VECTOR_R); - ENABLE (OPT_GAMMA_VECTOR_G); - ENABLE (OPT_GAMMA_VECTOR_B); - } - else - { - ENABLE (OPT_GAMMA_VECTOR); - DISABLE (OPT_GAMMA_VECTOR_R); - DISABLE (OPT_GAMMA_VECTOR_G); - DISABLE (OPT_GAMMA_VECTOR_B); - } - } - - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - case OPT_COLOR_FILTER: - s->color_filter = reinterpret_cast(val); - RIE (calc_parameters (s)); - break; - case OPT_CALIBRATION_FILE: - if (s->dev->force_calibration == 0) { - set_calibration_value(s, reinterpret_cast(val)); - } - break; - case OPT_LAMP_OFF_TIME: - if (*reinterpret_cast(val) != s->lamp_off_time) { - s->lamp_off_time = *reinterpret_cast(val); - RIE(s->dev->model->cmd_set->set_powersaving(s->dev, s->lamp_off_time)); - } - break; - case OPT_EXPIRATION_TIME: - if (*reinterpret_cast(val) != s->expiration_time) { - s->expiration_time = *reinterpret_cast(val); - // BUG: this is most likely not intended behavior, found out during refactor - RIE(s->dev->model->cmd_set->set_powersaving(s->dev, s->expiration_time)); - } - break; - - case OPT_CUSTOM_GAMMA: - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - s->custom_gamma = *reinterpret_cast(val); - - if (s->custom_gamma) { - if (s->mode == SANE_VALUE_SCAN_MODE_COLOR) - { - DISABLE (OPT_GAMMA_VECTOR); - ENABLE (OPT_GAMMA_VECTOR_R); - ENABLE (OPT_GAMMA_VECTOR_G); - ENABLE (OPT_GAMMA_VECTOR_B); - } - else - { - ENABLE (OPT_GAMMA_VECTOR); - DISABLE (OPT_GAMMA_VECTOR_R); - DISABLE (OPT_GAMMA_VECTOR_G); - DISABLE (OPT_GAMMA_VECTOR_B); - } - } - else - { - DISABLE (OPT_GAMMA_VECTOR); - DISABLE (OPT_GAMMA_VECTOR_R); - DISABLE (OPT_GAMMA_VECTOR_G); - DISABLE (OPT_GAMMA_VECTOR_B); - for (auto& table : s->dev->gamma_override_tables) { - table.clear(); - } - } - break; - - case OPT_GAMMA_VECTOR: - table = (SANE_Word *) val; - option_size = s->opt[option].size / sizeof (SANE_Word); - - s->dev->gamma_override_tables[GENESYS_RED].resize(option_size); - s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size); - s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size); - for (i = 0; i < option_size; i++) { - s->dev->gamma_override_tables[GENESYS_RED][i] = table[i]; - s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i]; - s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i]; - } - break; - case OPT_GAMMA_VECTOR_R: - table = (SANE_Word *) val; - option_size = s->opt[option].size / sizeof (SANE_Word); - s->dev->gamma_override_tables[GENESYS_RED].resize(option_size); - for (i = 0; i < option_size; i++) { - s->dev->gamma_override_tables[GENESYS_RED][i] = table[i]; - } - break; - case OPT_GAMMA_VECTOR_G: - table = (SANE_Word *) val; - option_size = s->opt[option].size / sizeof (SANE_Word); - s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size); - for (i = 0; i < option_size; i++) { - s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i]; - } - break; - case OPT_GAMMA_VECTOR_B: - table = (SANE_Word *) val; - option_size = s->opt[option].size / sizeof (SANE_Word); - s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size); - for (i = 0; i < option_size; i++) { - s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i]; - } - break; - case OPT_CALIBRATE: - status = s->dev->model->cmd_set->save_power (s->dev, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to disable power saving mode: %s\n", __func__, - sane_strstatus(status)); - } - else - status = genesys_scanner_calibration(s->dev, sensor); - /* not critical if this fails*/ - s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); - /* signals that sensors will have to be read again */ - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - case OPT_CLEAR_CALIBRATION: - s->dev->calibration_cache.clear(); - - /* remove file */ - unlink(s->dev->calib_file.c_str()); - /* signals that sensors will have to be read again */ - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - case OPT_FORCE_CALIBRATION: - s->dev->force_calibration = 1; - s->dev->calibration_cache.clear(); - s->dev->calib_file.clear(); - - /* signals that sensors will have to be read again */ - *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; - break; - - default: - DBG(DBG_warn, "%s: can't set unknown option %d\n", __func__, option); - } - return status; -} - - -/* sets and gets scanner option values */ -SANE_Status -sane_control_option_impl(SANE_Handle handle, SANE_Int option, - SANE_Action action, void *val, SANE_Int * info) -{ - Genesys_Scanner *s = (Genesys_Scanner*) handle; - SANE_Status status = SANE_STATUS_GOOD; - SANE_Word cap; - SANE_Int myinfo = 0; - - DBG(DBG_io2, "%s: start: action = %s, option = %s (%d)\n", __func__, - (action == SANE_ACTION_GET_VALUE) ? "get" : (action == SANE_ACTION_SET_VALUE) ? - "set" : (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown", - s->opt[option].name, option); - - if (info) - *info = 0; - - if (s->scanning) - { - DBG(DBG_warn, "%s: don't call this function while scanning (option = %s (%d))\n", __func__, - s->opt[option].name, option); - - return SANE_STATUS_DEVICE_BUSY; - } - if (option >= NUM_OPTIONS || option < 0) - { - DBG(DBG_warn, "%s: option %d >= NUM_OPTIONS || option < 0\n", __func__, option); - return SANE_STATUS_INVAL; - } - - cap = s->opt[option].cap; - - if (!SANE_OPTION_IS_ACTIVE (cap)) - { - DBG(DBG_warn, "%s: option %d is inactive\n", __func__, option); - return SANE_STATUS_INVAL; - } - - switch (action) - { - case SANE_ACTION_GET_VALUE: - status = get_option_value (s, option, val); - break; - - case SANE_ACTION_SET_VALUE: - if (!SANE_OPTION_IS_SETTABLE (cap)) - { - DBG(DBG_warn, "%s: option %d is not settable\n", __func__, option); - return SANE_STATUS_INVAL; - } - - status = sanei_constrain_value (s->opt + option, val, &myinfo); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_warn, "%s: sanei_constrain_value returned %s\n", __func__, - sane_strstatus(status)); - return status; - } - - status = set_option_value (s, option, val, &myinfo); - break; - - case SANE_ACTION_SET_AUTO: - DBG(DBG_error, - "%s: SANE_ACTION_SET_AUTO unsupported since no option has SANE_CAP_AUTOMATIC\n", - __func__); - status = SANE_STATUS_INVAL; - break; - - default: - DBG(DBG_warn, "%s: unknown action %d for option %d\n", __func__, action, option); - status = SANE_STATUS_INVAL; - break; - } - - if (info) - *info = myinfo; - - DBG(DBG_io2, "%s: exit\n", __func__); - return status; -} - -SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, - SANE_Action action, void *val, SANE_Int * info) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_control_option_impl(handle, option, action, val, info); - }); -} - -SANE_Status sane_get_parameters_impl(SANE_Handle handle, SANE_Parameters* params) -{ - Genesys_Scanner *s = (Genesys_Scanner*) handle; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - /* don't recompute parameters once data reading is active, ie during scan */ - if(s->dev->read_active == SANE_FALSE) - { - RIE (calc_parameters (s)); - } - if (params) - { - *params = s->params; - - /* in the case of a sheetfed scanner, when full height is specified - * we override the computed line number with -1 to signal that we - * don't know the real document height. - * We don't do that doing buffering image for digital processing - */ - if (s->dev->model->is_sheetfed == SANE_TRUE - && s->dev->buffer_image == SANE_FALSE - && s->pos_bottom_right_y == s->opt[OPT_BR_Y].constraint.range->max) - { - params->lines = -1; - } - } - - DBGCOMPLETED; - - return SANE_STATUS_GOOD; -} - -SANE_Status sane_get_parameters(SANE_Handle handle, SANE_Parameters* params) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_get_parameters_impl(handle, params); - }); -} - -SANE_Status sane_start_impl(SANE_Handle handle) -{ - Genesys_Scanner *s = (Genesys_Scanner*) handle; - SANE_Status status=SANE_STATUS_GOOD; - - DBGSTART; - - if (s->pos_top_left_x >= s->pos_bottom_right_x) - { - DBG(DBG_error0, "%s: top left x >= bottom right x --- exiting\n", __func__); - return SANE_STATUS_INVAL; - } - if (s->pos_top_left_y >= s->pos_bottom_right_y) - { - DBG(DBG_error0, "%s: top left y >= bottom right y --- exiting\n", __func__); - return SANE_STATUS_INVAL; - } - - /* First make sure we have a current parameter set. Some of the - parameters will be overwritten below, but that's OK. */ - - RIE (calc_parameters (s)); - RIE(genesys_start_scan(s->dev, s->lamp_off)); - - s->scanning = SANE_TRUE; - - /* allocate intermediate buffer when doing dynamic lineart */ - if(s->dev->settings.dynamic_lineart==SANE_TRUE) - { - s->dev->binarize_buffer.clear(); - s->dev->binarize_buffer.alloc(s->dev->settings.pixels); - s->dev->local_buffer.clear(); - s->dev->local_buffer.alloc(s->dev->binarize_buffer.size() * 8); - } - - /* if one of the software enhancement option is selected, - * we do the scan internally, process picture then put it an internal - * buffer. Since cropping may change scan parameters, we recompute them - * at the end */ - if (s->dev->buffer_image) - { - RIE(genesys_buffer_image(s)); - - /* check if we need to skip this page, sheetfed scanners - * can go to next doc while flatbed ones can't */ - if (s->swskip > 0 && IS_ACTIVE(OPT_SWSKIP)) { - status = sanei_magic_isBlank(&s->params, - s->dev->img_buffer.data(), - SANE_UNFIX(s->swskip)); - if(status == SANE_STATUS_NO_DOCS) - { - if (s->dev->model->is_sheetfed == SANE_TRUE) - { - DBG(DBG_info, "%s: blank page, recurse\n", __func__); - return sane_start(handle); - } - return status; - } - } - - if (s->swdeskew) { - const auto& sensor = sanei_genesys_find_sensor(s->dev, s->dev->settings.xres, - s->dev->settings.scan_method); - RIE(genesys_deskew(s, sensor)); - } - - if (s->swdespeck) { - RIE(genesys_despeck(s)); - } - - if(s->swcrop) { - RIE(genesys_crop(s)); - } - - if(s->swderotate) { - RIE(genesys_derotate(s)); - } - } - - DBGCOMPLETED; - return status; -} - -SANE_Status sane_start(SANE_Handle handle) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_start_impl(handle); - }); -} - -SANE_Status -sane_read_impl(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len) -{ - Genesys_Scanner *s = (Genesys_Scanner*) handle; - Genesys_Device *dev; - SANE_Status status=SANE_STATUS_GOOD; - size_t local_len; - - if (!s) - { - DBG(DBG_error, "%s: handle is null!\n", __func__); - return SANE_STATUS_INVAL; - } - - dev=s->dev; - if (!dev) - { - DBG(DBG_error, "%s: dev is null!\n", __func__); - return SANE_STATUS_INVAL; - } - - if (!buf) - { - DBG(DBG_error, "%s: buf is null!\n", __func__); - return SANE_STATUS_INVAL; - } - - if (!len) - { - DBG(DBG_error, "%s: len is null!\n", __func__); - return SANE_STATUS_INVAL; - } - - *len = 0; - - if (!s->scanning) - { - DBG(DBG_warn, "%s: scan was cancelled, is over or has not been initiated yet\n", __func__); - return SANE_STATUS_CANCELLED; - } - - DBG(DBG_proc, "%s: start, %d maximum bytes required\n", __func__, max_len); - DBG(DBG_io2, "%s: bytes_to_read=%lu, total_bytes_read=%lu\n", __func__, - (u_long) dev->total_bytes_to_read, (u_long) dev->total_bytes_read); - DBG(DBG_io2, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); - - if(dev->total_bytes_read>=dev->total_bytes_to_read) - { - DBG(DBG_proc, "%s: nothing more to scan: EOF\n", __func__); - - /* issue park command immediatly in case scanner can handle it - * so we save time */ - if (dev->model->is_sheetfed == SANE_FALSE - && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) - && dev->parking == SANE_FALSE) - { - dev->model->cmd_set->slow_back_home (dev, SANE_FALSE); - dev->parking = SANE_TRUE; - } - return SANE_STATUS_EOF; - } - - local_len = max_len; - - /* in case of image processing, all data has been stored in - * buffer_image. So read data from it if it exists, else from scanner */ - if(!dev->buffer_image) - { - /* dynamic lineart is another kind of digital processing that needs - * another layer of buffering on top of genesys_read_ordered_data */ - if(dev->settings.dynamic_lineart==SANE_TRUE) - { - /* if buffer is empty, fill it with genesys_read_ordered_data */ - if(dev->binarize_buffer.avail() == 0) - { - /* store gray data */ - local_len=dev->local_buffer.size(); - dev->local_buffer.reset(); - status = genesys_read_ordered_data (dev, dev->local_buffer.get_write_pos(local_len), - &local_len); - dev->local_buffer.produce(local_len); - - /* binarize data is read successful */ - if(status==SANE_STATUS_GOOD) - { - dev->binarize_buffer.reset(); - genesys_gray_lineart (dev, - dev->local_buffer.get_read_pos(), - dev->binarize_buffer.get_write_pos(local_len / 8), - dev->settings.pixels, - local_len/dev->settings.pixels, - dev->settings.threshold); - dev->binarize_buffer.produce(local_len / 8); - } - - } - - /* return data from lineart buffer if any, up to the available amount */ - local_len = max_len; - if((size_t)max_len>dev->binarize_buffer.avail()) - { - local_len=dev->binarize_buffer.avail(); - } - if(local_len) - { - memcpy(buf, dev->binarize_buffer.get_read_pos(), local_len); - dev->binarize_buffer.consume(local_len); - } - } - else - { - /* most usual case, direct read of data from scanner */ - status = genesys_read_ordered_data (dev, buf, &local_len); - } - } - else /* read data from buffer */ - { - if(dev->total_bytes_read+local_len>dev->total_bytes_to_read) - { - local_len=dev->total_bytes_to_read-dev->total_bytes_read; - } - memcpy(buf, dev->img_buffer.data() + dev->total_bytes_read, local_len); - dev->total_bytes_read+=local_len; - } - - *len = local_len; - if(local_len>(size_t)max_len) - { - fprintf (stderr, "[genesys] sane_read: returning incorrect length!!\n"); - } - DBG(DBG_proc, "%s: %d bytes returned\n", __func__, *len); - return status; -} - -SANE_Status sane_read(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_read_impl(handle, buf, max_len, len); - }); -} - -void sane_cancel_impl(SANE_Handle handle) -{ - Genesys_Scanner *s = (Genesys_Scanner*) handle; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - /* end binary logging if needed */ - if (s->dev->binary!=NULL) - { - fclose(s->dev->binary); - s->dev->binary=NULL; - } - - s->scanning = SANE_FALSE; - s->dev->read_active = SANE_FALSE; - s->dev->img_buffer.clear(); - - /* no need to end scan if we are parking the head */ - if(s->dev->parking==SANE_FALSE) - { - status = s->dev->model->cmd_set->end_scan(s->dev, &s->dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return; - } - } - - /* park head if flatbed scanner */ - if (s->dev->model->is_sheetfed == SANE_FALSE) - { - if(s->dev->parking==SANE_FALSE) - { - status = s->dev->model->cmd_set->slow_back_home (s->dev, s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to move scanhead to home position: %s\n", __func__, - sane_strstatus(status)); - return; - } - s->dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); - } - } - else - { /* in case of sheetfed scanners, we have to eject the document if still present */ - status = s->dev->model->cmd_set->eject_document (s->dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to eject document: %s\n", __func__, sane_strstatus(status)); - return; - } - } - - /* enable power saving mode unless we are parking .... */ - if(s->dev->parking==SANE_FALSE) - { - status = s->dev->model->cmd_set->save_power (s->dev, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to enable power saving mode: %s\n", __func__, - sane_strstatus(status)); - return; - } - } - - DBGCOMPLETED; - return; -} - -void sane_cancel(SANE_Handle handle) -{ - catch_all_exceptions(__func__, [=]() { sane_cancel_impl(handle); }); -} - -SANE_Status -sane_set_io_mode_impl(SANE_Handle handle, SANE_Bool non_blocking) -{ - Genesys_Scanner *s = (Genesys_Scanner*) handle; - - DBG(DBG_proc, "%s: handle = %p, non_blocking = %s\n", __func__, handle, - non_blocking == SANE_TRUE ? "true" : "false"); - - if (!s->scanning) - { - DBG(DBG_error, "%s: not scanning\n", __func__); - return SANE_STATUS_INVAL; - } - if (non_blocking) - return SANE_STATUS_UNSUPPORTED; - return SANE_STATUS_GOOD; -} - -SANE_Status -sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_set_io_mode_impl(handle, non_blocking); - }); -} - -SANE_Status -sane_get_select_fd_impl(SANE_Handle handle, SANE_Int * fd) -{ - Genesys_Scanner *s = (Genesys_Scanner*) handle; - - DBG(DBG_proc, "%s: handle = %p, fd = %p\n", __func__, handle, (void *) fd); - - if (!s->scanning) - { - DBG(DBG_error, "%s: not scanning\n", __func__); - return SANE_STATUS_INVAL; - } - return SANE_STATUS_UNSUPPORTED; -} - -SANE_Status -sane_get_select_fd(SANE_Handle handle, SANE_Int * fd) -{ - return wrap_exceptions_to_status_code(__func__, [=]() - { - return sane_get_select_fd_impl(handle, fd); - }); -} - -GenesysButtonName genesys_option_to_button(int option) -{ - switch (option) { - case OPT_SCAN_SW: return BUTTON_SCAN_SW; - case OPT_FILE_SW: return BUTTON_FILE_SW; - case OPT_EMAIL_SW: return BUTTON_EMAIL_SW; - case OPT_COPY_SW: return BUTTON_COPY_SW; - case OPT_PAGE_LOADED_SW: return BUTTON_PAGE_LOADED_SW; - case OPT_OCR_SW: return BUTTON_OCR_SW; - case OPT_POWER_SW: return BUTTON_POWER_SW; - case OPT_EXTRA_SW: return BUTTON_EXTRA_SW; - default: throw std::runtime_error("Unknown option to convert to button index"); - } -} diff --git a/backend/genesys.conf.in b/backend/genesys.conf.in index b1a0861..786ccd5 100644 --- a/backend/genesys.conf.in +++ b/backend/genesys.conf.in @@ -11,7 +11,7 @@ # Hewlett Packard ScanJet 2400c usb 0x03f0 0x0a01 -# Hewlett Packard ScanJet 3670c/3690c +# Hewlett Packard ScanJet 3670/3690c usb 0x03f0 0x1405 # Plustek OpticPro ST24 @@ -51,9 +51,6 @@ usb 0x04a9 0x1909 # Canon LiDE 200 usb 0x04a9 0x1905 -# Canon 5600F -usb 0x04a9 0x1906 - # Canon LiDE 700F usb 0x04a9 0x1907 @@ -66,9 +63,12 @@ usb 0x04a9 0x190e # Canon LiDE 220 usb 0x04a9 0x190f -# Canon 5600f +# Canon 5600F usb 0x04a9 0x1906 +# Canon 8400F +usb 0x04a9 0x221e + # Canon 8600F usb 0x04a9 0x2229 @@ -124,6 +124,15 @@ usb 0x03f0 0x4605 # Plustek OpticBook 3600 usb 0x07b3 0x0900 +# Plustek OpticFilm 7200i +usb 0x07b3 0x0c04 + +# Plustek OpticFilm 7300 +usb 0x07b3 0x0c12 + +# Plustek OpticFilm 7500i +usb 0x07b3 0x0c13 + # Primax Electronics, Ltd Xerox 2400 Onetouch usb 0x0461 0x038b diff --git a/backend/genesys.h b/backend/genesys.h deleted file mode 100644 index 47a684c..0000000 --- a/backend/genesys.h +++ /dev/null @@ -1,250 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003, 2004 Henning Meier-Geinitz - Copyright (C) 2005-2013 Stephane Voltz - Copyright (C) 2006 Laurent Charpentier - Copyright (C) 2009 Pierre Willenbrock - - 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. -*/ - -#ifndef GENESYS_H -#define GENESYS_H - -#ifndef BACKEND_NAME -# define BACKEND_NAME genesys -#endif - -#include "genesys_low.h" -#include - -#ifndef PATH_MAX -# define PATH_MAX 1024 -#endif - -#if defined(_WIN32) || defined(HAVE_OS2_H) -# define PATH_SEP '\\' -#else -# define PATH_SEP '/' -#endif - - -#define ENABLE(OPTION) s->opt[OPTION].cap &= ~SANE_CAP_INACTIVE -#define DISABLE(OPTION) s->opt[OPTION].cap |= SANE_CAP_INACTIVE -#define IS_ACTIVE(OPTION) (((s->opt[OPTION].cap) & SANE_CAP_INACTIVE) == 0) - -#define GENESYS_CONFIG_FILE "genesys.conf" - -/* Maximum time for lamp warm-up */ -#define WARMUP_TIME 65 - -#define STR_FLATBED "Flatbed" -#define STR_TRANSPARENCY_ADAPTER "Transparency Adapter" -#define STR_TRANSPARENCY_ADAPTER_INFRARED "Transparency Adapter Infrared" - -#ifndef SANE_I18N -#define SANE_I18N(text) text -#endif - -/** List of SANE options - */ -enum Genesys_Option -{ - OPT_NUM_OPTS = 0, - - OPT_MODE_GROUP, - OPT_MODE, - OPT_SOURCE, - OPT_PREVIEW, - OPT_BIT_DEPTH, - OPT_RESOLUTION, - - OPT_GEOMETRY_GROUP, - OPT_TL_X, /* top-left x */ - OPT_TL_Y, /* top-left y */ - OPT_BR_X, /* bottom-right x */ - OPT_BR_Y, /* bottom-right y */ - - /* advanced image enhancement options */ - OPT_ENHANCEMENT_GROUP, - OPT_CUSTOM_GAMMA, /* toggle to enable custom gamma tables */ - OPT_GAMMA_VECTOR, - OPT_GAMMA_VECTOR_R, - OPT_GAMMA_VECTOR_G, - OPT_GAMMA_VECTOR_B, - OPT_SWDESKEW, - OPT_SWCROP, - OPT_SWDESPECK, - OPT_DESPECK, - OPT_SWSKIP, - OPT_SWDEROTATE, - OPT_BRIGHTNESS, - OPT_CONTRAST, - - OPT_EXTRAS_GROUP, - OPT_LAMP_OFF_TIME, - OPT_LAMP_OFF, - OPT_THRESHOLD, - OPT_THRESHOLD_CURVE, - OPT_DISABLE_DYNAMIC_LINEART, - OPT_DISABLE_INTERPOLATION, - OPT_COLOR_FILTER, - OPT_CALIBRATION_FILE, - OPT_EXPIRATION_TIME, - - OPT_SENSOR_GROUP, - OPT_SCAN_SW, - OPT_FILE_SW, - OPT_EMAIL_SW, - OPT_COPY_SW, - OPT_PAGE_LOADED_SW, - OPT_OCR_SW, - OPT_POWER_SW, - OPT_EXTRA_SW, - OPT_NEED_CALIBRATION_SW, - OPT_BUTTON_GROUP, - OPT_CALIBRATE, - OPT_CLEAR_CALIBRATION, - OPT_FORCE_CALIBRATION, - - /* must come last: */ - NUM_OPTIONS -}; - -enum GenesysButtonName : unsigned { - BUTTON_SCAN_SW = 0, - BUTTON_FILE_SW, - BUTTON_EMAIL_SW, - BUTTON_COPY_SW, - BUTTON_PAGE_LOADED_SW, - BUTTON_OCR_SW, - BUTTON_POWER_SW, - BUTTON_EXTRA_SW, - NUM_BUTTONS -}; - -GenesysButtonName genesys_option_to_button(int option); - -class GenesysButton { -public: - void write(bool value) - { - if (value == value_) { - return; - } - values_to_read_.push(value); - value_ = value; - } - - bool read() - { - if (values_to_read_.empty()) { - return value_; - } - bool ret = values_to_read_.front(); - values_to_read_.pop(); - return ret; - } - -private: - bool value_ = false; - std::queue values_to_read_; -}; - -/** Scanner object. Should have better be called Session than Scanner - */ -struct Genesys_Scanner -{ - Genesys_Scanner() = default; - ~Genesys_Scanner() = default; - - // Next scanner in list - struct Genesys_Scanner *next; - - // Low-level device object - Genesys_Device* dev = nullptr; - - // SANE data - // We are currently scanning - SANE_Bool scanning; - // Option descriptors - SANE_Option_Descriptor opt[NUM_OPTIONS]; - - // Option values - SANE_Word bit_depth = 0; - SANE_Word resolution = 0; - bool preview = false; - SANE_Word threshold = 0; - SANE_Word threshold_curve = 0; - bool disable_dynamic_lineart = false; - bool disable_interpolation = false; - bool lamp_off = false; - SANE_Word lamp_off_time = 0; - bool swdeskew = false; - bool swcrop = false; - bool swdespeck = false; - bool swderotate = false; - SANE_Word swskip = 0; - SANE_Word despeck = 0; - SANE_Word contrast = 0; - SANE_Word brightness = 0; - SANE_Word expiration_time = 0; - bool custom_gamma = false; - - SANE_Word pos_top_left_y = 0; - SANE_Word pos_top_left_x = 0; - SANE_Word pos_bottom_right_y = 0; - SANE_Word pos_bottom_right_x = 0; - - std::string mode, source, color_filter; - - std::string calibration_file; - // Button states - GenesysButton buttons[NUM_BUTTONS]; - - // SANE Parameters - SANE_Parameters params = {}; - SANE_Int bpp_list[5] = {}; -}; - -void write_calibration(std::ostream& str, Genesys_Device::Calibration& cache); -bool read_calibration(std::istream& str, Genesys_Device::Calibration& cache, - const std::string& path); - -#endif /* not GENESYS_H */ diff --git a/backend/genesys/buffer.cpp b/backend/genesys/buffer.cpp new file mode 100644 index 0000000..f17e361 --- /dev/null +++ b/backend/genesys/buffer.cpp @@ -0,0 +1,102 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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 "buffer.h" +#include +#include + +namespace genesys { + +void Genesys_Buffer::alloc(std::size_t size) +{ + buffer_.resize(size); + avail_ = 0; + pos_ = 0; +} + +void Genesys_Buffer::clear() +{ + buffer_.clear(); + avail_ = 0; + pos_ = 0; +} + +void Genesys_Buffer::reset() +{ + avail_ = 0; + pos_ = 0; +} + +std::uint8_t* Genesys_Buffer::get_write_pos(std::size_t size) +{ + if (avail_ + size > buffer_.size()) + return nullptr; + if (pos_ + avail_ + size > buffer_.size()) + { + std::memmove(buffer_.data(), buffer_.data() + pos_, avail_); + pos_ = 0; + } + return buffer_.data() + pos_ + avail_; +} + +std::uint8_t* Genesys_Buffer::get_read_pos() +{ + return buffer_.data() + pos_; +} + +void Genesys_Buffer::produce(std::size_t size) +{ + if (size > buffer_.size() - avail_) + throw std::runtime_error("buffer size exceeded"); + avail_ += size; +} + +void Genesys_Buffer::consume(std::size_t size) +{ + if (size > avail_) + throw std::runtime_error("no more data in buffer"); + avail_ -= size; + pos_ += size; +} + +} // namespace genesys diff --git a/backend/genesys/buffer.h b/backend/genesys/buffer.h new file mode 100644 index 0000000..e9c889b --- /dev/null +++ b/backend/genesys/buffer.h @@ -0,0 +1,89 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_BUFFER_H +#define BACKEND_GENESYS_BUFFER_H + +#include +#include +#include + +namespace genesys { + +/* A FIFO buffer. Note, that this is _not_ a ringbuffer. + if we need a block which does not fit at the end of our available data, + we move the available data to the beginning. +*/ +struct Genesys_Buffer +{ + Genesys_Buffer() = default; + + std::size_t size() const { return buffer_.size(); } + std::size_t avail() const { return avail_; } + std::size_t pos() const { return pos_; } + + // TODO: refactor code that uses this function to no longer use it + void set_pos(std::size_t pos) { pos_ = pos; } + + void alloc(std::size_t size); + void clear(); + + void reset(); + + std::uint8_t* get_write_pos(std::size_t size); + std::uint8_t* get_read_pos(); // TODO: mark as const + + void produce(std::size_t size); + void consume(std::size_t size); + +private: + std::vector buffer_; + // current position in read buffer + std::size_t pos_ = 0; + // data bytes currently in buffer + std::size_t avail_ = 0; +}; + +} // namespace genesys + +#endif // BACKEND_GENESYS_BUFFER_H diff --git a/backend/genesys/calibration.h b/backend/genesys/calibration.h new file mode 100644 index 0000000..f14aaa3 --- /dev/null +++ b/backend/genesys/calibration.h @@ -0,0 +1,108 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_CALIBRATION_H +#define BACKEND_GENESYS_CALIBRATION_H + +#include "sensor.h" +#include "settings.h" +#include + +namespace genesys { + +struct Genesys_Calibration_Cache +{ + Genesys_Calibration_Cache() = default; + ~Genesys_Calibration_Cache() = default; + + // used to check if entry is compatible + SetupParams params; + + std::time_t last_calibration = 0; + + Genesys_Frontend frontend; + Genesys_Sensor sensor; + + size_t calib_pixels = 0; + size_t calib_channels = 0; + size_t average_size = 0; + std::vector white_average_data; + std::vector dark_average_data; + + bool operator==(const Genesys_Calibration_Cache& other) const + { + return params == other.params && + last_calibration == other.last_calibration && + frontend == other.frontend && + sensor == other.sensor && + calib_pixels == other.calib_pixels && + calib_channels == other.calib_channels && + average_size == other.average_size && + white_average_data == other.white_average_data && + dark_average_data == other.dark_average_data; + } +}; + +template +void serialize(Stream& str, Genesys_Calibration_Cache& x) +{ + serialize(str, x.params); + serialize_newline(str); + serialize(str, x.last_calibration); + serialize_newline(str); + serialize(str, x.frontend); + serialize_newline(str); + serialize(str, x.sensor); + serialize_newline(str); + serialize(str, x.calib_pixels); + serialize(str, x.calib_channels); + serialize(str, x.average_size); + serialize_newline(str); + serialize(str, x.white_average_data); + serialize_newline(str); + serialize(str, x.dark_average_data); +} + +} // namespace genesys + +#endif // BACKEND_GENESYS_CALIBRATION_H diff --git a/backend/genesys/command_set.h b/backend/genesys/command_set.h new file mode 100644 index 0000000..ab3a4b6 --- /dev/null +++ b/backend/genesys/command_set.h @@ -0,0 +1,166 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_COMMAND_SET_H +#define BACKEND_GENESYS_COMMAND_SET_H + +#include "device.h" +#include "fwd.h" +#include + +namespace genesys { + + +/** Scanner command set description. + + This description contains parts which are common to all scanners with the + same command set, but may have different optical resolution and other + parameters. + */ +class CommandSet +{ +public: + virtual ~CommandSet() = default; + + virtual bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const = 0; + + virtual void init(Genesys_Device* dev) const = 0; + + virtual void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const = 0; + + virtual void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const = 0; + virtual void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const = 0; + virtual void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const = 0; + + /** Set up registers for a scan. Similar to init_regs_for_scan except that the session is + already computed from the session + */ + virtual void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const= 0; + + virtual void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, std::uint8_t set) const = 0; + virtual void set_powersaving(Genesys_Device* dev, int delay) const = 0; + virtual void save_power(Genesys_Device* dev, bool enable) const = 0; + + virtual void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, bool start_motor) const = 0; + virtual void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, + bool check_stop) const = 0; + + + /** + * Send gamma tables to ASIC + */ + virtual void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const = 0; + + virtual void search_start_position(Genesys_Device* dev) const = 0; + virtual void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const = 0; + virtual void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const = 0; + virtual SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const = 0; + + virtual void wait_for_motor_stop(Genesys_Device* dev) const = 0; + virtual void move_back_home(Genesys_Device* dev, bool wait_until_home) const = 0; + + // Updates hardware sensor information in Genesys_Scanner.val[]. + virtual void update_hardware_sensors(struct Genesys_Scanner* s) const = 0; + + /** Whether the scanner needs to call update_home_sensor_gpio before reading the status of the + home sensor. On some chipsets this is unreliable until update_home_sensor_gpio() is called. + */ + virtual bool needs_update_home_sensor_gpio() const { return false; } + + /** Needed on some chipsets before reading the status of the home sensor to make this operation + reliable. + */ + virtual void update_home_sensor_gpio(Genesys_Device& dev) const { (void) dev; } + + // functions for sheetfed scanners + + // load document into scanner + virtual void load_document(Genesys_Device* dev) const = 0; + + /** Detects is the scanned document has left scanner. In this case it updates the amount of + data to read and set up flags in the dev struct + */ + virtual void detect_document_end(Genesys_Device* dev) const = 0; + + /// eject document from scanner + virtual void eject_document(Genesys_Device* dev) const = 0; + /** + * search for an black or white area in forward or reverse + * direction */ + virtual void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const = 0; + + /// move scanning head to transparency adapter + virtual void move_to_ta(Genesys_Device* dev) const = 0; + + /// write shading data calibration to ASIC + virtual void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + std::uint8_t* data, int size) const = 0; + + virtual bool has_send_shading_data() const + { + return true; + } + + /// calculate an instance of ScanSession for scanning with the given settings + virtual ScanSession calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const = 0; + + /// cold boot init function + virtual void asic_boot(Genesys_Device* dev, bool cold) const = 0; +}; + +} // namespace genesys + +#endif // BACKEND_GENESYS_COMMAND_SET_H diff --git a/backend/genesys/conv.cpp b/backend/genesys/conv.cpp new file mode 100644 index 0000000..a87c463 --- /dev/null +++ b/backend/genesys/conv.cpp @@ -0,0 +1,238 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2005, 2006 Pierre Willenbrock + Copyright (C) 2010-2013 Stéphane Voltz + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "conv.h" +#include "sane/sanei_magic.h" + +namespace genesys { + +/** + * uses the threshold/threshold_curve to control software binarization + * This code was taken from the epjistsu backend by m. allan noah + * @param dev device set up for the scan + * @param src pointer to raw data + * @param dst pointer where to store result + * @param width width of the processed line + * */ +void binarize_line(Genesys_Device* dev, std::uint8_t* src, std::uint8_t* dst, int width) +{ + DBG_HELPER(dbg); + int j, windowX, sum = 0; + int thresh; + int offset, addCol, dropCol; + unsigned char mask; + + int x; + std::uint8_t min, max; + + /* 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); + } + + /* ~1mm works best, but the window needs to have odd # of pixels */ + windowX = (6 * dev->settings.xres) / 150; + if (!(windowX % 2)) + windowX++; + + /* second, prefill the sliding sum */ + for (j = 0; j < windowX; j++) + sum += src[j]; + + /* third, walk the input buffer, update the sliding sum, */ + /* determine threshold, output bits */ + for (j = 0; j < width; j++) + { + /* output image location */ + offset = j % 8; + mask = 0x80 >> offset; + thresh = dev->settings.threshold; + + /* move sum/update threshold only if there is a curve */ + if (dev->settings.threshold_curve) + { + addCol = j + windowX / 2; + dropCol = addCol - windowX; + + if (dropCol >= 0 && addCol < width) + { + sum -= src[dropCol]; + sum += src[addCol]; + } + thresh = dev->lineart_lut[sum / windowX]; + } + + /* use average to lookup threshold */ + if (src[j] > thresh) + *dst &= ~mask; /* white */ + else + *dst |= mask; /* black */ + + if (offset == 7) + dst++; + } +} + +/** + * software lineart using data from a 8 bit gray scan. We assume true gray + * or monochrome scan as input. + */ +void genesys_gray_lineart(Genesys_Device* dev, + std::uint8_t* src_data, std::uint8_t* dst_data, + std::size_t pixels, std::size_t lines, std::uint8_t threshold) +{ + DBG_HELPER(dbg); + std::size_t y; + + DBG(DBG_io2, "%s: converting %zu lines of %zu pixels\n", __func__, lines, pixels); + DBG(DBG_io2, "%s: threshold=%d\n", __func__, threshold); + + for (y = 0; y < lines; y++) + { + binarize_line (dev, src_data + y * pixels, dst_data, pixels); + dst_data += pixels / 8; + } +} + +/** Look in image for likely left/right/bottom paper edges, then crop image. + */ +void genesys_crop(Genesys_Scanner* s) +{ + DBG_HELPER(dbg); + Genesys_Device *dev = s->dev; + int top = 0; + int bottom = 0; + int left = 0; + int right = 0; + + // first find edges if any + TIE(sanei_magic_findEdges(&s->params, dev->img_buffer.data(), + dev->settings.xres, dev->settings.yres, + &top, &bottom, &left, &right)); + + DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __func__, top, bottom, left, + right); + + // now crop the image + TIE(sanei_magic_crop (&(s->params), dev->img_buffer.data(), top, bottom, left, right)); + + /* update counters to new image size */ + dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; +} + +/** Look in image for likely upper and left paper edges, then rotate + * image so that upper left corner of paper is upper left of image. + */ +void genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + Genesys_Device *dev = s->dev; + + int x = 0, y = 0, bg; + double slope = 0; + + bg=0; + if(s->params.format==SANE_FRAME_GRAY && s->params.depth == 1) + { + bg=0xff; + } + TIE(sanei_magic_findSkew(&s->params, dev->img_buffer.data(), + sensor.optical_res, sensor.optical_res, + &x, &y, &slope)); + + DBG(DBG_info, "%s: slope=%f => %f\n", __func__, slope, slope * 180 / M_PI); + + // rotate image slope is in [-PI/2,PI/2]. Positive values rotate trigonometric direction wise + TIE(sanei_magic_rotate(&s->params, dev->img_buffer.data(), + x, y, slope, bg)); +} + +/** remove lone dots + */ +void genesys_despeck(Genesys_Scanner* s) +{ + DBG_HELPER(dbg); + TIE(sanei_magic_despeck(&s->params, s->dev->img_buffer.data(), s->despeck)); +} + +/** Look if image needs rotation and apply it + * */ +void genesys_derotate(Genesys_Scanner* s) +{ + DBG_HELPER(dbg); + int angle = 0; + + TIE(sanei_magic_findTurn(&s->params, s->dev->img_buffer.data(), + s->resolution, s->resolution, &angle)); + + // apply rotation angle found + TIE(sanei_magic_turn(&s->params, s->dev->img_buffer.data(), angle)); + + // update counters to new image size + s->dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; +} + +} // namespace genesys diff --git a/backend/genesys/conv.h b/backend/genesys/conv.h new file mode 100644 index 0000000..446a80d --- /dev/null +++ b/backend/genesys/conv.h @@ -0,0 +1,69 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_CONV_H +#define BACKEND_GENESYS_CONV_H + +#include "device.h" +#include "sensor.h" +#include "genesys.h" + +namespace genesys { + +void binarize_line(Genesys_Device* dev, std::uint8_t* src, std::uint8_t* dst, int width); + +void genesys_gray_lineart(Genesys_Device* dev, + std::uint8_t* src_data, std::uint8_t* dst_data, + std::size_t pixels, size_t lines, std::uint8_t threshold); + +void genesys_crop(Genesys_Scanner* s); + +void genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor); + +void genesys_despeck(Genesys_Scanner* s); + +void genesys_derotate(Genesys_Scanner* s); + +} // namespace genesys + +#endif // BACKEND_GENESYS_CONV_H diff --git a/backend/genesys/device.cpp b/backend/genesys/device.cpp new file mode 100644 index 0000000..ba035fd --- /dev/null +++ b/backend/genesys/device.cpp @@ -0,0 +1,272 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "device.h" +#include "command_set.h" +#include "low.h" +#include "utilities.h" + +namespace genesys { + +std::vector MethodResolutions::get_resolutions() const +{ + std::vector ret; + std::copy(resolutions_x.begin(), resolutions_x.end(), std::back_inserter(ret)); + std::copy(resolutions_y.begin(), resolutions_y.end(), std::back_inserter(ret)); + // sort in decreasing order + + std::sort(ret.begin(), ret.end(), std::greater()); + ret.erase(std::unique(ret.begin(), ret.end()), ret.end()); + return ret; +} + +const MethodResolutions& Genesys_Model::get_resolution_settings(ScanMethod method) const +{ + for (const auto& res_for_method : resolutions) { + for (auto res_method : res_for_method.methods) { + if (res_method == method) { + return res_for_method; + } + } + } + throw SaneException("Could not find resolution settings for method %d", + static_cast(method)); +} + +std::vector Genesys_Model::get_resolutions(ScanMethod method) const +{ + return get_resolution_settings(method).get_resolutions(); +} + +Genesys_Device::~Genesys_Device() +{ + clear(); +} + +void Genesys_Device::clear() +{ + read_buffer.clear(); + binarize_buffer.clear(); + local_buffer.clear(); + + calib_file.clear(); + + calibration_cache.clear(); + + white_average_data.clear(); + dark_average_data.clear(); +} + +ImagePipelineNodeBytesSource& Genesys_Device::get_pipeline_source() +{ + return static_cast(pipeline.front()); +} + +bool Genesys_Device::is_head_pos_known(ScanHeadId scan_head) const +{ + switch (scan_head) { + case ScanHeadId::PRIMARY: return is_head_pos_primary_known_; + case ScanHeadId::SECONDARY: return is_head_pos_secondary_known_; + case ScanHeadId::ALL: return is_head_pos_primary_known_ && is_head_pos_secondary_known_; + default: + throw SaneException("Unknown scan head ID"); + } +} +unsigned Genesys_Device::head_pos(ScanHeadId scan_head) const +{ + switch (scan_head) { + case ScanHeadId::PRIMARY: return head_pos_primary_; + case ScanHeadId::SECONDARY: return head_pos_secondary_; + default: + throw SaneException("Unknown scan head ID"); + } +} + +void Genesys_Device::set_head_pos_unknown() +{ + is_head_pos_primary_known_ = false; + is_head_pos_secondary_known_ = false; +} + +void Genesys_Device::set_head_pos_zero(ScanHeadId scan_head) +{ + if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) { + head_pos_primary_ = 0; + is_head_pos_primary_known_ = true; + } + if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) { + head_pos_secondary_ = 0; + is_head_pos_secondary_known_ = true; + } +} + +void Genesys_Device::advance_head_pos_by_session(ScanHeadId scan_head) +{ + int motor_steps = session.params.starty + + (session.params.lines * motor.base_ydpi) / session.params.yres; + auto direction = has_flag(session.params.flags, ScanFlag::REVERSE) ? Direction::BACKWARD + : Direction::FORWARD; + advance_head_pos_by_steps(scan_head, direction, motor_steps); +} + +static void advance_pos(unsigned& pos, Direction direction, unsigned offset) +{ + if (direction == Direction::FORWARD) { + pos += offset; + } else { + if (pos < offset) { + throw SaneException("Trying to advance head behind the home sensor"); + } + pos -= offset; + } +} + +void Genesys_Device::advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction, + unsigned steps) +{ + if ((scan_head & ScanHeadId::PRIMARY) != ScanHeadId::NONE) { + if (!is_head_pos_primary_known_) { + throw SaneException("Trying to advance head while scanhead position is not known"); + } + advance_pos(head_pos_primary_, direction, steps); + } + if ((scan_head & ScanHeadId::SECONDARY) != ScanHeadId::NONE) { + if (!is_head_pos_secondary_known_) { + throw SaneException("Trying to advance head while scanhead position is not known"); + } + advance_pos(head_pos_secondary_, direction, steps); + } +} + +void print_scan_position(std::ostream& out, const Genesys_Device& dev, ScanHeadId scan_head) +{ + if (dev.is_head_pos_known(scan_head)) { + out << dev.head_pos(scan_head); + } else { + out <<"(unknown)"; + } +} + +std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev) +{ + StreamStateSaver state_saver{out}; + + out << "Genesys_Device{\n" + << std::hex + << " vendorId: 0x" << dev.vendorId << '\n' + << " productId: 0x" << dev.productId << '\n' + << std::dec + << " usb_mode: " << dev.usb_mode << '\n' + << " file_name: " << dev.file_name << '\n' + << " calib_file: " << dev.calib_file << '\n' + << " force_calibration: " << dev.force_calibration << '\n' + << " ignore_offsets: " << dev.ignore_offsets << '\n' + << " model: (not printed)\n" + << " reg: " << format_indent_braced_list(4, dev.reg) << '\n' + << " calib_reg: " << format_indent_braced_list(4, dev.calib_reg) << '\n' + << " settings: " << format_indent_braced_list(4, dev.settings) << '\n' + << " frontend: " << format_indent_braced_list(4, dev.frontend) << '\n' + << " frontend_initial: " << format_indent_braced_list(4, dev.frontend_initial) << '\n' + << " frontend_is_init: " << dev.frontend_is_init << '\n' + << " gpo.regs: " << format_indent_braced_list(4, dev.gpo.regs) << '\n' + << " motor: " << format_indent_braced_list(4, dev.motor) << '\n' + << " control[0..6]: " << std::hex + << static_cast(dev.control[0]) << ' ' + << static_cast(dev.control[1]) << ' ' + << static_cast(dev.control[2]) << ' ' + << static_cast(dev.control[3]) << ' ' + << static_cast(dev.control[4]) << ' ' + << static_cast(dev.control[5]) << '\n' << std::dec + << " average_size: " << dev.average_size << '\n' + << " calib_pixels: " << dev.calib_pixels << '\n' + << " calib_lines: " << dev.calib_lines << '\n' + << " calib_channels: " << dev.calib_channels << '\n' + << " calib_resolution: " << dev.calib_resolution << '\n' + << " calib_total_bytes_to_read: " << dev.calib_total_bytes_to_read << '\n' + << " calib_session: " << format_indent_braced_list(4, dev.calib_session) << '\n' + << " calib_pixels_offset: " << dev.calib_pixels_offset << '\n' + << " gamma_override_tables[0].size(): " << dev.gamma_override_tables[0].size() << '\n' + << " gamma_override_tables[1].size(): " << dev.gamma_override_tables[1].size() << '\n' + << " gamma_override_tables[2].size(): " << dev.gamma_override_tables[2].size() << '\n' + << " white_average_data.size(): " << dev.white_average_data.size() << '\n' + << " dark_average_data.size(): " << dev.dark_average_data.size() << '\n' + << " already_initialized: " << dev.already_initialized << '\n' + << " scanhead_position[PRIMARY]: "; + print_scan_position(out, dev, ScanHeadId::PRIMARY); + out << '\n' + << " scanhead_position[SECONDARY]: "; + print_scan_position(out, dev, ScanHeadId::SECONDARY); + out << '\n' + << " read_active: " << dev.read_active << '\n' + << " parking: " << dev.parking << '\n' + << " document: " << dev.document << '\n' + << " read_buffer.size(): " << dev.read_buffer.size() << '\n' + << " binarize_buffer.size(): " << dev.binarize_buffer.size() << '\n' + << " local_buffer.size(): " << dev.local_buffer.size() << '\n' + << " oe_buffer.size(): " << dev.oe_buffer.size() << '\n' + << " total_bytes_read: " << dev.total_bytes_read << '\n' + << " total_bytes_to_read: " << dev.total_bytes_to_read << '\n' + << " session: " << format_indent_braced_list(4, dev.session) << '\n' + << " lineart_lut: (not printed)\n" + << " calibration_cache: (not printed)\n" + << " line_count: " << dev.line_count << '\n' + << " segment_order: " + << format_indent_braced_list(4, format_vector_unsigned(4, dev.segment_order)) << '\n' + << " buffer_image: " << dev.buffer_image << '\n' + << " img_buffer.size(): " << dev.img_buffer.size() << '\n' + << '}'; + return out; +} + +void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs) +{ + for (const auto& reg : regs) { + uint8_t val = dev.interface->read_register(reg.address); + val = (val & ~reg.mask) | (reg.value & reg.mask); + dev.interface->write_register(reg.address, val); + } +} + +} // namespace genesys diff --git a/backend/genesys/device.h b/backend/genesys/device.h new file mode 100644 index 0000000..6c744c9 --- /dev/null +++ b/backend/genesys/device.h @@ -0,0 +1,387 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_DEVICE_H +#define BACKEND_GENESYS_DEVICE_H + +#include "calibration.h" +#include "command_set.h" +#include "buffer.h" +#include "enums.h" +#include "image_pipeline.h" +#include "motor.h" +#include "settings.h" +#include "sensor.h" +#include "register.h" +#include "usb_device.h" +#include "scanner_interface.h" +#include + +namespace genesys { + +struct Genesys_Gpo +{ + Genesys_Gpo() = default; + + // Genesys_Gpo + GpioId id = GpioId::UNKNOWN; + + /* GL646 and possibly others: + - have the value registers at 0x66 and 0x67 + - have the enable registers at 0x68 and 0x69 + + GL841, GL842, GL843, GL846, GL848 and possibly others: + - have the value registers at 0x6c and 0x6d. + - have the enable registers at 0x6e and 0x6f. + */ + GenesysRegisterSettingSet regs; +}; + +/// Stores a SANE_Fixed value which is automatically converted from and to floating-point values +class FixedFloat +{ +public: + FixedFloat() = default; + FixedFloat(const FixedFloat&) = default; + FixedFloat(double number) : value_{SANE_FIX(number)} {} + FixedFloat& operator=(const FixedFloat&) = default; + FixedFloat& operator=(double number) { value_ = SANE_FIX(number); return *this; } + + operator double() const { return value(); } + + double value() const { return SANE_UNFIX(value_); } + +private: + SANE_Fixed value_ = 0; +}; + +struct MethodResolutions +{ + std::vector methods; + std::vector resolutions_x; + std::vector resolutions_y; + + unsigned get_min_resolution_x() const + { + return *std::min_element(resolutions_x.begin(), resolutions_x.end()); + } + + unsigned get_min_resolution_y() const + { + return *std::min_element(resolutions_y.begin(), resolutions_y.end()); + } + + std::vector get_resolutions() const; +}; + +/** @brief structure to describe a scanner model + * This structure describes a model. It is composed of information on the + * sensor, the motor, scanner geometry and flags to drive operation. + */ +struct Genesys_Model +{ + Genesys_Model() = default; + + const char* name = nullptr; + const char* vendor = nullptr; + const char* model = nullptr; + ModelId model_id = ModelId::UNKNOWN; + + AsicType asic_type = AsicType::UNKNOWN; + + // possible x and y resolutions for each method supported by the scanner + std::vector resolutions; + + // possible depths in gray mode + std::vector bpp_gray_values; + // possible depths in color mode + std::vector bpp_color_values; + + // the default scanning method. This is used when moving the head for example + ScanMethod default_method = ScanMethod::FLATBED; + + // All offsets below are with respect to the sensor home position + + // Start of scan area in mm + FixedFloat x_offset = 0; + + // Start of scan area in mm (Amount of feeding needed to get to the medium) + FixedFloat y_offset = 0; + + // Size of scan area in mm + FixedFloat x_size = 0; + + // Size of scan area in mm + FixedFloat y_size = 0; + + // Start of white strip in mm + FixedFloat y_offset_calib_white = 0; + + // Start of black mark in mm + FixedFloat x_offset_calib_black = 0; + + // Start of scan area in transparency mode in mm + FixedFloat x_offset_ta = 0; + + // Start of scan area in transparency mode in mm + FixedFloat y_offset_ta = 0; + + // Size of scan area in transparency mode in mm + FixedFloat x_size_ta = 0; + + // Size of scan area in transparency mode in mm + FixedFloat y_size_ta = 0; + + // The position of the sensor when it's aligned with the lamp for transparency scanning + FixedFloat y_offset_sensor_to_ta = 0; + + // Start of white strip in transparency mode in mm + FixedFloat y_offset_calib_white_ta = 0; + + // Start of black strip in transparency mode in mm + FixedFloat y_offset_calib_black_ta = 0; + + // Size of scan area after paper sensor stop sensing document in mm + FixedFloat post_scan = 0; + + // Amount of feeding needed to eject document after finishing scanning in mm + FixedFloat eject_feed = 0; + + // Line-distance correction (in pixel at optical_ydpi) for CCD scanners + SANE_Int ld_shift_r = 0; + SANE_Int ld_shift_g = 0; + SANE_Int ld_shift_b = 0; + + // Order of the CCD/CIS colors + ColorOrder line_mode_color_order = ColorOrder::RGB; + + // Is this a CIS or CCD scanner? + bool is_cis = false; + + // Is this sheetfed scanner? + bool is_sheetfed = false; + + // sensor type + SensorId sensor_id = SensorId::UNKNOWN; + // Analog-Digital converter type + AdcId adc_id = AdcId::UNKNOWN; + // General purpose output type + GpioId gpio_id = GpioId::UNKNOWN; + // stepper motor type + MotorId motor_id = MotorId::UNKNOWN; + + // Which hacks are needed for this scanner? + SANE_Word flags = 0; + + // Button flags, described existing buttons for the model + SANE_Word buttons = 0; + + // how many lines are used for shading calibration + SANE_Int shading_lines = 0; + // how many lines are used for shading calibration in TA mode + SANE_Int shading_ta_lines = 0; + // how many lines are used to search start position + SANE_Int search_lines = 0; + + const MethodResolutions& get_resolution_settings(ScanMethod method) const; + + std::vector get_resolutions(ScanMethod method) const; +}; + +/** + * Describes the current device status for the backend + * session. This should be more accurately called + * Genesys_Session . + */ +struct Genesys_Device +{ + Genesys_Device() = default; + ~Genesys_Device(); + + using Calibration = std::vector; + + // frees commonly used data + void clear(); + + SANE_Word vendorId = 0; /**< USB vendor identifier */ + SANE_Word productId = 0; /**< USB product identifier */ + + // USB mode: + // 0: not set + // 1: USB 1.1 + // 2: USB 2.0 + SANE_Int usb_mode = 0; + + std::string file_name; + std::string calib_file; + + // if enabled, no calibration data will be loaded or saved to files + SANE_Int force_calibration = 0; + // if enabled, will ignore the scan offsets and start scanning at true origin. This allows + // acquiring the positions of the black and white strips and the actual scan area + bool ignore_offsets = false; + + Genesys_Model *model = nullptr; + + // pointers to low level functions + std::unique_ptr cmd_set; + + Genesys_Register_Set reg; + Genesys_Register_Set calib_reg; + Genesys_Settings settings; + Genesys_Frontend frontend, frontend_initial; + + // whether the frontend is initialized. This is currently used just to preserve historical + // behavior + bool frontend_is_init = false; + + Genesys_Gpo gpo; + Genesys_Motor motor; + std::uint8_t control[6] = {}; + + size_t average_size = 0; + // number of pixels used during shading calibration + size_t calib_pixels = 0; + // number of lines used during shading calibration + size_t calib_lines = 0; + size_t calib_channels = 0; + size_t calib_resolution = 0; + // bytes to read from USB when calibrating. If 0, this is not set + size_t calib_total_bytes_to_read = 0; + + // the session that was configured for calibration + ScanSession calib_session; + + // certain scanners support much higher resolution when scanning transparency, but we can't + // read whole width of the scanner as a single line at that resolution. Thus for stuff like + // calibration we want to read only the possible calibration area. + size_t calib_pixels_offset = 0; + + // gamma overrides. If a respective array is not empty then it means that the gamma for that + // color is overridden. + std::vector gamma_override_tables[3]; + + std::vector white_average_data; + std::vector dark_average_data; + + bool already_initialized = false; + + bool read_active = false; + // signal wether the park command has been issued + bool parking = false; + + // for sheetfed scanner's, is TRUE when there is a document in the scanner + bool document = false; + + Genesys_Buffer read_buffer; + + // buffer for digital lineart from gray data + Genesys_Buffer binarize_buffer; + // local buffer for gray data during dynamix lineart + Genesys_Buffer local_buffer; + + // total bytes read sent to frontend + size_t total_bytes_read = 0; + // total bytes read to be sent to frontend + size_t total_bytes_to_read = 0; + + // contains computed data for the current setup + ScanSession session; + + // look up table used in dynamic rasterization + unsigned char lineart_lut[256] = {}; + + Calibration calibration_cache; + + // number of scan lines used during scan + int line_count = 0; + + // array describing the order of the sub-segments of the sensor + std::vector segment_order; + + // buffer to handle even/odd data + Genesys_Buffer oe_buffer = {}; + + // stores information about how the input image should be processed + ImagePipelineStack pipeline; + + // an buffer that allows reading from `pipeline` in chunks of any size + ImageBuffer pipeline_buffer; + + // when true the scanned picture is first buffered to allow software image enhancements + bool buffer_image = false; + + // image buffer where the scanned picture is stored + std::vector img_buffer; + + ImagePipelineNodeBytesSource& get_pipeline_source(); + + std::unique_ptr interface; + + bool is_head_pos_known(ScanHeadId scan_head) const; + unsigned head_pos(ScanHeadId scan_head) const; + void set_head_pos_unknown(); + void set_head_pos_zero(ScanHeadId scan_head); + void advance_head_pos_by_session(ScanHeadId scan_head); + void advance_head_pos_by_steps(ScanHeadId scan_head, Direction direction, unsigned steps); + +private: + // the position of the primary scan head in motor->base_dpi units + unsigned head_pos_primary_ = 0; + bool is_head_pos_primary_known_ = true; + + // the position of the secondary scan head in motor->base_dpi units. Only certain scanners + // have a secondary scan head. + unsigned head_pos_secondary_ = 0; + bool is_head_pos_secondary_known_ = true; + + friend class ScannerInterfaceUsb; +}; + +std::ostream& operator<<(std::ostream& out, const Genesys_Device& dev); + +void apply_reg_settings_to_device(Genesys_Device& dev, const GenesysRegisterSettingSet& regs); + +} // namespace genesys + +#endif diff --git a/backend/genesys/enums.cpp b/backend/genesys/enums.cpp new file mode 100644 index 0000000..f515cfd --- /dev/null +++ b/backend/genesys/enums.cpp @@ -0,0 +1,131 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "enums.h" +#include "genesys.h" +#include + +namespace genesys { + +const char* scan_method_to_option_string(ScanMethod method) +{ + switch (method) { + case ScanMethod::FLATBED: return STR_FLATBED; + case ScanMethod::TRANSPARENCY: return STR_TRANSPARENCY_ADAPTER; + case ScanMethod::TRANSPARENCY_INFRARED: return STR_TRANSPARENCY_ADAPTER_INFRARED; + } + throw SaneException("Unknown scan method %d", static_cast(method)); +} + +ScanMethod option_string_to_scan_method(const std::string& str) +{ + if (str == STR_FLATBED) { + return ScanMethod::FLATBED; + } else if (str == STR_TRANSPARENCY_ADAPTER) { + return ScanMethod::TRANSPARENCY; + } else if (str == STR_TRANSPARENCY_ADAPTER_INFRARED) { + return ScanMethod::TRANSPARENCY_INFRARED; + } + throw SaneException("Unknown scan method option %s", str.c_str()); +} + +const char* scan_color_mode_to_option_string(ScanColorMode mode) +{ + switch (mode) { + case ScanColorMode::COLOR_SINGLE_PASS: return SANE_VALUE_SCAN_MODE_COLOR; + case ScanColorMode::GRAY: return SANE_VALUE_SCAN_MODE_GRAY; + case ScanColorMode::HALFTONE: return SANE_VALUE_SCAN_MODE_HALFTONE; + case ScanColorMode::LINEART: return SANE_VALUE_SCAN_MODE_LINEART; + } + throw SaneException("Unknown scan mode %d", static_cast(mode)); +} + +ScanColorMode option_string_to_scan_color_mode(const std::string& str) +{ + if (str == SANE_VALUE_SCAN_MODE_COLOR) { + return ScanColorMode::COLOR_SINGLE_PASS; + } else if (str == SANE_VALUE_SCAN_MODE_GRAY) { + return ScanColorMode::GRAY; + } else if (str == SANE_VALUE_SCAN_MODE_HALFTONE) { + return ScanColorMode::HALFTONE; + } else if (str == SANE_VALUE_SCAN_MODE_LINEART) { + return ScanColorMode::LINEART; + } + throw SaneException("Unknown scan color mode %s", str.c_str()); +} + + +std::ostream& operator<<(std::ostream& out, ColorFilter mode) +{ + switch (mode) { + case ColorFilter::RED: out << "RED"; break; + case ColorFilter::GREEN: out << "GREEN"; break; + case ColorFilter::BLUE: out << "BLUE"; break; + case ColorFilter::NONE: out << "NONE"; break; + default: out << static_cast(mode); break; + } + return out; +} + +std::ostream& operator<<(std::ostream& out, StepType type) +{ + switch (type) { + case StepType::FULL: out << "1/1"; break; + case StepType::HALF: out << "1/2"; break; + case StepType::QUARTER: out << "1/4"; break; + case StepType::EIGHTH: out << "1/8"; break; + default: out << static_cast(type); break; + } + return out; +} + +std::ostream& operator<<(std::ostream& out, ScanFlag flags) +{ + StreamStateSaver state_saver{out}; + out << "0x" << std::hex << static_cast(flags); + return out; +} + +} // namespace genesys diff --git a/backend/genesys/enums.h b/backend/genesys/enums.h new file mode 100644 index 0000000..810c4ca --- /dev/null +++ b/backend/genesys/enums.h @@ -0,0 +1,530 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_ENUMS_H +#define BACKEND_GENESYS_ENUMS_H + +#include +#include "serialize.h" + +namespace genesys { + +enum class ScanMethod : unsigned { + // normal scan method + FLATBED = 0, + // scan using transparency adaptor + TRANSPARENCY = 1, + // scan using transparency adaptor via infrared channel + TRANSPARENCY_INFRARED = 2 +}; + +inline std::ostream& operator<<(std::ostream& out, ScanMethod mode) +{ + switch (mode) { + case ScanMethod::FLATBED: out << "FLATBED"; return out; + case ScanMethod::TRANSPARENCY: out << "TRANSPARENCY"; return out; + case ScanMethod::TRANSPARENCY_INFRARED: out << "TRANSPARENCY_INFRARED"; return out; + } + return out; +} + +inline void serialize(std::istream& str, ScanMethod& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, ScanMethod& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +const char* scan_method_to_option_string(ScanMethod method); +ScanMethod option_string_to_scan_method(const std::string& str); + +enum class ScanColorMode : unsigned { + LINEART = 0, + HALFTONE, + GRAY, + COLOR_SINGLE_PASS +}; + +inline std::ostream& operator<<(std::ostream& out, ScanColorMode mode) +{ + switch (mode) { + case ScanColorMode::LINEART: out << "LINEART"; return out; + case ScanColorMode::HALFTONE: out << "HALFTONE"; return out; + case ScanColorMode::GRAY: out << "GRAY"; return out; + case ScanColorMode::COLOR_SINGLE_PASS: out << "COLOR_SINGLE_PASS"; return out; + } + return out; +} + +inline void serialize(std::istream& str, ScanColorMode& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, ScanColorMode& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +const char* scan_color_mode_to_option_string(ScanColorMode mode); +ScanColorMode option_string_to_scan_color_mode(const std::string& str); + + +enum class ScanHeadId : unsigned { + NONE = 0, + PRIMARY = 1 << 0, + SECONDARY = 1 << 1, + ALL = PRIMARY | SECONDARY, +}; + +inline ScanHeadId operator|(ScanHeadId left, ScanHeadId right) +{ + return static_cast(static_cast(left) | static_cast(right)); +} + +inline ScanHeadId operator&(ScanHeadId left, ScanHeadId right) +{ + return static_cast(static_cast(left) & static_cast(right)); +} + + +enum class ColorFilter : unsigned { + RED = 0, + GREEN, + BLUE, + NONE +}; + +std::ostream& operator<<(std::ostream& out, ColorFilter mode); + +inline void serialize(std::istream& str, ColorFilter& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, ColorFilter& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +enum class ColorOrder +{ + RGB, + GBR, + BGR, +}; + +/* Enum value naming conventions: + Full name must be included with the following exceptions: + + Canon scanners omit "Canoscan" if present +*/ +enum class ModelId : unsigned +{ + UNKNOWN = 0, + CANON_4400F, + CANON_5600F, + CANON_8400F, + CANON_8600F, + CANON_IMAGE_FORMULA_101, + CANON_LIDE_50, + CANON_LIDE_60, + CANON_LIDE_80, + CANON_LIDE_100, + CANON_LIDE_110, + CANON_LIDE_120, + CANON_LIDE_200, + CANON_LIDE_210, + CANON_LIDE_220, + CANON_LIDE_700F, + DCT_DOCKETPORT_487, + HP_SCANJET_2300C, + HP_SCANJET_2400C, + HP_SCANJET_3670, + HP_SCANJET_4850C, + HP_SCANJET_G4010, + HP_SCANJET_G4050, + HP_SCANJET_N6310, + MEDION_MD5345, + PANASONIC_KV_SS080, + PENTAX_DSMOBILE_600, + PLUSTEK_OPTICBOOK_3800, + PLUSTEK_OPTICFILM_7200I, + PLUSTEK_OPTICFILM_7300, + PLUSTEK_OPTICFILM_7500I, + PLUSTEK_OPTICPRO_3600, + PLUSTEK_OPTICPRO_ST12, + PLUSTEK_OPTICPRO_ST24, + SYSCAN_DOCKETPORT_465, + SYSCAN_DOCKETPORT_467, + SYSCAN_DOCKETPORT_485, + SYSCAN_DOCKETPORT_665, + SYSCAN_DOCKETPORT_685, + UMAX_ASTRA_4500, + VISIONEER_7100, + VISIONEER_ROADWARRIOR, + VISIONEER_STROBE_XP100_REVISION3, + VISIONEER_STROBE_XP200, + VISIONEER_STROBE_XP300, + XEROX_2400, + XEROX_TRAVELSCANNER_100, +}; + +enum class SensorId : unsigned +{ + UNKNOWN = 0, + CCD_5345, + CCD_CANON_4400F, + CCD_CANON_8400F, + CCD_CANON_8600F, + CCD_DP665, + CCD_DP685, + CCD_DSMOBILE600, + CCD_G4050, + CCD_HP2300, + CCD_HP2400, + CCD_HP3670, + CCD_HP_N6310, + CCD_HP_4850C, + CCD_IMG101, + CCD_KVSS080, + CCD_PLUSTEK_OPTICBOOK_3800, + CCD_PLUSTEK_OPTICFILM_7200I, + CCD_PLUSTEK_OPTICFILM_7300, + CCD_PLUSTEK_OPTICFILM_7500I, + CCD_PLUSTEK_OPTICPRO_3600, + CCD_ROADWARRIOR, + CCD_ST12, // SONY ILX548: 5340 Pixel ??? + CCD_ST24, // SONY ILX569: 10680 Pixel ??? + CCD_UMAX, + CCD_XP300, + CIS_CANON_LIDE_35, + CIS_CANON_LIDE_80, + CIS_CANON_LIDE_100, + CIS_CANON_LIDE_110, + CIS_CANON_LIDE_120, + CIS_CANON_LIDE_200, + CIS_CANON_LIDE_210, + CIS_CANON_LIDE_220, + CIS_CANON_LIDE_700F, + CIS_XP200, +}; + +inline void serialize(std::istream& str, SensorId& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, SensorId& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + + +enum class AdcId : unsigned +{ + UNKNOWN = 0, + AD_XP200, + CANON_LIDE_35, + CANON_LIDE_80, + CANON_LIDE_110, + CANON_LIDE_120, + CANON_LIDE_200, + CANON_LIDE_700F, + CANON_4400F, + CANON_8400F, + CANON_8600F, + G4050, + IMG101, + KVSS080, + PLUSTEK_OPTICBOOK_3800, + PLUSTEK_OPTICFILM_7200I, + PLUSTEK_OPTICFILM_7300, + PLUSTEK_OPTICFILM_7500I, + PLUSTEK_OPTICPRO_3600, + WOLFSON_5345, + WOLFSON_DSM600, + WOLFSON_HP2300, + WOLFSON_HP2400, + WOLFSON_HP3670, + WOLFSON_ST12, + WOLFSON_ST24, + WOLFSON_UMAX, + WOLFSON_XP300, +}; + +inline void serialize(std::istream& str, AdcId& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, AdcId& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +enum class GpioId : unsigned +{ + UNKNOWN = 0, + CANON_LIDE_35, + CANON_LIDE_80, + CANON_LIDE_110, + CANON_LIDE_120, + CANON_LIDE_200, + CANON_LIDE_210, + CANON_LIDE_700F, + CANON_4400F, + CANON_8400F, + CANON_8600F, + DP665, + DP685, + G4050, + HP2300, + HP2400, + HP3670, + HP_N6310, + IMG101, + KVSS080, + MD_5345, + PLUSTEK_OPTICBOOK_3800, + PLUSTEK_OPTICFILM_7200I, + PLUSTEK_OPTICFILM_7300, + PLUSTEK_OPTICFILM_7500I, + PLUSTEK_OPTICPRO_3600, + ST12, + ST24, + UMAX, + XP200, + XP300, +}; + +enum class MotorId : unsigned +{ + UNKNOWN = 0, + CANON_LIDE_100, + CANON_LIDE_110, + CANON_LIDE_120, + CANON_LIDE_200, + CANON_LIDE_210, + CANON_LIDE_35, + CANON_LIDE_700, + CANON_LIDE_80, + CANON_4400F, + CANON_8400F, + CANON_8600F, + DP665, + DSMOBILE_600, + G4050, + HP2300, + HP2400, + HP3670, + IMG101, + KVSS080, + MD_5345, + PLUSTEK_OPTICBOOK_3800, + PLUSTEK_OPTICFILM_7200I, + PLUSTEK_OPTICFILM_7300, + PLUSTEK_OPTICFILM_7500I, + PLUSTEK_OPTICPRO_3600, + ROADWARRIOR, + ST24, + UMAX, + XP200, + XP300, +}; + +enum class StepType : unsigned +{ + FULL = 0, + HALF = 1, + QUARTER = 2, + EIGHTH = 3, +}; + +std::ostream& operator<<(std::ostream& out, StepType type); + +inline bool operator<(StepType lhs, StepType rhs) +{ + return static_cast(lhs) < static_cast(rhs); +} +inline bool operator<=(StepType lhs, StepType rhs) +{ + return static_cast(lhs) <= static_cast(rhs); +} +inline bool operator>(StepType lhs, StepType rhs) +{ + return static_cast(lhs) > static_cast(rhs); +} +inline bool operator>=(StepType lhs, StepType rhs) +{ + return static_cast(lhs) >= static_cast(rhs); +} + +enum class AsicType : unsigned +{ + UNKNOWN = 0, + GL646, + GL841, + GL843, + GL845, + GL846, + GL847, + GL124, +}; + + +enum class ScanFlag : unsigned +{ + NONE = 0, + SINGLE_LINE = 1 << 0, + DISABLE_SHADING = 1 << 1, + DISABLE_GAMMA = 1 << 2, + DISABLE_BUFFER_FULL_MOVE = 1 << 3, + IGNORE_LINE_DISTANCE = 1 << 4, + DISABLE_LAMP = 1 << 5, + CALIBRATION = 1 << 6, + FEEDING = 1 << 7, + USE_XPA = 1 << 8, + ENABLE_LEDADD = 1 << 9, + USE_XCORRECTION = 1 << 10, + REVERSE = 1 << 11, +}; + +inline ScanFlag operator|(ScanFlag left, ScanFlag right) +{ + return static_cast(static_cast(left) | static_cast(right)); +} + +inline ScanFlag& operator|=(ScanFlag& left, ScanFlag right) +{ + left = left | right; + return left; +} + +inline ScanFlag operator&(ScanFlag left, ScanFlag right) +{ + return static_cast(static_cast(left) & static_cast(right)); +} + +inline bool has_flag(ScanFlag flags, ScanFlag which) +{ + return (flags & which) == which; +} + +inline void serialize(std::istream& str, ScanFlag& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, ScanFlag& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +std::ostream& operator<<(std::ostream& out, ScanFlag flags); + + + +enum class MotorFlag : unsigned +{ + NONE = 0, + AUTO_GO_HOME = 1 << 0, + DISABLE_BUFFER_FULL_MOVE = 1 << 2, + FEED = 1 << 3, + USE_XPA = 1 << 4, + REVERSE = 1 << 5, +}; + +inline MotorFlag operator|(MotorFlag left, MotorFlag right) +{ + return static_cast(static_cast(left) | static_cast(right)); +} + +inline MotorFlag& operator|=(MotorFlag& left, MotorFlag right) +{ + left = left | right; + return left; +} + +inline MotorFlag operator&(MotorFlag left, MotorFlag right) +{ + return static_cast(static_cast(left) & static_cast(right)); +} + +inline bool has_flag(MotorFlag flags, MotorFlag which) +{ + return (flags & which) == which; +} + + +enum class Direction : unsigned +{ + FORWARD = 0, + BACKWARD = 1 +}; + + +} // namespace genesys + +#endif // BACKEND_GENESYS_ENUMS_H diff --git a/backend/genesys/error.cpp b/backend/genesys/error.cpp new file mode 100644 index 0000000..6c921c1 --- /dev/null +++ b/backend/genesys/error.cpp @@ -0,0 +1,215 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "error.h" +#include + +namespace genesys { + +extern "C" void sanei_debug_msg(int level, int max_level, const char *be, const char *fmt, + std::va_list ap); + +#if (defined(__GNUC__) || defined(__CLANG__)) && (defined(__linux__) || defined(__APPLE__)) +extern "C" char* __cxa_get_globals(); +#endif + +static unsigned num_uncaught_exceptions() +{ +#if __cplusplus >= 201703L + int count = std::uncaught_exceptions(); + return count >= 0 ? count : 0; +#elif (defined(__GNUC__) || defined(__CLANG__)) && (defined(__linux__) || defined(__APPLE__)) + // the format of the __cxa_eh_globals struct is enshrined into the Itanium C++ ABI and it's + // very unlikely we'll get issues referencing it directly + char* cxa_eh_globals_ptr = __cxa_get_globals(); + return *reinterpret_cast(cxa_eh_globals_ptr + sizeof(void*)); +#else + return std::uncaught_exception() ? 1 : 0; +#endif +} + +SaneException::SaneException(SANE_Status status) : status_(status) +{ + set_msg(); +} + +SaneException::SaneException(SANE_Status status, const char* format, ...) : status_(status) +{ + std::va_list args; + va_start(args, format); + set_msg(format, args); + va_end(args); +} + +SaneException::SaneException(const char* format, ...) : status_(SANE_STATUS_INVAL) +{ + std::va_list args; + va_start(args, format); + set_msg(format, args); + va_end(args); +} + +SANE_Status SaneException::status() const +{ + return status_; +} + +const char* SaneException::what() const noexcept +{ + return msg_.c_str(); +} + +void SaneException::set_msg() +{ + const char* status_msg = sane_strstatus(status_); + std::size_t status_msg_len = std::strlen(status_msg); + msg_.reserve(status_msg_len); + msg_ = status_msg; +} + +void SaneException::set_msg(const char* format, std::va_list vlist) +{ + const char* status_msg = sane_strstatus(status_); + std::size_t status_msg_len = std::strlen(status_msg); + + std::va_list vlist2; + va_copy(vlist2, vlist); + int msg_len = std::vsnprintf(nullptr, 0, format, vlist2); + va_end(vlist2); + + if (msg_len < 0) { + const char* formatting_error_msg = "(error formatting arguments)"; + msg_.reserve(std::strlen(formatting_error_msg) + 3 + status_msg_len); + msg_ = formatting_error_msg; + msg_ += " : "; + msg_ += status_msg; + return; + } + + msg_.reserve(msg_len + status_msg_len + 3); + msg_.resize(msg_len + 1, ' '); + std::vsnprintf(&msg_[0], msg_len + 1, format, vlist); + msg_.resize(msg_len, ' '); + + msg_ += " : "; + msg_ += status_msg; +} + +DebugMessageHelper::DebugMessageHelper(const char* func) +{ + func_ = func; + num_exceptions_on_enter_ = num_uncaught_exceptions(); + msg_[0] = '\0'; + DBG(DBG_proc, "%s: start\n", func_); +} + +DebugMessageHelper::DebugMessageHelper(const char* func, const char* format, ...) +{ + func_ = func; + num_exceptions_on_enter_ = num_uncaught_exceptions(); + msg_[0] = '\0'; + DBG(DBG_proc, "%s: start\n", func_); + DBG(DBG_proc, "%s: ", func_); + + std::va_list args; + va_start(args, format); + sanei_debug_msg(DBG_proc, DBG_LEVEL, STRINGIFY(BACKEND_NAME), format, args); + va_end(args); + DBG(DBG_proc, "\n"); +} + + +DebugMessageHelper::~DebugMessageHelper() +{ + if (num_exceptions_on_enter_ < num_uncaught_exceptions()) { + if (msg_[0] != '\0') { + DBG(DBG_error, "%s: failed during %s\n", func_, msg_); + } else { + DBG(DBG_error, "%s: failed\n", func_); + } + } else { + DBG(DBG_proc, "%s: completed\n", func_); + } +} + +void DebugMessageHelper::vstatus(const char* format, ...) +{ + std::va_list args; + va_start(args, format); + std::vsnprintf(msg_, MAX_BUF_SIZE, format, args); + va_end(args); +} + +void DebugMessageHelper::log(unsigned level, const char* msg) +{ + DBG(level, "%s: %s\n", func_, msg); +} + +void DebugMessageHelper::vlog(unsigned level, const char* format, ...) +{ + std::string msg; + + std::va_list args; + + va_start(args, format); + int msg_len = std::vsnprintf(nullptr, 0, format, args); + va_end(args); + + if (msg_len < 0) { + DBG(level, "%s: error formatting error message: %s\n", func_, format); + return; + } + msg.resize(msg_len + 1, ' '); + + va_start(args, format); + std::vsnprintf(&msg.front(), msg.size(), format, args); + va_end(args); + + msg.resize(msg_len, ' '); // strip the null character + + DBG(level, "%s: %s\n", func_, msg.c_str()); +} + +} // namespace genesys diff --git a/backend/genesys/error.h b/backend/genesys/error.h new file mode 100644 index 0000000..5aba8cf --- /dev/null +++ b/backend/genesys/error.h @@ -0,0 +1,199 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_ERROR_H +#define BACKEND_GENESYS_ERROR_H + +#include "../include/sane/config.h" +#include "../include/sane/sane.h" +#include "../include/sane/sanei_backend.h" + +#include +#include +#include +#include +#include + +#define DBG_error0 0 /* errors/warnings printed even with devuglevel 0 */ +#define DBG_error 1 /* fatal errors */ +#define DBG_init 2 /* initialization and scanning time messages */ +#define DBG_warn 3 /* warnings and non-fatal errors */ +#define DBG_info 4 /* informational messages */ +#define DBG_proc 5 /* starting/finishing functions */ +#define DBG_io 6 /* io functions */ +#define DBG_io2 7 /* io functions that are called very often */ +#define DBG_data 8 /* log image data */ + +namespace genesys { + +class SaneException : public std::exception { +public: + SaneException(SANE_Status status); + SaneException(SANE_Status status, const char* format, ...) + #ifdef __GNUC__ + __attribute__((format(printf, 3, 4))) + #endif + ; + + SaneException(const char* format, ...) + #ifdef __GNUC__ + __attribute__((format(printf, 2, 3))) + #endif + ; + + SANE_Status status() const; + const char* what() const noexcept override; + +private: + + void set_msg(); + void set_msg(const char* format, std::va_list vlist); + + std::string msg_; + SANE_Status status_; +}; + +// call a function and throw an exception on error +#define TIE(function) \ + do { \ + SANE_Status tmp_status = function; \ + if (tmp_status != SANE_STATUS_GOOD) { \ + throw ::genesys::SaneException(tmp_status); \ + } \ + } while (false) + +class DebugMessageHelper { +public: + static constexpr unsigned MAX_BUF_SIZE = 120; + + DebugMessageHelper(const char* func); + DebugMessageHelper(const char* func, const char* format, ...) + #ifdef __GNUC__ + __attribute__((format(printf, 3, 4))) + #endif + ; + + ~DebugMessageHelper(); + + void status(const char* msg) { vstatus("%s", msg); } + void vstatus(const char* format, ...) + #ifdef __GNUC__ + __attribute__((format(printf, 2, 3))) + #endif + ; + + void clear() { msg_[0] = '\n'; } + + void log(unsigned level, const char* msg); + void vlog(unsigned level, const char* format, ...) + #ifdef __GNUC__ + __attribute__((format(printf, 3, 4))) + #endif + ; + +private: + const char* func_ = nullptr; + char msg_[MAX_BUF_SIZE]; + unsigned num_exceptions_on_enter_ = 0; +}; + + +#if defined(__GNUC__) || defined(__clang__) +#define GENESYS_CURRENT_FUNCTION __PRETTY_FUNCTION__ +#elif defined(__FUNCSIG__) +#define GENESYS_CURRENT_FUNCTION __FUNCSIG__ +#else +#define GENESYS_CURRENT_FUNCTION __func__ +#endif + +#define DBG_HELPER(var) DebugMessageHelper var(GENESYS_CURRENT_FUNCTION) +#define DBG_HELPER_ARGS(var, ...) DebugMessageHelper var(GENESYS_CURRENT_FUNCTION, __VA_ARGS__) + +template +SANE_Status wrap_exceptions_to_status_code(const char* func, F&& function) +{ + try { + function(); + return SANE_STATUS_GOOD; + } catch (const SaneException& exc) { + DBG(DBG_error, "%s: got error: %s\n", func, exc.what()); + return exc.status(); + } catch (const std::bad_alloc& exc) { + (void) exc; + DBG(DBG_error, "%s: failed to allocate memory\n", func); + return SANE_STATUS_NO_MEM; + } catch (const std::exception& exc) { + DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what()); + return SANE_STATUS_INVAL; + } catch (...) { + DBG(DBG_error, "%s: got unknown uncaught exception\n", func); + return SANE_STATUS_INVAL; + } +} + +template +void catch_all_exceptions(const char* func, F&& function) +{ + try { + function(); + } catch (const SaneException& exc) { + DBG(DBG_error, "%s: got exception: %s\n", func, exc.what()); + } catch (const std::bad_alloc& exc) { + DBG(DBG_error, "%s: got exception: could not allocate memory: %s\n", func, exc.what()); + } catch (const std::exception& exc) { + DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what()); + } catch (...) { + DBG(DBG_error, "%s: got unknown uncaught exception\n", func); + } +} + +inline void wrap_status_code_to_exception(SANE_Status status) +{ + if (status == SANE_STATUS_GOOD) + return; + throw SaneException(status); +} + +} // namespace genesys + +#endif // BACKEND_GENESYS_ERROR_H diff --git a/backend/genesys/fwd.h b/backend/genesys/fwd.h new file mode 100644 index 0000000..2d55f98 --- /dev/null +++ b/backend/genesys/fwd.h @@ -0,0 +1,132 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_FWD_H +#define BACKEND_GENESYS_FWD_H + +namespace genesys { + +// buffer.h +struct Genesys_Buffer; + +// calibration.h +struct Genesys_Calibration_Cache; + +// command_set.h +class CommandSet; + +// device.h +class FixedFloat; +struct Genesys_Gpo; +struct MethodResolutions; +struct Genesys_Model; +struct Genesys_Device; + +// error.h +class DebugMessageHelper; +class SaneException; + +// genesys.h +class GenesysButton; +struct Genesys_Scanner; + +// image.h +class Image; + +// image_buffer.h +class ImageBuffer; +class FakeBufferModel; +class ImageBufferGenesysUsb; + +// image_pipeline.h +class ImagePipelineNode; +// ImagePipelineNode* skipped +class ImagePipelineStack; + +// image_pixel.h +struct Pixel; +struct RawPixel; + +// low.h +struct Genesys_USB_Device_Entry; +struct Motor_Profile; + +// motor.h +struct Genesys_Motor; +struct MotorSlope; +struct MotorSlopeTable; + +// register.h +class Genesys_Register_Set; +struct GenesysRegisterSetState; + +// row_buffer.h +class RowBuffer; + +// usb_device.h +class IUsbDevice; +class UsbDevice; + +// scanner_interface.h +class ScannerInterface; +class ScannerInterfaceUsb; +class TestScannerInterface; + +// sensor.h +class ResolutionFilter; +struct GenesysFrontendLayout; +struct Genesys_Frontend; +struct SensorExposure; +struct Genesys_Sensor; + +// settings.h +struct Genesys_Settings; +struct SetupParams; +struct ScanSession; + +// test_usb_device.h +class TestUsbDevice; + +} // namespace genesys + +#endif diff --git a/backend/genesys/genesys.cpp b/backend/genesys/genesys.cpp new file mode 100644 index 0000000..7c25168 --- /dev/null +++ b/backend/genesys/genesys.cpp @@ -0,0 +1,6172 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003, 2004 Henning Meier-Geinitz + Copyright (C) 2004, 2005 Gerhard Jaeger + Copyright (C) 2004-2016 Stéphane Voltz + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2006 Laurent Charpentier + Copyright (C) 2007 Luke + Copyright (C) 2010 Chris Berry and Michael Rickmann + for Plustek Opticbook 3600 support + + Dynamic rasterization code was taken from the epjistsu backend by + m. allan noah + + Software processing for deskew, crop and dspeckle are inspired by allan's + noah work in the fujitsu backend + + 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. +*/ + +/* + * SANE backend for Genesys Logic GL646/GL841/GL842/GL843/GL846/GL847/GL124 based scanners + */ + +#define DEBUG_NOT_STATIC + +#include "genesys.h" +#include "conv.h" +#include "gl124_registers.h" +#include "gl841_registers.h" +#include "gl843_registers.h" +#include "gl846_registers.h" +#include "gl847_registers.h" +#include "usb_device.h" +#include "utilities.h" +#include "scanner_interface_usb.h" +#include "test_scanner_interface.h" +#include "test_settings.h" +#include "../include/sane/sanei_config.h" +#include "../include/sane/sanei_magic.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifndef SANE_GENESYS_API_LINKAGE +#define SANE_GENESYS_API_LINKAGE extern "C" +#endif + +namespace genesys { + +// Data that we allocate to back SANE_Device objects in s_sane_devices +struct SANE_Device_Data +{ + std::string name; +}; + +namespace { + StaticInit> s_scanners; + StaticInit> s_sane_devices; + StaticInit> s_sane_devices_data; + StaticInit> s_sane_devices_ptrs; + StaticInit> s_devices; + + // Maximum time for lamp warm-up + constexpr unsigned WARMUP_TIME = 65; +} // namespace + +static SANE_String_Const mode_list[] = { + SANE_VALUE_SCAN_MODE_COLOR, + SANE_VALUE_SCAN_MODE_GRAY, + /* SANE_TITLE_HALFTONE, currently unused */ + SANE_VALUE_SCAN_MODE_LINEART, + nullptr +}; + +static SANE_String_Const color_filter_list[] = { + SANE_I18N ("Red"), + SANE_I18N ("Green"), + SANE_I18N ("Blue"), + nullptr +}; + +static SANE_String_Const cis_color_filter_list[] = { + SANE_I18N ("Red"), + SANE_I18N ("Green"), + SANE_I18N ("Blue"), + SANE_I18N ("None"), + nullptr +}; + +static SANE_Range swdespeck_range = { + 1, + 9, + 1 +}; + +static SANE_Range time_range = { + 0, /* minimum */ + 60, /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range u12_range = { + 0, /* minimum */ + 4095, /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range u14_range = { + 0, /* minimum */ + 16383, /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range u16_range = { + 0, /* minimum */ + 65535, /* maximum */ + 0 /* quantization */ +}; + +static const SANE_Range percentage_range = { + SANE_FIX (0), /* minimum */ + SANE_FIX (100), /* maximum */ + SANE_FIX (1) /* quantization */ +}; + +static const SANE_Range threshold_curve_range = { + 0, /* minimum */ + 127, /* maximum */ + 1 /* quantization */ +}; + +/** + * range for brightness and contrast + */ +static const SANE_Range enhance_range = { + -100, /* minimum */ + 100, /* maximum */ + 1 /* quantization */ +}; + +/** + * range for expiration time + */ +static const SANE_Range expiration_range = { + -1, /* minimum */ + 30000, /* maximum */ + 1 /* quantization */ +}; + +const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + for (const auto& sensor : *s_sensors) { + if (dev->model->sensor_id == sensor.sensor_id) { + return sensor; + } + } + throw std::runtime_error("Given device does not have sensor defined"); +} + +Genesys_Sensor* find_sensor_impl(Genesys_Device* dev, unsigned dpi, unsigned channels, + ScanMethod scan_method) +{ + DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels, + static_cast(scan_method)); + for (auto& sensor : *s_sensors) { + if (dev->model->sensor_id == sensor.sensor_id && sensor.resolutions.matches(dpi) && + sensor.matches_channel_count(channels) && sensor.method == scan_method) + { + return &sensor; + } + } + return nullptr; +} + +bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels, + ScanMethod scan_method) +{ + DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels, + static_cast(scan_method)); + return find_sensor_impl(dev, dpi, channels, scan_method) != nullptr; +} + +const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels, + ScanMethod scan_method) +{ + DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels, + static_cast(scan_method)); + const auto* sensor = find_sensor_impl(dev, dpi, channels, scan_method); + if (sensor) + return *sensor; + throw std::runtime_error("Given device does not have sensor defined"); +} + +Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, unsigned dpi, + unsigned channels, + ScanMethod scan_method) +{ + DBG_HELPER_ARGS(dbg, "dpi: %d, channels: %d, scan_method: %d", dpi, channels, + static_cast(scan_method)); + auto* sensor = find_sensor_impl(dev, dpi, channels, scan_method); + if (sensor) + return *sensor; + throw std::runtime_error("Given device does not have sensor defined"); +} + + +std::vector> + sanei_genesys_find_sensors_all(Genesys_Device* dev, ScanMethod scan_method) +{ + DBG_HELPER_ARGS(dbg, "scan_method: %d", static_cast(scan_method)); + std::vector> ret; + for (const Genesys_Sensor& sensor : sanei_genesys_find_sensors_all_for_write(dev, scan_method)) { + ret.push_back(sensor); + } + return ret; +} + +std::vector> + sanei_genesys_find_sensors_all_for_write(Genesys_Device* dev, ScanMethod scan_method) +{ + DBG_HELPER_ARGS(dbg, "scan_method: %d", static_cast(scan_method)); + std::vector> ret; + for (auto& sensor : *s_sensors) { + if (dev->model->sensor_id == sensor.sensor_id && sensor.method == scan_method) { + ret.push_back(sensor); + } + } + return ret; +} + +void sanei_genesys_init_structs (Genesys_Device * dev) +{ + DBG_HELPER(dbg); + + bool gpo_ok = false; + bool motor_ok = false; + bool fe_ok = false; + + /* initialize the GPO data stuff */ + for (const auto& gpo : *s_gpo) { + if (dev->model->gpio_id == gpo.id) { + dev->gpo = gpo; + gpo_ok = true; + break; + } + } + + // initialize the motor data stuff + for (const auto& motor : *s_motors) { + if (dev->model->motor_id == motor.id) { + dev->motor = motor; + motor_ok = true; + break; + } + } + + for (const auto& frontend : *s_frontends) { + if (dev->model->adc_id == frontend.id) { + dev->frontend_initial = frontend; + dev->frontend = frontend; + fe_ok = true; + break; + } + } + + if (!motor_ok || !gpo_ok || !fe_ok) { + throw SaneException("bad description(s) for fe/gpo/motor=%d/%d/%d\n", + static_cast(dev->model->sensor_id), + static_cast(dev->model->gpio_id), + static_cast(dev->model->motor_id)); + } +} + +/* Generate slope table for motor movement */ +/** + * This function generates a slope table using the slope from the motor struct + * truncated at the given exposure time or step count, whichever comes first. + * The summed time of the acceleration steps is returned, and the + * number of accerelation steps is put into used_steps. + * + * @param dev Device struct + * @param slope_table Table to write to + * @param step_type Generate table for this step_type. 0=>full, 1=>half, + * 2=>quarter + * @param exposure_time Minimum exposure time of a scan line + * @param yres Resolution of a scan line + * @param used_steps Final number of steps is stored here + * @return Motor slope table + * @note all times in pixel time + */ +MotorSlopeTable sanei_genesys_create_slope_table3(AsicType asic_type, const Genesys_Motor& motor, + StepType step_type, int exposure_time, + unsigned yres) +{ + unsigned target_speed_w = (exposure_time * yres) / motor.base_ydpi; + + return create_slope_table(motor.get_slope(step_type), target_speed_w, step_type, 1, 1, + get_slope_table_max_size(asic_type)); +} + +/** @brief computes gamma table + * Generates a gamma table of the given length within 0 and the given + * maximum value + * @param gamma_table gamma table to fill + * @param size size of the table + * @param maximum value allowed for gamma + * @param gamma_max maximum gamma value + * @param gamma gamma to compute values + * @return a gamma table filled with the computed values + * */ +void +sanei_genesys_create_gamma_table (std::vector& gamma_table, int size, + float maximum, float gamma_max, float gamma) +{ + gamma_table.clear(); + gamma_table.resize(size, 0); + + int i; + float value; + + DBG(DBG_proc, "%s: size = %d, ""maximum = %g, gamma_max = %g, gamma = %g\n", __func__, size, + maximum, gamma_max, gamma); + for (i = 0; i < size; i++) + { + value = static_cast(gamma_max * std::pow(static_cast(i) / size, 1.0 / gamma)); + if (value > maximum) { + value = maximum; + } + gamma_table[i] = static_cast(value); + } + DBG(DBG_proc, "%s: completed\n", __func__); +} + +void sanei_genesys_create_default_gamma_table(Genesys_Device* dev, + std::vector& gamma_table, float gamma) +{ + int size = 0; + int max = 0; + if (dev->model->asic_type == AsicType::GL646) { + if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) { + size = 16384; + } else { + size = 4096; + } + max = size - 1; + } else if (dev->model->asic_type == AsicType::GL124 || + dev->model->asic_type == AsicType::GL846 || + dev->model->asic_type == AsicType::GL847) { + size = 257; + max = 65535; + } else { + size = 256; + max = 65535; + } + sanei_genesys_create_gamma_table(gamma_table, size, max, max, gamma); +} + +/* computes the exposure_time on the basis of the given vertical dpi, + the number of pixels the ccd needs to send, + the step_type and the corresponding maximum speed from the motor struct */ +/* + Currently considers maximum motor speed at given step_type, minimum + line exposure needed for conversion and led exposure time. + + TODO: Should also consider maximum transfer rate: ~6.5MB/s. + Note: The enhance option of the scanners does _not_ help. It only halves + the amount of pixels transfered. + */ +SANE_Int sanei_genesys_exposure_time2(Genesys_Device * dev, float ydpi, + StepType step_type, int endpixel, int exposure_by_led) +{ + int exposure_by_ccd = endpixel + 32; + unsigned max_speed_motor_w = dev->motor.get_slope(step_type).max_speed_w; + int exposure_by_motor = static_cast((max_speed_motor_w * dev->motor.base_ydpi) / ydpi); + + int exposure = exposure_by_ccd; + + if (exposure < exposure_by_motor) + exposure = exposure_by_motor; + + if (exposure < exposure_by_led && dev->model->is_cis) + exposure = exposure_by_led; + + DBG(DBG_info, "%s: ydpi=%d, step=%d, endpixel=%d led=%d => exposure=%d\n", __func__, + static_cast(ydpi), static_cast(step_type), endpixel, + exposure_by_led, exposure); + return exposure; +} + + +/* Sends a block of shading information to the scanner. + The data is placed at address 0x0000 for color mode, gray mode and + unconditionally for the following CCD chips: HP2300, HP2400 and HP5345 + In the other cases (lineart, halftone on ccd chips not mentioned) the + addresses are 0x2a00 for dpihw==0, 0x5500 for dpihw==1 and 0xa800 for + dpihw==2. //Note: why this? + + The data needs to be of size "size", and in little endian byte order. + */ +static void genesys_send_offset_and_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + uint8_t* data, int size) +{ + DBG_HELPER_ARGS(dbg, "(size = %d)", size); + int dpihw; + int start_address; + + /* ASIC higher than gl843 doesn't have register 2A/2B, so we route to + * a per ASIC shading data loading function if available. + * It is also used for scanners using SHDAREA */ + if (dev->cmd_set->has_send_shading_data()) { + dev->cmd_set->send_shading_data(dev, sensor, data, size); + return; + } + + /* gl646, gl84[123] case */ + dpihw = dev->reg.get8(0x05) >> 6; + + /* TODO invert the test so only the 2 models behaving like that are + * tested instead of adding all the others */ + /* many scanners send coefficient for lineart/gray like in color mode */ + if ((dev->settings.scan_mode == ScanColorMode::LINEART || + dev->settings.scan_mode == ScanColorMode::HALFTONE) + && dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICBOOK_3800 + && dev->model->sensor_id != SensorId::CCD_KVSS080 + && dev->model->sensor_id != SensorId::CCD_G4050 + && dev->model->sensor_id != SensorId::CCD_HP_4850C + && dev->model->sensor_id != SensorId::CCD_CANON_4400F + && dev->model->sensor_id != SensorId::CCD_CANON_8400F + && dev->model->sensor_id != SensorId::CCD_CANON_8600F + && dev->model->sensor_id != SensorId::CCD_DSMOBILE600 + && dev->model->sensor_id != SensorId::CCD_XP300 + && dev->model->sensor_id != SensorId::CCD_DP665 + && dev->model->sensor_id != SensorId::CCD_DP685 + && dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80 + && dev->model->sensor_id != SensorId::CCD_ROADWARRIOR + && dev->model->sensor_id != SensorId::CCD_HP2300 + && dev->model->sensor_id != SensorId::CCD_HP2400 + && dev->model->sensor_id != SensorId::CCD_HP3670 + && dev->model->sensor_id != SensorId::CCD_5345) /* lineart, halftone */ + { + if (dpihw == 0) { /* 600 dpi */ + start_address = 0x02a00; + } else if (dpihw == 1) { /* 1200 dpi */ + start_address = 0x05500; + } else if (dpihw == 2) { /* 2400 dpi */ + start_address = 0x0a800; + } else { /* reserved */ + throw SaneException("unknown dpihw"); + } + } + else { // color + start_address = 0x00; + } + + dev->interface->write_buffer(0x3c, start_address, data, size); +} + +// ? +void sanei_genesys_init_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + int pixels_per_line) +{ + DBG_HELPER_ARGS(dbg, "pixels_per_line: %d", pixels_per_line); + + if (dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE) { + return; + } + + int channels; + int i; + + if (dev->cmd_set->has_send_shading_data()) { + return; + } + + DBG(DBG_proc, "%s (pixels_per_line = %d)\n", __func__, pixels_per_line); + + // BUG: GRAY shouldn't probably be in the if condition below. Discovered when refactoring + if (dev->settings.scan_mode == ScanColorMode::GRAY || + dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + channels = 3; + } else { + channels = 1; + } + + // 16 bit black, 16 bit white + std::vector shading_data(pixels_per_line * 4 * channels, 0); + + uint8_t* shading_data_ptr = shading_data.data(); + + for (i = 0; i < pixels_per_line * channels; i++) + { + *shading_data_ptr++ = 0x00; /* dark lo */ + *shading_data_ptr++ = 0x00; /* dark hi */ + *shading_data_ptr++ = 0x00; /* white lo */ + *shading_data_ptr++ = 0x40; /* white hi -> 0x4000 */ + } + + genesys_send_offset_and_shading(dev, sensor, shading_data.data(), + pixels_per_line * 4 * channels); +} + + +// Find the position of the reference point: takes gray level 8 bits data and find +// first CCD usable pixel and top of scanning area +void sanei_genesys_search_reference_point(Genesys_Device* dev, Genesys_Sensor& sensor, + const uint8_t* src_data, int start_pixel, int dpi, + int width, int height) +{ + DBG_HELPER(dbg); + int x, y; + int current, left, top = 0; + int size, count; + int level = 80; /* edge threshold level */ + + // sanity check + if ((width < 3) || (height < 3)) { + throw SaneException("invalid width or height"); + } + + /* transformed image data */ + size = width * height; + std::vector image2(size, 0); + std::vector image(size, 0); + + /* laplace filter to denoise picture */ + std::memcpy(image2.data(), src_data, size); + std::memcpy(image.data(), src_data, size); // to initialize unprocessed part of the image buffer + + for (y = 1; y < height - 1; y++) { + for (x = 1; x < width - 1; x++) { + image[y * width + x] = + (image2[(y - 1) * width + x + 1] + 2 * image2[(y - 1) * width + x] + + image2[(y - 1) * width + x - 1] + 2 * image2[y * width + x + 1] + + 4 * image2[y * width + x] + 2 * image2[y * width + x - 1] + + image2[(y + 1) * width + x + 1] + 2 * image2[(y + 1) * width + x] + + image2[(y + 1) * width + x - 1]) / 16; + } + } + + image2 = image; + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_laplace.pnm", image.data(), 8, 1, width, height); + + /* apply X direction sobel filter + -1 0 1 + -2 0 2 + -1 0 1 + and finds threshold level + */ + level = 0; + for (y = 2; y < height - 2; y++) { + for (x = 2; x < width - 2; x++) { + current = image2[(y - 1) * width + x + 1] - image2[(y - 1) * width + x - 1] + + 2 * image2[y * width + x + 1] - 2 * image2[y * width + x - 1] + + image2[(y + 1) * width + x + 1] - image2[(y + 1) * width + x - 1]; + if (current < 0) + current = -current; + if (current > 255) + current = 255; + image[y * width + x] = current; + if (current > level) + level = current; + } + } + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_xsobel.pnm", image.data(), 8, 1, width, height); + + /* set up detection level */ + level = level / 3; + + /* find left black margin first + todo: search top before left + we average the result of N searches */ + left = 0; + count = 0; + for (y = 2; y < 11; y++) + { + x = 8; + while ((x < width / 2) && (image[y * width + x] < level)) + { + image[y * width + x] = 255; + x++; + } + count++; + left += x; + } + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_detected-xsobel.pnm", image.data(), 8, 1, width, height); + left = left / count; + + // turn it in CCD pixel at full sensor optical resolution + sensor.ccd_start_xoffset = start_pixel + (left * sensor.optical_res) / dpi; + + /* find top edge by detecting black strip */ + /* apply Y direction sobel filter + -1 -2 -1 + 0 0 0 + 1 2 1 + */ + level = 0; + for (y = 2; y < height - 2; y++) { + for (x = 2; x < width - 2; x++) { + current = -image2[(y - 1) * width + x + 1] - 2 * image2[(y - 1) * width + x] - + image2[(y - 1) * width + x - 1] + image2[(y + 1) * width + x + 1] + + 2 * image2[(y + 1) * width + x] + image2[(y + 1) * width + x - 1]; + if (current < 0) + current = -current; + if (current > 255) + current = 255; + image[y * width + x] = current; + if (current > level) + level = current; + } + } + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_ysobel.pnm", image.data(), 8, 1, width, height); + + /* set up detection level */ + level = level / 3; + + /* search top of horizontal black stripe : TODO yet another flag */ + if (dev->model->sensor_id == SensorId::CCD_5345 + && dev->model->motor_id == MotorId::MD_5345) + { + top = 0; + count = 0; + for (x = width / 2; x < width - 1; x++) + { + y = 2; + while ((y < height) && (image[x + y * width] < level)) + { + image[y * width + x] = 255; + y++; + } + count++; + top += y; + } + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl_detected-ysobel.pnm", image.data(), 8, 1, width, height); + top = top / count; + + /* bottom of black stripe is of fixed witdh, this hardcoded value + * will be moved into device struct if more such values are needed */ + top += 10; + dev->model->y_offset_calib_white = (top * MM_PER_INCH) / dpi; + DBG(DBG_info, "%s: black stripe y_offset = %f mm \n", __func__, + dev->model->y_offset_calib_white.value()); + } + + /* find white corner in dark area : TODO yet another flag */ + if ((dev->model->sensor_id == SensorId::CCD_HP2300 && dev->model->motor_id == MotorId::HP2300) || + (dev->model->sensor_id == SensorId::CCD_HP2400 && dev->model->motor_id == MotorId::HP2400) || + (dev->model->sensor_id == SensorId::CCD_HP3670 && dev->model->motor_id == MotorId::HP3670)) + { + top = 0; + count = 0; + for (x = 10; x < 60; x++) + { + y = 2; + while ((y < height) && (image[x + y * width] < level)) + y++; + top += y; + count++; + } + top = top / count; + dev->model->y_offset_calib_white = (top * MM_PER_INCH) / dpi; + DBG(DBG_info, "%s: white corner y_offset = %f mm\n", __func__, + dev->model->y_offset_calib_white.value()); + } + + DBG(DBG_proc, "%s: ccd_start_xoffset = %d, left = %d, top = %d\n", __func__, + sensor.ccd_start_xoffset, left, top); +} + +namespace gl843 { + void gl843_park_xpa_lamp(Genesys_Device* dev); + void gl843_set_xpa_motor_power(Genesys_Device* dev, Genesys_Register_Set& regs, bool set); +} // namespace gl843 + +namespace gl124 { + void gl124_setup_scan_gpio(Genesys_Device* dev, int resolution); +} // namespace gl124 + +void scanner_clear_scan_and_feed_counts(Genesys_Device& dev) +{ + switch (dev.model->asic_type) { + case AsicType::GL843: { + dev.interface->write_register(gl843::REG_0x0D, + gl843::REG_0x0D_CLRLNCNT | gl843::REG_0x0D_CLRMCNT); + break; + } + case AsicType::GL845: + case AsicType::GL846: { + dev.interface->write_register(gl846::REG_0x0D, + gl846::REG_0x0D_CLRLNCNT | gl846::REG_0x0D_CLRMCNT); + break; + } + case AsicType::GL847:{ + dev.interface->write_register(gl847::REG_0x0D, + gl847::REG_0x0D_CLRLNCNT | gl847::REG_0x0D_CLRMCNT); + break; + } + case AsicType::GL124:{ + dev.interface->write_register(gl124::REG_0x0D, + gl124::REG_0x0D_CLRLNCNT | gl124::REG_0x0D_CLRMCNT); + break; + } + default: + throw SaneException("Unsupported asic type"); + } +} + +void scanner_clear_scan_and_feed_counts2(Genesys_Device& dev) +{ + // FIXME: switch to scanner_clear_scan_and_feed_counts when updating tests + switch (dev.model->asic_type) { + case AsicType::GL843: { + dev.interface->write_register(gl843::REG_0x0D, gl843::REG_0x0D_CLRLNCNT); + dev.interface->write_register(gl843::REG_0x0D, gl843::REG_0x0D_CLRMCNT); + break; + } + case AsicType::GL845: + case AsicType::GL846: { + dev.interface->write_register(gl846::REG_0x0D, gl846::REG_0x0D_CLRLNCNT); + dev.interface->write_register(gl846::REG_0x0D, gl846::REG_0x0D_CLRMCNT); + break; + } + case AsicType::GL847: { + dev.interface->write_register(gl847::REG_0x0D, gl847::REG_0x0D_CLRLNCNT); + dev.interface->write_register(gl847::REG_0x0D, gl847::REG_0x0D_CLRMCNT); + break; + } + case AsicType::GL124: { + dev.interface->write_register(gl124::REG_0x0D, gl124::REG_0x0D_CLRLNCNT); + dev.interface->write_register(gl124::REG_0x0D, gl124::REG_0x0D_CLRMCNT); + break; + } + default: + throw SaneException("Unsupported asic type"); + } +} + +bool scanner_is_motor_stopped(Genesys_Device& dev) +{ + switch (dev.model->asic_type) { + case AsicType::GL646: { + auto status = scanner_read_status(dev); + return !status.is_motor_enabled && status.is_feeding_finished; + } + case AsicType::GL841: { + auto reg = dev.interface->read_register(gl841::REG_0x40); + + return (!(reg & gl841::REG_0x40_DATAENB) && !(reg & gl841::REG_0x40_MOTMFLG)); + } + case AsicType::GL843: { + auto status = scanner_read_status(dev); + auto reg = dev.interface->read_register(gl843::REG_0x40); + + return (!(reg & gl843::REG_0x40_DATAENB) && !(reg & gl843::REG_0x40_MOTMFLG) && + !status.is_motor_enabled); + } + case AsicType::GL845: + case AsicType::GL846: { + auto status = scanner_read_status(dev); + auto reg = dev.interface->read_register(gl846::REG_0x40); + + return (!(reg & gl846::REG_0x40_DATAENB) && !(reg & gl846::REG_0x40_MOTMFLG) && + !status.is_motor_enabled); + } + case AsicType::GL847: { + auto status = scanner_read_status(dev); + auto reg = dev.interface->read_register(gl847::REG_0x40); + + return (!(reg & gl847::REG_0x40_DATAENB) && !(reg & gl847::REG_0x40_MOTMFLG) && + !status.is_motor_enabled); + } + case AsicType::GL124: { + auto status = scanner_read_status(dev); + auto reg = dev.interface->read_register(gl124::REG_0x100); + + return (!(reg & gl124::REG_0x100_DATAENB) && !(reg & gl124::REG_0x100_MOTMFLG) && + !status.is_motor_enabled); + } + default: + throw SaneException("Unsupported asic type"); + } +} + +void scanner_stop_action(Genesys_Device& dev) +{ + DBG_HELPER(dbg); + + switch (dev.model->asic_type) { + case AsicType::GL843: + case AsicType::GL845: + case AsicType::GL846: + case AsicType::GL847: + case AsicType::GL124: + break; + default: + throw SaneException("Unsupported asic type"); + } + + if (dev.cmd_set->needs_update_home_sensor_gpio()) { + dev.cmd_set->update_home_sensor_gpio(dev); + } + + if (scanner_is_motor_stopped(dev)) { + DBG(DBG_info, "%s: already stopped\n", __func__); + return; + } + + scanner_stop_action_no_move(dev, dev.reg); + + if (is_testing_mode()) { + return; + } + + for (unsigned i = 0; i < 10; ++i) { + if (scanner_is_motor_stopped(dev)) { + return; + } + + dev.interface->sleep_ms(100); + } + + throw SaneException(SANE_STATUS_IO_ERROR, "could not stop motor"); +} + +void scanner_stop_action_no_move(Genesys_Device& dev, genesys::Genesys_Register_Set& regs) +{ + switch (dev.model->asic_type) { + case AsicType::GL646: + case AsicType::GL841: + case AsicType::GL843: + case AsicType::GL845: + case AsicType::GL846: + case AsicType::GL847: + case AsicType::GL124: + break; + default: + throw SaneException("Unsupported asic type"); + } + + regs_set_optical_off(dev.model->asic_type, regs); + // same across all supported ASICs + dev.interface->write_register(0x01, regs.get8(0x01)); + + // looks like certain scanners lock up if we try to scan immediately after stopping previous + // action. + dev.interface->sleep_ms(100); +} + +void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, Direction direction) +{ + DBG_HELPER_ARGS(dbg, "steps=%d direction=%d", steps, static_cast(direction)); + + auto local_reg = dev.reg; + + unsigned resolution = dev.model->get_resolution_settings(scan_method).get_min_resolution_y(); + + const auto& sensor = sanei_genesys_find_sensor(&dev, resolution, 3, scan_method); + + bool uses_secondary_head = (scan_method == ScanMethod::TRANSPARENCY || + scan_method == ScanMethod::TRANSPARENCY_INFRARED); + bool uses_secondary_pos = uses_secondary_head && + dev.model->default_method == ScanMethod::FLATBED; + + if (!dev.is_head_pos_known(ScanHeadId::PRIMARY)) { + throw SaneException("Unknown head position"); + } + if (uses_secondary_pos && !dev.is_head_pos_known(ScanHeadId::SECONDARY)) { + throw SaneException("Unknown head position"); + } + if (direction == Direction::BACKWARD && steps > dev.head_pos(ScanHeadId::PRIMARY)) { + throw SaneException("Trying to feed behind the home position %d %d", + steps, dev.head_pos(ScanHeadId::PRIMARY)); + } + if (uses_secondary_pos && direction == Direction::BACKWARD && + steps > dev.head_pos(ScanHeadId::SECONDARY)) + { + throw SaneException("Trying to feed behind the home position %d %d", + steps, dev.head_pos(ScanHeadId::SECONDARY)); + } + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 0; + session.params.starty = steps; + session.params.pixels = 100; + session.params.lines = 3; + session.params.depth = 8; + session.params.channels = 3; + session.params.scan_method = scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + if (dev.model->asic_type == AsicType::GL843) { + session.params.color_filter = ColorFilter::RED; + } else { + session.params.color_filter = dev.settings.color_filter; + } + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::FEEDING | + ScanFlag::IGNORE_LINE_DISTANCE; + + if (dev.model->asic_type == AsicType::GL124) { + session.params.flags |= ScanFlag::DISABLE_BUFFER_FULL_MOVE; + } + + if (direction == Direction::BACKWARD) { + session.params.flags |= ScanFlag::REVERSE; + } + + compute_session(&dev, session, sensor); + + dev.cmd_set->init_regs_for_scan_session(&dev, sensor, &local_reg, session); + + if (dev.model->asic_type != AsicType::GL843) { + regs_set_exposure(dev.model->asic_type, local_reg, {0, 0, 0}); + } + scanner_clear_scan_and_feed_counts2(dev); + + dev.interface->write_registers(local_reg); + if (uses_secondary_head) { + gl843::gl843_set_xpa_motor_power(&dev, local_reg, true); + } + + try { + scanner_start_action(dev, true); + } catch (...) { + catch_all_exceptions(__func__, [&]() { + gl843::gl843_set_xpa_motor_power(&dev, local_reg, false); + }); + catch_all_exceptions(__func__, [&]() { scanner_stop_action(dev); }); + // restore original registers + catch_all_exceptions(__func__, [&]() { dev.interface->write_registers(dev.reg); }); + throw; + } + + if (is_testing_mode()) { + dev.interface->test_checkpoint("feed"); + + dev.advance_head_pos_by_steps(ScanHeadId::PRIMARY, direction, steps); + if (uses_secondary_pos) { + dev.advance_head_pos_by_steps(ScanHeadId::SECONDARY, direction, steps); + } + + // FIXME: why don't we stop the scanner like on other ASICs + if (dev.model->asic_type != AsicType::GL843) { + scanner_stop_action(dev); + } + if (uses_secondary_head) { + gl843::gl843_set_xpa_motor_power(&dev, local_reg, false); + } + return; + } + + // wait until feed count reaches the required value + // FIXME: should porbably wait for some timeout + Status status; + for (unsigned i = 0;; ++i) { + status = scanner_read_status(dev); + if (status.is_feeding_finished || ( + direction == Direction::BACKWARD && status.is_at_home)) + { + break; + } + dev.interface->sleep_ms(10); + } + + // FIXME: why don't we stop the scanner like on other ASICs + if (dev.model->asic_type != AsicType::GL843) { + scanner_stop_action(dev); + } + if (uses_secondary_head) { + gl843::gl843_set_xpa_motor_power(&dev, local_reg, false); + } + + dev.advance_head_pos_by_steps(ScanHeadId::PRIMARY, direction, steps); + if (uses_secondary_pos) { + dev.advance_head_pos_by_steps(ScanHeadId::SECONDARY, direction, steps); + } + + // looks like certain scanners lock up if we scan immediately after feeding + dev.interface->sleep_ms(100); +} + +void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home) +{ + DBG_HELPER_ARGS(dbg, "wait_until_home = %d", wait_until_home); + + switch (dev.model->asic_type) { + case AsicType::GL843: + case AsicType::GL845: + case AsicType::GL846: + case AsicType::GL847: + case AsicType::GL124: + break; + default: + throw SaneException("Unsupported asic type"); + } + + // FIXME: also check whether the scanner actually has a secondary head + if (!dev.is_head_pos_known(ScanHeadId::SECONDARY) || + dev.head_pos(ScanHeadId::SECONDARY) > 0 || + dev.settings.scan_method == ScanMethod::TRANSPARENCY || + dev.settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + scanner_move_back_home_ta(dev); + } + + if (dev.is_head_pos_known(ScanHeadId::PRIMARY) && + dev.head_pos(ScanHeadId::PRIMARY) > 1000) + { + // leave 500 steps for regular slow back home + scanner_move(dev, dev.model->default_method, dev.head_pos(ScanHeadId::PRIMARY) - 500, + Direction::BACKWARD); + } + + if (dev.cmd_set->needs_update_home_sensor_gpio()) { + dev.cmd_set->update_home_sensor_gpio(dev); + } + + auto status = scanner_read_reliable_status(dev); + + if (status.is_at_home) { + dbg.log(DBG_info, "already at home"); + dev.set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + + if (dev.model->model_id == ModelId::CANON_LIDE_210) { + // move the head back a little first + if (dev.is_head_pos_known(ScanHeadId::PRIMARY) && + dev.head_pos(ScanHeadId::PRIMARY) > 30) + { + scanner_move(dev, dev.model->default_method, 20, Direction::BACKWARD); + } + } + + Genesys_Register_Set local_reg = dev.reg; + unsigned resolution = sanei_genesys_get_lowest_ydpi(&dev); + + const auto& sensor = sanei_genesys_find_sensor(&dev, resolution, 1, dev.model->default_method); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 100; + if (dev.model->asic_type == AsicType::GL843) { + session.params.starty = 40000; + } else { + session.params.starty = 30000; + } + session.params.pixels = 100; + session.params.lines = 100; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = dev.settings.scan_method; + if (dev.model->asic_type == AsicType::GL843) { + session.params.scan_mode = ScanColorMode::LINEART; + session.params.color_filter = dev.settings.color_filter; + } else { + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::RED; + } + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::IGNORE_LINE_DISTANCE | + ScanFlag::REVERSE; + if (dev.model->asic_type == AsicType::GL843) { + session.params.flags |= ScanFlag::DISABLE_BUFFER_FULL_MOVE; + } + + compute_session(&dev, session, sensor); + + dev.cmd_set->init_regs_for_scan_session(&dev, sensor, &local_reg, session); + + scanner_clear_scan_and_feed_counts(dev); + + dev.interface->write_registers(local_reg); + + if (dev.model->asic_type == AsicType::GL124) { + gl124::gl124_setup_scan_gpio(&dev, resolution); + } + + try { + scanner_start_action(dev, true); + } catch (...) { + catch_all_exceptions(__func__, [&]() { scanner_stop_action(dev); }); + // restore original registers + catch_all_exceptions(__func__, [&]() + { + dev.interface->write_registers(dev.reg); + }); + throw; + } + + if (dev.cmd_set->needs_update_home_sensor_gpio()) { + dev.cmd_set->update_home_sensor_gpio(dev); + } + + if (is_testing_mode()) { + dev.interface->test_checkpoint("move_back_home"); + dev.set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + + if (wait_until_home) { + for (unsigned i = 0; i < 300; ++i) { + auto status = scanner_read_status(dev); + + if (status.is_at_home) { + dbg.log(DBG_info, "reached home position"); + if (dev.model->asic_type == AsicType::GL846 || + dev.model->asic_type == AsicType::GL847) + { + scanner_stop_action(dev); + } + dev.set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + + dev.interface->sleep_ms(100); + } + + // when we come here then the scanner needed too much time for this, so we better stop + // the motor + catch_all_exceptions(__func__, [&](){ scanner_stop_action(dev); }); + dev.set_head_pos_unknown(); + throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home"); + } + dbg.log(DBG_info, "scanhead is still moving"); +} + +void scanner_move_back_home_ta(Genesys_Device& dev) +{ + DBG_HELPER(dbg); + + switch (dev.model->asic_type) { + case AsicType::GL843: + break; + default: + throw SaneException("Unsupported asic type"); + } + + Genesys_Register_Set local_reg = dev.reg; + + auto scan_method = ScanMethod::TRANSPARENCY; + unsigned resolution = dev.model->get_resolution_settings(scan_method).get_min_resolution_y(); + + const auto& sensor = sanei_genesys_find_sensor(&dev, resolution, 1, scan_method); + + if (dev.is_head_pos_known(ScanHeadId::SECONDARY) && + dev.head_pos(ScanHeadId::SECONDARY) > 1000) + { + // leave 500 steps for regular slow back home + scanner_move(dev, scan_method, dev.head_pos(ScanHeadId::SECONDARY) - 500, + Direction::BACKWARD); + } + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 100; + session.params.starty = 30000; + session.params.pixels = 100; + session.params.lines = 100; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::RED; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::IGNORE_LINE_DISTANCE | + ScanFlag::REVERSE; + + compute_session(&dev, session, sensor); + + dev.cmd_set->init_regs_for_scan_session(&dev, sensor, &local_reg, session); + + scanner_clear_scan_and_feed_counts(dev); + + dev.interface->write_registers(local_reg); + gl843::gl843_set_xpa_motor_power(&dev, local_reg, true); + + try { + scanner_start_action(dev, true); + } catch (...) { + catch_all_exceptions(__func__, [&]() { scanner_stop_action(dev); }); + // restore original registers + catch_all_exceptions(__func__, [&]() { dev.interface->write_registers(dev.reg); }); + throw; + } + + if (is_testing_mode()) { + dev.interface->test_checkpoint("move_back_home_ta"); + + if (dev.is_head_pos_known(ScanHeadId::PRIMARY)) { + if (dev.head_pos(ScanHeadId::PRIMARY) > dev.head_pos(ScanHeadId::SECONDARY)) { + dev.advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::BACKWARD, + dev.head_pos(ScanHeadId::SECONDARY)); + } else { + dev.set_head_pos_zero(ScanHeadId::PRIMARY); + } + dev.set_head_pos_zero(ScanHeadId::SECONDARY); + } + + scanner_stop_action(dev); + gl843::gl843_set_xpa_motor_power(&dev, local_reg, false); + return; + } + + for (unsigned i = 0; i < 1200; ++i) { + + auto status = scanner_read_status(dev); + + if (status.is_at_home) { + dbg.log(DBG_info, "TA reached home position"); + + if (dev.is_head_pos_known(ScanHeadId::PRIMARY)) { + if (dev.head_pos(ScanHeadId::PRIMARY) > dev.head_pos(ScanHeadId::SECONDARY)) { + dev.advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::BACKWARD, + dev.head_pos(ScanHeadId::SECONDARY)); + } else { + dev.set_head_pos_zero(ScanHeadId::PRIMARY); + } + dev.set_head_pos_zero(ScanHeadId::SECONDARY); + } + + scanner_stop_action(dev); + gl843::gl843_set_xpa_motor_power(&dev, local_reg, false); + return; + } + + dev.interface->sleep_ms(100); + } + + throw SaneException("Timeout waiting for XPA lamp to park"); +} + +void sanei_genesys_calculate_zmod(bool two_table, + uint32_t exposure_time, + const std::vector& slope_table, + unsigned acceleration_steps, + unsigned move_steps, + unsigned buffer_acceleration_steps, + uint32_t* out_z1, uint32_t* out_z2) +{ + DBG(DBG_info, "%s: two_table=%d\n", __func__, two_table); + + // acceleration total time + unsigned sum = std::accumulate(slope_table.begin(), slope_table.begin() + acceleration_steps, + 0, std::plus()); + + /* Z1MOD: + c = sum(slope_table; reg_stepno) + d = reg_fwdstep * + Z1MOD = (c+d) % exposure_time + */ + *out_z1 = (sum + buffer_acceleration_steps * slope_table[acceleration_steps - 1]) % exposure_time; + + /* Z2MOD: + a = sum(slope_table; reg_stepno) + b = move_steps or 1 if 2 tables + Z1MOD = (a+b) % exposure_time + */ + if (!two_table) { + sum = sum + (move_steps * slope_table[acceleration_steps - 1]); + } else { + sum = sum + slope_table[acceleration_steps - 1]; + } + *out_z2 = sum % exposure_time; +} + +static uint8_t genesys_adjust_gain(double* applied_multi, double multi, uint8_t gain) +{ + double voltage, original_voltage; + uint8_t new_gain = 0; + + DBG(DBG_proc, "%s: multi=%f, gain=%d\n", __func__, multi, gain); + + voltage = 0.5 + gain * 0.25; + original_voltage = voltage; + + voltage *= multi; + + new_gain = static_cast((voltage - 0.5) * 4); + if (new_gain > 0x0e) + new_gain = 0x0e; + + voltage = 0.5 + (new_gain) * 0.25; + + *applied_multi = voltage / original_voltage; + + DBG(DBG_proc, "%s: orig voltage=%.2f, new voltage=%.2f, *applied_multi=%f, new_gain=%d\n", + __func__, original_voltage, voltage, *applied_multi, new_gain); + + return new_gain; +} + + +// todo: is return status necessary (unchecked?) +static void genesys_average_white(Genesys_Device* dev, Genesys_Sensor& sensor, int channels, + int channel, uint8_t* data, int size, int *max_average) +{ + + DBG_HELPER_ARGS(dbg, "channels=%d, channel=%d, size=%d", channels, channel, size); + int gain_white_ref, sum, range; + int average; + int i; + + range = size / 50; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + gain_white_ref = sensor.fau_gain_white_ref * 256; + } else { + gain_white_ref = sensor.gain_white_ref * 256; + } + + if (range < 1) + range = 1; + + size = size / (2 * range * channels); + + data += (channel * 2); + + *max_average = 0; + + while (size--) + { + sum = 0; + for (i = 0; i < range; i++) + { + sum += (*data); + sum += *(data + 1) * 256; + data += (2 * channels); /* byte based */ + } + + average = (sum / range); + if (average > *max_average) + *max_average = average; + } + + DBG(DBG_proc, "%s: max_average=%d, gain_white_ref = %d, finished\n", __func__, *max_average, + gain_white_ref); + + if (*max_average >= gain_white_ref) + throw SaneException(SANE_STATUS_INVAL); +} + +/* todo: understand, values are too high */ +static int +genesys_average_black (Genesys_Device * dev, int channel, + uint8_t * data, int pixels) +{ + int i; + int sum; + int pixel_step; + + DBG(DBG_proc, "%s: channel=%d, pixels=%d\n", __func__, channel, pixels); + + sum = 0; + + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + data += (channel * 2); + pixel_step = 3 * 2; + } + else + { + pixel_step = 2; + } + + for (i = 0; i < pixels; i++) + { + sum += *data; + sum += *(data + 1) * 256; + + data += pixel_step; + } + + DBG(DBG_proc, "%s = %d\n", __func__, sum / pixels); + + return sum / pixels; +} + + +// todo: check; it works but the lines 1, 2, and 3 are too dark even with the +// same offset and gain settings? +static void genesys_coarse_calibration(Genesys_Device* dev, Genesys_Sensor& sensor) +{ + DBG_HELPER_ARGS(dbg, "scan_mode = %d", static_cast(dev->settings.scan_mode)); + int black_pixels; + int white_average; + uint8_t offset[4] = { 0xa0, 0x00, 0xa0, 0x40 }; /* first value isn't used */ + uint16_t white[12], dark[12]; + int i, j; + + black_pixels = sensor.black_pixels + * dev->settings.xres / sensor.optical_res; + + unsigned channels = dev->settings.get_channels(); + + DBG(DBG_info, "channels %d y_size %f xres %d\n", channels, dev->model->y_size.value(), + dev->settings.xres); + unsigned size = static_cast(channels * 2 * dev->model->y_size * dev->settings.xres / + MM_PER_INCH); + /* 1 1 mm 1/inch inch/mm */ + + std::vector calibration_data(size); + std::vector all_data(size * 4, 1); + + dev->cmd_set->set_fe(dev, sensor, AFE_INIT); + + dev->frontend.set_gain(0, 2); + dev->frontend.set_gain(1, 2); + dev->frontend.set_gain(2, 2); // TODO: ? was 2 + dev->frontend.set_offset(0, offset[0]); + dev->frontend.set_offset(1, offset[0]); + dev->frontend.set_offset(2, offset[0]); + + for (i = 0; i < 4; i++) /* read 4 lines */ + { + if (i < 3) /* first 3 lines */ + { + dev->frontend.set_offset(0, offset[i]); + dev->frontend.set_offset(1, offset[i]); + dev->frontend.set_offset(2, offset[i]); + } + + if (i == 1) /* second line */ + { + double applied_multi; + double gain_white_ref; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + gain_white_ref = sensor.fau_gain_white_ref * 256; + } else { + gain_white_ref = sensor.gain_white_ref * 256; + } + + // white and black are defined downwards + + uint8_t gain0 = genesys_adjust_gain(&applied_multi, + gain_white_ref / (white[0] - dark[0]), + dev->frontend.get_gain(0)); + uint8_t gain1 = genesys_adjust_gain(&applied_multi, + gain_white_ref / (white[1] - dark[1]), + dev->frontend.get_gain(1)); + uint8_t gain2 = genesys_adjust_gain(&applied_multi, + gain_white_ref / (white[2] - dark[2]), + dev->frontend.get_gain(2)); + // FIXME: looks like overwritten data. Are the above calculations doing + // anything at all? + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain1); + dev->frontend.set_gain(2, gain2); + dev->frontend.set_gain(0, 2); + dev->frontend.set_gain(1, 2); + dev->frontend.set_gain(2, 2); + + dev->interface->write_fe_register(0x28, dev->frontend.get_gain(0)); + dev->interface->write_fe_register(0x29, dev->frontend.get_gain(1)); + dev->interface->write_fe_register(0x2a, dev->frontend.get_gain(2)); + } + + if (i == 3) /* last line */ + { + double x, y, rate; + + for (j = 0; j < 3; j++) + { + + x = static_cast(dark[(i - 2) * 3 + j] - + dark[(i - 1) * 3 + j]) * 254 / (offset[i - 1] / 2 - + offset[i - 2] / 2); + y = x - x * (offset[i - 1] / 2) / 254 - dark[(i - 1) * 3 + j]; + rate = (x - DARK_VALUE - y) * 254 / x + 0.5; + + uint8_t curr_offset = static_cast(rate); + + if (curr_offset > 0x7f) { + curr_offset = 0x7f; + } + curr_offset <<= 1; + dev->frontend.set_offset(j, curr_offset); + } + } + dev->interface->write_fe_register(0x20, dev->frontend.get_offset(0)); + dev->interface->write_fe_register(0x21, dev->frontend.get_offset(1)); + dev->interface->write_fe_register(0x22, dev->frontend.get_offset(2)); + + DBG(DBG_info, + "%s: doing scan: gain: %d/%d/%d, offset: %d/%d/%d\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2), + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + + + dev->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, false); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("coarse_calibration"); + dev->cmd_set->end_scan(dev, &dev->calib_reg, true); + return; + } + + sanei_genesys_read_data_from_scanner(dev, calibration_data.data(), size); + std::memcpy(all_data.data() + i * size, calibration_data.data(), size); + if (i == 3) /* last line */ + { + std::vector all_data_8(size * 4 / 2); + unsigned int count; + + for (count = 0; count < static_cast(size * 4 / 2); count++) { + all_data_8[count] = all_data[count * 2 + 1]; + } + sanei_genesys_write_pnm_file("gl_coarse.pnm", all_data_8.data(), 8, channels, size / 6, 4); + } + + dev->cmd_set->end_scan(dev, &dev->calib_reg, true); + + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + for (j = 0; j < 3; j++) + { + genesys_average_white(dev, sensor, 3, j, calibration_data.data(), size, &white_average); + white[i * 3 + j] = white_average; + dark[i * 3 + j] = + genesys_average_black (dev, j, calibration_data.data(), + black_pixels); + DBG(DBG_info, "%s: white[%d]=%d, black[%d]=%d\n", __func__, + i * 3 + j, white[i * 3 + j], i * 3 + j, dark[i * 3 + j]); + } + } + else /* one color-component modes */ + { + genesys_average_white(dev, sensor, 1, 0, calibration_data.data(), size, &white_average); + white[i * 3 + 0] = white[i * 3 + 1] = white[i * 3 + 2] = + white_average; + dark[i * 3 + 0] = dark[i * 3 + 1] = dark[i * 3 + 2] = + genesys_average_black (dev, 0, calibration_data.data(), black_pixels); + } + } /* for (i = 0; i < 4; i++) */ + + DBG(DBG_info, "%s: final: gain: %d/%d/%d, offset: %d/%d/%d\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2), + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); +} + +/** + * scans a white area with motor and lamp off to get the per CCD pixel offset + * that will be used to compute shading coefficient + * @param dev scanner's device + */ +static void genesys_shading_calibration_impl(Genesys_Device* dev, const Genesys_Sensor& sensor, + std::vector& out_average_data, + bool is_dark, const std::string& log_filename_prefix) +{ + DBG_HELPER(dbg); + + debug_dump(DBG_info, dev->calib_session); + + size_t size; + uint32_t pixels_per_line; + uint8_t channels; + + /* end pixel - start pixel */ + pixels_per_line = dev->calib_pixels; + channels = dev->calib_channels; + + uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; + + // FIXME: we set this during both dark and white calibration. A cleaner approach should + // probably be used + dev->average_size = channels * out_pixels_per_line; + + out_average_data.clear(); + out_average_data.resize(dev->average_size); + + if (is_dark && dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) { + // FIXME: dark shading currently not supported on infrared transparency scans + return; + } + + // FIXME: the current calculation is likely incorrect on non-GL843 implementations, + // but this needs checking + if (dev->calib_total_bytes_to_read > 0) { + size = dev->calib_total_bytes_to_read; + } else if (dev->model->asic_type == AsicType::GL843) { + size = channels * 2 * pixels_per_line * dev->calib_lines; + } else { + size = channels * 2 * pixels_per_line * (dev->calib_lines + 1); + } + + std::vector calibration_data(size / 2); + + bool motor = true; + if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) + { + motor = false; + } + + // turn off motor and lamp power for flatbed scanners, but not for sheetfed scanners + // because they have a calibration sheet with a sufficient black strip + if (is_dark && !dev->model->is_sheetfed) { + sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, false); + sanei_genesys_set_motor_power(dev->calib_reg, motor); + } else { + sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true); + sanei_genesys_set_motor_power(dev->calib_reg, motor); + } + + dev->interface->write_registers(dev->calib_reg); + + if (is_dark) { + // wait some time to let lamp to get dark + dev->interface->sleep_ms(200); + } else if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) { + // make sure lamp is bright again + // FIXME: what about scanners that take a long time to warm the lamp? + dev->interface->sleep_ms(500); + } + + bool start_motor = !is_dark; + dev->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, start_motor); + + + if (is_testing_mode()) { + dev->interface->test_checkpoint(is_dark ? "dark_shading_calibration" + : "white_shading_calibration"); + dev->cmd_set->end_scan(dev, &dev->calib_reg, true); + return; + } + + sanei_genesys_read_data_from_scanner(dev, reinterpret_cast(calibration_data.data()), + size); + + dev->cmd_set->end_scan(dev, &dev->calib_reg, true); + + if (dev->model->flags & GENESYS_FLAG_16BIT_DATA_INVERTED) { + for (std::size_t i = 0; i < size / 2; ++i) { + auto value = calibration_data[i]; + value = ((value >> 8) & 0xff) | ((value << 8) & 0xff00); + calibration_data[i] = value; + } + } + + std::fill(out_average_data.begin(), + out_average_data.begin() + dev->calib_pixels_offset * channels, 0); + + compute_array_percentile_approx(out_average_data.data() + dev->calib_pixels_offset * channels, + calibration_data.data(), + dev->calib_lines, pixels_per_line * channels, + 0.5f); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file16((log_filename_prefix + "_shading.pnm").c_str(), + calibration_data.data(), + channels, pixels_per_line, dev->calib_lines); + sanei_genesys_write_pnm_file16((log_filename_prefix + "_average.pnm").c_str(), + out_average_data.data(), + channels, out_pixels_per_line, 1); + } +} + + +static void genesys_dark_shading_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + genesys_shading_calibration_impl(dev, sensor, dev->dark_average_data, true, "gl_black_"); +} +/* + * this function builds dummy dark calibration data so that we can + * compute shading coefficient in a clean way + * todo: current values are hardcoded, we have to find if they + * can be computed from previous calibration data (when doing offset + * calibration ?) + */ +static void genesys_dummy_dark_shading(Genesys_Device* dev, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + uint32_t pixels_per_line; + uint8_t channels; + uint32_t skip, xend; + int dummy1, dummy2, dummy3; /* dummy black average per channel */ + + pixels_per_line = dev->calib_pixels; + channels = dev->calib_channels; + + uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; + + dev->average_size = channels * out_pixels_per_line; + dev->dark_average_data.clear(); + dev->dark_average_data.resize(dev->average_size, 0); + + /* we average values on 'the left' where CCD pixels are under casing and + give darkest values. We then use these as dummy dark calibration */ + if (dev->settings.xres <= sensor.optical_res / 2) + { + skip = 4; + xend = 36; + } + else + { + skip = 4; + xend = 68; + } + if (dev->model->sensor_id==SensorId::CCD_G4050 || + dev->model->sensor_id==SensorId::CCD_HP_4850C + || dev->model->sensor_id==SensorId::CCD_CANON_4400F + || dev->model->sensor_id==SensorId::CCD_CANON_8400F + || dev->model->sensor_id==SensorId::CCD_KVSS080) + { + skip = 2; + xend = sensor.black_pixels; + } + + /* average each channels on half left margin */ + dummy1 = 0; + dummy2 = 0; + dummy3 = 0; + + for (unsigned x = skip + 1; x <= xend; x++) { + dummy1 += dev->white_average_data[channels * x]; + if (channels > 1) { + dummy2 += dev->white_average_data[channels * x + 1]; + dummy3 += dev->white_average_data[channels * x + 2]; + } + } + + dummy1 /= (xend - skip); + if (channels > 1) + { + dummy2 /= (xend - skip); + dummy3 /= (xend - skip); + } + DBG(DBG_proc, "%s: dummy1=%d, dummy2=%d, dummy3=%d \n", __func__, dummy1, dummy2, dummy3); + + /* fill dark_average */ + for (unsigned x = 0; x < out_pixels_per_line; x++) { + dev->dark_average_data[channels * x] = dummy1; + if (channels > 1) { + dev->dark_average_data[channels * x + 1] = dummy2; + dev->dark_average_data[channels * x + 2] = dummy3; + } + } +} + + +static void genesys_repark_sensor_before_shading(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) { + dev->cmd_set->move_back_home(dev, true); + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + dev->cmd_set->move_to_ta(dev); + } + } +} + +static void genesys_repark_sensor_after_white_shading(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + if (dev->model->flags & GENESYS_FLAG_SHADING_REPARK) { + dev->cmd_set->move_back_home(dev, true); + } +} + +static void genesys_white_shading_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + genesys_shading_calibration_impl(dev, sensor, dev->white_average_data, false, "gl_white_"); +} + +// This calibration uses a scan over the calibration target, comprising a black and a white strip. +// (So the motor must be on.) +static void genesys_dark_white_shading_calibration(Genesys_Device* dev, + const Genesys_Sensor& sensor) +{ + DBG_HELPER_ARGS(dbg, "lines = %zu", dev->calib_lines); + size_t size; + uint32_t pixels_per_line; + uint8_t channels; + unsigned int x; + uint32_t dark, white, dark_sum, white_sum, dark_count, white_count, col, + dif; + + pixels_per_line = dev->calib_pixels; + channels = dev->calib_channels; + + uint32_t out_pixels_per_line = pixels_per_line + dev->calib_pixels_offset; + + dev->average_size = channels * out_pixels_per_line; + + dev->white_average_data.clear(); + dev->white_average_data.resize(dev->average_size); + + dev->dark_average_data.clear(); + dev->dark_average_data.resize(dev->average_size); + + if (dev->calib_total_bytes_to_read > 0) + size = dev->calib_total_bytes_to_read; + else + size = channels * 2 * pixels_per_line * dev->calib_lines; + + std::vector calibration_data(size); + + bool motor = true; + if (dev->model->flags & GENESYS_FLAG_SHADING_NO_MOVE) + { + motor = false; + } + + // turn on motor and lamp power + sanei_genesys_set_lamp_power(dev, sensor, dev->calib_reg, true); + sanei_genesys_set_motor_power(dev->calib_reg, motor); + + dev->interface->write_registers(dev->calib_reg); + + dev->cmd_set->begin_scan(dev, sensor, &dev->calib_reg, false); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("dark_white_shading_calibration"); + dev->cmd_set->end_scan(dev, &dev->calib_reg, true); + return; + } + + sanei_genesys_read_data_from_scanner(dev, calibration_data.data(), size); + + dev->cmd_set->end_scan(dev, &dev->calib_reg, true); + + if (DBG_LEVEL >= DBG_data) + { + if (dev->model->is_cis) + { + sanei_genesys_write_pnm_file("gl_black_white_shading.pnm", calibration_data.data(), + 16, 1, pixels_per_line*channels, + dev->calib_lines); + } + else + { + sanei_genesys_write_pnm_file("gl_black_white_shading.pnm", calibration_data.data(), + 16, channels, pixels_per_line, + dev->calib_lines); + } + } + + + std::fill(dev->dark_average_data.begin(), + dev->dark_average_data.begin() + dev->calib_pixels_offset * channels, 0); + std::fill(dev->white_average_data.begin(), + dev->white_average_data.begin() + dev->calib_pixels_offset * channels, 0); + + uint16_t* average_white = dev->white_average_data.data() + dev->calib_pixels_offset * channels; + uint16_t* average_dark = dev->dark_average_data.data() + dev->calib_pixels_offset * channels; + + for (x = 0; x < pixels_per_line * channels; x++) + { + dark = 0xffff; + white = 0; + + for (std::size_t y = 0; y < dev->calib_lines; y++) + { + col = calibration_data[(x + y * pixels_per_line * channels) * 2]; + col |= + calibration_data[(x + y * pixels_per_line * channels) * 2 + + 1] << 8; + + if (col > white) + white = col; + if (col < dark) + dark = col; + } + + dif = white - dark; + + dark = dark + dif / 8; + white = white - dif / 8; + + dark_count = 0; + dark_sum = 0; + + white_count = 0; + white_sum = 0; + + for (std::size_t y = 0; y < dev->calib_lines; y++) + { + col = calibration_data[(x + y * pixels_per_line * channels) * 2]; + col |= + calibration_data[(x + y * pixels_per_line * channels) * 2 + + 1] << 8; + + if (col >= white) + { + white_sum += col; + white_count++; + } + if (col <= dark) + { + dark_sum += col; + dark_count++; + } + + } + + dark_sum /= dark_count; + white_sum /= white_count; + + *average_dark++ = dark_sum; + *average_white++ = white_sum; + } + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file16("gl_white_average.pnm", dev->white_average_data.data(), + channels, out_pixels_per_line, 1); + sanei_genesys_write_pnm_file16("gl_dark_average.pnm", dev->dark_average_data.data(), + channels, out_pixels_per_line, 1); + } +} + +/* computes one coefficient given bright-dark value + * @param coeff factor giving 1.00 gain + * @param target desired target code + * @param value brght-dark value + * */ +static unsigned int +compute_coefficient (unsigned int coeff, unsigned int target, unsigned int value) +{ + int result; + + if (value > 0) + { + result = (coeff * target) / value; + if (result >= 65535) + { + result = 65535; + } + } + else + { + result = coeff; + } + return result; +} + +/** @brief compute shading coefficients for LiDE scanners + * The dark/white shading is actually performed _after_ reducing + * resolution via averaging. only dark/white shading data for what would be + * first pixel at full resolution is used. + * + * scanner raw input to output value calculation: + * o=(i-off)*(gain/coeff) + * + * from datasheet: + * off=dark_average + * gain=coeff*bright_target/(bright_average-dark_average) + * works for dark_target==0 + * + * what we want is these: + * bright_target=(bright_average-off)*(gain/coeff) + * dark_target=(dark_average-off)*(gain/coeff) + * leading to + * off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) + * gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff + * + * @param dev scanner's device + * @param shading_data memory area where to store the computed shading coefficients + * @param pixels_per_line number of pixels per line + * @param words_per_color memory words per color channel + * @param channels number of color channels (actually 1 or 3) + * @param o shading coefficients left offset + * @param coeff 4000h or 2000h depending on fast scan mode or not (GAIN4 bit) + * @param target_bright value of the white target code + * @param target_dark value of the black target code +*/ +static void +compute_averaged_planar (Genesys_Device * dev, const Genesys_Sensor& sensor, + uint8_t * shading_data, + unsigned int pixels_per_line, + unsigned int words_per_color, + unsigned int channels, + unsigned int o, + unsigned int coeff, + unsigned int target_bright, + unsigned int target_dark) +{ + unsigned int x, i, j, br, dk, res, avgpixels, basepixels, val; + unsigned int fill,factor; + + DBG(DBG_info, "%s: pixels=%d, offset=%d\n", __func__, pixels_per_line, o); + + /* initialize result */ + memset (shading_data, 0xff, words_per_color * 3 * 2); + + /* + strangely i can write 0x20000 bytes beginning at 0x00000 without overwriting + slope tables - which begin at address 0x10000(for 1200dpi hw mode): + memory is organized in words(2 bytes) instead of single bytes. explains + quite some things + */ +/* + another one: the dark/white shading is actually performed _after_ reducing + resolution via averaging. only dark/white shading data for what would be + first pixel at full resolution is used. + */ +/* + scanner raw input to output value calculation: + o=(i-off)*(gain/coeff) + + from datasheet: + off=dark_average + gain=coeff*bright_target/(bright_average-dark_average) + works for dark_target==0 + + what we want is these: + bright_target=(bright_average-off)*(gain/coeff) + dark_target=(dark_average-off)*(gain/coeff) + leading to + off = (dark_average*bright_target - bright_average*dark_target)/(bright_target - dark_target) + gain = (bright_target - dark_target)/(bright_average - dark_average)*coeff + */ + res = dev->settings.xres; + + if (sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres) > 1) + { + res *= 2; + } + + /* this should be evenly dividable */ + basepixels = sensor.optical_res / res; + + /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ + if (basepixels < 1) + avgpixels = 1; + else if (basepixels < 6) + avgpixels = basepixels; + else if (basepixels < 8) + avgpixels = 6; + else if (basepixels < 10) + avgpixels = 8; + else if (basepixels < 12) + avgpixels = 10; + else if (basepixels < 15) + avgpixels = 12; + else + avgpixels = 15; + + /* LiDE80 packs shading data */ + if (dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80) { + factor=1; + fill=avgpixels; + } + else + { + factor=avgpixels; + fill=1; + } + + DBG(DBG_info, "%s: averaging over %d pixels\n", __func__, avgpixels); + DBG(DBG_info, "%s: packing factor is %d\n", __func__, factor); + DBG(DBG_info, "%s: fill length is %d\n", __func__, fill); + + for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) + { + if ((x + o) * 2 * 2 + 3 > words_per_color * 2) + break; + + for (j = 0; j < channels; j++) + { + + dk = 0; + br = 0; + for (i = 0; i < avgpixels; i++) + { + // dark data + dk += dev->dark_average_data[(x + i + pixels_per_line * j)]; + // white data + br += dev->white_average_data[(x + i + pixels_per_line * j)]; + } + + br /= avgpixels; + dk /= avgpixels; + + if (br * target_dark > dk * target_bright) + val = 0; + else if (dk * target_bright - br * target_dark > + 65535 * (target_bright - target_dark)) + val = 65535; + else + { + val = (dk * target_bright - br * target_dark) / (target_bright - target_dark); + } + + /*fill all pixels, even if only the last one is relevant*/ + for (i = 0; i < fill; i++) + { + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j] = val & 0xff; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = val >> 8; + } + + val = br - dk; + + if (65535 * val > (target_bright - target_dark) * coeff) + { + val = (coeff * (target_bright - target_dark)) / val; + } + else + { + val = 65535; + } + + /*fill all pixels, even if only the last one is relevant*/ + for (i = 0; i < fill; i++) + { + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = val & 0xff; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = val >> 8; + } + } + + /* fill remaining channels */ + for (j = channels; j < 3; j++) + { + for (i = 0; i < fill; i++) + { + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j ] = shading_data[(x/factor + o + i) * 2 * 2 ]; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 1] = shading_data[(x/factor + o + i) * 2 * 2 + 1]; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 2] = shading_data[(x/factor + o + i) * 2 * 2 + 2]; + shading_data[(x/factor + o + i) * 2 * 2 + words_per_color * 2 * j + 3] = shading_data[(x/factor + o + i) * 2 * 2 + 3]; + } + } + } +} + +static std::array color_order_to_cmat(ColorOrder color_order) +{ + switch (color_order) { + case ColorOrder::RGB: return {0, 1, 2}; + case ColorOrder::GBR: return {2, 0, 1}; + default: + throw std::logic_error("Unknown color order"); + } +} + +/** + * Computes shading coefficient using formula in data sheet. 16bit data values + * manipulated here are little endian. For now we assume deletion scanning type + * and that there is always 3 channels. + * @param dev scanner's device + * @param shading_data memory area where to store the computed shading coefficients + * @param pixels_per_line number of pixels per line + * @param channels number of color channels (actually 1 or 3) + * @param cmat color transposition matrix + * @param offset shading coefficients left offset + * @param coeff 4000h or 2000h depending on fast scan mode or not + * @param target value of the target code + */ +static void compute_coefficients(Genesys_Device * dev, + uint8_t * shading_data, + unsigned int pixels_per_line, + unsigned int channels, + ColorOrder color_order, + int offset, + unsigned int coeff, + unsigned int target) +{ + uint8_t *ptr; /* contain 16bit words in little endian */ + unsigned int x, c; + unsigned int val, br, dk; + unsigned int start, end; + + DBG(DBG_io, "%s: pixels_per_line=%d, coeff=0x%04x\n", __func__, pixels_per_line, coeff); + + auto cmat = color_order_to_cmat(color_order); + + /* compute start & end values depending of the offset */ + if (offset < 0) + { + start = -1 * offset; + end = pixels_per_line; + } + else + { + start = 0; + end = pixels_per_line - offset; + } + + for (c = 0; c < channels; c++) + { + for (x = start; x < end; x++) + { + /* TODO if channels=1 , use filter to know the base addr */ + ptr = shading_data + 4 * ((x + offset) * channels + cmat[c]); + + // dark data + dk = dev->dark_average_data[x * channels + c]; + + // white data + br = dev->white_average_data[x * channels + c]; + + /* compute coeff */ + val=compute_coefficient(coeff,target,br-dk); + + /* assign it */ + ptr[0] = dk & 255; + ptr[1] = dk / 256; + ptr[2] = val & 0xff; + ptr[3] = val / 256; + + } + } +} + +/** + * Computes shading coefficient using formula in data sheet. 16bit data values + * manipulated here are little endian. Data is in planar form, ie grouped by + * lines of the same color component. + * @param dev scanner's device + * @param shading_data memory area where to store the computed shading coefficients + * @param factor averaging factor when the calibration scan is done at a higher resolution + * than the final scan + * @param pixels_per_line number of pixels per line + * @param words_per_color total number of shading data words for one color element + * @param channels number of color channels (actually 1 or 3) + * @param cmat transcoding matrix for color channel order + * @param offset shading coefficients left offset + * @param coeff 4000h or 2000h depending on fast scan mode or not + * @param target white target value + */ +static void compute_planar_coefficients(Genesys_Device * dev, + uint8_t * shading_data, + unsigned int factor, + unsigned int pixels_per_line, + unsigned int words_per_color, + unsigned int channels, + ColorOrder color_order, + unsigned int offset, + unsigned int coeff, + unsigned int target) +{ + uint8_t *ptr; /* contains 16bit words in little endian */ + uint32_t x, c, i; + uint32_t val, dk, br; + + auto cmat = color_order_to_cmat(color_order); + + DBG(DBG_io, "%s: factor=%d, pixels_per_line=%d, words=0x%X, coeff=0x%04x\n", __func__, factor, + pixels_per_line, words_per_color, coeff); + for (c = 0; c < channels; c++) + { + /* shading data is larger than pixels_per_line so offset can be neglected */ + for (x = 0; x < pixels_per_line; x+=factor) + { + /* x2 because of 16 bit values, and x2 since one coeff for dark + * and another for white */ + ptr = shading_data + words_per_color * cmat[c] * 2 + (x + offset) * 4; + + dk = 0; + br = 0; + + /* average case */ + for(i=0;idark_average_data[((x+i) + pixels_per_line * c)]; + br += dev->white_average_data[((x+i) + pixels_per_line * c)]; + } + dk /= factor; + br /= factor; + + val = compute_coefficient (coeff, target, br - dk); + + /* we duplicate the information to have calibration data at optical resolution */ + for (i = 0; i < factor; i++) + { + ptr[0 + 4 * i] = dk & 255; + ptr[1 + 4 * i] = dk / 256; + ptr[2 + 4 * i] = val & 0xff; + ptr[3 + 4 * i] = val / 256; + } + } + } + /* in case of gray level scan, we duplicate shading information on all + * three color channels */ + if(channels==1) + { + memcpy(shading_data+cmat[1]*2*words_per_color, + shading_data+cmat[0]*2*words_per_color, + words_per_color*2); + memcpy(shading_data+cmat[2]*2*words_per_color, + shading_data+cmat[0]*2*words_per_color, + words_per_color*2); + } +} + +static void +compute_shifted_coefficients (Genesys_Device * dev, + const Genesys_Sensor& sensor, + uint8_t * shading_data, + unsigned int pixels_per_line, + unsigned int channels, + ColorOrder color_order, + int offset, + unsigned int coeff, + unsigned int target_dark, + unsigned int target_bright, + unsigned int patch_size) /* contigous extent */ +{ + unsigned int x, avgpixels, basepixels, i, j, val1, val2; + unsigned int br_tmp [3], dk_tmp [3]; + uint8_t *ptr = shading_data + offset * 3 * 4; /* contain 16bit words in little endian */ + unsigned int patch_cnt = offset * 3; /* at start, offset of first patch */ + + auto cmat = color_order_to_cmat(color_order); + + x = dev->settings.xres; + if (sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres) > 1) + x *= 2; /* scanner is using half-ccd mode */ + basepixels = sensor.optical_res / x; /*this should be evenly dividable */ + + /* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ + if (basepixels < 1) + avgpixels = 1; + else if (basepixels < 6) + avgpixels = basepixels; + else if (basepixels < 8) + avgpixels = 6; + else if (basepixels < 10) + avgpixels = 8; + else if (basepixels < 12) + avgpixels = 10; + else if (basepixels < 15) + avgpixels = 12; + else + avgpixels = 15; + DBG(DBG_info, "%s: pixels_per_line=%d, coeff=0x%04x, averaging over %d pixels\n", __func__, + pixels_per_line, coeff, avgpixels); + + for (x = 0; x <= pixels_per_line - avgpixels; x += avgpixels) { + memset (&br_tmp, 0, sizeof(br_tmp)); + memset (&dk_tmp, 0, sizeof(dk_tmp)); + + for (i = 0; i < avgpixels; i++) { + for (j = 0; j < channels; j++) { + br_tmp[j] += dev->white_average_data[((x + i) * channels + j)]; + dk_tmp[i] += dev->dark_average_data[((x + i) * channels + j)]; + } + } + for (j = 0; j < channels; j++) { + br_tmp[j] /= avgpixels; + dk_tmp[j] /= avgpixels; + + if (br_tmp[j] * target_dark > dk_tmp[j] * target_bright) + val1 = 0; + else if (dk_tmp[j] * target_bright - br_tmp[j] * target_dark > 65535 * (target_bright - target_dark)) + val1 = 65535; + else + val1 = (dk_tmp[j] * target_bright - br_tmp[j] * target_dark) / (target_bright - target_dark); + + val2 = br_tmp[j] - dk_tmp[j]; + if (65535 * val2 > (target_bright - target_dark) * coeff) + val2 = (coeff * (target_bright - target_dark)) / val2; + else + val2 = 65535; + + br_tmp[j] = val1; + dk_tmp[j] = val2; + } + for (i = 0; i < avgpixels; i++) { + for (j = 0; j < channels; j++) { + * ptr++ = br_tmp[ cmat[j] ] & 0xff; + * ptr++ = br_tmp[ cmat[j] ] >> 8; + * ptr++ = dk_tmp[ cmat[j] ] & 0xff; + * ptr++ = dk_tmp[ cmat[j] ] >> 8; + patch_cnt++; + if (patch_cnt == patch_size) { + patch_cnt = 0; + val1 = cmat[2]; + cmat[2] = cmat[1]; + cmat[1] = cmat[0]; + cmat[0] = val1; + } + } + } + } +} + +static void genesys_send_shading_coefficient(Genesys_Device* dev, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + + if (dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE) { + return; + } + + uint32_t pixels_per_line; + uint8_t channels; + int o; + unsigned int length; /**> number of shading calibration data words */ + unsigned int factor; + unsigned int coeff, target_code, words_per_color = 0; + + pixels_per_line = dev->calib_pixels + dev->calib_pixels_offset; + channels = dev->calib_channels; + + /* we always build data for three channels, even for gray + * we make the shading data such that each color channel data line is contiguous + * to the next one, which allow to write the 3 channels in 1 write + * during genesys_send_shading_coefficient, some values are words, other bytes + * hence the x2 factor */ + switch (dev->reg.get8(0x05) >> 6) + { + /* 600 dpi */ + case 0: + words_per_color = 0x2a00; + break; + /* 1200 dpi */ + case 1: + words_per_color = 0x5500; + break; + /* 2400 dpi */ + case 2: + words_per_color = 0xa800; + break; + /* 4800 dpi */ + case 3: + words_per_color = 0x15000; + break; + } + + /* special case, memory is aligned on 0x5400, this has yet to be explained */ + /* could be 0xa800 because sensor is truly 2400 dpi, then halved because + * we only set 1200 dpi */ + if(dev->model->sensor_id==SensorId::CIS_CANON_LIDE_80) + { + words_per_color = 0x5400; + } + + length = words_per_color * 3 * 2; + + /* allocate computed size */ + // contains 16bit words in little endian + std::vector shading_data(length, 0); + + /* TARGET/(Wn-Dn) = white gain -> ~1.xxx then it is multiplied by 0x2000 + or 0x4000 to give an integer + Wn = white average for column n + Dn = dark average for column n + */ + if (get_registers_gain4_bit(dev->model->asic_type, dev->calib_reg)) { + coeff = 0x4000; + } else { + coeff = 0x2000; + } + + /* compute avg factor */ + if(dev->settings.xres>sensor.optical_res) + { + factor=1; + } + else + { + factor=sensor.optical_res/dev->settings.xres; + } + + /* for GL646, shading data is planar if REG_0x01_FASTMOD is set and + * chunky if not. For now we rely on the fact that we know that + * each sensor is used only in one mode. Currently only the CIS_XP200 + * sets REG_0x01_FASTMOD. + */ + + /* TODO setup a struct in genesys_devices that + * will handle these settings instead of having this switch growing up */ + switch (dev->model->sensor_id) + { + case SensorId::CCD_XP300: + case SensorId::CCD_ROADWARRIOR: + case SensorId::CCD_DP665: + case SensorId::CCD_DP685: + case SensorId::CCD_DSMOBILE600: + target_code = 0xdc00; + o = 4; + compute_planar_coefficients (dev, + shading_data.data(), + factor, + pixels_per_line, + words_per_color, + channels, + ColorOrder::RGB, + o, + coeff, + target_code); + break; + case SensorId::CIS_XP200: + target_code = 0xdc00; + o = 2; + compute_planar_coefficients (dev, + shading_data.data(), + 1, + pixels_per_line, + words_per_color, + channels, + ColorOrder::GBR, + o, + coeff, + target_code); + break; + case SensorId::CCD_HP2300: + target_code = 0xdc00; + o = 2; + if(dev->settings.xres<=sensor.optical_res/2) + { + o = o - sensor.dummy_pixel / 2; + } + compute_coefficients (dev, + shading_data.data(), + pixels_per_line, + 3, + ColorOrder::RGB, + o, + coeff, + target_code); + break; + case SensorId::CCD_5345: + target_code = 0xe000; + o = 4; + if(dev->settings.xres<=sensor.optical_res/2) + { + o = o - sensor.dummy_pixel; + } + compute_coefficients (dev, + shading_data.data(), + pixels_per_line, + 3, + ColorOrder::RGB, + o, + coeff, + target_code); + break; + case SensorId::CCD_HP3670: + case SensorId::CCD_HP2400: + target_code = 0xe000; + // offset is dependent on ccd_pixels_per_system_pixel(), but we couldn't use this in + // common code previously. + // FIXME: use sensor.ccd_pixels_per_system_pixel() + if(dev->settings.xres<=300) + { + o = -10; + } + else if(dev->settings.xres<=600) + { + o = -6; + } + else + { + o = +2; + } + compute_coefficients (dev, + shading_data.data(), + pixels_per_line, + 3, + ColorOrder::RGB, + o, + coeff, + target_code); + break; + case SensorId::CCD_KVSS080: + case SensorId::CCD_PLUSTEK_OPTICBOOK_3800: + case SensorId::CCD_G4050: + case SensorId::CCD_HP_4850C: + case SensorId::CCD_CANON_4400F: + case SensorId::CCD_CANON_8400F: + case SensorId::CCD_CANON_8600F: + case SensorId::CCD_PLUSTEK_OPTICFILM_7200I: + case SensorId::CCD_PLUSTEK_OPTICFILM_7300: + case SensorId::CCD_PLUSTEK_OPTICFILM_7500I: + target_code = 0xe000; + o = 0; + compute_coefficients (dev, + shading_data.data(), + pixels_per_line, + 3, + ColorOrder::RGB, + o, + coeff, + target_code); + break; + case SensorId::CIS_CANON_LIDE_700F: + case SensorId::CIS_CANON_LIDE_100: + case SensorId::CIS_CANON_LIDE_200: + case SensorId::CIS_CANON_LIDE_110: + case SensorId::CIS_CANON_LIDE_120: + case SensorId::CIS_CANON_LIDE_210: + case SensorId::CIS_CANON_LIDE_220: + /* TODO store this in a data struct so we avoid + * growing this switch */ + switch(dev->model->sensor_id) + { + case SensorId::CIS_CANON_LIDE_110: + case SensorId::CIS_CANON_LIDE_120: + case SensorId::CIS_CANON_LIDE_210: + case SensorId::CIS_CANON_LIDE_220: + case SensorId::CIS_CANON_LIDE_700F: + target_code = 0xc000; + break; + default: + target_code = 0xdc00; + } + words_per_color=pixels_per_line*2; + length = words_per_color * 3 * 2; + shading_data.clear(); + shading_data.resize(length, 0); + compute_planar_coefficients (dev, + shading_data.data(), + 1, + pixels_per_line, + words_per_color, + channels, + ColorOrder::RGB, + 0, + coeff, + target_code); + break; + case SensorId::CIS_CANON_LIDE_35: + compute_averaged_planar (dev, sensor, + shading_data.data(), + pixels_per_line, + words_per_color, + channels, + 4, + coeff, + 0xe000, + 0x0a00); + break; + case SensorId::CIS_CANON_LIDE_80: + compute_averaged_planar (dev, sensor, + shading_data.data(), + pixels_per_line, + words_per_color, + channels, + 0, + coeff, + 0xe000, + 0x0800); + break; + case SensorId::CCD_PLUSTEK_OPTICPRO_3600: + compute_shifted_coefficients (dev, sensor, + shading_data.data(), + pixels_per_line, + channels, + ColorOrder::RGB, + 12, /* offset */ + coeff, + 0x0001, /* target_dark */ + 0xf900, /* target_bright */ + 256); /* patch_size: contigous extent */ + break; + default: + throw SaneException(SANE_STATUS_UNSUPPORTED, "sensor %d not supported", + static_cast(dev->model->sensor_id)); + break; + } + + // do the actual write of shading calibration data to the scanner + genesys_send_offset_and_shading(dev, sensor, shading_data.data(), length); +} + + +/** + * search calibration cache list for an entry matching required scan. + * If one is found, set device calibration with it + * @param dev scanner's device + * @return false if no matching cache entry has been + * found, true if one has been found and used. + */ +static bool +genesys_restore_calibration(Genesys_Device * dev, Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + + // if no cache or no function to evaluate cache entry ther can be no match/ + if (dev->calibration_cache.empty()) { + return false; + } + + auto session = dev->cmd_set->calculate_scan_session(dev, sensor, dev->settings); + + /* we walk the link list of calibration cache in search for a + * matching one */ + for (auto& cache : dev->calibration_cache) + { + if (sanei_genesys_is_compatible_calibration(dev, session, &cache, false)) { + dev->frontend = cache.frontend; + /* we don't restore the gamma fields */ + sensor.exposure = cache.sensor.exposure; + + dev->average_size = cache.average_size; + dev->calib_pixels = cache.calib_pixels; + dev->calib_channels = cache.calib_channels; + + dev->dark_average_data = cache.dark_average_data; + dev->white_average_data = cache.white_average_data; + + if (!dev->cmd_set->has_send_shading_data()) { + genesys_send_shading_coefficient(dev, sensor); + } + + DBG(DBG_proc, "%s: restored\n", __func__); + return true; + } + } + DBG(DBG_proc, "%s: completed(nothing found)\n", __func__); + return false; +} + + +static void genesys_save_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); +#ifdef HAVE_SYS_TIME_H + struct timeval time; +#endif + + auto session = dev->cmd_set->calculate_scan_session(dev, sensor, dev->settings); + + auto found_cache_it = dev->calibration_cache.end(); + for (auto cache_it = dev->calibration_cache.begin(); cache_it != dev->calibration_cache.end(); + cache_it++) + { + if (sanei_genesys_is_compatible_calibration(dev, session, &*cache_it, true)) { + found_cache_it = cache_it; + break; + } + } + + /* if we found on overridable cache, we reuse it */ + if (found_cache_it == dev->calibration_cache.end()) + { + /* create a new cache entry and insert it in the linked list */ + dev->calibration_cache.push_back(Genesys_Calibration_Cache()); + found_cache_it = std::prev(dev->calibration_cache.end()); + } + + found_cache_it->average_size = dev->average_size; + + found_cache_it->dark_average_data = dev->dark_average_data; + found_cache_it->white_average_data = dev->white_average_data; + + found_cache_it->params = session.params; + found_cache_it->frontend = dev->frontend; + found_cache_it->sensor = sensor; + + found_cache_it->calib_pixels = dev->calib_pixels; + found_cache_it->calib_channels = dev->calib_channels; + +#ifdef HAVE_SYS_TIME_H + gettimeofday(&time, nullptr); + found_cache_it->last_calibration = time.tv_sec; +#endif +} + +/** + * does the calibration process for a flatbed scanner + * - offset calibration + * - gain calibration + * - shading calibration + * @param dev device to calibrate + */ +static void genesys_flatbed_calibration(Genesys_Device* dev, Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + uint32_t pixels_per_line; + + unsigned coarse_res = sensor.optical_res; + if (dev->settings.yres <= sensor.optical_res / 2) { + coarse_res /= 2; + } + + if (dev->model->model_id == ModelId::CANON_8400F) { + coarse_res = 1600; + } + + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8600F) + { + coarse_res = 1200; + } + + /* do offset calibration if needed */ + if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) + { + dev->interface->record_progress_message("offset_calibration"); + dev->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); + + /* since all the registers are set up correctly, just use them */ + dev->interface->record_progress_message("coarse_gain_calibration"); + dev->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, coarse_res); + } else { + /* since we have 2 gain calibration proc, skip second if first one was + used. */ + dev->interface->record_progress_message("init_regs_for_coarse_calibration"); + dev->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg); + + dev->interface->record_progress_message("genesys_coarse_calibration"); + genesys_coarse_calibration(dev, sensor); + } + + if (dev->model->is_cis) + { + /* the afe now sends valid data for doing led calibration */ + dev->interface->record_progress_message("led_calibration"); + switch (dev->model->asic_type) { + case AsicType::GL124: + case AsicType::GL845: + case AsicType::GL846: + case AsicType::GL847: { + auto calib_exposure = dev->cmd_set->led_calibration(dev, sensor, dev->calib_reg); + for (auto& sensor_update : + sanei_genesys_find_sensors_all_for_write(dev, sensor.method)) { + sensor_update.get().exposure = calib_exposure; + } + sensor.exposure = calib_exposure; + break; + } + default: { + sensor.exposure = dev->cmd_set->led_calibration(dev, sensor, dev->calib_reg); + } + } + + + /* calibrate afe again to match new exposure */ + if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) { + dev->interface->record_progress_message("offset_calibration"); + dev->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); + + // since all the registers are set up correctly, just use them + + dev->interface->record_progress_message("coarse_gain_calibration"); + dev->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, coarse_res); + } else { + // since we have 2 gain calibration proc, skip second if first one was used + dev->interface->record_progress_message("init_regs_for_coarse_calibration"); + dev->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg); + + dev->interface->record_progress_message("genesys_coarse_calibration"); + genesys_coarse_calibration(dev, sensor); + } + } + + /* we always use sensor pixel number when the ASIC can't handle multi-segments sensor */ + if (!(dev->model->flags & GENESYS_FLAG_SIS_SENSOR)) + { + pixels_per_line = static_cast((dev->model->x_size * dev->settings.xres) / + MM_PER_INCH); + } + else + { + pixels_per_line = sensor.sensor_pixels; + } + + // send default shading data + dev->interface->record_progress_message("sanei_genesys_init_shading_data"); + sanei_genesys_init_shading_data(dev, sensor, pixels_per_line); + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + dev->cmd_set->move_to_ta(dev); + } + + // shading calibration + if (dev->model->flags & GENESYS_FLAG_DARK_WHITE_CALIBRATION) { + dev->interface->record_progress_message("init_regs_for_shading"); + dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); + + dev->interface->record_progress_message("genesys_dark_white_shading_calibration"); + genesys_dark_white_shading_calibration(dev, sensor); + } else { + DBG(DBG_proc, "%s : genesys_dark_shading_calibration dev->calib_reg ", __func__); + debug_dump(DBG_proc, dev->calib_reg); + + if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) { + dev->interface->record_progress_message("init_regs_for_shading"); + dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); + + dev->interface->record_progress_message("genesys_dark_shading_calibration"); + genesys_dark_shading_calibration(dev, sensor); + genesys_repark_sensor_before_shading(dev); + } + + dev->interface->record_progress_message("init_regs_for_shading2"); + dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); + + dev->interface->record_progress_message("genesys_white_shading_calibration"); + genesys_white_shading_calibration(dev, sensor); + genesys_repark_sensor_after_white_shading(dev); + + if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) { + genesys_dummy_dark_shading(dev, sensor); + } + } + + if (!dev->cmd_set->has_send_shading_data()) { + dev->interface->record_progress_message("genesys_send_shading_coefficient"); + genesys_send_shading_coefficient(dev, sensor); + } +} + +/** + * Does the calibration process for a sheetfed scanner + * - offset calibration + * - gain calibration + * - shading calibration + * During calibration a predefined calibration sheet with specific black and white + * areas is used. + * @param dev device to calibrate + */ +static void genesys_sheetfed_calibration(Genesys_Device* dev, Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + bool forward = true; + + // first step, load document + dev->cmd_set->load_document(dev); + + /* led, offset and gain calibration are influenced by scan + * settings. So we set it to sensor resolution */ + dev->settings.xres = sensor.optical_res; + /* XP200 needs to calibrate a full and half sensor's resolution */ + if (dev->model->sensor_id == SensorId::CIS_XP200 && + dev->settings.xres <= sensor.optical_res / 2) + { + dev->settings.xres /= 2; + } + + /* the afe needs to sends valid data even before calibration */ + + /* go to a white area */ + try { + dev->cmd_set->search_strip(dev, sensor, forward, false); + } catch (...) { + catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); }); + throw; + } + + if (dev->model->is_cis) + { + dev->cmd_set->led_calibration(dev, sensor, dev->calib_reg); + } + + /* calibrate afe */ + if (dev->model->flags & GENESYS_FLAG_OFFSET_CALIBRATION) + { + dev->cmd_set->offset_calibration(dev, sensor, dev->calib_reg); + + /* since all the registers are set up correctly, just use them */ + + dev->cmd_set->coarse_gain_calibration(dev, sensor, dev->calib_reg, sensor.optical_res); + } + else + /* since we have 2 gain calibration proc, skip second if first one was + used. */ + { + dev->cmd_set->init_regs_for_coarse_calibration(dev, sensor, dev->calib_reg); + + genesys_coarse_calibration(dev, sensor); + } + + /* search for a full width black strip and then do a 16 bit scan to + * gather black shading data */ + if (dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION) + { + /* seek black/white reverse/forward */ + try { + dev->cmd_set->search_strip(dev, sensor, forward, true); + } catch (...) { + catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); }); + throw; + } + + dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); + + try { + genesys_dark_shading_calibration(dev, sensor); + } catch (...) { + catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); }); + throw; + } + forward = false; + } + + + /* go to a white area */ + try { + dev->cmd_set->search_strip(dev, sensor, forward, false); + } catch (...) { + catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); }); + throw; + } + + genesys_repark_sensor_before_shading(dev); + + dev->cmd_set->init_regs_for_shading(dev, sensor, dev->calib_reg); + + try { + genesys_white_shading_calibration(dev, sensor); + genesys_repark_sensor_after_white_shading(dev); + } catch (...) { + catch_all_exceptions(__func__, [&](){ dev->cmd_set->eject_document(dev); }); + throw; + } + + // in case we haven't black shading data, build it from black pixels of white calibration + // FIXME: shouldn't we use genesys_dummy_dark_shading() ? + if (!(dev->model->flags & GENESYS_FLAG_DARK_CALIBRATION)) { + dev->dark_average_data.clear(); + dev->dark_average_data.resize(dev->average_size, 0x0f0f); + /* XXX STEF XXX + * with black point in white shading, build an average black + * pixel and use it to fill the dark_average + * dev->calib_pixels + (sensor.sensor_pixels * dev->settings.xres) / sensor.optical_res, + dev->calib_lines, + */ + } + + /* send the shading coefficient when doing whole line shading + * but not when using SHDAREA like GL124 */ + if (!dev->cmd_set->has_send_shading_data()) { + genesys_send_shading_coefficient(dev, sensor); + } + + // save the calibration data + genesys_save_calibration(dev, sensor); + + // and finally eject calibration sheet + dev->cmd_set->eject_document(dev); + + // restore settings + dev->settings.xres = sensor.optical_res; +} + +/** + * does the calibration process for a device + * @param dev device to calibrate + */ +static void genesys_scanner_calibration(Genesys_Device* dev, Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + if (!dev->model->is_sheetfed) { + genesys_flatbed_calibration(dev, sensor); + return; + } + genesys_sheetfed_calibration(dev, sensor); +} + + +/* ------------------------------------------------------------------------ */ +/* High level (exported) functions */ +/* ------------------------------------------------------------------------ */ + +/* + * wait lamp to be warm enough by scanning the same line until + * differences between two scans are below a threshold + */ +static void genesys_warmup_lamp(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + unsigned seconds = 0; + int pixel; + int channels, total_size; + double first_average = 0; + double second_average = 0; + int difference = 255; + int lines = 3; + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + dev->cmd_set->init_regs_for_warmup(dev, sensor, &dev->reg, &channels, &total_size); + std::vector first_line(total_size); + std::vector second_line(total_size); + + do + { + DBG(DBG_info, "%s: one more loop\n", __func__); + dev->cmd_set->begin_scan(dev, sensor, &dev->reg, false); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("warmup_lamp"); + dev->cmd_set->end_scan(dev, &dev->reg, true); + return; + } + + wait_until_buffer_non_empty(dev); + + try { + sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); + } catch (...) { + // FIXME: document why this retry is here + sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); + } + + dev->cmd_set->end_scan(dev, &dev->reg, true); + + dev->interface->sleep_ms(1000); + seconds++; + + dev->cmd_set->begin_scan(dev, sensor, &dev->reg, false); + + wait_until_buffer_non_empty(dev); + + sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + dev->cmd_set->end_scan(dev, &dev->reg, true); + + /* compute difference between the two scans */ + for (pixel = 0; pixel < total_size; pixel++) + { + // 16 bit data + if (dev->session.params.depth == 16) { + first_average += (first_line[pixel] + first_line[pixel + 1] * 256); + second_average += (second_line[pixel] + second_line[pixel + 1] * 256); + pixel++; + } + else + { + first_average += first_line[pixel]; + second_average += second_line[pixel]; + } + } + if (dev->session.params.depth == 16) { + first_average /= pixel; + second_average /= pixel; + difference = static_cast(std::fabs(first_average - second_average)); + DBG(DBG_info, "%s: average = %.2f, diff = %.3f\n", __func__, + 100 * ((second_average) / (256 * 256)), + 100 * (difference / second_average)); + + if (second_average > (100 * 256) + && (difference / second_average) < 0.002) + break; + } + else + { + first_average /= pixel; + second_average /= pixel; + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_pnm_file("gl_warmup1.pnm", first_line.data(), 8, channels, + total_size / (lines * channels), lines); + sanei_genesys_write_pnm_file("gl_warmup2.pnm", second_line.data(), 8, channels, + total_size / (lines * channels), lines); + } + DBG(DBG_info, "%s: average 1 = %.2f, average 2 = %.2f\n", __func__, first_average, + second_average); + /* if delta below 15/255 ~= 5.8%, lamp is considred warm enough */ + if (fabs (first_average - second_average) < 15 + && second_average > 55) + break; + } + + /* sleep another second before next loop */ + dev->interface->sleep_ms(1000); + seconds++; + } while (seconds < WARMUP_TIME); + + if (seconds >= WARMUP_TIME) + { + throw SaneException(SANE_STATUS_IO_ERROR, + "warmup timed out after %d seconds. Lamp defective?", seconds); + } + else + { + DBG(DBG_info, "%s: warmup succeeded after %d seconds\n", __func__, seconds); + } +} + + +// High-level start of scanning +static void genesys_start_scan(Genesys_Device* dev, bool lamp_off) +{ + DBG_HELPER(dbg); + unsigned int steps, expected; + + /* since not all scanners are set ot wait for head to park + * we check we are not still parking before starting a new scan */ + if (dev->parking) { + sanei_genesys_wait_for_home(dev); + } + + // disable power saving + dev->cmd_set->save_power(dev, false); + + /* wait for lamp warmup : until a warmup for TRANSPARENCY is designed, skip + * it when scanning from XPA. */ + if (!(dev->model->flags & GENESYS_FLAG_SKIP_WARMUP) + && (dev->settings.scan_method == ScanMethod::FLATBED)) + { + genesys_warmup_lamp(dev); + } + + /* set top left x and y values by scanning the internals if flatbed scanners */ + if (!dev->model->is_sheetfed) { + /* do the geometry detection only once */ + if ((dev->model->flags & GENESYS_FLAG_SEARCH_START) + && (dev->model->y_offset_calib_white == 0)) + { + dev->cmd_set->search_start_position (dev); + + dev->parking = false; + dev->cmd_set->move_back_home(dev, true); + } + else + { + /* Go home */ + /* TODO: check we can drop this since we cannot have the + scanner's head wandering here */ + dev->parking = false; + dev->cmd_set->move_back_home(dev, true); + } + } + + /* move to calibration area for transparency adapter */ + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + dev->cmd_set->move_to_ta(dev); + } + + /* load document if needed (for sheetfed scanner for instance) */ + if (dev->model->is_sheetfed) { + dev->cmd_set->load_document(dev); + } + + auto& sensor = sanei_genesys_find_sensor_for_write(dev, dev->settings.xres, + dev->settings.get_channels(), + dev->settings.scan_method); + + // send gamma tables. They have been set to device or user value + // when setting option value */ + dev->cmd_set->send_gamma_table(dev, sensor); + + /* try to use cached calibration first */ + if (!genesys_restore_calibration (dev, sensor)) + { + /* calibration : sheetfed scanners can't calibrate before each scan */ + /* and also those who have the NO_CALIBRATION flag */ + if (!(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) && !dev->model->is_sheetfed) { + genesys_scanner_calibration(dev, sensor); + genesys_save_calibration (dev, sensor); + } + else + { + DBG(DBG_warn, "%s: no calibration done\n", __func__); + } + } + + /* build look up table for dynamic lineart */ + if (dev->settings.scan_mode == ScanColorMode::LINEART) { + sanei_genesys_load_lut(dev->lineart_lut, 8, 8, 50, 205, dev->settings.threshold_curve, + dev->settings.threshold-127); + } + + dev->cmd_set->wait_for_motor_stop(dev); + + if (dev->cmd_set->needs_home_before_init_regs_for_scan(dev)) { + dev->cmd_set->move_back_home(dev, true); + } + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + dev->cmd_set->move_to_ta(dev); + } + + dev->cmd_set->init_regs_for_scan(dev, sensor); + + /* no lamp during scan */ + if (lamp_off) { + sanei_genesys_set_lamp_power(dev, sensor, dev->reg, false); + } + + /* GL124 is using SHDAREA, so we have to wait for scan to be set up before + * sending shading data */ + if (dev->cmd_set->has_send_shading_data() && + !(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + genesys_send_shading_coefficient(dev, sensor); + } + + // now send registers for scan + dev->interface->write_registers(dev->reg); + + // start effective scan + dev->cmd_set->begin_scan(dev, sensor, &dev->reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("start_scan"); + return; + } + + /*do we really need this? the valid data check should be sufficent -- pierre*/ + /* waits for head to reach scanning position */ + expected = dev->reg.get8(0x3d) * 65536 + + dev->reg.get8(0x3e) * 256 + + dev->reg.get8(0x3f); + do + { + // wait some time between each test to avoid overloading USB and CPU + dev->interface->sleep_ms(100); + sanei_genesys_read_feed_steps (dev, &steps); + } + while (steps < expected); + + wait_until_buffer_non_empty(dev); + + // we wait for at least one word of valid scan data + // this is also done in sanei_genesys_read_data_from_scanner -- pierre + if (!dev->model->is_sheetfed) { + do { + dev->interface->sleep_ms(100); + sanei_genesys_read_valid_words(dev, &steps); + } + while (steps < 1); + } +} + +static void genesys_fill_read_buffer(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + + /* for sheetfed scanner, we must check is document is shorter than + * the requested scan */ + if (dev->model->is_sheetfed) { + dev->cmd_set->detect_document_end(dev); + } + + std::size_t size = dev->read_buffer.size() - dev->read_buffer.avail(); + + /* due to sensors and motors, not all data can be directly used. It + * may have to be read from another intermediate buffer and then processed. + * There are currently 3 intermediate stages: + * - handling of odd/even sensors + * - handling of line interpolation for motors that can't have low + * enough dpi + * - handling of multi-segments sensors + * + * This is also the place where full duplex data will be handled. + */ + dev->pipeline_buffer.get_data(size, dev->read_buffer.get_write_pos(size)); + + dev->read_buffer.produce(size); +} + +/* this function does the effective data read in a manner that suits + the scanner. It does data reordering and resizing if need. + It also manages EOF and I/O errors, and line distance correction. + Returns true on success, false on end-of-file. +*/ +static void genesys_read_ordered_data(Genesys_Device* dev, SANE_Byte* destination, size_t* len) +{ + DBG_HELPER(dbg); + size_t bytes = 0; + uint8_t *work_buffer_src; + Genesys_Buffer *src_buffer; + + if (!dev->read_active) { + *len = 0; + throw SaneException("read is not active"); + } + + DBG(DBG_info, "%s: frontend requested %zu bytes\n", __func__, *len); + DBG(DBG_info, "%s: bytes_to_read=%zu, total_bytes_read=%zu\n", __func__, + dev->total_bytes_to_read, dev->total_bytes_read); + + /* is there data left to scan */ + if (dev->total_bytes_read >= dev->total_bytes_to_read) + { + /* issue park command immediatly in case scanner can handle it + * so we save time */ + if (!dev->model->is_sheetfed && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) && + !dev->parking) + { + dev->cmd_set->move_back_home(dev, false); + dev->parking = true; + } + throw SaneException(SANE_STATUS_EOF, "nothing more to scan: EOF"); + } + +/* convert data */ +/* + 0. fill_read_buffer +-------------- read_buffer ---------------------- + 1a). (opt)uncis (assumes color components to be laid out + planar) + 1b). (opt)reverse_RGB (assumes pixels to be BGR or BBGGRR)) +-------------- lines_buffer ---------------------- + 2a). (opt)line_distance_correction (assumes RGB or RRGGBB) + 2b). (opt)unstagger (assumes pixels to be depth*channels/8 + bytes long, unshrinked) +------------- shrink_buffer --------------------- + 3. (opt)shrink_lines (assumes component separation in pixels) +-------------- out_buffer ----------------------- + 4. memcpy to destination (for lineart with bit reversal) +*/ +/*FIXME: for lineart we need sub byte addressing in buffers, or conversion to + bytes at 0. and back to bits at 4. +Problems with the first approach: + - its not clear how to check if we need to output an incomplete byte + because it is the last one. + */ +/*FIXME: add lineart support for gl646. in the meantime add logic to convert + from gray to lineart at the end? would suffer the above problem, + total_bytes_to_read and total_bytes_read help in that case. + */ + + if (is_testing_mode()) { + if (dev->total_bytes_read + *len > dev->total_bytes_to_read) { + *len = dev->total_bytes_to_read - dev->total_bytes_read; + } + dev->total_bytes_read += *len; + } else { + genesys_fill_read_buffer(dev); + + src_buffer = &(dev->read_buffer); + + /* move data to destination */ + bytes = std::min(src_buffer->avail(), *len); + + work_buffer_src = src_buffer->get_read_pos(); + + std::memcpy(destination, work_buffer_src, bytes); + *len = bytes; + + /* avoid signaling some extra data because we have treated a full block + * on the last block */ + if (dev->total_bytes_read + *len > dev->total_bytes_to_read) { + *len = dev->total_bytes_to_read - dev->total_bytes_read; + } + + /* count bytes sent to frontend */ + dev->total_bytes_read += *len; + + src_buffer->consume(bytes); + } + + /* end scan if all needed data have been read */ + if(dev->total_bytes_read >= dev->total_bytes_to_read) + { + dev->cmd_set->end_scan(dev, &dev->reg, true); + if (dev->model->is_sheetfed) { + dev->cmd_set->eject_document (dev); + } + } + + DBG(DBG_proc, "%s: completed, %zu bytes read\n", __func__, bytes); +} + + + +/* ------------------------------------------------------------------------ */ +/* Start of higher level functions */ +/* ------------------------------------------------------------------------ */ + +static size_t +max_string_size (const SANE_String_Const strings[]) +{ + size_t size, max_size = 0; + SANE_Int i; + + for (i = 0; strings[i]; ++i) + { + size = strlen (strings[i]) + 1; + if (size > max_size) + max_size = size; + } + return max_size; +} + +static std::size_t max_string_size(const std::vector& strings) +{ + std::size_t max_size = 0; + for (const auto& s : strings) { + if (!s) { + continue; + } + max_size = std::max(max_size, std::strlen(s)); + } + return max_size; +} + +static unsigned pick_resolution(const std::vector& resolutions, unsigned resolution, + const char* direction) +{ + DBG_HELPER(dbg); + + if (resolutions.empty()) + throw SaneException("Empty resolution list"); + + unsigned best_res = resolutions.front(); + unsigned min_diff = abs_diff(best_res, resolution); + + for (auto it = std::next(resolutions.begin()); it != resolutions.end(); ++it) { + unsigned curr_diff = abs_diff(*it, resolution); + if (curr_diff < min_diff) { + min_diff = curr_diff; + best_res = *it; + } + } + + if (best_res != resolution) { + DBG(DBG_warn, "%s: using resolution %d that is nearest to %d for direction %s\n", + __func__, best_res, resolution, direction); + } + return best_res; +} + +static void calc_parameters(Genesys_Scanner* s) +{ + DBG_HELPER(dbg); + double tl_x = 0, tl_y = 0, br_x = 0, br_y = 0; + + tl_x = SANE_UNFIX(s->pos_top_left_x); + tl_y = SANE_UNFIX(s->pos_top_left_y); + br_x = SANE_UNFIX(s->pos_bottom_right_x); + br_y = SANE_UNFIX(s->pos_bottom_right_y); + + s->params.last_frame = true; /* only single pass scanning supported */ + + if (s->mode == SANE_VALUE_SCAN_MODE_GRAY || s->mode == SANE_VALUE_SCAN_MODE_LINEART) { + s->params.format = SANE_FRAME_GRAY; + } else { + s->params.format = SANE_FRAME_RGB; + } + + if (s->mode == SANE_VALUE_SCAN_MODE_LINEART) { + s->params.depth = 1; + } else { + s->params.depth = s->bit_depth; + } + + s->dev->settings.scan_method = s->scan_method; + const auto& resolutions = s->dev->model->get_resolution_settings(s->dev->settings.scan_method); + + s->dev->settings.depth = s->bit_depth; + + /* interpolation */ + s->dev->settings.disable_interpolation = s->disable_interpolation; + + // FIXME: use correct sensor + const auto& sensor = sanei_genesys_find_sensor_any(s->dev); + + // hardware settings + if (static_cast(s->resolution) > sensor.optical_res && + s->dev->settings.disable_interpolation) + { + s->dev->settings.xres = sensor.optical_res; + } else { + s->dev->settings.xres = s->resolution; + } + s->dev->settings.yres = s->resolution; + + s->dev->settings.xres = pick_resolution(resolutions.resolutions_x, s->dev->settings.xres, "X"); + s->dev->settings.yres = pick_resolution(resolutions.resolutions_y, s->dev->settings.yres, "Y"); + + s->params.lines = static_cast(((br_y - tl_y) * s->dev->settings.yres) / + MM_PER_INCH); + unsigned pixels_per_line = static_cast(((br_x - tl_x) * s->dev->settings.xres) / + MM_PER_INCH); + + /* we need an even pixels number + * TODO invert test logic or generalize behaviour across all ASICs */ + if ((s->dev->model->flags & GENESYS_FLAG_SIS_SENSOR) || + s->dev->model->asic_type == AsicType::GL847 || + s->dev->model->asic_type == AsicType::GL124 || + s->dev->model->asic_type == AsicType::GL845 || + s->dev->model->asic_type == AsicType::GL846 || + s->dev->model->asic_type == AsicType::GL843) + { + if (s->dev->settings.xres <= 1200) { + pixels_per_line = (pixels_per_line / 4) * 4; + } else if (s->dev->settings.xres < s->dev->settings.yres) { + // BUG: this is an artifact of the fact that the resolution was twice as large than + // the actual resolution when scanning above the supported scanner X resolution + pixels_per_line = (pixels_per_line / 8) * 8; + } else { + pixels_per_line = (pixels_per_line / 16) * 16; + } + } + + /* corner case for true lineart for sensor with several segments + * or when xres is doubled to match yres */ + if (s->dev->settings.xres >= 1200 && ( + s->dev->model->asic_type == AsicType::GL124 || + s->dev->model->asic_type == AsicType::GL847 || + s->dev->session.params.xres < s->dev->session.params.yres)) + { + if (s->dev->settings.xres < s->dev->settings.yres) { + // FIXME: this is an artifact of the fact that the resolution was twice as large than + // the actual resolution when scanning above the supported scanner X resolution + pixels_per_line = (pixels_per_line / 8) * 8; + } else { + pixels_per_line = (pixels_per_line / 16) * 16; + } + } + + unsigned xres_factor = s->resolution / s->dev->settings.xres; + + unsigned bytes_per_line = 0; + + if (s->params.depth > 8) + { + s->params.depth = 16; + bytes_per_line = 2 * pixels_per_line; + } + else if (s->params.depth == 1) + { + // round down pixel number. This will is lossy operation, at most 7 pixels will be lost + pixels_per_line = (pixels_per_line / 8) * 8; + bytes_per_line = pixels_per_line / 8; + } else { + bytes_per_line = pixels_per_line; + } + + if (s->params.format == SANE_FRAME_RGB) { + bytes_per_line *= 3; + } + + s->dev->settings.scan_mode = option_string_to_scan_color_mode(s->mode); + + s->dev->settings.lines = s->params.lines; + s->dev->settings.pixels = pixels_per_line; + s->dev->settings.requested_pixels = pixels_per_line * xres_factor; + s->params.pixels_per_line = pixels_per_line * xres_factor; + s->params.bytes_per_line = bytes_per_line * xres_factor; + s->dev->settings.tl_x = tl_x; + s->dev->settings.tl_y = tl_y; + + // threshold setting + s->dev->settings.threshold = static_cast(2.55 * (SANE_UNFIX(s->threshold))); + + // color filter + if (s->color_filter == "Red") { + s->dev->settings.color_filter = ColorFilter::RED; + } else if (s->color_filter == "Green") { + s->dev->settings.color_filter = ColorFilter::GREEN; + } else if (s->color_filter == "Blue") { + s->dev->settings.color_filter = ColorFilter::BLUE; + } else { + s->dev->settings.color_filter = ColorFilter::NONE; + } + + // true gray + if (s->color_filter == "None") { + s->dev->settings.true_gray = 1; + } else { + s->dev->settings.true_gray = 0; + } + + // threshold curve for dynamic rasterization + s->dev->settings.threshold_curve = s->threshold_curve; + + /* some digital processing requires the whole picture to be buffered */ + /* no digital processing takes place when doing preview, or when bit depth is + * higher than 8 bits */ + if ((s->swdespeck || s->swcrop || s->swdeskew || s->swderotate ||(SANE_UNFIX(s->swskip)>0)) + && (!s->preview) + && (s->bit_depth <= 8)) + { + s->dev->buffer_image = true; + } + else + { + s->dev->buffer_image = false; + } + + /* brigthness and contrast only for for 8 bit scans */ + if(s->bit_depth <= 8) + { + s->dev->settings.contrast = (s->contrast * 127) / 100; + s->dev->settings.brightness = (s->brightness * 127) / 100; + } + else + { + s->dev->settings.contrast=0; + s->dev->settings.brightness=0; + } + + /* cache expiration time */ + s->dev->settings.expiration_time = s->expiration_time; +} + + +static void create_bpp_list (Genesys_Scanner * s, const std::vector& bpp) +{ + s->bpp_list[0] = bpp.size(); + std::reverse_copy(bpp.begin(), bpp.end(), s->bpp_list + 1); +} + +/** @brief this function initialize a gamma vector based on the ASIC: + * Set up a default gamma table vector based on device description + * gl646: 12 or 14 bits gamma table depending on GENESYS_FLAG_14BIT_GAMMA + * gl84x: 16 bits + * gl12x: 16 bits + * @param scanner pointer to scanner session to get options + * @param option option number of the gamma table to set + */ +static void +init_gamma_vector_option (Genesys_Scanner * scanner, int option) +{ + /* the option is inactive until the custom gamma control + * is enabled */ + scanner->opt[option].type = SANE_TYPE_INT; + scanner->opt[option].cap |= SANE_CAP_INACTIVE | SANE_CAP_ADVANCED; + scanner->opt[option].unit = SANE_UNIT_NONE; + scanner->opt[option].constraint_type = SANE_CONSTRAINT_RANGE; + if (scanner->dev->model->asic_type == AsicType::GL646) { + if ((scanner->dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) != 0) + { + scanner->opt[option].size = 16384 * sizeof (SANE_Word); + scanner->opt[option].constraint.range = &u14_range; + } + else + { /* 12 bits gamma tables */ + scanner->opt[option].size = 4096 * sizeof (SANE_Word); + scanner->opt[option].constraint.range = &u12_range; + } + } + else + { /* other asics have 16 bits words gamma table */ + scanner->opt[option].size = 256 * sizeof (SANE_Word); + scanner->opt[option].constraint.range = &u16_range; + } +} + +/** + * allocate a geometry range + * @param size maximum size of the range + * @return a pointer to a valid range or nullptr + */ +static SANE_Range create_range(float size) +{ + SANE_Range range; + range.min = SANE_FIX(0.0); + range.max = SANE_FIX(size); + range.quant = SANE_FIX(0.0); + return range; +} + +/** @brief generate calibration cache file nam + * Generates the calibration cache file name to use. + * Tries to store the chache in $HOME/.sane or + * then fallbacks to $TMPDIR or TMP. The filename + * uses the model name if only one scanner is plugged + * else is uses the device name when several identical + * scanners are in use. + * @param currdev current scanner device + * @return an allocated string containing a file name + */ +static std::string calibration_filename(Genesys_Device *currdev) +{ + std::string ret; + ret.resize(PATH_MAX); + + char filename[80]; + unsigned int count; + unsigned int i; + + /* first compute the DIR where we can store cache: + * 1 - home dir + * 2 - $TMPDIR + * 3 - $TMP + * 4 - tmp dir + * 5 - temp dir + * 6 - then resort to current dir + */ + char* ptr = std::getenv("HOME"); + if (ptr == nullptr) { + ptr = std::getenv("USERPROFILE"); + } + if (ptr == nullptr) { + ptr = std::getenv("TMPDIR"); + } + if (ptr == nullptr) { + ptr = std::getenv("TMP"); + } + + /* now choose filename: + * 1 - if only one scanner, name of the model + * 2 - if several scanners of the same model, use device name, + * replacing special chars + */ + count=0; + /* count models of the same names if several scanners attached */ + if(s_devices->size() > 1) { + for (const auto& dev : *s_devices) { + if (dev.model->model_id == currdev->model->model_id) { + count++; + } + } + } + if(count>1) + { + std::snprintf(filename, sizeof(filename), "%s.cal", currdev->file_name.c_str()); + for(i=0;imodel->name); + } + + /* build final final name : store dir + filename */ + if (ptr == nullptr) { + int size = std::snprintf(&ret.front(), ret.size(), "%s", filename); + ret.resize(size); + } + else + { + int size = 0; +#ifdef HAVE_MKDIR + /* make sure .sane directory exists in existing store dir */ + size = std::snprintf(&ret.front(), ret.size(), "%s%c.sane", ptr, PATH_SEP); + ret.resize(size); + mkdir(ret.c_str(), 0700); + + ret.resize(PATH_MAX); +#endif + size = std::snprintf(&ret.front(), ret.size(), "%s%c.sane%c%s", + ptr, PATH_SEP, PATH_SEP, filename); + ret.resize(size); + } + + DBG(DBG_info, "%s: calibration filename >%s<\n", __func__, ret.c_str()); + + return ret; +} + +static void set_resolution_option_values(Genesys_Scanner& s, bool reset_resolution_value) +{ + auto resolutions = s.dev->model->get_resolutions(s.scan_method); + + s.opt_resolution_values.resize(resolutions.size() + 1, 0); + s.opt_resolution_values[0] = resolutions.size(); + std::copy(resolutions.begin(), resolutions.end(), s.opt_resolution_values.begin() + 1); + + s.opt[OPT_RESOLUTION].constraint.word_list = s.opt_resolution_values.data(); + + if (reset_resolution_value) { + s.resolution = *std::min_element(resolutions.begin(), resolutions.end()); + } +} + +static void set_xy_range_option_values(Genesys_Scanner& s) +{ + if (s.scan_method == ScanMethod::FLATBED) + { + s.opt_x_range = create_range(static_cast(s.dev->model->x_size)); + s.opt_y_range = create_range(static_cast(s.dev->model->y_size)); + } + else + { + s.opt_x_range = create_range(static_cast(s.dev->model->x_size_ta)); + s.opt_y_range = create_range(static_cast(s.dev->model->y_size_ta)); + } + + s.opt[OPT_TL_X].constraint.range = &s.opt_x_range; + s.opt[OPT_TL_Y].constraint.range = &s.opt_y_range; + s.opt[OPT_BR_X].constraint.range = &s.opt_x_range; + s.opt[OPT_BR_Y].constraint.range = &s.opt_y_range; + + s.pos_top_left_x = 0; + s.pos_top_left_y = 0; + s.pos_bottom_right_x = s.opt_x_range.max; + s.pos_bottom_right_y = s.opt_y_range.max; +} + +static void init_options(Genesys_Scanner* s) +{ + DBG_HELPER(dbg); + SANE_Int option; + Genesys_Model *model = s->dev->model; + + memset (s->opt, 0, sizeof (s->opt)); + + for (option = 0; option < NUM_OPTIONS; ++option) + { + s->opt[option].size = sizeof (SANE_Word); + s->opt[option].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + } + s->opt[OPT_NUM_OPTS].name = SANE_NAME_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].title = SANE_TITLE_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].desc = SANE_DESC_NUM_OPTIONS; + s->opt[OPT_NUM_OPTS].type = SANE_TYPE_INT; + s->opt[OPT_NUM_OPTS].cap = SANE_CAP_SOFT_DETECT; + + /* "Mode" group: */ + s->opt[OPT_MODE_GROUP].name = "scanmode-group"; + s->opt[OPT_MODE_GROUP].title = SANE_I18N ("Scan Mode"); + s->opt[OPT_MODE_GROUP].desc = ""; + s->opt[OPT_MODE_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_MODE_GROUP].size = 0; + s->opt[OPT_MODE_GROUP].cap = 0; + s->opt[OPT_MODE_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* scan mode */ + s->opt[OPT_MODE].name = SANE_NAME_SCAN_MODE; + s->opt[OPT_MODE].title = SANE_TITLE_SCAN_MODE; + s->opt[OPT_MODE].desc = SANE_DESC_SCAN_MODE; + s->opt[OPT_MODE].type = SANE_TYPE_STRING; + s->opt[OPT_MODE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->opt[OPT_MODE].size = max_string_size (mode_list); + s->opt[OPT_MODE].constraint.string_list = mode_list; + s->mode = SANE_VALUE_SCAN_MODE_GRAY; + + /* scan source */ + s->opt_source_values.clear(); + for (const auto& resolution_setting : model->resolutions) { + for (auto method : resolution_setting.methods) { + s->opt_source_values.push_back(scan_method_to_option_string(method)); + } + } + s->opt_source_values.push_back(nullptr); + + s->opt[OPT_SOURCE].name = SANE_NAME_SCAN_SOURCE; + s->opt[OPT_SOURCE].title = SANE_TITLE_SCAN_SOURCE; + s->opt[OPT_SOURCE].desc = SANE_DESC_SCAN_SOURCE; + s->opt[OPT_SOURCE].type = SANE_TYPE_STRING; + s->opt[OPT_SOURCE].constraint_type = SANE_CONSTRAINT_STRING_LIST; + s->opt[OPT_SOURCE].size = max_string_size(s->opt_source_values); + s->opt[OPT_SOURCE].constraint.string_list = s->opt_source_values.data(); + if (s->opt_source_values.size() < 2) { + throw SaneException("No scan methods specified for scanner"); + } + s->scan_method = model->default_method; + + /* preview */ + s->opt[OPT_PREVIEW].name = SANE_NAME_PREVIEW; + s->opt[OPT_PREVIEW].title = SANE_TITLE_PREVIEW; + s->opt[OPT_PREVIEW].desc = SANE_DESC_PREVIEW; + s->opt[OPT_PREVIEW].type = SANE_TYPE_BOOL; + s->opt[OPT_PREVIEW].unit = SANE_UNIT_NONE; + s->opt[OPT_PREVIEW].constraint_type = SANE_CONSTRAINT_NONE; + s->preview = false; + + /* bit depth */ + s->opt[OPT_BIT_DEPTH].name = SANE_NAME_BIT_DEPTH; + s->opt[OPT_BIT_DEPTH].title = SANE_TITLE_BIT_DEPTH; + s->opt[OPT_BIT_DEPTH].desc = SANE_DESC_BIT_DEPTH; + s->opt[OPT_BIT_DEPTH].type = SANE_TYPE_INT; + s->opt[OPT_BIT_DEPTH].constraint_type = SANE_CONSTRAINT_WORD_LIST; + s->opt[OPT_BIT_DEPTH].size = sizeof (SANE_Word); + s->opt[OPT_BIT_DEPTH].constraint.word_list = s->bpp_list; + create_bpp_list (s, model->bpp_gray_values); + s->bit_depth = model->bpp_gray_values[0]; + + // resolution + s->opt[OPT_RESOLUTION].name = SANE_NAME_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].title = SANE_TITLE_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].desc = SANE_DESC_SCAN_RESOLUTION; + s->opt[OPT_RESOLUTION].type = SANE_TYPE_INT; + s->opt[OPT_RESOLUTION].unit = SANE_UNIT_DPI; + s->opt[OPT_RESOLUTION].constraint_type = SANE_CONSTRAINT_WORD_LIST; + set_resolution_option_values(*s, true); + + /* "Geometry" group: */ + s->opt[OPT_GEOMETRY_GROUP].name = SANE_NAME_GEOMETRY; + s->opt[OPT_GEOMETRY_GROUP].title = SANE_I18N ("Geometry"); + s->opt[OPT_GEOMETRY_GROUP].desc = ""; + s->opt[OPT_GEOMETRY_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_GEOMETRY_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_GEOMETRY_GROUP].size = 0; + s->opt[OPT_GEOMETRY_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + s->opt_x_range = create_range(static_cast(model->x_size)); + s->opt_y_range = create_range(static_cast(model->y_size)); + + // scan area + s->opt[OPT_TL_X].name = SANE_NAME_SCAN_TL_X; + s->opt[OPT_TL_X].title = SANE_TITLE_SCAN_TL_X; + s->opt[OPT_TL_X].desc = SANE_DESC_SCAN_TL_X; + s->opt[OPT_TL_X].type = SANE_TYPE_FIXED; + s->opt[OPT_TL_X].unit = SANE_UNIT_MM; + s->opt[OPT_TL_X].constraint_type = SANE_CONSTRAINT_RANGE; + + s->opt[OPT_TL_Y].name = SANE_NAME_SCAN_TL_Y; + s->opt[OPT_TL_Y].title = SANE_TITLE_SCAN_TL_Y; + s->opt[OPT_TL_Y].desc = SANE_DESC_SCAN_TL_Y; + s->opt[OPT_TL_Y].type = SANE_TYPE_FIXED; + s->opt[OPT_TL_Y].unit = SANE_UNIT_MM; + s->opt[OPT_TL_Y].constraint_type = SANE_CONSTRAINT_RANGE; + + s->opt[OPT_BR_X].name = SANE_NAME_SCAN_BR_X; + s->opt[OPT_BR_X].title = SANE_TITLE_SCAN_BR_X; + s->opt[OPT_BR_X].desc = SANE_DESC_SCAN_BR_X; + s->opt[OPT_BR_X].type = SANE_TYPE_FIXED; + s->opt[OPT_BR_X].unit = SANE_UNIT_MM; + s->opt[OPT_BR_X].constraint_type = SANE_CONSTRAINT_RANGE; + + s->opt[OPT_BR_Y].name = SANE_NAME_SCAN_BR_Y; + s->opt[OPT_BR_Y].title = SANE_TITLE_SCAN_BR_Y; + s->opt[OPT_BR_Y].desc = SANE_DESC_SCAN_BR_Y; + s->opt[OPT_BR_Y].type = SANE_TYPE_FIXED; + s->opt[OPT_BR_Y].unit = SANE_UNIT_MM; + s->opt[OPT_BR_Y].constraint_type = SANE_CONSTRAINT_RANGE; + + set_xy_range_option_values(*s); + + /* "Enhancement" group: */ + s->opt[OPT_ENHANCEMENT_GROUP].name = SANE_NAME_ENHANCEMENT; + s->opt[OPT_ENHANCEMENT_GROUP].title = SANE_I18N ("Enhancement"); + s->opt[OPT_ENHANCEMENT_GROUP].desc = ""; + s->opt[OPT_ENHANCEMENT_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_ENHANCEMENT_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_ENHANCEMENT_GROUP].size = 0; + s->opt[OPT_ENHANCEMENT_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* custom-gamma table */ + s->opt[OPT_CUSTOM_GAMMA].name = SANE_NAME_CUSTOM_GAMMA; + s->opt[OPT_CUSTOM_GAMMA].title = SANE_TITLE_CUSTOM_GAMMA; + s->opt[OPT_CUSTOM_GAMMA].desc = SANE_DESC_CUSTOM_GAMMA; + s->opt[OPT_CUSTOM_GAMMA].type = SANE_TYPE_BOOL; + s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_ADVANCED; + s->custom_gamma = false; + + /* grayscale gamma vector */ + s->opt[OPT_GAMMA_VECTOR].name = SANE_NAME_GAMMA_VECTOR; + s->opt[OPT_GAMMA_VECTOR].title = SANE_TITLE_GAMMA_VECTOR; + s->opt[OPT_GAMMA_VECTOR].desc = SANE_DESC_GAMMA_VECTOR; + init_gamma_vector_option (s, OPT_GAMMA_VECTOR); + + /* red gamma vector */ + s->opt[OPT_GAMMA_VECTOR_R].name = SANE_NAME_GAMMA_VECTOR_R; + s->opt[OPT_GAMMA_VECTOR_R].title = SANE_TITLE_GAMMA_VECTOR_R; + s->opt[OPT_GAMMA_VECTOR_R].desc = SANE_DESC_GAMMA_VECTOR_R; + init_gamma_vector_option (s, OPT_GAMMA_VECTOR_R); + + /* green gamma vector */ + s->opt[OPT_GAMMA_VECTOR_G].name = SANE_NAME_GAMMA_VECTOR_G; + s->opt[OPT_GAMMA_VECTOR_G].title = SANE_TITLE_GAMMA_VECTOR_G; + s->opt[OPT_GAMMA_VECTOR_G].desc = SANE_DESC_GAMMA_VECTOR_G; + init_gamma_vector_option (s, OPT_GAMMA_VECTOR_G); + + /* blue gamma vector */ + s->opt[OPT_GAMMA_VECTOR_B].name = SANE_NAME_GAMMA_VECTOR_B; + s->opt[OPT_GAMMA_VECTOR_B].title = SANE_TITLE_GAMMA_VECTOR_B; + s->opt[OPT_GAMMA_VECTOR_B].desc = SANE_DESC_GAMMA_VECTOR_B; + init_gamma_vector_option (s, OPT_GAMMA_VECTOR_B); + + /* currently, there are only gamma table options in this group, + * so if the scanner doesn't support gamma table, disable the + * whole group */ + if (!(model->flags & GENESYS_FLAG_CUSTOM_GAMMA)) + { + s->opt[OPT_ENHANCEMENT_GROUP].cap |= SANE_CAP_INACTIVE; + s->opt[OPT_CUSTOM_GAMMA].cap |= SANE_CAP_INACTIVE; + DBG(DBG_info, "%s: custom gamma disabled\n", __func__); + } + + /* software base image enhancements, these are consuming as many + * memory than used by the full scanned image and may fail at high + * resolution + */ + /* software deskew */ + s->opt[OPT_SWDESKEW].name = "swdeskew"; + s->opt[OPT_SWDESKEW].title = "Software deskew"; + s->opt[OPT_SWDESKEW].desc = "Request backend to rotate skewed pages digitally"; + s->opt[OPT_SWDESKEW].type = SANE_TYPE_BOOL; + s->opt[OPT_SWDESKEW].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->swdeskew = false; + + /* software deskew */ + s->opt[OPT_SWDESPECK].name = "swdespeck"; + s->opt[OPT_SWDESPECK].title = "Software despeck"; + s->opt[OPT_SWDESPECK].desc = "Request backend to remove lone dots digitally"; + s->opt[OPT_SWDESPECK].type = SANE_TYPE_BOOL; + s->opt[OPT_SWDESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->swdespeck = false; + + /* software despeckle radius */ + s->opt[OPT_DESPECK].name = "despeck"; + s->opt[OPT_DESPECK].title = "Software despeckle diameter"; + s->opt[OPT_DESPECK].desc = "Maximum diameter of lone dots to remove from scan"; + s->opt[OPT_DESPECK].type = SANE_TYPE_INT; + s->opt[OPT_DESPECK].unit = SANE_UNIT_NONE; + s->opt[OPT_DESPECK].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_DESPECK].constraint.range = &swdespeck_range; + s->opt[OPT_DESPECK].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED | SANE_CAP_INACTIVE; + s->despeck = 1; + + /* crop by software */ + s->opt[OPT_SWCROP].name = "swcrop"; + s->opt[OPT_SWCROP].title = SANE_I18N ("Software crop"); + s->opt[OPT_SWCROP].desc = SANE_I18N ("Request backend to remove border from pages digitally"); + s->opt[OPT_SWCROP].type = SANE_TYPE_BOOL; + s->opt[OPT_SWCROP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->opt[OPT_SWCROP].unit = SANE_UNIT_NONE; + s->swcrop = false; + + /* Software blank page skip */ + s->opt[OPT_SWSKIP].name = "swskip"; + s->opt[OPT_SWSKIP].title = SANE_I18N ("Software blank skip percentage"); + s->opt[OPT_SWSKIP].desc = SANE_I18N("Request driver to discard pages with low numbers of dark pixels"); + s->opt[OPT_SWSKIP].type = SANE_TYPE_FIXED; + s->opt[OPT_SWSKIP].unit = SANE_UNIT_PERCENT; + s->opt[OPT_SWSKIP].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_SWSKIP].constraint.range = &(percentage_range); + s->opt[OPT_SWSKIP].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->swskip = 0; // disable by default + + /* Software Derotate */ + s->opt[OPT_SWDEROTATE].name = "swderotate"; + s->opt[OPT_SWDEROTATE].title = SANE_I18N ("Software derotate"); + s->opt[OPT_SWDEROTATE].desc = SANE_I18N("Request driver to detect and correct 90 degree image rotation"); + s->opt[OPT_SWDEROTATE].type = SANE_TYPE_BOOL; + s->opt[OPT_SWDEROTATE].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_ADVANCED; + s->opt[OPT_SWDEROTATE].unit = SANE_UNIT_NONE; + s->swderotate = false; + + /* Software brightness */ + s->opt[OPT_BRIGHTNESS].name = SANE_NAME_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].title = SANE_TITLE_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].desc = SANE_DESC_BRIGHTNESS; + s->opt[OPT_BRIGHTNESS].type = SANE_TYPE_INT; + s->opt[OPT_BRIGHTNESS].unit = SANE_UNIT_NONE; + s->opt[OPT_BRIGHTNESS].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_BRIGHTNESS].constraint.range = &(enhance_range); + s->opt[OPT_BRIGHTNESS].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->brightness = 0; // disable by default + + /* Sowftware contrast */ + s->opt[OPT_CONTRAST].name = SANE_NAME_CONTRAST; + s->opt[OPT_CONTRAST].title = SANE_TITLE_CONTRAST; + s->opt[OPT_CONTRAST].desc = SANE_DESC_CONTRAST; + s->opt[OPT_CONTRAST].type = SANE_TYPE_INT; + s->opt[OPT_CONTRAST].unit = SANE_UNIT_NONE; + s->opt[OPT_CONTRAST].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_CONTRAST].constraint.range = &(enhance_range); + s->opt[OPT_CONTRAST].cap = SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT; + s->contrast = 0; // disable by default + + /* "Extras" group: */ + s->opt[OPT_EXTRAS_GROUP].name = "extras-group"; + s->opt[OPT_EXTRAS_GROUP].title = SANE_I18N ("Extras"); + s->opt[OPT_EXTRAS_GROUP].desc = ""; + s->opt[OPT_EXTRAS_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_EXTRAS_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_EXTRAS_GROUP].size = 0; + s->opt[OPT_EXTRAS_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* BW threshold */ + s->opt[OPT_THRESHOLD].name = SANE_NAME_THRESHOLD; + s->opt[OPT_THRESHOLD].title = SANE_TITLE_THRESHOLD; + s->opt[OPT_THRESHOLD].desc = SANE_DESC_THRESHOLD; + s->opt[OPT_THRESHOLD].type = SANE_TYPE_FIXED; + s->opt[OPT_THRESHOLD].unit = SANE_UNIT_PERCENT; + s->opt[OPT_THRESHOLD].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_THRESHOLD].constraint.range = &percentage_range; + s->threshold = SANE_FIX(50); + + /* BW threshold curve */ + s->opt[OPT_THRESHOLD_CURVE].name = "threshold-curve"; + s->opt[OPT_THRESHOLD_CURVE].title = SANE_I18N ("Threshold curve"); + s->opt[OPT_THRESHOLD_CURVE].desc = SANE_I18N ("Dynamic threshold curve, from light to dark, normally 50-65"); + s->opt[OPT_THRESHOLD_CURVE].type = SANE_TYPE_INT; + s->opt[OPT_THRESHOLD_CURVE].unit = SANE_UNIT_NONE; + s->opt[OPT_THRESHOLD_CURVE].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_THRESHOLD_CURVE].constraint.range = &threshold_curve_range; + s->threshold_curve = 50; + + /* disable_interpolation */ + s->opt[OPT_DISABLE_INTERPOLATION].name = "disable-interpolation"; + s->opt[OPT_DISABLE_INTERPOLATION].title = + SANE_I18N ("Disable interpolation"); + s->opt[OPT_DISABLE_INTERPOLATION].desc = + SANE_I18N + ("When using high resolutions where the horizontal resolution is smaller " + "than the vertical resolution this disables horizontal interpolation."); + s->opt[OPT_DISABLE_INTERPOLATION].type = SANE_TYPE_BOOL; + s->opt[OPT_DISABLE_INTERPOLATION].unit = SANE_UNIT_NONE; + s->opt[OPT_DISABLE_INTERPOLATION].constraint_type = SANE_CONSTRAINT_NONE; + s->disable_interpolation = false; + + /* color filter */ + s->opt[OPT_COLOR_FILTER].name = "color-filter"; + s->opt[OPT_COLOR_FILTER].title = SANE_I18N ("Color filter"); + s->opt[OPT_COLOR_FILTER].desc = + SANE_I18N + ("When using gray or lineart this option selects the used color."); + s->opt[OPT_COLOR_FILTER].type = SANE_TYPE_STRING; + s->opt[OPT_COLOR_FILTER].constraint_type = SANE_CONSTRAINT_STRING_LIST; + /* true gray not yet supported for GL847 and GL124 scanners */ + if (!model->is_cis || model->asic_type==AsicType::GL847 || model->asic_type==AsicType::GL124) { + s->opt[OPT_COLOR_FILTER].size = max_string_size (color_filter_list); + s->opt[OPT_COLOR_FILTER].constraint.string_list = color_filter_list; + s->color_filter = s->opt[OPT_COLOR_FILTER].constraint.string_list[1]; + } + else + { + s->opt[OPT_COLOR_FILTER].size = max_string_size (cis_color_filter_list); + s->opt[OPT_COLOR_FILTER].constraint.string_list = cis_color_filter_list; + /* default to "None" ie true gray */ + s->color_filter = s->opt[OPT_COLOR_FILTER].constraint.string_list[3]; + } + + // no support for color filter for cis+gl646 scanners + if (model->asic_type == AsicType::GL646 && model->is_cis) { + DISABLE (OPT_COLOR_FILTER); + } + + /* calibration store file name */ + s->opt[OPT_CALIBRATION_FILE].name = "calibration-file"; + s->opt[OPT_CALIBRATION_FILE].title = SANE_I18N ("Calibration file"); + s->opt[OPT_CALIBRATION_FILE].desc = SANE_I18N ("Specify the calibration file to use"); + s->opt[OPT_CALIBRATION_FILE].type = SANE_TYPE_STRING; + s->opt[OPT_CALIBRATION_FILE].unit = SANE_UNIT_NONE; + s->opt[OPT_CALIBRATION_FILE].size = PATH_MAX; + s->opt[OPT_CALIBRATION_FILE].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; + s->opt[OPT_CALIBRATION_FILE].constraint_type = SANE_CONSTRAINT_NONE; + s->calibration_file.clear(); + /* disable option if ran as root */ +#ifdef HAVE_GETUID + if(geteuid()==0) + { + DISABLE (OPT_CALIBRATION_FILE); + } +#endif + + /* expiration time for calibration cache entries */ + s->opt[OPT_EXPIRATION_TIME].name = "expiration-time"; + s->opt[OPT_EXPIRATION_TIME].title = SANE_I18N ("Calibration cache expiration time"); + s->opt[OPT_EXPIRATION_TIME].desc = SANE_I18N ("Time (in minutes) before a cached calibration expires. " + "A value of 0 means cache is not used. A negative value means cache never expires."); + s->opt[OPT_EXPIRATION_TIME].type = SANE_TYPE_INT; + s->opt[OPT_EXPIRATION_TIME].unit = SANE_UNIT_NONE; + s->opt[OPT_EXPIRATION_TIME].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_EXPIRATION_TIME].constraint.range = &expiration_range; + s->expiration_time = 60; // 60 minutes by default + + /* Powersave time (turn lamp off) */ + s->opt[OPT_LAMP_OFF_TIME].name = "lamp-off-time"; + s->opt[OPT_LAMP_OFF_TIME].title = SANE_I18N ("Lamp off time"); + s->opt[OPT_LAMP_OFF_TIME].desc = + SANE_I18N + ("The lamp will be turned off after the given time (in minutes). " + "A value of 0 means, that the lamp won't be turned off."); + s->opt[OPT_LAMP_OFF_TIME].type = SANE_TYPE_INT; + s->opt[OPT_LAMP_OFF_TIME].unit = SANE_UNIT_NONE; + s->opt[OPT_LAMP_OFF_TIME].constraint_type = SANE_CONSTRAINT_RANGE; + s->opt[OPT_LAMP_OFF_TIME].constraint.range = &time_range; + s->lamp_off_time = 15; // 15 minutes + + /* turn lamp off during scan */ + s->opt[OPT_LAMP_OFF].name = "lamp-off-scan"; + s->opt[OPT_LAMP_OFF].title = SANE_I18N ("Lamp off during scan"); + s->opt[OPT_LAMP_OFF].desc = SANE_I18N ("The lamp will be turned off during scan. "); + s->opt[OPT_LAMP_OFF].type = SANE_TYPE_BOOL; + s->opt[OPT_LAMP_OFF].unit = SANE_UNIT_NONE; + s->opt[OPT_LAMP_OFF].constraint_type = SANE_CONSTRAINT_NONE; + s->lamp_off = false; + + s->opt[OPT_SENSOR_GROUP].name = SANE_NAME_SENSORS; + s->opt[OPT_SENSOR_GROUP].title = SANE_TITLE_SENSORS; + s->opt[OPT_SENSOR_GROUP].desc = SANE_DESC_SENSORS; + s->opt[OPT_SENSOR_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_SENSOR_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_SENSOR_GROUP].size = 0; + s->opt[OPT_SENSOR_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + s->opt[OPT_SCAN_SW].name = SANE_NAME_SCAN; + s->opt[OPT_SCAN_SW].title = SANE_TITLE_SCAN; + s->opt[OPT_SCAN_SW].desc = SANE_DESC_SCAN; + s->opt[OPT_SCAN_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_SCAN_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_SCAN_SW) + s->opt[OPT_SCAN_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_SCAN_SW].cap = SANE_CAP_INACTIVE; + + /* SANE_NAME_FILE is not for buttons */ + s->opt[OPT_FILE_SW].name = "file"; + s->opt[OPT_FILE_SW].title = SANE_I18N ("File button"); + s->opt[OPT_FILE_SW].desc = SANE_I18N ("File button"); + s->opt[OPT_FILE_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_FILE_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_FILE_SW) + s->opt[OPT_FILE_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_FILE_SW].cap = SANE_CAP_INACTIVE; + + s->opt[OPT_EMAIL_SW].name = SANE_NAME_EMAIL; + s->opt[OPT_EMAIL_SW].title = SANE_TITLE_EMAIL; + s->opt[OPT_EMAIL_SW].desc = SANE_DESC_EMAIL; + s->opt[OPT_EMAIL_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_EMAIL_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_EMAIL_SW) + s->opt[OPT_EMAIL_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_EMAIL_SW].cap = SANE_CAP_INACTIVE; + + s->opt[OPT_COPY_SW].name = SANE_NAME_COPY; + s->opt[OPT_COPY_SW].title = SANE_TITLE_COPY; + s->opt[OPT_COPY_SW].desc = SANE_DESC_COPY; + s->opt[OPT_COPY_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_COPY_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_COPY_SW) + s->opt[OPT_COPY_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_COPY_SW].cap = SANE_CAP_INACTIVE; + + s->opt[OPT_PAGE_LOADED_SW].name = SANE_NAME_PAGE_LOADED; + s->opt[OPT_PAGE_LOADED_SW].title = SANE_TITLE_PAGE_LOADED; + s->opt[OPT_PAGE_LOADED_SW].desc = SANE_DESC_PAGE_LOADED; + s->opt[OPT_PAGE_LOADED_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_PAGE_LOADED_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_PAGE_LOADED_SW) + s->opt[OPT_PAGE_LOADED_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_PAGE_LOADED_SW].cap = SANE_CAP_INACTIVE; + + /* OCR button */ + s->opt[OPT_OCR_SW].name = "ocr"; + s->opt[OPT_OCR_SW].title = SANE_I18N ("OCR button"); + s->opt[OPT_OCR_SW].desc = SANE_I18N ("OCR button"); + s->opt[OPT_OCR_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_OCR_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_OCR_SW) + s->opt[OPT_OCR_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_OCR_SW].cap = SANE_CAP_INACTIVE; + + /* power button */ + s->opt[OPT_POWER_SW].name = "power"; + s->opt[OPT_POWER_SW].title = SANE_I18N ("Power button"); + s->opt[OPT_POWER_SW].desc = SANE_I18N ("Power button"); + s->opt[OPT_POWER_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_POWER_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_POWER_SW) + s->opt[OPT_POWER_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_POWER_SW].cap = SANE_CAP_INACTIVE; + + /* extra button */ + s->opt[OPT_EXTRA_SW].name = "extra"; + s->opt[OPT_EXTRA_SW].title = SANE_I18N ("Extra button"); + s->opt[OPT_EXTRA_SW].desc = SANE_I18N ("Extra button"); + s->opt[OPT_EXTRA_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_EXTRA_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_EXTRA_SW) + s->opt[OPT_EXTRA_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_EXTRA_SW].cap = SANE_CAP_INACTIVE; + + /* calibration needed */ + s->opt[OPT_NEED_CALIBRATION_SW].name = "need-calibration"; + s->opt[OPT_NEED_CALIBRATION_SW].title = SANE_I18N ("Needs calibration"); + s->opt[OPT_NEED_CALIBRATION_SW].desc = SANE_I18N ("The scanner needs calibration for the current settings"); + s->opt[OPT_NEED_CALIBRATION_SW].type = SANE_TYPE_BOOL; + s->opt[OPT_NEED_CALIBRATION_SW].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_CALIBRATE) + s->opt[OPT_NEED_CALIBRATION_SW].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_HARD_SELECT | SANE_CAP_ADVANCED; + else + s->opt[OPT_NEED_CALIBRATION_SW].cap = SANE_CAP_INACTIVE; + + /* button group */ + s->opt[OPT_BUTTON_GROUP].name = "buttons"; + s->opt[OPT_BUTTON_GROUP].title = SANE_I18N ("Buttons"); + s->opt[OPT_BUTTON_GROUP].desc = ""; + s->opt[OPT_BUTTON_GROUP].type = SANE_TYPE_GROUP; + s->opt[OPT_BUTTON_GROUP].cap = SANE_CAP_ADVANCED; + s->opt[OPT_BUTTON_GROUP].size = 0; + s->opt[OPT_BUTTON_GROUP].constraint_type = SANE_CONSTRAINT_NONE; + + /* calibrate button */ + s->opt[OPT_CALIBRATE].name = "calibrate"; + s->opt[OPT_CALIBRATE].title = SANE_I18N ("Calibrate"); + s->opt[OPT_CALIBRATE].desc = + SANE_I18N ("Start calibration using special sheet"); + s->opt[OPT_CALIBRATE].type = SANE_TYPE_BUTTON; + s->opt[OPT_CALIBRATE].unit = SANE_UNIT_NONE; + if (model->buttons & GENESYS_HAS_CALIBRATE) + s->opt[OPT_CALIBRATE].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED | + SANE_CAP_AUTOMATIC; + else + s->opt[OPT_CALIBRATE].cap = SANE_CAP_INACTIVE; + + /* clear calibration cache button */ + s->opt[OPT_CLEAR_CALIBRATION].name = "clear-calibration"; + s->opt[OPT_CLEAR_CALIBRATION].title = SANE_I18N ("Clear calibration"); + s->opt[OPT_CLEAR_CALIBRATION].desc = SANE_I18N ("Clear calibration cache"); + s->opt[OPT_CLEAR_CALIBRATION].type = SANE_TYPE_BUTTON; + s->opt[OPT_CLEAR_CALIBRATION].unit = SANE_UNIT_NONE; + s->opt[OPT_CLEAR_CALIBRATION].size = 0; + s->opt[OPT_CLEAR_CALIBRATION].constraint_type = SANE_CONSTRAINT_NONE; + s->opt[OPT_CLEAR_CALIBRATION].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; + + /* force calibration cache button */ + s->opt[OPT_FORCE_CALIBRATION].name = "force-calibration"; + s->opt[OPT_FORCE_CALIBRATION].title = SANE_I18N("Force calibration"); + s->opt[OPT_FORCE_CALIBRATION].desc = SANE_I18N("Force calibration ignoring all and any calibration caches"); + s->opt[OPT_FORCE_CALIBRATION].type = SANE_TYPE_BUTTON; + s->opt[OPT_FORCE_CALIBRATION].unit = SANE_UNIT_NONE; + s->opt[OPT_FORCE_CALIBRATION].size = 0; + s->opt[OPT_FORCE_CALIBRATION].constraint_type = SANE_CONSTRAINT_NONE; + s->opt[OPT_FORCE_CALIBRATION].cap = + SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | SANE_CAP_ADVANCED; + + // ignore offsets option + s->opt[OPT_IGNORE_OFFSETS].name = "ignore-internal-offsets"; + s->opt[OPT_IGNORE_OFFSETS].title = SANE_I18N("Ignore internal offsets"); + s->opt[OPT_IGNORE_OFFSETS].desc = + SANE_I18N("Acquires the image including the internal calibration areas of the scanner"); + s->opt[OPT_IGNORE_OFFSETS].type = SANE_TYPE_BUTTON; + s->opt[OPT_IGNORE_OFFSETS].unit = SANE_UNIT_NONE; + s->opt[OPT_IGNORE_OFFSETS].size = 0; + s->opt[OPT_IGNORE_OFFSETS].constraint_type = SANE_CONSTRAINT_NONE; + s->opt[OPT_IGNORE_OFFSETS].cap = SANE_CAP_SOFT_DETECT | SANE_CAP_SOFT_SELECT | + SANE_CAP_ADVANCED; + + calc_parameters(s); +} + +static bool present; + +// this function is passed to C API, it must not throw +static SANE_Status +check_present (SANE_String_Const devname) noexcept +{ + DBG_HELPER_ARGS(dbg, "%s detected.", devname); + present = true; + return SANE_STATUS_GOOD; +} + +static Genesys_Device* attach_usb_device(const char* devname, + std::uint16_t vendor_id, std::uint16_t product_id) +{ + Genesys_USB_Device_Entry* found_usb_dev = nullptr; + for (auto& usb_dev : *s_usb_devices) { + if (usb_dev.vendor == vendor_id && + usb_dev.product == product_id) + { + found_usb_dev = &usb_dev; + break; + } + } + + if (found_usb_dev == nullptr) { + throw SaneException("vendor 0x%xd product 0x%xd is not supported by this backend", + vendor_id, product_id); + } + + s_devices->emplace_back(); + Genesys_Device* dev = &s_devices->back(); + dev->file_name = devname; + + dev->model = &found_usb_dev->model; + dev->vendorId = found_usb_dev->vendor; + dev->productId = found_usb_dev->product; + dev->usb_mode = 0; // i.e. unset + dev->already_initialized = false; + return dev; +} + +static Genesys_Device* attach_device_by_name(SANE_String_Const devname, bool may_wait) +{ + DBG_HELPER_ARGS(dbg, " devname: %s, may_wait = %d", devname, may_wait); + + if (!devname) { + throw SaneException("devname must not be nullptr"); + } + + for (auto& dev : *s_devices) { + if (dev.file_name == devname) { + DBG(DBG_info, "%s: device `%s' was already in device list\n", __func__, devname); + return &dev; + } + } + + DBG(DBG_info, "%s: trying to open device `%s'\n", __func__, devname); + + UsbDevice usb_dev; + + usb_dev.open(devname); + DBG(DBG_info, "%s: device `%s' successfully opened\n", __func__, devname); + + int vendor, product; + usb_dev.get_vendor_product(vendor, product); + usb_dev.close(); + + /* KV-SS080 is an auxiliary device which requires a master device to be here */ + if(vendor == 0x04da && product == 0x100f) + { + present = false; + sanei_usb_find_devices (vendor, 0x1006, check_present); + sanei_usb_find_devices (vendor, 0x1007, check_present); + sanei_usb_find_devices (vendor, 0x1010, check_present); + if (present == false) { + throw SaneException("master device not present"); + } + } + + Genesys_Device* dev = attach_usb_device(devname, vendor, product); + + DBG(DBG_info, "%s: found %s flatbed scanner %s at %s\n", __func__, dev->model->vendor, + dev->model->model, dev->file_name.c_str()); + + return dev; +} + +// this function is passed to C API and must not throw +static SANE_Status attach_one_device(SANE_String_Const devname) noexcept +{ + DBG_HELPER(dbg); + return wrap_exceptions_to_status_code(__func__, [=]() + { + attach_device_by_name(devname, false); + }); +} + +/* configuration framework functions */ + +// this function is passed to C API, it must not throw +static SANE_Status +config_attach_genesys(SANEI_Config __sane_unused__ *config, const char *devname) noexcept +{ + /* the devname has been processed and is ready to be used + * directly. Since the backend is an USB only one, we can + * call sanei_usb_attach_matching_devices straight */ + sanei_usb_attach_matching_devices (devname, attach_one_device); + + return SANE_STATUS_GOOD; +} + +/* probes for scanner to attach to the backend */ +static void probe_genesys_devices() +{ + DBG_HELPER(dbg); + if (is_testing_mode()) { + attach_usb_device(get_testing_device_name().c_str(), + get_testing_vendor_id(), get_testing_product_id()); + return; + } + + SANEI_Config config; + + // set configuration options structure : no option for this backend + config.descriptors = nullptr; + config.values = nullptr; + config.count = 0; + + TIE(sanei_configure_attach(GENESYS_CONFIG_FILE, &config, config_attach_genesys)); + + DBG(DBG_info, "%s: %zu devices currently attached\n", __func__, s_devices->size()); +} + +/** + * This should be changed if one of the substructures of + Genesys_Calibration_Cache change, but it must be changed if there are + changes that don't change size -- at least for now, as we store most + of Genesys_Calibration_Cache as is. +*/ +static const char* CALIBRATION_IDENT = "sane_genesys"; +static const int CALIBRATION_VERSION = 21; + +bool read_calibration(std::istream& str, Genesys_Device::Calibration& calibration, + const std::string& path) +{ + DBG_HELPER(dbg); + + std::string ident; + serialize(str, ident); + + if (ident != CALIBRATION_IDENT) { + DBG(DBG_info, "%s: Incorrect calibration file '%s' header\n", __func__, path.c_str()); + return false; + } + + size_t version; + serialize(str, version); + + if (version != CALIBRATION_VERSION) { + DBG(DBG_info, "%s: Incorrect calibration file '%s' version\n", __func__, path.c_str()); + return false; + } + + calibration.clear(); + serialize(str, calibration); + return true; +} + +/** + * reads previously cached calibration data + * from file defined in dev->calib_file + */ +static bool sanei_genesys_read_calibration(Genesys_Device::Calibration& calibration, + const std::string& path) +{ + DBG_HELPER(dbg); + + std::ifstream str; + str.open(path); + if (!str.is_open()) { + DBG(DBG_info, "%s: Cannot open %s\n", __func__, path.c_str()); + return false; + } + + return read_calibration(str, calibration, path); +} + +void write_calibration(std::ostream& str, Genesys_Device::Calibration& calibration) +{ + std::string ident = CALIBRATION_IDENT; + serialize(str, ident); + size_t version = CALIBRATION_VERSION; + serialize(str, version); + serialize_newline(str); + serialize(str, calibration); +} + +static void write_calibration(Genesys_Device::Calibration& calibration, const std::string& path) +{ + DBG_HELPER(dbg); + + std::ofstream str; + str.open(path); + if (!str.is_open()) { + throw SaneException("Cannot open calibration for writing"); + } + write_calibration(str, calibration); +} + +/** @brief buffer scanned picture + * In order to allow digital processing, we must be able to put all the + * scanned picture in a buffer. + */ +static void genesys_buffer_image(Genesys_Scanner *s) +{ + DBG_HELPER(dbg); + size_t maximum; /**> maximum bytes size of the scan */ + size_t len; /**> length of scanned data read */ + size_t total; /**> total of butes read */ + size_t size; /**> size of image buffer */ + size_t read_size; /**> size of reads */ + int lines; /** number of lines of the scan */ + Genesys_Device *dev = s->dev; + + /* compute maximum number of lines for the scan */ + if (s->params.lines > 0) + { + lines = s->params.lines; + } + else + { + lines = static_cast((dev->model->y_size * dev->settings.yres) / MM_PER_INCH); + } + DBG(DBG_info, "%s: buffering %d lines of %d bytes\n", __func__, lines, + s->params.bytes_per_line); + + /* maximum bytes to read */ + maximum = s->params.bytes_per_line * lines; + if (s->dev->settings.scan_mode == ScanColorMode::LINEART) { + maximum *= 8; + } + + /* initial size of the read buffer */ + size = + ((2048 * 2048) / s->params.bytes_per_line) * s->params.bytes_per_line; + + /* read size */ + read_size = size / 2; + + dev->img_buffer.resize(size); + + /* loop reading data until we reach maximum or EOF */ + total = 0; + while (total < maximum) { + len = size - maximum; + if (len > read_size) + { + len = read_size; + } + + try { + genesys_read_ordered_data(dev, dev->img_buffer.data() + total, &len); + } catch (const SaneException& e) { + if (e.status() == SANE_STATUS_EOF) { + // ideally we shouldn't end up here, but because computations are duplicated and + // slightly different everywhere in the genesys backend, we have no other choice + break; + } + throw; + } + total += len; + + // do we need to enlarge read buffer ? + if (total + read_size > size) { + size += read_size; + dev->img_buffer.resize(size); + } + } + + /* since digital processing is going to take place, + * issue head parking command so that the head move while + * computing so we can save time + */ + if (!dev->model->is_sheetfed && !dev->parking) { + dev->cmd_set->move_back_home(dev, dev->model->flags & GENESYS_FLAG_MUST_WAIT); + dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); + } + + /* in case of dynamic lineart, we have buffered gray data which + * must be converted to lineart first */ + if (s->dev->settings.scan_mode == ScanColorMode::LINEART) { + total/=8; + std::vector lineart(total); + + genesys_gray_lineart (dev, + dev->img_buffer.data(), + lineart.data(), + dev->settings.pixels, + (total*8)/dev->settings.pixels, + dev->settings.threshold); + dev->img_buffer = lineart; + } + + /* update counters */ + dev->total_bytes_to_read = total; + dev->total_bytes_read = 0; + + /* update params */ + s->params.lines = total / s->params.bytes_per_line; + if (DBG_LEVEL >= DBG_io2) + { + sanei_genesys_write_pnm_file("gl_unprocessed.pnm", dev->img_buffer.data(), s->params.depth, + s->params.format==SANE_FRAME_RGB ? 3 : 1, + s->params.pixels_per_line, s->params.lines); + } +} + +/* -------------------------- SANE API functions ------------------------- */ + +void sane_init_impl(SANE_Int * version_code, SANE_Auth_Callback authorize) +{ + DBG_INIT (); + DBG_HELPER_ARGS(dbg, "authorize %s null", authorize ? "!=" : "=="); + DBG(DBG_init, "SANE Genesys backend from %s\n", PACKAGE_STRING); + + if (!is_testing_mode()) { +#ifdef HAVE_LIBUSB + DBG(DBG_init, "SANE Genesys backend built with libusb-1.0\n"); +#endif +#ifdef HAVE_LIBUSB_LEGACY + DBG(DBG_init, "SANE Genesys backend built with libusb\n"); +#endif + } + + if (version_code) { + *version_code = SANE_VERSION_CODE(SANE_CURRENT_MAJOR, SANE_CURRENT_MINOR, 0); + } + + if (!is_testing_mode()) { + sanei_usb_init(); + } + + /* init sanei_magic */ + sanei_magic_init(); + + s_scanners.init(); + s_devices.init(); + s_sane_devices.init(); + s_sane_devices_data.init(); + s_sane_devices_ptrs.init(); + genesys_init_sensor_tables(); + genesys_init_frontend_tables(); + genesys_init_gpo_tables(); + genesys_init_motor_tables(); + genesys_init_motor_profile_tables(); + genesys_init_usb_device_tables(); + + + DBG(DBG_info, "%s: %s endian machine\n", __func__, +#ifdef WORDS_BIGENDIAN + "big" +#else + "little" +#endif + ); + + // cold-plug case :detection of allready connected scanners + probe_genesys_devices(); +} + + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_init(SANE_Int * version_code, SANE_Auth_Callback authorize) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_init_impl(version_code, authorize); + }); +} + +void +sane_exit_impl(void) +{ + DBG_HELPER(dbg); + + if (!is_testing_mode()) { + sanei_usb_exit(); + } + + run_functions_at_backend_exit(); +} + +SANE_GENESYS_API_LINKAGE +void sane_exit() +{ + catch_all_exceptions(__func__, [](){ sane_exit_impl(); }); +} + +void sane_get_devices_impl(const SANE_Device *** device_list, SANE_Bool local_only) +{ + DBG_HELPER_ARGS(dbg, "local_only = %s", local_only ? "true" : "false"); + + if (!is_testing_mode()) { + // hot-plug case : detection of newly connected scanners */ + sanei_usb_scan_devices(); + } + probe_genesys_devices(); + + s_sane_devices->clear(); + s_sane_devices_data->clear(); + s_sane_devices_ptrs->clear(); + s_sane_devices->reserve(s_devices->size()); + s_sane_devices_data->reserve(s_devices->size()); + s_sane_devices_ptrs->reserve(s_devices->size() + 1); + + for (auto dev_it = s_devices->begin(); dev_it != s_devices->end();) { + + if (is_testing_mode()) { + present = true; + } else { + present = false; + sanei_usb_find_devices(dev_it->vendorId, dev_it->productId, check_present); + } + + if (present) { + s_sane_devices->emplace_back(); + s_sane_devices_data->emplace_back(); + auto& sane_device = s_sane_devices->back(); + auto& sane_device_data = s_sane_devices_data->back(); + sane_device_data.name = dev_it->file_name; + sane_device.name = sane_device_data.name.c_str(); + sane_device.vendor = dev_it->model->vendor; + sane_device.model = dev_it->model->model; + sane_device.type = "flatbed scanner"; + s_sane_devices_ptrs->push_back(&sane_device); + dev_it++; + } else { + dev_it = s_devices->erase(dev_it); + } + } + s_sane_devices_ptrs->push_back(nullptr); + + *const_cast(device_list) = s_sane_devices_ptrs->data(); +} + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_get_devices(const SANE_Device *** device_list, SANE_Bool local_only) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_get_devices_impl(device_list, local_only); + }); +} + +static void sane_open_impl(SANE_String_Const devicename, SANE_Handle * handle) +{ + DBG_HELPER_ARGS(dbg, "devicename = %s", devicename); + Genesys_Device* dev = nullptr; + + /* devicename="" or devicename="genesys" are default values that use + * first available device + */ + if (devicename[0] && strcmp ("genesys", devicename) != 0) { + /* search for the given devicename in the device list */ + for (auto& d : *s_devices) { + if (d.file_name == devicename) { + dev = &d; + break; + } + } + + if (dev) { + DBG(DBG_info, "%s: found `%s' in devlist\n", __func__, dev->model->name); + } else if (is_testing_mode()) { + DBG(DBG_info, "%s: couldn't find `%s' in devlist, not attaching", __func__, devicename); + } else { + DBG(DBG_info, "%s: couldn't find `%s' in devlist, trying attach\n", __func__, + devicename); + dbg.status("attach_device_by_name"); + dev = attach_device_by_name(devicename, true); + dbg.clear(); + } + } else { + // empty devicename or "genesys" -> use first device + if (!s_devices->empty()) { + dev = &s_devices->front(); + DBG(DBG_info, "%s: empty devicename, trying `%s'\n", __func__, dev->file_name.c_str()); + } + } + + if (!dev) { + throw SaneException("could not find the device to open: %s", devicename); + } + + if (dev->model->flags & GENESYS_FLAG_UNTESTED) + { + DBG(DBG_error0, "WARNING: Your scanner is not fully supported or at least \n"); + DBG(DBG_error0, " had only limited testing. Please be careful and \n"); + DBG(DBG_error0, " report any failure/success to \n"); + DBG(DBG_error0, " sane-devel@alioth-lists.debian.net. Please provide as many\n"); + DBG(DBG_error0, " details as possible, e.g. the exact name of your\n"); + DBG(DBG_error0, " scanner and what does (not) work.\n"); + } + + dbg.vstatus("open device '%s'", dev->file_name.c_str()); + + if (is_testing_mode()) { + auto interface = std::unique_ptr{new TestScannerInterface{dev}}; + interface->set_checkpoint_callback(get_testing_checkpoint_callback()); + dev->interface = std::move(interface); + } else { + dev->interface = std::unique_ptr{new ScannerInterfaceUsb{dev}}; + } + dev->interface->get_usb_device().open(dev->file_name.c_str()); + dbg.clear(); + + s_scanners->push_back(Genesys_Scanner()); + auto* s = &s_scanners->back(); + + s->dev = dev; + s->scanning = false; + s->dev->parking = false; + s->dev->read_active = false; + s->dev->force_calibration = 0; + s->dev->line_count = 0; + + *handle = s; + + if (!dev->already_initialized) { + sanei_genesys_init_structs (dev); + } + + init_options(s); + + sanei_genesys_init_cmd_set(s->dev); + + // FIXME: we create sensor tables for the sensor, this should happen when we know which sensor + // we will select + dev->cmd_set->init(dev); + + // some hardware capabilities are detected through sensors + s->dev->cmd_set->update_hardware_sensors (s); + + /* here is the place to fetch a stored calibration cache */ + if (s->dev->force_calibration == 0) + { + auto path = calibration_filename(s->dev); + s->calibration_file = path; + s->dev->calib_file = path; + DBG(DBG_info, "%s: Calibration filename set to:\n", __func__); + DBG(DBG_info, "%s: >%s<\n", __func__, s->dev->calib_file.c_str()); + + catch_all_exceptions(__func__, [&]() + { + sanei_genesys_read_calibration(s->dev->calibration_cache, s->dev->calib_file); + }); + } +} + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_open(SANE_String_Const devicename, SANE_Handle* handle) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_open_impl(devicename, handle); + }); +} + +void +sane_close_impl(SANE_Handle handle) +{ + DBG_HELPER(dbg); + + /* remove handle from list of open handles: */ + auto it = s_scanners->end(); + for (auto it2 = s_scanners->begin(); it2 != s_scanners->end(); it2++) + { + if (&*it2 == handle) { + it = it2; + break; + } + } + if (it == s_scanners->end()) + { + DBG(DBG_error, "%s: invalid handle %p\n", __func__, handle); + return; /* oops, not a handle we know about */ + } + + Genesys_Scanner* s = &*it; + + /* eject document for sheetfed scanners */ + if (s->dev->model->is_sheetfed) { + catch_all_exceptions(__func__, [&](){ s->dev->cmd_set->eject_document(s->dev); }); + } + else + { + /* in case scanner is parking, wait for the head + * to reach home position */ + if (s->dev->parking) { + sanei_genesys_wait_for_home(s->dev); + } + } + + // enable power saving before leaving + s->dev->cmd_set->save_power(s->dev, true); + + // here is the place to store calibration cache + if (s->dev->force_calibration == 0 && !is_testing_mode()) { + catch_all_exceptions(__func__, [&](){ write_calibration(s->dev->calibration_cache, + s->dev->calib_file); }); + } + + s->dev->already_initialized = false; + + s->dev->clear(); + + // LAMP OFF : same register across all the ASICs */ + s->dev->interface->write_register(0x03, 0x00); + + catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().clear_halt(); }); + + // we need this to avoid these ASIC getting stuck in bulk writes + catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().reset(); }); + + // not freeing s->dev because it's in the dev list + catch_all_exceptions(__func__, [&](){ s->dev->interface->get_usb_device().close(); }); + + s_scanners->erase(it); +} + +SANE_GENESYS_API_LINKAGE +void sane_close(SANE_Handle handle) +{ + catch_all_exceptions(__func__, [=]() + { + sane_close_impl(handle); + }); +} + +const SANE_Option_Descriptor * +sane_get_option_descriptor_impl(SANE_Handle handle, SANE_Int option) +{ + DBG_HELPER(dbg); + Genesys_Scanner* s = reinterpret_cast(handle); + + if (static_cast(option) >= NUM_OPTIONS) { + return nullptr; + } + + DBG(DBG_io2, "%s: option = %s (%d)\n", __func__, s->opt[option].name, option); + return s->opt + option; +} + + +SANE_GENESYS_API_LINKAGE +const SANE_Option_Descriptor* sane_get_option_descriptor(SANE_Handle handle, SANE_Int option) +{ + const SANE_Option_Descriptor* ret = nullptr; + catch_all_exceptions(__func__, [&]() + { + ret = sane_get_option_descriptor_impl(handle, option); + }); + return ret; +} + +static void print_option(DebugMessageHelper& dbg, const Genesys_Scanner& s, int option, void* val) +{ + switch (s.opt[option].type) { + case SANE_TYPE_INT: { + dbg.vlog(DBG_proc, "value: %d", *reinterpret_cast(val)); + return; + } + case SANE_TYPE_BOOL: { + dbg.vlog(DBG_proc, "value: %s", *reinterpret_cast(val) ? "true" : "false"); + return; + } + case SANE_TYPE_FIXED: { + dbg.vlog(DBG_proc, "value: %f", SANE_UNFIX(*reinterpret_cast(val))); + return; + } + case SANE_TYPE_STRING: { + dbg.vlog(DBG_proc, "value: %s", reinterpret_cast(val)); + return; + } + default: break; + } + dbg.log(DBG_proc, "value: (non-printable)"); +} + +static void get_option_value(Genesys_Scanner* s, int option, void* val) +{ + DBG_HELPER_ARGS(dbg, "option: %s (%d)", s->opt[option].name, option); + unsigned int i; + SANE_Word* table = nullptr; + std::vector gamma_table; + unsigned option_size = 0; + + const Genesys_Sensor* sensor = nullptr; + if (sanei_genesys_has_sensor(s->dev, s->dev->settings.xres, s->dev->settings.get_channels(), + s->dev->settings.scan_method)) + { + sensor = &sanei_genesys_find_sensor(s->dev, s->dev->settings.xres, + s->dev->settings.get_channels(), + s->dev->settings.scan_method); + } + + switch (option) + { + /* geometry */ + case OPT_TL_X: + *reinterpret_cast(val) = s->pos_top_left_x; + break; + case OPT_TL_Y: + *reinterpret_cast(val) = s->pos_top_left_y; + break; + case OPT_BR_X: + *reinterpret_cast(val) = s->pos_bottom_right_x; + break; + case OPT_BR_Y: + *reinterpret_cast(val) = s->pos_bottom_right_y; + break; + /* word options: */ + case OPT_NUM_OPTS: + *reinterpret_cast(val) = NUM_OPTIONS; + break; + case OPT_RESOLUTION: + *reinterpret_cast(val) = s->resolution; + break; + case OPT_BIT_DEPTH: + *reinterpret_cast(val) = s->bit_depth; + break; + case OPT_PREVIEW: + *reinterpret_cast(val) = s->preview; + break; + case OPT_THRESHOLD: + *reinterpret_cast(val) = s->threshold; + break; + case OPT_THRESHOLD_CURVE: + *reinterpret_cast(val) = s->threshold_curve; + break; + case OPT_DISABLE_INTERPOLATION: + *reinterpret_cast(val) = s->disable_interpolation; + break; + case OPT_LAMP_OFF: + *reinterpret_cast(val) = s->lamp_off; + break; + case OPT_LAMP_OFF_TIME: + *reinterpret_cast(val) = s->lamp_off_time; + break; + case OPT_SWDESKEW: + *reinterpret_cast(val) = s->swdeskew; + break; + case OPT_SWCROP: + *reinterpret_cast(val) = s->swcrop; + break; + case OPT_SWDESPECK: + *reinterpret_cast(val) = s->swdespeck; + break; + case OPT_SWDEROTATE: + *reinterpret_cast(val) = s->swderotate; + break; + case OPT_SWSKIP: + *reinterpret_cast(val) = s->swskip; + break; + case OPT_DESPECK: + *reinterpret_cast(val) = s->despeck; + break; + case OPT_CONTRAST: + *reinterpret_cast(val) = s->contrast; + break; + case OPT_BRIGHTNESS: + *reinterpret_cast(val) = s->brightness; + break; + case OPT_EXPIRATION_TIME: + *reinterpret_cast(val) = s->expiration_time; + break; + case OPT_CUSTOM_GAMMA: + *reinterpret_cast(val) = s->custom_gamma; + break; + + /* string options: */ + case OPT_MODE: + std::strcpy(reinterpret_cast(val), s->mode.c_str()); + break; + case OPT_COLOR_FILTER: + std::strcpy(reinterpret_cast(val), s->color_filter.c_str()); + break; + case OPT_CALIBRATION_FILE: + std::strcpy(reinterpret_cast(val), s->calibration_file.c_str()); + break; + case OPT_SOURCE: + std::strcpy(reinterpret_cast(val), scan_method_to_option_string(s->scan_method)); + break; + + /* word array options */ + case OPT_GAMMA_VECTOR: + if (!sensor) + throw SaneException("Unsupported scanner mode selected"); + + table = reinterpret_cast(val); + if (s->color_filter == "Red") { + gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_RED); + } else if (s->color_filter == "Blue") { + gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_BLUE); + } else { + gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_GREEN); + } + option_size = s->opt[option].size / sizeof (SANE_Word); + if (gamma_table.size() != option_size) { + throw std::runtime_error("The size of the gamma tables does not match"); + } + for (i = 0; i < option_size; i++) { + table[i] = gamma_table[i]; + } + break; + case OPT_GAMMA_VECTOR_R: + if (!sensor) + throw SaneException("Unsupported scanner mode selected"); + + table = reinterpret_cast(val); + gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_RED); + option_size = s->opt[option].size / sizeof (SANE_Word); + if (gamma_table.size() != option_size) { + throw std::runtime_error("The size of the gamma tables does not match"); + } + for (i = 0; i < option_size; i++) { + table[i] = gamma_table[i]; + } + break; + case OPT_GAMMA_VECTOR_G: + if (!sensor) + throw SaneException("Unsupported scanner mode selected"); + + table = reinterpret_cast(val); + gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_GREEN); + option_size = s->opt[option].size / sizeof (SANE_Word); + if (gamma_table.size() != option_size) { + throw std::runtime_error("The size of the gamma tables does not match"); + } + for (i = 0; i < option_size; i++) { + table[i] = gamma_table[i]; + } + break; + case OPT_GAMMA_VECTOR_B: + if (!sensor) + throw SaneException("Unsupported scanner mode selected"); + + table = reinterpret_cast(val); + gamma_table = get_gamma_table(s->dev, *sensor, GENESYS_BLUE); + option_size = s->opt[option].size / sizeof (SANE_Word); + if (gamma_table.size() != option_size) { + throw std::runtime_error("The size of the gamma tables does not match"); + } + for (i = 0; i < option_size; i++) { + table[i] = gamma_table[i]; + } + break; + /* sensors */ + case OPT_SCAN_SW: + case OPT_FILE_SW: + case OPT_EMAIL_SW: + case OPT_COPY_SW: + case OPT_PAGE_LOADED_SW: + case OPT_OCR_SW: + case OPT_POWER_SW: + case OPT_EXTRA_SW: + s->dev->cmd_set->update_hardware_sensors(s); + *reinterpret_cast(val) = s->buttons[genesys_option_to_button(option)].read(); + break; + + case OPT_NEED_CALIBRATION_SW: { + if (!sensor) { + throw SaneException("Unsupported scanner mode selected"); + } + + // scanner needs calibration for current mode unless a matching calibration cache is + // found + + bool result = true; + + auto session = s->dev->cmd_set->calculate_scan_session(s->dev, *sensor, + s->dev->settings); + + for (auto& cache : s->dev->calibration_cache) { + if (sanei_genesys_is_compatible_calibration(s->dev, session, &cache, false)) { + *reinterpret_cast(val) = SANE_FALSE; + } + } + *reinterpret_cast(val) = result; + break; + } + default: + DBG(DBG_warn, "%s: can't get unknown option %d\n", __func__, option); + } + print_option(dbg, *s, option, val); +} + +/** @brief set calibration file value + * Set calibration file value. Load new cache values from file if it exists, + * else creates the file*/ +static void set_calibration_value(Genesys_Scanner* s, const char* val) +{ + DBG_HELPER(dbg); + + std::string new_calib_path = val; + Genesys_Device::Calibration new_calibration; + + bool is_calib_success = false; + catch_all_exceptions(__func__, [&]() + { + is_calib_success = sanei_genesys_read_calibration(new_calibration, new_calib_path); + }); + + if (!is_calib_success) { + return; + } + + s->dev->calibration_cache = std::move(new_calibration); + s->dev->calib_file = new_calib_path; + s->calibration_file = new_calib_path; + DBG(DBG_info, "%s: Calibration filename set to '%s':\n", __func__, new_calib_path.c_str()); +} + +/* sets an option , called by sane_control_option */ +static void set_option_value(Genesys_Scanner* s, int option, void *val, SANE_Int* myinfo) +{ + DBG_HELPER_ARGS(dbg, "option: %s (%d)", s->opt[option].name, option); + print_option(dbg, *s, option, val); + + SANE_Word *table; + unsigned int i; + unsigned option_size = 0; + + switch (option) + { + case OPT_TL_X: + s->pos_top_left_x = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_TL_Y: + s->pos_top_left_y = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_BR_X: + s->pos_bottom_right_x = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_BR_Y: + s->pos_bottom_right_y = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_RESOLUTION: + s->resolution = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_THRESHOLD: + s->threshold = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_THRESHOLD_CURVE: + s->threshold_curve = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWCROP: + s->swcrop = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWDESKEW: + s->swdeskew = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_DESPECK: + s->despeck = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWDEROTATE: + s->swderotate = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWSKIP: + s->swskip = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_DISABLE_INTERPOLATION: + s->disable_interpolation = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_LAMP_OFF: + s->lamp_off = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_PREVIEW: + s->preview = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_BRIGHTNESS: + s->brightness = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_CONTRAST: + s->contrast = *reinterpret_cast(val); + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS; + break; + case OPT_SWDESPECK: + s->swdespeck = *reinterpret_cast(val); + if (s->swdespeck) { + ENABLE(OPT_DESPECK); + } else { + DISABLE(OPT_DESPECK); + } + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + /* software enhancement functions only apply to 8 or 1 bits data */ + case OPT_BIT_DEPTH: + s->bit_depth = *reinterpret_cast(val); + if(s->bit_depth>8) + { + DISABLE(OPT_SWDESKEW); + DISABLE(OPT_SWDESPECK); + DISABLE(OPT_SWCROP); + DISABLE(OPT_DESPECK); + DISABLE(OPT_SWDEROTATE); + DISABLE(OPT_SWSKIP); + DISABLE(OPT_CONTRAST); + DISABLE(OPT_BRIGHTNESS); + } + else + { + ENABLE(OPT_SWDESKEW); + ENABLE(OPT_SWDESPECK); + ENABLE(OPT_SWCROP); + ENABLE(OPT_DESPECK); + ENABLE(OPT_SWDEROTATE); + ENABLE(OPT_SWSKIP); + ENABLE(OPT_CONTRAST); + ENABLE(OPT_BRIGHTNESS); + } + calc_parameters(s); + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + case OPT_SOURCE: { + auto scan_method = option_string_to_scan_method(reinterpret_cast(val)); + if (s->scan_method != scan_method) { + s->scan_method = scan_method; + + set_xy_range_option_values(*s); + set_resolution_option_values(*s, false); + + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + } + break; + } + case OPT_MODE: + s->mode = reinterpret_cast(val); + + if (s->mode == SANE_VALUE_SCAN_MODE_LINEART) + { + ENABLE (OPT_THRESHOLD); + ENABLE (OPT_THRESHOLD_CURVE); + DISABLE (OPT_BIT_DEPTH); + if (s->dev->model->asic_type != AsicType::GL646 || !s->dev->model->is_cis) { + ENABLE(OPT_COLOR_FILTER); + } + } + else + { + DISABLE (OPT_THRESHOLD); + DISABLE (OPT_THRESHOLD_CURVE); + if (s->mode == SANE_VALUE_SCAN_MODE_GRAY) + { + if (s->dev->model->asic_type != AsicType::GL646 || !s->dev->model->is_cis) { + ENABLE(OPT_COLOR_FILTER); + } + create_bpp_list (s, s->dev->model->bpp_gray_values); + s->bit_depth = s->dev->model->bpp_gray_values[0]; + } + else + { + DISABLE (OPT_COLOR_FILTER); + create_bpp_list (s, s->dev->model->bpp_color_values); + s->bit_depth = s->dev->model->bpp_color_values[0]; + } + } + calc_parameters(s); + + /* if custom gamma, toggle gamma table options according to the mode */ + if (s->custom_gamma) + { + if (s->mode == SANE_VALUE_SCAN_MODE_COLOR) + { + DISABLE (OPT_GAMMA_VECTOR); + ENABLE (OPT_GAMMA_VECTOR_R); + ENABLE (OPT_GAMMA_VECTOR_G); + ENABLE (OPT_GAMMA_VECTOR_B); + } + else + { + ENABLE (OPT_GAMMA_VECTOR); + DISABLE (OPT_GAMMA_VECTOR_R); + DISABLE (OPT_GAMMA_VECTOR_G); + DISABLE (OPT_GAMMA_VECTOR_B); + } + } + + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + case OPT_COLOR_FILTER: + s->color_filter = reinterpret_cast(val); + calc_parameters(s); + break; + case OPT_CALIBRATION_FILE: + if (s->dev->force_calibration == 0) { + set_calibration_value(s, reinterpret_cast(val)); + } + break; + case OPT_LAMP_OFF_TIME: + if (*reinterpret_cast(val) != s->lamp_off_time) { + s->lamp_off_time = *reinterpret_cast(val); + s->dev->cmd_set->set_powersaving(s->dev, s->lamp_off_time); + } + break; + case OPT_EXPIRATION_TIME: + if (*reinterpret_cast(val) != s->expiration_time) { + s->expiration_time = *reinterpret_cast(val); + // BUG: this is most likely not intended behavior, found out during refactor + s->dev->cmd_set->set_powersaving(s->dev, s->expiration_time); + } + break; + + case OPT_CUSTOM_GAMMA: + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + s->custom_gamma = *reinterpret_cast(val); + + if (s->custom_gamma) { + if (s->mode == SANE_VALUE_SCAN_MODE_COLOR) + { + DISABLE (OPT_GAMMA_VECTOR); + ENABLE (OPT_GAMMA_VECTOR_R); + ENABLE (OPT_GAMMA_VECTOR_G); + ENABLE (OPT_GAMMA_VECTOR_B); + } + else + { + ENABLE (OPT_GAMMA_VECTOR); + DISABLE (OPT_GAMMA_VECTOR_R); + DISABLE (OPT_GAMMA_VECTOR_G); + DISABLE (OPT_GAMMA_VECTOR_B); + } + } + else + { + DISABLE (OPT_GAMMA_VECTOR); + DISABLE (OPT_GAMMA_VECTOR_R); + DISABLE (OPT_GAMMA_VECTOR_G); + DISABLE (OPT_GAMMA_VECTOR_B); + for (auto& table : s->dev->gamma_override_tables) { + table.clear(); + } + } + break; + + case OPT_GAMMA_VECTOR: + table = reinterpret_cast(val); + option_size = s->opt[option].size / sizeof (SANE_Word); + + s->dev->gamma_override_tables[GENESYS_RED].resize(option_size); + s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size); + s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size); + for (i = 0; i < option_size; i++) { + s->dev->gamma_override_tables[GENESYS_RED][i] = table[i]; + s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i]; + s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i]; + } + break; + case OPT_GAMMA_VECTOR_R: + table = reinterpret_cast(val); + option_size = s->opt[option].size / sizeof (SANE_Word); + s->dev->gamma_override_tables[GENESYS_RED].resize(option_size); + for (i = 0; i < option_size; i++) { + s->dev->gamma_override_tables[GENESYS_RED][i] = table[i]; + } + break; + case OPT_GAMMA_VECTOR_G: + table = reinterpret_cast(val); + option_size = s->opt[option].size / sizeof (SANE_Word); + s->dev->gamma_override_tables[GENESYS_GREEN].resize(option_size); + for (i = 0; i < option_size; i++) { + s->dev->gamma_override_tables[GENESYS_GREEN][i] = table[i]; + } + break; + case OPT_GAMMA_VECTOR_B: + table = reinterpret_cast(val); + option_size = s->opt[option].size / sizeof (SANE_Word); + s->dev->gamma_override_tables[GENESYS_BLUE].resize(option_size); + for (i = 0; i < option_size; i++) { + s->dev->gamma_override_tables[GENESYS_BLUE][i] = table[i]; + } + break; + case OPT_CALIBRATE: { + auto& sensor = sanei_genesys_find_sensor_for_write(s->dev, s->dev->settings.xres, + s->dev->settings.get_channels(), + s->dev->settings.scan_method); + catch_all_exceptions(__func__, [&]() + { + s->dev->cmd_set->save_power(s->dev, false); + genesys_scanner_calibration(s->dev, sensor); + }); + catch_all_exceptions(__func__, [&]() + { + s->dev->cmd_set->save_power(s->dev, true); + }); + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + } + case OPT_CLEAR_CALIBRATION: + s->dev->calibration_cache.clear(); + + /* remove file */ + unlink(s->dev->calib_file.c_str()); + /* signals that sensors will have to be read again */ + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + case OPT_FORCE_CALIBRATION: + s->dev->force_calibration = 1; + s->dev->calibration_cache.clear(); + s->dev->calib_file.clear(); + + /* signals that sensors will have to be read again */ + *myinfo |= SANE_INFO_RELOAD_PARAMS | SANE_INFO_RELOAD_OPTIONS; + break; + + case OPT_IGNORE_OFFSETS: { + s->dev->ignore_offsets = true; + break; + } + default: + DBG(DBG_warn, "%s: can't set unknown option %d\n", __func__, option); + } +} + + +/* sets and gets scanner option values */ +void sane_control_option_impl(SANE_Handle handle, SANE_Int option, + SANE_Action action, void *val, SANE_Int * info) +{ + Genesys_Scanner* s = reinterpret_cast(handle); + auto action_str = (action == SANE_ACTION_GET_VALUE) ? "get" : + (action == SANE_ACTION_SET_VALUE) ? "set" : + (action == SANE_ACTION_SET_AUTO) ? "set_auto" : "unknown"; + DBG_HELPER_ARGS(dbg, "action = %s, option = %s (%d)", action_str, + s->opt[option].name, option); + + SANE_Word cap; + SANE_Int myinfo = 0; + + if (info) { + *info = 0; + } + + if (s->scanning) { + throw SaneException(SANE_STATUS_DEVICE_BUSY, + "don't call this function while scanning (option = %s (%d))", + s->opt[option].name, option); + } + if (option >= NUM_OPTIONS || option < 0) { + throw SaneException("option %d >= NUM_OPTIONS || option < 0", option); + } + + cap = s->opt[option].cap; + + if (!SANE_OPTION_IS_ACTIVE (cap)) { + throw SaneException("option %d is inactive", option); + } + + switch (action) { + case SANE_ACTION_GET_VALUE: + get_option_value(s, option, val); + break; + + case SANE_ACTION_SET_VALUE: + if (!SANE_OPTION_IS_SETTABLE (cap)) { + throw SaneException("option %d is not settable", option); + } + + TIE(sanei_constrain_value(s->opt + option, val, &myinfo)); + + set_option_value(s, option, val, &myinfo); + break; + + case SANE_ACTION_SET_AUTO: + throw SaneException("SANE_ACTION_SET_AUTO unsupported since no option " + "has SANE_CAP_AUTOMATIC"); + default: + throw SaneException("unknown action %d for option %d", action, option); + } + + if (info) + *info = myinfo; +} + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_control_option(SANE_Handle handle, SANE_Int option, + SANE_Action action, void *val, SANE_Int * info) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_control_option_impl(handle, option, action, val, info); + }); +} + +void sane_get_parameters_impl(SANE_Handle handle, SANE_Parameters* params) +{ + DBG_HELPER(dbg); + Genesys_Scanner* s = reinterpret_cast(handle); + + /* don't recompute parameters once data reading is active, ie during scan */ + if (!s->dev->read_active) { + calc_parameters(s); + } + if (params) + { + *params = s->params; + + /* in the case of a sheetfed scanner, when full height is specified + * we override the computed line number with -1 to signal that we + * don't know the real document height. + * We don't do that doing buffering image for digital processing + */ + if (s->dev->model->is_sheetfed && !s->dev->buffer_image && + s->pos_bottom_right_y == s->opt[OPT_BR_Y].constraint.range->max) + { + params->lines = -1; + } + } + debug_dump(DBG_proc, *params); +} + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_get_parameters(SANE_Handle handle, SANE_Parameters* params) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_get_parameters_impl(handle, params); + }); +} + +void sane_start_impl(SANE_Handle handle) +{ + DBG_HELPER(dbg); + Genesys_Scanner* s = reinterpret_cast(handle); + + if (s->pos_top_left_x >= s->pos_bottom_right_x) { + throw SaneException("top left x >= bottom right x"); + } + if (s->pos_top_left_y >= s->pos_bottom_right_y) { + throw SaneException("top left y >= bottom right y"); + } + + /* First make sure we have a current parameter set. Some of the + parameters will be overwritten below, but that's OK. */ + + calc_parameters(s); + genesys_start_scan(s->dev, s->lamp_off); + + s->scanning = true; + + /* allocate intermediate buffer when doing dynamic lineart */ + if (s->dev->settings.scan_mode == ScanColorMode::LINEART) { + s->dev->binarize_buffer.clear(); + s->dev->binarize_buffer.alloc(s->dev->settings.pixels); + s->dev->local_buffer.clear(); + s->dev->local_buffer.alloc(s->dev->binarize_buffer.size() * 8); + } + + /* if one of the software enhancement option is selected, + * we do the scan internally, process picture then put it an internal + * buffer. Since cropping may change scan parameters, we recompute them + * at the end */ + if (s->dev->buffer_image) + { + genesys_buffer_image(s); + + /* check if we need to skip this page, sheetfed scanners + * can go to next doc while flatbed ones can't */ + if (s->swskip > 0 && IS_ACTIVE(OPT_SWSKIP)) { + auto status = sanei_magic_isBlank(&s->params, + s->dev->img_buffer.data(), + SANE_UNFIX(s->swskip)); + + if (status == SANE_STATUS_NO_DOCS && s->dev->model->is_sheetfed) { + DBG(DBG_info, "%s: blank page, recurse\n", __func__); + sane_start(handle); + return; + } + + if (status != SANE_STATUS_GOOD) { + throw SaneException(status); + } + } + + if (s->swdeskew) { + const auto& sensor = sanei_genesys_find_sensor(s->dev, s->dev->settings.xres, + s->dev->settings.get_channels(), + s->dev->settings.scan_method); + catch_all_exceptions(__func__, [&](){ genesys_deskew(s, sensor); }); + } + + if (s->swdespeck) { + catch_all_exceptions(__func__, [&](){ genesys_despeck(s); }); + } + + if(s->swcrop) { + catch_all_exceptions(__func__, [&](){ genesys_crop(s); }); + } + + if(s->swderotate) { + catch_all_exceptions(__func__, [&](){ genesys_derotate(s); }); + } + } +} + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_start(SANE_Handle handle) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_start_impl(handle); + }); +} + +void sane_read_impl(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len) +{ + DBG_HELPER(dbg); + Genesys_Scanner* s = reinterpret_cast(handle); + Genesys_Device *dev; + size_t local_len; + + if (!s) { + throw SaneException("handle is nullptr"); + } + + dev=s->dev; + if (!dev) { + throw SaneException("dev is nullptr"); + } + + if (!buf) { + throw SaneException("buf is nullptr"); + } + + if (!len) { + throw SaneException("len is nullptr"); + } + + *len = 0; + + if (!s->scanning) { + throw SaneException(SANE_STATUS_CANCELLED, + "scan was cancelled, is over or has not been initiated yet"); + } + + DBG(DBG_proc, "%s: start, %d maximum bytes required\n", __func__, max_len); + DBG(DBG_io2, "%s: bytes_to_read=%zu, total_bytes_read=%zu\n", __func__, + dev->total_bytes_to_read, dev->total_bytes_read); + + if(dev->total_bytes_read>=dev->total_bytes_to_read) + { + DBG(DBG_proc, "%s: nothing more to scan: EOF\n", __func__); + + /* issue park command immediatly in case scanner can handle it + * so we save time */ + if (!dev->model->is_sheetfed && !(dev->model->flags & GENESYS_FLAG_MUST_WAIT) && + !dev->parking) + { + dev->cmd_set->move_back_home(dev, false); + dev->parking = true; + } + throw SaneException(SANE_STATUS_EOF); + } + + local_len = max_len; + + /* in case of image processing, all data has been stored in + * buffer_image. So read data from it if it exists, else from scanner */ + if(!dev->buffer_image) + { + /* dynamic lineart is another kind of digital processing that needs + * another layer of buffering on top of genesys_read_ordered_data */ + if (dev->settings.scan_mode == ScanColorMode::LINEART) { + /* if buffer is empty, fill it with genesys_read_ordered_data */ + if(dev->binarize_buffer.avail() == 0) + { + /* store gray data */ + local_len=dev->local_buffer.size(); + dev->local_buffer.reset(); + genesys_read_ordered_data(dev, dev->local_buffer.get_write_pos(local_len), + &local_len); + dev->local_buffer.produce(local_len); + + dev->binarize_buffer.reset(); + if (!is_testing_mode()) { + genesys_gray_lineart(dev, dev->local_buffer.get_read_pos(), + dev->binarize_buffer.get_write_pos(local_len / 8), + dev->settings.pixels, + local_len / dev->settings.pixels, + dev->settings.threshold); + } + dev->binarize_buffer.produce(local_len / 8); + } + + /* return data from lineart buffer if any, up to the available amount */ + local_len = max_len; + if (static_cast(max_len) > dev->binarize_buffer.avail()) + { + local_len=dev->binarize_buffer.avail(); + } + if(local_len) + { + memcpy(buf, dev->binarize_buffer.get_read_pos(), local_len); + dev->binarize_buffer.consume(local_len); + } + } + else + { + // most usual case, direct read of data from scanner */ + genesys_read_ordered_data(dev, buf, &local_len); + } + } + else /* read data from buffer */ + { + if(dev->total_bytes_read+local_len>dev->total_bytes_to_read) + { + local_len=dev->total_bytes_to_read-dev->total_bytes_read; + } + memcpy(buf, dev->img_buffer.data() + dev->total_bytes_read, local_len); + dev->total_bytes_read+=local_len; + } + + *len = local_len; + if (local_len > static_cast(max_len)) { + fprintf (stderr, "[genesys] sane_read: returning incorrect length!!\n"); + } + DBG(DBG_proc, "%s: %d bytes returned\n", __func__, *len); +} + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_read(SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, SANE_Int* len) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_read_impl(handle, buf, max_len, len); + }); +} + +void sane_cancel_impl(SANE_Handle handle) +{ + DBG_HELPER(dbg); + Genesys_Scanner* s = reinterpret_cast(handle); + + s->scanning = false; + s->dev->read_active = false; + s->dev->img_buffer.clear(); + + /* no need to end scan if we are parking the head */ + if (!s->dev->parking) { + s->dev->cmd_set->end_scan(s->dev, &s->dev->reg, true); + } + + /* park head if flatbed scanner */ + if (!s->dev->model->is_sheetfed) { + if (!s->dev->parking) { + s->dev->cmd_set->move_back_home (s->dev, s->dev->model->flags & + GENESYS_FLAG_MUST_WAIT); + + s->dev->parking = !(s->dev->model->flags & GENESYS_FLAG_MUST_WAIT); + } + } + else + { /* in case of sheetfed scanners, we have to eject the document if still present */ + s->dev->cmd_set->eject_document(s->dev); + } + + /* enable power saving mode unless we are parking .... */ + if (!s->dev->parking) { + s->dev->cmd_set->save_power(s->dev, true); + } + + return; +} + +SANE_GENESYS_API_LINKAGE +void sane_cancel(SANE_Handle handle) +{ + catch_all_exceptions(__func__, [=]() { sane_cancel_impl(handle); }); +} + +void sane_set_io_mode_impl(SANE_Handle handle, SANE_Bool non_blocking) +{ + DBG_HELPER_ARGS(dbg, "handle = %p, non_blocking = %s", handle, + non_blocking == SANE_TRUE ? "true" : "false"); + Genesys_Scanner* s = reinterpret_cast(handle); + + if (!s->scanning) { + throw SaneException("not scanning"); + } + if (non_blocking) { + throw SaneException(SANE_STATUS_UNSUPPORTED); + } +} + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_set_io_mode(SANE_Handle handle, SANE_Bool non_blocking) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_set_io_mode_impl(handle, non_blocking); + }); +} + +void sane_get_select_fd_impl(SANE_Handle handle, SANE_Int* fd) +{ + DBG_HELPER_ARGS(dbg, "handle = %p, fd = %p", handle, reinterpret_cast(fd)); + Genesys_Scanner* s = reinterpret_cast(handle); + + if (!s->scanning) { + throw SaneException("not scanning"); + } + throw SaneException(SANE_STATUS_UNSUPPORTED); +} + +SANE_GENESYS_API_LINKAGE +SANE_Status sane_get_select_fd(SANE_Handle handle, SANE_Int* fd) +{ + return wrap_exceptions_to_status_code(__func__, [=]() + { + sane_get_select_fd_impl(handle, fd); + }); +} + +GenesysButtonName genesys_option_to_button(int option) +{ + switch (option) { + case OPT_SCAN_SW: return BUTTON_SCAN_SW; + case OPT_FILE_SW: return BUTTON_FILE_SW; + case OPT_EMAIL_SW: return BUTTON_EMAIL_SW; + case OPT_COPY_SW: return BUTTON_COPY_SW; + case OPT_PAGE_LOADED_SW: return BUTTON_PAGE_LOADED_SW; + case OPT_OCR_SW: return BUTTON_OCR_SW; + case OPT_POWER_SW: return BUTTON_POWER_SW; + case OPT_EXTRA_SW: return BUTTON_EXTRA_SW; + default: throw std::runtime_error("Unknown option to convert to button index"); + } +} + +} // namespace genesys diff --git a/backend/genesys/genesys.h b/backend/genesys/genesys.h new file mode 100644 index 0000000..255bf76 --- /dev/null +++ b/backend/genesys/genesys.h @@ -0,0 +1,258 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003, 2004 Henning Meier-Geinitz + Copyright (C) 2005-2013 Stephane Voltz + Copyright (C) 2006 Laurent Charpentier + Copyright (C) 2009 Pierre Willenbrock + + 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. +*/ + +#ifndef GENESYS_H +#define GENESYS_H + +#ifndef BACKEND_NAME +# define BACKEND_NAME genesys +#endif + +#include "low.h" +#include + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + +#if defined(_WIN32) || defined(HAVE_OS2_H) +# define PATH_SEP '\\' +#else +# define PATH_SEP '/' +#endif + + +#define ENABLE(OPTION) s->opt[OPTION].cap &= ~SANE_CAP_INACTIVE +#define DISABLE(OPTION) s->opt[OPTION].cap |= SANE_CAP_INACTIVE +#define IS_ACTIVE(OPTION) (((s->opt[OPTION].cap) & SANE_CAP_INACTIVE) == 0) + +#define GENESYS_CONFIG_FILE "genesys.conf" + +#ifndef SANE_I18N +#define SANE_I18N(text) text +#endif + +#define STR_FLATBED SANE_I18N("Flatbed") +#define STR_TRANSPARENCY_ADAPTER SANE_I18N("Transparency Adapter") +#define STR_TRANSPARENCY_ADAPTER_INFRARED SANE_I18N("Transparency Adapter Infrared") + +namespace genesys { + +/** List of SANE options + */ +enum Genesys_Option +{ + OPT_NUM_OPTS = 0, + + OPT_MODE_GROUP, + OPT_MODE, + OPT_SOURCE, + OPT_PREVIEW, + OPT_BIT_DEPTH, + OPT_RESOLUTION, + + OPT_GEOMETRY_GROUP, + OPT_TL_X, /* top-left x */ + OPT_TL_Y, /* top-left y */ + OPT_BR_X, /* bottom-right x */ + OPT_BR_Y, /* bottom-right y */ + + /* advanced image enhancement options */ + OPT_ENHANCEMENT_GROUP, + OPT_CUSTOM_GAMMA, /* toggle to enable custom gamma tables */ + OPT_GAMMA_VECTOR, + OPT_GAMMA_VECTOR_R, + OPT_GAMMA_VECTOR_G, + OPT_GAMMA_VECTOR_B, + OPT_SWDESKEW, + OPT_SWCROP, + OPT_SWDESPECK, + OPT_DESPECK, + OPT_SWSKIP, + OPT_SWDEROTATE, + OPT_BRIGHTNESS, + OPT_CONTRAST, + + OPT_EXTRAS_GROUP, + OPT_LAMP_OFF_TIME, + OPT_LAMP_OFF, + OPT_THRESHOLD, + OPT_THRESHOLD_CURVE, + OPT_DISABLE_INTERPOLATION, + OPT_COLOR_FILTER, + OPT_CALIBRATION_FILE, + OPT_EXPIRATION_TIME, + + OPT_SENSOR_GROUP, + OPT_SCAN_SW, + OPT_FILE_SW, + OPT_EMAIL_SW, + OPT_COPY_SW, + OPT_PAGE_LOADED_SW, + OPT_OCR_SW, + OPT_POWER_SW, + OPT_EXTRA_SW, + OPT_NEED_CALIBRATION_SW, + OPT_BUTTON_GROUP, + OPT_CALIBRATE, + OPT_CLEAR_CALIBRATION, + OPT_FORCE_CALIBRATION, + OPT_IGNORE_OFFSETS, + + /* must come last: */ + NUM_OPTIONS +}; + +enum GenesysButtonName : unsigned { + BUTTON_SCAN_SW = 0, + BUTTON_FILE_SW, + BUTTON_EMAIL_SW, + BUTTON_COPY_SW, + BUTTON_PAGE_LOADED_SW, + BUTTON_OCR_SW, + BUTTON_POWER_SW, + BUTTON_EXTRA_SW, + NUM_BUTTONS +}; + +GenesysButtonName genesys_option_to_button(int option); + +class GenesysButton { +public: + void write(bool value) + { + if (value == value_) { + return; + } + values_to_read_.push(value); + value_ = value; + } + + bool read() + { + if (values_to_read_.empty()) { + return value_; + } + bool ret = values_to_read_.front(); + values_to_read_.pop(); + return ret; + } + +private: + bool value_ = false; + std::queue values_to_read_; +}; + +/** Scanner object. Should have better be called Session than Scanner + */ +struct Genesys_Scanner +{ + Genesys_Scanner() = default; + ~Genesys_Scanner() = default; + + // Next scanner in list + struct Genesys_Scanner *next; + + // Low-level device object + Genesys_Device* dev = nullptr; + + // SANE data + // We are currently scanning + bool scanning; + // Option descriptors + SANE_Option_Descriptor opt[NUM_OPTIONS]; + + std::vector opt_resolution_values; + SANE_Range opt_x_range = {}; + SANE_Range opt_y_range = {}; + std::vector opt_source_values; + + // Option values + SANE_Word bit_depth = 0; + SANE_Word resolution = 0; + bool preview = false; + SANE_Word threshold = 0; + SANE_Word threshold_curve = 0; + bool disable_interpolation = false; + bool lamp_off = false; + SANE_Word lamp_off_time = 0; + bool swdeskew = false; + bool swcrop = false; + bool swdespeck = false; + bool swderotate = false; + SANE_Word swskip = 0; + SANE_Word despeck = 0; + SANE_Word contrast = 0; + SANE_Word brightness = 0; + SANE_Word expiration_time = 0; + bool custom_gamma = false; + + SANE_Word pos_top_left_y = 0; + SANE_Word pos_top_left_x = 0; + SANE_Word pos_bottom_right_y = 0; + SANE_Word pos_bottom_right_x = 0; + + std::string mode, color_filter; + + // the value of the source option + ScanMethod scan_method = ScanMethod::FLATBED; + + std::string calibration_file; + // Button states + GenesysButton buttons[NUM_BUTTONS]; + + // SANE Parameters + SANE_Parameters params = {}; + SANE_Int bpp_list[5] = {}; +}; + +void write_calibration(std::ostream& str, Genesys_Device::Calibration& cache); +bool read_calibration(std::istream& str, Genesys_Device::Calibration& cache, + const std::string& path); + +} // namespace genesys + +#endif /* not GENESYS_H */ diff --git a/backend/genesys/gl124.cpp b/backend/genesys/gl124.cpp new file mode 100644 index 0000000..054f1ef --- /dev/null +++ b/backend/genesys/gl124.cpp @@ -0,0 +1,2269 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2016 Stéphane Voltz + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "gl124.h" +#include "gl124_registers.h" +#include "test_settings.h" + +#include + +namespace genesys { +namespace gl124 { + +/** @brief set all registers to default values . + * This function is called only once at the beginning and + * fills register startup values for registers reused across scans. + * Those that are rarely modified or not modified are written + * individually. + * @param dev device structure holding register set to initialize + */ +static void +gl124_init_registers (Genesys_Device * dev) +{ + DBG_HELPER(dbg); + + dev->reg.clear(); + + // default to LiDE 110 + dev->reg.init_reg(0x01, 0xa2); // + REG_0x01_SHDAREA + dev->reg.init_reg(0x02, 0x90); + dev->reg.init_reg(0x03, 0x50); + dev->reg.init_reg(0x04, 0x03); + dev->reg.init_reg(0x05, 0x00); + + if(dev->model->sensor_id == SensorId::CIS_CANON_LIDE_120) { + dev->reg.init_reg(0x06, 0x50); + dev->reg.init_reg(0x07, 0x00); + } else { + dev->reg.init_reg(0x03, 0x50 & ~REG_0x03_AVEENB); + dev->reg.init_reg(0x06, 0x50 | REG_0x06_GAIN4); + } + dev->reg.init_reg(0x09, 0x00); + dev->reg.init_reg(0x0a, 0xc0); + dev->reg.init_reg(0x0b, 0x2a); + dev->reg.init_reg(0x0c, 0x12); + dev->reg.init_reg(0x11, 0x00); + dev->reg.init_reg(0x12, 0x00); + dev->reg.init_reg(0x13, 0x0f); + dev->reg.init_reg(0x14, 0x00); + dev->reg.init_reg(0x15, 0x80); + dev->reg.init_reg(0x16, 0x10); // SENSOR_DEF + dev->reg.init_reg(0x17, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x19, 0x01); // SENSOR_DEF + dev->reg.init_reg(0x1a, 0x30); // SENSOR_DEF + dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x1c, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x1d, 0x01); // SENSOR_DEF + dev->reg.init_reg(0x1e, 0x10); + dev->reg.init_reg(0x1f, 0x00); + dev->reg.init_reg(0x20, 0x15); // SENSOR_DEF + dev->reg.init_reg(0x21, 0x00); + if(dev->model->sensor_id != SensorId::CIS_CANON_LIDE_120) { + dev->reg.init_reg(0x22, 0x02); + } else { + dev->reg.init_reg(0x22, 0x14); + } + dev->reg.init_reg(0x23, 0x00); + dev->reg.init_reg(0x24, 0x00); + dev->reg.init_reg(0x25, 0x00); + dev->reg.init_reg(0x26, 0x0d); + dev->reg.init_reg(0x27, 0x48); + dev->reg.init_reg(0x28, 0x00); + dev->reg.init_reg(0x29, 0x56); + dev->reg.init_reg(0x2a, 0x5e); + dev->reg.init_reg(0x2b, 0x02); + dev->reg.init_reg(0x2c, 0x02); + dev->reg.init_reg(0x2d, 0x58); + dev->reg.init_reg(0x3b, 0x00); + dev->reg.init_reg(0x3c, 0x00); + dev->reg.init_reg(0x3d, 0x00); + dev->reg.init_reg(0x3e, 0x00); + dev->reg.init_reg(0x3f, 0x02); + dev->reg.init_reg(0x40, 0x00); + dev->reg.init_reg(0x41, 0x00); + dev->reg.init_reg(0x42, 0x00); + dev->reg.init_reg(0x43, 0x00); + dev->reg.init_reg(0x44, 0x00); + dev->reg.init_reg(0x45, 0x00); + dev->reg.init_reg(0x46, 0x00); + dev->reg.init_reg(0x47, 0x00); + dev->reg.init_reg(0x48, 0x00); + dev->reg.init_reg(0x49, 0x00); + dev->reg.init_reg(0x4f, 0x00); + dev->reg.init_reg(0x52, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x53, 0x02); // SENSOR_DEF + dev->reg.init_reg(0x54, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x55, 0x06); // SENSOR_DEF + dev->reg.init_reg(0x56, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x57, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x58, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x59, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x5a, 0x1a); // SENSOR_DEF + dev->reg.init_reg(0x5b, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x5c, 0xc0); // SENSOR_DEF + dev->reg.init_reg(0x5f, 0x00); + dev->reg.init_reg(0x60, 0x02); + dev->reg.init_reg(0x61, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x62, 0x00); + dev->reg.init_reg(0x63, 0x00); + dev->reg.init_reg(0x64, 0x00); + dev->reg.init_reg(0x65, 0x00); + dev->reg.init_reg(0x66, 0x00); + dev->reg.init_reg(0x67, 0x00); + dev->reg.init_reg(0x68, 0x00); + dev->reg.init_reg(0x69, 0x00); + dev->reg.init_reg(0x6a, 0x00); + dev->reg.init_reg(0x6b, 0x00); + dev->reg.init_reg(0x6c, 0x00); + dev->reg.init_reg(0x6e, 0x00); + dev->reg.init_reg(0x6f, 0x00); + + if (dev->model->sensor_id != SensorId::CIS_CANON_LIDE_120) { + dev->reg.init_reg(0x6d, 0xd0); + dev->reg.init_reg(0x71, 0x08); + } else { + dev->reg.init_reg(0x6d, 0x00); + dev->reg.init_reg(0x71, 0x1f); + } + dev->reg.init_reg(0x70, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x71, 0x08); // SENSOR_DEF + dev->reg.init_reg(0x72, 0x08); // SENSOR_DEF + dev->reg.init_reg(0x73, 0x0a); // SENSOR_DEF + + // CKxMAP + dev->reg.init_reg(0x74, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x75, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x76, 0x3c); // SENSOR_DEF + dev->reg.init_reg(0x77, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x78, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x79, 0x9f); // SENSOR_DEF + dev->reg.init_reg(0x7a, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x7b, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x7c, 0x55); // SENSOR_DEF + + dev->reg.init_reg(0x7d, 0x00); + dev->reg.init_reg(0x7e, 0x08); + dev->reg.init_reg(0x7f, 0x58); + + if (dev->model->sensor_id != SensorId::CIS_CANON_LIDE_120) { + dev->reg.init_reg(0x80, 0x00); + dev->reg.init_reg(0x81, 0x14); + } else { + dev->reg.init_reg(0x80, 0x00); + dev->reg.init_reg(0x81, 0x10); + } + + // STRPIXEL + dev->reg.init_reg(0x82, 0x00); + dev->reg.init_reg(0x83, 0x00); + dev->reg.init_reg(0x84, 0x00); + + // ENDPIXEL + dev->reg.init_reg(0x85, 0x00); + dev->reg.init_reg(0x86, 0x00); + dev->reg.init_reg(0x87, 0x00); + + dev->reg.init_reg(0x88, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x89, 0x65); // SENSOR_DEF + dev->reg.init_reg(0x8a, 0x00); + dev->reg.init_reg(0x8b, 0x00); + dev->reg.init_reg(0x8c, 0x00); + dev->reg.init_reg(0x8d, 0x00); + dev->reg.init_reg(0x8e, 0x00); + dev->reg.init_reg(0x8f, 0x00); + dev->reg.init_reg(0x90, 0x00); + dev->reg.init_reg(0x91, 0x00); + dev->reg.init_reg(0x92, 0x00); + dev->reg.init_reg(0x93, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x94, 0x14); // SENSOR_DEF + dev->reg.init_reg(0x95, 0x30); // SENSOR_DEF + dev->reg.init_reg(0x96, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x97, 0x90); // SENSOR_DEF + dev->reg.init_reg(0x98, 0x01); // SENSOR_DEF + dev->reg.init_reg(0x99, 0x1f); + dev->reg.init_reg(0x9a, 0x00); + dev->reg.init_reg(0x9b, 0x80); + dev->reg.init_reg(0x9c, 0x80); + dev->reg.init_reg(0x9d, 0x3f); + dev->reg.init_reg(0x9e, 0x00); + dev->reg.init_reg(0x9f, 0x00); + dev->reg.init_reg(0xa0, 0x20); + dev->reg.init_reg(0xa1, 0x30); + dev->reg.init_reg(0xa2, 0x00); + dev->reg.init_reg(0xa3, 0x20); + dev->reg.init_reg(0xa4, 0x01); + dev->reg.init_reg(0xa5, 0x00); + dev->reg.init_reg(0xa6, 0x00); + dev->reg.init_reg(0xa7, 0x08); + dev->reg.init_reg(0xa8, 0x00); + dev->reg.init_reg(0xa9, 0x08); + dev->reg.init_reg(0xaa, 0x01); + dev->reg.init_reg(0xab, 0x00); + dev->reg.init_reg(0xac, 0x00); + dev->reg.init_reg(0xad, 0x40); + dev->reg.init_reg(0xae, 0x01); + dev->reg.init_reg(0xaf, 0x00); + dev->reg.init_reg(0xb0, 0x00); + dev->reg.init_reg(0xb1, 0x40); + dev->reg.init_reg(0xb2, 0x00); + dev->reg.init_reg(0xb3, 0x09); + dev->reg.init_reg(0xb4, 0x5b); + dev->reg.init_reg(0xb5, 0x00); + dev->reg.init_reg(0xb6, 0x10); + dev->reg.init_reg(0xb7, 0x3f); + dev->reg.init_reg(0xb8, 0x00); + dev->reg.init_reg(0xbb, 0x00); + dev->reg.init_reg(0xbc, 0xff); + dev->reg.init_reg(0xbd, 0x00); + dev->reg.init_reg(0xbe, 0x07); + dev->reg.init_reg(0xc3, 0x00); + dev->reg.init_reg(0xc4, 0x00); + + /* gamma + dev->reg.init_reg(0xc5, 0x00); + dev->reg.init_reg(0xc6, 0x00); + dev->reg.init_reg(0xc7, 0x00); + dev->reg.init_reg(0xc8, 0x00); + dev->reg.init_reg(0xc9, 0x00); + dev->reg.init_reg(0xca, 0x00); + dev->reg.init_reg(0xcb, 0x00); + dev->reg.init_reg(0xcc, 0x00); + dev->reg.init_reg(0xcd, 0x00); + dev->reg.init_reg(0xce, 0x00); + */ + + if (dev->model->sensor_id == SensorId::CIS_CANON_LIDE_120) { + dev->reg.init_reg(0xc5, 0x20); + dev->reg.init_reg(0xc6, 0xeb); + dev->reg.init_reg(0xc7, 0x20); + dev->reg.init_reg(0xc8, 0xeb); + dev->reg.init_reg(0xc9, 0x20); + dev->reg.init_reg(0xca, 0xeb); + } + + // memory layout + /* + dev->reg.init_reg(0xd0, 0x0a); + dev->reg.init_reg(0xd1, 0x1f); + dev->reg.init_reg(0xd2, 0x34); + */ + dev->reg.init_reg(0xd3, 0x00); + dev->reg.init_reg(0xd4, 0x00); + dev->reg.init_reg(0xd5, 0x00); + dev->reg.init_reg(0xd6, 0x00); + dev->reg.init_reg(0xd7, 0x00); + dev->reg.init_reg(0xd8, 0x00); + dev->reg.init_reg(0xd9, 0x00); + + // memory layout + /* + dev->reg.init_reg(0xe0, 0x00); + dev->reg.init_reg(0xe1, 0x48); + dev->reg.init_reg(0xe2, 0x15); + dev->reg.init_reg(0xe3, 0x90); + dev->reg.init_reg(0xe4, 0x15); + dev->reg.init_reg(0xe5, 0x91); + dev->reg.init_reg(0xe6, 0x2a); + dev->reg.init_reg(0xe7, 0xd9); + dev->reg.init_reg(0xe8, 0x2a); + dev->reg.init_reg(0xe9, 0xad); + dev->reg.init_reg(0xea, 0x40); + dev->reg.init_reg(0xeb, 0x22); + dev->reg.init_reg(0xec, 0x40); + dev->reg.init_reg(0xed, 0x23); + dev->reg.init_reg(0xee, 0x55); + dev->reg.init_reg(0xef, 0x6b); + dev->reg.init_reg(0xf0, 0x55); + dev->reg.init_reg(0xf1, 0x6c); + dev->reg.init_reg(0xf2, 0x6a); + dev->reg.init_reg(0xf3, 0xb4); + dev->reg.init_reg(0xf4, 0x6a); + dev->reg.init_reg(0xf5, 0xb5); + dev->reg.init_reg(0xf6, 0x7f); + dev->reg.init_reg(0xf7, 0xfd); + */ + + dev->reg.init_reg(0xf8, 0x01); // other value is 0x05 + dev->reg.init_reg(0xf9, 0x00); + dev->reg.init_reg(0xfa, 0x00); + dev->reg.init_reg(0xfb, 0x00); + dev->reg.init_reg(0xfc, 0x00); + dev->reg.init_reg(0xff, 0x00); + + // fine tune upon device description + const auto& sensor = sanei_genesys_find_sensor_any(dev); + sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res); + + dev->calib_reg = dev->reg; +} + +/**@brief send slope table for motor movement + * Send slope_table in machine byte order + * @param dev device to send slope table + * @param table_nr index of the slope table in ASIC memory + * Must be in the [0-4] range. + * @param slope_table pointer to 16 bit values array of the slope table + * @param steps number of elemnts in the slope table + */ +static void gl124_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, + int steps) +{ + DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); + int i; + char msg[10000]; + + /* sanity check */ + if(table_nr<0 || table_nr>4) + { + throw SaneException("invalid table number"); + } + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + std::sprintf(msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) { + std::sprintf(msg + std::strlen(msg), ",%d", slope_table[i]); + } + DBG (DBG_io, "%s: %s\n", __func__, msg); + } + + if (dev->interface->is_mock()) { + dev->interface->record_slope_table(table_nr, slope_table); + } + // slope table addresses are fixed + dev->interface->write_ahb(0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); +} + +/** @brief * Set register values of 'special' ti type frontend + * Registers value are taken from the frontend register data + * set. + * @param dev device owning the AFE + * @param set flag AFE_INIT to specify the AFE must be reset before writing data + * */ +static void gl124_set_ti_fe(Genesys_Device* dev, uint8_t set) +{ + DBG_HELPER(dbg); + int i; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s: setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + + dev->frontend = dev->frontend_initial; + } + + // start writing to DAC + dev->interface->write_fe_register(0x00, 0x80); + + /* write values to analog frontend */ + for (uint16_t addr = 0x01; addr < 0x04; addr++) + { + dev->interface->write_fe_register(addr, dev->frontend.regs.get_value(addr)); + } + + dev->interface->write_fe_register(0x04, 0x00); + + /* these are not really sign for this AFE */ + for (i = 0; i < 3; i++) + { + dev->interface->write_fe_register(0x05 + i, dev->frontend.regs.get_value(0x24 + i)); + } + + if (dev->model->adc_id == AdcId::CANON_LIDE_120) { + dev->interface->write_fe_register(0x00, 0x01); + } + else + { + dev->interface->write_fe_register(0x00, 0x11); + } +} + + +// Set values of analog frontend +void CommandSetGl124::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const +{ + DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" : + set == AFE_SET ? "set" : + set == AFE_POWER_SAVE ? "powersave" : "huh?"); + (void) sensor; + uint8_t val; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + dev->frontend = dev->frontend_initial; + } + + val = dev->interface->read_register(REG_0x0A); + + /* route to correct analog FE */ + switch ((val & REG_0x0A_SIFSEL) >> REG_0x0AS_SIFSEL) { + case 3: + gl124_set_ti_fe(dev, set); + break; + case 0: + case 1: + case 2: + default: + throw SaneException("unsupported analog FE 0x%02x", val); + } +} + +static void gl124_init_motor_regs_scan(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const Motor_Profile& motor_profile, + unsigned int scan_exposure_time, + unsigned scan_yres, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + ScanColorMode scan_mode, + MotorFlag flags) +{ + DBG_HELPER(dbg); + int use_fast_fed; + unsigned int lincnt, fast_dpi; + unsigned int feedl,dist; + uint32_t z1, z2; + unsigned yres; + unsigned min_speed; + unsigned int linesel; + + DBG(DBG_info, "%s : scan_exposure_time=%d, scan_yres=%d, step_type=%d, scan_lines=%d, " + "scan_dummy=%d, feed_steps=%d, scan_mode=%d, flags=%x\n", __func__, scan_exposure_time, + scan_yres, static_cast(motor_profile.step_type), scan_lines, scan_dummy, + feed_steps, static_cast(scan_mode), + static_cast(flags)); + + /* we never use fast fed since we do manual feed for the scans */ + use_fast_fed=0; + + /* enforce motor minimal scan speed + * @TODO extend motor struct for this value */ + if (scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + min_speed = 900; + } + else + { + switch(dev->model->motor_id) + { + case MotorId::CANON_LIDE_110: + min_speed = 600; + break; + case MotorId::CANON_LIDE_120: + min_speed = 900; + break; + default: + min_speed = 900; + break; + } + } + + /* compute min_speed and linesel */ + if(scan_yres 0 */ + if(linesel==0) + { + linesel=1; + yres=scan_yres*2; + } + } + else + { + yres=scan_yres; + linesel=0; + } + + DBG(DBG_io2, "%s: final yres=%d, linesel=%d\n", __func__, yres, linesel); + + lincnt=scan_lines*(linesel+1); + reg->set24(REG_LINCNT, lincnt); + DBG (DBG_io, "%s: lincnt=%d\n", __func__, lincnt); + + /* compute register 02 value */ + uint8_t r02 = REG_0x02_NOTHOME; + + if (use_fast_fed) { + r02 |= REG_0x02_FASTFED; + } else { + r02 &= ~REG_0x02_FASTFED; + } + + if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { + r02 |= REG_0x02_AGOHOME; + } + + if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE) || (yres >= sensor.optical_res)) + { + r02 |= REG_0x02_ACDCDIS; + } + if (has_flag(flags, MotorFlag::REVERSE)) { + r02 |= REG_0x02_MTRREV; + } + + reg->set8(REG_0x02, r02); + sanei_genesys_set_motor_power(*reg, true); + + reg->set16(REG_SCANFED, 4); + + /* scan and backtracking slope table */ + auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, yres, scan_exposure_time, + dev->motor.base_ydpi, 1, + motor_profile); + gl124_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count); + gl124_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count); + + reg->set16(REG_STEPNO, scan_table.steps_count); + + /* fast table */ + fast_dpi=yres; + + /* + if (scan_mode != ScanColorMode::COLOR_SINGLE_PASS) + { + fast_dpi*=3; + } + */ + auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi, + scan_exposure_time, dev->motor.base_ydpi, + 1, motor_profile); + gl124_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count); + gl124_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count); + + reg->set16(REG_FASTNO, fast_table.steps_count); + reg->set16(REG_FSHDEC, fast_table.steps_count); + reg->set16(REG_FMOVNO, fast_table.steps_count); + + /* substract acceleration distance from feedl */ + feedl=feed_steps; + feedl <<= static_cast(motor_profile.step_type); + + dist = scan_table.steps_count; + if (has_flag(flags, MotorFlag::FEED)) { + dist *= 2; + } + if (use_fast_fed) { + dist += fast_table.steps_count * 2; + } + DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + /* get sure we don't use insane value */ + if (dist < feedl) { + feedl -= dist; + } else { + feedl = 0; + } + + reg->set24(REG_FEEDL, feedl); + DBG (DBG_io, "%s: feedl=%d\n", __func__, feedl); + + /* doesn't seem to matter that much */ + sanei_genesys_calculate_zmod(use_fast_fed, + scan_exposure_time, + scan_table.table, + scan_table.steps_count, + feedl, + scan_table.steps_count, + &z1, + &z2); + + reg->set24(REG_Z1MOD, z1); + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + + reg->set24(REG_Z2MOD, z2); + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + + /* LINESEL */ + reg->set8_mask(REG_0x1D, linesel, REG_0x1D_LINESEL); + reg->set8(REG_0xA0, (static_cast(motor_profile.step_type) << REG_0xA0S_STEPSEL) | + (static_cast(motor_profile.step_type) << REG_0xA0S_FSTPSEL)); + + reg->set16(REG_FMOVDEC, fast_table.steps_count); +} + + +/** @brief copy sensor specific settings + * Set up register set for the given sensor resolution. Values are from the device table + * in genesys_devices.c for registers: + * [0x16 ... 0x1d] + * [0x52 ... 0x5e] + * Other come from the specific device sensor table in genesys_gl124.h: + * 0x18, 0x20, 0x61, 0x98 and + * @param dev device to set up + * @param regs register set to modify + * @param dpi resolution of the sensor during scan + * @param ccd_size_divisor flag for half ccd mode + * */ +static void gl124_setup_sensor(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs) +{ + DBG_HELPER(dbg); + + for (const auto& reg : sensor.custom_regs) { + regs->set8(reg.address, reg.value); + } + + regs->set24(REG_EXPR, sensor.exposure.red); + regs->set24(REG_EXPG, sensor.exposure.green); + regs->set24(REG_EXPB, sensor.exposure.blue); + + dev->segment_order = sensor.segment_order; +} + +/** @brief setup optical related registers + * start and pixels are expressed in optical sensor resolution coordinate + * space. + * @param dev scanner device to use + * @param reg registers to set up + * @param exposure_time exposure time to use + * @param used_res scanning resolution used, may differ from + * scan's one + * @param start logical start pixel coordinate + * @param pixels logical number of pixels to use + * @param channels number of color channels (currently 1 or 3) + * @param depth bit depth of the scan (1, 8 or 16) + * @param ccd_size_divisor whether sensor's timings are such that x coordinates must be halved + * @param color_filter color channel to use as gray data + * @param flags optical flags (@see ) + */ +static void gl124_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, unsigned int exposure_time, + const ScanSession& session) +{ + DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time); + unsigned int dpihw; + GenesysRegister *r; + uint32_t expmax; + + // resolution is divided according to ccd_pixels_per_system_pixel + unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel(); + DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel); + + // to manage high resolution device while keeping good low resolution scanning speed, we + // make hardware dpi vary + dpihw = sensor.get_register_hwdpi(session.output_resolution * ccd_pixels_per_system_pixel); + DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw); + + gl124_setup_sensor(dev, sensor, reg); + + dev->cmd_set->set_fe(dev, sensor, AFE_SET); + + /* enable shading */ + regs_set_optical_off(dev->model->asic_type, *reg); + r = sanei_genesys_get_address (reg, REG_0x01); + if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + r->value &= ~REG_0x01_DVDSET; + } else { + r->value |= REG_0x01_DVDSET; + } + + r = sanei_genesys_get_address(reg, REG_0x03); + if ((dev->model->sensor_id != SensorId::CIS_CANON_LIDE_120) && (session.params.xres>=600)) { + r->value &= ~REG_0x03_AVEENB; + DBG (DBG_io, "%s: disabling AVEENB\n", __func__); + } + else + { + r->value |= ~REG_0x03_AVEENB; + DBG (DBG_io, "%s: enabling AVEENB\n", __func__); + } + + sanei_genesys_set_lamp_power(dev, sensor, *reg, + !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); + + // BW threshold + dev->interface->write_register(REG_0x114, dev->settings.threshold); + dev->interface->write_register(REG_0x115, dev->settings.threshold); + + /* monochrome / color scan */ + r = sanei_genesys_get_address (reg, REG_0x04); + switch (session.params.depth) { + case 8: + r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); + break; + case 16: + r->value &= ~REG_0x04_LINEART; + r->value |= REG_0x04_BITSET; + break; + } + + r->value &= ~REG_0x04_FILTER; + if (session.params.channels == 1) + { + switch (session.params.color_filter) + { + case ColorFilter::RED: + r->value |= 0x10; + break; + case ColorFilter::BLUE: + r->value |= 0x30; + break; + case ColorFilter::GREEN: + r->value |= 0x20; + break; + default: + break; // should not happen + } + } + + sanei_genesys_set_dpihw(*reg, sensor, dpihw); + + if (should_enable_gamma(session, sensor)) { + reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB; + } else { + reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB; + } + + unsigned dpiset_reg = session.output_resolution * ccd_pixels_per_system_pixel * + session.ccd_size_divisor; + if (sensor.dpiset_override != 0) { + dpiset_reg = sensor.dpiset_override; + } + + reg->set16(REG_DPISET, dpiset_reg); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset_reg); + + r = sanei_genesys_get_address(reg, REG_0x06); + r->value |= REG_0x06_GAIN4; + + /* CIS scanners can do true gray by setting LEDADD */ + /* we set up LEDADD only when asked */ + if (dev->model->is_cis) { + r = sanei_genesys_get_address (reg, REG_0x60); + r->value &= ~REG_0x60_LEDADD; + if (session.enable_ledadd) { + r->value |= REG_0x60_LEDADD; + expmax = reg->get24(REG_EXPR); + expmax = std::max(expmax, reg->get24(REG_EXPG)); + expmax = std::max(expmax, reg->get24(REG_EXPB)); + + dev->reg.set24(REG_EXPR, expmax); + dev->reg.set24(REG_EXPG, expmax); + dev->reg.set24(REG_EXPB, expmax); + } + /* RGB weighting, REG_TRUER,G and B are to be set */ + r = sanei_genesys_get_address (reg, 0x01); + r->value &= ~REG_0x01_TRUEGRAY; + if (session.enable_ledadd) { + r->value |= REG_0x01_TRUEGRAY; + dev->interface->write_register(REG_TRUER, 0x80); + dev->interface->write_register(REG_TRUEG, 0x80); + dev->interface->write_register(REG_TRUEB, 0x80); + } + } + + reg->set24(REG_STRPIXEL, session.pixel_startx); + reg->set24(REG_ENDPIXEL, session.pixel_endx); + + dev->line_count = 0; + + build_image_pipeline(dev, session); + + // MAXWD is expressed in 2 words unit + + // BUG: we shouldn't multiply by channels here + reg->set24(REG_MAXWD, session.output_line_bytes_raw / session.ccd_size_divisor * session.params.channels); + + reg->set24(REG_LPERIOD, exposure_time); + DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); + + reg->set16(REG_DUMMY, sensor.dummy_pixel); +} + +void CommandSetGl124::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const +{ + DBG_HELPER(dbg); + session.assert_computed(); + + int move; + int exposure_time; + + int dummy = 0; + int slope_dpi = 0; + + /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ + if (dev->model->is_cis) { + slope_dpi = session.params.yres * session.params.channels; + } else { + slope_dpi = session.params.yres; + } + + if (has_flag(session.params.flags, ScanFlag::FEEDING)) { + exposure_time = 2304; + } else { + exposure_time = sensor.exposure_lperiod; + } + const auto& motor_profile = sanei_genesys_get_motor_profile(*gl124_motor_profiles, + dev->model->motor_id, + exposure_time); + + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, static_cast(motor_profile.step_type)); + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + + // now _LOGICAL_ optical values used are known, setup registers + gl124_init_optical_regs_scan(dev, sensor, reg, exposure_time, session); + + /* add tl_y to base movement */ + move = session.params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + MotorFlag mflags = MotorFlag::NONE; + if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) { + mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE; + } + if (has_flag(session.params.flags, ScanFlag::FEEDING)) { + mflags |= MotorFlag::FEED; + } + if (has_flag(session.params.flags, ScanFlag::REVERSE)) { + mflags |= MotorFlag::REVERSE; + } + gl124_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi, + dev->model->is_cis ? session.output_line_count * session.params.channels : + session.output_line_count, + dummy, move, session.params.scan_mode, mflags); + + /*** prepares data reordering ***/ + + dev->read_buffer.clear(); + dev->read_buffer.alloc(session.buffer_size_read); + + dev->read_active = true; + + dev->session = session; + + dev->total_bytes_read = 0; + dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines; + + DBG(DBG_info, "%s: total bytes to send to frontend = %zu\n", __func__, + dev->total_bytes_to_read); +} + +ScanSession CommandSetGl124::calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const +{ + int start; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, settings); + + /* start */ + start = static_cast(dev->model->x_offset); + start += static_cast(settings.tl_x); + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = settings.xres; + session.params.yres = settings.yres; + session.params.startx = start; + session.params.starty = 0; // not used + session.params.pixels = settings.pixels; + session.params.requested_pixels = settings.requested_pixels; + session.params.lines = settings.lines; + session.params.depth = settings.depth; + session.params.channels = settings.get_channels(); + session.params.scan_method = settings.scan_method; + session.params.scan_mode = settings.scan_mode; + session.params.color_filter = settings.color_filter; + session.params.flags = ScanFlag::NONE; + + compute_session(dev, session, sensor); + + return session; +} + +/** + * for fast power saving methods only, like disabling certain amplifiers + * @param dev device to use + * @param enable true to set inot powersaving + * */ +void CommandSetGl124::save_power(Genesys_Device* dev, bool enable) const +{ + (void) dev; + DBG_HELPER_ARGS(dbg, "enable = %d", enable); +} + +void CommandSetGl124::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const +{ + DBG_HELPER_ARGS(dbg, "delay = %d", delay); + GenesysRegister *r; + + r = sanei_genesys_get_address(&dev->reg, REG_0x03); + r->value &= ~0xf0; + if(delay<15) + { + r->value |= delay; + } + else + { + r->value |= 0x0f; + } +} + +/** @brief setup GPIOs for scan + * Setup GPIO values to drive motor (or light) needed for the + * target resolution + * @param *dev device to set up + * @param resolution dpi of the target scan + */ +void gl124_setup_scan_gpio(Genesys_Device* dev, int resolution) +{ + DBG_HELPER(dbg); + + uint8_t val = dev->interface->read_register(REG_0x32); + + /* LiDE 110, 210 and 220 cases */ + if(dev->model->gpio_id != GpioId::CANON_LIDE_120) { + if(resolution>=dev->motor.base_ydpi/2) + { + val &= 0xf7; + } + else if(resolution>=dev->motor.base_ydpi/4) + { + val &= 0xef; + } + else + { + val |= 0x10; + } + } + /* 120 : <=300 => 0x53 */ + else + { /* base_ydpi is 4800 */ + if(resolution<=300) + { + val &= 0xf7; + } + else if(resolution<=600) + { + val |= 0x08; + } + else if(resolution<=1200) + { + val &= 0xef; + val |= 0x08; + } + else + { + val &= 0xf7; + } + } + val |= 0x02; + dev->interface->write_register(REG_0x32, val); +} + +// Send the low-level scan command +// todo: is this that useful ? +void CommandSetGl124::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, bool start_motor) const +{ + DBG_HELPER(dbg); + (void) sensor; + (void) reg; + + // set up GPIO for scan + gl124_setup_scan_gpio(dev,dev->settings.yres); + + // clear scan and feed count + dev->interface->write_register(REG_0x0D, REG_0x0D_CLRLNCNT | REG_0x0D_CLRMCNT); + + // enable scan and motor + uint8_t val = dev->interface->read_register(REG_0x01); + val |= REG_0x01_SCAN; + dev->interface->write_register(REG_0x01, val); + + scanner_start_action(*dev, start_motor); + + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); +} + + +// Send the stop scan command +void CommandSetGl124::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg, + bool check_stop) const +{ + (void) reg; + DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop); + + if (!dev->model->is_sheetfed) { + scanner_stop_action(*dev); + } +} + + +/** Park head + * Moves the slider to the home (top) position slowly + * @param dev device to park + * @param wait_until_home true to make the function waiting for head + * to be home before returning, if fals returne immediately + */ +void CommandSetGl124::move_back_home(Genesys_Device* dev, bool wait_until_home) const +{ + scanner_move_back_home(*dev, wait_until_home); +} + +// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi +// from very top of scanner +void CommandSetGl124::search_start_position(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + int size; + Genesys_Register_Set local_reg = dev->reg; + + int pixels = 600; + int dpi = 300; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, ScanMethod::FLATBED); + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; /*we should give a small offset here~60 steps */ + session.params.pixels = 600; + session.params.lines = dev->model->search_lines; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::GREEN; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::IGNORE_LINE_DISTANCE | + ScanFlag::DISABLE_BUFFER_FULL_MOVE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &local_reg, session); + + // send to scanner + dev->interface->write_registers(local_reg); + + size = pixels * dev->model->search_lines; + + std::vector data(size); + + begin_scan(dev, sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_start_position"); + end_scan(dev, &local_reg, true); + dev->reg = local_reg; + return; + } + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl124_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + } + + end_scan(dev, &local_reg, true); + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + + for (auto& sensor_update : + sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) + { + sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels, + dev->model->search_lines); + } +} + +// sets up register for coarse gain calibration +// todo: check it for scanners using it +void CommandSetGl124::init_regs_for_coarse_calibration(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel(); + session.params.lines = 20; + session.params.depth = 16; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::FEEDING | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, ®s, session); + + sanei_genesys_set_motor_power(regs, false); + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres); + + dev->interface->write_registers(regs); +} + + +// init registers for shading calibration shading calibration is done at dpihw +void CommandSetGl124::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int move, resolution, dpihw, factor; + + /* initial calibration reg values */ + regs = dev->reg; + + dev->calib_channels = 3; + dev->calib_lines = dev->model->shading_lines; + dpihw = sensor.get_register_hwdpi(dev->settings.xres); + if(dpihw>=2400) + { + dev->calib_lines *= 2; + } + resolution=dpihw; + + unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); + + resolution /= ccd_size_divisor; + dev->calib_lines /= ccd_size_divisor; // reducing just because we reduced the resolution + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, + dev->calib_channels, + dev->settings.scan_method); + dev->calib_resolution = resolution; + dev->calib_total_bytes_to_read = 0; + factor = calib_sensor.optical_res / resolution; + dev->calib_pixels = calib_sensor.sensor_pixels / factor; + + /* distance to move to reach white target at high resolution */ + move=0; + if (dev->settings.yres >= 1200) { + move = static_cast(dev->model->y_offset_calib_white); + move = static_cast((move * (dev->motor.base_ydpi/4)) / MM_PER_INCH); + } + DBG (DBG_io, "%s: move=%d steps\n", __func__, move); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 0; + session.params.starty = move; + session.params.pixels = dev->calib_pixels; + session.params.lines = dev->calib_lines; + session.params.depth = 16; + session.params.channels = dev->calib_channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = ColorFilter::RED; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::DISABLE_BUFFER_FULL_MOVE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + try { + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + } catch (...) { + catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); }); + throw; + } + sanei_genesys_set_motor_power(regs, false); + + dev->interface->write_registers(regs); +} + +void CommandSetGl124::wait_for_motor_stop(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + + auto status = scanner_read_status(*dev); + uint8_t val40 = dev->interface->read_register(REG_0x100); + + if (!status.is_motor_enabled && (val40 & REG_0x100_MOTMFLG) == 0) { + return; + } + + do { + dev->interface->sleep_ms(10); + status = scanner_read_status(*dev); + val40 = dev->interface->read_register(REG_0x100); + } while (status.is_motor_enabled ||(val40 & REG_0x100_MOTMFLG)); + dev->interface->sleep_ms(50); +} + +/** @brief set up registers for the actual scan + */ +void CommandSetGl124::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + float move; + int move_dpi; + float start; + + debug_dump(DBG_info, dev->settings); + + /* y (motor) distance to move to reach scanned area */ + move_dpi = dev->motor.base_ydpi/4; + move = static_cast(dev->model->y_offset); + move += static_cast(dev->settings.tl_y); + move = static_cast((move * move_dpi) / MM_PER_INCH); + DBG (DBG_info, "%s: move=%f steps\n", __func__, move); + + if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) { + scanner_move(*dev, dev->model->default_method, static_cast(move - 500), + Direction::FORWARD); + move=500; + } + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* start */ + start = static_cast(dev->model->x_offset); + start += static_cast(dev->settings.tl_x); + start /= sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = dev->settings.pixels; + session.params.requested_pixels = dev->settings.requested_pixels; + session.params.lines = dev->settings.lines; + session.params.depth = dev->settings.depth; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::NONE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &dev->reg, session); +} + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +void CommandSetGl124::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + std::uint8_t* data, int size) const +{ + DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size); + uint32_t addr, length, x, factor, segcnt, pixels, i; + uint16_t dpiset,dpihw; + uint8_t *ptr, *src; + + /* logical size of a color as seen by generic code of the frontend */ + length = size / 3; + std::uint32_t strpixel = dev->session.pixel_startx; + std::uint32_t endpixel = dev->session.pixel_endx; + segcnt = dev->reg.get24(REG_SEGCNT); + if(endpixel==0) + { + endpixel=segcnt; + } + + /* compute deletion factor */ + dpiset = dev->reg.get16(REG_DPISET); + dpihw = sensor.get_register_hwdpi(dpiset); + factor=dpihw/dpiset; + DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); + + /* turn pixel value into bytes 2x16 bits words */ + strpixel*=2*2; /* 2 words of 2 bytes */ + endpixel*=2*2; + segcnt*=2*2; + pixels=endpixel-strpixel; + + dev->interface->record_key_value("shading_start_pixel", std::to_string(strpixel)); + dev->interface->record_key_value("shading_pixels", std::to_string(pixels)); + dev->interface->record_key_value("shading_length", std::to_string(length)); + dev->interface->record_key_value("shading_factor", std::to_string(factor)); + dev->interface->record_key_value("shading_segcnt", std::to_string(segcnt)); + dev->interface->record_key_value("shading_segment_count", + std::to_string(dev->session.segment_count)); + + DBG( DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__func__,length, length/4); + std::vector buffer(pixels * dev->session.segment_count, 0); + + /* write actual red data */ + for(i=0;i<3;i++) + { + /* copy data to work buffer and process it */ + /* coefficent destination */ + ptr = buffer.data(); + + /* iterate on both sensor segment */ + for(x=0;xsession.segment_count) { + case 1: + ptr[0+pixels*0]=src[0+segcnt*0]; + ptr[1+pixels*0]=src[1+segcnt*0]; + ptr[2+pixels*0]=src[2+segcnt*0]; + ptr[3+pixels*0]=src[3+segcnt*0]; + break; + case 2: + ptr[0+pixels*0]=src[0+segcnt*0]; + ptr[1+pixels*0]=src[1+segcnt*0]; + ptr[2+pixels*0]=src[2+segcnt*0]; + ptr[3+pixels*0]=src[3+segcnt*0]; + ptr[0+pixels*1]=src[0+segcnt*1]; + ptr[1+pixels*1]=src[1+segcnt*1]; + ptr[2+pixels*1]=src[2+segcnt*1]; + ptr[3+pixels*1]=src[3+segcnt*1]; + break; + case 4: + ptr[0+pixels*0]=src[0+segcnt*0]; + ptr[1+pixels*0]=src[1+segcnt*0]; + ptr[2+pixels*0]=src[2+segcnt*0]; + ptr[3+pixels*0]=src[3+segcnt*0]; + ptr[0+pixels*1]=src[0+segcnt*2]; + ptr[1+pixels*1]=src[1+segcnt*2]; + ptr[2+pixels*1]=src[2+segcnt*2]; + ptr[3+pixels*1]=src[3+segcnt*2]; + ptr[0+pixels*2]=src[0+segcnt*1]; + ptr[1+pixels*2]=src[1+segcnt*1]; + ptr[2+pixels*2]=src[2+segcnt*1]; + ptr[3+pixels*2]=src[3+segcnt*1]; + ptr[0+pixels*3]=src[0+segcnt*3]; + ptr[1+pixels*3]=src[1+segcnt*3]; + ptr[2+pixels*3]=src[2+segcnt*3]; + ptr[3+pixels*3]=src[3+segcnt*3]; + break; + } + + /* next shading coefficient */ + ptr+=4; + } + uint8_t val = dev->interface->read_register(0xd0+i); + addr = val * 8192 + 0x10000000; + dev->interface->write_ahb(addr, pixels * dev->session.segment_count, buffer.data()); + } +} + + +/** @brief move to calibration area + * This functions moves scanning head to calibration area + * by doing a 600 dpi scan + * @param dev scanner device + */ +static void move_to_calibration_area(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + (void) sensor; + + DBG_HELPER(dbg); + int pixels; + int size; + + unsigned resolution = 600; + unsigned channels = 3; + const auto& move_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + pixels = (move_sensor.sensor_pixels * 600) / move_sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = 1; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, move_sensor); + + dev->cmd_set->init_regs_for_scan_session(dev, move_sensor, ®s, session); + + size = pixels * 3; + std::vector line(size); + + // write registers and scan data + dev->interface->write_registers(regs); + + DBG (DBG_info, "%s: starting line reading\n", __func__); + dev->cmd_set->begin_scan(dev, move_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("move_to_calibration_area"); + scanner_stop_action(*dev); + return; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), size); + + // stop scanning + scanner_stop_action(*dev); + + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_pnm_file("gl124_movetocalarea.pnm", line.data(), 8, 3, pixels, 1); + } +} + +/* this function does the led calibration by scanning one line of the calibration + area below scanner's top on white strip. + +-needs working coarse/gain +*/ +SensorExposure CommandSetGl124::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int num_pixels; + int total_size; + int resolution; + int dpihw; + int i, j; + int val; + int channels; + int avg[3]; + int turn; + uint16_t exp[3],target; + + /* move to calibration area */ + move_to_calibration_area(dev, sensor, regs); + + /* offset calibration is always done in 16 bit depth color mode */ + channels = 3; + dpihw = sensor.get_register_hwdpi(dev->settings.xres); + resolution = dpihw; + unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); + resolution /= ccd_size_divisor; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + num_pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + total_size = num_pixels * channels * (session.params.depth / 8) * 1; + std::vector line(total_size); + + // initial loop values and boundaries + exp[0] = calib_sensor.exposure.red; + exp[1] = calib_sensor.exposure.green; + exp[2] = calib_sensor.exposure.blue; + target=sensor.gain_white_ref*256; + + turn = 0; + + /* no move during led calibration */ + sanei_genesys_set_motor_power(regs, false); + bool acceptable = false; + do + { + // set up exposure + regs.set24(REG_EXPR, exp[0]); + regs.set24(REG_EXPG, exp[1]); + regs.set24(REG_EXPB, exp[2]); + + // write registers and scan data + dev->interface->write_registers(regs); + + DBG(DBG_info, "%s: starting line reading\n", __func__); + begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("led_calibration"); + scanner_stop_action(*dev); + return calib_sensor.exposure; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + + // stop scanning + scanner_stop_action(*dev); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl124_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth, channels, num_pixels, + 1); + } + + /* compute average */ + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + /* check if exposure gives average within the boundaries */ + acceptable = true; + for(i=0;i<3;i++) + { + /* we accept +- 2% delta from target */ + if(abs(avg[i]-target)>target/50) + { + float prev_weight = 0.5; + exp[i] = exp[i] * prev_weight + ((exp[i] * target) / avg[i]) * (1 - prev_weight); + acceptable = false; + } + } + + turn++; + } + while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); + + // set these values as final ones for scan + dev->reg.set24(REG_EXPR, exp[0]); + dev->reg.set24(REG_EXPG, exp[1]); + dev->reg.set24(REG_EXPB, exp[2]); + + return { exp[0], exp[1], exp[2] }; +} + +/** + * average dark pixels of a 8 bits scan + */ +static int +dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black) +{ + unsigned int i, j, k, average, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average value on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + for (i = 0; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + average = 0; + for (i = 0; i < channels; i++) + average += avg[i]; + average /= channels; + DBG(DBG_info, "%s: average = %d\n", __func__, average); + return average; +} + + +void CommandSetGl124::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + unsigned channels; + int pass = 0, avg, total_size; + int topavg, bottomavg, lines; + int top, bottom, black_pixels, pixels; + + // no gain nor offset for TI AFE + uint8_t reg0a = dev->interface->read_register(REG_0x0A); + if (((reg0a & REG_0x0A_SIFSEL) >> REG_0x0AS_SIFSEL) == 3) { + return; + } + + /* offset calibration is always done in color mode */ + channels = 3; + dev->calib_pixels = sensor.sensor_pixels; + lines=1; + pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res; + black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + ScanSession session; + session.params.xres = sensor.optical_res; + session.params.yres = sensor.optical_res; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, ®s, session); + + sanei_genesys_set_motor_power(regs, false); + + /* allocate memory for scans */ + total_size = pixels * channels * lines * (session.params.depth / 8); + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* init gain */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* scan with no move */ + bottom = 10; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting first line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("offset_calibration"); + return; + } + + sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + std::snprintf(title, 30, "gl124_offset%03d.pnm", bottom); + sanei_genesys_write_pnm_file(title, first_line.data(), session.params.depth, + channels, pixels, lines); + } + + bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); + + /* now top value */ + top = 255; + dev->frontend.set_offset(0, top); + dev->frontend.set_offset(1, top); + dev->frontend.set_offset(2, top); + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + + topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); + + /* loop until acceptable level */ + while ((pass < 32) && (top - bottom > 1)) + { + pass++; + + /* settings for new scan */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + // scan with no move + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + std::snprintf(title, 30, "gl124_offset%03d.pnm", dev->frontend.get_offset(1)); + sanei_genesys_write_pnm_file(title, second_line.data(), session.params.depth, + channels, pixels, lines); + } + + avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); + + /* compute new boundaries */ + if (topavg == avg) + { + topavg = avg; + top = dev->frontend.get_offset(1); + } + else + { + bottomavg = avg; + bottom = dev->frontend.get_offset(1); + } + } + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); +} + + +/* alternative coarse gain calibration + this on uses the settings from offset_calibration and + uses only one scanline + */ +/* + with offset and coarse calibration we only want to get our input range into + a reasonable shape. the fine calibration of the upper and lower bounds will + be done with shading. + */ +void CommandSetGl124::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const +{ + DBG_HELPER_ARGS(dbg, "dpi = %d", dpi); + int pixels; + int total_size; + int i, j, channels; + int max[3]; + float gain[3],coeff; + int val, code, lines; + + // no gain nor offset for TI AFE + uint8_t reg0a = dev->interface->read_register(REG_0x0A); + if (((reg0a & REG_0x0A_SIFSEL) >> REG_0x0AS_SIFSEL) == 3) { + return; + } + + /* coarse gain calibration is always done in color mode */ + channels = 3; + + if(dev->settings.xressettings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + try { + init_regs_for_scan_session(dev, sensor, ®s, session); + } catch (...) { + catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); }); + throw; + } + + sanei_genesys_set_motor_power(regs, false); + + dev->interface->write_registers(regs); + + total_size = pixels * channels * (16 / session.params.depth) * lines; + + std::vector line(total_size); + + set_fe(dev, sensor, AFE_SET); + begin_scan(dev, sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("coarse_gain_calibration"); + scanner_stop_action(*dev); + move_back_home(dev, true); + return; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl124_gain.pnm", line.data(), session.params.depth, + channels, pixels, lines); + } + + /* average value on each channel */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + for (i = pixels/4; i < (pixels*3/4); i++) + { + if (dev->model->is_cis) { + val = line[i + j * pixels]; + } else { + val = line[i * channels + j]; + } + + max[j] += val; + } + max[j] = max[j] / (pixels/2); + + gain[j] = (static_cast(sensor.gain_white_ref) * coeff) / max[j]; + + /* turn logical gain value into gain code, checking for overflow */ + code = static_cast(283 - 208 / gain[j]); + if (code > 255) + code = 255; + else if (code < 0) + code = 0; + dev->frontend.set_gain(j, code); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], + gain[j], dev->frontend.get_gain(j)); + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + if (channels == 1) { + dev->frontend.set_gain(0, dev->frontend.get_gain(1)); + dev->frontend.set_gain(2, dev->frontend.get_gain(1)); + } + + scanner_stop_action(*dev); + + move_back_home(dev, true); +} + +// wait for lamp warmup by scanning the same line until difference +// between 2 scans is below a threshold +void CommandSetGl124::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, int* channels, + int* total_size) const +{ + DBG_HELPER(dbg); + int num_pixels; + + *channels=3; + + *reg = dev->reg; + + ScanSession session; + session.params.xres = sensor.optical_res; + session.params.yres = dev->motor.base_ydpi; + session.params.startx = sensor.sensor_pixels / 4; + session.params.starty = 0; + session.params.pixels = sensor.sensor_pixels / 2; + session.params.lines = 1; + session.params.depth = 8; + session.params.channels = *channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, reg, session); + + num_pixels = session.output_pixels; + + *total_size = num_pixels * 3 * 1; /* colors * bytes_per_color * scan lines */ + + sanei_genesys_set_motor_power(*reg, false); + dev->interface->write_registers(*reg); +} + +/** @brief default GPIO values + * set up GPIO/GPOE for idle state + * @param dev device to set up + */ +static void gl124_init_gpio(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + int idx; + + /* per model GPIO layout */ + if (dev->model->model_id == ModelId::CANON_LIDE_110) { + idx = 0; + } else if (dev->model->model_id == ModelId::CANON_LIDE_120) { + idx = 2; + } + else + { /* canon LiDE 210 and 220 case */ + idx = 1; + } + + dev->interface->write_register(REG_0x31, gpios[idx].r31); + dev->interface->write_register(REG_0x32, gpios[idx].r32); + dev->interface->write_register(REG_0x33, gpios[idx].r33); + dev->interface->write_register(REG_0x34, gpios[idx].r34); + dev->interface->write_register(REG_0x35, gpios[idx].r35); + dev->interface->write_register(REG_0x36, gpios[idx].r36); + dev->interface->write_register(REG_0x38, gpios[idx].r38); +} + +/** + * set memory layout by filling values in dedicated registers + */ +static void gl124_init_memory_layout(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + int idx = 0; + + /* point to per model memory layout */ + if (dev->model->model_id == ModelId::CANON_LIDE_110 || + dev->model->model_id == ModelId::CANON_LIDE_120) + { + idx = 0; + } + else + { /* canon LiDE 210 and 220 case */ + idx = 1; + } + + /* setup base address for shading data. */ + /* values must be multiplied by 8192=0x4000 to give address on AHB */ + /* R-Channel shading bank0 address setting for CIS */ + dev->interface->write_register(0xd0, layouts[idx].rd0); + /* G-Channel shading bank0 address setting for CIS */ + dev->interface->write_register(0xd1, layouts[idx].rd1); + /* B-Channel shading bank0 address setting for CIS */ + dev->interface->write_register(0xd2, layouts[idx].rd2); + + /* setup base address for scanned data. */ + /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ + /* R-Channel ODD image buffer 0x0124->0x92000 */ + /* size for each buffer is 0x16d*1k word */ + dev->interface->write_register(0xe0, layouts[idx].re0); + dev->interface->write_register(0xe1, layouts[idx].re1); + /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ + dev->interface->write_register(0xe2, layouts[idx].re2); + dev->interface->write_register(0xe3, layouts[idx].re3); + + /* R-Channel EVEN image buffer 0x0292 */ + dev->interface->write_register(0xe4, layouts[idx].re4); + dev->interface->write_register(0xe5, layouts[idx].re5); + /* R-Channel EVEN image buffer end-address 0x03ff*/ + dev->interface->write_register(0xe6, layouts[idx].re6); + dev->interface->write_register(0xe7, layouts[idx].re7); + + /* same for green, since CIS, same addresses */ + dev->interface->write_register(0xe8, layouts[idx].re0); + dev->interface->write_register(0xe9, layouts[idx].re1); + dev->interface->write_register(0xea, layouts[idx].re2); + dev->interface->write_register(0xeb, layouts[idx].re3); + dev->interface->write_register(0xec, layouts[idx].re4); + dev->interface->write_register(0xed, layouts[idx].re5); + dev->interface->write_register(0xee, layouts[idx].re6); + dev->interface->write_register(0xef, layouts[idx].re7); + +/* same for blue, since CIS, same addresses */ + dev->interface->write_register(0xf0, layouts[idx].re0); + dev->interface->write_register(0xf1, layouts[idx].re1); + dev->interface->write_register(0xf2, layouts[idx].re2); + dev->interface->write_register(0xf3, layouts[idx].re3); + dev->interface->write_register(0xf4, layouts[idx].re4); + dev->interface->write_register(0xf5, layouts[idx].re5); + dev->interface->write_register(0xf6, layouts[idx].re6); + dev->interface->write_register(0xf7, layouts[idx].re7); +} + +/** + * initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +void CommandSetGl124::init(Genesys_Device* dev) const +{ + DBG_INIT (); + DBG_HELPER(dbg); + + sanei_genesys_asic_init(dev, 0); +} + + +/* * + * initialize ASIC from power on condition + */ +void CommandSetGl124::asic_boot(Genesys_Device* dev, bool cold) const +{ + DBG_HELPER(dbg); + + // reset ASIC in case of cold boot + if (cold) { + dev->interface->write_register(0x0e, 0x01); + dev->interface->write_register(0x0e, 0x00); + } + + // enable GPOE 17 + dev->interface->write_register(0x36, 0x01); + + // set GPIO 17 + uint8_t val = dev->interface->read_register(0x33); + val |= 0x01; + dev->interface->write_register(0x33, val); + + // test CHKVER + val = dev->interface->read_register(REG_0x100); + if (val & REG_0x100_CHKVER) { + val = dev->interface->read_register(0x00); + DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); + } + + /* Set default values for registers */ + gl124_init_registers (dev); + + // Write initial registers + dev->interface->write_registers(dev->reg); + + // tune reg 0B + dev->interface->write_register(REG_0x0B, REG_0x0B_30MHZ | REG_0x0B_ENBDRAM | REG_0x0B_64M); + dev->reg.remove_reg(0x0b); + + //set up end access + dev->interface->write_0x8c(0x10, 0x0b); + dev->interface->write_0x8c(0x13, 0x0e); + + /* CIS_LINE */ + dev->reg.init_reg(0x08, REG_0x08_CIS_LINE); + dev->interface->write_register(0x08, dev->reg.find_reg(0x08).value); + + // setup gpio + gl124_init_gpio(dev); + + // setup internal memory layout + gl124_init_memory_layout(dev); +} + + +void CommandSetGl124::update_hardware_sensors(Genesys_Scanner* s) const +{ + /* do what is needed to get a new set of events, but try to not loose + any of them. + */ + DBG_HELPER(dbg); + uint8_t val = s->dev->interface->read_register(REG_0x31); + + /* TODO : for the next scanner special case, + * add another per scanner button profile struct to avoid growing + * hard-coded button mapping here. + */ + if ((s->dev->model->gpio_id == GpioId::CANON_LIDE_110) || + (s->dev->model->gpio_id == GpioId::CANON_LIDE_120)) + { + s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_FILE_SW].write((val & 0x08) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); + s->buttons[BUTTON_COPY_SW].write((val & 0x02) == 0); + } + else + { /* LiDE 210 case */ + s->buttons[BUTTON_EXTRA_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_SCAN_SW].write((val & 0x02) == 0); + s->buttons[BUTTON_COPY_SW].write((val & 0x04) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & 0x08) == 0); + s->buttons[BUTTON_FILE_SW].write((val & 0x10) == 0); + } +} + +void CommandSetGl124::update_home_sensor_gpio(Genesys_Device& dev) const +{ + DBG_HELPER(dbg); + + std::uint8_t val = dev.interface->read_register(REG_0x32); + val &= ~REG_0x32_GPIO10; + dev.interface->write_register(REG_0x32, val); +} + +bool CommandSetGl124::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const +{ + (void) dev; + return true; +} + +void CommandSetGl124::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + sanei_genesys_send_gamma_table(dev, sensor); +} + +void CommandSetGl124::load_document(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl124::detect_document_end(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl124::eject_document(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl124::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const +{ + (void) dev; + (void) sensor; + (void) forward; + (void) black; + throw SaneException("not implemented"); +} + +void CommandSetGl124::move_to_ta(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +std::unique_ptr create_gl124_cmd_set() +{ + return std::unique_ptr(new CommandSetGl124{}); +} + +} // namespace gl124 +} // namespace genesys diff --git a/backend/genesys/gl124.h b/backend/genesys/gl124.h new file mode 100644 index 0000000..cdf8faf --- /dev/null +++ b/backend/genesys/gl124.h @@ -0,0 +1,205 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2016 Stéphane Voltz + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL124_H +#define BACKEND_GENESYS_GL124_H + +#include "genesys.h" +#include "command_set.h" + +namespace genesys { +namespace gl124 { + +typedef struct +{ + uint8_t r31; + uint8_t r32; + uint8_t r33; + uint8_t r34; + uint8_t r35; + uint8_t r36; + uint8_t r38; +} Gpio_layout; + +/** @brief gpio layout + * describes initial gpio settings for a given model + * registers 0x31 to 0x38 + */ +static Gpio_layout gpios[]={ + /* LiDE 110 */ + { /* 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38 */ + 0x9f, 0x59, 0x01, 0x80, 0x5f, 0x01, 0x00 + }, + /* LiDE 210 */ + { + 0x9f, 0x59, 0x01, 0x80, 0x5f, 0x01, 0x00 + }, + /* LiDE 120 */ + { + 0x9f, 0x53, 0x01, 0x80, 0x5f, 0x01, 0x00 + }, +}; + +typedef struct +{ + uint8_t rd0; + uint8_t rd1; + uint8_t rd2; + uint8_t re0; + uint8_t re1; + uint8_t re2; + uint8_t re3; + uint8_t re4; + uint8_t re5; + uint8_t re6; + uint8_t re7; +} Memory_layout; + +static Memory_layout layouts[]={ + /* LIDE 110, 120 */ + { /* 0xd0 0xd1 0xd2 */ + 0x0a, 0x15, 0x20, + /* 0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 */ + 0x00, 0xac, 0x08, 0x55, 0x08, 0x56, 0x0f, 0xff + }, + /* LIDE 210, 220 */ + { + 0x0a, 0x1f, 0x34, + 0x01, 0x24, 0x08, 0x91, 0x08, 0x92, 0x0f, 0xff + } +}; + +static void gl124_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, int steps); + +class CommandSetGl124 : public CommandSet +{ +public: + ~CommandSetGl124() override = default; + + bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override; + + void init(Genesys_Device* dev) const override; + + void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const override; + + void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const override; + + void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override; + void set_powersaving(Genesys_Device* dev, int delay) const override; + void save_power(Genesys_Device* dev, bool enable) const override; + + void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, bool start_motor) const override; + + void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override; + + void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void search_start_position(Genesys_Device* dev) const override; + + void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const override; + + SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void wait_for_motor_stop(Genesys_Device* dev) const override; + + void move_back_home(Genesys_Device* dev, bool wait_until_home) const override; + + void update_hardware_sensors(struct Genesys_Scanner* s) const override; + + bool needs_update_home_sensor_gpio() const override { return true; } + + void update_home_sensor_gpio(Genesys_Device& dev) const override; + + void load_document(Genesys_Device* dev) const override; + + void detect_document_end(Genesys_Device* dev) const override; + + void eject_document(Genesys_Device* dev) const override; + + void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const override; + + void move_to_ta(Genesys_Device* dev) const override; + + void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data, + int size) const override; + + ScanSession calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const override; + + void asic_boot(Genesys_Device* dev, bool cold) const override; +}; + +enum SlopeTable +{ + SCAN_TABLE = 0, // table 1 at 0x4000 + BACKTRACK_TABLE = 1, // table 2 at 0x4800 + STOP_TABLE = 2, // table 3 at 0x5000 + FAST_TABLE = 3, // table 4 at 0x5800 + HOME_TABLE = 4, // table 5 at 0x6000 +}; + +} // namespace gl124 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL124_H diff --git a/backend/genesys/gl124_registers.h b/backend/genesys/gl124_registers.h new file mode 100644 index 0000000..9b42084 --- /dev/null +++ b/backend/genesys/gl124_registers.h @@ -0,0 +1,316 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL124_REGISTERS_H +#define BACKEND_GENESYS_GL124_REGISTERS_H + +#include + +namespace genesys { +namespace gl124 { + +using RegAddr = std::uint16_t; +using RegMask = std::uint8_t; +using RegShift = unsigned; + +static constexpr RegAddr REG_0x01 = 0x01; +static constexpr RegMask REG_0x01_CISSET = 0x80; +static constexpr RegMask REG_0x01_DOGENB = 0x40; +static constexpr RegMask REG_0x01_DVDSET = 0x20; +static constexpr RegMask REG_0x01_STAGGER = 0x10; +static constexpr RegMask REG_0x01_COMPENB = 0x08; +static constexpr RegMask REG_0x01_TRUEGRAY = 0x04; +static constexpr RegMask REG_0x01_SHDAREA = 0x02; +static constexpr RegMask REG_0x01_SCAN = 0x01; + +static constexpr RegAddr REG_0x02 = 0x02; +static constexpr RegMask REG_0x02_NOTHOME = 0x80; +static constexpr RegMask REG_0x02_ACDCDIS = 0x40; +static constexpr RegMask REG_0x02_AGOHOME = 0x20; +static constexpr RegMask REG_0x02_MTRPWR = 0x10; +static constexpr RegMask REG_0x02_FASTFED = 0x08; +static constexpr RegMask REG_0x02_MTRREV = 0x04; +static constexpr RegMask REG_0x02_HOMENEG = 0x02; +static constexpr RegMask REG_0x02_LONGCURV = 0x01; + +static constexpr RegAddr REG_0x03 = 0x03; +static constexpr RegMask REG_0x03_LAMPDOG = 0x80; +static constexpr RegMask REG_0x03_AVEENB = 0x40; +static constexpr RegMask REG_0x03_XPASEL = 0x20; +static constexpr RegMask REG_0x03_LAMPPWR = 0x10; +static constexpr RegMask REG_0x03_LAMPTIM = 0x0f; + +static constexpr RegAddr REG_0x04 = 0x04; +static constexpr RegMask REG_0x04_LINEART = 0x80; +static constexpr RegMask REG_0x04_BITSET = 0x40; +static constexpr RegMask REG_0x04_FILTER = 0x30; +static constexpr RegMask REG_0x04_AFEMOD = 0x07; + +static constexpr RegAddr REG_0x05 = 0x05; +static constexpr RegMask REG_0x05_DPIHW = 0xc0; +static constexpr RegMask REG_0x05_DPIHW_600 = 0x00; +static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40; +static constexpr RegMask REG_0x05_DPIHW_2400 = 0x80; +static constexpr RegMask REG_0x05_DPIHW_4800 = 0xc0; +static constexpr RegMask REG_0x05_MTLLAMP = 0x30; +static constexpr RegMask REG_0x05_GMMENB = 0x08; +static constexpr RegMask REG_0x05_ENB20M = 0x04; +static constexpr RegMask REG_0x05_MTLBASE = 0x03; + +static constexpr RegAddr REG_0x06 = 0x06; +static constexpr RegMask REG_0x06_SCANMOD = 0xe0; +static constexpr RegMask REG_0x06S_SCANMOD = 5; +static constexpr RegMask REG_0x06_PWRBIT = 0x10; +static constexpr RegMask REG_0x06_GAIN4 = 0x08; +static constexpr RegMask REG_0x06_OPTEST = 0x07; + +static constexpr RegMask REG_0x07_LAMPSIM = 0x80; + +static constexpr RegMask REG_0x08_DRAM2X = 0x80; +static constexpr RegMask REG_0x08_MPENB = 0x20; +static constexpr RegMask REG_0x08_CIS_LINE = 0x10; +static constexpr RegMask REG_0x08_IR2_ENB = 0x08; +static constexpr RegMask REG_0x08_IR1_ENB = 0x04; +static constexpr RegMask REG_0x08_ENB24M = 0x01; + +static constexpr RegMask REG_0x09_MCNTSET = 0xc0; +static constexpr RegMask REG_0x09_EVEN1ST = 0x20; +static constexpr RegMask REG_0x09_BLINE1ST = 0x10; +static constexpr RegMask REG_0x09_BACKSCAN = 0x08; +static constexpr RegMask REG_0x09_OUTINV = 0x04; +static constexpr RegMask REG_0x09_SHORTTG = 0x02; + +static constexpr RegShift REG_0x09S_MCNTSET = 6; +static constexpr RegShift REG_0x09S_CLKSET = 4; + +static constexpr RegAddr REG_0x0A = 0x0a; +static constexpr RegMask REG_0x0A_SIFSEL = 0xc0; +static constexpr RegShift REG_0x0AS_SIFSEL = 6; +static constexpr RegMask REG_0x0A_SHEETFED = 0x20; +static constexpr RegMask REG_0x0A_LPWMEN = 0x10; + +static constexpr RegAddr REG_0x0B = 0x0b; +static constexpr RegMask REG_0x0B_DRAMSEL = 0x07; +static constexpr RegMask REG_0x0B_16M = 0x01; +static constexpr RegMask REG_0x0B_64M = 0x02; +static constexpr RegMask REG_0x0B_128M = 0x03; +static constexpr RegMask REG_0x0B_256M = 0x04; +static constexpr RegMask REG_0x0B_512M = 0x05; +static constexpr RegMask REG_0x0B_1G = 0x06; +static constexpr RegMask REG_0x0B_ENBDRAM = 0x08; +static constexpr RegMask REG_0x0B_RFHDIS = 0x10; +static constexpr RegMask REG_0x0B_CLKSET = 0xe0; +static constexpr RegMask REG_0x0B_24MHZ = 0x00; +static constexpr RegMask REG_0x0B_30MHZ = 0x20; +static constexpr RegMask REG_0x0B_40MHZ = 0x40; +static constexpr RegMask REG_0x0B_48MHZ = 0x60; +static constexpr RegMask REG_0x0B_60MHZ = 0x80; + +static constexpr RegAddr REG_0x0D = 0x0d; +static constexpr RegMask REG_0x0D_MTRP_RDY = 0x80; +static constexpr RegMask REG_0x0D_FULLSTP = 0x10; +static constexpr RegMask REG_0x0D_CLRMCNT = 0x04; +static constexpr RegMask REG_0x0D_CLRDOCJM = 0x02; +static constexpr RegMask REG_0x0D_CLRLNCNT = 0x01; + +static constexpr RegAddr REG_0x0F = 0x0f; + +static constexpr RegMask REG_0x16_CTRLHI = 0x80; +static constexpr RegMask REG_0x16_TOSHIBA = 0x40; +static constexpr RegMask REG_0x16_TGINV = 0x20; +static constexpr RegMask REG_0x16_CK1INV = 0x10; +static constexpr RegMask REG_0x16_CK2INV = 0x08; +static constexpr RegMask REG_0x16_CTRLINV = 0x04; +static constexpr RegMask REG_0x16_CKDIS = 0x02; +static constexpr RegMask REG_0x16_CTRLDIS = 0x01; + +static constexpr RegMask REG_0x17_TGMODE = 0xc0; +static constexpr RegMask REG_0x17_SNRSYN = 0x0f; + +static constexpr RegAddr REG_0x18 = 0x18; +static constexpr RegMask REG_0x18_CNSET = 0x80; +static constexpr RegMask REG_0x18_DCKSEL = 0x60; +static constexpr RegMask REG_0x18_CKTOGGLE = 0x10; +static constexpr RegMask REG_0x18_CKDELAY = 0x0c; +static constexpr RegMask REG_0x18_CKSEL = 0x03; + +static constexpr RegMask REG_0x1A_SW2SET = 0x80; +static constexpr RegMask REG_0x1A_SW1SET = 0x40; +static constexpr RegMask REG_0x1A_MANUAL3 = 0x02; +static constexpr RegMask REG_0x1A_MANUAL1 = 0x01; +static constexpr RegMask REG_0x1A_CK4INV = 0x08; +static constexpr RegMask REG_0x1A_CK3INV = 0x04; +static constexpr RegMask REG_0x1A_LINECLP = 0x02; + +static constexpr RegMask REG_0x1C_TBTIME = 0x07; + +static constexpr RegAddr REG_0x1D = 0x1d; +static constexpr RegMask REG_0x1D_CK4LOW = 0x80; +static constexpr RegMask REG_0x1D_CK3LOW = 0x40; +static constexpr RegMask REG_0x1D_CK1LOW = 0x20; +static constexpr RegMask REG_0x1D_LINESEL = 0x1f; +static constexpr RegShift REG_0x1DS_LINESEL = 0; + +static constexpr RegAddr REG_0x1E = 0x1e; +static constexpr RegMask REG_0x1E_WDTIME = 0xf0; +static constexpr RegShift REG_0x1ES_WDTIME = 4; + +static constexpr RegAddr REG_0x30 = 0x30; +static constexpr RegAddr REG_0x31 = 0x31; +static constexpr RegAddr REG_0x32 = 0x32; +static constexpr RegMask REG_0x32_GPIO16 = 0x80; +static constexpr RegMask REG_0x32_GPIO15 = 0x40; +static constexpr RegMask REG_0x32_GPIO14 = 0x20; +static constexpr RegMask REG_0x32_GPIO13 = 0x10; +static constexpr RegMask REG_0x32_GPIO12 = 0x08; +static constexpr RegMask REG_0x32_GPIO11 = 0x04; +static constexpr RegMask REG_0x32_GPIO10 = 0x02; +static constexpr RegMask REG_0x32_GPIO9 = 0x01; +static constexpr RegAddr REG_0x33 = 0x33; +static constexpr RegAddr REG_0x34 = 0x34; +static constexpr RegAddr REG_0x35 = 0x35; +static constexpr RegAddr REG_0x36 = 0x36; +static constexpr RegAddr REG_0x37 = 0x37; +static constexpr RegAddr REG_0x38 = 0x38; +static constexpr RegAddr REG_0x39 = 0x39; + +static constexpr RegAddr REG_0x60 = 0x60; +static constexpr RegMask REG_0x60_LED4TG = 0x80; +static constexpr RegMask REG_0x60_YENB = 0x40; +static constexpr RegMask REG_0x60_YBIT = 0x20; +static constexpr RegMask REG_0x60_ACYNCNRLC = 0x10; +static constexpr RegMask REG_0x60_ENOFFSET = 0x08; +static constexpr RegMask REG_0x60_LEDADD = 0x04; +static constexpr RegMask REG_0x60_CK4ADC = 0x02; +static constexpr RegMask REG_0x60_AUTOCONF = 0x01; + +static constexpr RegAddr REG_0x80 = 0x80; +static constexpr RegAddr REG_0x81 = 0x81; + +static constexpr RegAddr REG_0xA0 = 0xa0; +static constexpr RegMask REG_0xA0_FSTPSEL = 0x38; +static constexpr RegShift REG_0xA0S_FSTPSEL = 3; +static constexpr RegMask REG_0xA0_STEPSEL = 0x07; +static constexpr RegShift REG_0xA0S_STEPSEL = 0; + +static constexpr RegAddr REG_0xA1 = 0xa1; +static constexpr RegAddr REG_0xA2 = 0xa2; +static constexpr RegAddr REG_0xA3 = 0xa3; +static constexpr RegAddr REG_0xA4 = 0xa4; +static constexpr RegAddr REG_0xA5 = 0xa5; +static constexpr RegAddr REG_0xA6 = 0xa6; +static constexpr RegAddr REG_0xA7 = 0xa7; +static constexpr RegAddr REG_0xA8 = 0xa8; +static constexpr RegAddr REG_0xA9 = 0xa9; +static constexpr RegAddr REG_0xAA = 0xaa; +static constexpr RegAddr REG_0xAB = 0xab; +static constexpr RegAddr REG_0xAC = 0xac; +static constexpr RegAddr REG_0xAD = 0xad; +static constexpr RegAddr REG_0xAE = 0xae; +static constexpr RegAddr REG_0xAF = 0xaf; +static constexpr RegAddr REG_0xB0 = 0xb0; +static constexpr RegAddr REG_0xB1 = 0xb1; + +static constexpr RegAddr REG_0xB2 = 0xb2; +static constexpr RegMask REG_0xB2_Z1MOD = 0x1f; +static constexpr RegAddr REG_0xB3 = 0xb3; +static constexpr RegMask REG_0xB3_Z1MOD = 0xff; +static constexpr RegAddr REG_0xB4 = 0xb4; +static constexpr RegMask REG_0xB4_Z1MOD = 0xff; + +static constexpr RegAddr REG_0xB5 = 0xb5; +static constexpr RegMask REG_0xB5_Z2MOD = 0x1f; +static constexpr RegAddr REG_0xB6 = 0xb6; +static constexpr RegMask REG_0xB6_Z2MOD = 0xff; +static constexpr RegAddr REG_0xB7 = 0xb7; +static constexpr RegMask REG_0xB7_Z2MOD = 0xff; + +static constexpr RegAddr REG_0x100 = 0x100; +static constexpr RegMask REG_0x100_DOCSNR = 0x80; +static constexpr RegMask REG_0x100_ADFSNR = 0x40; +static constexpr RegMask REG_0x100_COVERSNR = 0x20; +static constexpr RegMask REG_0x100_CHKVER = 0x10; +static constexpr RegMask REG_0x100_DOCJAM = 0x08; +static constexpr RegMask REG_0x100_HISPDFLG = 0x04; +static constexpr RegMask REG_0x100_MOTMFLG = 0x02; +static constexpr RegMask REG_0x100_DATAENB = 0x01; + +static constexpr RegAddr REG_0x114 = 0x114; +static constexpr RegAddr REG_0x115 = 0x115; + +static constexpr RegAddr REG_LINCNT = 0x25; +static constexpr RegAddr REG_MAXWD = 0x28; +static constexpr RegAddr REG_DPISET = 0x2c; +static constexpr RegAddr REG_FEEDL = 0x3d; +static constexpr RegAddr REG_CK1MAP = 0x74; +static constexpr RegAddr REG_CK3MAP = 0x77; +static constexpr RegAddr REG_CK4MAP = 0x7a; +static constexpr RegAddr REG_LPERIOD = 0x7d; +static constexpr RegAddr REG_DUMMY = 0x80; +static constexpr RegAddr REG_STRPIXEL = 0x82; +static constexpr RegAddr REG_ENDPIXEL = 0x85; +static constexpr RegAddr REG_EXPDMY = 0x88; +static constexpr RegAddr REG_EXPR = 0x8a; +static constexpr RegAddr REG_EXPG = 0x8d; +static constexpr RegAddr REG_EXPB = 0x90; +static constexpr RegAddr REG_SEGCNT = 0x93; +static constexpr RegAddr REG_TG0CNT = 0x96; +static constexpr RegAddr REG_SCANFED = 0xa2; +static constexpr RegAddr REG_STEPNO = 0xa4; +static constexpr RegAddr REG_FWDSTEP = 0xa6; +static constexpr RegAddr REG_BWDSTEP = 0xa8; +static constexpr RegAddr REG_FASTNO = 0xaa; +static constexpr RegAddr REG_FSHDEC = 0xac; +static constexpr RegAddr REG_FMOVNO = 0xae; +static constexpr RegAddr REG_FMOVDEC = 0xb0; +static constexpr RegAddr REG_Z1MOD = 0xb2; +static constexpr RegAddr REG_Z2MOD = 0xb5; + +static constexpr RegAddr REG_TRUER = 0x110; +static constexpr RegAddr REG_TRUEG = 0x111; +static constexpr RegAddr REG_TRUEB = 0x112; + +} // namespace gl124 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL843_REGISTERS_H diff --git a/backend/genesys/gl646.cpp b/backend/genesys/gl646.cpp new file mode 100644 index 0000000..04ee85e --- /dev/null +++ b/backend/genesys/gl646.cpp @@ -0,0 +1,3436 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003 Oliver Rauch + Copyright (C) 2003, 2004 Henning Meier-Geinitz + Copyright (C) 2004 Gerhard Jaeger + Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2007 Luke + Copyright (C) 2011 Alexey Osipov for HP2400 description + and tuning + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "gl646.h" +#include "gl646_registers.h" +#include "test_settings.h" + +#include + +namespace genesys { +namespace gl646 { + +namespace { +constexpr unsigned CALIBRATION_LINES = 10; +} // namespace + +static void gl646_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, + int steps); + +/** + * reads value from gpio endpoint + */ +static void gl646_gpio_read(IUsbDevice& usb_dev, uint8_t* value) +{ + DBG_HELPER(dbg); + usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, GPIO_READ, INDEX, 1, value); +} + +/** + * writes the given value to gpio endpoint + */ +static void gl646_gpio_write(IUsbDevice& usb_dev, uint8_t value) +{ + DBG_HELPER_ARGS(dbg, "(0x%02x)", value); + usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_WRITE, INDEX, 1, &value); +} + +/** + * writes the given value to gpio output enable endpoint + */ +static void gl646_gpio_output_enable(IUsbDevice& usb_dev, uint8_t value) +{ + DBG_HELPER_ARGS(dbg, "(0x%02x)", value); + usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_OUTPUT_ENABLE, INDEX, 1, &value); +} + +/** + * stop scanner's motor + * @param dev scanner's device + */ +static void gl646_stop_motor(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + dev->interface->write_register(0x0f, 0x00); +} + +/** + * find the closest match in mode tables for the given resolution and scan mode. + * @param sensor id of the sensor + * @param required required resolution + * @param color true is color mode + * @return the closest resolution for the sensor and mode + */ +static unsigned get_closest_resolution(SensorId sensor_id, int required, unsigned channels) +{ + unsigned best_res = 0; + unsigned best_diff = 9600; + + for (const auto& sensor : *s_sensors) { + if (sensor_id != sensor.sensor_id) + continue; + + // exit on perfect match + if (sensor.resolutions.matches(required) && sensor.matches_channel_count(channels)) { + DBG(DBG_info, "%s: match found for %d\n", __func__, required); + return required; + } + + // computes distance and keep mode if it is closer than previous + if (sensor.matches_channel_count(channels)) { + for (auto res : sensor.resolutions.resolutions()) { + unsigned curr_diff = std::abs(static_cast(res) - static_cast(required)); + if (curr_diff < best_diff) { + best_res = res; + best_diff = curr_diff; + } + } + } + } + + DBG(DBG_info, "%s: closest match for %d is %d\n", __func__, required, best_res); + return best_res; +} + +/** + * Returns the cksel values used by the required scan mode. + * @param sensor id of the sensor + * @param required required resolution + * @param color true is color mode + * @return cksel value for mode + */ +static int get_cksel(SensorId sensor_id, int required, unsigned channels) +{ + for (const auto& sensor : *s_sensors) { + // exit on perfect match + if (sensor.sensor_id == sensor_id && sensor.resolutions.matches(required) && + sensor.matches_channel_count(channels)) + { + unsigned cksel = sensor.ccd_pixels_per_system_pixel(); + DBG(DBG_io, "%s: match found for %d (cksel=%d)\n", __func__, required, cksel); + return cksel; + } + } + DBG(DBG_error, "%s: failed to find match for %d dpi\n", __func__, required); + /* fail safe fallback */ + return 1; +} + +void CommandSetGl646::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, + const ScanSession& session) const +{ + DBG_HELPER(dbg); + session.assert_computed(); + + debug_dump(DBG_info, sensor); + + uint32_t move = session.params.starty; + + int i, nb; + Motor_Master *motor = nullptr; + uint32_t z1, z2; + int feedl; + + + /* for the given resolution, search for master + * motor mode setting */ + i = 0; + nb = sizeof (motor_master) / sizeof (Motor_Master); + while (i < nb) + { + if (dev->model->motor_id == motor_master[i].motor_id + && motor_master[i].dpi == session.params.yres + && motor_master[i].channels == session.params.channels) + { + motor = &motor_master[i]; + } + i++; + } + if (motor == nullptr) + { + throw SaneException("unable to find settings for motor %d at %d dpi, color=%d", + static_cast(dev->model->motor_id), + session.params.yres, session.params.channels); + } + + /* now we can search for the specific sensor settings */ + i = 0; + + // now apply values from settings to registers + regs->set16(REG_EXPR, sensor.exposure.red); + regs->set16(REG_EXPG, sensor.exposure.green); + regs->set16(REG_EXPB, sensor.exposure.blue); + + for (const auto& reg : sensor.custom_regs) { + regs->set8(reg.address, reg.value); + } + + /* now generate slope tables : we are not using generate_slope_table3 yet */ + auto slope_table1 = create_slope_table(motor->slope1, motor->slope1.max_speed_w, StepType::FULL, + 1, 4, get_slope_table_max_size(AsicType::GL646)); + auto slope_table2 = create_slope_table(motor->slope2, motor->slope2.max_speed_w, StepType::FULL, + 1, 4, get_slope_table_max_size(AsicType::GL646)); + + /* R01 */ + /* now setup other registers for final scan (ie with shading enabled) */ + /* watch dog + shading + scan enable */ + regs->find_reg(0x01).value |= REG_0x01_DOGENB | REG_0x01_DVDSET | REG_0x01_SCAN; + if (dev->model->is_cis) { + regs->find_reg(0x01).value |= REG_0x01_CISSET; + } else { + regs->find_reg(0x01).value &= ~REG_0x01_CISSET; + } + + /* if device has no calibration, don't enable shading correction */ + if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) + { + regs->find_reg(0x01).value &= ~REG_0x01_DVDSET; + } + + regs->find_reg(0x01).value &= ~REG_0x01_FASTMOD; + if (motor->fastmod) { + regs->find_reg(0x01).value |= REG_0x01_FASTMOD; + } + + /* R02 */ + /* allow moving when buffer full by default */ + if (!dev->model->is_sheetfed) { + dev->reg.find_reg(0x02).value &= ~REG_0x02_ACDCDIS; + } else { + dev->reg.find_reg(0x02).value |= REG_0x02_ACDCDIS; + } + + /* setup motor power and direction */ + sanei_genesys_set_motor_power(*regs, true); + + if (has_flag(session.params.flags, ScanFlag::REVERSE)) { + regs->find_reg(0x02).value |= REG_0x02_MTRREV; + } else { + regs->find_reg(0x02).value &= ~REG_0x02_MTRREV; + } + + /* fastfed enabled (2 motor slope tables) */ + if (motor->fastfed) { + regs->find_reg(0x02).value |= REG_0x02_FASTFED; + } else { + regs->find_reg(0x02).value &= ~REG_0x02_FASTFED; + } + + /* step type */ + regs->find_reg(0x02).value &= ~REG_0x02_STEPSEL; + switch (motor->steptype) + { + case StepType::FULL: + break; + case StepType::HALF: + regs->find_reg(0x02).value |= 1; + break; + case StepType::QUARTER: + regs->find_reg(0x02).value |= 2; + break; + default: + regs->find_reg(0x02).value |= 3; + break; + } + + if (dev->model->is_sheetfed) { + regs->find_reg(0x02).value &= ~REG_0x02_AGOHOME; + } else { + regs->find_reg(0x02).value |= REG_0x02_AGOHOME; + } + + /* R03 */ + regs->find_reg(0x03).value &= ~REG_0x03_AVEENB; + // regs->find_reg(0x03).value |= REG_0x03_AVEENB; + regs->find_reg(0x03).value &= ~REG_0x03_LAMPDOG; + + /* select XPA */ + regs->find_reg(0x03).value &= ~REG_0x03_XPASEL; + if ((session.params.flags & ScanFlag::USE_XPA) != ScanFlag::NONE) { + regs->find_reg(0x03).value |= REG_0x03_XPASEL; + } + regs->state.is_xpa_on = (session.params.flags & ScanFlag::USE_XPA) != ScanFlag::NONE; + + /* R04 */ + /* monochrome / color scan */ + switch (session.params.depth) { + case 8: + regs->find_reg(0x04).value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); + break; + case 16: + regs->find_reg(0x04).value &= ~REG_0x04_LINEART; + regs->find_reg(0x04).value |= REG_0x04_BITSET; + break; + } + + sanei_genesys_set_dpihw(*regs, sensor, sensor.optical_res); + + /* gamma enable for scans */ + if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) { + regs->find_reg(0x05).value |= REG_0x05_GMM14BIT; + } + + regs->find_reg(0x05).value &= ~REG_0x05_GMMENB; + + /* true CIS gray if needed */ + if (dev->model->is_cis && session.params.channels == 1 && dev->settings.true_gray) { + regs->find_reg(0x05).value |= REG_0x05_LEDADD; + } else { + regs->find_reg(0x05).value &= ~REG_0x05_LEDADD; + } + + /* HP2400 1200dpi mode tuning */ + + if (dev->model->sensor_id == SensorId::CCD_HP2400) { + /* reset count of dummy lines to zero */ + regs->find_reg(0x1e).value &= ~REG_0x1E_LINESEL; + if (session.params.xres >= 1200) { + /* there must be one dummy line */ + regs->find_reg(0x1e).value |= 1 & REG_0x1E_LINESEL; + + /* GPO12 need to be set to zero */ + regs->find_reg(0x66).value &= ~0x20; + } + else + { + /* set GPO12 back to one */ + regs->find_reg(0x66).value |= 0x20; + } + } + + /* motor steps used */ + unsigned forward_steps = motor->fwdbwd; + unsigned backward_steps = motor->fwdbwd; + + // the steps count must be different by at most 128, otherwise it's impossible to construct + // a proper backtracking curve. We're using slightly lower limit to allow at least a minimum + // distance between accelerations (forward_steps, backward_steps) + if (slope_table1.steps_count > slope_table2.steps_count + 100) { + slope_table2.steps_count += slope_table1.steps_count - 100; + } + if (slope_table2.steps_count > slope_table1.steps_count + 100) { + slope_table1.steps_count += slope_table2.steps_count - 100; + } + + if (slope_table1.steps_count >= slope_table2.steps_count) { + backward_steps += (slope_table1.steps_count - slope_table2.steps_count) * 2; + } else { + forward_steps += (slope_table2.steps_count - slope_table1.steps_count) * 2; + } + + if (forward_steps > 255) { + if (backward_steps < (forward_steps - 255)) { + throw SaneException("Can't set backtracking parameters without skipping image"); + } + backward_steps -= forward_steps - 255; + } + if (backward_steps > 255) { + if (forward_steps < (backward_steps - 255)) { + throw SaneException("Can't set backtracking parameters without skipping image"); + } + forward_steps -= backward_steps - 255; + } + + regs->find_reg(0x21).value = slope_table1.steps_count; + regs->find_reg(0x24).value = slope_table2.steps_count; + regs->find_reg(0x22).value = forward_steps; + regs->find_reg(0x23).value = backward_steps; + + /* CIS scanners read one line per color channel + * since gray mode use 'add' we also read 3 channels even not in + * color mode */ + if (dev->model->is_cis) { + regs->set24(REG_LINCNT, session.output_line_count * 3); + } else { + regs->set24(REG_LINCNT, session.output_line_count); + } + + regs->set16(REG_STRPIXEL, session.pixel_startx); + regs->set16(REG_ENDPIXEL, session.pixel_endx); + + regs->set24(REG_MAXWD, session.output_line_bytes); + + regs->set16(REG_DPISET, session.output_resolution * session.ccd_size_divisor * + sensor.ccd_pixels_per_system_pixel()); + regs->set16(REG_LPERIOD, sensor.exposure_lperiod); + + /* move distance must be adjusted to take into account the extra lines + * read to reorder data */ + feedl = move; + + if (session.num_staggered_lines + session.max_color_shift_lines > 0 && feedl != 0) { + int feed_offset = ((session.max_color_shift_lines + session.num_staggered_lines) * dev->motor.optical_ydpi) / + motor->dpi; + if (feedl > feed_offset) { + feedl = feedl - feed_offset; + } + } + + /* we assume all scans are done with 2 tables */ + /* + feedl = feed_steps - fast_slope_steps*2 - + (slow_slope_steps >> scan_step_type); */ + /* but head has moved due to shading calibration => dev->scanhead_position_primary */ + if (feedl > 0) + { + DBG(DBG_info, "%s: initial move=%d\n", __func__, feedl); + + /* TODO clean up this when I'll fully understand. + * for now, special casing each motor */ + switch (dev->model->motor_id) { + case MotorId::MD_5345: + switch (motor->dpi) { + case 200: + feedl -= 70; + break; + case 300: + feedl -= 70; + break; + case 400: + feedl += 130; + break; + case 600: + feedl += 160; + break; + case 1200: + feedl += 160; + break; + case 2400: + feedl += 180; + break; + default: + break; + } + break; + case MotorId::HP2300: + switch (motor->dpi) { + case 75: + feedl -= 180; + break; + case 150: + feedl += 0; + break; + case 300: + feedl += 30; + break; + case 600: + feedl += 35; + break; + case 1200: + feedl += 45; + break; + default: + break; + } + break; + case MotorId::HP2400: + switch (motor->dpi) { + case 150: + feedl += 150; + break; + case 300: + feedl += 220; + break; + case 600: + feedl += 260; + break; + case 1200: + feedl += 280; /* 300 */ + break; + case 50: + feedl += 0; + break; + case 100: + feedl += 100; + break; + default: + break; + } + break; + + /* theorical value */ + default: { + unsigned step_shift = static_cast(motor->steptype); + + if (motor->fastfed) + { + feedl = feedl - 2 * slope_table2.steps_count - + (slope_table1.steps_count >> step_shift); + } + else + { + feedl = feedl - (slope_table1.steps_count >> step_shift); + } + break; + } + } + /* security */ + if (feedl < 0) + feedl = 0; + } + + DBG(DBG_info, "%s: final move=%d\n", __func__, feedl); + regs->set24(REG_FEEDL, feedl); + + regs->find_reg(0x65).value = motor->mtrpwm; + + sanei_genesys_calculate_zmod(regs->find_reg(0x02).value & REG_0x02_FASTFED, + sensor.exposure_lperiod, + slope_table1.table, + slope_table1.steps_count, + move, motor->fwdbwd, &z1, &z2); + + /* no z1/z2 for sheetfed scanners */ + if (dev->model->is_sheetfed) { + z1 = 0; + z2 = 0; + } + regs->set16(REG_Z1MOD, z1); + regs->set16(REG_Z2MOD, z2); + regs->find_reg(0x6b).value = slope_table2.steps_count; + regs->find_reg(0x6c).value = + (regs->find_reg(0x6c).value & REG_0x6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16) + & 0x07); + + write_control(dev, sensor, session.output_resolution); + + // setup analog frontend + gl646_set_fe(dev, sensor, AFE_SET, session.output_resolution); + + dev->read_buffer.clear(); + dev->read_buffer.alloc(session.buffer_size_read); + + build_image_pipeline(dev, session); + + dev->read_active = true; + + dev->session = session; + + dev->total_bytes_read = 0; + dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines; + + /* select color filter based on settings */ + regs->find_reg(0x04).value &= ~REG_0x04_FILTER; + if (session.params.channels == 1) { + switch (session.params.color_filter) { + case ColorFilter::RED: + regs->find_reg(0x04).value |= 0x04; + break; + case ColorFilter::GREEN: + regs->find_reg(0x04).value |= 0x08; + break; + case ColorFilter::BLUE: + regs->find_reg(0x04).value |= 0x0c; + break; + default: + break; + } + } + + gl646_send_slope_table(dev, 0, slope_table1.table, regs->get8(0x21)); + gl646_send_slope_table(dev, 1, slope_table2.table, regs->get8(0x6b)); +} + + +/** copy sensor specific settings */ +/* *dev : device infos + *regs : regiters to be set + extended : do extended set up + ccd_size_divisor: set up for half ccd resolution + all registers 08-0B, 10-1D, 52-5E are set up. They shouldn't + appear anywhere else but in register init +*/ +static void +gl646_setup_sensor (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * regs) +{ + (void) dev; + DBG(DBG_proc, "%s: start\n", __func__); + + for (const auto& reg_setting : sensor.custom_base_regs) { + regs->set8(reg_setting.address, reg_setting.value); + } + // FIXME: all other drivers don't set exposure here + regs_set_exposure(AsicType::GL646, *regs, sensor.exposure); + + DBG(DBG_proc, "%s: end\n", __func__); +} + +/** + * Set all registers to default values after init + * @param dev scannerr's device to set + */ +static void +gl646_init_regs (Genesys_Device * dev) +{ + int addr; + + DBG(DBG_proc, "%s\n", __func__); + + dev->reg.clear(); + + for (addr = 1; addr <= 0x0b; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x10; addr <= 0x29; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x2c; addr <= 0x39; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x3d; addr <= 0x3f; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x52; addr <= 0x5e; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x60; addr <= 0x6d; addr++) + dev->reg.init_reg(addr, 0); + + dev->reg.find_reg(0x01).value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */ + dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ + if (dev->model->motor_id == MotorId::MD_5345) { + dev->reg.find_reg(0x02).value |= 0x01; // half-step + } + switch (dev->model->motor_id) { + case MotorId::MD_5345: + dev->reg.find_reg(0x02).value |= 0x01; /* half-step */ + break; + case MotorId::XP200: + /* for this sheetfed scanner, no AGOHOME, nor backtracking */ + dev->reg.find_reg(0x02).value = 0x50; + break; + default: + break; + } + dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */ + dev->reg.find_reg(0x04).value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */ + switch (dev->model->adc_id) + { + case AdcId::AD_XP200: + dev->reg.find_reg(0x04).value = 0x12; + break; + default: + /* Wolfson frontend */ + dev->reg.find_reg(0x04).value = 0x13; + break; + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + dev->reg.find_reg(0x05).value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */ + sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res); + + if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) { + dev->reg.find_reg(0x05).value |= REG_0x05_GMM14BIT; + } + if (dev->model->adc_id == AdcId::AD_XP200) { + dev->reg.find_reg(0x05).value |= 0x01; /* 12 clocks/pixel */ + } + + if (dev->model->sensor_id == SensorId::CCD_HP2300) { + dev->reg.find_reg(0x06).value = 0x00; // PWRBIT off, shading gain=4, normal AFE image capture + } else { + dev->reg.find_reg(0x06).value = 0x18; // PWRBIT on, shading gain=8, normal AFE image capture + } + + + gl646_setup_sensor(dev, sensor, &dev->reg); + + dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */ + + switch (dev->model->sensor_id) + { + case SensorId::CCD_HP2300: + dev->reg.find_reg(0x1e).value = 0xf0; + dev->reg.find_reg(0x1f).value = 0x10; + dev->reg.find_reg(0x20).value = 0x20; + break; + case SensorId::CCD_HP2400: + dev->reg.find_reg(0x1e).value = 0x80; + dev->reg.find_reg(0x1f).value = 0x10; + dev->reg.find_reg(0x20).value = 0x20; + break; + case SensorId::CCD_HP3670: + dev->reg.find_reg(0x19).value = 0x2a; + dev->reg.find_reg(0x1e).value = 0x80; + dev->reg.find_reg(0x1f).value = 0x10; + dev->reg.find_reg(0x20).value = 0x20; + break; + case SensorId::CIS_XP200: + dev->reg.find_reg(0x1e).value = 0x10; + dev->reg.find_reg(0x1f).value = 0x01; + dev->reg.find_reg(0x20).value = 0x50; + break; + default: + dev->reg.find_reg(0x1f).value = 0x01; + dev->reg.find_reg(0x20).value = 0x50; + break; + } + + dev->reg.find_reg(0x21).value = 0x08 /*0x20 */ ; /* table one steps number for forward slope curve of the acc/dec */ + dev->reg.find_reg(0x22).value = 0x10 /*0x08 */ ; /* steps number of the forward steps for start/stop */ + dev->reg.find_reg(0x23).value = 0x10 /*0x08 */ ; /* steps number of the backward steps for start/stop */ + dev->reg.find_reg(0x24).value = 0x08 /*0x20 */ ; /* table one steps number backward slope curve of the acc/dec */ + dev->reg.find_reg(0x25).value = 0x00; /* scan line numbers (7000) */ + dev->reg.find_reg(0x26).value = 0x00 /*0x1b */ ; + dev->reg.find_reg(0x27).value = 0xd4 /*0x58 */ ; + dev->reg.find_reg(0x28).value = 0x01; /* PWM duty for lamp control */ + dev->reg.find_reg(0x29).value = 0xff; + + dev->reg.find_reg(0x2c).value = 0x02; /* set resolution (600 DPI) */ + dev->reg.find_reg(0x2d).value = 0x58; + dev->reg.find_reg(0x2e).value = 0x78; /* set black&white threshold high level */ + dev->reg.find_reg(0x2f).value = 0x7f; /* set black&white threshold low level */ + + dev->reg.find_reg(0x30).value = 0x00; /* begin pixel position (16) */ + dev->reg.find_reg(0x31).value = sensor.dummy_pixel /*0x10 */ ; /* TGW + 2*TG_SHLD + x */ + dev->reg.find_reg(0x32).value = 0x2a /*0x15 */ ; /* end pixel position (5390) */ + dev->reg.find_reg(0x33).value = 0xf8 /*0x0e */ ; /* TGW + 2*TG_SHLD + y */ + dev->reg.find_reg(0x34).value = sensor.dummy_pixel; + dev->reg.find_reg(0x35).value = 0x01 /*0x00 */ ; /* set maximum word size per line, for buffer full control (10800) */ + dev->reg.find_reg(0x36).value = 0x00 /*0x2a */ ; + dev->reg.find_reg(0x37).value = 0x00 /*0x30 */ ; + dev->reg.find_reg(0x38).value = 0x2a; // line period (exposure time = 11000 pixels) */ + dev->reg.find_reg(0x39).value = 0xf8; + dev->reg.find_reg(0x3d).value = 0x00; /* set feed steps number of motor move */ + dev->reg.find_reg(0x3e).value = 0x00; + dev->reg.find_reg(0x3f).value = 0x01 /*0x00 */ ; + + dev->reg.find_reg(0x60).value = 0x00; /* Z1MOD, 60h:61h:(6D b5:b3), remainder for start/stop */ + dev->reg.find_reg(0x61).value = 0x00; /* (21h+22h)/LPeriod */ + dev->reg.find_reg(0x62).value = 0x00; /* Z2MODE, 62h:63h:(6D b2:b0), remainder for start scan */ + dev->reg.find_reg(0x63).value = 0x00; /* (3Dh+3Eh+3Fh)/LPeriod for one-table mode,(21h+1Fh)/LPeriod */ + dev->reg.find_reg(0x64).value = 0x00; /* motor PWM frequency */ + dev->reg.find_reg(0x65).value = 0x00; /* PWM duty cycle for table one motor phase (63 = max) */ + if (dev->model->motor_id == MotorId::MD_5345) { + // PWM duty cycle for table one motor phase (63 = max) + dev->reg.find_reg(0x65).value = 0x02; + } + + for (const auto& reg : dev->gpo.regs) { + dev->reg.set8(reg.address, reg.value); + } + + switch (dev->model->motor_id) { + case MotorId::HP2300: + case MotorId::HP2400: + dev->reg.find_reg(0x6a).value = 0x7f; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6b).value = 0x78; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x7f; + break; + case MotorId::MD_5345: + dev->reg.find_reg(0x6a).value = 0x42; /* table two fast moving step type, PWM duty for table two */ + dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x41; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ + break; + case MotorId::XP200: + dev->reg.find_reg(0x6a).value = 0x7f; /* table two fast moving step type, PWM duty for table two */ + dev->reg.find_reg(0x6b).value = 0x08; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ + break; + case MotorId::HP3670: + dev->reg.find_reg(0x6a).value = 0x41; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6b).value = 0xc8; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x7f; + break; + default: + dev->reg.find_reg(0x6a).value = 0x40; /* table two fast moving step type, PWM duty for table two */ + dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */ + dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ + break; + } + dev->reg.find_reg(0x6c).value = 0x00; /* peroid times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE (one period time) */ +} + + +// Send slope table for motor movement slope_table in machine byte order +static void gl646_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, + int steps) +{ + DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d)=%d .. %d", table_nr, steps, slope_table[0], + slope_table[steps - 1]); + int dpihw; + int start_address; + + dpihw = dev->reg.find_reg(0x05).value >> 6; + + if (dpihw == 0) /* 600 dpi */ + start_address = 0x08000; + else if (dpihw == 1) /* 1200 dpi */ + start_address = 0x10000; + else if (dpihw == 2) /* 2400 dpi */ + start_address = 0x1f800; + else { + throw SaneException("Unexpected dpihw"); + } + + std::vector table(steps * 2); + for (int i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (dev->interface->is_mock()) { + dev->interface->record_slope_table(table_nr, slope_table); + } + dev->interface->write_buffer(0x3c, start_address + table_nr * 0x100, table.data(), steps * 2); +} + +// Set values of Analog Device type frontend +static void gl646_set_ad_fe(Genesys_Device* dev, uint8_t set) +{ + DBG_HELPER(dbg); + int i; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + + dev->frontend = dev->frontend_initial; + + // write them to analog frontend + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); + } + if (set == AFE_SET) + { + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x02 + i, dev->frontend.get_gain(i)); + } + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x05 + i, dev->frontend.get_offset(i)); + } + } + /* + if (set == AFE_POWER_SAVE) + { + dev->interface->write_fe_register(0x00, dev->frontend.reg[0] | 0x04); + } */ +} + +/** set up analog frontend + * set up analog frontend + * @param dev device to set up + * @param set action from AFE_SET, AFE_INIT and AFE_POWERSAVE + * @param dpi resolution of the scan since it affects settings + */ +static void gl646_wm_hp3670(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set, + unsigned dpi) +{ + DBG_HELPER(dbg); + int i; + + switch (set) + { + case AFE_INIT: + dev->interface->write_fe_register(0x04, 0x80); + dev->interface->sleep_ms(200); + dev->interface->write_register(0x50, 0x00); + dev->frontend = dev->frontend_initial; + dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); + dev->interface->write_fe_register(0x02, dev->frontend.regs.get_value(0x02)); + gl646_gpio_output_enable(dev->interface->get_usb_device(), 0x07); + break; + case AFE_POWER_SAVE: + dev->interface->write_fe_register(0x01, 0x06); + dev->interface->write_fe_register(0x06, 0x0f); + return; + break; + default: /* AFE_SET */ + /* mode setup */ + i = dev->frontend.regs.get_value(0x03); + if (dpi > sensor.optical_res / 2) + { + /* fe_reg_0x03 must be 0x12 for 1200 dpi in WOLFSON_HP3670. + * WOLFSON_HP2400 in 1200 dpi mode works well with + * fe_reg_0x03 set to 0x32 or 0x12 but not to 0x02 */ + i = 0x12; + } + dev->interface->write_fe_register(0x03, i); + /* offset and sign (or msb/lsb ?) */ + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); + dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); + } + + // gain + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); + } + } +} + +/** Set values of analog frontend + * @param dev device to set + * @param set action to execute + * @param dpi dpi to setup the AFE + */ +static void gl646_set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set, int dpi) +{ + DBG_HELPER_ARGS(dbg, "%s,%d", set == AFE_INIT ? "init" : + set == AFE_SET ? "set" : + set == AFE_POWER_SAVE ? "powersave" : "huh?", dpi); + int i; + uint8_t val; + + /* Analog Device type frontend */ + uint8_t frontend_type = dev->reg.find_reg(0x04).value & REG_0x04_FESET; + if (frontend_type == 0x02) { + gl646_set_ad_fe(dev, set); + return; + } + + /* Wolfson type frontend */ + if (frontend_type != 0x03) { + throw SaneException("unsupported frontend type %d", frontend_type); + } + + /* per frontend function to keep code clean */ + switch (dev->model->adc_id) + { + case AdcId::WOLFSON_HP3670: + case AdcId::WOLFSON_HP2400: + gl646_wm_hp3670(dev, sensor, set, dpi); + return; + default: + DBG(DBG_proc, "%s(): using old method\n", __func__); + break; + } + + /* initialize analog frontend */ + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + dev->frontend = dev->frontend_initial; + + // reset only done on init + dev->interface->write_fe_register(0x04, 0x80); + + /* enable GPIO for some models */ + if (dev->model->sensor_id == SensorId::CCD_HP2300) { + val = 0x07; + gl646_gpio_output_enable(dev->interface->get_usb_device(), val); + } + return; + } + + // set fontend to power saving mode + if (set == AFE_POWER_SAVE) { + dev->interface->write_fe_register(0x01, 0x02); + return; + } + + /* here starts AFE_SET */ + /* TODO : base this test on cfg reg3 or a CCD family flag to be created */ + /* if (dev->model->ccd_type != SensorId::CCD_HP2300 + && dev->model->ccd_type != SensorId::CCD_HP3670 + && dev->model->ccd_type != SensorId::CCD_HP2400) */ + { + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + dev->interface->write_fe_register(0x02, dev->frontend.regs.get_value(0x02)); + } + + // start with reg3 + dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x03)); + + switch (dev->model->sensor_id) + { + default: + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); + dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); + dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); + } + break; + /* just can't have it to work .... + case SensorId::CCD_HP2300: + case SensorId::CCD_HP2400: + case SensorId::CCD_HP3670: + + dev->interface->write_fe_register(0x23, dev->frontend.get_offset(1)); + dev->interface->write_fe_register(0x28, dev->frontend.get_gain(1)); + break; */ + } + + // end with reg1 + dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); +} + +/** Set values of analog frontend + * this this the public interface, the gl646 as to use one more + * parameter to work effectively, hence the redirection + * @param dev device to set + * @param set action to execute + */ +void CommandSetGl646::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const +{ + gl646_set_fe(dev, sensor, set, dev->settings.yres); +} + +/** + * enters or leaves power saving mode + * limited to AFE for now. + * @param dev scanner's device + * @param enable true to enable power saving, false to leave it + */ +void CommandSetGl646::save_power(Genesys_Device* dev, bool enable) const +{ + DBG_HELPER_ARGS(dbg, "enable = %d", enable); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + if (enable) + { + // gl646_set_fe(dev, sensor, AFE_POWER_SAVE); + } + else + { + gl646_set_fe(dev, sensor, AFE_INIT, 0); + } +} + +void CommandSetGl646::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const +{ + DBG_HELPER_ARGS(dbg, "delay = %d", delay); + Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); + int rate, exposure_time, tgtime, time; + + local_reg.init_reg(0x01, dev->reg.get8(0x01)); // disable fastmode + local_reg.init_reg(0x03, dev->reg.get8(0x03)); // Lamp power control + local_reg.init_reg(0x05, dev->reg.get8(0x05) & ~REG_0x05_BASESEL); // 24 clocks/pixel + local_reg.init_reg(0x38, 0x00); // line period low + local_reg.init_reg(0x39, 0x00); //line period high + local_reg.init_reg(0x6c, 0x00); // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE + + if (!delay) + local_reg.find_reg(0x03).value &= 0xf0; /* disable lampdog and set lamptime = 0 */ + else if (delay < 20) + local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ + else + local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ + + time = delay * 1000 * 60; /* -> msec */ + exposure_time = static_cast((time * 32000.0 / + (24.0 * 64.0 * (local_reg.get8(0x03) & REG_0x03_LAMPTIM) * + 1024.0) + 0.5)); + /* 32000 = system clock, 24 = clocks per pixel */ + rate = (exposure_time + 65536) / 65536; + if (rate > 4) + { + rate = 8; + tgtime = 3; + } + else if (rate > 2) + { + rate = 4; + tgtime = 2; + } + else if (rate > 1) + { + rate = 2; + tgtime = 1; + } + else + { + rate = 1; + tgtime = 0; + } + + local_reg.find_reg(0x6c).value |= tgtime << 6; + exposure_time /= rate; + + if (exposure_time > 65535) + exposure_time = 65535; + + local_reg.find_reg(0x38).value = exposure_time / 256; + local_reg.find_reg(0x39).value = exposure_time & 255; + + dev->interface->write_registers(local_reg); +} + + +/** + * loads document into scanner + * currently only used by XP200 + * bit2 (0x04) of gpio is paper event (document in/out) on XP200 + * HOMESNR is set if no document in front of sensor, the sequence of events is + * paper event -> document is in the sheet feeder + * HOMESNR becomes 0 -> document reach sensor + * HOMESNR becomes 1 ->document left sensor + * paper event -> document is out + */ +void CommandSetGl646::load_document(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + + // FIXME: sequential not really needed in this case + Genesys_Register_Set regs(Genesys_Register_Set::SEQUENTIAL); + unsigned count; + + /* no need to load document is flatbed scanner */ + if (!dev->model->is_sheetfed) { + DBG(DBG_proc, "%s: nothing to load\n", __func__); + DBG(DBG_proc, "%s: end\n", __func__); + return; + } + + auto status = scanner_read_status(*dev); + + // home sensor is set if a document is inserted + if (status.is_at_home) { + /* if no document, waits for a paper event to start loading */ + /* with a 60 seconde minutes timeout */ + count = 0; + std::uint8_t val = 0; + do { + gl646_gpio_read(dev->interface->get_usb_device(), &val); + + DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, val); + if ((val & 0x04) != 0x04) + { + DBG(DBG_warn, "%s: no paper detected\n", __func__); + } + dev->interface->sleep_ms(200); + count++; + } + while (((val & 0x04) != 0x04) && (count < 300)); /* 1 min time out */ + if (count == 300) + { + throw SaneException(SANE_STATUS_NO_DOCS, "timeout waiting for document"); + } + } + + /* set up to fast move before scan then move until document is detected */ + regs.init_reg(0x01, 0x90); + + /* AGOME, 2 slopes motor moving */ + regs.init_reg(0x02, 0x79); + + /* motor feeding steps to 0 */ + regs.init_reg(0x3d, 0); + regs.init_reg(0x3e, 0); + regs.init_reg(0x3f, 0); + + /* 50 fast moving steps */ + regs.init_reg(0x6b, 50); + + /* set GPO */ + regs.init_reg(0x66, 0x30); + + /* stesp NO */ + regs.init_reg(0x21, 4); + regs.init_reg(0x22, 1); + regs.init_reg(0x23, 1); + regs.init_reg(0x24, 4); + + /* generate slope table 2 */ + auto slope_table = create_slope_table(MotorSlope::create_from_steps(6000, 2400, 50), 2400, + StepType::FULL, 1, 4, + get_slope_table_max_size(AsicType::GL646)); + // document loading: + // send regs + // start motor + // wait e1 status to become e0 + gl646_send_slope_table(dev, 1, slope_table.table, slope_table.steps_count); + + dev->interface->write_registers(regs); + + scanner_start_action(*dev, true); + + count = 0; + do + { + status = scanner_read_status(*dev); + dev->interface->sleep_ms(200); + count++; + } while (status.is_motor_enabled && (count < 300)); + + if (count == 300) + { + throw SaneException(SANE_STATUS_JAMMED, "can't load document"); + } + + /* when loading OK, document is here */ + dev->document = true; + + /* set up to idle */ + regs.set8(0x02, 0x71); + regs.set8(0x3f, 1); + regs.set8(0x6b, 8); + dev->interface->write_registers(regs); +} + +/** + * detects end of document and adjust current scan + * to take it into account + * used by sheetfed scanners + */ +void CommandSetGl646::detect_document_end(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + std::uint8_t gpio; + unsigned int bytes_left; + + // test for document presence + scanner_read_print_status(*dev); + + gl646_gpio_read(dev->interface->get_usb_device(), &gpio); + DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); + + /* detect document event. There one event when the document go in, + * then another when it leaves */ + if (dev->document && (gpio & 0x04) && (dev->total_bytes_read > 0)) { + DBG(DBG_info, "%s: no more document\n", __func__); + dev->document = false; + + /* adjust number of bytes to read: + * total_bytes_to_read is the number of byte to send to frontend + * total_bytes_read is the number of bytes sent to frontend + * read_bytes_left is the number of bytes to read from the scanner + */ + DBG(DBG_io, "%s: total_bytes_to_read=%zu\n", __func__, dev->total_bytes_to_read); + DBG(DBG_io, "%s: total_bytes_read =%zu\n", __func__, dev->total_bytes_read); + + // amount of data available from scanner is what to scan + sanei_genesys_read_valid_words(dev, &bytes_left); + + unsigned lines_in_buffer = bytes_left / dev->session.output_line_bytes_raw; + + // we add the number of lines needed to read the last part of the document in + unsigned lines_offset = static_cast( + (dev->model->y_offset * dev->session.params.yres) / MM_PER_INCH); + + unsigned remaining_lines = lines_in_buffer + lines_offset; + + bytes_left = remaining_lines * dev->session.output_line_bytes_raw; + + if (bytes_left < dev->get_pipeline_source().remaining_bytes()) { + dev->get_pipeline_source().set_remaining_bytes(bytes_left); + dev->total_bytes_to_read = dev->total_bytes_read + bytes_left; + } + DBG(DBG_io, "%s: total_bytes_to_read=%zu\n", __func__, dev->total_bytes_to_read); + DBG(DBG_io, "%s: total_bytes_read =%zu\n", __func__, dev->total_bytes_read); + } +} + +/** + * eject document from the feeder + * currently only used by XP200 + * TODO we currently rely on AGOHOME not being set for sheetfed scanners, + * maybe check this flag in eject to let the document being eject automaticaly + */ +void CommandSetGl646::eject_document(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set regs((Genesys_Register_Set::SEQUENTIAL)); + unsigned count; + std::uint8_t gpio; + + /* at the end there will be noe more document */ + dev->document = false; + + // first check for document event + gl646_gpio_read(dev->interface->get_usb_device(), &gpio); + + DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); + + // test status : paper event + HOMESNR -> no more doc ? + auto status = scanner_read_status(*dev); + + // home sensor is set when document is inserted + if (status.is_at_home) { + dev->document = false; + DBG(DBG_info, "%s: no more document to eject\n", __func__); + DBG(DBG_proc, "%s: end\n", __func__); + return; + } + + // there is a document inserted, eject it + dev->interface->write_register(0x01, 0xb0); + + /* wait for motor to stop */ + do { + dev->interface->sleep_ms(200); + status = scanner_read_status(*dev); + } + while (status.is_motor_enabled); + + /* set up to fast move before scan then move until document is detected */ + regs.init_reg(0x01, 0xb0); + + /* AGOME, 2 slopes motor moving , eject 'backward' */ + regs.init_reg(0x02, 0x5d); + + /* motor feeding steps to 119880 */ + regs.init_reg(0x3d, 1); + regs.init_reg(0x3e, 0xd4); + regs.init_reg(0x3f, 0x48); + + /* 60 fast moving steps */ + regs.init_reg(0x6b, 60); + + /* set GPO */ + regs.init_reg(0x66, 0x30); + + /* stesp NO */ + regs.init_reg(0x21, 4); + regs.init_reg(0x22, 1); + regs.init_reg(0x23, 1); + regs.init_reg(0x24, 4); + + /* generate slope table 2 */ + auto slope_table = create_slope_table(MotorSlope::create_from_steps(10000, 1600, 60), 1600, + StepType::FULL, 1, 4, + get_slope_table_max_size(AsicType::GL646)); + // document eject: + // send regs + // start motor + // wait c1 status to become c8 : HOMESNR and ~MOTFLAG + gl646_send_slope_table(dev, 1, slope_table.table, slope_table.steps_count); + + dev->interface->write_registers(regs); + + scanner_start_action(*dev, true); + + /* loop until paper sensor tells paper is out, and till motor is running */ + /* use a 30 timeout */ + count = 0; + do { + status = scanner_read_status(*dev); + + dev->interface->sleep_ms(200); + count++; + } while (!status.is_at_home && (count < 150)); + + // read GPIO on exit + gl646_gpio_read(dev->interface->get_usb_device(), &gpio); + + DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); +} + +// Send the low-level scan command +void CommandSetGl646::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, bool start_motor) const +{ + DBG_HELPER(dbg); + (void) sensor; + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); + + local_reg.init_reg(0x03, reg->get8(0x03)); + local_reg.init_reg(0x01, reg->get8(0x01) | REG_0x01_SCAN); + + if (start_motor) { + local_reg.init_reg(0x0f, 0x01); + } else { + local_reg.init_reg(0x0f, 0x00); // do not start motor yet + } + + dev->interface->write_registers(local_reg); + + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); +} + + +// Send the stop scan command +static void end_scan_impl(Genesys_Device* dev, Genesys_Register_Set* reg, bool check_stop, + bool eject) +{ + DBG_HELPER_ARGS(dbg, "check_stop = %d, eject = %d", check_stop, eject); + + scanner_stop_action_no_move(*dev, *reg); + + unsigned wait_limit_seconds = 30; + + /* for sheetfed scanners, we may have to eject document */ + if (dev->model->is_sheetfed) { + if (eject && dev->document) { + dev->cmd_set->eject_document(dev); + } + wait_limit_seconds = 3; + } + + if (is_testing_mode()) { + return; + } + + dev->interface->sleep_ms(100); + + if (check_stop) { + for (unsigned i = 0; i < wait_limit_seconds * 10; i++) { + if (scanner_is_motor_stopped(*dev)) { + return; + } + + dev->interface->sleep_ms(100); + } + throw SaneException(SANE_STATUS_IO_ERROR, "could not stop motor"); + } +} + +// Send the stop scan command +void CommandSetGl646::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg, + bool check_stop) const +{ + end_scan_impl(dev, reg, check_stop, false); +} + +/** + * parks head + * @param dev scanner's device + * @param wait_until_home true if the function waits until head parked + */ +void CommandSetGl646::move_back_home(Genesys_Device* dev, bool wait_until_home) const +{ + DBG_HELPER_ARGS(dbg, "wait_until_home = %d\n", wait_until_home); + int i; + int loop = 0; + + auto status = scanner_read_status(*dev); + + if (status.is_at_home) { + DBG(DBG_info, "%s: end since already at home\n", __func__); + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + + /* stop motor if needed */ + if (status.is_motor_enabled) { + gl646_stop_motor(dev); + dev->interface->sleep_ms(200); + } + + /* when scanhead is moving then wait until scanhead stops or timeout */ + DBG(DBG_info, "%s: ensuring that motor is off\n", __func__); + for (i = 400; i > 0; i--) { + // do not wait longer than 40 seconds, count down to get i = 0 when busy + + status = scanner_read_status(*dev); + + if (!status.is_motor_enabled && status.is_at_home) { + DBG(DBG_info, "%s: already at home and not moving\n", __func__); + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + if (!status.is_motor_enabled) { + break; + } + + dev->interface->sleep_ms(100); + } + + if (!i) /* the loop counted down to 0, scanner still is busy */ + { + dev->set_head_pos_unknown(); + throw SaneException(SANE_STATUS_DEVICE_BUSY, "motor is still on: device busy"); + } + + // setup for a backward scan of 65535 steps, with no actual data reading + auto resolution = sanei_genesys_get_lowest_dpi(dev); + + const auto& sensor = sanei_genesys_find_sensor(dev, resolution, 3, + dev->model->default_method); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 0; + session.params.starty = 65535; + session.params.pixels = 600; + session.params.requested_pixels = 600; + session.params.lines = 1; + session.params.depth = 8; + session.params.channels = 3; + session.params.scan_method = dev->model->default_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = ColorFilter::RED; + session.params.flags = ScanFlag::USE_XCORRECTION | + ScanFlag::REVERSE; + if (dev->model->default_method == ScanMethod::TRANSPARENCY) { + session.params.flags |= ScanFlag::USE_XPA; + } + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &dev->reg, session); + + /* backward , no actual data scanned TODO more setup flags to avoid this register manipulations ? */ + regs_set_optical_off(dev->model->asic_type, dev->reg); + + // sets frontend + gl646_set_fe(dev, sensor, AFE_SET, resolution); + + /* write scan registers */ + try { + dev->interface->write_registers(dev->reg); + } catch (...) { + DBG(DBG_error, "%s: failed to bulk write registers\n", __func__); + } + + /* registers are restored to an iddl state, give up if no head to park */ + if (dev->model->is_sheetfed) { + DBG(DBG_proc, "%s: end \n", __func__); + return; + } + + // starts scan + { + // this is effectively the same as dev->cmd_set->begin_scan(dev, sensor, &dev->reg, true); + // except that we don't modify the head position calculations + + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set scan_local_reg(Genesys_Register_Set::SEQUENTIAL); + + scan_local_reg.init_reg(0x03, dev->reg.get8(0x03)); + scan_local_reg.init_reg(0x01, dev->reg.get8(0x01) | REG_0x01_SCAN); + scan_local_reg.init_reg(0x0f, 0x01); + + dev->interface->write_registers(scan_local_reg); + } + + if (is_testing_mode()) { + dev->interface->test_checkpoint("move_back_home"); + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + + /* loop until head parked */ + if (wait_until_home) + { + while (loop < 300) /* do not wait longer then 30 seconds */ + { + auto status = scanner_read_status(*dev); + + if (status.is_at_home) { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBG(DBG_proc, "%s: end\n", __func__); + dev->interface->sleep_ms(500); + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + dev->interface->sleep_ms(100); + ++loop; + } + + // when we come here then the scanner needed too much time for this, so we better + // stop the motor + catch_all_exceptions(__func__, [&](){ gl646_stop_motor (dev); }); + catch_all_exceptions(__func__, [&](){ end_scan_impl(dev, &dev->reg, true, false); }); + dev->set_head_pos_unknown(); + throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home"); + } + + + DBG(DBG_info, "%s: scanhead is still moving\n", __func__); +} + +/** + * Automatically set top-left edge of the scan area by scanning an + * area at 300 dpi from very top of scanner + * @param dev device stucture describing the scanner + */ +void CommandSetGl646::search_start_position(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + Genesys_Settings settings; + unsigned int resolution, x, y; + + /* we scan at 300 dpi */ + resolution = get_closest_resolution(dev->model->sensor_id, 300, 1); + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + const auto& sensor = sanei_genesys_find_sensor(dev, resolution, 1, + dev->model->default_method); + + /* fill settings for a gray level scan */ + settings.scan_method = dev->model->default_method; + settings.scan_mode = ScanColorMode::GRAY; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = 600; + settings.requested_pixels = settings.pixels; + settings.lines = dev->model->search_lines; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + // scan the desired area + std::vector data; + simple_scan(dev, sensor, settings, true, true, false, data, "search_start_position"); + + // handle stagger case : reorder gray data and thus loose some lines + auto staggered_lines = dev->session.num_staggered_lines; + if (staggered_lines > 0) { + DBG(DBG_proc, "%s: 'un-staggering'\n", __func__); + for (y = 0; y < settings.lines - staggered_lines; y++) { + /* one point out of 2 is 'unaligned' */ + for (x = 0; x < settings.pixels; x += 2) + { + data[y * settings.pixels + x] = data[(y + staggered_lines) * settings.pixels + x]; + } + } + /* correct line number */ + settings.lines -= staggered_lines; + } + + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_pnm_file("gl646_search_position.pnm", data.data(), settings.depth, 1, + settings.pixels, settings.lines); + } + + // now search reference points on the data + for (auto& sensor_update : + sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) + { + sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, + resolution, settings.pixels, settings.lines); + } +} + +/** + * internally overriden during effective calibration + * sets up register for coarse gain calibration + */ +void CommandSetGl646::init_regs_for_coarse_calibration(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + (void) dev; + (void) sensor; + (void) regs; +} + + +/** + * init registers for shading calibration + * we assume that scanner's head is on an area suiting shading calibration. + * We scan a full scan width area by the shading line number for the device + * at either at full sensor's resolution or half depending upon ccd_size_divisor + * @param dev scanner's device + */ +void CommandSetGl646::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + (void) regs; + Genesys_Settings settings; + int cksel = 1; + + /* fill settings for scan : always a color scan */ + int channels = 3; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->settings.xres, channels, + dev->settings.scan_method); + + unsigned ccd_size_divisor = calib_sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); + + settings.scan_method = dev->settings.scan_method; + settings.scan_mode = dev->settings.scan_mode; + if (!dev->model->is_cis) { + // FIXME: always a color scan, but why don't we set scan_mode to COLOR_SINGLE_PASS always? + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + } + settings.xres = sensor.optical_res / ccd_size_divisor; + cksel = get_cksel(dev->model->sensor_id, dev->settings.xres, channels); + settings.xres = settings.xres / cksel; + settings.yres = settings.xres; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = (calib_sensor.sensor_pixels * settings.xres) / calib_sensor.optical_res; + settings.requested_pixels = settings.pixels; + dev->calib_lines = dev->model->shading_lines; + settings.lines = dev->calib_lines * (3 - ccd_size_divisor); + settings.depth = 16; + settings.color_filter = dev->settings.color_filter; + + settings.disable_interpolation = dev->settings.disable_interpolation; + settings.threshold = dev->settings.threshold; + + // we don't want top offset, but we need right margin to be the same than the one for the final + // scan + setup_for_scan(dev, calib_sensor, &dev->reg, settings, true, false, false, false); + + /* used when sending shading calibration data */ + dev->calib_pixels = settings.pixels; + dev->calib_channels = dev->session.params.channels; + if (!dev->model->is_cis) { + dev->calib_channels = 3; + } + + /* no shading */ + dev->reg.find_reg(0x01).value &= ~REG_0x01_DVDSET; + dev->reg.find_reg(0x02).value |= REG_0x02_ACDCDIS; /* ease backtracking */ + dev->reg.find_reg(0x02).value &= ~(REG_0x02_FASTFED | REG_0x02_AGOHOME); + dev->reg.find_reg(0x05).value &= ~REG_0x05_GMMENB; + sanei_genesys_set_motor_power(dev->reg, false); + + /* TODO another flag to setup regs ? */ + /* enforce needed LINCNT, getting rid of extra lines for color reordering */ + if (!dev->model->is_cis) { + dev->reg.set24(REG_LINCNT, dev->calib_lines); + } else { + dev->reg.set24(REG_LINCNT, dev->calib_lines * 3); + } + + /* copy reg to calib_reg */ + dev->calib_reg = dev->reg; + + DBG(DBG_info, "%s:\n\tdev->settings.xres=%d\n\tdev->settings.yres=%d\n", __func__, + dev->settings.xres, dev->settings.yres); +} + +bool CommandSetGl646::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const +{ + return dev->is_head_pos_known(ScanHeadId::PRIMARY) && + dev->head_pos(ScanHeadId::PRIMARY) && + dev->settings.scan_method == ScanMethod::FLATBED; +} + +/** + * set up registers for the actual scan. The scan's parameters are given + * through the device settings. It allocates the scan buffers. + */ +void CommandSetGl646::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + + debug_dump(DBG_info, dev->settings); + + ScanSession session = calculate_scan_session(dev, sensor, dev->settings); + + init_regs_for_scan_session(dev, sensor, &dev->reg, session); + + /* gamma is only enabled at final scan time */ + if (dev->settings.depth < 16) { + dev->reg.find_reg(0x05).value |= REG_0x05_GMMENB; + } +} + +/** + * set up registers for the actual scan. The scan's parameters are given + * through the device settings. It allocates the scan buffers. + * @param dev scanner's device + * @param regs registers to set up + * @param settings settings of scan + * @param split true if move to scan area is split from scan, false is + * scan first moves to area + * @param xcorrection take x geometry correction into account (fixed and detected offsets) + * @param ycorrection take y geometry correction into account + */ +static void setup_for_scan(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set*regs, + Genesys_Settings settings, + bool split, + bool xcorrection, + bool ycorrection, + bool reverse) +{ + DBG_HELPER(dbg); + + debug_dump(DBG_info, dev->settings); + + // compute distance to move + float move = 0; + // XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */ + if (!split) { + if (!dev->model->is_sheetfed) { + if (ycorrection) { + move = static_cast(dev->model->y_offset); + } + + // add tl_y to base movement + } + move += static_cast(settings.tl_y); + + if (move < 0) { + DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move); + move = 0; + } + } + move = static_cast((move * dev->motor.optical_ydpi) / MM_PER_INCH); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + float start = static_cast(settings.tl_x); + if (xcorrection) { + if (settings.scan_method == ScanMethod::FLATBED) { + start += static_cast(dev->model->x_offset); + } else { + start += static_cast(dev->model->x_offset_ta); + } + } + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = settings.xres; + session.params.yres = settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = settings.pixels; + session.params.requested_pixels = settings.requested_pixels; + session.params.lines = settings.lines; + session.params.depth = settings.depth; + session.params.channels = settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = settings.scan_mode; + session.params.color_filter = settings.color_filter; + session.params.flags = ScanFlag::NONE; + if (settings.scan_method == ScanMethod::TRANSPARENCY) { + session.params.flags |= ScanFlag::USE_XPA; + } + if (xcorrection) { + session.params.flags |= ScanFlag::USE_XCORRECTION; + } + if (reverse) { + session.params.flags |= ScanFlag::REVERSE; + } + compute_session(dev, session, sensor); + + dev->cmd_set->init_regs_for_scan_session(dev, sensor, regs, session); +} + +/** + * this function send gamma table to ASIC + */ +void CommandSetGl646::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + int size; + int address; + int bits; + + /* gamma table size */ + if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) + { + size = 16384; + bits = 14; + } + else + { + size = 4096; + bits = 12; + } + + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3); + + sanei_genesys_generate_gamma_buffer(dev, sensor, bits, size-1, size, gamma.data()); + + /* table address */ + switch (dev->reg.find_reg(0x05).value >> 6) + { + case 0: /* 600 dpi */ + address = 0x09000; + break; + case 1: /* 1200 dpi */ + address = 0x11000; + break; + case 2: /* 2400 dpi */ + address = 0x20000; + break; + default: + throw SaneException("invalid dpi"); + } + + dev->interface->write_buffer(0x3c, address, gamma.data(), size * 2 * 3); +} + +/** @brief this function does the led calibration. + * this function does the led calibration by scanning one line of the calibration + * area below scanner's top on white strip. The scope of this function is + * currently limited to the XP200 + */ +SensorExposure CommandSetGl646::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + (void) regs; + int total_size; + unsigned int i, j; + int val; + int avg[3], avga, avge; + int turn; + uint16_t expr, expg, expb; + Genesys_Settings settings; + SANE_Int resolution; + + unsigned channels = dev->settings.get_channels(); + + /* get led calibration resolution */ + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) + { + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + } + else + { + settings.scan_mode = ScanColorMode::GRAY; + } + resolution = get_closest_resolution(dev->model->sensor_id, sensor.optical_res, channels); + + /* offset calibration is always done in color mode */ + settings.scan_method = dev->model->default_method; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = (sensor.sensor_pixels * resolution) / sensor.optical_res; + settings.requested_pixels = settings.pixels; + settings.lines = 1; + settings.depth = 16; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + /* colors * bytes_per_color * scan lines */ + total_size = settings.pixels * channels * 2 * 1; + + std::vector line(total_size); + +/* + we try to get equal bright leds here: + + loop: + average per color + adjust exposure times + */ + expr = sensor.exposure.red; + expg = sensor.exposure.green; + expb = sensor.exposure.blue; + + turn = 0; + + auto calib_sensor = sensor; + + bool acceptable = false; + do { + calib_sensor.exposure.red = expr; + calib_sensor.exposure.green = expg; + calib_sensor.exposure.blue = expb; + + DBG(DBG_info, "%s: starting first line reading\n", __func__); + + simple_scan(dev, calib_sensor, settings, false, true, false, line, "led_calibration"); + + if (is_testing_mode()) { + return calib_sensor.exposure; + } + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl646_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, settings.pixels, 1); + } + + acceptable = true; + + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < settings.pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * settings.pixels + 1] * 256 + + line[i * 2 + j * 2 * settings.pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= settings.pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + acceptable = true; + + if (!acceptable) + { + avga = (avg[0] + avg[1] + avg[2]) / 3; + expr = (expr * avga) / avg[0]; + expg = (expg * avga) / avg[1]; + expb = (expb * avga) / avg[2]; + + /* keep exposure time in a working window */ + avge = (expr + expg + expb) / 3; + if (avge > 0x2000) + { + expr = (expr * 0x2000) / avge; + expg = (expg * 0x2000) / avge; + expb = (expb * 0x2000) / avge; + } + if (avge < 0x400) + { + expr = (expr * 0x400) / avge; + expg = (expg * 0x400) / avge; + expb = (expb * 0x400) / avge; + } + } + + turn++; + + } + while (!acceptable && turn < 100); + + DBG(DBG_info,"%s: acceptable exposure: 0x%04x,0x%04x,0x%04x\n", __func__, expr, expg, expb); + // BUG: we don't store the result of the last iteration to the sensor + return calib_sensor.exposure; +} + +/** + * average dark pixels of a scan + */ +static int +dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black) +{ + unsigned int i, j, k, average, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average value on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + for (i = 0; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + average = 0; + for (i = 0; i < channels; i++) + average += avg[i]; + average /= channels; + DBG(DBG_info, "%s: average = %d\n", __func__, average); + return average; +} + + +/** @brief calibration for AD frontend devices + * we do simple scan until all black_pixels are higher than 0, + * raising offset at each turn. + */ +static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + (void) sensor; + + unsigned int channels; + int pass = 0; + SANE_Int resolution; + Genesys_Settings settings; + unsigned int x, y, adr, min; + unsigned int bottom, black_pixels; + + channels = 3; + resolution = get_closest_resolution(dev->model->sensor_id, sensor.optical_res, channels); + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, ScanMethod::FLATBED); + black_pixels = (calib_sensor.black_pixels * resolution) / calib_sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + settings.scan_method = dev->model->default_method; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res; + settings.requested_pixels = settings.pixels; + settings.lines = CALIBRATION_LINES; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + /* scan first line of data with no gain */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + std::vector line; + + /* scan with no move */ + bottom = 1; + do + { + pass++; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + simple_scan(dev, calib_sensor, settings, false, true, false, line, + "ad_fe_offset_calibration"); + + if (is_testing_mode()) { + return; + } + + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + std::snprintf(title, 30, "gl646_offset%03d.pnm", static_cast(bottom)); + sanei_genesys_write_pnm_file (title, line.data(), 8, channels, + settings.pixels, settings.lines); + } + + min = 0; + for (y = 0; y < settings.lines; y++) + { + for (x = 0; x < black_pixels; x++) + { + adr = (x + y * settings.pixels) * channels; + if (line[adr] > min) + min = line[adr]; + if (line[adr + 1] > min) + min = line[adr + 1]; + if (line[adr + 2] > min) + min = line[adr + 2]; + } + } + + DBG(DBG_io2, "%s: pass=%d, min=%d\n", __func__, pass, min); + bottom++; + } + while (pass < 128 && min == 0); + if (pass == 128) + { + throw SaneException(SANE_STATUS_INVAL, "failed to find correct offset"); + } + + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); +} + +/** + * This function does the offset calibration by scanning one line of the calibration + * area below scanner's top. There is a black margin and the remaining is white. + * genesys_search_start() must have been called so that the offsets and margins + * are already known. + * @param dev scanner's device +*/ +void CommandSetGl646::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + (void) regs; + + unsigned int channels; + int pass = 0, avg; + Genesys_Settings settings; + int topavg, bottomavg; + int top, bottom, black_pixels; + + if (dev->model->adc_id == AdcId::AD_XP200) { + ad_fe_offset_calibration(dev, sensor); + return; + } + + DBG(DBG_proc, "%s: start\n", __func__); // TODO + + /* setup for a RGB scan, one full sensor's width line */ + /* resolution is the one from the final scan */ + channels = 3; + int resolution = get_closest_resolution(dev->model->sensor_id, dev->settings.xres, channels); + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, ScanMethod::FLATBED); + black_pixels = (calib_sensor.black_pixels * resolution) / calib_sensor.optical_res; + + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + settings.scan_method = dev->model->default_method; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res; + settings.requested_pixels = settings.pixels; + settings.lines = CALIBRATION_LINES; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + /* scan first line of data with no gain, but with offset from + * last calibration */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* scan with no move */ + bottom = 90; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + + std::vector first_line, second_line; + + simple_scan(dev, calib_sensor, settings, false, true, false, first_line, + "offset_first_line"); + + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + std::snprintf(title, 30, "gl646_offset%03d.pnm", bottom); + sanei_genesys_write_pnm_file(title, first_line.data(), 8, channels, + settings.pixels, settings.lines); + } + bottomavg = dark_average(first_line.data(), settings.pixels, settings.lines, channels, + black_pixels); + DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); + + /* now top value */ + top = 231; + dev->frontend.set_offset(0, top); + dev->frontend.set_offset(1, top); + dev->frontend.set_offset(2, top); + simple_scan(dev, calib_sensor, settings, false, true, false, second_line, + "offset_second_line"); + + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + std::snprintf(title, 30, "gl646_offset%03d.pnm", top); + sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels, + settings.pixels, settings.lines); + } + topavg = dark_average(second_line.data(), settings.pixels, settings.lines, channels, + black_pixels); + DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); + + if (is_testing_mode()) { + return; + } + + /* loop until acceptable level */ + while ((pass < 32) && (top - bottom > 1)) + { + pass++; + + /* settings for new scan */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + // scan with no move + simple_scan(dev, calib_sensor, settings, false, true, false, second_line, + "offset_calibration_i"); + + if (DBG_LEVEL >= DBG_data) + { + char title[30]; + std::snprintf(title, 30, "gl646_offset%03d.pnm", dev->frontend.get_offset(1)); + sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels, + settings.pixels, settings.lines); + } + + avg = + dark_average (second_line.data(), settings.pixels, settings.lines, channels, + black_pixels); + DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); + + /* compute new boundaries */ + if (topavg == avg) + { + topavg = avg; + top = dev->frontend.get_offset(1); + } + else + { + bottomavg = avg; + bottom = dev->frontend.get_offset(1); + } + } + + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); +} + +/** @brief gain calibration for Analog Device frontends + * Alternative coarse gain calibration + */ +static void ad_fe_coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) +{ + DBG_HELPER(dbg); + (void) sensor; + (void) regs; + + unsigned int i, channels, val; + unsigned int size, count, resolution, pass; + float average; + Genesys_Settings settings; + char title[32]; + + /* setup for a RGB scan, one full sensor's width line */ + /* resolution is the one from the final scan */ + channels = 3; + resolution = get_closest_resolution(dev->model->sensor_id, dpi, channels); + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, ScanMethod::FLATBED); + + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + + settings.scan_method = dev->model->default_method; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res; + settings.requested_pixels = settings.pixels; + settings.lines = CALIBRATION_LINES; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + size = channels * settings.pixels * settings.lines; + + /* start gain value */ + dev->frontend.set_gain(0, 1); + dev->frontend.set_gain(1, 1); + dev->frontend.set_gain(2, 1); + + average = 0; + pass = 0; + + std::vector line; + + // loop until each channel raises to acceptable level + while ((average < calib_sensor.gain_white_ref) && (pass < 30)) { + // scan with no move + simple_scan(dev, calib_sensor, settings, false, true, false, line, + "ad_fe_coarse_gain_calibration"); + + /* log scanning data */ + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl646_alternative_gain%02d.pnm", pass); + sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels, + settings.lines); + } + pass++; + + /* computes white average */ + average = 0; + count = 0; + for (i = 0; i < size; i++) + { + val = line[i]; + average += val; + count++; + } + average = average / count; + + uint8_t gain0 = dev->frontend.get_gain(0); + // adjusts gain for the channel + if (average < calib_sensor.gain_white_ref) { + gain0 += 1; + } + + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + + DBG(DBG_proc, "%s: average = %.2f, gain = %d\n", __func__, average, gain0); + } + + DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2)); +} + +/** + * Alternative coarse gain calibration + * this on uses the settings from offset_calibration. First scan moves so + * we can go to calibration area for XPA. + * @param dev device for scan + * @param dpi resolutnio to calibrate at + */ +void CommandSetGl646::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const +{ + DBG_HELPER(dbg); + (void) dpi; + + unsigned int i, j, k, channels, val, maximum, idx; + unsigned int count, resolution, pass; + float average[3]; + Genesys_Settings settings; + char title[32]; + + if (dev->model->sensor_id == SensorId::CIS_XP200) { + return ad_fe_coarse_gain_calibration(dev, sensor, regs, sensor.optical_res); + } + + /* setup for a RGB scan, one full sensor's width line */ + /* resolution is the one from the final scan */ + channels = 3; + + /* we are searching a sensor resolution */ + resolution = get_closest_resolution(dev->model->sensor_id, dev->settings.xres, channels); + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + ScanMethod::FLATBED); + + settings.scan_method = dev->settings.scan_method; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_y = 0; + if (settings.scan_method == ScanMethod::FLATBED) + { + settings.tl_x = 0; + settings.pixels = (calib_sensor.sensor_pixels * resolution) / calib_sensor.optical_res; + } + else + { + settings.tl_x = dev->model->x_offset_ta; + settings.pixels = static_cast((dev->model->x_size_ta * resolution) / MM_PER_INCH); + } + settings.requested_pixels = settings.pixels; + settings.lines = CALIBRATION_LINES; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + /* start gain value */ + dev->frontend.set_gain(0, 1); + dev->frontend.set_gain(1, 1); + dev->frontend.set_gain(2, 1); + + if (channels > 1) + { + average[0] = 0; + average[1] = 0; + average[2] = 0; + idx = 0; + } + else + { + average[0] = 255; + average[1] = 255; + average[2] = 255; + switch (dev->settings.color_filter) { + case ColorFilter::RED: idx = 0; break; + case ColorFilter::GREEN: idx = 1; break; + case ColorFilter::BLUE: idx = 2; break; + default: idx = 0; break; // should not happen + } + average[idx] = 0; + } + pass = 0; + + std::vector line; + + /* loop until each channel raises to acceptable level */ + while (((average[0] < calib_sensor.gain_white_ref) || + (average[1] < calib_sensor.gain_white_ref) || + (average[2] < calib_sensor.gain_white_ref)) && (pass < 30)) + { + // scan with no move + simple_scan(dev, calib_sensor, settings, false, true, false, line, + "coarse_gain_calibration"); + + /* log scanning data */ + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl646_gain%02d.pnm", pass); + sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels, + settings.lines); + } + pass++; + + /* average high level for each channel and compute gain + to reach the target code + we only use the central half of the CCD data */ + for (k = idx; k < idx + channels; k++) + { + /* we find the maximum white value, so we can deduce a threshold + to average white values */ + maximum = 0; + for (i = 0; i < settings.lines; i++) + { + for (j = 0; j < settings.pixels; j++) + { + val = line[i * channels * settings.pixels + j + k]; + if (val > maximum) + maximum = val; + } + } + + /* threshold */ + maximum = static_cast(maximum * 0.9); + + /* computes white average */ + average[k] = 0; + count = 0; + for (i = 0; i < settings.lines; i++) + { + for (j = 0; j < settings.pixels; j++) + { + /* averaging only white points allow us not to care about dark margins */ + val = line[i * channels * settings.pixels + j + k]; + if (val > maximum) + { + average[k] += val; + count++; + } + } + } + average[k] = average[k] / count; + + /* adjusts gain for the channel */ + if (average[k] < calib_sensor.gain_white_ref) + dev->frontend.set_gain(k, dev->frontend.get_gain(k) + 1); + + DBG(DBG_proc, "%s: channel %d, average = %.2f, gain = %d\n", __func__, k, average[k], + dev->frontend.get_gain(k)); + } + } + + if (channels < 3) { + dev->frontend.set_gain(1, dev->frontend.get_gain(0)); + dev->frontend.set_gain(2, dev->frontend.get_gain(0)); + } + + DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2)); +} + +/** + * sets up the scanner's register for warming up. We scan 2 lines without moving. + * + */ +void CommandSetGl646::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* local_reg, int* channels, + int* total_size) const +{ + DBG_HELPER(dbg); + (void) sensor; + + Genesys_Settings settings; + int resolution, lines; + + dev->frontend = dev->frontend_initial; + + resolution = get_closest_resolution(dev->model->sensor_id, 300, 1); + + const auto& local_sensor = sanei_genesys_find_sensor(dev, resolution, 1, + dev->settings.scan_method); + + /* set up for a half width 2 lines gray scan without moving */ + settings.scan_method = dev->model->default_method; + settings.scan_mode = ScanColorMode::GRAY; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = (local_sensor.sensor_pixels * resolution) / local_sensor.optical_res; + settings.requested_pixels = settings.pixels; + settings.lines = 2; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + // setup for scan + setup_for_scan(dev, local_sensor, &dev->reg, settings, true, false, false, false); + + /* we are not going to move, so clear these bits */ + dev->reg.find_reg(0x02).value &= ~(REG_0x02_FASTFED | REG_0x02_AGOHOME); + + /* don't enable any correction for this scan */ + dev->reg.find_reg(0x01).value &= ~REG_0x01_DVDSET; + + /* copy to local_reg */ + *local_reg = dev->reg; + + /* turn off motor during this scan */ + sanei_genesys_set_motor_power(*local_reg, false); + + /* returned value to higher level warmup function */ + *channels = 1; + lines = local_reg->get24(REG_LINCNT) + 1; + *total_size = lines * settings.pixels; + + // now registers are ok, write them to scanner + gl646_set_fe(dev, local_sensor, AFE_SET, settings.xres); + dev->interface->write_registers(*local_reg); +} + + +/* + * this function moves head without scanning, forward, then backward + * so that the head goes to park position. + * as a by-product, also check for lock + */ +static void gl646_repark_head(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + Genesys_Settings settings; + unsigned int expected, steps; + + settings.scan_method = dev->model->default_method; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = get_closest_resolution(dev->model->sensor_id, 75, 1); + settings.yres = settings.xres; + settings.tl_x = 0; + settings.tl_y = 5; + settings.pixels = 600; + settings.requested_pixels = settings.pixels; + settings.lines = 4; + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres, 3, + dev->model->default_method); + + setup_for_scan(dev, sensor, &dev->reg, settings, false, false, false, false); + + /* TODO seems wrong ... no effective scan */ + regs_set_optical_off(dev->model->asic_type, dev->reg); + + dev->interface->write_registers(dev->reg); + + // start scan + dev->cmd_set->begin_scan(dev, sensor, &dev->reg, true); + + expected = dev->reg.get24(REG_FEEDL); + do + { + dev->interface->sleep_ms(100); + sanei_genesys_read_feed_steps (dev, &steps); + } + while (steps < expected); + + // toggle motor flag, put an huge step number and redo move backward + dev->cmd_set->move_back_home(dev, 1); +} + +/* * + * initialize ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + * @param dev device description of the scanner to initailize + */ +void CommandSetGl646::init(Genesys_Device* dev) const +{ + DBG_INIT(); + DBG_HELPER(dbg); + + uint8_t val = 0; + uint32_t addr = 0xdead; + size_t len; + + // to detect real power up condition, we write to REG_0x41 with pwrbit set, then read it back. + // When scanner is cold (just replugged) PWRBIT will be set in the returned value + auto status = scanner_read_status(*dev); + if (status.is_replugged) { + DBG(DBG_info, "%s: device is cold\n", __func__); + } else { + DBG(DBG_info, "%s: device is hot\n", __func__); + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + /* if scanning session hasn't been initialized, set it up */ + if (!dev->already_initialized) + { + dev->dark_average_data.clear(); + dev->white_average_data.clear(); + + dev->settings.color_filter = ColorFilter::GREEN; + + /* Set default values for registers */ + gl646_init_regs (dev); + + // Init shading data + sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels); + + /* initial calibration reg values */ + dev->calib_reg = dev->reg; + } + + // execute physical unit init only if cold + if (status.is_replugged) + { + DBG(DBG_info, "%s: device is cold\n", __func__); + + val = 0x04; + dev->interface->get_usb_device().control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, + VALUE_INIT, INDEX, 1, &val); + + // ASIC reset + dev->interface->write_register(0x0e, 0x00); + dev->interface->sleep_ms(100); + + // Write initial registers + dev->interface->write_registers(dev->reg); + + // send gamma tables if needed + dev->cmd_set->send_gamma_table(dev, sensor); + + // Set powersaving(default = 15 minutes) + dev->cmd_set->set_powersaving(dev, 15); + } + + // Set analog frontend + gl646_set_fe(dev, sensor, AFE_INIT, 0); + + /* GPO enabling for XP200 */ + if (dev->model->sensor_id == SensorId::CIS_XP200) { + dev->interface->write_register(0x68, dev->gpo.regs.get_value(0x68)); + dev->interface->write_register(0x69, dev->gpo.regs.get_value(0x69)); + + // enable GPIO + gl646_gpio_output_enable(dev->interface->get_usb_device(), 6); + + // writes 0 to GPIO + gl646_gpio_write(dev->interface->get_usb_device(), 0); + + // clear GPIO enable + gl646_gpio_output_enable(dev->interface->get_usb_device(), 0); + + dev->interface->write_register(0x66, 0x10); + dev->interface->write_register(0x66, 0x00); + dev->interface->write_register(0x66, 0x10); + } + + /* MD6471/G2410 and XP200 read/write data from an undocumented memory area which + * is after the second slope table */ + if (dev->model->gpio_id != GpioId::HP3670 && + dev->model->gpio_id != GpioId::HP2400) + { + switch (sensor.optical_res) + { + case 600: + addr = 0x08200; + break; + case 1200: + addr = 0x10200; + break; + case 2400: + addr = 0x1fa00; + break; + } + sanei_genesys_set_buffer_address(dev, addr); + + sanei_usb_set_timeout (2 * 1000); + len = 6; + // for some reason, read fails here for MD6471, HP2300 and XP200 one time out of + // 2 scanimage launches + try { + dev->interface->bulk_read_data(0x45, dev->control, len); + } catch (...) { + dev->interface->bulk_read_data(0x45, dev->control, len); + } + DBG(DBG_info, "%s: control read=0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, + dev->control[0], dev->control[1], dev->control[2], dev->control[3], dev->control[4], + dev->control[5]); + sanei_usb_set_timeout (30 * 1000); + } + else + /* HP2400 and HP3670 case */ + { + dev->control[0] = 0x00; + dev->control[1] = 0x00; + dev->control[2] = 0x01; + dev->control[3] = 0x00; + dev->control[4] = 0x00; + dev->control[5] = 0x00; + } + + /* ensure head is correctly parked, and check lock */ + if (!dev->model->is_sheetfed) { + if (dev->model->flags & GENESYS_FLAG_REPARK) + { + // FIXME: if repark fails, we should print an error message that the scanner is locked and + // the user should unlock the lock. We should also rethrow with SANE_STATUS_JAMMED + gl646_repark_head(dev); + } + else + { + move_back_home(dev, true); + } + } + + /* here session and device are initialized */ + dev->already_initialized = true; +} + +void CommandSetGl646::move_to_ta(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + + simple_move(dev, static_cast(dev->model->y_offset_sensor_to_ta)); +} + + +/** + * Does a simple scan: ie no line reordering and avanced data buffering and + * shading correction. Memory for data is allocated in this function + * and must be freed by caller. + * @param dev device of the scanner + * @param settings parameters of the scan + * @param move true if moving during scan + * @param forward true if moving forward during scan + * @param shading true to enable shading correction + * @param data pointer for the data + */ +static void simple_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Settings settings, bool move, bool forward, + bool shading, std::vector& data, + const char* scan_identifier) +{ + DBG_HELPER_ARGS(dbg, "move=%d, forward=%d, shading=%d", move, forward, shading); + unsigned int size, lines, x, y, bpp; + bool split; + + /* round up to multiple of 3 in case of CIS scanner */ + if (dev->model->is_cis) { + settings.lines = ((settings.lines + 2) / 3) * 3; + } + + /* setup for move then scan */ + split = !(move && settings.tl_y > 0); + setup_for_scan(dev, sensor, &dev->reg, settings, split, false, false, !forward); + + /* allocate memory fo scan : LINCNT may have been adjusted for CCD reordering */ + if (dev->model->is_cis) { + lines = dev->reg.get24(REG_LINCNT) / 3; + } else { + lines = dev->reg.get24(REG_LINCNT) + 1; + } + size = lines * settings.pixels; + if (settings.depth == 16) { + bpp = 2; + } else { + bpp = 1; + } + size *= bpp * settings.get_channels(); + data.clear(); + data.resize(size); + + DBG(DBG_io, "%s: allocated %d bytes of memory for %d lines\n", __func__, size, lines); + + /* put back real line number in settings */ + settings.lines = lines; + + // initialize frontend + gl646_set_fe(dev, sensor, AFE_SET, settings.xres); + + /* no shading correction and not watch dog for simple scan */ + dev->reg.find_reg(0x01).value &= ~(REG_0x01_DVDSET | REG_0x01_DOGENB); + if (shading) { + dev->reg.find_reg(0x01).value |= REG_0x01_DVDSET; + } + + /* enable gamma table for the scan */ + dev->reg.find_reg(0x05).value |= REG_0x05_GMMENB; + + /* one table movement for simple scan */ + dev->reg.find_reg(0x02).value &= ~REG_0x02_FASTFED; + + if (!move) { + sanei_genesys_set_motor_power(dev->reg, false); + + /* no automatic go home if no movement */ + dev->reg.find_reg(0x02).value &= ~REG_0x02_AGOHOME; + } + + /* no automatic go home when using XPA */ + if (settings.scan_method == ScanMethod::TRANSPARENCY) { + dev->reg.find_reg(0x02).value &= ~REG_0x02_AGOHOME; + } + + // write scan registers + dev->interface->write_registers(dev->reg); + + // starts scan + dev->cmd_set->begin_scan(dev, sensor, &dev->reg, move); + + if (is_testing_mode()) { + dev->interface->test_checkpoint(scan_identifier); + return; + } + + wait_until_buffer_non_empty(dev, true); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + /* in case of CIS scanner, we must reorder data */ + if (dev->model->is_cis && settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) { + /* alloc one line sized working buffer */ + std::vector buffer(settings.pixels * 3 * bpp); + + /* reorder one line of data and put it back to buffer */ + if (bpp == 1) + { + for (y = 0; y < lines; y++) + { + /* reorder line */ + for (x = 0; x < settings.pixels; x++) + { + buffer[x * 3] = data[y * settings.pixels * 3 + x]; + buffer[x * 3 + 1] = data[y * settings.pixels * 3 + settings.pixels + x]; + buffer[x * 3 + 2] = data[y * settings.pixels * 3 + 2 * settings.pixels + x]; + } + /* copy line back */ + memcpy (data.data() + settings.pixels * 3 * y, buffer.data(), + settings.pixels * 3); + } + } + else + { + for (y = 0; y < lines; y++) + { + /* reorder line */ + for (x = 0; x < settings.pixels; x++) + { + buffer[x * 6] = data[y * settings.pixels * 6 + x * 2]; + buffer[x * 6 + 1] = data[y * settings.pixels * 6 + x * 2 + 1]; + buffer[x * 6 + 2] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2]; + buffer[x * 6 + 3] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2 + 1]; + buffer[x * 6 + 4] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2]; + buffer[x * 6 + 5] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2 + 1]; + } + /* copy line back */ + memcpy (data.data() + settings.pixels * 6 * y, buffer.data(), + settings.pixels * 6); + } + } + } + + // end scan , waiting the motor to stop if needed (if moving), but without ejecting doc + end_scan_impl(dev, &dev->reg, true, false); +} + +/** + * Does a simple move of the given distance by doing a scan at lowest resolution + * shading correction. Memory for data is allocated in this function + * and must be freed by caller. + * @param dev device of the scanner + * @param distance distance to move in MM + */ +static void simple_move(Genesys_Device* dev, SANE_Int distance) +{ + DBG_HELPER_ARGS(dbg, "%d mm", distance); + Genesys_Settings settings; + + unsigned resolution = sanei_genesys_get_lowest_dpi(dev); + + const auto& sensor = sanei_genesys_find_sensor(dev, resolution, 3, dev->model->default_method); + + /* TODO give a no AGOHOME flag */ + settings.scan_method = dev->model->default_method; + settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + settings.xres = resolution; + settings.yres = resolution; + settings.tl_y = 0; + settings.tl_x = 0; + settings.pixels = (sensor.sensor_pixels * settings.xres) / sensor.optical_res; + settings.requested_pixels = settings.pixels; + settings.lines = static_cast((distance * settings.xres) / MM_PER_INCH); + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + std::vector data; + simple_scan(dev, sensor, settings, true, true, false, data, "simple_move"); +} + +/** + * update the status of the required sensor in the scanner session + * the button fileds are used to make events 'sticky' + */ +void CommandSetGl646::update_hardware_sensors(Genesys_Scanner* session) const +{ + DBG_HELPER(dbg); + Genesys_Device *dev = session->dev; + uint8_t value; + + // do what is needed to get a new set of events, but try to not loose any of them. + gl646_gpio_read(dev->interface->get_usb_device(), &value); + DBG(DBG_io, "%s: GPIO=0x%02x\n", __func__, value); + + // scan button + if (dev->model->buttons & GENESYS_HAS_SCAN_SW) { + switch (dev->model->gpio_id) { + case GpioId::XP200: + session->buttons[BUTTON_SCAN_SW].write((value & 0x02) != 0); + break; + case GpioId::MD_5345: + session->buttons[BUTTON_SCAN_SW].write(value == 0x16); + break; + case GpioId::HP2300: + session->buttons[BUTTON_SCAN_SW].write(value == 0x6c); + break; + case GpioId::HP3670: + case GpioId::HP2400: + session->buttons[BUTTON_SCAN_SW].write((value & 0x20) == 0); + break; + default: + throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); + } + } + + // email button + if (dev->model->buttons & GENESYS_HAS_EMAIL_SW) { + switch (dev->model->gpio_id) { + case GpioId::MD_5345: + session->buttons[BUTTON_EMAIL_SW].write(value == 0x12); + break; + case GpioId::HP3670: + case GpioId::HP2400: + session->buttons[BUTTON_EMAIL_SW].write((value & 0x08) == 0); + break; + default: + throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); + } + } + + // copy button + if (dev->model->buttons & GENESYS_HAS_COPY_SW) { + switch (dev->model->gpio_id) { + case GpioId::MD_5345: + session->buttons[BUTTON_COPY_SW].write(value == 0x11); + break; + case GpioId::HP2300: + session->buttons[BUTTON_COPY_SW].write(value == 0x5c); + break; + case GpioId::HP3670: + case GpioId::HP2400: + session->buttons[BUTTON_COPY_SW].write((value & 0x10) == 0); + break; + default: + throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); + } + } + + // power button + if (dev->model->buttons & GENESYS_HAS_POWER_SW) { + switch (dev->model->gpio_id) { + case GpioId::MD_5345: + session->buttons[BUTTON_POWER_SW].write(value == 0x14); + break; + default: + throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); + } + } + + // ocr button + if (dev->model->buttons & GENESYS_HAS_OCR_SW) { + switch (dev->model->gpio_id) { + case GpioId::MD_5345: + session->buttons[BUTTON_OCR_SW].write(value == 0x13); + break; + default: + throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); + } + } + + // document detection + if (dev->model->buttons & GENESYS_HAS_PAGE_LOADED_SW) { + switch (dev->model->gpio_id) { + case GpioId::XP200: + session->buttons[BUTTON_PAGE_LOADED_SW].write((value & 0x04) != 0); + break; + default: + throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); + } + } + + /* XPA detection */ + if (dev->model->flags & GENESYS_FLAG_XPA) + { + switch (dev->model->gpio_id) { + case GpioId::HP3670: + case GpioId::HP2400: + /* test if XPA is plugged-in */ + if ((value & 0x40) == 0) + { + DBG(DBG_io, "%s: enabling XPA\n", __func__); + session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE; + } + else + { + DBG(DBG_io, "%s: disabling XPA\n", __func__); + session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; + } + break; + default: + throw SaneException(SANE_STATUS_UNSUPPORTED, "unknown gpo type"); + } + } +} + + +static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int resolution) +{ + DBG_HELPER(dbg); + uint8_t control[4]; + uint32_t addr = 0xdead; + + /* 2300 does not write to 'control' */ + if (dev->model->motor_id == MotorId::HP2300) { + return; + } + + /* MD6471/G2410/HP2300 and XP200 read/write data from an undocumented memory area which + * is after the second slope table */ + switch (sensor.optical_res) + { + case 600: + addr = 0x08200; + break; + case 1200: + addr = 0x10200; + break; + case 2400: + addr = 0x1fa00; + break; + default: + throw SaneException("failed to compute control address"); + } + + /* XP200 sets dpi, what other scanner put is unknown yet */ + switch (dev->model->motor_id) + { + case MotorId::XP200: + /* we put scan's dpi, not motor one */ + control[0] = resolution & 0xff; + control[1] = (resolution >> 8) & 0xff; + control[2] = dev->control[4]; + control[3] = dev->control[5]; + break; + case MotorId::HP3670: + case MotorId::HP2400: + case MotorId::MD_5345: + default: + control[0] = dev->control[2]; + control[1] = dev->control[3]; + control[2] = dev->control[4]; + control[3] = dev->control[5]; + break; + } + + DBG(DBG_info, "%s: control write=0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, control[0], control[1], + control[2], control[3]); + dev->interface->write_buffer(0x3c, addr, control, 4); +} + +/** + * search for a full width black or white strip. + * @param dev scanner device + * @param forward true if searching forward, false if searching backward + * @param black true if searching for a black strip, false for a white strip + */ +void CommandSetGl646::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward, + bool black) const +{ + DBG_HELPER(dbg); + (void) sensor; + + Genesys_Settings settings; + int res = get_closest_resolution(dev->model->sensor_id, 75, 1); + unsigned int pass, count, found, x, y; + char title[80]; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, res, 1, ScanMethod::FLATBED); + + /* we set up for a lowest available resolution color grey scan, full width */ + settings.scan_method = dev->model->default_method; + settings.scan_mode = ScanColorMode::GRAY; + settings.xres = res; + settings.yres = res; + settings.tl_x = 0; + settings.tl_y = 0; + settings.pixels = static_cast((dev->model->x_size * res) / MM_PER_INCH); + settings.pixels /= calib_sensor.get_ccd_size_divisor_for_dpi(res); + settings.requested_pixels = settings.pixels; + + /* 15 mm at at time */ + settings.lines = static_cast((15 * settings.yres) / MM_PER_INCH); + settings.depth = 8; + settings.color_filter = ColorFilter::RED; + + settings.disable_interpolation = 0; + settings.threshold = 0; + + /* signals if a strip of the given color has been found */ + found = 0; + + /* detection pass done */ + pass = 0; + + std::vector data; + + /* loop until strip is found or maximum pass number done */ + while (pass < 20 && !found) + { + // scan a full width strip + simple_scan(dev, calib_sensor, settings, true, forward, false, data, "search_strip"); + + if (is_testing_mode()) { + return; + } + + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl646_search_strip_%s%02d.pnm", forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file (title, data.data(), settings.depth, 1, + settings.pixels, settings.lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < settings.lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < settings.pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * settings.pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * settings.pixels + x] < 60) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / settings.pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < settings.lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < settings.pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * settings.pixels + x] > 60) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * settings.pixels + x] < 60) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (settings.pixels * settings.lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count); + } + } + pass++; + } + if (found) + { + DBG(DBG_info, "%s: strip found\n", __func__); + } + else + { + throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white"); + } +} + +void CommandSetGl646::wait_for_motor_stop(Genesys_Device* dev) const +{ + (void) dev; +} + +void CommandSetGl646::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + std::uint8_t* data, int size) const +{ + (void) dev; + (void) sensor; + (void) data; + (void) size; + throw SaneException("not implemented"); +} + +ScanSession CommandSetGl646::calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const +{ + // compute distance to move + float move = 0; + // XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */ + if (!dev->model->is_sheetfed) { + move = static_cast(dev->model->y_offset); + // add tl_y to base movement + } + move += static_cast(settings.tl_y); + + if (move < 0) { + DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move); + move = 0; + } + + move = static_cast((move * dev->motor.optical_ydpi) / MM_PER_INCH); + float start = static_cast(settings.tl_x); + if (settings.scan_method == ScanMethod::FLATBED) { + start += static_cast(dev->model->x_offset); + } else { + start += static_cast(dev->model->x_offset_ta); + } + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = settings.xres; + session.params.yres = settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = settings.pixels; + session.params.requested_pixels = settings.requested_pixels; + session.params.lines = settings.lines; + session.params.depth = settings.depth; + session.params.channels = settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = settings.scan_mode; + session.params.color_filter = settings.color_filter; + session.params.flags = ScanFlag::USE_XCORRECTION; + if (settings.scan_method == ScanMethod::TRANSPARENCY) { + session.params.flags |= ScanFlag::USE_XPA; + } + compute_session(dev, session, sensor); + + return session; +} + +void CommandSetGl646::asic_boot(Genesys_Device *dev, bool cold) const +{ + (void) dev; + (void) cold; + throw SaneException("not implemented"); +} + +std::unique_ptr create_gl646_cmd_set() +{ + return std::unique_ptr(new CommandSetGl646{}); +} + +} // namespace gl646 +} // namespace genesys diff --git a/backend/genesys/gl646.h b/backend/genesys/gl646.h new file mode 100644 index 0000000..afcfa05 --- /dev/null +++ b/backend/genesys/gl646.h @@ -0,0 +1,521 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003-2004 Henning Meier-Geinitz + Copyright (C) 2004-2005 Gerhard Jaeger + Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2005-2009 Pierre Willenbrock + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL646_H +#define BACKEND_GENESYS_GL646_H + +#include "genesys.h" +#include "command_set.h" +#include "motor.h" + +namespace genesys { +namespace gl646 { + +static void gl646_set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set, int dpi); + +/** + * sets up the scanner for a scan, registers, gamma tables, shading tables + * and slope tables, based on the parameter struct. + * @param dev device to set up + * @param regs registers to set up + * @param settings settings of the scan + * @param split true if move before scan has to be done + * @param xcorrection true if scanner's X geometry must be taken into account to + * compute X, ie add left margins + * @param ycorrection true if scanner's Y geometry must be taken into account to + * compute Y, ie add top margins + */ +static void setup_for_scan(Genesys_Device* device, + const Genesys_Sensor& sensor, + Genesys_Register_Set*regs, + Genesys_Settings settings, + bool split, + bool xcorrection, + bool ycorrection, + bool reverse); + +/** + * Does a simple move of the given distance by doing a scan at lowest resolution + * shading correction. Memory for data is allocated in this function + * and must be freed by caller. + * @param dev device of the scanner + * @param distance distance to move in MM + */ +static void simple_move(Genesys_Device* dev, SANE_Int distance); + +/** + * Does a simple scan of the area given by the settings. Scanned data + * it put in an allocated area which must be freed by the caller. + * and slope tables, based on the parameter struct. There is no shading + * correction while gamma correction is active. + * @param dev device to set up + * @param settings settings of the scan + * @param move flag to enable scanhead to move + * @param forward flag to tell movement direction + * @param shading flag to tell if shading correction should be done + * @param data pointer that will point to the scanned data + */ +static void simple_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Settings settings, bool move, bool forward, + bool shading, std::vector& data, const char* test_identifier); + +/** + * Send the stop scan command + * */ +static void end_scan_impl(Genesys_Device* dev, Genesys_Register_Set* reg, bool check_stop, + bool eject); +/** + * writes control data to an area behind the last motor table. + */ +static void write_control(Genesys_Device* dev, const Genesys_Sensor& sensor, int resolution); + + +/** + * initialize scanner's registers at SANE init time + */ +static void gl646_init_regs (Genesys_Device * dev); + +/** + * master motor settings table entry + */ +typedef struct +{ + /* key */ + MotorId motor_id; + unsigned dpi; + unsigned channels; + + /* settings */ + StepType steptype; + bool fastmod; // fast scanning + bool fastfed; // fast fed slope tables + SANE_Int mtrpwm; + MotorSlope slope1; + MotorSlope slope2; + SANE_Int fwdbwd; /* forward/backward steps */ +} Motor_Master; + +/** + * master motor settings, for a given motor and dpi, + * it gives steps and speed informations + */ +static Motor_Master motor_master[] = { + /* HP3670 motor settings */ + {MotorId::HP3670, 50, 3, StepType::HALF, false, true, 1, + MotorSlope::create_from_steps(2329, 120, 229), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 75, 3, StepType::FULL, false, true, 1, + MotorSlope::create_from_steps(3429, 305, 200), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 100, 3, StepType::HALF, false, true, 1, + MotorSlope::create_from_steps(2905, 187, 143), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 150, 3, StepType::HALF, false, true, 1, + MotorSlope::create_from_steps(3429, 305, 73), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 300, 3, StepType::HALF, false, true, 1, + MotorSlope::create_from_steps(1055, 563, 11), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 600, 3, StepType::FULL, false, true, 0, + MotorSlope::create_from_steps(10687, 5126, 3), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670,1200, 3, StepType::HALF, false, true, 0, + MotorSlope::create_from_steps(15937, 6375, 3), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 50, 1, StepType::HALF, false, true, 1, + MotorSlope::create_from_steps(2329, 120, 229), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 75, 1, StepType::FULL, false, true, 1, + MotorSlope::create_from_steps(3429, 305, 200), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 100, 1, StepType::HALF, false, true, 1, + MotorSlope::create_from_steps(2905, 187, 143), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 150, 1, StepType::HALF, false, true, 1, + MotorSlope::create_from_steps(3429, 305, 73), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 300, 1, StepType::HALF, false, true, 1, + MotorSlope::create_from_steps(1055, 563, 11), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670, 600, 1, StepType::FULL, false, true, 0, + MotorSlope::create_from_steps(10687, 5126, 3), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + {MotorId::HP3670,1200, 1, StepType::HALF, false, true, 0, + MotorSlope::create_from_steps(15937, 6375, 3), + MotorSlope::create_from_steps(3399, 337, 192), 192}, + + /* HP2400/G2410 motor settings base motor dpi = 600 */ + {MotorId::HP2400, 50, 3, StepType::FULL, false, true, 63, + MotorSlope::create_from_steps(8736, 601, 120), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400, 100, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(8736, 601, 120), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400, 150, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(15902, 902, 67), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400, 300, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(16703, 2188, 32), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400, 600, 3, StepType::FULL, false, true, 63, + MotorSlope::create_from_steps(18761, 18761, 3), + MotorSlope::create_from_steps(4905, 627, 192), 192}, + + {MotorId::HP2400,1200, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(43501, 43501, 3), + MotorSlope::create_from_steps(4905, 627, 192), 192}, + + {MotorId::HP2400, 50, 1, StepType::FULL, false, true, 63, + MotorSlope::create_from_steps(8736, 601, 120), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400, 100, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(8736, 601, 120), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400, 150, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(15902, 902, 67), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400, 300, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(16703, 2188, 32), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400, 600, 1, StepType::FULL, false, true, 63, + MotorSlope::create_from_steps(18761, 18761, 3), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + {MotorId::HP2400,1200, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(43501, 43501, 3), + MotorSlope::create_from_steps(4905, 337, 192), 192}, + + /* XP 200 motor settings */ + {MotorId::XP200, 75, 3, StepType::HALF, true, false, 0, + MotorSlope::create_from_steps(6000, 2136, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 100, 3, StepType::HALF, true, false, 0, + MotorSlope::create_from_steps(6000, 2850, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 200, 3, StepType::HALF, true, false, 0, + MotorSlope::create_from_steps(6999, 5700, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 250, 3, StepType::HALF, true, false, 0, + MotorSlope::create_from_steps(6999, 6999, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 300, 3, StepType::HALF, true, false, 0, + MotorSlope::create_from_steps(13500, 13500, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 600, 3, StepType::HALF, true, true, 0, + MotorSlope::create_from_steps(31998, 31998, 4), + MotorSlope::create_from_steps(12000, 1200, 2), 1}, + + {MotorId::XP200, 75, 1, StepType::HALF, true, false, 0, + MotorSlope::create_from_steps(6000, 2000, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 100, 1, StepType::HALF, true, false, 0, + MotorSlope::create_from_steps(6000, 1300, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 200, 1, StepType::HALF, true, true, 0, + MotorSlope::create_from_steps(6000, 3666, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 300, 1, StepType::HALF, true, false, 0, + MotorSlope::create_from_steps(6500, 6500, 4), + MotorSlope::create_from_steps(12000, 1200, 8), 1}, + + {MotorId::XP200, 600, 1, StepType::HALF, true, true, 0, + MotorSlope::create_from_steps(24000, 24000, 4), + MotorSlope::create_from_steps(12000, 1200, 2), 1}, + + /* HP scanjet 2300c */ + {MotorId::HP2300, 75, 3, StepType::FULL, false, true, 63, + MotorSlope::create_from_steps(8139, 560, 120), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300, 150, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(7903, 543, 67), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300, 300, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(2175, 1087, 3), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300, 600, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(8700, 4350, 3), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300,1200, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(17400, 8700, 3), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300, 75, 1, StepType::FULL, false, true, 63, + MotorSlope::create_from_steps(8139, 560, 120), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300, 150, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(7903, 543, 67), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300, 300, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(2175, 1087, 3), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300, 600, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(8700, 4350, 3), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300,1200, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(17400, 8700, 3), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + /* non half ccd settings for 300 dpi + {MotorId::HP2300, 300, 3, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(5386, 2175, 44), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + + {MotorId::HP2300, 300, 1, StepType::HALF, false, true, 63, + MotorSlope::create_from_steps(5386, 2175, 44), + MotorSlope::create_from_steps(4905, 337, 120), 16}, + */ + + /* MD5345/6471 motor settings */ + /* vfinal=(exposure/(1200/dpi))/step_type */ + {MotorId::MD_5345, 50, 3, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 250, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 75, 3, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 343, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 100, 3, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 458, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 150, 3, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 687, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 200, 3, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 916, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 300, 3, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 1375, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 400, 3, StepType::HALF, false, true, 0, + MotorSlope::create_from_steps(2000, 1833, 32), + MotorSlope::create_from_steps(2000, 300, 255), 32}, + + {MotorId::MD_5345, 500, 3, StepType::HALF, false, true, 0, + MotorSlope::create_from_steps(2291, 2291, 32), + MotorSlope::create_from_steps(2000, 300, 255), 32}, + + {MotorId::MD_5345, 600, 3, StepType::HALF, false, true, 0, + MotorSlope::create_from_steps(2750, 2750, 32), + MotorSlope::create_from_steps(2000, 300, 255), 32}, + + {MotorId::MD_5345, 1200, 3, StepType::QUARTER, false, true, 0, + MotorSlope::create_from_steps(2750, 2750, 16), + MotorSlope::create_from_steps(2000, 300, 255), 146}, + + {MotorId::MD_5345, 2400, 3, StepType::QUARTER, false, true, 0, + MotorSlope::create_from_steps(5500, 5500, 16), + MotorSlope::create_from_steps(2000, 300, 255), 146}, + + {MotorId::MD_5345, 50, 1, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 250, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 75, 1, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 343, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 100, 1, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 458, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 150, 1, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 687, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 200, 1, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 916, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 300, 1, StepType::HALF, false, true, 2, + MotorSlope::create_from_steps(2500, 1375, 255), + MotorSlope::create_from_steps(2000, 300, 255), 64}, + + {MotorId::MD_5345, 400, 1, StepType::HALF, false, true, 0, + MotorSlope::create_from_steps(2000, 1833, 32), + MotorSlope::create_from_steps(2000, 300, 255), 32}, + + {MotorId::MD_5345, 500, 1, StepType::HALF, false, true, 0, + MotorSlope::create_from_steps(2291, 2291, 32), + MotorSlope::create_from_steps(2000, 300, 255), 32}, + + {MotorId::MD_5345, 600, 1, StepType::HALF, false, true, 0, + MotorSlope::create_from_steps(2750, 2750, 32), + MotorSlope::create_from_steps(2000, 300, 255), 32}, + + {MotorId::MD_5345, 1200, 1, StepType::QUARTER, false, true, 0, + MotorSlope::create_from_steps(2750, 2750, 16), + MotorSlope::create_from_steps(2000, 300, 255), 146}, + + {MotorId::MD_5345, 2400, 1, StepType::QUARTER, false, true, 0, + MotorSlope::create_from_steps(5500, 5500, 16), + MotorSlope::create_from_steps(2000, 300, 255), 146}, /* 5500 guessed */ +}; + +class CommandSetGl646 : public CommandSet +{ +public: + ~CommandSetGl646() override = default; + + bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override; + + void init(Genesys_Device* dev) const override; + + void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const override; + + void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const override; + + void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override; + void set_powersaving(Genesys_Device* dev, int delay) const override; + void save_power(Genesys_Device* dev, bool enable) const override; + + void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, bool start_motor) const override; + + void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override; + + void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void search_start_position(Genesys_Device* dev) const override; + + void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const override; + + SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void wait_for_motor_stop(Genesys_Device* dev) const override; + + void move_back_home(Genesys_Device* dev, bool wait_until_home) const override; + + void update_hardware_sensors(struct Genesys_Scanner* s) const override; + + void load_document(Genesys_Device* dev) const override; + + void detect_document_end(Genesys_Device* dev) const override; + + void eject_document(Genesys_Device* dev) const override; + + void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const override; + + void move_to_ta(Genesys_Device* dev) const override; + + void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data, + int size) const override; + + bool has_send_shading_data() const override + { + return false; + } + + ScanSession calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const override; + + void asic_boot(Genesys_Device* dev, bool cold) const override; +}; + +} // namespace gl646 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL646_H diff --git a/backend/genesys/gl646_registers.h b/backend/genesys/gl646_registers.h new file mode 100644 index 0000000..2fe8f19 --- /dev/null +++ b/backend/genesys/gl646_registers.h @@ -0,0 +1,176 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL646_REGISTERS_H +#define BACKEND_GENESYS_GL646_REGISTERS_H + +#include + +namespace genesys { +namespace gl646 { + +using RegAddr = std::uint16_t; +using RegMask = std::uint8_t; +using RegShift = unsigned; + +static constexpr RegAddr REG_0x01 = 0x01; +static constexpr RegMask REG_0x01_CISSET = 0x80; +static constexpr RegMask REG_0x01_DOGENB = 0x40; +static constexpr RegMask REG_0x01_DVDSET = 0x20; +static constexpr RegMask REG_0x01_FASTMOD = 0x10; +static constexpr RegMask REG_0x01_COMPENB = 0x08; +static constexpr RegMask REG_0x01_DRAMSEL = 0x04; +static constexpr RegMask REG_0x01_SHDAREA = 0x02; +static constexpr RegMask REG_0x01_SCAN = 0x01; + +static constexpr RegMask REG_0x02_NOTHOME = 0x80; +static constexpr RegMask REG_0x02_ACDCDIS = 0x40; +static constexpr RegMask REG_0x02_AGOHOME = 0x20; +static constexpr RegMask REG_0x02_MTRPWR = 0x10; +static constexpr RegMask REG_0x02_FASTFED = 0x08; +static constexpr RegMask REG_0x02_MTRREV = 0x04; +static constexpr RegMask REG_0x02_STEPSEL = 0x03; + +static constexpr RegMask REG_0x02_FULLSTEP = 0x00; +static constexpr RegMask REG_0x02_HALFSTEP = 0x01; +static constexpr RegMask REG_0x02_QUATERSTEP = 0x02; + +static constexpr RegMask REG_0x03_TG3 = 0x80; +static constexpr RegMask REG_0x03_AVEENB = 0x40; +static constexpr RegMask REG_0x03_XPASEL = 0x20; +static constexpr RegMask REG_0x03_LAMPPWR = 0x10; +static constexpr RegMask REG_0x03_LAMPDOG = 0x08; +static constexpr RegMask REG_0x03_LAMPTIM = 0x07; + +static constexpr RegMask REG_0x04_LINEART = 0x80; +static constexpr RegMask REG_0x04_BITSET = 0x40; +static constexpr RegMask REG_0x04_ADTYPE = 0x30; +static constexpr RegMask REG_0x04_FILTER = 0x0c; +static constexpr RegMask REG_0x04_FESET = 0x03; + +static constexpr RegMask REG_0x05_DPIHW = 0xc0; +static constexpr RegMask REG_0x05_DPIHW_600 = 0x00; +static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40; +static constexpr RegMask REG_0x05_DPIHW_2400 = 0x80; +static constexpr RegMask REG_0x05_DPIHW_4800 = 0xc0; +static constexpr RegMask REG_0x05_GMMTYPE = 0x30; +static constexpr RegMask REG_0x05_GMM14BIT = 0x10; +static constexpr RegMask REG_0x05_GMMENB = 0x08; +static constexpr RegMask REG_0x05_LEDADD = 0x04; +static constexpr RegMask REG_0x05_BASESEL = 0x03; + +static constexpr RegAddr REG_0x06 = 0x06; +static constexpr RegMask REG_0x06_PWRBIT = 0x10; +static constexpr RegMask REG_0x06_GAIN4 = 0x08; +static constexpr RegMask REG_0x06_OPTEST = 0x07; + +static constexpr RegMask REG_0x07_DMASEL = 0x02; +static constexpr RegMask REG_0x07_DMARDWR = 0x01; + +static constexpr RegMask REG_0x16_CTRLHI = 0x80; +static constexpr RegMask REG_0x16_SELINV = 0x40; +static constexpr RegMask REG_0x16_TGINV = 0x20; +static constexpr RegMask REG_0x16_CK1INV = 0x10; +static constexpr RegMask REG_0x16_CK2INV = 0x08; +static constexpr RegMask REG_0x16_CTRLINV = 0x04; +static constexpr RegMask REG_0x16_CKDIS = 0x02; +static constexpr RegMask REG_0x16_CTRLDIS = 0x01; + +static constexpr RegMask REG_0x17_TGMODE = 0xc0; +static constexpr RegMask REG_0x17_TGMODE_NO_DUMMY = 0x00; +static constexpr RegMask REG_0x17_TGMODE_REF = 0x40; +static constexpr RegMask REG_0x17_TGMODE_XPA = 0x80; +static constexpr RegMask REG_0x17_TGW = 0x3f; + +static constexpr RegMask REG_0x18_CNSET = 0x80; +static constexpr RegMask REG_0x18_DCKSEL = 0x60; +static constexpr RegMask REG_0x18_CKTOGGLE = 0x10; +static constexpr RegMask REG_0x18_CKDELAY = 0x0c; +static constexpr RegMask REG_0x18_CKSEL = 0x03; + +static constexpr RegMask REG_0x1D_CKMANUAL = 0x80; + +static constexpr RegMask REG_0x1E_WDTIME = 0xf0; +static constexpr RegMask REG_0x1E_LINESEL = 0x0f; + +static constexpr RegMask REG_0x41_PWRBIT = 0x80; +static constexpr RegMask REG_0x41_BUFEMPTY = 0x40; +static constexpr RegMask REG_0x41_FEEDFSH = 0x20; +static constexpr RegMask REG_0x41_SCANFSH = 0x10; +static constexpr RegMask REG_0x41_HOMESNR = 0x08; +static constexpr RegMask REG_0x41_LAMPSTS = 0x04; +static constexpr RegMask REG_0x41_FEBUSY = 0x02; +static constexpr RegMask REG_0x41_MOTMFLG = 0x01; + +static constexpr RegMask REG_0x66_LOW_CURRENT = 0x10; + +static constexpr RegMask REG_0x6A_FSTPSEL = 0xc0; +static constexpr RegMask REG_0x6A_FASTPWM = 0x3f; + +static constexpr RegMask REG_0x6C_TGTIME = 0xc0; +static constexpr RegMask REG_0x6C_Z1MOD = 0x38; +static constexpr RegMask REG_0x6C_Z2MOD = 0x07; + +static constexpr RegAddr REG_EXPR = 0x10; +static constexpr RegAddr REG_EXPG = 0x12; +static constexpr RegAddr REG_EXPB = 0x14; +static constexpr RegAddr REG_SCANFED = 0x1f; +static constexpr RegAddr REG_BUFSEL = 0x20; +static constexpr RegAddr REG_LINCNT = 0x25; +static constexpr RegAddr REG_DPISET = 0x2c; +static constexpr RegAddr REG_STRPIXEL = 0x30; +static constexpr RegAddr REG_ENDPIXEL = 0x32; +static constexpr RegAddr REG_DUMMY = 0x34; +static constexpr RegAddr REG_MAXWD = 0x35; +static constexpr RegAddr REG_LPERIOD = 0x38; +static constexpr RegAddr REG_FEEDL = 0x3d; +static constexpr RegAddr REG_VALIDWORD = 0x42; +static constexpr RegAddr REG_FEDCNT = 0x48; +static constexpr RegAddr REG_SCANCNT = 0x4b; +static constexpr RegAddr REG_Z1MOD = 0x60; +static constexpr RegAddr REG_Z2MOD = 0x62; + +} // namespace gl646 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL646_REGISTERS_H diff --git a/backend/genesys/gl841.cpp b/backend/genesys/gl841.cpp new file mode 100644 index 0000000..470f9ba --- /dev/null +++ b/backend/genesys/gl841.cpp @@ -0,0 +1,4010 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003 Oliver Rauch + Copyright (C) 2003, 2004 Henning Meier-Geinitz + Copyright (C) 2004 Gerhard Jaeger + Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2005 Philipp Schmid + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2006 Laurent Charpentier + Copyright (C) 2010 Chris Berry and Michael Rickmann + for Plustek Opticbook 3600 support + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "gl841.h" +#include "gl841_registers.h" +#include "test_settings.h" + +#include + +namespace genesys { +namespace gl841 { + + +static int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, + float slope_dpi, + StepType scan_step_type, + int start, + int used_pixels); + +/** copy sensor specific settings */ +/* *dev : device infos + *regs : registers to be set + extended : do extended set up + ccd_size_divisor: set up for half ccd resolution + all registers 08-0B, 10-1D, 52-59 are set up. They shouldn't + appear anywhere else but in register_ini + +Responsible for signals to CCD/CIS: + CCD_CK1X (CK1INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1MTGL(0x1C),CK1LOW(0x1D),CK1MAP(0x74,0x75,0x76),CK1NEG(0x7D)) + CCD_CK2X (CK2INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1LOW(0x1D),CK1NEG(0x7D)) + CCD_CK3X (MANUAL3(0x1A),CK3INV(0x1A),CK3MTGL(0x1C),CK3LOW(0x1D),CK3MAP(0x77,0x78,0x79),CK3NEG(0x7D)) + CCD_CK4X (MANUAL3(0x1A),CK4INV(0x1A),CK4MTGL(0x1C),CK4LOW(0x1D),CK4MAP(0x7A,0x7B,0x7C),CK4NEG(0x7D)) + CCD_CPX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),CPH(0x72),CPL(0x73),CPNEG(0x7D)) + CCD_RSX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),RSH(0x70),RSL(0x71),RSNEG(0x7D)) + CCD_TGX (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPR(0x10,0x11),TGSHLD(0x1D)) + CCD_TGG (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPG(0x12,0x13),TGSHLD(0x1D)) + CCD_TGB (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPB(0x14,0x15),TGSHLD(0x1D)) + LAMP_SW (EXPR(0x10,0x11),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) + XPA_SW (EXPG(0x12,0x13),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) + LAMP_B (EXPB(0x14,0x15),LAMP_PWR(0x03)) + +other registers: + CISSET(0x01),CNSET(0x18),DCKSEL(0x18),SCANMOD(0x18),EXPDMY(0x19),LINECLP(0x1A),CKAREA(0x1C),TGTIME(0x1C),LINESEL(0x1E),DUMMY(0x34) + +Responsible for signals to AFE: + VSMP (VSMP(0x58),VSMPW(0x58)) + BSMP (BSMP(0x59),BSMPW(0x59)) + +other register settings depending on this: + RHI(0x52),RLOW(0x53),GHI(0x54),GLOW(0x55),BHI(0x56),BLOW(0x57), + +*/ +static void sanei_gl841_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set * regs, + bool extended, unsigned ccd_size_divisor) +{ + DBG(DBG_proc, "%s\n", __func__); + + // that one is tricky at least + for (uint16_t addr = 0x08; addr <= 0x0b; ++addr) { + regs->set8(0x70 + addr - 0x08, sensor.custom_regs.get_value(addr)); + } + + // ignore registers in range [0x10..0x16) + for (uint16_t addr = 0x16; addr < 0x1e; ++addr) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + // ignore registers in range [0x5b..0x5e] + for (uint16_t addr = 0x52; addr < 0x52 + 9; ++addr) { + regs->set8(addr, sensor.custom_regs.get_value(addr)); + } + + /* don't go any further if no extended setup */ + if (!extended) + return; + + /* todo : add more CCD types if needed */ + /* we might want to expand the Sensor struct to have these + 2 kind of settings */ + if (dev->model->sensor_id == SensorId::CCD_5345) { + if (ccd_size_divisor > 1) { + GenesysRegister* r; + /* settings for CCD used at half is max resolution */ + r = sanei_genesys_get_address (regs, 0x70); + r->value = 0x00; + r = sanei_genesys_get_address (regs, 0x71); + r->value = 0x05; + r = sanei_genesys_get_address (regs, 0x72); + r->value = 0x06; + r = sanei_genesys_get_address (regs, 0x73); + r->value = 0x08; + r = sanei_genesys_get_address (regs, 0x18); + r->value = 0x28; + r = sanei_genesys_get_address (regs, 0x58); + r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ + } + else + { + GenesysRegister* r; + /* swap latch times */ + r = sanei_genesys_get_address (regs, 0x18); + r->value = 0x30; + regs->set8(0x52, sensor.custom_regs.get_value(0x55)); + regs->set8(0x53, sensor.custom_regs.get_value(0x56)); + regs->set8(0x54, sensor.custom_regs.get_value(0x57)); + regs->set8(0x55, sensor.custom_regs.get_value(0x52)); + regs->set8(0x56, sensor.custom_regs.get_value(0x53)); + regs->set8(0x57, sensor.custom_regs.get_value(0x54)); + r = sanei_genesys_get_address (regs, 0x58); + r->value = 0x20 | (r->value & 0x03); /* VSMP=4 */ + } + return; + } + + if (dev->model->sensor_id == SensorId::CCD_HP2300) { + /* settings for CCD used at half is max resolution */ + GenesysRegister* r; + if (ccd_size_divisor > 1) { + r = sanei_genesys_get_address (regs, 0x70); + r->value = 0x16; + r = sanei_genesys_get_address (regs, 0x71); + r->value = 0x00; + r = sanei_genesys_get_address (regs, 0x72); + r->value = 0x01; + r = sanei_genesys_get_address (regs, 0x73); + r->value = 0x03; + /* manual clock programming */ + r = sanei_genesys_get_address (regs, 0x1d); + r->value |= 0x80; + } + else + { + r = sanei_genesys_get_address (regs, 0x70); + r->value = 1; + r = sanei_genesys_get_address (regs, 0x71); + r->value = 3; + r = sanei_genesys_get_address (regs, 0x72); + r->value = 4; + r = sanei_genesys_get_address (regs, 0x73); + r->value = 6; + } + r = sanei_genesys_get_address (regs, 0x58); + r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ + return; + } +} + +/* + * Set all registers LiDE 80 to default values + * (function called only once at the beginning) + * we are doing a special case to ease development + */ +static void +gl841_init_lide80 (Genesys_Device * dev) +{ + dev->reg.init_reg(0x01, 0x82); // 0x02 = SHDAREA and no CISSET ! + dev->reg.init_reg(0x02, 0x10); + dev->reg.init_reg(0x03, 0x50); + dev->reg.init_reg(0x04, 0x02); + dev->reg.init_reg(0x05, 0x4c); // 1200 DPI + dev->reg.init_reg(0x06, 0x38); // 0x38 scanmod=1, pwrbit, GAIN4 + dev->reg.init_reg(0x07, 0x00); + dev->reg.init_reg(0x08, 0x00); + dev->reg.init_reg(0x09, 0x11); + dev->reg.init_reg(0x0a, 0x00); + + dev->reg.init_reg(0x10, 0x40); + dev->reg.init_reg(0x11, 0x00); + dev->reg.init_reg(0x12, 0x40); + dev->reg.init_reg(0x13, 0x00); + dev->reg.init_reg(0x14, 0x40); + dev->reg.init_reg(0x15, 0x00); + dev->reg.init_reg(0x16, 0x00); + dev->reg.init_reg(0x17, 0x01); + dev->reg.init_reg(0x18, 0x00); + dev->reg.init_reg(0x19, 0x06); + dev->reg.init_reg(0x1a, 0x00); + dev->reg.init_reg(0x1b, 0x00); + dev->reg.init_reg(0x1c, 0x00); + dev->reg.init_reg(0x1d, 0x04); + dev->reg.init_reg(0x1e, 0x10); + dev->reg.init_reg(0x1f, 0x04); + dev->reg.init_reg(0x20, 0x02); + dev->reg.init_reg(0x21, 0x10); + dev->reg.init_reg(0x22, 0x20); + dev->reg.init_reg(0x23, 0x20); + dev->reg.init_reg(0x24, 0x10); + dev->reg.init_reg(0x25, 0x00); + dev->reg.init_reg(0x26, 0x00); + dev->reg.init_reg(0x27, 0x00); + + dev->reg.init_reg(0x29, 0xff); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + dev->reg.init_reg(0x2c, sensor.optical_res>>8); + dev->reg.init_reg(0x2d, sensor.optical_res & 0xff); + dev->reg.init_reg(0x2e, 0x80); + dev->reg.init_reg(0x2f, 0x80); + dev->reg.init_reg(0x30, 0x00); + dev->reg.init_reg(0x31, 0x10); + dev->reg.init_reg(0x32, 0x15); + dev->reg.init_reg(0x33, 0x0e); + dev->reg.init_reg(0x34, 0x40); + dev->reg.init_reg(0x35, 0x00); + dev->reg.init_reg(0x36, 0x2a); + dev->reg.init_reg(0x37, 0x30); + dev->reg.init_reg(0x38, 0x2a); + dev->reg.init_reg(0x39, 0xf8); + + dev->reg.init_reg(0x3d, 0x00); + dev->reg.init_reg(0x3e, 0x00); + dev->reg.init_reg(0x3f, 0x00); + + dev->reg.init_reg(0x52, 0x03); + dev->reg.init_reg(0x53, 0x07); + dev->reg.init_reg(0x54, 0x00); + dev->reg.init_reg(0x55, 0x00); + dev->reg.init_reg(0x56, 0x00); + dev->reg.init_reg(0x57, 0x00); + dev->reg.init_reg(0x58, 0x29); + dev->reg.init_reg(0x59, 0x69); + dev->reg.init_reg(0x5a, 0x55); + + dev->reg.init_reg(0x5d, 0x20); + dev->reg.init_reg(0x5e, 0x41); + dev->reg.init_reg(0x5f, 0x40); + dev->reg.init_reg(0x60, 0x00); + dev->reg.init_reg(0x61, 0x00); + dev->reg.init_reg(0x62, 0x00); + dev->reg.init_reg(0x63, 0x00); + dev->reg.init_reg(0x64, 0x00); + dev->reg.init_reg(0x65, 0x00); + dev->reg.init_reg(0x66, 0x00); + dev->reg.init_reg(0x67, 0x40); + dev->reg.init_reg(0x68, 0x40); + dev->reg.init_reg(0x69, 0x20); + dev->reg.init_reg(0x6a, 0x20); + dev->reg.init_reg(0x6c, 0x00); + dev->reg.init_reg(0x6d, 0x00); + dev->reg.init_reg(0x6e, 0x00); + dev->reg.init_reg(0x6f, 0x00); + dev->reg.init_reg(0x70, 0x00); + dev->reg.init_reg(0x71, 0x05); + dev->reg.init_reg(0x72, 0x07); + dev->reg.init_reg(0x73, 0x09); + dev->reg.init_reg(0x74, 0x00); + dev->reg.init_reg(0x75, 0x01); + dev->reg.init_reg(0x76, 0xff); + dev->reg.init_reg(0x77, 0x00); + dev->reg.init_reg(0x78, 0x0f); + dev->reg.init_reg(0x79, 0xf0); + dev->reg.init_reg(0x7a, 0xf0); + dev->reg.init_reg(0x7b, 0x00); + dev->reg.init_reg(0x7c, 0x1e); + dev->reg.init_reg(0x7d, 0x11); + dev->reg.init_reg(0x7e, 0x00); + dev->reg.init_reg(0x7f, 0x50); + dev->reg.init_reg(0x80, 0x00); + dev->reg.init_reg(0x81, 0x00); + dev->reg.init_reg(0x82, 0x0f); + dev->reg.init_reg(0x83, 0x00); + dev->reg.init_reg(0x84, 0x0e); + dev->reg.init_reg(0x85, 0x00); + dev->reg.init_reg(0x86, 0x0d); + dev->reg.init_reg(0x87, 0x02); + dev->reg.init_reg(0x88, 0x00); + dev->reg.init_reg(0x89, 0x00); + + for (const auto& reg : dev->gpo.regs) { + dev->reg.set8(reg.address, reg.value); + } + + // specific scanner settings, clock and gpio first + // FIXME: remove the dummy reads as we don't use the values + if (!is_testing_mode()) { + dev->interface->read_register(REG_0x6B); + } + dev->interface->write_register(REG_0x6B, 0x0c); + dev->interface->write_register(0x06, 0x10); + dev->interface->write_register(REG_0x6E, 0x6d); + dev->interface->write_register(REG_0x6F, 0x80); + dev->interface->write_register(REG_0x6B, 0x0e); + if (!is_testing_mode()) { + dev->interface->read_register(REG_0x6C); + } + dev->interface->write_register(REG_0x6C, 0x00); + if (!is_testing_mode()) { + dev->interface->read_register(REG_0x6D); + } + dev->interface->write_register(REG_0x6D, 0x8f); + if (!is_testing_mode()) { + dev->interface->read_register(REG_0x6B); + } + dev->interface->write_register(REG_0x6B, 0x0e); + if (!is_testing_mode()) { + dev->interface->read_register(REG_0x6B); + } + dev->interface->write_register(REG_0x6B, 0x0e); + if (!is_testing_mode()) { + dev->interface->read_register(REG_0x6B); + } + dev->interface->write_register(REG_0x6B, 0x0a); + if (!is_testing_mode()) { + dev->interface->read_register(REG_0x6B); + } + dev->interface->write_register(REG_0x6B, 0x02); + if (!is_testing_mode()) { + dev->interface->read_register(REG_0x6B); + } + dev->interface->write_register(REG_0x6B, 0x06); + + dev->interface->write_0x8c(0x10, 0x94); + dev->interface->write_register(0x09, 0x10); + + // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was + // effectively changed. The current behavior matches the old code, but should probably be fixed. + dev->reg.find_reg(0x6c).value |= REG_0x6B_GPO18; + dev->reg.find_reg(0x6c).value &= ~REG_0x6B_GPO17; + + sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 1); +} + +/* + * Set all registers to default values + * (function called only once at the beginning) + */ +static void +gl841_init_registers (Genesys_Device * dev) +{ + int addr; + + DBG(DBG_proc, "%s\n", __func__); + + dev->reg.clear(); + if (dev->model->model_id == ModelId::CANON_LIDE_80) { + gl841_init_lide80(dev); + return ; + } + + for (addr = 1; addr <= 0x0a; addr++) { + dev->reg.init_reg(addr, 0); + } + for (addr = 0x10; addr <= 0x27; addr++) { + dev->reg.init_reg(addr, 0); + } + dev->reg.init_reg(0x29, 0); + for (addr = 0x2c; addr <= 0x39; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x3d; addr <= 0x3f; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x52; addr <= 0x5a; addr++) + dev->reg.init_reg(addr, 0); + for (addr = 0x5d; addr <= 0x87; addr++) + dev->reg.init_reg(addr, 0); + + + dev->reg.find_reg(0x01).value = 0x20; /* (enable shading), CCD, color, 1M */ + if (dev->model->is_cis) { + dev->reg.find_reg(0x01).value |= REG_0x01_CISSET; + } else { + dev->reg.find_reg(0x01).value &= ~REG_0x01_CISSET; + } + + dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ + dev->reg.find_reg(0x02).value |= REG_0x02_AGOHOME; + sanei_genesys_set_motor_power(dev->reg, true); + dev->reg.find_reg(0x02).value |= REG_0x02_FASTFED; + + dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */ + dev->reg.find_reg(0x03).value |= REG_0x03_AVEENB; + + if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) { + // AD front end + dev->reg.find_reg(0x04).value = (2 << REG_0x04S_AFEMOD) | 0x02; + } + else /* Wolfson front end */ + { + dev->reg.find_reg(0x04).value |= 1 << REG_0x04S_AFEMOD; + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + dev->reg.find_reg(0x05).value = 0x00; /* disable gamma, 24 clocks/pixel */ + + unsigned dpihw = 0; + if (sensor.sensor_pixels < 0x1500) { + dpihw = 600; + } else if (sensor.sensor_pixels < 0x2a80) { + dpihw = 1200; + } else if (sensor.sensor_pixels < 0x5400) { + dpihw = 2400; + } else { + throw SaneException("Cannot handle sensor pixel count %d", sensor.sensor_pixels); + } + sanei_genesys_set_dpihw(dev->reg, sensor, dpihw); + + dev->reg.find_reg(0x06).value |= REG_0x06_PWRBIT; + dev->reg.find_reg(0x06).value |= REG_0x06_GAIN4; + + /* XP300 CCD needs different clock and clock/pixels values */ + if (dev->model->sensor_id != SensorId::CCD_XP300 && + dev->model->sensor_id != SensorId::CCD_DP685 && + dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICPRO_3600) + { + dev->reg.find_reg(0x06).value |= 0 << REG_0x06S_SCANMOD; + dev->reg.find_reg(0x09).value |= 1 << REG_0x09S_CLKSET; + } + else + { + dev->reg.find_reg(0x06).value |= 0x05 << REG_0x06S_SCANMOD; /* 15 clocks/pixel */ + dev->reg.find_reg(0x09).value = 0; /* 24 MHz CLKSET */ + } + + dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */ + + dev->reg.find_reg(0x17).value |= 1 << REG_0x17S_TGW; + + dev->reg.find_reg(0x19).value = 0x50; + + dev->reg.find_reg(0x1d).value |= 1 << REG_0x1DS_TGSHLD; + + dev->reg.find_reg(0x1e).value |= 1 << REG_0x1ES_WDTIME; + +/*SCANFED*/ + dev->reg.find_reg(0x1f).value = 0x01; + +/*BUFSEL*/ + dev->reg.find_reg(0x20).value = 0x20; + +/*LAMPPWM*/ + dev->reg.find_reg(0x29).value = 0xff; + +/*BWHI*/ + dev->reg.find_reg(0x2e).value = 0x80; + +/*BWLOW*/ + dev->reg.find_reg(0x2f).value = 0x80; + +/*LPERIOD*/ + dev->reg.find_reg(0x38).value = 0x4f; + dev->reg.find_reg(0x39).value = 0xc1; + +/*VSMPW*/ + dev->reg.find_reg(0x58).value |= 3 << REG_0x58S_VSMPW; + +/*BSMPW*/ + dev->reg.find_reg(0x59).value |= 3 << REG_0x59S_BSMPW; + +/*RLCSEL*/ + dev->reg.find_reg(0x5a).value |= REG_0x5A_RLCSEL; + +/*STOPTIM*/ + dev->reg.find_reg(0x5e).value |= 0x2 << REG_0x5ES_STOPTIM; + + sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 1); + + // set up GPIO + for (const auto& reg : dev->gpo.regs) { + dev->reg.set8(reg.address, reg.value); + } + + /* TODO there is a switch calling to be written here */ + if (dev->model->gpio_id == GpioId::CANON_LIDE_35) { + dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18; + dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17; + } + + if (dev->model->gpio_id == GpioId::XP300) { + dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17; + } + + if (dev->model->gpio_id == GpioId::DP685) { + /* REG_0x6B_GPO18 lights on green led */ + dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17|REG_0x6B_GPO18; + } + + DBG(DBG_proc, "%s complete\n", __func__); +} + +// Send slope table for motor movement slope_table in machine byte order +static void gl841_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, + int steps) +{ + DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); + int dpihw; + int start_address; + char msg[4000]; +/*#ifdef WORDS_BIGENDIAN*/ + int i; +/*#endif*/ + + dpihw = dev->reg.find_reg(0x05).value >> 6; + + if (dpihw == 0) /* 600 dpi */ + start_address = 0x08000; + else if (dpihw == 1) /* 1200 dpi */ + start_address = 0x10000; + else if (dpihw == 2) /* 2400 dpi */ + start_address = 0x20000; + else { + throw SaneException("Unexpected dpihw"); + } + + std::vector table(steps * 2); + for(i = 0; i < steps; i++) { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + std::sprintf(msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) { + std::sprintf (msg+strlen(msg), ",%d", slope_table[i]); + } + DBG(DBG_io, "%s: %s\n", __func__, msg); + } + + if (dev->interface->is_mock()) { + dev->interface->record_slope_table(table_nr, slope_table); + } + dev->interface->write_buffer(0x3c, start_address + table_nr * 0x200, table.data(), steps * 2); +} + +static void gl841_set_lide80_fe(Genesys_Device* dev, uint8_t set) +{ + DBG_HELPER(dbg); + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + + dev->frontend = dev->frontend_initial; + + // write them to analog frontend + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x01)); + dev->interface->write_fe_register(0x06, dev->frontend.regs.get_value(0x02)); + } + + if (set == AFE_SET) + { + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + dev->interface->write_fe_register(0x06, dev->frontend.regs.get_value(0x20)); + dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x28)); + } +} + +// Set values of Analog Device type frontend +static void gl841_set_ad_fe(Genesys_Device* dev, uint8_t set) +{ + DBG_HELPER(dbg); + int i; + + if (dev->model->adc_id==AdcId::CANON_LIDE_80) { + gl841_set_lide80_fe(dev, set); + return; + } + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + + dev->frontend = dev->frontend_initial; + + // write them to analog frontend + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + + dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); + + for (i = 0; i < 6; i++) { + dev->interface->write_fe_register(0x02 + i, 0x00); + } + } + if (set == AFE_SET) + { + // write them to analog frontend + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + + dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); + + // Write fe 0x02 (red gain) + dev->interface->write_fe_register(0x02, dev->frontend.get_gain(0)); + + // Write fe 0x03 (green gain) + dev->interface->write_fe_register(0x03, dev->frontend.get_gain(1)); + + // Write fe 0x04 (blue gain) + dev->interface->write_fe_register(0x04, dev->frontend.get_gain(2)); + + // Write fe 0x05 (red offset) + dev->interface->write_fe_register(0x05, dev->frontend.get_offset(0)); + + // Write fe 0x06 (green offset) + dev->interface->write_fe_register(0x06, dev->frontend.get_offset(1)); + + // Write fe 0x07 (blue offset) + dev->interface->write_fe_register(0x07, dev->frontend.get_offset(2)); + } +} + +// Set values of analog frontend +void CommandSetGl841::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const +{ + DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" : + set == AFE_SET ? "set" : + set == AFE_POWER_SAVE ? "powersave" : "huh?"); + (void) sensor; + + /* Analog Device type frontend */ + uint8_t frontend_type = dev->reg.find_reg(0x04).value & REG_0x04_FESET; + + if (frontend_type == 0x02) { + gl841_set_ad_fe(dev, set); + return; + } + + if (frontend_type != 0x00) { + throw SaneException("unsupported frontend type %d", frontend_type); + } + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + dev->frontend = dev->frontend_initial; + + // reset only done on init + dev->interface->write_fe_register(0x04, 0x80); + DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); + } + + + if (set == AFE_POWER_SAVE) + { + dev->interface->write_fe_register(0x01, 0x02); + return; + } + + /* todo : base this test on cfg reg3 or a CCD family flag to be created */ + /*if (dev->model->ccd_type!=SensorId::CCD_HP2300 && dev->model->ccd_type!=SensorId::CCD_HP2400) */ + { + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + dev->interface->write_fe_register(0x02, dev->frontend.regs.get_value(0x02)); + } + + dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); + dev->interface->write_fe_register(0x03, dev->frontend.regs.get_value(0x03)); + dev->interface->write_fe_register(0x06, dev->frontend.reg2[0]); + dev->interface->write_fe_register(0x08, dev->frontend.reg2[1]); + dev->interface->write_fe_register(0x09, dev->frontend.reg2[2]); + + for (unsigned i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); + dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); + dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); + } +} + +enum MotorAction { + MOTOR_ACTION_FEED = 1, + MOTOR_ACTION_GO_HOME = 2, + MOTOR_ACTION_HOME_FREE = 3 +}; + +// @brief turn off motor +static void gl841_init_motor_regs_off(Genesys_Register_Set* reg, unsigned int scan_lines) +{ + DBG_HELPER_ARGS(dbg, "scan_lines=%d", scan_lines); + unsigned int feedl; + GenesysRegister* r; + + feedl = 2; + + r = sanei_genesys_get_address (reg, 0x3d); + r->value = (feedl >> 16) & 0xf; + r = sanei_genesys_get_address (reg, 0x3e); + r->value = (feedl >> 8) & 0xff; + r = sanei_genesys_get_address (reg, 0x3f); + r->value = feedl & 0xff; + r = sanei_genesys_get_address (reg, 0x5e); + r->value &= ~0xe0; + + r = sanei_genesys_get_address (reg, 0x25); + r->value = (scan_lines >> 16) & 0xf; + r = sanei_genesys_get_address (reg, 0x26); + r->value = (scan_lines >> 8) & 0xff; + r = sanei_genesys_get_address (reg, 0x27); + r->value = scan_lines & 0xff; + + r = sanei_genesys_get_address (reg, 0x02); + r->value &= ~0x01; /*LONGCURV OFF*/ + r->value &= ~0x80; /*NOT_HOME OFF*/ + + r->value &= ~0x10; + + r->value &= ~0x06; + + r->value &= ~0x08; + + r->value &= ~0x20; + + r->value &= ~0x40; + + r = sanei_genesys_get_address (reg, 0x67); + r->value = 0x3f; + + r = sanei_genesys_get_address (reg, 0x68); + r->value = 0x3f; + + r = sanei_genesys_get_address(reg, REG_STEPNO); + r->value = 0; + + r = sanei_genesys_get_address(reg, REG_FASTNO); + r->value = 0; + + r = sanei_genesys_get_address (reg, 0x69); + r->value = 0; + + r = sanei_genesys_get_address (reg, 0x6a); + r->value = 0; + + r = sanei_genesys_get_address (reg, 0x5f); + r->value = 0; +} + +/** @brief write motor table frequency + * Write motor frequency data table. + * @param dev device to set up motor + * @param ydpi motor target resolution + */ +static void gl841_write_freq(Genesys_Device* dev, unsigned int ydpi) +{ + DBG_HELPER(dbg); +/**< fast table */ +uint8_t tdefault[] = {0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76}; +uint8_t t1200[] = {0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20}; +uint8_t t300[] = {0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60}; +uint8_t t150[] = {0x0c,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0x40,0x14,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x0c,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0x11,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x0c,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0x40,0xd4,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x0c,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0x11,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60}; + +uint8_t *table; + + if(dev->model->motor_id == MotorId::CANON_LIDE_80) { + switch(ydpi) + { + case 3600: + case 1200: + table=t1200; + break; + case 900: + case 300: + table=t300; + break; + case 450: + case 150: + table=t150; + break; + default: + table=tdefault; + } + dev->interface->write_register(0x66, 0x00); + dev->interface->write_gamma(0x28, 0xc000, table, 128, + ScannerInterface::FLAG_SWAP_REGISTERS); + dev->interface->write_register(0x5b, 0x00); + dev->interface->write_register(0x5c, 0x00); + } +} + + +static void gl841_init_motor_regs(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, unsigned int feed_steps,/*1/base_ydpi*/ + /*maybe float for half/quarter step resolution?*/ + unsigned int action, MotorFlag flags) +{ + DBG_HELPER_ARGS(dbg, "feed_steps=%d, action=%d, flags=%x", feed_steps, action, + static_cast(flags)); + unsigned int fast_exposure = 0; + int use_fast_fed = 0; + unsigned int feedl; + GenesysRegister* r; +/*number of scan lines to add in a scan_lines line*/ + + { + std::vector table; + table.resize(256, 0xffff); + + gl841_send_slope_table(dev, 0, table, 256); + gl841_send_slope_table(dev, 1, table, 256); + gl841_send_slope_table(dev, 2, table, 256); + gl841_send_slope_table(dev, 3, table, 256); + gl841_send_slope_table(dev, 4, table, 256); + } + + gl841_write_freq(dev, dev->motor.base_ydpi / 4); + + if (action == MOTOR_ACTION_FEED || action == MOTOR_ACTION_GO_HOME) { + /* FEED and GO_HOME can use fastest slopes available */ + fast_exposure = gl841_exposure_time(dev, sensor, + dev->motor.base_ydpi / 4, + StepType::FULL, + 0, + 0); + DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); + } + + if (action == MOTOR_ACTION_HOME_FREE) { +/* HOME_FREE must be able to stop in one step, so do not try to get faster */ + fast_exposure = dev->motor.get_slope(StepType::FULL).max_speed_w; + } + + auto fast_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor, + StepType::FULL, fast_exposure, + dev->motor.base_ydpi / 4); + + feedl = feed_steps - fast_table.steps_count * 2; + use_fast_fed = 1; + +/* all needed slopes available. we did even decide which mode to use. + what next? + - transfer slopes +SCAN: +flags \ use_fast_fed ! 0 1 +------------------------\-------------------- + 0 ! 0,1,2 0,1,2,3 +MotorFlag::AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 +OFF: none +FEED: 3 +GO_HOME: 3 +HOME_FREE: 3 + - setup registers + * slope specific registers (already done) + * DECSEL for HOME_FREE/GO_HOME/SCAN + * FEEDL + * MTRREV + * MTRPWR + * FASTFED + * STEPSEL + * MTRPWM + * FSTPSEL + * FASTPWM + * HOMENEG + * BWDSTEP + * FWDSTEP + * Z1 + * Z2 + */ + + r = sanei_genesys_get_address(reg, 0x3d); + r->value = (feedl >> 16) & 0xf; + r = sanei_genesys_get_address(reg, 0x3e); + r->value = (feedl >> 8) & 0xff; + r = sanei_genesys_get_address(reg, 0x3f); + r->value = feedl & 0xff; + r = sanei_genesys_get_address(reg, 0x5e); + r->value &= ~0xe0; + + r = sanei_genesys_get_address(reg, 0x25); + r->value = 0; + r = sanei_genesys_get_address(reg, 0x26); + r->value = 0; + r = sanei_genesys_get_address(reg, 0x27); + r->value = 0; + + r = sanei_genesys_get_address(reg, 0x02); + r->value &= ~0x01; /*LONGCURV OFF*/ + r->value &= ~0x80; /*NOT_HOME OFF*/ + + r->value |= 0x10; + + if (action == MOTOR_ACTION_GO_HOME) + r->value |= 0x06; + else + r->value &= ~0x06; + + if (use_fast_fed) + r->value |= 0x08; + else + r->value &= ~0x08; + + if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { + r->value |= 0x20; + } else { + r->value &= ~0x20; + } + + r->value &= ~0x40; + + if (has_flag(flags, MotorFlag::REVERSE)) { + r->value |= REG_0x02_MTRREV; + } + + gl841_send_slope_table(dev, 3, fast_table.table, 256); + + r = sanei_genesys_get_address(reg, 0x67); + r->value = 0x3f; + + r = sanei_genesys_get_address(reg, 0x68); + r->value = 0x3f; + + r = sanei_genesys_get_address(reg, REG_STEPNO); + r->value = 0; + + r = sanei_genesys_get_address(reg, REG_FASTNO); + r->value = 0; + + r = sanei_genesys_get_address(reg, 0x69); + r->value = 0; + + r = sanei_genesys_get_address(reg, 0x6a); + r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1); + + r = sanei_genesys_get_address(reg, 0x5f); + r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1); +} + +static void gl841_init_motor_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + unsigned int scan_exposure_time,/*pixel*/ + unsigned scan_yres, // dpi, motor resolution + StepType scan_step_type, + unsigned int scan_lines,/*lines, scan resolution*/ + unsigned int scan_dummy, + // number of scan lines to add in a scan_lines line + unsigned int feed_steps,/*1/base_ydpi*/ + // maybe float for half/quarter step resolution? + MotorFlag flags) +{ + DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, scan_yres=%d, scan_step_type=%d, scan_lines=%d," + " scan_dummy=%d, feed_steps=%d, flags=%x", + scan_exposure_time, scan_yres, static_cast(scan_step_type), + scan_lines, scan_dummy, feed_steps, static_cast(flags)); + unsigned int fast_exposure; + int use_fast_fed = 0; + unsigned int fast_time; + unsigned int slow_time; + unsigned int feedl; + GenesysRegister* r; + unsigned int min_restep = 0x20; + uint32_t z1, z2; + + fast_exposure = gl841_exposure_time(dev, sensor, + dev->motor.base_ydpi / 4, + StepType::FULL, + 0, + 0); + + DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); + + { + std::vector table; + table.resize(256, 0xffff); + + gl841_send_slope_table(dev, 0, table, 256); + gl841_send_slope_table(dev, 1, table, 256); + gl841_send_slope_table(dev, 2, table, 256); + gl841_send_slope_table(dev, 3, table, 256); + gl841_send_slope_table(dev, 4, table, 256); + } + + + /* motor frequency table */ + gl841_write_freq(dev, scan_yres); + +/* + we calculate both tables for SCAN. the fast slope step count depends on + how many steps we need for slow acceleration and how much steps we are + allowed to use. + */ + + auto slow_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor, + scan_step_type, scan_exposure_time, + scan_yres); + + auto back_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor, + scan_step_type, 0, scan_yres); + + if (feed_steps < (slow_table.steps_count >> static_cast(scan_step_type))) { + /*TODO: what should we do here?? go back to exposure calculation?*/ + feed_steps = slow_table.steps_count >> static_cast(scan_step_type); + } + + auto fast_table = sanei_genesys_create_slope_table3(dev->model->asic_type, dev->motor, + StepType::FULL, fast_exposure, + dev->motor.base_ydpi / 4); + + unsigned max_fast_slope_steps_count = 1; + if (feed_steps > (slow_table.steps_count >> static_cast(scan_step_type)) + 2) { + max_fast_slope_steps_count = (feed_steps - + (slow_table.steps_count >> static_cast(scan_step_type))) / 2; + } + + if (fast_table.steps_count > max_fast_slope_steps_count) { + fast_table.slice_steps(max_fast_slope_steps_count); + } + + /* fast fed special cases handling */ + if (dev->model->gpio_id == GpioId::XP300 + || dev->model->gpio_id == GpioId::DP685) + { + /* quirk: looks like at least this scanner is unable to use + 2-feed mode */ + use_fast_fed = 0; + } + else if (feed_steps < fast_table.steps_count * 2 + + (slow_table.steps_count >> static_cast(scan_step_type))) + { + use_fast_fed = 0; + DBG(DBG_info, "%s: feed too short, slow move forced.\n", __func__); + } else { +/* for deciding whether we should use fast mode we need to check how long we + need for (fast)accelerating, moving, decelerating, (TODO: stopping?) + (slow)accelerating again versus (slow)accelerating and moving. we need + fast and slow tables here. +*/ +/*NOTE: scan_exposure_time is per scan_yres*/ +/*NOTE: fast_exposure is per base_ydpi/4*/ +/*we use full steps as base unit here*/ + fast_time = + fast_exposure / 4 * + (feed_steps - fast_table.steps_count*2 - + (slow_table.steps_count >> static_cast(scan_step_type))) + + fast_table.pixeltime_sum*2 + slow_table.pixeltime_sum; + slow_time = + (scan_exposure_time * scan_yres) / dev->motor.base_ydpi * + (feed_steps - (slow_table.steps_count >> static_cast(scan_step_type))) + + slow_table.pixeltime_sum; + + DBG(DBG_info, "%s: Time for slow move: %d\n", __func__, slow_time); + DBG(DBG_info, "%s: Time for fast move: %d\n", __func__, fast_time); + + use_fast_fed = fast_time < slow_time; + } + + if (use_fast_fed) { + feedl = feed_steps - fast_table.steps_count * 2 - + (slow_table.steps_count >> static_cast(scan_step_type)); + } else if ((feed_steps << static_cast(scan_step_type)) < slow_table.steps_count) { + feedl = 0; + } else { + feedl = (feed_steps << static_cast(scan_step_type)) - slow_table.steps_count; + } + DBG(DBG_info, "%s: Decided to use %s mode\n", __func__, use_fast_fed?"fast feed":"slow feed"); + +/* all needed slopes available. we did even decide which mode to use. + what next? + - transfer slopes +SCAN: +flags \ use_fast_fed ! 0 1 +------------------------\-------------------- + 0 ! 0,1,2 0,1,2,3 +MotorFlag::AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 +OFF: none +FEED: 3 +GO_HOME: 3 +HOME_FREE: 3 + - setup registers + * slope specific registers (already done) + * DECSEL for HOME_FREE/GO_HOME/SCAN + * FEEDL + * MTRREV + * MTRPWR + * FASTFED + * STEPSEL + * MTRPWM + * FSTPSEL + * FASTPWM + * HOMENEG + * BWDSTEP + * FWDSTEP + * Z1 + * Z2 + */ + + r = sanei_genesys_get_address (reg, 0x3d); + r->value = (feedl >> 16) & 0xf; + r = sanei_genesys_get_address (reg, 0x3e); + r->value = (feedl >> 8) & 0xff; + r = sanei_genesys_get_address (reg, 0x3f); + r->value = feedl & 0xff; + r = sanei_genesys_get_address (reg, 0x5e); + r->value &= ~0xe0; + + r = sanei_genesys_get_address (reg, 0x25); + r->value = (scan_lines >> 16) & 0xf; + r = sanei_genesys_get_address (reg, 0x26); + r->value = (scan_lines >> 8) & 0xff; + r = sanei_genesys_get_address (reg, 0x27); + r->value = scan_lines & 0xff; + + r = sanei_genesys_get_address (reg, 0x02); + r->value &= ~0x01; /*LONGCURV OFF*/ + r->value &= ~0x80; /*NOT_HOME OFF*/ + r->value |= 0x10; + + r->value &= ~0x06; + + if (use_fast_fed) + r->value |= 0x08; + else + r->value &= ~0x08; + + if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) + r->value |= 0x20; + else + r->value &= ~0x20; + + if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE)) { + r->value |= 0x40; + } else { + r->value &= ~0x40; + } + + gl841_send_slope_table(dev, 0, slow_table.table, 256); + + gl841_send_slope_table(dev, 1, back_table.table, 256); + + gl841_send_slope_table(dev, 2, slow_table.table, 256); + + if (use_fast_fed) { + gl841_send_slope_table(dev, 3, fast_table.table, 256); + } + + if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { + gl841_send_slope_table(dev, 4, fast_table.table, 256); + } + +/* now reg 0x21 and 0x24 are available, we can calculate reg 0x22 and 0x23, + reg 0x60-0x62 and reg 0x63-0x65 + rule: + 2*STEPNO+FWDSTEP=2*FASTNO+BWDSTEP +*/ +/* steps of table 0*/ + if (min_restep < slow_table.steps_count * 2 + 2) { + min_restep = slow_table.steps_count * 2 + 2; + } +/* steps of table 1*/ + if (min_restep < back_table.steps_count * 2 + 2) { + min_restep = back_table.steps_count * 2 + 2; + } +/* steps of table 0*/ + r = sanei_genesys_get_address(reg, REG_FWDSTEP); + r->value = min_restep - slow_table.steps_count*2; +/* steps of table 1*/ + r = sanei_genesys_get_address(reg, REG_BWDSTEP); + r->value = min_restep - back_table.steps_count*2; + +/* + for z1/z2: + in dokumentation mentioned variables a-d: + a = time needed for acceleration, table 1 + b = time needed for reg 0x1f... wouldn't that be reg0x1f*exposure_time? + c = time needed for acceleration, table 1 + d = time needed for reg 0x22... wouldn't that be reg0x22*exposure_time? + z1 = (c+d-1) % exposure_time + z2 = (a+b-1) % exposure_time +*/ +/* i don't see any effect of this. i can only guess that this will enhance + sub-pixel accuracy + z1 = (slope_0_time-1) % exposure_time; + z2 = (slope_0_time-1) % exposure_time; +*/ + z1 = z2 = 0; + + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + r = sanei_genesys_get_address (reg, 0x60); + r->value = ((z1 >> 16) & 0xff); + r = sanei_genesys_get_address (reg, 0x61); + r->value = ((z1 >> 8) & 0xff); + r = sanei_genesys_get_address (reg, 0x62); + r->value = (z1 & 0xff); + r = sanei_genesys_get_address (reg, 0x63); + r->value = ((z2 >> 16) & 0xff); + r = sanei_genesys_get_address (reg, 0x64); + r->value = ((z2 >> 8) & 0xff); + r = sanei_genesys_get_address (reg, 0x65); + r->value = (z2 & 0xff); + + r = sanei_genesys_get_address(reg, REG_0x1E); + r->value &= REG_0x1E_WDTIME; + r->value |= scan_dummy; + + r = sanei_genesys_get_address (reg, 0x67); + r->value = 0x3f | (static_cast(scan_step_type) << 6); + + r = sanei_genesys_get_address (reg, 0x68); + r->value = 0x3f; + + r = sanei_genesys_get_address(reg, REG_STEPNO); + r->value = (slow_table.steps_count >> 1) + (slow_table.steps_count & 1); + + r = sanei_genesys_get_address(reg, REG_FASTNO); + r->value = (back_table.steps_count >> 1) + (back_table.steps_count & 1); + + r = sanei_genesys_get_address (reg, 0x69); + r->value = (slow_table.steps_count >> 1) + (slow_table.steps_count & 1); + + r = sanei_genesys_get_address (reg, 0x6a); + r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1); + + r = sanei_genesys_get_address (reg, 0x5f); + r->value = (fast_table.steps_count >> 1) + (fast_table.steps_count & 1); +} + +static int +gl841_get_dpihw(Genesys_Device * dev) +{ + GenesysRegister* r; + r = sanei_genesys_get_address(&dev->reg, 0x05); + if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_600) { + return 600; + } + if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_1200) { + return 1200; + } + if ((r->value & REG_0x05_DPIHW) == REG_0x05_DPIHW_2400) { + return 2400; + } + return 0; +} + +static void gl841_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, unsigned int exposure_time, + const ScanSession& session) +{ + DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time); + GenesysRegister* r; + uint16_t expavg, expr, expb, expg; + + dev->cmd_set->set_fe(dev, sensor, AFE_SET); + + /* gpio part.*/ + if (dev->model->gpio_id == GpioId::CANON_LIDE_35) { + r = sanei_genesys_get_address(reg, REG_0x6C); + if (session.ccd_size_divisor > 1) { + r->value &= ~0x80; + } else { + r->value |= 0x80; + } + } + if (dev->model->gpio_id == GpioId::CANON_LIDE_80) { + r = sanei_genesys_get_address(reg, REG_0x6C); + if (session.ccd_size_divisor > 1) { + r->value &= ~0x40; + r->value |= 0x20; + } else { + r->value &= ~0x20; + r->value |= 0x40; + } + } + + /* enable shading */ + r = sanei_genesys_get_address (reg, 0x01); + r->value |= REG_0x01_SCAN; + if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) { + r->value &= ~REG_0x01_DVDSET; + } else { + r->value |= REG_0x01_DVDSET; + } + + /* average looks better than deletion, and we are already set up to + use one of the average enabled resolutions + */ + r = sanei_genesys_get_address (reg, 0x03); + r->value |= REG_0x03_AVEENB; + sanei_genesys_set_lamp_power(dev, sensor, *reg, + !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); + + /* BW threshold */ + r = sanei_genesys_get_address (reg, 0x2e); + r->value = dev->settings.threshold; + r = sanei_genesys_get_address (reg, 0x2f); + r->value = dev->settings.threshold; + + + /* monochrome / color scan */ + r = sanei_genesys_get_address (reg, 0x04); + switch (session.params.depth) { + case 8: + r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); + break; + case 16: + r->value &= ~REG_0x04_LINEART; + r->value |= REG_0x04_BITSET; + break; + } + + /* AFEMOD should depend on FESET, and we should set these + * bits separately */ + r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); + if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) { + r->value |= 0x10; /* no filter */ + } + else if (session.params.channels == 1) + { + switch (session.params.color_filter) + { + case ColorFilter::RED: + r->value |= 0x14; + break; + case ColorFilter::GREEN: + r->value |= 0x18; + break; + case ColorFilter::BLUE: + r->value |= 0x1c; + break; + default: + r->value |= 0x10; + break; + } + } + else + { + if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) { + r->value |= 0x22; /* slow color pixel by pixel */ + } + else + { + r->value |= 0x10; /* color pixel by pixel */ + } + } + + /* CIS scanners can do true gray by setting LEDADD */ + r = sanei_genesys_get_address (reg, 0x87); + r->value &= ~REG_0x87_LEDADD; + if (has_flag(session.params.flags, ScanFlag::ENABLE_LEDADD)) { + r->value |= REG_0x87_LEDADD; + expr = reg->get16(REG_EXPR); + expg = reg->get16(REG_EXPG); + expb = reg->get16(REG_EXPB); + + /* use minimal exposure for best image quality */ + expavg = expg; + if (expr < expg) + expavg = expr; + if (expb < expavg) + expavg = expb; + + dev->reg.set16(REG_EXPR, expavg); + dev->reg.set16(REG_EXPG, expavg); + dev->reg.set16(REG_EXPB, expavg); + } + + // enable gamma tables + if (should_enable_gamma(session, sensor)) { + reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB; + } else { + reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB; + } + + /* sensor parameters */ + sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 1, session.ccd_size_divisor); + + r = sanei_genesys_get_address (reg, 0x29); + r->value = 255; /*<<<"magic" number, only suitable for cis*/ + + reg->set16(REG_DPISET, gl841_get_dpihw(dev) * session.output_resolution / session.optical_resolution); + reg->set16(REG_STRPIXEL, session.pixel_startx); + reg->set16(REG_ENDPIXEL, session.pixel_endx); + + reg->set24(REG_MAXWD, session.output_line_bytes); + + reg->set16(REG_LPERIOD, exposure_time); + + r = sanei_genesys_get_address (reg, 0x34); + r->value = sensor.dummy_pixel; +} + +static int +gl841_get_led_exposure(Genesys_Device * dev, const Genesys_Sensor& sensor) +{ + int d,r,g,b,m; + if (!dev->model->is_cis) + return 0; + d = dev->reg.find_reg(0x19).value; + + r = sensor.exposure.red; + g = sensor.exposure.green; + b = sensor.exposure.blue; + + m = r; + if (m < g) + m = g; + if (m < b) + m = b; + + return m + d; +} + +/** @brief compute exposure time + * Compute exposure time for the device and the given scan resolution + */ +static int +gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, + float slope_dpi, + StepType scan_step_type, + int start, + int used_pixels) +{ +int exposure_time = 0; +int led_exposure; + + led_exposure=gl841_get_led_exposure(dev, sensor); + exposure_time = sanei_genesys_exposure_time2( + dev, + slope_dpi, + scan_step_type, + start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ + led_exposure); + + return exposure_time; +} + +/**@brief compute scan_step_type + * Try to do at least 4 steps per line. if that is impossible we will have to + * live with that. + * @param dev device + * @param yres motor resolution + */ +static StepType gl841_scan_step_type(Genesys_Device *dev, int yres) +{ + StepType type = StepType::FULL; + + /* TODO : check if there is a bug around the use of max_step_type */ + /* should be <=1, need to chek all devices entry in genesys_devices */ + if (yres * 4 < dev->motor.base_ydpi || dev->motor.max_step_type() == StepType::FULL) { + type = StepType::FULL; + } else if (yres * 4 < dev->motor.base_ydpi * 2 || + dev->motor.max_step_type() <= StepType::HALF) + { + type = StepType::HALF; + } else { + type = StepType::QUARTER; + } + + /* this motor behaves differently */ + if (dev->model->motor_id==MotorId::CANON_LIDE_80) { + // driven by 'frequency' tables ? + type = StepType::FULL; + } + + return type; +} + +void CommandSetGl841::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const +{ + DBG_HELPER(dbg); + session.assert_computed(); + + int move; + int exposure_time; + + int slope_dpi = 0; + int dummy = 0; + +/* +results: + +for scanner: +start +end +dpiset +exposure_time +dummy +z1 +z2 + +for ordered_read: + dev->words_per_line + dev->read_factor + dev->requested_buffer_size + dev->read_buffer_size + dev->read_pos + dev->read_bytes_in_buffer + dev->read_bytes_left + dev->max_shift + dev->stagger + +independent of our calculated values: + dev->total_bytes_read + dev->bytes_to_read + */ + +/* dummy */ + /* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1 + dummy line. Maybe the dummy line adds correctness since the motor runs + slower (higher dpi) + */ +/* for cis this creates better aligned color lines: +dummy \ scanned lines + 0: R G B R ... + 1: R G B - R ... + 2: R G B - - R ... + 3: R G B - - - R ... + 4: R G B - - - - R ... + 5: R G B - - - - - R ... + 6: R G B - - - - - - R ... + 7: R G B - - - - - - - R ... + 8: R G B - - - - - - - - R ... + 9: R G B - - - - - - - - - R ... + 10: R G B - - - - - - - - - - R ... + 11: R G B - - - - - - - - - - - R ... + 12: R G B - - - - - - - - - - - - R ... + 13: R G B - - - - - - - - - - - - - R ... + 14: R G B - - - - - - - - - - - - - - R ... + 15: R G B - - - - - - - - - - - - - - - R ... + -- pierre + */ + dummy = 0; + +/* slope_dpi */ +/* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) { + slope_dpi = session.params.yres* session.params.channels; + } else { + slope_dpi = session.params.yres; + } + + slope_dpi = slope_dpi * (1 + dummy); + + StepType scan_step_type = gl841_scan_step_type(dev, session.params.yres); + exposure_time = gl841_exposure_time(dev, sensor, + slope_dpi, + scan_step_type, + session.pixel_startx, + session.optical_pixels); + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + + gl841_init_optical_regs_scan(dev, sensor, reg, exposure_time, session); + + move = session.params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + /* subtract current head position */ + move -= (dev->head_pos(ScanHeadId::PRIMARY) * session.params.yres) / dev->motor.base_ydpi; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + if (move < 0) + move = 0; + + /* round it */ +/* the move is not affected by dummy -- pierre */ +/* move = ((move + dummy) / (dummy + 1)) * (dummy + 1); + DBG(DBG_info, "%s: move=%d steps\n", __func__, move);*/ + + if (has_flag(session.params.flags, ScanFlag::SINGLE_LINE)) { + gl841_init_motor_regs_off(reg, dev->model->is_cis ? session.output_line_count * session.params.channels + : session.output_line_count); + } else { + auto motor_flag = has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE) ? + MotorFlag::DISABLE_BUFFER_FULL_MOVE : MotorFlag::NONE; + + gl841_init_motor_regs_scan(dev, sensor, reg, exposure_time, slope_dpi, scan_step_type, + dev->model->is_cis ? session.output_line_count * session.params.channels + : session.output_line_count, + dummy, move, motor_flag); + } + + dev->read_buffer.clear(); + dev->read_buffer.alloc(session.buffer_size_read); + + build_image_pipeline(dev, session); + + dev->read_active = true; + + dev->session = session; + + dev->total_bytes_read = 0; + dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines; + + DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read); +} + +ScanSession CommandSetGl841::calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const +{ + int start; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, settings); + +/* start */ + start = static_cast(dev->model->x_offset); + start += static_cast(settings.tl_x); + + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = settings.xres; + session.params.yres = settings.yres; + session.params.startx = start; + session.params.starty = 0; // not used + session.params.pixels = settings.pixels; + session.params.requested_pixels = settings.requested_pixels; + session.params.lines = settings.lines; + session.params.depth = settings.depth; + session.params.channels = settings.get_channels(); + session.params.scan_method = settings.scan_method; + session.params.scan_mode = settings.scan_mode; + session.params.color_filter = settings.color_filter; + session.params.flags = ScanFlag::NONE; + + compute_session(dev, session, sensor); + + return session; +} + +// for fast power saving methods only, like disabling certain amplifiers +void CommandSetGl841::save_power(Genesys_Device* dev, bool enable) const +{ + DBG_HELPER_ARGS(dbg, "enable = %d", enable); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + if (enable) + { + if (dev->model->gpio_id == GpioId::CANON_LIDE_35) + { +/* expect GPIO17 to be enabled, and GPIO9 to be disabled, + while GPIO8 is disabled*/ +/* final state: GPIO8 disabled, GPIO9 enabled, GPIO17 disabled, + GPIO18 disabled*/ + + uint8_t val = dev->interface->read_register(REG_0x6D); + dev->interface->write_register(REG_0x6D, val | 0x80); + + dev->interface->sleep_ms(1); + + /*enable GPIO9*/ + val = dev->interface->read_register(REG_0x6C); + dev->interface->write_register(REG_0x6C, val | 0x01); + + /*disable GPO17*/ + val = dev->interface->read_register(REG_0x6B); + dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO17); + + /*disable GPO18*/ + val = dev->interface->read_register(REG_0x6B); + dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO18); + + dev->interface->sleep_ms(1); + + val = dev->interface->read_register(REG_0x6D); + dev->interface->write_register(REG_0x6D, val & ~0x80); + + } + if (dev->model->gpio_id == GpioId::DP685) + { + uint8_t val = dev->interface->read_register(REG_0x6B); + dev->interface->write_register(REG_0x6B, val & ~REG_0x6B_GPO17); + dev->reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17; + dev->calib_reg.find_reg(0x6b).value &= ~REG_0x6B_GPO17; + } + + set_fe(dev, sensor, AFE_POWER_SAVE); + + } + else + { + if (dev->model->gpio_id == GpioId::CANON_LIDE_35) + { +/* expect GPIO17 to be enabled, and GPIO9 to be disabled, + while GPIO8 is disabled*/ +/* final state: GPIO8 enabled, GPIO9 disabled, GPIO17 enabled, + GPIO18 enabled*/ + + uint8_t val = dev->interface->read_register(REG_0x6D); + dev->interface->write_register(REG_0x6D, val | 0x80); + + dev->interface->sleep_ms(10); + + /*disable GPIO9*/ + val = dev->interface->read_register(REG_0x6C); + dev->interface->write_register(REG_0x6C, val & ~0x01); + + /*enable GPIO10*/ + val = dev->interface->read_register(REG_0x6C); + dev->interface->write_register(REG_0x6C, val | 0x02); + + /*enable GPO17*/ + val = dev->interface->read_register(REG_0x6B); + dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17); + dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17; + dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO17; + + /*enable GPO18*/ + val = dev->interface->read_register(REG_0x6B); + dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO18); + dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO18; + dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO18; + + } + if (dev->model->gpio_id == GpioId::DP665 + || dev->model->gpio_id == GpioId::DP685) + { + uint8_t val = dev->interface->read_register(REG_0x6B); + dev->interface->write_register(REG_0x6B, val | REG_0x6B_GPO17); + dev->reg.find_reg(0x6b).value |= REG_0x6B_GPO17; + dev->calib_reg.find_reg(0x6b).value |= REG_0x6B_GPO17; + } + + } +} + +void CommandSetGl841::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const +{ + DBG_HELPER_ARGS(dbg, "delay = %d", delay); + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); + int rate, exposure_time, tgtime, time; + + local_reg.init_reg(0x01, dev->reg.get8(0x01)); /* disable fastmode */ + local_reg.init_reg(0x03, dev->reg.get8(0x03)); /* Lamp power control */ + local_reg.init_reg(0x05, dev->reg.get8(0x05)); /*& ~REG_0x05_BASESEL*/; /* 24 clocks/pixel */ + local_reg.init_reg(0x18, 0x00); // Set CCD type + local_reg.init_reg(0x38, 0x00); + local_reg.init_reg(0x39, 0x00); + + // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE + local_reg.init_reg(0x1c, dev->reg.get8(0x05) & ~REG_0x1C_TGTIME); + + if (!delay) { + local_reg.find_reg(0x03).value = local_reg.find_reg(0x03).value & 0xf0; /* disable lampdog and set lamptime = 0 */ + } else if (delay < 20) { + local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ + } else { + local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ + } + + time = delay * 1000 * 60; /* -> msec */ + exposure_time = static_cast(time * 32000.0 / + (24.0 * 64.0 * (local_reg.find_reg(0x03).value & REG_0x03_LAMPTIM) * + 1024.0) + 0.5); + /* 32000 = system clock, 24 = clocks per pixel */ + rate = (exposure_time + 65536) / 65536; + if (rate > 4) + { + rate = 8; + tgtime = 3; + } + else if (rate > 2) + { + rate = 4; + tgtime = 2; + } + else if (rate > 1) + { + rate = 2; + tgtime = 1; + } + else + { + rate = 1; + tgtime = 0; + } + + local_reg.find_reg(0x1c).value |= tgtime; + exposure_time /= rate; + + if (exposure_time > 65535) + exposure_time = 65535; + + local_reg.set8(0x38, exposure_time >> 8); + local_reg.set8(0x39, exposure_time & 255); /* lowbyte */ + + dev->interface->write_registers(local_reg); +} + +static void gl841_stop_action(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + Genesys_Register_Set local_reg; + unsigned int loop; + + scanner_read_print_status(*dev); + + if (scanner_is_motor_stopped(*dev)) { + DBG(DBG_info, "%s: already stopped\n", __func__); + return; + } + + local_reg = dev->reg; + + regs_set_optical_off(dev->model->asic_type, local_reg); + + gl841_init_motor_regs_off(&local_reg,0); + dev->interface->write_registers(local_reg); + + if (is_testing_mode()) { + return; + } + + /* looks like writing the right registers to zero is enough to get the chip + out of scan mode into command mode, actually triggering(writing to + register 0x0f) seems to be unnecessary */ + + loop = 10; + while (loop > 0) { + if (scanner_is_motor_stopped(*dev)) { + return; + } + + dev->interface->sleep_ms(100); + loop--; + } + + throw SaneException(SANE_STATUS_IO_ERROR, "could not stop motor"); +} + +static bool gl841_get_paper_sensor(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + + uint8_t val = dev->interface->read_register(REG_0x6D); + + return (val & 0x1) == 0; +} + +void CommandSetGl841::eject_document(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + Genesys_Register_Set local_reg; + unsigned int init_steps; + float feed_mm; + int loop; + + if (!dev->model->is_sheetfed) { + DBG(DBG_proc, "%s: there is no \"eject sheet\"-concept for non sheet fed\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + return; + } + + + local_reg.clear(); + + // FIXME: unused result + scanner_read_status(*dev); + + gl841_stop_action(dev); + + local_reg = dev->reg; + + regs_set_optical_off(dev->model->asic_type, local_reg); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + gl841_init_motor_regs(dev, sensor, &local_reg, 65536, MOTOR_ACTION_FEED, MotorFlag::NONE); + + dev->interface->write_registers(local_reg); + + try { + scanner_start_action(*dev, true); + } catch (...) { + catch_all_exceptions(__func__, [&]() { gl841_stop_action(dev); }); + // restore original registers + catch_all_exceptions(__func__, [&]() + { + dev->interface->write_registers(dev->reg); + }); + throw; + } + + if (is_testing_mode()) { + dev->interface->test_checkpoint("eject_document"); + gl841_stop_action(dev); + return; + } + + if (gl841_get_paper_sensor(dev)) { + DBG(DBG_info, "%s: paper still loaded\n", __func__); + /* force document TRUE, because it is definitely present */ + dev->document = true; + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + + loop = 300; + while (loop > 0) /* do not wait longer then 30 seconds */ + { + + if (!gl841_get_paper_sensor(dev)) { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + break; + } + dev->interface->sleep_ms(100); + --loop; + } + + if (loop == 0) + { + // when we come here then the scanner needed too much time for this, so we better stop + // the motor + catch_all_exceptions(__func__, [&](){ gl841_stop_action(dev); }); + throw SaneException(SANE_STATUS_IO_ERROR, + "timeout while waiting for scanhead to go home"); + } + } + + feed_mm = static_cast(dev->model->eject_feed); + if (dev->document) + { + feed_mm += static_cast(dev->model->post_scan); + } + + sanei_genesys_read_feed_steps(dev, &init_steps); + + /* now feed for extra steps */ + loop = 0; + while (loop < 300) /* do not wait longer then 30 seconds */ + { + unsigned int steps; + + sanei_genesys_read_feed_steps(dev, &steps); + + DBG(DBG_info, "%s: init_steps: %d, steps: %d\n", __func__, init_steps, steps); + + if (steps > init_steps + (feed_mm * dev->motor.base_ydpi) / MM_PER_INCH) + { + break; + } + + dev->interface->sleep_ms(100); + ++loop; + } + + gl841_stop_action(dev); + + dev->document = false; +} + + +void CommandSetGl841::load_document(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + int loop = 300; + while (loop > 0) /* do not wait longer then 30 seconds */ + { + if (gl841_get_paper_sensor(dev)) { + DBG(DBG_info, "%s: document inserted\n", __func__); + + /* when loading OK, document is here */ + dev->document = true; + + // give user some time to place document correctly + dev->interface->sleep_ms(1000); + break; + } + dev->interface->sleep_ms(100); + --loop; + } + + if (loop == 0) + { + // when we come here then the user needed to much time for this + throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for document"); + } +} + +/** + * detects end of document and adjust current scan + * to take it into account + * used by sheetfed scanners + */ +void CommandSetGl841::detect_document_end(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + bool paper_loaded = gl841_get_paper_sensor(dev); + + /* sheetfed scanner uses home sensor as paper present */ + if (dev->document && !paper_loaded) { + DBG(DBG_info, "%s: no more document\n", __func__); + dev->document = false; + + /* we can't rely on total_bytes_to_read since the frontend + * might have been slow to read data, so we re-evaluate the + * amount of data to scan form the hardware settings + */ + unsigned scanned_lines = 0; + try { + sanei_genesys_read_scancnt(dev, &scanned_lines); + } catch (...) { + dev->total_bytes_to_read = dev->total_bytes_read; + throw; + } + + if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS && dev->model->is_cis) { + scanned_lines /= 3; + } + + std::size_t output_lines = dev->session.output_line_count; + + std::size_t offset_lines = static_cast( + (dev->model->post_scan / MM_PER_INCH) * dev->settings.yres); + + std::size_t scan_end_lines = scanned_lines + offset_lines; + + std::size_t remaining_lines = dev->get_pipeline_source().remaining_bytes() / + dev->session.output_line_bytes_raw; + + DBG(DBG_io, "%s: scanned_lines=%u\n", __func__, scanned_lines); + DBG(DBG_io, "%s: scan_end_lines=%zu\n", __func__, scan_end_lines); + DBG(DBG_io, "%s: output_lines=%zu\n", __func__, output_lines); + DBG(DBG_io, "%s: remaining_lines=%zu\n", __func__, remaining_lines); + + if (scan_end_lines > output_lines) { + auto skip_lines = scan_end_lines - output_lines; + + if (remaining_lines > skip_lines) { + DBG(DBG_io, "%s: skip_lines=%zu\n", __func__, skip_lines); + + remaining_lines -= skip_lines; + dev->get_pipeline_source().set_remaining_bytes(remaining_lines * + dev->session.output_line_bytes_raw); + dev->total_bytes_to_read -= skip_lines * dev->session.output_line_bytes_requested; + } + } + } +} + +// Send the low-level scan command +// todo : is this that useful ? +void CommandSetGl841::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, bool start_motor) const +{ + DBG_HELPER(dbg); + (void) sensor; + // FIXME: SEQUENTIAL not really needed in this case + Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); + uint8_t val; + + if (dev->model->gpio_id == GpioId::CANON_LIDE_80) { + val = dev->interface->read_register(REG_0x6B); + val = REG_0x6B_GPO18; + dev->interface->write_register(REG_0x6B, val); + } + + if (dev->model->sensor_id != SensorId::CCD_PLUSTEK_OPTICPRO_3600) { + local_reg.init_reg(0x03, reg->get8(0x03) | REG_0x03_LAMPPWR); + } else { + // TODO PLUSTEK_3600: why ?? + local_reg.init_reg(0x03, reg->get8(0x03)); + } + + local_reg.init_reg(0x01, reg->get8(0x01) | REG_0x01_SCAN); + local_reg.init_reg(0x0d, 0x01); + + // scanner_start_action(dev, start_motor) + if (start_motor) { + local_reg.init_reg(0x0f, 0x01); + } else { + // do not start motor yet + local_reg.init_reg(0x0f, 0x00); + } + + dev->interface->write_registers(local_reg); + + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); +} + + +// Send the stop scan command +void CommandSetGl841::end_scan(Genesys_Device* dev, Genesys_Register_Set __sane_unused__* reg, + bool check_stop) const +{ + DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop); + + if (!dev->model->is_sheetfed) { + gl841_stop_action(dev); + } +} + +// Moves the slider to steps +static void gl841_feed(Genesys_Device* dev, int steps) +{ + DBG_HELPER_ARGS(dbg, "steps = %d", steps); + Genesys_Register_Set local_reg; + int loop; + + gl841_stop_action(dev); + + // FIXME: we should pick sensor according to the resolution scanner is currently operating on + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + local_reg = dev->reg; + + regs_set_optical_off(dev->model->asic_type, local_reg); + + gl841_init_motor_regs(dev, sensor, &local_reg, steps, MOTOR_ACTION_FEED, MotorFlag::NONE); + + dev->interface->write_registers(local_reg); + + try { + scanner_start_action(*dev, true); + } catch (...) { + catch_all_exceptions(__func__, [&]() { gl841_stop_action (dev); }); + // restore original registers + catch_all_exceptions(__func__, [&]() + { + dev->interface->write_registers(dev->reg); + }); + throw; + } + + if (is_testing_mode()) { + dev->interface->test_checkpoint("feed"); + dev->advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::FORWARD, steps); + gl841_stop_action(dev); + return; + } + + loop = 0; + while (loop < 300) /* do not wait longer then 30 seconds */ + { + auto status = scanner_read_status(*dev); + + if (!status.is_motor_enabled) { + DBG(DBG_proc, "%s: finished\n", __func__); + dev->advance_head_pos_by_steps(ScanHeadId::PRIMARY, Direction::FORWARD, steps); + return; + } + dev->interface->sleep_ms(100); + ++loop; + } + + /* when we come here then the scanner needed too much time for this, so we better stop the motor */ + gl841_stop_action (dev); + + dev->set_head_pos_unknown(); + + throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home"); +} + +// Moves the slider to the home (top) position slowly +void CommandSetGl841::move_back_home(Genesys_Device* dev, bool wait_until_home) const +{ + DBG_HELPER_ARGS(dbg, "wait_until_home = %d", wait_until_home); + Genesys_Register_Set local_reg; + int loop = 0; + + if (dev->model->is_sheetfed) { + DBG(DBG_proc, "%s: there is no \"home\"-concept for sheet fed\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + return; + } + + // reset gpio pin + uint8_t val; + if (dev->model->gpio_id == GpioId::CANON_LIDE_35) { + val = dev->interface->read_register(REG_0x6C); + val = dev->gpo.regs.get_value(0x6c); + dev->interface->write_register(REG_0x6C, val); + } + if (dev->model->gpio_id == GpioId::CANON_LIDE_80) { + val = dev->interface->read_register(REG_0x6B); + val = REG_0x6B_GPO18 | REG_0x6B_GPO17; + dev->interface->write_register(REG_0x6B, val); + } + dev->cmd_set->save_power(dev, false); + + // first read gives HOME_SENSOR true + auto status = scanner_read_reliable_status(*dev); + + + if (status.is_at_home) { + DBG(DBG_info, "%s: already at home, completed\n", __func__); + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + + scanner_stop_action_no_move(*dev, dev->reg); + + /* if motor is on, stop current action */ + if (status.is_motor_enabled) { + gl841_stop_action(dev); + } + + local_reg = dev->reg; + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + gl841_init_motor_regs(dev, sensor, &local_reg, 65536, MOTOR_ACTION_GO_HOME, MotorFlag::REVERSE); + + // set up for no scan + regs_set_optical_off(dev->model->asic_type, local_reg); + + dev->interface->write_registers(local_reg); + + try { + scanner_start_action(*dev, true); + } catch (...) { + catch_all_exceptions(__func__, [&]() { gl841_stop_action(dev); }); + // restore original registers + catch_all_exceptions(__func__, [&]() + { + dev->interface->write_registers(dev->reg); + }); + throw; + } + + if (is_testing_mode()) { + dev->interface->test_checkpoint("move_back_home"); + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + + if (wait_until_home) + { + while (loop < 300) /* do not wait longer then 30 seconds */ + { + auto status = scanner_read_status(*dev); + if (status.is_at_home) { + DBG(DBG_info, "%s: reached home position\n", __func__); + DBG(DBG_proc, "%s: finished\n", __func__); + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + return; + } + dev->interface->sleep_ms(100); + ++loop; + } + + // when we come here then the scanner needed too much time for this, so we better stop + // the motor + catch_all_exceptions(__func__, [&](){ gl841_stop_action(dev); }); + dev->set_head_pos_unknown(); + throw SaneException(SANE_STATUS_IO_ERROR, "timeout while waiting for scanhead to go home"); + } + + DBG(DBG_info, "%s: scanhead is still moving\n", __func__); +} + +// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi +// from very top of scanner +void CommandSetGl841::search_start_position(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + int size; + Genesys_Register_Set local_reg; + + int pixels = 600; + int dpi = 300; + + local_reg = dev->reg; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method); + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; /*we should give a small offset here~60 steps*/ + session.params.pixels = 600; + session.params.lines = dev->model->search_lines; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::GREEN; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::IGNORE_LINE_DISTANCE | + ScanFlag::DISABLE_BUFFER_FULL_MOVE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &local_reg, session); + + // send to scanner + dev->interface->write_registers(local_reg); + + size = pixels * dev->model->search_lines; + + std::vector data(size); + + dev->cmd_set->begin_scan(dev, sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_start_position"); + dev->cmd_set->end_scan(dev, &local_reg, true); + dev->reg = local_reg; + return; + } + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl841_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + } + + dev->cmd_set->end_scan(dev, &local_reg, true); + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + + for (auto& sensor_update : + sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) + { + sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels, + dev->model->search_lines); + } +} + +// sets up register for coarse gain calibration +// todo: check it for scanners using it +void CommandSetGl841::init_regs_for_coarse_calibration(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel(); + session.params.lines = 20; + session.params.depth = 16; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, ®s, session); + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres); + + dev->interface->write_registers(regs); + +/* if (DBG_LEVEL >= DBG_info) + sanei_gl841_print_registers (regs);*/ +} + + +// init registers for shading calibration +void CommandSetGl841::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER_ARGS(dbg, "lines = %zu", dev->calib_lines); + SANE_Int ydpi; + unsigned starty = 0; + + /* initial calibration reg values */ + regs = dev->reg; + + ydpi = dev->motor.base_ydpi; + if (dev->model->motor_id == MotorId::PLUSTEK_OPTICPRO_3600) /* TODO PLUSTEK_3600: 1200dpi not yet working, produces dark bar */ + { + ydpi = 600; + } + if (dev->model->motor_id == MotorId::CANON_LIDE_80) { + ydpi = gl841_get_dpihw(dev); + /* get over extra dark area for this model. + It looks like different devices have dark areas of different width + due to manufacturing variability. The initial value of starty was 140, + but it moves the sensor almost past the dark area completely in places + on certain devices. + + On a particular device the black area starts at roughly position + 160 to 230 depending on location (the dark area is not completely + parallel to the frame). + */ + starty = 70; + } + + dev->calib_channels = 3; + dev->calib_lines = dev->model->shading_lines; + + unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); + unsigned factor = sensor.optical_res / resolution; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, dev->calib_channels, + dev->settings.scan_method); + + dev->calib_pixels = calib_sensor.sensor_pixels / factor; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = ydpi; + session.params.startx = 0; + session.params.starty = starty; + session.params.pixels = dev->calib_pixels; + session.params.lines = dev->calib_lines; + session.params.depth = 16; + session.params.channels = dev->calib_channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + /*ScanFlag::DISABLE_BUFFER_FULL_MOVE |*/ + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + dev->interface->write_registers(regs); +} + +// set up registers for the actual scan +void CommandSetGl841::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + float move; + int move_dpi; + float start; + + debug_dump(DBG_info, dev->settings); + + /* steps to move to reach scanning area: + - first we move to physical start of scanning + either by a fixed steps amount from the black strip + or by a fixed amount from parking position, + minus the steps done during shading calibration + - then we move by the needed offset whitin physical + scanning area + + assumption: steps are expressed at maximum motor resolution + + we need: + float y_offset; + float y_size; + float y_offset_calib; + mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ + + /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is + relative from origin, else, it is from parking position */ + + move_dpi = dev->motor.base_ydpi; + + move = 0; + if (dev->model->flags & GENESYS_FLAG_SEARCH_START) { + move += static_cast(dev->model->y_offset_calib_white); + } + + DBG(DBG_info, "%s move=%f steps\n", __func__, move); + + move += static_cast(dev->model->y_offset); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + move += static_cast(dev->settings.tl_y); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + move = static_cast((move * move_dpi) / MM_PER_INCH); + +/* start */ + start = static_cast(dev->model->x_offset); + + start += static_cast(dev->settings.tl_x); + + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + ScanFlag flags = ScanFlag::NONE; + + /* true gray (led add for cis scanners) */ + if(dev->model->is_cis && dev->settings.true_gray + && dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS + && dev->model->sensor_id != SensorId::CIS_CANON_LIDE_80) + { + // on Lide 80 the LEDADD bit results in only red LED array being lit + DBG(DBG_io, "%s: activating LEDADD\n", __func__); + flags |= ScanFlag::ENABLE_LEDADD; + } + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = dev->settings.pixels; + session.params.requested_pixels = dev->settings.requested_pixels; + session.params.lines = dev->settings.lines; + session.params.depth = dev->settings.depth; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &dev->reg, session); +} + + +// this function sends generic gamma table (ie linear ones) or the Sensor specific one if provided +void CommandSetGl841::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + int size; + + size = 256; + + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3); + + sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data()); + + dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3); +} + + +/* this function does the led calibration by scanning one line of the calibration + area below scanner's top on white strip. + +-needs working coarse/gain +*/ +SensorExposure CommandSetGl841::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int num_pixels; + int total_size; + int i, j; + int val; + int channels; + int avg[3], avga, avge; + int turn; + uint16_t exp[3], target; + int move; + + /* these 2 boundaries should be per sensor */ + uint16_t min_exposure=500; + uint16_t max_exposure; + + /* feed to white strip if needed */ + if (dev->model->y_offset_calib_white > 0) { + move = static_cast(dev->model->y_offset_calib_white); + move = static_cast((move * (dev->motor.base_ydpi)) / MM_PER_INCH); + DBG(DBG_io, "%s: move=%d lines\n", __func__, move); + gl841_feed(dev, move); + } + + /* offset calibration is always done in color mode */ + channels = 3; + + unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); + unsigned factor = sensor.optical_res / resolution; + + const auto& calib_sensor_base = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + + num_pixels = calib_sensor_base.sensor_pixels / factor; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor_base); + + init_regs_for_scan_session(dev, calib_sensor_base, ®s, session); + + dev->interface->write_registers(regs); + + + total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ + + std::vector line(total_size); + +/* + we try to get equal bright leds here: + + loop: + average per color + adjust exposure times + */ + + exp[0] = sensor.exposure.red; + exp[1] = sensor.exposure.green; + exp[2] = sensor.exposure.blue; + + turn = 0; + /* max exposure is set to ~2 time initial average + * exposure, or 2 time last calibration exposure */ + max_exposure=((exp[0]+exp[1]+exp[2])/3)*2; + target=sensor.gain_white_ref*256; + + auto calib_sensor = calib_sensor_base; + + bool acceptable = false; + do { + calib_sensor.exposure.red = exp[0]; + calib_sensor.exposure.green = exp[1]; + calib_sensor.exposure.blue = exp[2]; + + regs_set_exposure(dev->model->asic_type, regs, calib_sensor.exposure); + dev->interface->write_register(0x10, (calib_sensor.exposure.red >> 8) & 0xff); + dev->interface->write_register(0x11, calib_sensor.exposure.red & 0xff); + dev->interface->write_register(0x12, (calib_sensor.exposure.green >> 8) & 0xff); + dev->interface->write_register(0x13, calib_sensor.exposure.green & 0xff); + dev->interface->write_register(0x14, (calib_sensor.exposure.blue >> 8) & 0xff); + dev->interface->write_register(0x15, calib_sensor.exposure.blue & 0xff); + + dev->interface->write_registers(regs); + + DBG(DBG_info, "%s: starting line reading\n", __func__); + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("led_calibration"); + move_back_home(dev, true); + return calib_sensor.exposure; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) { + char fn[30]; + std::snprintf(fn, 30, "gl841_led_%d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, num_pixels, 1); + } + + /* compute average */ + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info,"%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + acceptable = true; + + /* exposure is acceptable if each color is in the %5 range + * of other color channels */ + if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || + avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || + avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) + { + acceptable = false; + } + + /* led exposure is not acceptable if white level is too low + * ~80 hardcoded value for white level */ + if(avg[0]<20000 || avg[1]<20000 || avg[2]<20000) + { + acceptable = false; + } + + /* for scanners using target value */ + if(target>0) + { + acceptable = true; + for(i=0;i<3;i++) + { + /* we accept +- 2% delta from target */ + if(abs(avg[i]-target)>target/50) + { + exp[i]=(exp[i]*target)/avg[i]; + acceptable = false; + } + } + } + else + { + if (!acceptable) + { + avga = (avg[0]+avg[1]+avg[2])/3; + exp[0] = (exp[0] * avga) / avg[0]; + exp[1] = (exp[1] * avga) / avg[1]; + exp[2] = (exp[2] * avga) / avg[2]; + /* + keep the resulting exposures below this value. + too long exposure drives the ccd into saturation. + we may fix this by relying on the fact that + we get a striped scan without shading, by means of + statistical calculation + */ + avge = (exp[0] + exp[1] + exp[2]) / 3; + + if (avge > max_exposure) { + exp[0] = (exp[0] * max_exposure) / avge; + exp[1] = (exp[1] * max_exposure) / avge; + exp[2] = (exp[2] * max_exposure) / avge; + } + if (avge < min_exposure) { + exp[0] = (exp[0] * min_exposure) / avge; + exp[1] = (exp[1] * min_exposure) / avge; + exp[2] = (exp[2] * min_exposure) / avge; + } + + } + } + + gl841_stop_action(dev); + + turn++; + + } while (!acceptable && turn < 100); + + DBG(DBG_info,"%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); + + dev->cmd_set->move_back_home(dev, true); + + return calib_sensor.exposure; +} + +/** @brief calibration for AD frontend devices + * offset calibration assumes that the scanning head is on a black area + * For LiDE80 analog frontend + * 0x0003 : is gain and belongs to [0..63] + * 0x0006 : is offset + * We scan a line with no gain until average offset reaches the target + */ +static void ad_fe_offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) +{ + DBG_HELPER(dbg); + int num_pixels; + int total_size; + int i; + int average; + int turn; + int top; + int bottom; + int target; + + /* don't impact 3600 behavior since we can't test it */ + if (dev->model->sensor_id == SensorId::CCD_PLUSTEK_OPTICPRO_3600) { + return; + } + + unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); + unsigned factor = sensor.optical_res / resolution; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, + dev->settings.scan_method); + + num_pixels = calib_sensor.sensor_pixels / factor; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 8; + session.params.channels = 3; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + dev->cmd_set->init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + total_size = num_pixels * 3 * 2 * 1; + + std::vector line(total_size); + + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* loop on scan until target offset is reached */ + turn=0; + target=24; + bottom=0; + top=255; + do { + /* set up offset mid range */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + /* scan line */ + DBG(DBG_info, "%s: starting line reading\n", __func__); + dev->interface->write_registers(regs); + dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("ad_fe_offset_calibration"); + gl841_stop_action(dev); + return; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + gl841_stop_action (dev); + if (DBG_LEVEL >= DBG_data) { + char fn[30]; + std::snprintf(fn, 30, "gl841_offset_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), 8, 3, num_pixels, 1); + } + + /* search for minimal value */ + average=0; + for(i=0;itarget) + { + top=(top+bottom)/2; + } + else + { + bottom=(top+bottom)/2; + } + turn++; + } while ((top-bottom)>1 && turn < 100); + + // FIXME: don't overwrite the calibrated values + dev->frontend.set_offset(0, 0); + dev->frontend.set_offset(1, 0); + dev->frontend.set_offset(2, 0); + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); +} + +/* this function does the offset calibration by scanning one line of the calibration + area below scanner's top. There is a black margin and the remaining is white. + sanei_genesys_search_start() must have been called so that the offsets and margins + are allready known. + +this function expects the slider to be where? +*/ +void CommandSetGl841::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int num_pixels; + int total_size; + int i, j; + int val; + int channels; + int off[3],offh[3],offl[3],off1[3],off2[3]; + int min1[3],min2[3]; + int cmin[3],cmax[3]; + int turn; + int mintgt = 0x400; + + /* Analog Device fronted have a different calibration */ + if ((dev->reg.find_reg(0x04).value & REG_0x04_FESET) == 0x02) { + return ad_fe_offset_calibration(dev, sensor, regs); + } + + /* offset calibration is always done in color mode */ + channels = 3; + + unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); + unsigned factor = sensor.optical_res / resolution; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + + num_pixels = calib_sensor.sensor_pixels / factor; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE | + ScanFlag::DISABLE_LAMP; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* scan first line of data with no offset nor gain */ +/*WM8199: gain=0.73; offset=-260mV*/ +/*okay. the sensor black level is now at -260mV. we only get 0 from AFE...*/ +/* we should probably do real calibration here: + * -detect acceptable offset with binary search + * -calculate offset from this last version + * + * acceptable offset means + * - few completely black pixels(<10%?) + * - few completely white pixels(<10%?) + * + * final offset should map the minimum not completely black + * pixel to 0(16 bits) + * + * this does account for dummy pixels at the end of ccd + * this assumes slider is at black strip(which is not quite as black as "no + * signal"). + * + */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + offh[0] = 0xff; + offh[1] = 0xff; + offh[2] = 0xff; + offl[0] = 0x00; + offl[1] = 0x00; + offl[2] = 0x00; + turn = 0; + + bool acceptable = false; + do { + + dev->interface->write_registers(regs); + + for (j=0; j < channels; j++) { + off[j] = (offh[j]+offl[j])/2; + dev->frontend.set_offset(j, off[j]); + } + + dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); + + DBG(DBG_info, "%s: starting first line reading\n", __func__); + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("offset_calibration"); + return; + } + + sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) { + char fn[30]; + std::snprintf(fn, 30, "gl841_offset1_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, first_line.data(), 16, channels, num_pixels, 1); + } + + acceptable = true; + + for (j = 0; j < channels; j++) + { + cmin[j] = 0; + cmax[j] = 0; + + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + + first_line[i * 2 + j * 2 * num_pixels]; + else + val = + first_line[i * 2 * channels + 2 * j + 1] * 256 + + first_line[i * 2 * channels + 2 * j]; + if (val < 10) + cmin[j]++; + if (val > 65525) + cmax[j]++; + } + + /* TODO the DP685 has a black strip in the middle of the sensor + * should be handled in a more elegant way , could be a bug */ + if (dev->model->sensor_id == SensorId::CCD_DP685) + cmin[j] -= 20; + + if (cmin[j] > num_pixels/100) { + acceptable = false; + if (dev->model->is_cis) + offl[0] = off[0]; + else + offl[j] = off[j]; + } + if (cmax[j] > num_pixels/100) { + acceptable = false; + if (dev->model->is_cis) + offh[0] = off[0]; + else + offh[j] = off[j]; + } + } + + DBG(DBG_info,"%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0], + cmin[1], cmax[1], cmin[2], cmax[2]); + + if (dev->model->is_cis) { + offh[2] = offh[1] = offh[0]; + offl[2] = offl[1] = offl[0]; + } + + gl841_stop_action(dev); + + turn++; + } while (!acceptable && turn < 100); + + DBG(DBG_info,"%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); + + + for (j = 0; j < channels; j++) + { + off1[j] = off[j]; + + min1[j] = 65536; + + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + + first_line[i * 2 + j * 2 * num_pixels]; + else + val = + first_line[i * 2 * channels + 2 * j + 1] * 256 + + first_line[i * 2 * channels + 2 * j]; + if (min1[j] > val && val >= 10) + min1[j] = val; + } + } + + + offl[0] = off[0]; + offl[1] = off[0]; + offl[2] = off[0]; + turn = 0; + + do { + + for (j=0; j < channels; j++) { + off[j] = (offh[j]+offl[j])/2; + dev->frontend.set_offset(j, off[j]); + } + + dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); + + DBG(DBG_info, "%s: starting second line reading\n", __func__); + dev->interface->write_registers(regs); + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) { + char fn[30]; + std::snprintf(fn, 30, "gl841_offset2_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, second_line.data(), 16, channels, num_pixels, 1); + } + + acceptable = true; + + for (j = 0; j < channels; j++) + { + cmin[j] = 0; + cmax[j] = 0; + + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + + second_line[i * 2 + j * 2 * num_pixels]; + else + val = + second_line[i * 2 * channels + 2 * j + 1] * 256 + + second_line[i * 2 * channels + 2 * j]; + if (val < 10) + cmin[j]++; + if (val > 65525) + cmax[j]++; + } + + if (cmin[j] > num_pixels/100) { + acceptable = false; + if (dev->model->is_cis) + offl[0] = off[0]; + else + offl[j] = off[j]; + } + if (cmax[j] > num_pixels/100) { + acceptable = false; + if (dev->model->is_cis) + offh[0] = off[0]; + else + offh[j] = off[j]; + } + } + + DBG(DBG_info, "%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0], + cmin[1], cmax[1], cmin[2], cmax[2]); + + if (dev->model->is_cis) { + offh[2] = offh[1] = offh[0]; + offl[2] = offl[1] = offl[0]; + } + + gl841_stop_action(dev); + + turn++; + + } while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); + + + for (j = 0; j < channels; j++) + { + off2[j] = off[j]; + + min2[j] = 65536; + + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + + second_line[i * 2 + j * 2 * num_pixels]; + else + val = + second_line[i * 2 * channels + 2 * j + 1] * 256 + + second_line[i * 2 * channels + 2 * j]; + if (min2[j] > val && val != 0) + min2[j] = val; + } + } + + DBG(DBG_info, "%s: first set: %d/%d,%d/%d,%d/%d\n", __func__, off1[0], min1[0], off1[1], min1[1], + off1[2], min1[2]); + + DBG(DBG_info, "%s: second set: %d/%d,%d/%d,%d/%d\n", __func__, off2[0], min2[0], off2[1], min2[1], + off2[2], min2[2]); + +/* + calculate offset for each channel + based on minimal pixel value min1 at offset off1 and minimal pixel value min2 + at offset off2 + + to get min at off, values are linearly interpolated: + min=real+off*fact + min1=real+off1*fact + min2=real+off2*fact + + fact=(min1-min2)/(off1-off2) + real=min1-off1*(min1-min2)/(off1-off2) + + off=(min-min1+off1*(min1-min2)/(off1-off2))/((min1-min2)/(off1-off2)) + + off=(min*(off1-off2)+min1*off2-off1*min2)/(min1-min2) + + */ + for (j = 0; j < channels; j++) + { + if (min2[j]-min1[j] == 0) { +/*TODO: try to avoid this*/ + DBG(DBG_warn, "%s: difference too small\n", __func__); + if (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j] >= 0) + off[j] = 0x0000; + else + off[j] = 0xffff; + } else + off[j] = (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j])/(min1[j]-min2[j]); + if (off[j] > 255) + off[j] = 255; + if (off[j] < 0) + off[j] = 0; + dev->frontend.set_offset(j, off[j]); + } + + DBG(DBG_info, "%s: final offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); + + if (dev->model->is_cis) { + if (off[0] < off[1]) + off[0] = off[1]; + if (off[0] < off[2]) + off[0] = off[2]; + dev->frontend.set_offset(0, off[0]); + dev->frontend.set_offset(1, off[0]); + dev->frontend.set_offset(2, off[0]); + } + + if (channels == 1) + { + dev->frontend.set_offset(1, dev->frontend.get_offset(0)); + dev->frontend.set_offset(2, dev->frontend.get_offset(0)); + } +} + + +/* alternative coarse gain calibration + this on uses the settings from offset_calibration and + uses only one scanline + */ +/* + with offset and coarse calibration we only want to get our input range into + a reasonable shape. the fine calibration of the upper and lower bounds will + be done with shading. + */ +void CommandSetGl841::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const +{ + DBG_HELPER_ARGS(dbg, "dpi=%d", dpi); + int num_pixels; + int total_size; + int i, j, channels; + int max[3]; + float gain[3]; + int val; + int lines=1; + int move; + + // feed to white strip if needed + if (dev->model->y_offset_calib_white > 0) { + move = static_cast(dev->model->y_offset_calib_white); + move = static_cast((move * (dev->motor.base_ydpi)) / MM_PER_INCH); + DBG(DBG_io, "%s: move=%d lines\n", __func__, move); + gl841_feed(dev, move); + } + + /* coarse gain calibration is allways done in color mode */ + channels = 3; + + unsigned resolution = sensor.get_logical_hwdpi(dev->settings.xres); + unsigned factor = sensor.optical_res / resolution; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + + num_pixels = calib_sensor.sensor_pixels / factor; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = lines; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + dev->interface->write_registers(regs); + + total_size = num_pixels * channels * 2 * lines; /* colors * bytes_per_color * scan lines */ + + std::vector line(total_size); + + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("coarse_gain_calibration"); + gl841_stop_action(dev); + move_back_home(dev, true); + return; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) + sanei_genesys_write_pnm_file("gl841_gain.pnm", line.data(), 16, channels, num_pixels, lines); + + /* average high level for each channel and compute gain + to reach the target code + we only use the central half of the CCD data */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + + if (val > max[j]) + max[j] = val; + } + + gain[j] = 65535.0f / max[j]; + + uint8_t out_gain = 0; + + if (dev->model->adc_id == AdcId::CANON_LIDE_35 || + dev->model->adc_id == AdcId::WOLFSON_XP300 || + dev->model->adc_id == AdcId::WOLFSON_DSM600) + { + gain[j] *= 0.69f; // seems we don't get the real maximum. empirically derived + if (283 - 208/gain[j] > 255) + out_gain = 255; + else if (283 - 208/gain[j] < 0) + out_gain = 0; + else + out_gain = static_cast(283 - 208 / gain[j]); + } else if (dev->model->adc_id == AdcId::CANON_LIDE_80) { + out_gain = static_cast(gain[j] * 12); + } + dev->frontend.set_gain(j, out_gain); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], + out_gain); + } + + for (j = 0; j < channels; j++) + { + if(gain[j] > 10) + { + DBG (DBG_error0, "**********************************************\n"); + DBG (DBG_error0, "**********************************************\n"); + DBG (DBG_error0, "**** ****\n"); + DBG (DBG_error0, "**** Extremely low Brightness detected. ****\n"); + DBG (DBG_error0, "**** Check the scanning head is ****\n"); + DBG (DBG_error0, "**** unlocked and moving. ****\n"); + DBG (DBG_error0, "**** ****\n"); + DBG (DBG_error0, "**********************************************\n"); + DBG (DBG_error0, "**********************************************\n"); + throw SaneException(SANE_STATUS_JAMMED, "scanning head is locked"); + } + + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + if (channels == 1) { + dev->frontend.set_gain(0, dev->frontend.get_gain(1)); + dev->frontend.set_gain(2, dev->frontend.get_gain(1)); + } + + DBG(DBG_info, "%s: gain=(%d,%d,%d)\n", __func__, + dev->frontend.get_gain(0), + dev->frontend.get_gain(1), + dev->frontend.get_gain(2)); + + gl841_stop_action(dev); + + dev->cmd_set->move_back_home(dev, true); +} + +// wait for lamp warmup by scanning the same line until difference +// between 2 scans is below a threshold +void CommandSetGl841::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* local_reg, int* channels, + int* total_size) const +{ + DBG_HELPER(dbg); + int num_pixels = 4 * 300; + *local_reg = dev->reg; + +/* okay.. these should be defaults stored somewhere */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + dev->frontend.set_offset(0, 0x80); + dev->frontend.set_offset(1, 0x80); + dev->frontend.set_offset(2, 0x80); + + ScanSession session; + session.params.xres = sensor.optical_res; + session.params.yres = dev->settings.yres; + session.params.startx = sensor.dummy_pixel; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 16; + session.params.channels = *channels; + session.params.scan_method = dev->settings.scan_method; + if (*channels == 3) { + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + } else { + session.params.scan_mode = ScanColorMode::GRAY; + } + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, local_reg, session); + + num_pixels = session.output_pixels; + + *total_size = num_pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */ + + dev->interface->write_registers(*local_reg); +} + + +/* + * this function moves head without scanning, forward, then backward + * so that the head goes to park position. + * as a by-product, also check for lock + */ +static void sanei_gl841_repark_head(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + + gl841_feed(dev,232); + + // toggle motor flag, put an huge step number and redo move backward + dev->cmd_set->move_back_home(dev, true); +} + +/* + * initialize ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +void CommandSetGl841::init(Genesys_Device* dev) const +{ + size_t size; + + DBG_INIT (); + DBG_HELPER(dbg); + + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + + /* Check if the device has already been initialized and powered up */ + if (dev->already_initialized) + { + auto status = scanner_read_status(*dev); + if (!status.is_replugged) { + DBG(DBG_info, "%s: already initialized\n", __func__); + return; + } + } + + dev->dark_average_data.clear(); + dev->white_average_data.clear(); + + dev->settings.color_filter = ColorFilter::RED; + + // ASIC reset + dev->interface->write_register(0x0e, 0x01); + dev->interface->write_register(0x0e, 0x00); + + /* Set default values for registers */ + gl841_init_registers (dev); + + // Write initial registers + dev->interface->write_registers(dev->reg); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + // Set analog frontend + dev->cmd_set->set_fe(dev, sensor, AFE_INIT); + + // FIXME: move_back_home modifies dev->calib_reg and requires it to be filled + dev->calib_reg = dev->reg; + + // Move home + dev->cmd_set->move_back_home(dev, true); + + // Init shading data + sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels); + + /* ensure head is correctly parked, and check lock */ + if (dev->model->flags & GENESYS_FLAG_REPARK) + { + // FIXME: if repark fails, we should print an error message that the scanner is locked and + // the user should unlock the lock. We should also rethrow with SANE_STATUS_JAMMED + sanei_gl841_repark_head(dev); + } + + // send gamma tables + dev->cmd_set->send_gamma_table(dev, sensor); + + /* initial calibration reg values */ + Genesys_Register_Set& regs = dev->calib_reg; + regs = dev->reg; + + unsigned resolution = sensor.get_logical_hwdpi(300); + unsigned factor = sensor.optical_res / resolution; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, 3, + dev->settings.scan_method); + + unsigned num_pixels = 16 / factor; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = 300; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 16; + session.params.channels = 3; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = ColorFilter::RED; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + dev->interface->write_registers(regs); + + size = num_pixels * 3 * 2 * 1; // colors * bytes_per_color * scan lines + + std::vector line(size); + + DBG(DBG_info, "%s: starting dummy data reading\n", __func__); + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + + sanei_usb_set_timeout(1000);/* 1 second*/ + + if (is_testing_mode()) { + dev->interface->test_checkpoint("init"); + } else { + // ignore errors. next read will succeed + catch_all_exceptions(__func__, + [&](){ sanei_genesys_read_data_from_scanner(dev, line.data(), size); }); + } + + sanei_usb_set_timeout(30 * 1000);/* 30 seconds*/ + + end_scan(dev, ®s, true); + + regs = dev->reg; + + // Set powersaving(default = 15 minutes) + set_powersaving(dev, 15); + dev->already_initialized = true; +} + +void CommandSetGl841::update_hardware_sensors(Genesys_Scanner* s) const +{ + DBG_HELPER(dbg); + /* do what is needed to get a new set of events, but try to not lose + any of them. + */ + uint8_t val; + + if (s->dev->model->gpio_id == GpioId::CANON_LIDE_35 + || s->dev->model->gpio_id == GpioId::CANON_LIDE_80) + { + val = s->dev->interface->read_register(REG_0x6D); + s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_FILE_SW].write((val & 0x02) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); + s->buttons[BUTTON_COPY_SW].write((val & 0x08) == 0); + } + + if (s->dev->model->gpio_id == GpioId::XP300 || + s->dev->model->gpio_id == GpioId::DP665 || + s->dev->model->gpio_id == GpioId::DP685) + { + val = s->dev->interface->read_register(REG_0x6D); + + s->buttons[BUTTON_PAGE_LOADED_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_SCAN_SW].write((val & 0x02) == 0); + } +} + +/** @brief search for a full width black or white strip. + * This function searches for a black or white stripe across the scanning area. + * When searching backward, the searched area must completely be of the desired + * color since this area will be used for calibration which scans forward. + * @param dev scanner device + * @param forward true if searching forward, false if searching backward + * @param black true if searching for a black strip, false for a white strip + */ +void CommandSetGl841::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward, + bool black) const +{ + DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse"); + unsigned int pixels, lines, channels; + Genesys_Register_Set local_reg; + size_t size; + unsigned int pass, count, found, x, y, length; + char title[80]; + GenesysRegister *r; + uint8_t white_level=90; /**< default white level to detect white dots */ + uint8_t black_level=60; /**< default black level to detect black dots */ + + /* use maximum gain when doing forward white strip detection + * since we don't have calibrated the sensor yet */ + if(!black && forward) + { + dev->frontend.set_gain(0, 0xff); + dev->frontend.set_gain(1, 0xff); + dev->frontend.set_gain(2, 0xff); + } + + dev->cmd_set->set_fe(dev, sensor, AFE_SET); + gl841_stop_action(dev); + + // set up for a gray scan at lowest dpi + const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method); + unsigned dpi = resolution_settings.get_min_resolution_x(); + channels = 1; + + /* shading calibation is done with dev->motor.base_ydpi */ + /* lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; */ + lines = static_cast((10 * dpi) / MM_PER_INCH); + + pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; + + /* 20 cm max length for calibration sheet */ + length = static_cast(((200 * dpi) / MM_PER_INCH) / lines); + + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + + local_reg = dev->reg; + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::RED; + session.params.flags = ScanFlag::DISABLE_SHADING | ScanFlag::DISABLE_GAMMA; + compute_session(dev, session, sensor); + + size = pixels * channels * lines * (session.params.depth / 8); + std::vector data(size); + + init_regs_for_scan_session(dev, sensor, &local_reg, session); + + /* set up for reverse or forward */ + r = sanei_genesys_get_address(&local_reg, 0x02); + if (forward) { + r->value &= ~4; + } else { + r->value |= 4; + } + + dev->interface->write_registers(local_reg); + + dev->cmd_set->begin_scan(dev, sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_strip"); + gl841_stop_action(dev); + return; + } + + // waits for valid data + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + gl841_stop_action(dev); + + pass = 0; + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", black ? "black" : "white", + forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, + channels, pixels, lines); + } + + /* loop until strip is found or maximum pass number done */ + found = 0; + while (pass < length && !found) + { + dev->interface->write_registers(local_reg); + + //now start scan + dev->cmd_set->begin_scan(dev, sensor, &local_reg, true); + + // waits for valid data + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + gl841_stop_action (dev); + + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, + channels, pixels, lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > white_level) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < black_level) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > white_level) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < black_level) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (pixels * lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + pass++; + } + + if (found) + { + DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); + } + else + { + throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white"); + } +} + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +void CommandSetGl841::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + uint8_t* data, int size) const +{ + DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size); + uint32_t length, x, factor, pixels, i; + uint16_t dpiset, dpihw, beginpixel; + uint8_t *ptr,*src; + + /* old method if no SHDAREA */ + if ((dev->reg.find_reg(0x01).value & REG_0x01_SHDAREA) == 0) { + dev->interface->write_buffer(0x3c, 0x0000, data, size); + return; + } + + /* data is whole line, we extract only the part for the scanned area */ + length = static_cast(size / 3); + unsigned strpixel = dev->session.pixel_startx; + unsigned endpixel = dev->session.pixel_endx; + + /* compute deletion/average factor */ + dpiset = dev->reg.get16(REG_DPISET); + dpihw = gl841_get_dpihw(dev); + unsigned ccd_size_divisor = dev->session.ccd_size_divisor; + factor=dpihw/dpiset; + DBG(DBG_io2, "%s: dpihw=%d, dpiset=%d, ccd_size_divisor=%d, factor=%d\n", __func__, dpihw, dpiset, + ccd_size_divisor, factor); + + /* turn pixel value into bytes 2x16 bits words */ + strpixel*=2*2; /* 2 words of 2 bytes */ + endpixel*=2*2; + pixels=endpixel-strpixel; + + /* shading pixel begin is start pixel minus start pixel during shading + * calibration. Currently only cases handled are full and half ccd resolution. + */ + beginpixel = sensor.ccd_start_xoffset / ccd_size_divisor; + beginpixel += sensor.dummy_pixel + 1; + DBG(DBG_io2, "%s: ORIGIN PIXEL=%d\n", __func__, beginpixel); + beginpixel = (strpixel-beginpixel*2*2)/factor; + DBG(DBG_io2, "%s: BEGIN PIXEL=%d\n", __func__, beginpixel/4); + + dev->interface->record_key_value("shading_offset", std::to_string(beginpixel)); + dev->interface->record_key_value("shading_pixels", std::to_string(pixels)); + dev->interface->record_key_value("shading_length", std::to_string(length)); + + DBG(DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n", __func__, length, + length/4); + std::vector buffer(pixels, 0); + + /* write actual shading data contigously + * channel by channel, starting at addr 0x0000 + * */ + for(i=0;i<3;i++) + { + /* copy data to work buffer and process it */ + /* coefficent destination */ + ptr=buffer.data(); + + /* iterate on both sensor segment, data has been averaged, + * so is in the right order and we only have to copy it */ + for(x=0;xinterface->write_buffer(0x3c, 0x5400 * i, buffer.data(), pixels); + } +} + +bool CommandSetGl841::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const +{ + (void) dev; + return true; +} + +void CommandSetGl841::wait_for_motor_stop(Genesys_Device* dev) const +{ + (void) dev; +} + +void CommandSetGl841::move_to_ta(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl841::asic_boot(Genesys_Device *dev, bool cold) const +{ + (void) dev; + (void) cold; + throw SaneException("not implemented"); +} + +std::unique_ptr create_gl841_cmd_set() +{ + return std::unique_ptr(new CommandSetGl841{}); +} + +} // namespace gl841 +} // namespace genesys diff --git a/backend/genesys/gl841.h b/backend/genesys/gl841.h new file mode 100644 index 0000000..5e24249 --- /dev/null +++ b/backend/genesys/gl841.h @@ -0,0 +1,130 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2011-2013 Stéphane Voltz + + 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 "genesys.h" +#include "command_set.h" + +#ifndef BACKEND_GENESYS_GL841_H +#define BACKEND_GENESYS_GL841_H + +namespace genesys { +namespace gl841 { + +class CommandSetGl841 : public CommandSet +{ +public: + ~CommandSetGl841() override = default; + + bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override; + + void init(Genesys_Device* dev) const override; + + void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const override; + + void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const override; + + void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override; + void set_powersaving(Genesys_Device* dev, int delay) const override; + void save_power(Genesys_Device* dev, bool enable) const override; + + void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, bool start_motor) const override; + + void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override; + + void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void search_start_position(Genesys_Device* dev) const override; + + void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const override; + + SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void wait_for_motor_stop(Genesys_Device* dev) const override; + + void move_back_home(Genesys_Device* dev, bool wait_until_home) const override; + + void update_hardware_sensors(struct Genesys_Scanner* s) const override; + + void load_document(Genesys_Device* dev) const override; + + void detect_document_end(Genesys_Device* dev) const override; + + void eject_document(Genesys_Device* dev) const override; + + void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const override; + + void move_to_ta(Genesys_Device* dev) const override; + + void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data, + int size) const override; + + ScanSession calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const override; + + void asic_boot(Genesys_Device* dev, bool cold) const override; +}; + +} // namespace gl841 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL841_H diff --git a/backend/genesys/gl841_registers.h b/backend/genesys/gl841_registers.h new file mode 100644 index 0000000..8e0c204 --- /dev/null +++ b/backend/genesys/gl841_registers.h @@ -0,0 +1,269 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL841_REGISTERS_H +#define BACKEND_GENESYS_GL841_REGISTERS_H + +#include + +namespace genesys { +namespace gl841 { + +using RegAddr = std::uint16_t; +using RegMask = std::uint8_t; +using RegShift = unsigned; + +static constexpr RegAddr REG_0x01 = 0x01; +static constexpr RegMask REG_0x01_CISSET = 0x80; +static constexpr RegMask REG_0x01_DOGENB = 0x40; +static constexpr RegMask REG_0x01_DVDSET = 0x20; +static constexpr RegMask REG_0x01_M16DRAM = 0x08; +static constexpr RegMask REG_0x01_DRAMSEL = 0x04; +static constexpr RegMask REG_0x01_SHDAREA = 0x02; +static constexpr RegMask REG_0x01_SCAN = 0x01; + +static constexpr RegAddr REG_0x02 = 0x02; +static constexpr RegMask REG_0x02_NOTHOME = 0x80; +static constexpr RegMask REG_0x02_ACDCDIS = 0x40; +static constexpr RegMask REG_0x02_AGOHOME = 0x20; +static constexpr RegMask REG_0x02_MTRPWR = 0x10; +static constexpr RegMask REG_0x02_FASTFED = 0x08; +static constexpr RegMask REG_0x02_MTRREV = 0x04; +static constexpr RegMask REG_0x02_HOMENEG = 0x02; +static constexpr RegMask REG_0x02_LONGCURV = 0x01; + +static constexpr RegMask REG_0x03_LAMPDOG = 0x80; +static constexpr RegMask REG_0x03_AVEENB = 0x40; +static constexpr RegMask REG_0x03_XPASEL = 0x20; +static constexpr RegMask REG_0x03_LAMPPWR = 0x10; +static constexpr RegMask REG_0x03_LAMPTIM = 0x0f; + +static constexpr RegMask REG_0x04_LINEART = 0x80; +static constexpr RegMask REG_0x04_BITSET = 0x40; +static constexpr RegMask REG_0x04_AFEMOD = 0x30; +static constexpr RegMask REG_0x04_FILTER = 0x0c; +static constexpr RegMask REG_0x04_FESET = 0x03; + +static constexpr RegShift REG_0x04S_AFEMOD = 4; + +static constexpr RegAddr REG_0x05 = 0x05; +static constexpr RegMask REG_0x05_DPIHW = 0xc0; +static constexpr RegMask REG_0x05_DPIHW_600 = 0x00; +static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40; +static constexpr RegMask REG_0x05_DPIHW_2400 = 0x80; +static constexpr RegMask REG_0x05_MTLLAMP = 0x30; +static constexpr RegMask REG_0x05_GMMENB = 0x08; +static constexpr RegMask REG_0x05_MTLBASE = 0x03; + +static constexpr RegAddr REG_0x06 = 0x06; +static constexpr RegMask REG_0x06_SCANMOD = 0xe0; +static constexpr RegShift REG_0x06S_SCANMOD = 5; +static constexpr RegMask REG_0x06_PWRBIT = 0x10; +static constexpr RegMask REG_0x06_GAIN4 = 0x08; +static constexpr RegMask REG_0x06_OPTEST = 0x07; + +static constexpr RegMask REG_0x07_SRAMSEL = 0x08; +static constexpr RegMask REG_0x07_FASTDMA = 0x04; +static constexpr RegMask REG_0x07_DMASEL = 0x02; +static constexpr RegMask REG_0x07_DMARDWR = 0x01; + +static constexpr RegMask REG_0x08_DECFLAG = 0x40; +static constexpr RegMask REG_0x08_GMMFFR = 0x20; +static constexpr RegMask REG_0x08_GMMFFG = 0x10; +static constexpr RegMask REG_0x08_GMMFFB = 0x08; +static constexpr RegMask REG_0x08_GMMZR = 0x04; +static constexpr RegMask REG_0x08_GMMZG = 0x02; +static constexpr RegMask REG_0x08_GMMZB = 0x01; + +static constexpr RegMask REG_0x09_MCNTSET = 0xc0; +static constexpr RegMask REG_0x09_CLKSET = 0x30; +static constexpr RegMask REG_0x09_BACKSCAN = 0x08; +static constexpr RegMask REG_0x09_ENHANCE = 0x04; +static constexpr RegMask REG_0x09_SHORTTG = 0x02; +static constexpr RegMask REG_0x09_NWAIT = 0x01; + +static constexpr RegShift REG_0x09S_MCNTSET = 6; +static constexpr RegShift REG_0x09S_CLKSET = 4; + + +static constexpr RegMask REG_0x0A_SRAMBUF = 0x01; + +static constexpr RegAddr REG_0x0D = 0x0d; +static constexpr RegMask REG_0x0D_CLRLNCNT = 0x01; + +static constexpr RegMask REG_0x16_CTRLHI = 0x80; +static constexpr RegMask REG_0x16_TOSHIBA = 0x40; +static constexpr RegMask REG_0x16_TGINV = 0x20; +static constexpr RegMask REG_0x16_CK1INV = 0x10; +static constexpr RegMask REG_0x16_CK2INV = 0x08; +static constexpr RegMask REG_0x16_CTRLINV = 0x04; +static constexpr RegMask REG_0x16_CKDIS = 0x02; +static constexpr RegMask REG_0x16_CTRLDIS = 0x01; + +static constexpr RegMask REG_0x17_TGMODE = 0xc0; +static constexpr RegMask REG_0x17_TGMODE_NO_DUMMY = 0x00; +static constexpr RegMask REG_0x17_TGMODE_REF = 0x40; +static constexpr RegMask REG_0x17_TGMODE_XPA = 0x80; +static constexpr RegMask REG_0x17_TGW = 0x3f; +static constexpr RegShift REG_0x17S_TGW = 0; + +static constexpr RegMask REG_0x18_CNSET = 0x80; +static constexpr RegMask REG_0x18_DCKSEL = 0x60; +static constexpr RegMask REG_0x18_CKTOGGLE = 0x10; +static constexpr RegMask REG_0x18_CKDELAY = 0x0c; +static constexpr RegMask REG_0x18_CKSEL = 0x03; + +static constexpr RegMask REG_0x1A_MANUAL3 = 0x02; +static constexpr RegMask REG_0x1A_MANUAL1 = 0x01; +static constexpr RegMask REG_0x1A_CK4INV = 0x08; +static constexpr RegMask REG_0x1A_CK3INV = 0x04; +static constexpr RegMask REG_0x1A_LINECLP = 0x02; + +static constexpr RegMask REG_0x1C_TGTIME = 0x07; + +static constexpr RegMask REG_0x1D_CK4LOW = 0x80; +static constexpr RegMask REG_0x1D_CK3LOW = 0x40; +static constexpr RegMask REG_0x1D_CK1LOW = 0x20; +static constexpr RegMask REG_0x1D_TGSHLD = 0x1f; +static constexpr RegShift REG_0x1DS_TGSHLD = 0; + + +static constexpr RegAddr REG_0x1E = 0x1e; +static constexpr RegMask REG_0x1E_WDTIME = 0xf0; +static constexpr RegShift REG_0x1ES_WDTIME = 4; +static constexpr RegMask REG_0x1E_LINESEL = 0x0f; +static constexpr RegShift REG_0x1ES_LINESEL = 0; + +static constexpr RegAddr REG_EXPR = 0x10; +static constexpr RegAddr REG_EXPG = 0x12; +static constexpr RegAddr REG_EXPB = 0x14; +static constexpr RegAddr REG_STEPNO = 0x21; +static constexpr RegAddr REG_FWDSTEP = 0x22; +static constexpr RegAddr REG_BWDSTEP = 0x23; +static constexpr RegAddr REG_FASTNO = 0x24; +static constexpr RegAddr REG_LINCNT = 0x25; +static constexpr RegAddr REG_DPISET = 0x2c; +static constexpr RegAddr REG_STRPIXEL = 0x30; +static constexpr RegAddr REG_ENDPIXEL = 0x32; +static constexpr RegAddr REG_MAXWD = 0x35; +static constexpr RegAddr REG_LPERIOD = 0x38; + +static constexpr RegAddr REG_0x40 = 0x40; +static constexpr RegMask REG_0x40_HISPDFLG = 0x04; +static constexpr RegMask REG_0x40_MOTMFLG = 0x02; +static constexpr RegMask REG_0x40_DATAENB = 0x01; + +static constexpr RegMask REG_0x41_PWRBIT = 0x80; +static constexpr RegMask REG_0x41_BUFEMPTY = 0x40; +static constexpr RegMask REG_0x41_FEEDFSH = 0x20; +static constexpr RegMask REG_0x41_SCANFSH = 0x10; +static constexpr RegMask REG_0x41_HOMESNR = 0x08; +static constexpr RegMask REG_0x41_LAMPSTS = 0x04; +static constexpr RegMask REG_0x41_FEBUSY = 0x02; +static constexpr RegMask REG_0x41_MOTORENB = 0x01; + +static constexpr RegMask REG_0x58_VSMP = 0xf8; +static constexpr RegShift REG_0x58S_VSMP = 3; +static constexpr RegMask REG_0x58_VSMPW = 0x07; +static constexpr RegShift REG_0x58S_VSMPW = 0; + +static constexpr RegMask REG_0x59_BSMP = 0xf8; +static constexpr RegShift REG_0x59S_BSMP = 3; +static constexpr RegMask REG_0x59_BSMPW = 0x07; +static constexpr RegShift REG_0x59S_BSMPW = 0; + +static constexpr RegMask REG_0x5A_ADCLKINV = 0x80; +static constexpr RegMask REG_0x5A_RLCSEL = 0x40; +static constexpr RegMask REG_0x5A_CDSREF = 0x30; +static constexpr RegShift REG_0x5AS_CDSREF = 4; +static constexpr RegMask REG_0x5A_RLC = 0x0f; +static constexpr RegShift REG_0x5AS_RLC = 0; + +static constexpr RegMask REG_0x5E_DECSEL = 0xe0; +static constexpr RegShift REG_0x5ES_DECSEL = 5; +static constexpr RegMask REG_0x5E_STOPTIM = 0x1f; +static constexpr RegShift REG_0x5ES_STOPTIM = 0; + +static constexpr RegMask REG_0x60_ZIMOD = 0x1f; +static constexpr RegMask REG_0x61_Z1MOD = 0xff; +static constexpr RegMask REG_0x62_Z1MOD = 0xff; + +static constexpr RegMask REG_0x63_Z2MOD = 0x1f; +static constexpr RegMask REG_0x64_Z2MOD = 0xff; +static constexpr RegMask REG_0x65_Z2MOD = 0xff; + +static constexpr RegMask REG_0x67_STEPSEL = 0xc0; +static constexpr RegMask REG_0x67_FULLSTEP = 0x00; +static constexpr RegMask REG_0x67_HALFSTEP = 0x40; +static constexpr RegMask REG_0x67_QUATERSTEP = 0x80; +static constexpr RegMask REG_0x67_MTRPWM = 0x3f; + +static constexpr RegMask REG_0x68_FSTPSEL = 0xc0; +static constexpr RegMask REG_0x68_FULLSTEP = 0x00; +static constexpr RegMask REG_0x68_HALFSTEP = 0x40; +static constexpr RegMask REG_0x68_QUATERSTEP = 0x80; +static constexpr RegMask REG_0x68_FASTPWM = 0x3f; + +static constexpr RegMask REG_0x6B_MULTFILM = 0x80; +static constexpr RegMask REG_0x6B_GPOM13 = 0x40; +static constexpr RegMask REG_0x6B_GPOM12 = 0x20; +static constexpr RegMask REG_0x6B_GPOM11 = 0x10; +static constexpr RegMask REG_0x6B_GPO18 = 0x02; +static constexpr RegMask REG_0x6B_GPO17 = 0x01; + +static constexpr RegAddr REG_0x6B = 0x6b; + +static constexpr RegAddr REG_0x6C = 0x6c; +static constexpr RegMask REG_0x6C_GPIOH = 0xff; +static constexpr RegMask REG_0x6C_GPIOL = 0xff; + +static constexpr RegAddr REG_0x6D = 0x6d; +static constexpr RegAddr REG_0x6E = 0x6e; +static constexpr RegAddr REG_0x6F = 0x6f; + +static constexpr RegMask REG_0x87_LEDADD = 0x04; + +} // namespace gl841 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL841_REGISTERS_H diff --git a/backend/genesys/gl843.cpp b/backend/genesys/gl843.cpp new file mode 100644 index 0000000..f83ac8d --- /dev/null +++ b/backend/genesys/gl843.cpp @@ -0,0 +1,3060 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "gl843_registers.h" +#include "gl843.h" +#include "test_settings.h" + +#include +#include + +namespace genesys { +namespace gl843 { + +// Set address for writing data +static void gl843_set_buffer_address(Genesys_Device* dev, uint32_t addr) +{ + DBG_HELPER_ARGS(dbg, "setting address to 0x%05x", addr & 0xffff); + + dev->interface->write_register(0x5b, ((addr >> 8) & 0xff)); + dev->interface->write_register(0x5c, (addr & 0xff)); +} + +/** + * compute the step multiplier used + */ +static int gl843_get_step_multiplier(Genesys_Register_Set* regs) +{ + GenesysRegister *r = sanei_genesys_get_address(regs, REG_0x9D); + int value = 1; + if (r != nullptr) + { + switch (r->value & 0x0c) + { + case 0x04: + value = 2; + break; + case 0x08: + value = 4; + break; + default: + value = 1; + } + } + DBG(DBG_io, "%s: step multiplier is %d\n", __func__, value); + return value; +} + +/** copy sensor specific settings */ +static void gl843_setup_sensor(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs) +{ + DBG_HELPER(dbg); + for (const auto& custom_reg : sensor.custom_regs) { + regs->set8(custom_reg.address, custom_reg.value); + } + if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE) && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300 && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7500I) + { + regs->set8(0x7d, 0x90); + } + + dev->segment_order = sensor.segment_order; +} + + +/** @brief set all registers to default values . + * This function is called only once at the beginning and + * fills register startup values for registers reused across scans. + * Those that are rarely modified or not modified are written + * individually. + * @param dev device structure holding register set to initialize + */ +static void +gl843_init_registers (Genesys_Device * dev) +{ + // Within this function SENSOR_DEF marker documents that a register is part + // of the sensors definition and the actual value is set in + // gl843_setup_sensor(). + + // 0x6c, 0x6d, 0x6e, 0x6f, 0xa6, 0xa7, 0xa8, 0xa9 are defined in the Gpo sensor struct + + DBG_HELPER(dbg); + + dev->reg.clear(); + + dev->reg.init_reg(0x01, 0x00); + dev->reg.init_reg(0x02, 0x78); + dev->reg.init_reg(0x03, 0x1f); + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x03, 0x1d); + } + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x03, 0x1c); + } + + dev->reg.init_reg(0x04, 0x10); + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->reg.init_reg(0x04, 0x22); + } + + // fine tune upon device description + dev->reg.init_reg(0x05, 0x80); + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x05, 0x08); + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res); + + // TODO: on 8600F the windows driver turns off GAIN4 which is recommended + dev->reg.init_reg(0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ + } + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I) { + dev->reg.init_reg(0x06, 0xd0); + } + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->reg.init_reg(0x06, 0xf0); /* SCANMOD=111, PWRBIT and no GAIN4 */ + } + + dev->reg.init_reg(0x08, 0x00); + dev->reg.init_reg(0x09, 0x00); + dev->reg.init_reg(0x0a, 0x00); + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x0a, 0x18); + } + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x0a, 0x10); + } + + // This register controls clock and RAM settings and is further modified in + // gl843_boot + dev->reg.init_reg(0x0b, 0x6a); + + if (dev->model->model_id == ModelId::CANON_4400F) { + dev->reg.init_reg(0x0b, 0x69); // 16M only + } + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x0b, 0x89); + } + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I) { + dev->reg.init_reg(0x0b, 0x2a); + } + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) { + dev->reg.init_reg(0x0b, 0x4a); + } + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x0b, 0x69); + } + + if (dev->model->model_id != ModelId::CANON_8400F && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300) + { + dev->reg.init_reg(0x0c, 0x00); + } + + // EXPR[0:15], EXPG[0:15], EXPB[0:15]: Exposure time settings. + dev->reg.init_reg(0x10, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x11, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x12, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x13, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x14, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x15, 0x00); // SENSOR_DEF + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8600F) + { + dev->reg.set16(REG_EXPR, 0x9c40); + dev->reg.set16(REG_EXPG, 0x9c40); + dev->reg.set16(REG_EXPB, 0x9c40); + } + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.set16(REG_EXPR, 0x2c09); + dev->reg.set16(REG_EXPG, 0x22b8); + dev->reg.set16(REG_EXPB, 0x10f0); + } + + // CCD signal settings. + dev->reg.init_reg(0x16, 0x33); // SENSOR_DEF + dev->reg.init_reg(0x17, 0x1c); // SENSOR_DEF + dev->reg.init_reg(0x18, 0x10); // SENSOR_DEF + + // EXPDMY[0:7]: Exposure time of dummy lines. + dev->reg.init_reg(0x19, 0x2a); // SENSOR_DEF + + // Various CCD clock settings. + dev->reg.init_reg(0x1a, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x1c, 0x20); // SENSOR_DEF + dev->reg.init_reg(0x1d, 0x04); // SENSOR_DEF + + dev->reg.init_reg(0x1e, 0x10); + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8600F) + { + dev->reg.init_reg(0x1e, 0x20); + } + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x1e, 0xa0); + } + + dev->reg.init_reg(0x1f, 0x01); + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x1f, 0xff); + } + + dev->reg.init_reg(0x20, 0x10); + dev->reg.init_reg(0x21, 0x04); + + dev->reg.init_reg(0x22, 0x10); + dev->reg.init_reg(0x23, 0x10); + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x22, 0xc8); + dev->reg.init_reg(0x23, 0xc8); + } + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x22, 0x50); + dev->reg.init_reg(0x23, 0x50); + } + + dev->reg.init_reg(0x24, 0x04); + dev->reg.init_reg(0x25, 0x00); + dev->reg.init_reg(0x26, 0x00); + dev->reg.init_reg(0x27, 0x00); + dev->reg.init_reg(0x2c, 0x02); + dev->reg.init_reg(0x2d, 0x58); + // BWHI[0:7]: high level of black and white threshold + dev->reg.init_reg(0x2e, 0x80); + // BWLOW[0:7]: low level of black and white threshold + dev->reg.init_reg(0x2f, 0x80); + dev->reg.init_reg(0x30, 0x00); + dev->reg.init_reg(0x31, 0x14); + dev->reg.init_reg(0x32, 0x27); + dev->reg.init_reg(0x33, 0xec); + + // DUMMY: CCD dummy and optically black pixel count + dev->reg.init_reg(0x34, 0x24); + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x34, 0x14); + } + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->reg.init_reg(0x34, 0x3c); + } + + // MAXWD: If available buffer size is less than 2*MAXWD words, then + // "buffer full" state will be set. + dev->reg.init_reg(0x35, 0x00); + dev->reg.init_reg(0x36, 0xff); + dev->reg.init_reg(0x37, 0xff); + + // LPERIOD: Line period or exposure time for CCD or CIS. + dev->reg.init_reg(0x38, 0x55); // SENSOR_DEF + dev->reg.init_reg(0x39, 0xf0); // SENSOR_DEF + + // FEEDL[0:24]: The number of steps of motor movement. + dev->reg.init_reg(0x3d, 0x00); + dev->reg.init_reg(0x3e, 0x00); + dev->reg.init_reg(0x3f, 0x01); + + // Latch points for high and low bytes of R, G and B channels of AFE. If + // multiple clocks per pixel are consumed, then the setting defines during + // which clock the corresponding value will be read. + // RHI[0:4]: The latch point for high byte of R channel. + // RLOW[0:4]: The latch point for low byte of R channel. + // GHI[0:4]: The latch point for high byte of G channel. + // GLOW[0:4]: The latch point for low byte of G channel. + // BHI[0:4]: The latch point for high byte of B channel. + // BLOW[0:4]: The latch point for low byte of B channel. + dev->reg.init_reg(0x52, 0x01); // SENSOR_DEF + dev->reg.init_reg(0x53, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x54, 0x07); // SENSOR_DEF + dev->reg.init_reg(0x55, 0x0a); // SENSOR_DEF + dev->reg.init_reg(0x56, 0x0d); // SENSOR_DEF + dev->reg.init_reg(0x57, 0x10); // SENSOR_DEF + + // VSMP[0:4]: The position of the image sampling pulse for AFE in cycles. + // VSMPW[0:2]: The length of the image sampling pulse for AFE in cycles. + dev->reg.init_reg(0x58, 0x1b); // SENSOR_DEF + + dev->reg.init_reg(0x59, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x5a, 0x40); // SENSOR_DEF + + // 0x5b-0x5c: GMMADDR[0:15] address for gamma or motor tables download + // SENSOR_DEF + + // DECSEL[0:2]: The number of deceleration steps after touching home sensor + // STOPTIM[0:4]: The stop duration between change of directions in + // backtracking + dev->reg.init_reg(0x5e, 0x23); + if (dev->model->model_id == ModelId::CANON_4400F) { + dev->reg.init_reg(0x5e, 0x3f); + } + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x5e, 0x85); + } + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x5e, 0x1f); + } + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->reg.init_reg(0x5e, 0x01); + } + + //FMOVDEC: The number of deceleration steps in table 5 for auto-go-home + dev->reg.init_reg(0x5f, 0x01); + if (dev->model->model_id == ModelId::CANON_4400F) { + dev->reg.init_reg(0x5f, 0xf0); + } + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x5f, 0xf0); + } + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->reg.init_reg(0x5f, 0x01); + } + + // Z1MOD[0:20] + dev->reg.init_reg(0x60, 0x00); + dev->reg.init_reg(0x61, 0x00); + dev->reg.init_reg(0x62, 0x00); + + // Z2MOD[0:20] + dev->reg.init_reg(0x63, 0x00); + dev->reg.init_reg(0x64, 0x00); + dev->reg.init_reg(0x65, 0x00); + + // STEPSEL[0:1]. Motor movement step mode selection for tables 1-3 in + // scanning mode. + // MTRPWM[0:5]. Motor phase PWM duty cycle setting for tables 1-3 + dev->reg.init_reg(0x67, 0x7f); + // FSTPSEL[0:1]: Motor movement step mode selection for tables 4-5 in + // command mode. + // FASTPWM[5:0]: Motor phase PWM duty cycle setting for tables 4-5 + dev->reg.init_reg(0x68, 0x7f); + + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300) { + dev->reg.init_reg(0x67, 0x80); + dev->reg.init_reg(0x68, 0x80); + } + + // FSHDEC[0:7]: The number of deceleration steps after scanning is finished + // (table 3) + dev->reg.init_reg(0x69, 0x01); + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x69, 64); + } + + // FMOVNO[0:7] The number of acceleration or deceleration steps for fast + // moving (table 4) + dev->reg.init_reg(0x6a, 0x04); + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x69, 64); + } + + // GPIO-related register bits + dev->reg.init_reg(0x6b, 0x30); + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8600F) + { + dev->reg.init_reg(0x6b, 0x72); + } + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x6b, 0xb1); + } + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x6b, 0xf4); + } + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->reg.init_reg(0x6b, 0x31); + } + + // 0x6c, 0x6d, 0x6e, 0x6f are set according to gpio tables. See + // gl843_init_gpio. + + // RSH[0:4]: The position of rising edge of CCD RS signal in cycles + // RSL[0:4]: The position of falling edge of CCD RS signal in cycles + // CPH[0:4]: The position of rising edge of CCD CP signal in cycles. + // CPL[0:4]: The position of falling edge of CCD CP signal in cycles + dev->reg.init_reg(0x70, 0x01); // SENSOR_DEF + dev->reg.init_reg(0x71, 0x03); // SENSOR_DEF + dev->reg.init_reg(0x72, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x73, 0x05); // SENSOR_DEF + + if (dev->model->model_id == ModelId::CANON_4400F) { + dev->reg.init_reg(0x70, 0x01); + dev->reg.init_reg(0x71, 0x03); + dev->reg.init_reg(0x72, 0x01); + dev->reg.init_reg(0x73, 0x03); + } + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x70, 0x01); + dev->reg.init_reg(0x71, 0x03); + dev->reg.init_reg(0x72, 0x03); + dev->reg.init_reg(0x73, 0x04); + } + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x70, 0x00); + dev->reg.init_reg(0x71, 0x02); + dev->reg.init_reg(0x72, 0x02); + dev->reg.init_reg(0x73, 0x04); + } + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x70, 0x00); + dev->reg.init_reg(0x71, 0x02); + dev->reg.init_reg(0x72, 0x00); + dev->reg.init_reg(0x73, 0x00); + } + + // CK1MAP[0:17], CK3MAP[0:17], CK4MAP[0:17]: CCD clock bit mapping setting. + dev->reg.init_reg(0x74, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x75, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x76, 0x3c); // SENSOR_DEF + dev->reg.init_reg(0x77, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x78, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x79, 0x9f); // SENSOR_DEF + dev->reg.init_reg(0x7a, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x7b, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x7c, 0x55); // SENSOR_DEF + + // various AFE settings + dev->reg.init_reg(0x7d, 0x00); + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x7d, 0x20); + } + + // GPOLED[x]: LED vs GPIO settings + dev->reg.init_reg(0x7e, 0x00); + + // BSMPDLY, VSMPDLY + // LEDCNT[0:1]: Controls led blinking and its period + dev->reg.init_reg(0x7f, 0x00); + + // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for + // moving in various situations. + dev->reg.init_reg(0x80, 0x00); + if (dev->model->model_id == ModelId::CANON_4400F) { + dev->reg.init_reg(0x80, 0x0c); + } + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->reg.init_reg(0x80, 0x28); + } + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x80, 0x50); + } + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->reg.init_reg(0x80, 0x0f); + } + + if (dev->model->model_id != ModelId::CANON_4400F) { + dev->reg.init_reg(0x81, 0x00); + dev->reg.init_reg(0x82, 0x00); + dev->reg.init_reg(0x83, 0x00); + dev->reg.init_reg(0x84, 0x00); + dev->reg.init_reg(0x85, 0x00); + dev->reg.init_reg(0x86, 0x00); + } + + dev->reg.init_reg(0x87, 0x00); + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8400F || + dev->model->model_id == ModelId::CANON_8600F) + { + dev->reg.init_reg(0x87, 0x02); + } + + // MTRPLS[0:7]: The width of the ADF motor trigger signal pulse. + if (dev->model->model_id != ModelId::CANON_8400F && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300) + { + dev->reg.init_reg(0x94, 0xff); + } + + // 0x95-0x97: SCANLEN[0:19]: Controls when paper jam bit is set in sheetfed + // scanners. + + // ONDUR[0:15]: The duration of PWM ON phase for LAMP control + // OFFDUR[0:15]: The duration of PWM OFF phase for LAMP control + // both of the above are in system clocks + if (dev->model->model_id == ModelId::CANON_8600F) { + dev->reg.init_reg(0x98, 0x00); + dev->reg.init_reg(0x99, 0x00); + dev->reg.init_reg(0x9a, 0x00); + dev->reg.init_reg(0x9b, 0x00); + } + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + // TODO: move to set for scan + dev->reg.init_reg(0x98, 0x03); + dev->reg.init_reg(0x99, 0x30); + dev->reg.init_reg(0x9a, 0x01); + dev->reg.init_reg(0x9b, 0x80); + } + + // RMADLY[0:1], MOTLAG, CMODE, STEPTIM, MULDMYLN, IFRS + dev->reg.init_reg(0x9d, 0x04); + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->reg.init_reg(0x9d, 0x00); + } + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8400F || + dev->model->model_id == ModelId::CANON_8600F || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0x9d, 0x08); // sets the multiplier for slope tables + } + + + // SEL3INV, TGSTIME[0:2], TGWTIME[0:2] + if (dev->model->model_id != ModelId::CANON_8400F && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300) + { + dev->reg.init_reg(0x9e, 0x00); // SENSOR_DEF + } + + if (dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300) { + dev->reg.init_reg(0xa2, 0x0f); + } + + // RFHSET[0:4]: Refresh time of SDRAM in units of 2us + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8600F) + { + dev->reg.init_reg(0xa2, 0x1f); + } + + // 0xa6-0xa9: controls gpio, see gl843_gpio_init + + // not documented + if (dev->model->model_id != ModelId::CANON_4400F && + dev->model->model_id != ModelId::CANON_8400F && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300) + { + dev->reg.init_reg(0xaa, 0x00); + } + + // GPOM9, MULSTOP[0-2], NODECEL, TB3TB1, TB5TB2, FIX16CLK. Not documented + if (dev->model->model_id != ModelId::CANON_8400F && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7200I && + dev->model->model_id != ModelId::PLUSTEK_OPTICFILM_7300) { + dev->reg.init_reg(0xab, 0x50); + } + if (dev->model->model_id == ModelId::CANON_4400F) { + dev->reg.init_reg(0xab, 0x00); + } + if (dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + // BUG: this should apply to ModelId::CANON_CANOSCAN_8600F too, but due to previous bug + // the 8400F case overwrote it + dev->reg.init_reg(0xab, 0x40); + } + + // VRHOME[3:2], VRMOVE[3:2], VRBACK[3:2]: Vref setting of the motor driver IC + // for various situations. + if (dev->model->model_id == ModelId::CANON_8600F || + dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050 || + dev->model->model_id == ModelId::HP_SCANJET_4850C) + { + dev->reg.init_reg(0xac, 0x00); + } + + dev->calib_reg = dev->reg; + + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I) { + uint8_t data[32] = { + 0x8c, 0x8f, 0xc9, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x6a, 0x73, 0x63, 0x68, 0x69, 0x65, 0x6e, 0x00, + }; + + dev->interface->write_buffer(0x3c, 0x3ff000, data, 32, + ScannerInterface::FLAG_SWAP_REGISTERS); + } +} + +// Send slope table for motor movement slope_table in machine byte order +static void gl843_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, + int steps) +{ + DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); + + int i; + char msg[10000]; + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + std::sprintf(msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) { + std::sprintf (msg+strlen(msg), "%d", slope_table[i]); + } + DBG(DBG_io, "%s: %s\n", __func__, msg); + } + + if (dev->interface->is_mock()) { + dev->interface->record_slope_table(table_nr, slope_table); + } + + // slope table addresses are fixed : 0x40000, 0x48000, 0x50000, 0x58000, 0x60000 + // XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14); + dev->interface->write_gamma(0x28, 0x40000 + 0x8000 * table_nr, table.data(), steps * 2, + ScannerInterface::FLAG_SWAP_REGISTERS); + + // FIXME: remove this when updating tests + gl843_set_buffer_address(dev, 0); +} + +static void gl843_set_ad_fe(Genesys_Device* dev) +{ + for (const auto& reg : dev->frontend.regs) { + dev->interface->write_fe_register(reg.address, reg.value); + } +} + +// Set values of analog frontend +void CommandSetGl843::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const +{ + DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" : + set == AFE_SET ? "set" : + set == AFE_POWER_SAVE ? "powersave" : "huh?"); + (void) sensor; + int i; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + dev->frontend = dev->frontend_initial; + dev->frontend_is_init = true; + } + + // check analog frontend type + // FIXME: looks like we write to that register with initial data + uint8_t fe_type = dev->interface->read_register(REG_0x04) & REG_0x04_FESET; + if (fe_type == 2) { + gl843_set_ad_fe(dev); + return; + } + if (fe_type != 0) { + throw SaneException(SANE_STATUS_UNSUPPORTED, "unsupported frontend type %d", fe_type); + } + + DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); + + for (i = 1; i <= 3; i++) + { + // FIXME: the check below is just historical artifact, we can remove it when convenient + if (!dev->frontend_is_init) { + dev->interface->write_fe_register(i, 0x00); + } else { + dev->interface->write_fe_register(i, dev->frontend.regs.get_value(0x00 + i)); + } + } + for (const auto& reg : sensor.custom_fe_regs) { + dev->interface->write_fe_register(reg.address, reg.value); + } + + for (i = 0; i < 3; i++) + { + // FIXME: the check below is just historical artifact, we can remove it when convenient + if (!dev->frontend_is_init) { + dev->interface->write_fe_register(0x20 + i, 0x00); + } else { + dev->interface->write_fe_register(0x20 + i, dev->frontend.get_offset(i)); + } + } + + if (dev->model->sensor_id == SensorId::CCD_KVSS080) { + for (i = 0; i < 3; i++) + { + // FIXME: the check below is just historical artifact, we can remove it when convenient + if (!dev->frontend_is_init) { + dev->interface->write_fe_register(0x24 + i, 0x00); + } else { + dev->interface->write_fe_register(0x24 + i, dev->frontend.regs.get_value(0x24 + i)); + } + } + } + + for (i = 0; i < 3; i++) + { + // FIXME: the check below is just historical artifact, we can remove it when convenient + if (!dev->frontend_is_init) { + dev->interface->write_fe_register(0x28 + i, 0x00); + } else { + dev->interface->write_fe_register(0x28 + i, dev->frontend.get_gain(i)); + } + } +} + + +static void gl843_init_motor_regs_scan(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const Motor_Profile& motor_profile, + unsigned int exposure, + unsigned scan_yres, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + MotorFlag flags) +{ + DBG_HELPER_ARGS(dbg, "exposure=%d, scan_yres=%d, step_type=%d, scan_lines=%d, scan_dummy=%d, " + "feed_steps=%d, flags=%x", + exposure, scan_yres, static_cast(motor_profile.step_type), + scan_lines, scan_dummy, feed_steps, static_cast(flags)); + + int use_fast_fed, coeff; + unsigned int lincnt; + unsigned feedl, dist; + GenesysRegister *r; + uint32_t z1, z2; + + /* get step multiplier */ + unsigned step_multiplier = gl843_get_step_multiplier (reg); + + use_fast_fed = 0; + + if ((scan_yres >= 300 && feed_steps > 900) || (has_flag(flags, MotorFlag::FEED))) { + use_fast_fed = 1; + } + + lincnt=scan_lines; + reg->set24(REG_LINCNT, lincnt); + DBG(DBG_io, "%s: lincnt=%d\n", __func__, lincnt); + + /* compute register 02 value */ + r = sanei_genesys_get_address(reg, REG_0x02); + r->value = 0x00; + sanei_genesys_set_motor_power(*reg, true); + + if (use_fast_fed) { + r->value |= REG_0x02_FASTFED; + } else { + r->value &= ~REG_0x02_FASTFED; + } + + /* in case of automatic go home, move until home sensor */ + if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { + r->value |= REG_0x02_AGOHOME | REG_0x02_NOTHOME; + } + + /* disable backtracking */ + if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE) + ||(scan_yres>=2400 && dev->model->model_id != ModelId::CANON_4400F) + ||(scan_yres>=sensor.optical_res)) + { + r->value |= REG_0x02_ACDCDIS; + } + + if (has_flag(flags, MotorFlag::REVERSE)) { + r->value |= REG_0x02_MTRREV; + } else { + r->value &= ~REG_0x02_MTRREV; + } + + /* scan and backtracking slope table */ + auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres, exposure, + dev->motor.base_ydpi, step_multiplier, + motor_profile); + + gl843_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count); + gl843_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count); + + reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier); + reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier); + + // fast table + unsigned fast_yres = sanei_genesys_get_lowest_ydpi(dev); + auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_yres, exposure, + dev->motor.base_ydpi, step_multiplier, + motor_profile); + gl843_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count); + gl843_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count); + gl843_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count); + + reg->set8(REG_FSHDEC, fast_table.steps_count / step_multiplier); + reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier); + + /* substract acceleration distance from feedl */ + feedl=feed_steps; + feedl <<= static_cast(motor_profile.step_type); + + dist = scan_table.steps_count / step_multiplier; + if (use_fast_fed) + { + dist += (fast_table.steps_count / step_multiplier) * 2; + } + DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + /* get sure when don't insane value : XXX STEF XXX in this case we should + * fall back to single table move */ + if (dist < feedl) { + feedl -= dist; + } else { + feedl = 1; + } + + reg->set24(REG_FEEDL, feedl); + DBG(DBG_io, "%s: feedl=%d\n", __func__, feedl); + + /* doesn't seem to matter that much */ + sanei_genesys_calculate_zmod(use_fast_fed, + exposure, + scan_table.table, + scan_table.steps_count / step_multiplier, + feedl, + scan_table.steps_count / step_multiplier, + &z1, + &z2); + if(scan_yres>600) + { + z1=0; + z2=0; + } + + reg->set24(REG_Z1MOD, z1); + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + + reg->set24(REG_Z2MOD, z2); + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + + r = sanei_genesys_get_address(reg, REG_0x1E); + r->value &= 0xf0; /* 0 dummy lines */ + r->value |= scan_dummy; /* dummy lines */ + + reg->set8_mask(REG_0x67, static_cast(motor_profile.step_type) << REG_0x67S_STEPSEL, 0xc0); + reg->set8_mask(REG_0x68, static_cast(motor_profile.step_type) << REG_0x68S_FSTPSEL, 0xc0); + + // steps for STOP table + reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier); + + /* Vref XXX STEF XXX : optical divider or step type ? */ + r = sanei_genesys_get_address (reg, 0x80); + if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE)) + { + r->value = 0x50; + coeff = sensor.get_hwdpi_divisor_for_dpi(scan_yres); + if (dev->model->motor_id == MotorId::KVSS080) { + if(coeff>=1) + { + r->value |= 0x05; + } + } + else { + switch(coeff) + { + case 4: + r->value |= 0x0a; + break; + case 2: + r->value |= 0x0f; + break; + case 1: + r->value |= 0x0f; + break; + } + } + } +} + + +/** @brief setup optical related registers + * start and pixels are expressed in optical sensor resolution coordinate + * space. + * @param dev device to use + * @param reg registers to set up + * @param exposure exposure time to use + * @param used_res scanning resolution used, may differ from + * scan's one + * @param start logical start pixel coordinate + * @param pixels logical number of pixels to use + * @param channels number of color channles used (1 or 3) + * @param depth bit depth of the scan (1, 8 or 16 bits) + * @param ccd_size_divisor true specifies how much x coordinates must be shrunk + * @param color_filter to choose the color channel used in gray scans + * @param flags to drive specific settings such no calibration, XPA use ... + */ +static void gl843_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, unsigned int exposure, + const ScanSession& session) +{ + DBG_HELPER_ARGS(dbg, "exposure=%d", exposure); + unsigned int dpihw; + unsigned int tgtime; /**> exposure time multiplier */ + GenesysRegister *r; + + /* tgtime */ + tgtime = exposure / 65536 + 1; + DBG(DBG_io2, "%s: tgtime=%d\n", __func__, tgtime); + + // to manage high resolution device while keeping good low resolution scanning speed, we make + // hardware dpi vary + dpihw = sensor.get_register_hwdpi(session.output_resolution); + DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw); + + /* sensor parameters */ + gl843_setup_sensor(dev, sensor, reg); + + // resolution is divided according to CKSEL + unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel(); + DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel); + + dev->cmd_set->set_fe(dev, sensor, AFE_SET); + + /* enable shading */ + regs_set_optical_off(dev->model->asic_type, *reg); + r = sanei_genesys_get_address (reg, REG_0x01); + if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION || + (dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE))) + { + r->value &= ~REG_0x01_DVDSET; + } else { + r->value |= REG_0x01_DVDSET; + } + + bool use_shdarea = dpihw > 600; + if (dev->model->model_id == ModelId::CANON_4400F) { + use_shdarea = session.params.xres <= 600; + } else if (dev->model->model_id == ModelId::CANON_8400F) { + use_shdarea = session.params.xres <= 400; + } + if (use_shdarea) { + r->value |= REG_0x01_SHDAREA; + } else { + r->value &= ~REG_0x01_SHDAREA; + } + + r = sanei_genesys_get_address (reg, REG_0x03); + if (dev->model->model_id == ModelId::CANON_8600F) { + r->value |= REG_0x03_AVEENB; + } else { + r->value &= ~REG_0x03_AVEENB; + } + + // FIXME: we probably don't need to set exposure to registers at this point. It was this way + // before a refactor. + sanei_genesys_set_lamp_power(dev, sensor, *reg, + !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); + + /* select XPA */ + r->value &= ~REG_0x03_XPASEL; + if (has_flag(session.params.flags, ScanFlag::USE_XPA)) { + r->value |= REG_0x03_XPASEL; + } + reg->state.is_xpa_on = has_flag(session.params.flags, ScanFlag::USE_XPA); + + /* BW threshold */ + r = sanei_genesys_get_address(reg, REG_0x2E); + r->value = dev->settings.threshold; + r = sanei_genesys_get_address(reg, REG_0x2F); + r->value = dev->settings.threshold; + + /* monochrome / color scan */ + r = sanei_genesys_get_address(reg, REG_0x04); + switch (session.params.depth) { + case 8: + r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); + break; + case 16: + r->value &= ~REG_0x04_LINEART; + r->value |= REG_0x04_BITSET; + break; + } + + r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); + if (session.params.channels == 1) + { + switch (session.params.color_filter) + { + case ColorFilter::RED: + r->value |= 0x14; + break; + case ColorFilter::BLUE: + r->value |= 0x1c; + break; + case ColorFilter::GREEN: + r->value |= 0x18; + break; + default: + break; // should not happen + } + } else { + switch (dev->frontend.layout.type) { + case FrontendType::WOLFSON: + r->value |= 0x10; // pixel by pixel + break; + case FrontendType::ANALOG_DEVICES: + r->value |= 0x20; // slow color pixel by pixel + break; + default: + throw SaneException("Invalid frontend type %d", + static_cast(dev->frontend.layout.type)); + } + } + + sanei_genesys_set_dpihw(*reg, sensor, dpihw); + + if (should_enable_gamma(session, sensor)) { + reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB; + } else { + reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB; + } + + unsigned dpiset = session.output_resolution * session.ccd_size_divisor * + ccd_pixels_per_system_pixel; + + if (sensor.dpiset_override != 0) { + dpiset = sensor.dpiset_override; + } + reg->set16(REG_DPISET, dpiset); + DBG(DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); + + reg->set16(REG_STRPIXEL, session.pixel_startx); + reg->set16(REG_ENDPIXEL, session.pixel_endx); + + /* MAXWD is expressed in 2 words unit */ + /* nousedspace = (mem_bank_range * 1024 / 256 -1 ) * 4; */ + // BUG: the division by ccd_size_divisor likely does not make sense + reg->set24(REG_MAXWD, (session.output_line_bytes / session.ccd_size_divisor) >> 1); + + reg->set16(REG_LPERIOD, exposure / tgtime); + DBG(DBG_io2, "%s: exposure used=%d\n", __func__, exposure/tgtime); + + r = sanei_genesys_get_address (reg, REG_DUMMY); + r->value = sensor.dummy_pixel; +} + +void CommandSetGl843::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const +{ + DBG_HELPER(dbg); + session.assert_computed(); + + int exposure; + + int slope_dpi = 0; + int dummy = 0; + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + + dummy = 0; + if (dev->model->model_id == ModelId::CANON_4400F && session.params.yres == 1200) { + dummy = 1; + } + + /* slope_dpi */ + /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ + if (dev->model->is_cis) + slope_dpi = session.params.yres * session.params.channels; + else + slope_dpi = session.params.yres; + slope_dpi = slope_dpi * (1 + dummy); + + /* scan_step_type */ + exposure = sensor.exposure_lperiod; + if (exposure < 0) { + throw std::runtime_error("Exposure not defined in sensor definition"); + } + const auto& motor_profile = sanei_genesys_get_motor_profile(*gl843_motor_profiles, + dev->model->motor_id, + exposure); + + DBG(DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, + static_cast(motor_profile.step_type)); + + // now _LOGICAL_ optical values used are known, setup registers + gl843_init_optical_regs_scan(dev, sensor, reg, exposure, session); + + /*** motor parameters ***/ + MotorFlag mflags = MotorFlag::NONE; + if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) { + mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE; + } + if (has_flag(session.params.flags, ScanFlag::FEEDING)) { + mflags |= MotorFlag::FEED; + } + if (has_flag(session.params.flags, ScanFlag::USE_XPA)) { + mflags |= MotorFlag::USE_XPA; + } + if (has_flag(session.params.flags, ScanFlag::REVERSE)) { + mflags |= MotorFlag::REVERSE; + } + + unsigned scan_lines = dev->model->is_cis ? session.output_line_count * session.params.channels + : session.output_line_count; + + gl843_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure, slope_dpi, + scan_lines, dummy, session.params.starty, mflags); + + dev->read_buffer.clear(); + dev->read_buffer.alloc(session.buffer_size_read); + + build_image_pipeline(dev, session); + + dev->read_active = true; + + dev->session = session; + + dev->total_bytes_read = 0; + dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines; + + DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read); +} + +ScanSession CommandSetGl843::calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const +{ + DBG_HELPER(dbg); + debug_dump(DBG_info, settings); + + int start; + + /* we have 2 domains for ccd: xres below or above half ccd max dpi */ + unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(settings.xres); + + if (settings.scan_method == ScanMethod::TRANSPARENCY || + settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + start = static_cast(dev->model->x_offset_ta); + } else { + start = static_cast(dev->model->x_offset); + } + + if (dev->model->model_id == ModelId::CANON_8600F) + { + // FIXME: this is probably just an artifact of a bug elsewhere + start /= ccd_size_divisor; + } + + start += static_cast(settings.tl_x); + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = settings.xres; + session.params.yres = settings.yres; + session.params.startx = start; // not used + session.params.starty = 0; // not used + session.params.pixels = settings.pixels; + session.params.requested_pixels = settings.requested_pixels; + session.params.lines = settings.lines; + session.params.depth = settings.depth; + session.params.channels = settings.get_channels(); + session.params.scan_method = settings.scan_method; + session.params.scan_mode = settings.scan_mode; + session.params.color_filter = settings.color_filter; + session.params.flags = ScanFlag::NONE; + + compute_session(dev, session, sensor); + + return session; +} + +/** + * for fast power saving methods only, like disabling certain amplifiers + * @param dev device to use + * @param enable true to set inot powersaving + * */ +void CommandSetGl843::save_power(Genesys_Device* dev, bool enable) const +{ + DBG_HELPER_ARGS(dbg, "enable = %d", enable); + + // switch KV-SS080 lamp off + if (dev->model->gpio_id == GpioId::KVSS080) { + uint8_t val = dev->interface->read_register(REG_0x6C); + if (enable) { + val &= 0xef; + } else { + val |= 0x10; + } + dev->interface->write_register(REG_0x6C, val); + } +} + +void CommandSetGl843::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const +{ + (void) dev; + DBG_HELPER_ARGS(dbg, "delay = %d", delay); +} + +static bool gl843_get_paper_sensor(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + + uint8_t val = dev->interface->read_register(REG_0x6D); + + return (val & 0x1) == 0; +} + +void CommandSetGl843::eject_document(Genesys_Device* dev) const +{ + (void) dev; + DBG_HELPER(dbg); +} + + +void CommandSetGl843::load_document(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + (void) dev; +} + +/** + * detects end of document and adjust current scan + * to take it into account + * used by sheetfed scanners + */ +void CommandSetGl843::detect_document_end(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + bool paper_loaded = gl843_get_paper_sensor(dev); + + /* sheetfed scanner uses home sensor as paper present */ + if (dev->document && !paper_loaded) { + DBG(DBG_info, "%s: no more document\n", __func__); + dev->document = false; + + unsigned scanned_lines = 0; + catch_all_exceptions(__func__, [&](){ sanei_genesys_read_scancnt(dev, &scanned_lines); }); + + std::size_t output_lines = dev->session.output_line_count; + + std::size_t offset_lines = static_cast( + (dev->model->post_scan * dev->session.params.yres) / MM_PER_INCH); + + std::size_t scan_end_lines = scanned_lines + offset_lines; + + std::size_t remaining_lines = dev->get_pipeline_source().remaining_bytes() / + dev->session.output_line_bytes_raw; + + DBG(DBG_io, "%s: scanned_lines=%u\n", __func__, scanned_lines); + DBG(DBG_io, "%s: scan_end_lines=%zu\n", __func__, scan_end_lines); + DBG(DBG_io, "%s: output_lines=%zu\n", __func__, output_lines); + DBG(DBG_io, "%s: remaining_lines=%zu\n", __func__, remaining_lines); + + if (scan_end_lines > output_lines) { + auto skip_lines = scan_end_lines - output_lines; + + if (remaining_lines > skip_lines) { + DBG(DBG_io, "%s: skip_lines=%zu\n", __func__, skip_lines); + + remaining_lines -= skip_lines; + dev->get_pipeline_source().set_remaining_bytes(remaining_lines * + dev->session.output_line_bytes_raw); + dev->total_bytes_to_read -= skip_lines * dev->session.output_line_bytes_requested; + } + } + } +} + +// enables or disables XPA slider motor +void gl843_set_xpa_motor_power(Genesys_Device* dev, Genesys_Register_Set& regs, bool set) +{ + DBG_HELPER(dbg); + uint8_t val; + + if (dev->model->model_id == ModelId::CANON_8400F) { + + if (set) { + val = dev->interface->read_register(0x6c); + val &= ~(REG_0x6C_GPIO16 | REG_0x6C_GPIO13); + if (dev->session.output_resolution >= 2400) { + val &= ~REG_0x6C_GPIO10; + } + dev->interface->write_register(0x6c, val); + + val = dev->interface->read_register(0xa9); + val |= REG_0xA9_GPO30; + val &= ~REG_0xA9_GPO29; + dev->interface->write_register(0xa9, val); + } else { + val = dev->interface->read_register(0x6c); + val |= REG_0x6C_GPIO16 | REG_0x6C_GPIO13; + dev->interface->write_register(0x6c, val); + + val = dev->interface->read_register(0xa9); + val &= ~REG_0xA9_GPO30; + val |= REG_0xA9_GPO29; + dev->interface->write_register(0xa9, val); + } + } else if (dev->model->model_id == ModelId::CANON_8600F) { + if (set) { + val = dev->interface->read_register(REG_0x6C); + val &= ~REG_0x6C_GPIO14; + if (dev->session.output_resolution >= 2400) { + val |= REG_0x6C_GPIO10; + } + dev->interface->write_register(REG_0x6C, val); + + val = dev->interface->read_register(REG_0xA6); + val |= REG_0xA6_GPIO17; + val &= ~REG_0xA6_GPIO23; + dev->interface->write_register(REG_0xA6, val); + } else { + val = dev->interface->read_register(REG_0x6C); + val |= REG_0x6C_GPIO14; + val &= ~REG_0x6C_GPIO10; + dev->interface->write_register(REG_0x6C, val); + + val = dev->interface->read_register(REG_0xA6); + val &= ~REG_0xA6_GPIO17; + val &= ~REG_0xA6_GPIO23; + dev->interface->write_register(REG_0xA6, val); + } + } else if (dev->model->model_id == ModelId::HP_SCANJET_G4050) { + if (set) { + // set MULTFILM et GPOADF + val = dev->interface->read_register(REG_0x6B); + val |=REG_0x6B_MULTFILM|REG_0x6B_GPOADF; + dev->interface->write_register(REG_0x6B, val); + + val = dev->interface->read_register(REG_0x6C); + val &= ~REG_0x6C_GPIO15; + dev->interface->write_register(REG_0x6C, val); + + /* Motor power ? No move at all without this one */ + val = dev->interface->read_register(REG_0xA6); + val |= REG_0xA6_GPIO20; + dev->interface->write_register(REG_0xA6, val); + + val = dev->interface->read_register(REG_0xA8); + val &= ~REG_0xA8_GPO27; + dev->interface->write_register(REG_0xA8, val); + + val = dev->interface->read_register(REG_0xA9); + val |= REG_0xA9_GPO32|REG_0xA9_GPO31; + dev->interface->write_register(REG_0xA9, val); + } else { + // unset GPOADF + val = dev->interface->read_register(REG_0x6B); + val &= ~REG_0x6B_GPOADF; + dev->interface->write_register(REG_0x6B, val); + + val = dev->interface->read_register(REG_0xA8); + val |= REG_0xA8_GPO27; + dev->interface->write_register(REG_0xA8, val); + + val = dev->interface->read_register(REG_0xA9); + val &= ~REG_0xA9_GPO31; + dev->interface->write_register(REG_0xA9, val); + } + } + regs.state.is_xpa_motor_on = set; +} + + +/** @brief light XPA lamp + * toggle gpios to switch off regular lamp and light on the + * XPA light + * @param dev device to set up + */ +static void gl843_set_xpa_lamp_power(Genesys_Device* dev, bool set) +{ + DBG_HELPER(dbg); + + struct LampSettings { + ModelId model_id; + ScanMethod scan_method; + GenesysRegisterSettingSet regs_on; + GenesysRegisterSettingSet regs_off; + }; + + // FIXME: BUG: we're not clearing the registers to the previous state when returning back when + // turning off the lamp + LampSettings settings[] = { + { ModelId::CANON_8400F, ScanMethod::TRANSPARENCY, { + { 0xa6, 0x34, 0xf4 }, + }, { + { 0xa6, 0x40, 0x70 }, + } + }, + { ModelId::CANON_8400F, ScanMethod::TRANSPARENCY_INFRARED, { + { 0x6c, 0x40, 0x40 }, + { 0xa6, 0x01, 0xff }, + }, { + { 0x6c, 0x00, 0x40 }, + { 0xa6, 0x00, 0xff }, + } + }, + { ModelId::CANON_8600F, ScanMethod::TRANSPARENCY, { + { 0xa6, 0x34, 0xf4 }, + { 0xa7, 0xe0, 0xe0 }, + }, { + { 0xa6, 0x40, 0x70 }, + } + }, + { ModelId::CANON_8600F, ScanMethod::TRANSPARENCY_INFRARED, { + { 0xa6, 0x00, 0xc0 }, + { 0xa7, 0xe0, 0xe0 }, + { 0x6c, 0x80, 0x80 }, + }, { + { 0xa6, 0x00, 0xc0 }, + { 0x6c, 0x00, 0x80 }, + } + }, + { ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY, { + }, { + { 0xa6, 0x40, 0x70 }, // BUG: remove this cleanup write, it was enabled by accident + } + }, + { ModelId::PLUSTEK_OPTICFILM_7200I, ScanMethod::TRANSPARENCY_INFRARED, { + { 0xa8, 0x07, 0x07 }, + }, { + { 0xa8, 0x00, 0x07 }, + } + }, + { ModelId::PLUSTEK_OPTICFILM_7300, ScanMethod::TRANSPARENCY, {}, {} }, + { ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY, {}, {} }, + { ModelId::PLUSTEK_OPTICFILM_7500I, ScanMethod::TRANSPARENCY_INFRARED, { + { 0xa8, 0x07, 0x07 }, + }, { + { 0xa8, 0x00, 0x07 }, + } + }, + }; + + for (const auto& setting : settings) { + if (setting.model_id == dev->model->model_id && + setting.scan_method == dev->settings.scan_method) + { + apply_reg_settings_to_device(*dev, set ? setting.regs_on : setting.regs_off); + return; + } + } + + // BUG: we're currently calling the function in shut down path of regular lamp + if (set) { + throw SaneException("Unexpected code path entered"); + } + + GenesysRegisterSettingSet regs = { + { 0xa6, 0x40, 0x70 }, + }; + apply_reg_settings_to_device(*dev, regs); + // TODO: throw exception when we're only calling this function in error return path + // throw SaneException("Could not find XPA lamp settings"); +} + +// Send the low-level scan command +void CommandSetGl843::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, bool start_motor) const +{ + DBG_HELPER(dbg); + (void) sensor; + + /* set up GPIO for scan */ + switch(dev->model->gpio_id) { + /* KV case */ + case GpioId::KVSS080: + dev->interface->write_register(REG_0xA9, 0x00); + dev->interface->write_register(REG_0xA6, 0xf6); + // blinking led + dev->interface->write_register(0x7e, 0x04); + break; + case GpioId::G4050: + dev->interface->write_register(REG_0xA7, 0xfe); + dev->interface->write_register(REG_0xA8, 0x3e); + dev->interface->write_register(REG_0xA9, 0x06); + if ((reg->get8(0x05) & REG_0x05_DPIHW) == REG_0x05_DPIHW_600) { + dev->interface->write_register(REG_0x6C, 0x20); + dev->interface->write_register(REG_0xA6, 0x44); + } else { + dev->interface->write_register(REG_0x6C, 0x60); + dev->interface->write_register(REG_0xA6, 0x46); + } + + if (reg->state.is_xpa_on && reg->state.is_lamp_on) { + gl843_set_xpa_lamp_power(dev, true); + } + + if (reg->state.is_xpa_on) { + gl843_set_xpa_motor_power(dev, *reg, true); + } + + // blinking led + dev->interface->write_register(REG_0x7E, 0x01); + break; + case GpioId::CANON_8400F: + case GpioId::CANON_8600F: + if (reg->state.is_xpa_on && reg->state.is_lamp_on) { + gl843_set_xpa_lamp_power(dev, true); + } + if (reg->state.is_xpa_on) { + gl843_set_xpa_motor_power(dev, *reg, true); + } + break; + case GpioId::PLUSTEK_OPTICFILM_7200I: + case GpioId::PLUSTEK_OPTICFILM_7300: + case GpioId::PLUSTEK_OPTICFILM_7500I: { + if (reg->state.is_xpa_on && reg->state.is_lamp_on) { + gl843_set_xpa_lamp_power(dev, true); + } + break; + } + case GpioId::CANON_4400F: + default: + break; + } + + // clear scan and feed count + dev->interface->write_register(REG_0x0D, REG_0x0D_CLRLNCNT | REG_0x0D_CLRMCNT); + + // enable scan and motor + uint8_t val = dev->interface->read_register(REG_0x01); + val |= REG_0x01_SCAN; + dev->interface->write_register(REG_0x01, val); + + scanner_start_action(*dev, start_motor); + + if (reg->state.is_motor_on) { + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); + } + if (reg->state.is_xpa_motor_on) { + dev->advance_head_pos_by_session(ScanHeadId::SECONDARY); + } +} + + +// Send the stop scan command +void CommandSetGl843::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg, + bool check_stop) const +{ + DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop); + + // post scan gpio + dev->interface->write_register(0x7e, 0x00); + + // turn off XPA lamp if needed + // BUG: the if condition below probably shouldn't be enabled when XPA is off + if (reg->state.is_xpa_on || reg->state.is_lamp_on) { + gl843_set_xpa_lamp_power(dev, false); + } + + if (!dev->model->is_sheetfed) { + scanner_stop_action(*dev); + } +} + +/** @brief Moves the slider to the home (top) position slowly + * */ +void CommandSetGl843::move_back_home(Genesys_Device* dev, bool wait_until_home) const +{ + scanner_move_back_home(*dev, wait_until_home); +} + +// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi +// from very top of scanner +void CommandSetGl843::search_start_position(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + Genesys_Register_Set local_reg; + + int pixels = 600; + int dpi = 300; + + local_reg = dev->reg; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method); + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; // we should give a small offset here - ~60 steps + session.params.pixels = 600; + session.params.lines = dev->model->search_lines; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::GREEN; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::IGNORE_LINE_DISTANCE | + ScanFlag::DISABLE_BUFFER_FULL_MOVE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &local_reg, session); + + // send to scanner + dev->interface->write_registers(local_reg); + + dev->cmd_set->begin_scan(dev, sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_start_position"); + end_scan(dev, &local_reg, true); + dev->reg = local_reg; + return; + } + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + Image image = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw); + + scanner_stop_action_no_move(*dev, local_reg); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl843_search_position.pnm", image); + } + + dev->cmd_set->end_scan(dev, &local_reg, true); + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + + for (auto& sensor_update : + sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) + { + sanei_genesys_search_reference_point(dev, sensor_update, image.get_row_ptr(0), 0, dpi, + pixels, dev->model->search_lines); + } +} + +// sets up register for coarse gain calibration +// todo: check it for scanners using it +void CommandSetGl843::init_regs_for_coarse_calibration(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + + ScanFlag flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) { + flags |= ScanFlag::USE_XPA; + } + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel(); + session.params.lines = 20; + session.params.depth = 16; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, ®s, session); + + sanei_genesys_set_motor_power(regs, false); + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres); + + dev->interface->write_registers(regs); +} + +// init registers for shading calibration shading calibration is done at dpihw +void CommandSetGl843::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int move, resolution, dpihw, factor; + + /* initial calibration reg values */ + regs = dev->reg; + + dev->calib_channels = 3; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + dev->calib_lines = dev->model->shading_ta_lines; + } else { + dev->calib_lines = dev->model->shading_lines; + } + + dpihw = sensor.get_logical_hwdpi(dev->settings.xres); + factor=sensor.optical_res/dpihw; + resolution=dpihw; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, dev->calib_channels, + dev->settings.scan_method); + + if ((dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) && + dev->model->model_id == ModelId::CANON_8600F && + dev->settings.xres == 4800) + { + float offset = static_cast(dev->model->x_offset_ta); + offset /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); + offset = static_cast((offset * calib_sensor.optical_res) / MM_PER_INCH); + + float size = static_cast(dev->model->x_size_ta); + size /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); + size = static_cast((size * calib_sensor.optical_res) / MM_PER_INCH); + + dev->calib_pixels_offset = static_cast(offset); + dev->calib_pixels = static_cast(size); + } + else + { + dev->calib_pixels_offset = 0; + dev->calib_pixels = calib_sensor.sensor_pixels / factor; + } + + dev->calib_resolution = resolution; + + ScanFlag flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::DISABLE_BUFFER_FULL_MOVE | + ScanFlag::IGNORE_LINE_DISTANCE; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + // note: move_to_ta() function has already been called and the sensor is at the + // transparency adapter + move = static_cast(dev->model->y_offset_calib_white_ta - dev->model->y_offset_sensor_to_ta); + flags |= ScanFlag::USE_XPA; + } else { + move = static_cast(dev->model->y_offset_calib_white); + } + + move = static_cast((move * resolution) / MM_PER_INCH); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = dev->calib_pixels_offset; + session.params.starty = move; + session.params.pixels = dev->calib_pixels; + session.params.lines = dev->calib_lines; + session.params.depth = 16; + session.params.channels = dev->calib_channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + // the pixel number may be updated to conform to scanner constraints + dev->calib_pixels = session.output_pixels; + + dev->calib_session = session; + dev->calib_total_bytes_to_read = session.output_total_bytes_raw; + + dev->interface->write_registers(regs); +} + +/** @brief set up registers for the actual scan + */ +void CommandSetGl843::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + float move; + int move_dpi; + float start; + + debug_dump(DBG_info, dev->settings); + + move_dpi = dev->motor.base_ydpi; + + ScanFlag flags = ScanFlag::NONE; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + // note: move_to_ta() function has already been called and the sensor is at the + // transparency adapter + if (dev->ignore_offsets) { + move = 0; + } else { + move = static_cast(dev->model->y_offset_ta - dev->model->y_offset_sensor_to_ta); + } + flags |= ScanFlag::USE_XPA; + } else { + if (dev->ignore_offsets) { + move = 0; + } else { + move = static_cast(dev->model->y_offset); + } + } + + move += static_cast(dev->settings.tl_y); + move = static_cast((move * move_dpi) / MM_PER_INCH); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* start */ + if (dev->settings.scan_method==ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + start = static_cast(dev->model->x_offset_ta); + } else { + start = static_cast(dev->model->x_offset); + } + + if (dev->model->model_id == ModelId::CANON_8400F || + dev->model->model_id == ModelId::CANON_8600F) + { + // FIXME: this is probably just an artifact of a bug elsewhere + start /= sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); + } + + start = static_cast(start + dev->settings.tl_x); + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = dev->settings.pixels; + session.params.requested_pixels = dev->settings.requested_pixels; + session.params.lines = dev->settings.lines; + session.params.depth = dev->settings.depth; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &dev->reg, session); +} + +/** + * This function sends gamma tables to ASIC + */ +void CommandSetGl843::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + int size; + int i; + + size = 256; + + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3); + + std::vector rgamma = get_gamma_table(dev, sensor, GENESYS_RED); + std::vector ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN); + std::vector bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE); + + // copy sensor specific's gamma tables + for (i = 0; i < size; i++) { + gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff; + gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff; + gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff; + gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff; + gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff; + gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff; + } + + dev->interface->write_gamma(0x28, 0x0000, gamma.data(), size * 2 * 3, + ScannerInterface::FLAG_SWAP_REGISTERS); +} + +/* this function does the led calibration by scanning one line of the calibration + area below scanner's top on white strip. + +-needs working coarse/gain +*/ +SensorExposure CommandSetGl843::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int num_pixels; + int avg[3], avga, avge; + int turn; + uint16_t expr, expg, expb; + + // offset calibration is always done in color mode + unsigned channels = 3; + + // take a copy, as we're going to modify exposure + auto calib_sensor = sanei_genesys_find_sensor(dev, sensor.optical_res, channels, + dev->settings.scan_method); + + num_pixels = (calib_sensor.sensor_pixels * calib_sensor.optical_res) / calib_sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + ScanSession session; + session.params.xres = calib_sensor.sensor_pixels; + session.params.yres = dev->motor.base_ydpi; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + dev->interface->write_registers(regs); + +/* + we try to get equal bright leds here: + + loop: + average per color + adjust exposure times + */ + + expr = calib_sensor.exposure.red; + expg = calib_sensor.exposure.green; + expb = calib_sensor.exposure.blue; + + turn = 0; + + bool acceptable = false; + do + { + + calib_sensor.exposure.red = expr; + calib_sensor.exposure.green = expg; + calib_sensor.exposure.blue = expb; + + regs_set_exposure(dev->model->asic_type, regs, calib_sensor.exposure); + + dev->interface->write_registers(regs); + + DBG(DBG_info, "%s: starting first line reading\n", __func__); + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("led_calibration"); + move_back_home(dev, true); + return calib_sensor.exposure; + } + + auto image = read_unshuffled_image_from_scanner(dev, session, + session.output_total_bytes_raw); + scanner_stop_action_no_move(*dev, regs); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl843_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, image); + } + + acceptable = true; + + for (unsigned ch = 0; ch < channels; ch++) { + avg[ch] = 0; + for (std::size_t x = 0; x < image.get_width(); x++) { + avg[ch] += image.get_raw_channel(x, 0, ch); + } + avg[ch] /= image.get_width(); + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + acceptable = true; + + if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || + avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || + avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) + acceptable = false; + + if (!acceptable) + { + avga = (avg[0] + avg[1] + avg[2]) / 3; + expr = (expr * avga) / avg[0]; + expg = (expg * avga) / avg[1]; + expb = (expb * avga) / avg[2]; +/* + keep the resulting exposures below this value. + too long exposure drives the ccd into saturation. + we may fix this by relying on the fact that + we get a striped scan without shading, by means of + statistical calculation +*/ + avge = (expr + expg + expb) / 3; + + /* don't overflow max exposure */ + if (avge > 3000) + { + expr = (expr * 2000) / avge; + expg = (expg * 2000) / avge; + expb = (expb * 2000) / avge; + } + if (avge < 50) + { + expr = (expr * 50) / avge; + expg = (expg * 50) / avge; + expb = (expb * 50) / avge; + } + + } + scanner_stop_action(*dev); + + turn++; + + } + while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, expr, expg, expb); + + move_back_home(dev, true); + + return calib_sensor.exposure; +} + + + +/** + * average dark pixels of a 8 bits scan of a given channel + */ +static int dark_average_channel(const Image& image, unsigned black, unsigned channel) +{ + auto channels = get_pixel_channels(image.get_format()); + + unsigned avg[3]; + + // computes average values on black margin + for (unsigned ch = 0; ch < channels; ch++) { + avg[ch] = 0; + unsigned count = 0; + // FIXME: start with the second line because the black pixels often have noise on the first + // line; the cause is probably incorrectly cleaned up previous scan + for (std::size_t y = 1; y < image.get_height(); y++) { + for (unsigned j = 0; j < black; j++) { + avg[ch] += image.get_raw_channel(j, y, ch); + count++; + } + } + if (count > 0) { + avg[ch] /= count; + } + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, ch, avg[ch]); + } + DBG(DBG_info, "%s: average = %d\n", __func__, avg[channel]); + return avg[channel]; +} + +/** @brief calibrate AFE offset + * Iterate doing scans at target dpi until AFE offset if correct. One + * color line is scanned at a time. Scanning head doesn't move. + * @param dev device to calibrate + */ +void CommandSetGl843::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + + if (dev->frontend.layout.type != FrontendType::WOLFSON) + return; + + unsigned channels; + int pass, resolution, lines; + int topavg[3], bottomavg[3], avg[3]; + int top[3], bottom[3], black_pixels, pixels, factor, dpihw; + + /* offset calibration is always done in color mode */ + channels = 3; + lines = 8; + + // compute divider factor to compute final pixels number + dpihw = sensor.get_logical_hwdpi(dev->settings.xres); + factor = sensor.optical_res / dpihw; + resolution = dpihw; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + + int target_pixels = calib_sensor.sensor_pixels / factor; + int start_pixel = 0; + black_pixels = calib_sensor.black_pixels / factor; + + if ((dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) && + dev->model->model_id == ModelId::CANON_8600F && + dev->settings.xres == 4800) + { + start_pixel = static_cast(dev->model->x_offset_ta); + start_pixel /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); + start_pixel = static_cast((start_pixel * calib_sensor.optical_res) / MM_PER_INCH); + + target_pixels = static_cast(dev->model->x_size_ta); + target_pixels /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); + target_pixels = static_cast((target_pixels * calib_sensor.optical_res) / MM_PER_INCH); + } + + ScanFlag flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + + if (dev->settings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + flags |= ScanFlag::USE_XPA; + } + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = start_pixel; + session.params.starty = 0; + session.params.pixels = target_pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = ColorFilter::RED; + session.params.flags = flags; + compute_session(dev, session, calib_sensor); + pixels = session.output_pixels; + + DBG(DBG_io, "%s: dpihw =%d\n", __func__, dpihw); + DBG(DBG_io, "%s: factor =%d\n", __func__, factor); + DBG(DBG_io, "%s: resolution =%d\n", __func__, resolution); + DBG(DBG_io, "%s: pixels =%d\n", __func__, pixels); + DBG(DBG_io, "%s: black_pixels=%d\n", __func__, black_pixels); + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + sanei_genesys_set_motor_power(regs, false); + + // init gain and offset + for (unsigned ch = 0; ch < 3; ch++) + { + bottom[ch] = 10; + dev->frontend.set_offset(ch, bottom[ch]); + dev->frontend.set_gain(ch, 0); + } + dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); + + // scan with bottom AFE settings + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting first line reading\n", __func__); + + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("offset_calibration"); + scanner_stop_action_no_move(*dev, regs); + return; + } + + auto first_line = read_unshuffled_image_from_scanner(dev, session, + session.output_total_bytes_raw); + scanner_stop_action_no_move(*dev, regs); + + if (DBG_LEVEL >= DBG_data) + { + char fn[40]; + std::snprintf(fn, 40, "gl843_bottom_offset_%03d_%03d_%03d.pnm", + bottom[0], bottom[1], bottom[2]); + sanei_genesys_write_pnm_file(fn, first_line); + } + + for (unsigned ch = 0; ch < 3; ch++) { + bottomavg[ch] = dark_average_channel(first_line, black_pixels, ch); + DBG(DBG_io2, "%s: bottom avg %d=%d\n", __func__, ch, bottomavg[ch]); + } + + // now top value + for (unsigned ch = 0; ch < 3; ch++) { + top[ch] = 255; + dev->frontend.set_offset(ch, top[ch]); + } + dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); + + // scan with top AFE values + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + auto second_line = read_unshuffled_image_from_scanner(dev, session, + session.output_total_bytes_raw); + scanner_stop_action_no_move(*dev, regs); + + for (unsigned ch = 0; ch < 3; ch++){ + topavg[ch] = dark_average_channel(second_line, black_pixels, ch); + DBG(DBG_io2, "%s: top avg %d=%d\n", __func__, ch, topavg[ch]); + } + + pass = 0; + + std::vector debug_image; + size_t debug_image_lines = 0; + std::string debug_image_info; + + /* loop until acceptable level */ + while ((pass < 32) + && ((top[0] - bottom[0] > 1) + || (top[1] - bottom[1] > 1) || (top[2] - bottom[2] > 1))) + { + pass++; + + // settings for new scan + for (unsigned ch = 0; ch < 3; ch++) { + if (top[ch] - bottom[ch] > 1) { + dev->frontend.set_offset(ch, (top[ch] + bottom[ch]) / 2); + } + } + dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); + + // scan with no move + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + second_line = read_unshuffled_image_from_scanner(dev, session, + session.output_total_bytes_raw); + scanner_stop_action_no_move(*dev, regs); + + if (DBG_LEVEL >= DBG_data) + { + char title[100]; + std::snprintf(title, 100, "lines: %d pixels_per_line: %d offsets[0..2]: %d %d %d\n", + lines, pixels, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); + debug_image_info += title; + std::copy(second_line.get_row_ptr(0), + second_line.get_row_ptr(0) + second_line.get_row_bytes() * second_line.get_height(), + std::back_inserter(debug_image)); + debug_image_lines += lines; + } + + for (unsigned ch = 0; ch < 3; ch++) { + avg[ch] = dark_average_channel(second_line, black_pixels, ch); + DBG(DBG_info, "%s: avg[%d]=%d offset=%d\n", __func__, ch, avg[ch], + dev->frontend.get_offset(ch)); + } + + // compute new boundaries + for (unsigned ch = 0; ch < 3; ch++) { + if (topavg[ch] >= avg[ch]) { + topavg[ch] = avg[ch]; + top[ch] = dev->frontend.get_offset(ch); + } else { + bottomavg[ch] = avg[ch]; + bottom[ch] = dev->frontend.get_offset(ch); + } + } + } + + if (DBG_LEVEL >= DBG_data) + { + sanei_genesys_write_file("gl843_offset_all_desc.txt", + reinterpret_cast(debug_image_info.data()), + debug_image_info.size()); + sanei_genesys_write_pnm_file("gl843_offset_all.pnm", + debug_image.data(), session.params.depth, channels, pixels, + debug_image_lines); + } + + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); +} + + +/* alternative coarse gain calibration + this on uses the settings from offset_calibration and + uses only one scanline + */ +/* + with offset and coarse calibration we only want to get our input range into + a reasonable shape. the fine calibration of the upper and lower bounds will + be done with shading. + */ +void CommandSetGl843::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const +{ + DBG_HELPER_ARGS(dbg, "dpi = %d", dpi); + int factor, dpihw; + float coeff; + int lines; + int resolution; + + if (dev->frontend.layout.type != FrontendType::WOLFSON) + return; + + dpihw = sensor.get_logical_hwdpi(dpi); + factor=sensor.optical_res/dpihw; + + // coarse gain calibration is always done in color mode + unsigned channels = 3; + + /* follow CKSEL */ + if (dev->model->sensor_id == SensorId::CCD_KVSS080) { + if(dev->settings.xressettings.scan_method == ScanMethod::TRANSPARENCY || + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + flags |= ScanFlag::USE_XPA; + } + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, channels, + dev->settings.scan_method); + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = target_pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = flags; + compute_session(dev, session, calib_sensor); + std::size_t pixels = session.output_pixels; + + try { + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + } catch (...) { + catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); }); + throw; + } + + sanei_genesys_set_motor_power(regs, false); + + dev->interface->write_registers(regs); + + dev->cmd_set->set_fe(dev, calib_sensor, AFE_SET); + dev->cmd_set->begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("coarse_gain_calibration"); + scanner_stop_action(*dev); + move_back_home(dev, true); + return; + } + + auto line = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw); + scanner_stop_action_no_move(*dev, regs); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl843_gain.pnm", line); + } + + // average value on each channel + for (unsigned ch = 0; ch < channels; ch++) { + + std::vector values; + // FIXME: start from the second line because the first line often has artifacts. Probably + // caused by unclean cleanup of previous scan + for (std::size_t x = pixels / 4; x < (pixels * 3 / 4); x++) { + values.push_back(line.get_raw_channel(x, 1, ch)); + } + + // pick target value at 95th percentile of all values. There may be a lot of black values + // in transparency scans for example + std::sort(values.begin(), values.end()); + uint16_t curr_output = values[unsigned((values.size() - 1) * 0.95)]; + float target_value = calib_sensor.gain_white_ref * coeff; + + int code = compute_frontend_gain(curr_output, target_value, dev->frontend.layout.type); + dev->frontend.set_gain(ch, code); + + DBG(DBG_proc, "%s: channel %d, max=%d, target=%d, setting:%d\n", __func__, ch, curr_output, + static_cast(target_value), code); + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + if (channels == 1) { + dev->frontend.set_gain(0, dev->frontend.get_gain(1)); + dev->frontend.set_gain(2, dev->frontend.get_gain(1)); + } + + scanner_stop_action(*dev); + + move_back_home(dev, true); +} + +// wait for lamp warmup by scanning the same line until difference +// between 2 scans is below a threshold +void CommandSetGl843::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, int* channels, + int* total_size) const +{ + DBG_HELPER(dbg); + int num_pixels; + int dpihw; + int resolution; + int factor; + + /* setup scan */ + *channels=3; + resolution=600; + dpihw = sensor.get_logical_hwdpi(resolution); + resolution=dpihw; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, *channels, + dev->settings.scan_method); + factor = calib_sensor.optical_res/dpihw; + num_pixels = calib_sensor.sensor_pixels/(factor*2); + *total_size = num_pixels * 3 * 1; + + *reg = dev->reg; + + ScanSession session; + session.params.xres = resolution; + session.params.yres = resolution; + session.params.startx = num_pixels/2; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 8; + session.params.channels = *channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, reg, session); + + sanei_genesys_set_motor_power(*reg, false); + dev->interface->write_registers(*reg); +} + +/** + * set up GPIO/GPOE for idle state +WRITE GPIO[17-21]= GPIO19 +WRITE GPOE[17-21]= GPOE21 GPOE20 GPOE19 GPOE18 +genesys_write_register(0xa8,0x3e) +GPIO(0xa8)=0x3e + */ +static void gl843_init_gpio(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + apply_registers_ordered(dev->gpo.regs, { 0x6e, 0x6f }, [&](const GenesysRegisterSetting& reg) + { + dev->interface->write_register(reg.address, reg.value); + }); +} + + +/* * + * initialize ASIC from power on condition + */ +void CommandSetGl843::asic_boot(Genesys_Device* dev, bool cold) const +{ + DBG_HELPER(dbg); + uint8_t val; + + if (cold) { + dev->interface->write_register(0x0e, 0x01); + dev->interface->write_register(0x0e, 0x00); + } + + if(dev->usb_mode == 1) + { + val = 0x14; + } + else + { + val = 0x11; + } + dev->interface->write_0x8c(0x0f, val); + + // test CHKVER + val = dev->interface->read_register(REG_0x40); + if (val & REG_0x40_CHKVER) { + val = dev->interface->read_register(0x00); + DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); + } + + /* Set default values for registers */ + gl843_init_registers (dev); + + if (dev->model->model_id == ModelId::CANON_8600F) { + // turns on vref control for maximum current of the motor driver + dev->interface->write_register(REG_0x6B, 0x72); + } else { + dev->interface->write_register(REG_0x6B, 0x02); + } + + // Write initial registers + dev->interface->write_registers(dev->reg); + + // Enable DRAM by setting a rising edge on bit 3 of reg 0x0b + val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL; + val = (val | REG_0x0B_ENBDRAM); + dev->interface->write_register(REG_0x0B, val); + dev->reg.find_reg(0x0b).value = val; + + if (dev->model->model_id == ModelId::CANON_8400F) { + dev->interface->write_0x8c(0x1e, 0x01); + dev->interface->write_0x8c(0x10, 0xb4); + dev->interface->write_0x8c(0x0f, 0x02); + } + else if (dev->model->model_id == ModelId::CANON_8600F) { + dev->interface->write_0x8c(0x10, 0xc8); + } else if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + dev->interface->write_0x8c(0x10, 0xd4); + } else { + dev->interface->write_0x8c(0x10, 0xb4); + } + + /* CLKSET */ + int clock_freq = REG_0x0B_48MHZ; + switch (dev->model->model_id) { + case ModelId::CANON_8600F: + clock_freq = REG_0x0B_60MHZ; + break; + case ModelId::PLUSTEK_OPTICFILM_7200I: + clock_freq = REG_0x0B_30MHZ; + break; + case ModelId::PLUSTEK_OPTICFILM_7300: + case ModelId::PLUSTEK_OPTICFILM_7500I: + clock_freq = REG_0x0B_40MHZ; + break; + default: + break; + } + + val = (dev->reg.find_reg(0x0b).value & ~REG_0x0B_CLKSET) | clock_freq; + + dev->interface->write_register(REG_0x0B, val); + dev->reg.find_reg(0x0b).value = val; + + /* prevent further writings by bulk write register */ + dev->reg.remove_reg(0x0b); + + if (dev->model->model_id != ModelId::CANON_8600F) { + // set up end access + // FIXME: this is overwritten in gl843_init_gpio + dev->interface->write_register(REG_0xA7, 0x04); + dev->interface->write_register(REG_0xA9, 0x00); + } + + // set RAM read address + dev->interface->write_register(REG_0x29, 0x00); + dev->interface->write_register(REG_0x2A, 0x00); + dev->interface->write_register(REG_0x2B, 0x00); + + // setup gpio + gl843_init_gpio(dev); + + scanner_move(*dev, dev->model->default_method, 300, Direction::FORWARD); + dev->interface->sleep_ms(100); +} + +/* * + * initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +void CommandSetGl843::init(Genesys_Device* dev) const +{ + DBG_INIT (); + DBG_HELPER(dbg); + + sanei_genesys_asic_init(dev, 0); +} + +void CommandSetGl843::update_hardware_sensors(Genesys_Scanner* s) const +{ + DBG_HELPER(dbg); + /* do what is needed to get a new set of events, but try to not lose + any of them. + */ + + uint8_t val = s->dev->interface->read_register(REG_0x6D); + + switch (s->dev->model->gpio_id) + { + case GpioId::KVSS080: + s->buttons[BUTTON_SCAN_SW].write((val & 0x04) == 0); + break; + case GpioId::G4050: + s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); + s->buttons[BUTTON_FILE_SW].write((val & 0x02) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); + s->buttons[BUTTON_COPY_SW].write((val & 0x08) == 0); + break; + case GpioId::CANON_4400F: + case GpioId::CANON_8400F: + default: + break; + } +} + +/** @brief move sensor to transparency adaptor + * Move sensor to the calibration of the transparency adapator (XPA). + * @param dev device to use + */ +void CommandSetGl843::move_to_ta(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + + const auto& resolution_settings = dev->model->get_resolution_settings(dev->model->default_method); + float resolution = resolution_settings.get_min_resolution_y(); + + unsigned multiplier = 16; + if (dev->model->model_id == ModelId::CANON_8400F) { + multiplier = 4; + } + unsigned feed = static_cast(multiplier * (dev->model->y_offset_sensor_to_ta * resolution) / + MM_PER_INCH); + scanner_move(*dev, dev->model->default_method, feed, Direction::FORWARD); +} + + +/** @brief search for a full width black or white strip. + * This function searches for a black or white stripe across the scanning area. + * When searching backward, the searched area must completely be of the desired + * color since this area will be used for calibration which scans forward. + * @param dev scanner device + * @param forward true if searching forward, false if searching backward + * @param black true if searching for a black strip, false for a white strip + */ +void CommandSetGl843::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const +{ + DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse"); + unsigned int pixels, lines, channels; + Genesys_Register_Set local_reg; + int dpi; + unsigned int pass, count, found, x, y; + + dev->cmd_set->set_fe(dev, sensor, AFE_SET); + scanner_stop_action(*dev); + + /* set up for a gray scan at lowest dpi */ + dpi = sanei_genesys_get_lowest_dpi(dev); + channels = 1; + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, dpi, channels, + dev->settings.scan_method); + + /* 10 MM */ + /* lines = (10 * dpi) / MM_PER_INCH; */ + /* shading calibation is done with dev->motor.base_ydpi */ + lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; + pixels = (calib_sensor.sensor_pixels * dpi) / calib_sensor.optical_res; + + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + + local_reg = dev->reg; + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::RED; + session.params.flags = ScanFlag::DISABLE_SHADING | ScanFlag::DISABLE_SHADING; + if (!forward) { + session.params.flags = ScanFlag::REVERSE; + } + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, &local_reg, session); + + dev->interface->write_registers(local_reg); + + dev->cmd_set->begin_scan(dev, calib_sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_strip"); + scanner_stop_action(*dev); + return; + } + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + auto data = read_unshuffled_image_from_scanner(dev, session, + session.output_total_bytes_raw); + + scanner_stop_action(*dev); + + pass = 0; + if (DBG_LEVEL >= DBG_data) + { + char fn[40]; + std::snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(fn, data); + } + + /* loop until strip is found or maximum pass number done */ + found = 0; + while (pass < 20 && !found) + { + dev->interface->write_registers(local_reg); + + // now start scan + dev->cmd_set->begin_scan(dev, calib_sensor, &local_reg, true); + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + data = read_unshuffled_image_from_scanner(dev, session, session.output_total_bytes_raw); + + scanner_stop_action(*dev); + + if (DBG_LEVEL >= DBG_data) + { + char fn[40]; + std::snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(fn, data); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data.get_raw_channel(x, y, 0) > 90) { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data.get_raw_channel(x, y, 0) < 60) { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + // when searching for black, detect white pixels + if (black && data.get_raw_channel(x, y, 0) > 90) { + count++; + } + // when searching for white, detect black pixels + if (!black && data.get_raw_channel(x, y, 0) < 60) { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (pixels * lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + pass++; + } + if (found) + { + DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); + } + else + { + throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white"); + } +} + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +void CommandSetGl843::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + uint8_t* data, int size) const +{ + DBG_HELPER(dbg); + uint32_t final_size, length, i; + uint8_t *buffer; + int count,offset; + GenesysRegister *r; + uint16_t strpixel, endpixel, startx; + + offset=0; + length=size; + r = sanei_genesys_get_address(&dev->reg, REG_0x01); + if (r->value & REG_0x01_SHDAREA) + { + /* recompute STRPIXEL used shading calibration so we can + * compute offset within data for SHDAREA case */ + + // FIXME: the following is likely incorrect + // start coordinate in optical dpi coordinates + startx = (sensor.dummy_pixel / sensor.ccd_pixels_per_system_pixel()) / dev->session.hwdpi_divisor; + startx *= dev->session.pixel_count_multiplier; + + /* current scan coordinates */ + strpixel = dev->session.pixel_startx; + endpixel = dev->session.pixel_endx; + + if (dev->model->model_id == ModelId::CANON_4400F || + dev->model->model_id == ModelId::CANON_8600F) + { + int half_ccd_factor = dev->session.optical_resolution / + sensor.get_logical_hwdpi(dev->session.output_resolution); + strpixel /= half_ccd_factor * sensor.ccd_pixels_per_system_pixel(); + endpixel /= half_ccd_factor * sensor.ccd_pixels_per_system_pixel(); + } + + /* 16 bit words, 2 words per color, 3 color channels */ + offset=(strpixel-startx)*2*2*3; + length=(endpixel-strpixel)*2*2*3; + DBG(DBG_info, "%s: STRPIXEL=%d, ENDPIXEL=%d, startx=%d\n", __func__, strpixel, endpixel, + startx); + } + + dev->interface->record_key_value("shading_offset", std::to_string(offset)); + dev->interface->record_key_value("shading_length", std::to_string(length)); + + /* compute and allocate size for final data */ + final_size = ((length+251) / 252) * 256; + DBG(DBG_io, "%s: final shading size=%04x (length=%d)\n", __func__, final_size, length); + std::vector final_data(final_size, 0); + + /* copy regular shading data to the expected layout */ + buffer = final_data.data(); + count = 0; + + /* loop over calibration data */ + for (i = 0; i < length; i++) + { + buffer[count] = data[offset+i]; + count++; + if ((count % (256*2)) == (252*2)) + { + count += 4*2; + } + } + + dev->interface->write_buffer(0x3c, 0, final_data.data(), count, + ScannerInterface::FLAG_SMALL_ADDRESS); +} + +bool CommandSetGl843::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const +{ + (void) dev; + return true; +} + +void CommandSetGl843::wait_for_motor_stop(Genesys_Device* dev) const +{ + (void) dev; +} + +std::unique_ptr create_gl843_cmd_set() +{ + return std::unique_ptr(new CommandSetGl843{}); +} + +} // namespace gl843 +} // namespace genesys diff --git a/backend/genesys/gl843.h b/backend/genesys/gl843.h new file mode 100644 index 0000000..9f0a9e9 --- /dev/null +++ b/backend/genesys/gl843.h @@ -0,0 +1,139 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + 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 "genesys.h" +#include "command_set.h" + +#ifndef BACKEND_GENESYS_GL843_H +#define BACKEND_GENESYS_GL843_H + +namespace genesys { +namespace gl843 { + +class CommandSetGl843 : public CommandSet +{ +public: + ~CommandSetGl843() override = default; + + bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override; + + void init(Genesys_Device* dev) const override; + + void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const override; + + void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const override; + + void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override; + void set_powersaving(Genesys_Device* dev, int delay) const override; + void save_power(Genesys_Device* dev, bool enable) const override; + + void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, bool start_motor) const override; + + void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override; + + void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void search_start_position(Genesys_Device* dev) const override; + + void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const override; + + SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void wait_for_motor_stop(Genesys_Device* dev) const override; + + void move_back_home(Genesys_Device* dev, bool wait_until_home) const override; + + void update_hardware_sensors(struct Genesys_Scanner* s) const override; + + void load_document(Genesys_Device* dev) const override; + + void detect_document_end(Genesys_Device* dev) const override; + + void eject_document(Genesys_Device* dev) const override; + + void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const override; + + void move_to_ta(Genesys_Device* dev) const override; + + void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data, + int size) const override; + + ScanSession calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const override; + + void asic_boot(Genesys_Device* dev, bool cold) const override; +}; + +enum SlopeTable +{ + SCAN_TABLE = 0, // table 1 at 0x4000 + BACKTRACK_TABLE = 1, // table 2 at 0x4800 + STOP_TABLE = 2, // table 3 at 0x5000 + FAST_TABLE = 3, // table 4 at 0x5800 + HOME_TABLE = 4, // table 5 at 0x6000 +}; + +} // namespace gl843 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL843_H diff --git a/backend/genesys/gl843_registers.h b/backend/genesys/gl843_registers.h new file mode 100644 index 0000000..8ecb0fc --- /dev/null +++ b/backend/genesys/gl843_registers.h @@ -0,0 +1,382 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL843_REGISTERS_H +#define BACKEND_GENESYS_GL843_REGISTERS_H + +#include + +namespace genesys { +namespace gl843 { + +using RegAddr = std::uint16_t; +using RegMask = std::uint8_t; +using RegShift = unsigned; + +static constexpr RegAddr REG_0x01 = 0x01; +static constexpr RegMask REG_0x01_CISSET = 0x80; +static constexpr RegMask REG_0x01_DOGENB = 0x40; +static constexpr RegMask REG_0x01_DVDSET = 0x20; +static constexpr RegMask REG_0x01_STAGGER = 0x10; +static constexpr RegMask REG_0x01_COMPENB = 0x08; +static constexpr RegMask REG_0x01_TRUEGRAY = 0x04; +static constexpr RegMask REG_0x01_SHDAREA = 0x02; +static constexpr RegMask REG_0x01_SCAN = 0x01; + +static constexpr RegAddr REG_0x02 = 0x02; +static constexpr RegMask REG_0x02_NOTHOME = 0x80; +static constexpr RegMask REG_0x02_ACDCDIS = 0x40; +static constexpr RegMask REG_0x02_AGOHOME = 0x20; +static constexpr RegMask REG_0x02_MTRPWR = 0x10; +static constexpr RegMask REG_0x02_FASTFED = 0x08; +static constexpr RegMask REG_0x02_MTRREV = 0x04; +static constexpr RegMask REG_0x02_HOMENEG = 0x02; +static constexpr RegMask REG_0x02_LONGCURV = 0x01; + +static constexpr RegAddr REG_0x03 = 0x03; +static constexpr RegMask REG_0x03_LAMPDOG = 0x80; +static constexpr RegMask REG_0x03_AVEENB = 0x40; +static constexpr RegMask REG_0x03_XPASEL = 0x20; +static constexpr RegMask REG_0x03_LAMPPWR = 0x10; +static constexpr RegMask REG_0x03_LAMPTIM = 0x0f; + +static constexpr RegAddr REG_0x04 = 0x04; +static constexpr RegMask REG_0x04_LINEART = 0x80; +static constexpr RegMask REG_0x04_BITSET = 0x40; +static constexpr RegMask REG_0x04_AFEMOD = 0x30; +static constexpr RegMask REG_0x04_FILTER = 0x0c; +static constexpr RegMask REG_0x04_FESET = 0x03; + +static constexpr RegShift REG_0x04S_AFEMOD = 4; + +static constexpr RegAddr REG_0x05 = 0x05; +static constexpr RegMask REG_0x05_DPIHW = 0xc0; +static constexpr RegMask REG_0x05_DPIHW_600 = 0x00; +static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40; +static constexpr RegMask REG_0x05_DPIHW_2400 = 0x80; +static constexpr RegMask REG_0x05_DPIHW_4800 = 0xc0; +static constexpr RegMask REG_0x05_MTLLAMP = 0x30; +static constexpr RegMask REG_0x05_GMMENB = 0x08; +static constexpr RegMask REG_0x05_MTLBASE = 0x03; + +static constexpr RegAddr REG_0x06 = 0x06; +static constexpr RegMask REG_0x06_SCANMOD = 0xe0; +static constexpr RegShift REG_0x06S_SCANMOD = 5; +static constexpr RegMask REG_0x06_PWRBIT = 0x10; +static constexpr RegMask REG_0x06_GAIN4 = 0x08; +static constexpr RegMask REG_0x06_OPTEST = 0x07; + +static constexpr RegMask REG_0x07_LAMPSIM = 0x80; + +static constexpr RegMask REG_0x08_DECFLAG = 0x40; +static constexpr RegMask REG_0x08_GMMFFR = 0x20; +static constexpr RegMask REG_0x08_GMMFFG = 0x10; +static constexpr RegMask REG_0x08_GMMFFB = 0x08; +static constexpr RegMask REG_0x08_GMMZR = 0x04; +static constexpr RegMask REG_0x08_GMMZG = 0x02; +static constexpr RegMask REG_0x08_GMMZB = 0x01; + +static constexpr RegMask REG_0x09_MCNTSET = 0xc0; +static constexpr RegMask REG_0x09_EVEN1ST = 0x20; +static constexpr RegMask REG_0x09_BLINE1ST = 0x10; +static constexpr RegMask REG_0x09_BACKSCAN = 0x08; +static constexpr RegMask REG_0x09_ENHANCE = 0x04; +static constexpr RegMask REG_0x09_SHORTTG = 0x02; +static constexpr RegMask REG_0x09_NWAIT = 0x01; + +static constexpr RegShift REG_0x09S_MCNTSET = 6; +static constexpr RegShift REG_0x09S_CLKSET = 4; + +static constexpr RegAddr REG_0x0B = 0x0b; +static constexpr RegMask REG_0x0B_DRAMSEL = 0x07; +static constexpr RegMask REG_0x0B_ENBDRAM = 0x08; +static constexpr RegMask REG_0x0B_RFHDIS = 0x10; +static constexpr RegMask REG_0x0B_CLKSET = 0xe0; +static constexpr RegMask REG_0x0B_24MHZ = 0x00; +static constexpr RegMask REG_0x0B_30MHZ = 0x20; +static constexpr RegMask REG_0x0B_40MHZ = 0x40; +static constexpr RegMask REG_0x0B_48MHZ = 0x60; +static constexpr RegMask REG_0x0B_60MHZ = 0x80; + +static constexpr RegAddr REG_0x0D = 0x0d; +static constexpr RegMask REG_0x0D_JAMPCMD = 0x80; +static constexpr RegMask REG_0x0D_DOCCMD = 0x40; +static constexpr RegMask REG_0x0D_CCDCMD = 0x20; +static constexpr RegMask REG_0x0D_FULLSTP = 0x10; +static constexpr RegMask REG_0x0D_SEND = 0x08; +static constexpr RegMask REG_0x0D_CLRMCNT = 0x04; +static constexpr RegMask REG_0x0D_CLRDOCJM = 0x02; +static constexpr RegMask REG_0x0D_CLRLNCNT = 0x01; + +static constexpr RegAddr REG_0x0F = 0x0f; + +static constexpr RegAddr REG_EXPR = 0x10; +static constexpr RegAddr REG_EXPG = 0x12; +static constexpr RegAddr REG_EXPB = 0x14; + +static constexpr RegMask REG_0x16_CTRLHI = 0x80; +static constexpr RegMask REG_0x16_TOSHIBA = 0x40; +static constexpr RegMask REG_0x16_TGINV = 0x20; +static constexpr RegMask REG_0x16_CK1INV = 0x10; +static constexpr RegMask REG_0x16_CK2INV = 0x08; +static constexpr RegMask REG_0x16_CTRLINV = 0x04; +static constexpr RegMask REG_0x16_CKDIS = 0x02; +static constexpr RegMask REG_0x16_CTRLDIS = 0x01; + +static constexpr RegMask REG_0x17_TGMODE = 0xc0; +static constexpr RegMask REG_0x17_TGMODE_NO_DUMMY = 0x00; +static constexpr RegMask REG_0x17_TGMODE_REF = 0x40; +static constexpr RegMask REG_0x17_TGMODE_XPA = 0x80; +static constexpr RegMask REG_0x17_TGW = 0x3f; +static constexpr RegShift REG_0x17S_TGW = 0; + +static constexpr RegAddr REG_0x18 = 0x18; +static constexpr RegMask REG_0x18_CNSET = 0x80; +static constexpr RegMask REG_0x18_DCKSEL = 0x60; +static constexpr RegMask REG_0x18_CKTOGGLE = 0x10; +static constexpr RegMask REG_0x18_CKDELAY = 0x0c; +static constexpr RegMask REG_0x18_CKSEL = 0x03; + +static constexpr RegAddr REG_EXPDMY = 0x19; + +static constexpr RegMask REG_0x1A_TGLSW2 = 0x80; +static constexpr RegMask REG_0x1A_TGLSW1 = 0x40; +static constexpr RegMask REG_0x1A_MANUAL3 = 0x02; +static constexpr RegMask REG_0x1A_MANUAL1 = 0x01; +static constexpr RegMask REG_0x1A_CK4INV = 0x08; +static constexpr RegMask REG_0x1A_CK3INV = 0x04; +static constexpr RegMask REG_0x1A_LINECLP = 0x02; + +static constexpr RegAddr REG_0x1C = 0x1c; +static constexpr RegMask REG_0x1C_TGTIME = 0x07; + +static constexpr RegMask REG_0x1D_CK4LOW = 0x80; +static constexpr RegMask REG_0x1D_CK3LOW = 0x40; +static constexpr RegMask REG_0x1D_CK1LOW = 0x20; +static constexpr RegMask REG_0x1D_TGSHLD = 0x1f; +static constexpr RegShift REG_0x1DS_TGSHLD = 0; + + +static constexpr RegAddr REG_0x1E = 0x1e; +static constexpr RegMask REG_0x1E_WDTIME = 0xf0; +static constexpr RegShift REG_0x1ES_WDTIME = 4; +static constexpr RegMask REG_0x1E_LINESEL = 0x0f; +static constexpr RegShift REG_0x1ES_LINESEL = 0; + +static constexpr RegAddr REG_0x21 = 0x21; +static constexpr RegAddr REG_STEPNO = 0x21; +static constexpr RegAddr REG_FWDSTEP = 0x22; +static constexpr RegAddr REG_BWDSTEP = 0x23; +static constexpr RegAddr REG_FASTNO = 0x24; +static constexpr RegAddr REG_LINCNT = 0x25; + +static constexpr RegAddr REG_0x29 = 0x29; +static constexpr RegAddr REG_0x2A = 0x2a; +static constexpr RegAddr REG_0x2B = 0x2b; +static constexpr RegAddr REG_DPISET = 0x2c; +static constexpr RegAddr REG_0x2E = 0x2e; +static constexpr RegAddr REG_0x2F = 0x2f; + +static constexpr RegAddr REG_STRPIXEL = 0x30; +static constexpr RegAddr REG_ENDPIXEL = 0x32; +static constexpr RegAddr REG_DUMMY = 0x34; +static constexpr RegAddr REG_MAXWD = 0x35; +static constexpr RegAddr REG_LPERIOD = 0x38; +static constexpr RegAddr REG_FEEDL = 0x3d; + +static constexpr RegAddr REG_0x40 = 0x40; +static constexpr RegMask REG_0x40_DOCSNR = 0x80; +static constexpr RegMask REG_0x40_ADFSNR = 0x40; +static constexpr RegMask REG_0x40_COVERSNR = 0x20; +static constexpr RegMask REG_0x40_CHKVER = 0x10; +static constexpr RegMask REG_0x40_DOCJAM = 0x08; +static constexpr RegMask REG_0x40_HISPDFLG = 0x04; +static constexpr RegMask REG_0x40_MOTMFLG = 0x02; +static constexpr RegMask REG_0x40_DATAENB = 0x01; + +static constexpr RegMask REG_0x41_PWRBIT = 0x80; +static constexpr RegMask REG_0x41_BUFEMPTY = 0x40; +static constexpr RegMask REG_0x41_FEEDFSH = 0x20; +static constexpr RegMask REG_0x41_SCANFSH = 0x10; +static constexpr RegMask REG_0x41_HOMESNR = 0x08; +static constexpr RegMask REG_0x41_LAMPSTS = 0x04; +static constexpr RegMask REG_0x41_FEBUSY = 0x02; +static constexpr RegMask REG_0x41_MOTORENB = 0x01; + +static constexpr RegMask REG_0x58_VSMP = 0xf8; +static constexpr RegShift REG_0x58S_VSMP = 3; +static constexpr RegMask REG_0x58_VSMPW = 0x07; +static constexpr RegShift REG_0x58S_VSMPW = 0; + +static constexpr RegMask REG_0x59_BSMP = 0xf8; +static constexpr RegShift REG_0x59S_BSMP = 3; +static constexpr RegMask REG_0x59_BSMPW = 0x07; +static constexpr RegShift REG_0x59S_BSMPW = 0; + +static constexpr RegMask REG_0x5A_ADCLKINV = 0x80; +static constexpr RegMask REG_0x5A_RLCSEL = 0x40; +static constexpr RegMask REG_0x5A_CDSREF = 0x30; +static constexpr RegShift REG_0x5AS_CDSREF = 4; +static constexpr RegMask REG_0x5A_RLC = 0x0f; +static constexpr RegShift REG_0x5AS_RLC = 0; + +static constexpr RegAddr REG_0x5E = 0x5e; +static constexpr RegMask REG_0x5E_DECSEL = 0xe0; +static constexpr RegShift REG_0x5ES_DECSEL = 5; +static constexpr RegMask REG_0x5E_STOPTIM = 0x1f; +static constexpr RegShift REG_0x5ES_STOPTIM = 0; + +static constexpr RegAddr REG_FMOVDEC = 0x5f; + +static constexpr RegAddr REG_0x60 = 0x60; +static constexpr RegMask REG_0x60_Z1MOD = 0x1f; +static constexpr RegAddr REG_0x61 = 0x61; +static constexpr RegMask REG_0x61_Z1MOD = 0xff; +static constexpr RegAddr REG_0x62 = 0x62; +static constexpr RegMask REG_0x62_Z1MOD = 0xff; + +static constexpr RegAddr REG_0x63 = 0x63; +static constexpr RegMask REG_0x63_Z2MOD = 0x1f; +static constexpr RegAddr REG_0x64 = 0x64; +static constexpr RegMask REG_0x64_Z2MOD = 0xff; +static constexpr RegAddr REG_0x65 = 0x65; +static constexpr RegMask REG_0x65_Z2MOD = 0xff; + +static constexpr RegAddr REG_0x67 = 0x67; + +static constexpr RegAddr REG_0x68 = 0x68; + +static constexpr RegShift REG_0x67S_STEPSEL = 6; +static constexpr RegMask REG_0x67_STEPSEL = 0xc0; +static constexpr RegMask REG_0x67_FULLSTEP = 0x00; +static constexpr RegMask REG_0x67_HALFSTEP = 0x20; +static constexpr RegMask REG_0x67_EIGHTHSTEP = 0x60; +static constexpr RegMask REG_0x67_16THSTEP = 0x80; + +static constexpr RegShift REG_0x68S_FSTPSEL = 6; +static constexpr RegMask REG_0x68_FSTPSEL = 0xc0; +static constexpr RegMask REG_0x68_FULLSTEP = 0x00; +static constexpr RegMask REG_0x68_HALFSTEP = 0x20; +static constexpr RegMask REG_0x68_EIGHTHSTEP = 0x60; +static constexpr RegMask REG_0x68_16THSTEP = 0x80; + +static constexpr RegAddr REG_FSHDEC = 0x69; +static constexpr RegAddr REG_FMOVNO = 0x6a; + +static constexpr RegAddr REG_0x6B = 0x6b; +static constexpr RegMask REG_0x6B_MULTFILM = 0x80; +static constexpr RegMask REG_0x6B_GPOM13 = 0x40; +static constexpr RegMask REG_0x6B_GPOM12 = 0x20; +static constexpr RegMask REG_0x6B_GPOM11 = 0x10; +static constexpr RegMask REG_0x6B_GPOCK4 = 0x08; +static constexpr RegMask REG_0x6B_GPOCP = 0x04; +static constexpr RegMask REG_0x6B_GPOLEDB = 0x02; +static constexpr RegMask REG_0x6B_GPOADF = 0x01; + +static constexpr RegAddr REG_0x6C = 0x6c; +static constexpr RegMask REG_0x6C_GPIO16 = 0x80; +static constexpr RegMask REG_0x6C_GPIO15 = 0x40; +static constexpr RegMask REG_0x6C_GPIO14 = 0x20; +static constexpr RegMask REG_0x6C_GPIO13 = 0x10; +static constexpr RegMask REG_0x6C_GPIO12 = 0x08; +static constexpr RegMask REG_0x6C_GPIO11 = 0x04; +static constexpr RegMask REG_0x6C_GPIO10 = 0x02; +static constexpr RegMask REG_0x6C_GPIO9 = 0x01; +static constexpr RegMask REG_0x6C_GPIOH = 0xff; +static constexpr RegMask REG_0x6C_GPIOL = 0xff; + +static constexpr RegAddr REG_Z1MOD = 0x60; +static constexpr RegAddr REG_Z2MOD = 0x63; + +static constexpr RegAddr REG_0x6D = 0x6d; +static constexpr RegAddr REG_0x6E = 0x6e; +static constexpr RegAddr REG_0x6F = 0x6f; + +static constexpr RegAddr REG_CK1MAP = 0x74; +static constexpr RegAddr REG_CK3MAP = 0x77; +static constexpr RegAddr REG_CK4MAP = 0x7a; + +static constexpr RegAddr REG_0x7E = 0x7e; + +static constexpr RegAddr REG_0x9D = 0x9d; +static constexpr RegShift REG_0x9DS_STEPTIM = 2; + +static constexpr RegMask REG_0x87_LEDADD = 0x04; + +static constexpr RegAddr REG_0xA6 = 0xa6; +static constexpr RegMask REG_0xA6_GPIO24 = 0x80; +static constexpr RegMask REG_0xA6_GPIO23 = 0x40; +static constexpr RegMask REG_0xA6_GPIO22 = 0x20; +static constexpr RegMask REG_0xA6_GPIO21 = 0x10; +static constexpr RegMask REG_0xA6_GPIO20 = 0x08; +static constexpr RegMask REG_0xA6_GPIO19 = 0x04; +static constexpr RegMask REG_0xA6_GPIO18 = 0x02; +static constexpr RegMask REG_0xA6_GPIO17 = 0x01; +static constexpr RegAddr REG_0xA7 = 0xa7; +static constexpr RegMask REG_0xA7_GPOE24 = 0x80; +static constexpr RegMask REG_0xA7_GPOE23 = 0x40; +static constexpr RegMask REG_0xA7_GPOE22 = 0x20; +static constexpr RegMask REG_0xA7_GPOE21 = 0x10; +static constexpr RegMask REG_0xA7_GPOE20 = 0x08; +static constexpr RegMask REG_0xA7_GPOE19 = 0x04; +static constexpr RegMask REG_0xA7_GPOE18 = 0x02; +static constexpr RegMask REG_0xA7_GPOE17 = 0x01; +static constexpr RegAddr REG_0xA8 = 0xa8; +static constexpr RegMask REG_0xA8_GPOE27 = 0x20; +static constexpr RegMask REG_0xA8_GPOE26 = 0x10; +static constexpr RegMask REG_0xA8_GPOE25 = 0x08; +static constexpr RegMask REG_0xA8_GPO27 = 0x04; +static constexpr RegMask REG_0xA8_GPO26 = 0x02; +static constexpr RegMask REG_0xA8_GPO25 = 0x01; +static constexpr RegAddr REG_0xA9 = 0xa9; +static constexpr RegMask REG_0xA9_GPO33 = 0x20; +static constexpr RegMask REG_0xA9_GPO32 = 0x10; +static constexpr RegMask REG_0xA9_GPO31 = 0x08; +static constexpr RegMask REG_0xA9_GPO30 = 0x04; +static constexpr RegMask REG_0xA9_GPO29 = 0x02; +static constexpr RegMask REG_0xA9_GPO28 = 0x01; + +} // namespace gl843 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL843_REGISTERS_H diff --git a/backend/genesys/gl846.cpp b/backend/genesys/gl846.cpp new file mode 100644 index 0000000..d309d29 --- /dev/null +++ b/backend/genesys/gl846.cpp @@ -0,0 +1,2098 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2012-2013 Stéphane Voltz + + + 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. +*/ + +/** @file + * + * This file handles GL846 and GL845 ASICs since they are really close to each other. + */ + +#define DEBUG_DECLARE_ONLY + +#include "gl846.h" +#include "gl846_registers.h" +#include "test_settings.h" + +#include + +namespace genesys { +namespace gl846 { + +/** + * compute the step multiplier used + */ +static int +gl846_get_step_multiplier (Genesys_Register_Set * regs) +{ + GenesysRegister *r = sanei_genesys_get_address(regs, 0x9d); + int value = 1; + if (r != nullptr) { + value = (r->value & 0x0f)>>1; + value = 1 << value; + } + DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); + return value; +} + +/** @brief sensor specific settings +*/ +static void gl846_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs) +{ + DBG_HELPER(dbg); + + for (const auto& reg : sensor.custom_regs) { + regs->set8(reg.address, reg.value); + } + + regs->set16(REG_EXPR, sensor.exposure.red); + regs->set16(REG_EXPG, sensor.exposure.green); + regs->set16(REG_EXPB, sensor.exposure.blue); + + dev->segment_order = sensor.segment_order; +} + + +/** @brief set all registers to default values . + * This function is called only once at the beginning and + * fills register startup values for registers reused across scans. + * Those that are rarely modified or not modified are written + * individually. + * @param dev device structure holding register set to initialize + */ +static void +gl846_init_registers (Genesys_Device * dev) +{ + DBG_HELPER(dbg); + + dev->reg.clear(); + + dev->reg.init_reg(0x01, 0x60); + dev->reg.init_reg(0x02, 0x38); + dev->reg.init_reg(0x03, 0x03); + dev->reg.init_reg(0x04, 0x22); + dev->reg.init_reg(0x05, 0x60); + dev->reg.init_reg(0x06, 0x10); + dev->reg.init_reg(0x08, 0x60); + dev->reg.init_reg(0x09, 0x00); + dev->reg.init_reg(0x0a, 0x00); + dev->reg.init_reg(0x0b, 0x8b); + dev->reg.init_reg(0x0c, 0x00); + dev->reg.init_reg(0x0d, 0x00); + dev->reg.init_reg(0x10, 0x00); + dev->reg.init_reg(0x11, 0x00); + dev->reg.init_reg(0x12, 0x00); + dev->reg.init_reg(0x13, 0x00); + dev->reg.init_reg(0x14, 0x00); + dev->reg.init_reg(0x15, 0x00); + dev->reg.init_reg(0x16, 0xbb); // SENSOR_DEF + dev->reg.init_reg(0x17, 0x13); // SENSOR_DEF + dev->reg.init_reg(0x18, 0x10); // SENSOR_DEF + dev->reg.init_reg(0x19, 0x2a); // SENSOR_DEF + dev->reg.init_reg(0x1a, 0x34); // SENSOR_DEF + dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x1c, 0x20); // SENSOR_DEF + dev->reg.init_reg(0x1d, 0x06); // SENSOR_DEF + dev->reg.init_reg(0x1e, 0xf0); + dev->reg.init_reg(0x1f, 0x01); + dev->reg.init_reg(0x20, 0x03); + dev->reg.init_reg(0x21, 0x10); + dev->reg.init_reg(0x22, 0x60); + dev->reg.init_reg(0x23, 0x60); + dev->reg.init_reg(0x24, 0x60); + dev->reg.init_reg(0x25, 0x00); + dev->reg.init_reg(0x26, 0x00); + dev->reg.init_reg(0x27, 0x00); + dev->reg.init_reg(0x2c, 0x00); + dev->reg.init_reg(0x2d, 0x00); + dev->reg.init_reg(0x2e, 0x80); + dev->reg.init_reg(0x2f, 0x80); + dev->reg.init_reg(0x30, 0x00); + dev->reg.init_reg(0x31, 0x00); + dev->reg.init_reg(0x32, 0x00); + dev->reg.init_reg(0x33, 0x00); + dev->reg.init_reg(0x34, 0x1f); + dev->reg.init_reg(0x35, 0x00); + dev->reg.init_reg(0x36, 0x40); + dev->reg.init_reg(0x37, 0x00); + dev->reg.init_reg(0x38, 0x2a); + dev->reg.init_reg(0x39, 0xf8); + dev->reg.init_reg(0x3d, 0x00); + dev->reg.init_reg(0x3e, 0x00); + dev->reg.init_reg(0x3f, 0x01); + dev->reg.init_reg(0x52, 0x02); // SENSOR_DEF + dev->reg.init_reg(0x53, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x54, 0x06); // SENSOR_DEF + dev->reg.init_reg(0x55, 0x08); // SENSOR_DEF + dev->reg.init_reg(0x56, 0x0a); // SENSOR_DEF + dev->reg.init_reg(0x57, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x58, 0x59); // SENSOR_DEF + dev->reg.init_reg(0x59, 0x31); // SENSOR_DEF + dev->reg.init_reg(0x5a, 0x40); // SENSOR_DEF + dev->reg.init_reg(0x5e, 0x1f); + dev->reg.init_reg(0x5f, 0x01); + dev->reg.init_reg(0x60, 0x00); + dev->reg.init_reg(0x61, 0x00); + dev->reg.init_reg(0x62, 0x00); + dev->reg.init_reg(0x63, 0x00); + dev->reg.init_reg(0x64, 0x00); + dev->reg.init_reg(0x65, 0x00); + dev->reg.init_reg(0x67, 0x7f); + dev->reg.init_reg(0x68, 0x7f); + dev->reg.init_reg(0x69, 0x01); + dev->reg.init_reg(0x6a, 0x01); + dev->reg.init_reg(0x70, 0x01); + dev->reg.init_reg(0x71, 0x00); + dev->reg.init_reg(0x72, 0x02); + dev->reg.init_reg(0x73, 0x01); + dev->reg.init_reg(0x74, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x75, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x76, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x77, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x78, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x79, 0x3f); // SENSOR_DEF + dev->reg.init_reg(0x7a, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x7b, 0x09); // SENSOR_DEF + dev->reg.init_reg(0x7c, 0x99); // SENSOR_DEF + dev->reg.init_reg(0x7d, 0x20); + dev->reg.init_reg(0x7f, 0x05); + dev->reg.init_reg(0x80, 0x4f); + dev->reg.init_reg(0x87, 0x02); + dev->reg.init_reg(0x94, 0xff); + dev->reg.init_reg(0x9d, 0x04); + dev->reg.init_reg(0x9e, 0x00); + dev->reg.init_reg(0xa1, 0xe0); + dev->reg.init_reg(0xa2, 0x1f); + dev->reg.init_reg(0xab, 0xc0); + dev->reg.init_reg(0xbb, 0x00); + dev->reg.init_reg(0xbc, 0x0f); + dev->reg.init_reg(0xdb, 0xff); + dev->reg.init_reg(0xfe, 0x08); + dev->reg.init_reg(0xff, 0x02); + dev->reg.init_reg(0x98, 0x20); + dev->reg.init_reg(0x99, 0x00); + dev->reg.init_reg(0x9a, 0x90); + dev->reg.init_reg(0x9b, 0x00); + dev->reg.init_reg(0xf8, 0x05); + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res); + + /* initalize calibration reg */ + dev->calib_reg = dev->reg; +} + +/**@brief send slope table for motor movement + * Send slope_table in machine byte order + * @param dev device to send slope table + * @param table_nr index of the slope table in ASIC memory + * Must be in the [0-4] range. + * @param slope_table pointer to 16 bit values array of the slope table + * @param steps number of elements in the slope table + */ +static void gl846_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, + int steps) +{ + DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); + int i; + char msg[10000]; + + /* sanity check */ + if(table_nr<0 || table_nr>4) + { + throw SaneException("invalid table number %d", table_nr); + } + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + std::sprintf(msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) + { + std::sprintf(msg+strlen(msg), "%d", slope_table[i]); + } + DBG (DBG_io, "%s: %s\n", __func__, msg); + } + + if (dev->interface->is_mock()) { + dev->interface->record_slope_table(table_nr, slope_table); + } + // slope table addresses are fixed + dev->interface->write_ahb(0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); +} + +/** + * Set register values of Analog Device type frontend + * */ +static void gl846_set_adi_fe(Genesys_Device* dev, uint8_t set) +{ + DBG_HELPER(dbg); + int i; + + // wait for FE to be ready + auto status = scanner_read_status(*dev); + while (status.is_front_end_busy) { + dev->interface->sleep_ms(10); + status = scanner_read_status(*dev); + }; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + dev->frontend = dev->frontend_initial; + } + + // write them to analog frontend + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + + dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); + + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x02 + i, dev->frontend.get_gain(i)); + } + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x05 + i, dev->frontend.get_offset(i)); + } +} + +// Set values of analog frontend +void CommandSetGl846::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const +{ + DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" : + set == AFE_SET ? "set" : + set == AFE_POWER_SAVE ? "powersave" : "huh?"); + (void) sensor; + + /* route to specific analog frontend setup */ + uint8_t frontend_type = dev->reg.find_reg(0x04).value & REG_0x04_FESET; + switch (frontend_type) { + case 0x02: /* ADI FE */ + gl846_set_adi_fe(dev, set); + break; + default: + throw SaneException("unsupported frontend type %d", frontend_type); + } +} + + +// @brief set up motor related register for scan +static void gl846_init_motor_regs_scan(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const Motor_Profile& motor_profile, + unsigned int scan_exposure_time, + unsigned scan_yres, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + MotorFlag flags) +{ + DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, scan_yres=%d, step_type=%d, scan_lines=%d, " + "scan_dummy=%d, feed_steps=%d, flags=%x", + scan_exposure_time, scan_yres, static_cast(motor_profile.step_type), + scan_lines, scan_dummy, feed_steps, static_cast(flags)); + int use_fast_fed; + unsigned int fast_dpi; + unsigned int feedl, dist; + GenesysRegister *r; + uint32_t z1, z2; + unsigned int min_restep = 0x20; + uint8_t val; + unsigned int ccdlmt,tgtime; + + unsigned step_multiplier = gl846_get_step_multiplier(reg); + + use_fast_fed=0; + /* no fast fed since feed works well */ + if (dev->settings.yres == 4444 && feed_steps > 100 && !has_flag(flags, MotorFlag::FEED)) { + use_fast_fed = 1; + } + DBG (DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); + + reg->set24(REG_LINCNT, scan_lines); + DBG (DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); + + /* compute register 02 value */ + r = sanei_genesys_get_address(reg, REG_0x02); + r->value = 0x00; + sanei_genesys_set_motor_power(*reg, true); + + if (use_fast_fed) + r->value |= REG_0x02_FASTFED; + else + r->value &= ~REG_0x02_FASTFED; + + if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { + r->value |= REG_0x02_AGOHOME | REG_0x02_NOTHOME; + } + + if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE) ||(scan_yres>=sensor.optical_res)) { + r->value |= REG_0x02_ACDCDIS; + } + if (has_flag(flags, MotorFlag::REVERSE)) { + r->value |= REG_0x02_MTRREV; + } else { + r->value &= ~REG_0x02_MTRREV; + } + + /* scan and backtracking slope table */ + auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres, + scan_exposure_time, dev->motor.base_ydpi, + step_multiplier, motor_profile); + + gl846_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count); + gl846_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count); + + /* fast table */ + fast_dpi=sanei_genesys_get_lowest_ydpi(dev); + + // BUG: looks like for fast moves we use inconsistent step type + StepType fast_step_type = motor_profile.step_type; + if (static_cast(motor_profile.step_type) >= static_cast(StepType::QUARTER)) { + fast_step_type = StepType::QUARTER; + } + + Motor_Profile fast_motor_profile = motor_profile; + fast_motor_profile.step_type = fast_step_type; + + auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi, + scan_exposure_time, dev->motor.base_ydpi, + step_multiplier, fast_motor_profile); + + gl846_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count); + gl846_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count); + gl846_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count); + + /* correct move distance by acceleration and deceleration amounts */ + feedl=feed_steps; + if (use_fast_fed) + { + feedl <<= static_cast(fast_step_type); + dist = (scan_table.steps_count + 2 * fast_table.steps_count); + /* TODO read and decode REG_0xAB */ + r = sanei_genesys_get_address (reg, 0x5e); + dist += (r->value & 31); + /* FEDCNT */ + r = sanei_genesys_get_address(reg, REG_FEDCNT); + dist += r->value; + } + else + { + feedl <<= static_cast(motor_profile.step_type); + dist = scan_table.steps_count; + if (has_flag(flags, MotorFlag::FEED)) { + dist *= 2; + } + } + DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + /* check for overflow */ + if (dist < feedl) { + feedl -= dist; + } else { + feedl = 0; + } + + reg->set24(REG_FEEDL, feedl); + DBG (DBG_io ,"%s: feedl=%d\n",__func__,feedl); + + r = sanei_genesys_get_address(reg, REG_0x0C); + ccdlmt = (r->value & REG_0x0C_CCDLMT) + 1; + + r = sanei_genesys_get_address(reg, REG_0x1C); + tgtime = 1 << (r->value & REG_0x1C_TGTIME); + + /* hi res motor speed GPIO */ + /* + uint8_t effective = dev->interface->read_register(REG_0x6C); + */ + + /* if quarter step, bipolar Vref2 */ + /* XXX STEF XXX GPIO + if (motor_profile.step_type > 1) + { + if (motor_profile.step_type < 3) + { + val = effective & ~REG_0x6C_GPIO13; + } + else + { + val = effective | REG_0x6C_GPIO13; + } + } + else + { + val = effective; + } + dev->interface->write_register(REG_0x6C, val); + */ + + /* effective scan */ + /* + effective = dev->interface->read_register(REG_0x6C); + val = effective | REG_0x6C_GPIO10; + dev->interface->write_register(REG_0x6C, val); + */ + + if(dev->model->gpio_id == GpioId::IMG101) { + if (scan_yres == sensor.get_register_hwdpi(scan_yres)) { + val=1; + } + else + { + val=0; + } + dev->interface->write_register(REG_0x7E, val); + } + + min_restep = (scan_table.steps_count / step_multiplier) / 2 - 1; + if (min_restep < 1) { + min_restep = 1; + } + r = sanei_genesys_get_address(reg, REG_FWDSTEP); + r->value = min_restep; + r = sanei_genesys_get_address(reg, REG_BWDSTEP); + r->value = min_restep; + + sanei_genesys_calculate_zmod(use_fast_fed, + scan_exposure_time*ccdlmt*tgtime, + scan_table.table, + scan_table.steps_count, + feedl, + min_restep * step_multiplier, + &z1, + &z2); + + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + reg->set24(REG_0x60, z1 | (static_cast(motor_profile.step_type) << (16 + REG_0x60S_STEPSEL))); + + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + reg->set24(REG_0x63, z2 | (static_cast(motor_profile.step_type) << (16 + REG_0x63S_FSTPSEL))); + + r = sanei_genesys_get_address (reg, 0x1e); + r->value &= 0xf0; /* 0 dummy lines */ + r->value |= scan_dummy; /* dummy lines */ + + r = sanei_genesys_get_address(reg, REG_0x67); + r->value = 0x7f; + + r = sanei_genesys_get_address(reg, REG_0x68); + r->value = 0x7f; + + reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier); + reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier); + reg->set8(REG_FSHDEC, scan_table.steps_count / step_multiplier); + reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier); + reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier); +} + + +/** @brief set up registers related to sensor + * Set up the following registers + 0x01 + 0x03 + 0x10-0x015 R/G/B exposures + 0x19 EXPDMY + 0x2e BWHI + 0x2f BWLO + 0x04 + 0x87 + 0x05 + 0x2c,0x2d DPISET + 0x30,0x31 STRPIXEL + 0x32,0x33 ENDPIXEL + 0x35,0x36,0x37 MAXWD [25:2] (>>2) + 0x38,0x39 LPERIOD + 0x34 DUMMY + */ +static void gl846_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, unsigned int exposure_time, + const ScanSession& session) +{ + DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time); + unsigned int dpihw; + GenesysRegister *r; + + // resolution is divided according to ccd_pixels_per_system_pixel() + unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel(); + DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel); + + // to manage high resolution device while keeping good low resolution scanning speed, + // we make hardware dpi vary + dpihw = sensor.get_register_hwdpi(session.params.xres * ccd_pixels_per_system_pixel); + DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw); + + gl846_setup_sensor(dev, sensor, reg); + + dev->cmd_set->set_fe(dev, sensor, AFE_SET); + + /* enable shading */ + regs_set_optical_off(dev->model->asic_type, *reg); + r = sanei_genesys_get_address(reg, REG_0x01); + r->value |= REG_0x01_SHDAREA; + if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + r->value &= ~REG_0x01_DVDSET; + } + else + { + r->value |= REG_0x01_DVDSET; + } + + r = sanei_genesys_get_address(reg, REG_0x03); + r->value &= ~REG_0x03_AVEENB; + + sanei_genesys_set_lamp_power(dev, sensor, *reg, + !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); + + /* BW threshold */ + r = sanei_genesys_get_address (reg, 0x2e); + r->value = dev->settings.threshold; + r = sanei_genesys_get_address (reg, 0x2f); + r->value = dev->settings.threshold; + + /* monochrome / color scan */ + r = sanei_genesys_get_address(reg, REG_0x04); + switch (session.params.depth) { + case 8: + r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); + break; + case 16: + r->value &= ~REG_0x04_LINEART; + r->value |= REG_0x04_BITSET; + break; + } + + r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); + if (session.params.channels == 1) + { + switch (session.params.color_filter) + { + case ColorFilter::RED: + r->value |= 0x24; + break; + case ColorFilter::BLUE: + r->value |= 0x2c; + break; + case ColorFilter::GREEN: + r->value |= 0x28; + break; + default: + break; // should not happen + } + } else { + r->value |= 0x20; // mono + } + + sanei_genesys_set_dpihw(*reg, sensor, dpihw); + + if (should_enable_gamma(session, sensor)) { + reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB; + } else { + reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB; + } + + /* CIS scanners can do true gray by setting LEDADD */ + /* we set up LEDADD only when asked */ + if (dev->model->is_cis) { + r = sanei_genesys_get_address (reg, 0x87); + r->value &= ~REG_0x87_LEDADD; + if (session.enable_ledadd) { + r->value |= REG_0x87_LEDADD; + } + /* RGB weighting + r = sanei_genesys_get_address (reg, 0x01); + r->value &= ~REG_0x01_TRUEGRAY; + if (session.enable_ledadd)) + { + r->value |= REG_0x01_TRUEGRAY; + }*/ + } + + unsigned dpiset = session.params.xres * ccd_pixels_per_system_pixel; + reg->set16(REG_DPISET, dpiset); + DBG(DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); + + reg->set16(REG_STRPIXEL, session.pixel_startx); + reg->set16(REG_ENDPIXEL, session.pixel_endx); + + build_image_pipeline(dev, session); + + /* MAXWD is expressed in 4 words unit */ + // BUG: we shouldn't multiply by channels here + reg->set24(REG_MAXWD, (session.output_line_bytes_raw * session.params.channels >> 2)); + + reg->set16(REG_LPERIOD, exposure_time); + DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); + + r = sanei_genesys_get_address (reg, 0x34); + r->value = sensor.dummy_pixel; +} + +void CommandSetGl846::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const +{ + DBG_HELPER(dbg); + session.assert_computed(); + + int move; + int exposure_time; + + int slope_dpi = 0; + int dummy = 0; + + dummy = 3-session.params.channels; + +/* slope_dpi */ +/* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) { + slope_dpi = session.params.yres * session.params.channels; + } else { + slope_dpi = session.params.yres; + } + + slope_dpi = slope_dpi * (1 + dummy); + + exposure_time = sensor.exposure_lperiod; + const auto& motor_profile = sanei_genesys_get_motor_profile(*gl846_motor_profiles, + dev->model->motor_id, + exposure_time); + + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, + static_cast(motor_profile.step_type)); + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + gl846_init_optical_regs_scan(dev, sensor, reg, exposure_time, session); + +/*** motor parameters ***/ + + /* add tl_y to base movement */ + move = session.params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + MotorFlag mflags = MotorFlag::NONE; + if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) { + mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE; + } + if (has_flag(session.params.flags, ScanFlag::FEEDING)) { + mflags |= MotorFlag::FEED; + } + if (has_flag(session.params.flags, ScanFlag::REVERSE)) { + mflags |= MotorFlag::REVERSE; + } + + gl846_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi, + dev->model->is_cis ? session.output_line_count * session.params.channels + : session.output_line_count, + dummy, move, mflags); + + /*** prepares data reordering ***/ + + dev->read_buffer.clear(); + dev->read_buffer.alloc(session.buffer_size_read); + + dev->read_active = true; + + dev->session = session; + + dev->total_bytes_read = 0; + dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines; + + DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read); +} + +ScanSession CommandSetGl846::calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const +{ + int start; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, settings); + + /* start */ + start = static_cast(dev->model->x_offset); + start += static_cast(settings.tl_x); + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = settings.xres; + session.params.yres = settings.yres; + session.params.startx = start; // not used + session.params.starty = 0; // not used + session.params.pixels = settings.pixels; + session.params.requested_pixels = settings.requested_pixels; + session.params.lines = settings.lines; + session.params.depth = settings.depth; + session.params.channels = settings.get_channels(); + session.params.scan_method = settings.scan_method; + session.params.scan_mode = settings.scan_mode; + session.params.color_filter = settings.color_filter; + session.params.flags = ScanFlag::NONE; + + compute_session(dev, session, sensor); + + return session; +} + +// for fast power saving methods only, like disabling certain amplifiers +void CommandSetGl846::save_power(Genesys_Device* dev, bool enable) const +{ + (void) dev; + DBG_HELPER_ARGS(dbg, "enable = %d", enable); +} + +void CommandSetGl846::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const +{ + (void) dev; + DBG_HELPER_ARGS(dbg, "delay = %d", delay); +} + +// Send the low-level scan command +void CommandSetGl846::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, bool start_motor) const +{ + DBG_HELPER(dbg); + (void) sensor; + uint8_t val; + GenesysRegister *r; + + /* XXX STEF XXX SCAN GPIO */ + /* + val = dev->interface->read_register(REG_0x6C); + dev->interface->write_register(REG_0x6C, val); + */ + + val = REG_0x0D_CLRLNCNT; + dev->interface->write_register(REG_0x0D, val); + val = REG_0x0D_CLRMCNT; + dev->interface->write_register(REG_0x0D, val); + + val = dev->interface->read_register(REG_0x01); + val |= REG_0x01_SCAN; + dev->interface->write_register(REG_0x01, val); + r = sanei_genesys_get_address (reg, REG_0x01); + r->value = val; + + scanner_start_action(*dev, start_motor); + + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); +} + + +// Send the stop scan command +void CommandSetGl846::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg, + bool check_stop) const +{ + (void) reg; + DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop); + + if (!dev->model->is_sheetfed) { + scanner_stop_action(*dev); + } +} + +// Moves the slider to the home (top) postion slowly +void CommandSetGl846::move_back_home(Genesys_Device* dev, bool wait_until_home) const +{ + scanner_move_back_home(*dev, wait_until_home); +} + +// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi +// from very top of scanner +void CommandSetGl846::search_start_position(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + int size; + Genesys_Register_Set local_reg; + + int pixels = 600; + int dpi = 300; + + local_reg = dev->reg; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method); + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; /*we should give a small offset here~60 steps */ + session.params.pixels = 600; + session.params.lines = dev->model->search_lines; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::GREEN; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &local_reg, session); + + // send to scanner + dev->interface->write_registers(local_reg); + + size = pixels * dev->model->search_lines; + + std::vector data(size); + + begin_scan(dev, sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_start_position"); + end_scan(dev, &local_reg, true); + dev->reg = local_reg; + return; + } + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl846_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + } + + end_scan(dev, &local_reg, true); + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + + // TODO: find out where sanei_genesys_search_reference_point stores information, + // and use that correctly + for (auto& sensor_update : + sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) + { + sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels, + dev->model->search_lines); + } +} + +// sets up register for coarse gain calibration +// todo: check it for scanners using it +void CommandSetGl846::init_regs_for_coarse_calibration(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel(); + session.params.lines = 20; + session.params.depth = 16; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, ®s, session); + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres); + + dev->interface->write_registers(regs); +} + +// init registers for shading calibration +void CommandSetGl846::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + float move; + + dev->calib_channels = 3; + + /* initial calibration reg values */ + regs = dev->reg; + + dev->calib_resolution = sensor.get_register_hwdpi(dev->settings.xres); + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->calib_resolution, + dev->calib_channels, + dev->settings.scan_method); + dev->calib_total_bytes_to_read = 0; + dev->calib_lines = dev->model->shading_lines; + if (dev->calib_resolution==4800) { + dev->calib_lines *= 2; + } + dev->calib_pixels = (calib_sensor.sensor_pixels * dev->calib_resolution) / + calib_sensor.optical_res; + + DBG(DBG_io, "%s: calib_lines = %zu\n", __func__, dev->calib_lines); + DBG(DBG_io, "%s: calib_pixels = %zu\n", __func__, dev->calib_pixels); + + /* this is aworkaround insufficent distance for slope + * motor acceleration TODO special motor slope for shading */ + move=1; + if(dev->calib_resolution<1200) + { + move=40; + } + + ScanSession session; + session.params.xres = dev->calib_resolution; + session.params.yres = dev->calib_resolution; + session.params.startx = 0; + session.params.starty = static_cast(move); + session.params.pixels = dev->calib_pixels; + session.params.lines = dev->calib_lines; + session.params.depth = 16; + session.params.channels = dev->calib_channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::DISABLE_BUFFER_FULL_MOVE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + dev->interface->write_registers(regs); + + /* we use GENESYS_FLAG_SHADING_REPARK */ + dev->set_head_pos_zero(ScanHeadId::PRIMARY); +} + +/** @brief set up registers for the actual scan + */ +void CommandSetGl846::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + float move; + int move_dpi; + float start; + + debug_dump(DBG_info, dev->settings); + + /* steps to move to reach scanning area: + - first we move to physical start of scanning + either by a fixed steps amount from the black strip + or by a fixed amount from parking position, + minus the steps done during shading calibration + - then we move by the needed offset whitin physical + scanning area + + assumption: steps are expressed at maximum motor resolution + + we need: + float y_offset; + float y_size; + float y_offset_calib; + mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ + + /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is + relative from origin, else, it is from parking position */ + + move_dpi = dev->motor.base_ydpi; + + move = static_cast(dev->model->y_offset); + move = static_cast(move + dev->settings.tl_y); + move = static_cast((move * move_dpi) / MM_PER_INCH); + move -= dev->head_pos(ScanHeadId::PRIMARY); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* fast move to scan area */ + /* we don't move fast the whole distance since it would involve + * computing acceleration/deceleration distance for scan + * resolution. So leave a remainder for it so scan makes the final + * move tuning */ + if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) { + scanner_move(*dev, dev->model->default_method, static_cast(move - 500), + Direction::FORWARD); + move=500; + } + + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* start */ + start = static_cast(dev->model->x_offset); + start = static_cast(start + dev->settings.tl_x); + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = dev->settings.pixels; + session.params.requested_pixels = dev->settings.requested_pixels; + session.params.lines = dev->settings.lines; + session.params.depth = dev->settings.depth; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + // backtracking isn't handled well, so don't enable it + session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &dev->reg, session); +} + + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +void CommandSetGl846::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + uint8_t* data, int size) const +{ + DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size); + uint32_t addr, length, i, x, factor, pixels; + uint32_t dpiset, dpihw; + uint8_t val,*ptr,*src; + + /* shading data is plit in 3 (up to 5 with IR) areas + write(0x10014000,0x00000dd8) + URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x.... + write(0x1003e000,0x00000dd8) + write(0x10068000,0x00000dd8) + */ + length = static_cast(size / 3); + unsigned strpixel = dev->session.pixel_startx; + unsigned endpixel = dev->session.pixel_endx; + + /* compute deletion factor */ + dpiset = dev->reg.get16(REG_DPISET); + dpihw = sensor.get_register_hwdpi(dpiset); + factor=dpihw/dpiset; + DBG(DBG_io2, "%s: factor=%d\n", __func__, factor); + + pixels=endpixel-strpixel; + + /* since we're using SHDAREA, substract startx coordinate from shading */ + strpixel -= (sensor.ccd_start_xoffset * 600) / sensor.optical_res; + + /* turn pixel value into bytes 2x16 bits words */ + strpixel*=2*2; + pixels*=2*2; + + dev->interface->record_key_value("shading_offset", std::to_string(strpixel)); + dev->interface->record_key_value("shading_pixels", std::to_string(pixels)); + dev->interface->record_key_value("shading_length", std::to_string(length)); + dev->interface->record_key_value("shading_factor", std::to_string(factor)); + + std::vector buffer(pixels, 0); + + DBG(DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n", __func__, pixels, pixels); + + /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address + * is 8192*reg value */ + + /* write actual color channel data */ + for(i=0;i<3;i++) + { + /* build up actual shading data by copying the part from the full width one + * to the one corresponding to SHDAREA */ + ptr = buffer.data(); + + /* iterate on both sensor segment */ + for(x=0;xinterface->read_register(0xd0+i); + addr = val * 8192 + 0x10000000; + dev->interface->write_ahb(addr, pixels, buffer.data()); + } +} + +/** @brief calibrates led exposure + * Calibrate exposure by scanning a white area until the used exposure gives + * data white enough. + * @param dev device to calibrate + */ +SensorExposure CommandSetGl846::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int num_pixels; + int total_size; + int used_res; + int i, j; + int val; + int channels; + int avg[3], top[3], bottom[3]; + int turn; + uint16_t exp[3]; + + float move = static_cast(dev->model->y_offset_calib_white); + move = static_cast((move * (dev->motor.base_ydpi / 4)) / MM_PER_INCH); + if(move>20) + { + scanner_move(*dev, dev->model->default_method, static_cast(move), + Direction::FORWARD); + } + DBG(DBG_io, "%s: move=%f steps\n", __func__, move); + + /* offset calibration is always done in color mode */ + channels = 3; + used_res = sensor.get_register_hwdpi(dev->settings.xres); + const auto& calib_sensor = sanei_genesys_find_sensor(dev, used_res, channels, + dev->settings.scan_method); + num_pixels = (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + ScanSession session; + session.params.xres = used_res; + session.params.yres = used_res; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + total_size = num_pixels * channels * (session.params.depth / 8) * 1; + std::vector line(total_size); + + /* initial loop values and boundaries */ + exp[0] = calib_sensor.exposure.red; + exp[1] = calib_sensor.exposure.green; + exp[2] = calib_sensor.exposure.blue; + + bottom[0]=29000; + bottom[1]=29000; + bottom[2]=29000; + + top[0]=41000; + top[1]=51000; + top[2]=51000; + + turn = 0; + + /* no move during led calibration */ + sanei_genesys_set_motor_power(regs, false); + bool acceptable = false; + do + { + // set up exposure + regs.set16(REG_EXPR, exp[0]); + regs.set16(REG_EXPG, exp[1]); + regs.set16(REG_EXPB, exp[2]); + + // write registers and scan data + dev->interface->write_registers(regs); + + DBG(DBG_info, "%s: starting line reading\n", __func__); + begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("led_calibration"); + scanner_stop_action(*dev); + move_back_home(dev, true); + return calib_sensor.exposure; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + + // stop scanning + scanner_stop_action(*dev); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl846_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth, + channels, num_pixels, 1); + } + + /* compute average */ + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + /* check if exposure gives average within the boundaries */ + acceptable = true; + for(i=0;i<3;i++) + { + if(avg[i]top[i]) + { + exp[i]=(exp[i]*top[i])/avg[i]; + acceptable = false; + } + } + + turn++; + } + while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); + + // set these values as final ones for scan + dev->reg.set16(REG_EXPR, exp[0]); + dev->reg.set16(REG_EXPG, exp[1]); + dev->reg.set16(REG_EXPB, exp[2]); + + /* go back home */ + if(move>20) + { + move_back_home(dev, true); + } + + return { exp[0], exp[1], exp[2] }; +} + +/** + * set up GPIO/GPOE for idle state + */ +static void gl846_init_gpio(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + int idx=0; + + /* search GPIO profile */ + while (gpios[idx].gpio_id != GpioId::UNKNOWN && dev->model->gpio_id != gpios[idx].gpio_id) { + idx++; + } + if (gpios[idx].gpio_id == GpioId::UNKNOWN) + { + throw SaneException("failed to find GPIO profile for sensor_id=%d", + static_cast(dev->model->sensor_id)); + } + + dev->interface->write_register(REG_0xA7, gpios[idx].ra7); + dev->interface->write_register(REG_0xA6, gpios[idx].ra6); + + dev->interface->write_register(REG_0x6B, gpios[idx].r6b); + dev->interface->write_register(REG_0x6C, gpios[idx].r6c); + dev->interface->write_register(REG_0x6D, gpios[idx].r6d); + dev->interface->write_register(REG_0x6E, gpios[idx].r6e); + dev->interface->write_register(REG_0x6F, gpios[idx].r6f); + + dev->interface->write_register(REG_0xA8, gpios[idx].ra8); + dev->interface->write_register(REG_0xA9, gpios[idx].ra9); +} + +/** + * set memory layout by filling values in dedicated registers + */ +static void gl846_init_memory_layout(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + int idx = 0, i; + uint8_t val; + + /* point to per model memory layout */ + idx = 0; + while (layouts[idx].model != nullptr && strcmp(dev->model->name,layouts[idx].model)!=0) { + if(strcmp(dev->model->name,layouts[idx].model)!=0) + idx++; + } + if (layouts[idx].model == nullptr) { + throw SaneException("failed to find memory layout for model %s", dev->model->name); + } + + /* CLKSET and DRAMSEL */ + val = layouts[idx].dramsel; + dev->interface->write_register(REG_0x0B, val); + dev->reg.find_reg(0x0b).value = val; + + /* prevent further writings by bulk write register */ + dev->reg.remove_reg(0x0b); + + /* setup base address for shading and scanned data. */ + for(i=0;i<10;i++) + { + dev->interface->write_register(0xe0+i, layouts[idx].rx[i]); + } +} + +/* * + * initialize ASIC from power on condition + */ +void CommandSetGl846::asic_boot(Genesys_Device* dev, bool cold) const +{ + DBG_HELPER(dbg); + uint8_t val; + + // reset ASIC if cold boot + if (cold) { + dev->interface->write_register(0x0e, 0x01); + dev->interface->write_register(0x0e, 0x00); + } + + if(dev->usb_mode == 1) + { + val = 0x14; + } + else + { + val = 0x11; + } + dev->interface->write_0x8c(0x0f, val); + + // test CHKVER + val = dev->interface->read_register(REG_0x40); + if (val & REG_0x40_CHKVER) { + val = dev->interface->read_register(0x00); + DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); + } + + /* Set default values for registers */ + gl846_init_registers (dev); + + // Write initial registers + dev->interface->write_registers(dev->reg); + + /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ + val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL; + val = (val | REG_0x0B_ENBDRAM); + dev->interface->write_register(REG_0x0B, val); + dev->reg.find_reg(0x0b).value = val; + + /* CIS_LINE */ + if (dev->model->is_cis) + { + dev->reg.init_reg(0x08, REG_0x08_CIS_LINE); + dev->interface->write_register(0x08, dev->reg.find_reg(0x08).value); + } + + // set up clocks + dev->interface->write_0x8c(0x10, 0x0e); + dev->interface->write_0x8c(0x13, 0x0e); + + // setup gpio + gl846_init_gpio(dev); + + // setup internal memory layout + gl846_init_memory_layout(dev); + + dev->reg.init_reg(0xf8, 0x05); + dev->interface->write_register(0xf8, dev->reg.find_reg(0xf8).value); +} + +/** + * initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +void CommandSetGl846::init(Genesys_Device* dev) const +{ + DBG_INIT (); + DBG_HELPER(dbg); + + sanei_genesys_asic_init(dev, 0); +} + +void CommandSetGl846::update_hardware_sensors(Genesys_Scanner* s) const +{ + DBG_HELPER(dbg); + /* do what is needed to get a new set of events, but try to not lose + any of them. + */ + uint8_t val; + uint8_t scan, file, email, copy; + switch(s->dev->model->gpio_id) + { + default: + scan=0x01; + file=0x02; + email=0x04; + copy=0x08; + } + val = s->dev->interface->read_register(REG_0x6D); + + s->buttons[BUTTON_SCAN_SW].write((val & scan) == 0); + s->buttons[BUTTON_FILE_SW].write((val & file) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & email) == 0); + s->buttons[BUTTON_COPY_SW].write((val & copy) == 0); +} + + +void CommandSetGl846::update_home_sensor_gpio(Genesys_Device& dev) const +{ + DBG_HELPER(dbg); + + std::uint8_t val = dev.interface->read_register(REG_0x6C); + val |= 0x41; + dev.interface->write_register(REG_0x6C, val); +} + +/** @brief search for a full width black or white strip. + * This function searches for a black or white stripe across the scanning area. + * When searching backward, the searched area must completely be of the desired + * color since this area will be used for calibration which scans forward. + * @param dev scanner device + * @param forward true if searching forward, false if searching backward + * @param black true if searching for a black strip, false for a white strip + */ +void CommandSetGl846::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward, + bool black) const +{ + DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse"); + unsigned int pixels, lines, channels; + Genesys_Register_Set local_reg; + size_t size; + unsigned int pass, count, found, x, y; + char title[80]; + + set_fe(dev, sensor, AFE_SET); + + scanner_stop_action(*dev); + + // set up for a gray scan at lowest dpi + const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method); + unsigned dpi = resolution_settings.get_min_resolution_x(); + channels = 1; + /* 10 MM */ + /* lines = (10 * dpi) / MM_PER_INCH; */ + /* shading calibation is done with dev->motor.base_ydpi */ + lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; + pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; + + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + + local_reg = dev->reg; + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::RED; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA; + if (!forward) { + session.params.flags |= ScanFlag::REVERSE; + } + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &local_reg, session); + + size = pixels * channels * lines * (session.params.depth / 8); + std::vector data(size); + + dev->interface->write_registers(local_reg); + + begin_scan(dev, sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_strip"); + scanner_stop_action(*dev); + return; + } + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + scanner_stop_action(*dev); + + pass = 0; + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl846_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, + channels, pixels, lines); + } + + /* loop until strip is found or maximum pass number done */ + found = 0; + while (pass < 20 && !found) + { + dev->interface->write_registers(local_reg); + + // now start scan + begin_scan(dev, sensor, &local_reg, true); + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + scanner_stop_action(*dev); + + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl846_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, + channels, pixels, lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (pixels * lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + pass++; + } + + if (found) + { + DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); + } + else + { + throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white"); + } +} + +/** + * average dark pixels of a 8 bits scan + */ +static int +dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black) +{ + unsigned int i, j, k, average, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average value on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + for (i = 0; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + average = 0; + for (i = 0; i < channels; i++) + average += avg[i]; + average /= channels; + DBG(DBG_info, "%s: average = %d\n", __func__, average); + return average; +} + +void CommandSetGl846::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + unsigned channels; + int pass = 0, avg, total_size; + int topavg, bottomavg, lines; + int top, bottom, black_pixels, pixels; + + // no gain nor offset for AKM AFE + uint8_t reg04 = dev->interface->read_register(REG_0x04); + if ((reg04 & REG_0x04_FESET) == 0x02) { + return; + } + + /* offset calibration is always done in color mode */ + channels = 3; + dev->calib_pixels = sensor.sensor_pixels; + lines=1; + pixels = (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res; + black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + ScanSession session; + session.params.xres = sensor.optical_res; + session.params.yres = sensor.optical_res; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, ®s, session); + + sanei_genesys_set_motor_power(regs, false); + + total_size = pixels * channels * lines * (session.params.depth / 8); + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* init gain */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* scan with no move */ + bottom = 10; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting first line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("offset_calibration"); + return; + } + + sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl846_offset%03d.pnm", bottom); + sanei_genesys_write_pnm_file(fn, first_line.data(), session.params.depth, + channels, pixels, lines); + } + + bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); + + /* now top value */ + top = 255; + dev->frontend.set_offset(0, top); + dev->frontend.set_offset(1, top); + dev->frontend.set_offset(2, top); + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + + topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); + + /* loop until acceptable level */ + while ((pass < 32) && (top - bottom > 1)) + { + pass++; + + /* settings for new scan */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + // scan with no move + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl846_offset%03d.pnm", dev->frontend.get_offset(1)); + sanei_genesys_write_pnm_file(fn, second_line.data(), session.params.depth, + channels, pixels, lines); + } + + avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); + + /* compute new boundaries */ + if (topavg == avg) + { + topavg = avg; + top = dev->frontend.get_offset(1); + } + else + { + bottomavg = avg; + bottom = dev->frontend.get_offset(1); + } + } + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); +} + +void CommandSetGl846::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const +{ + DBG_HELPER(dbg); + int pixels; + int total_size; + int i, j, channels; + int max[3]; + float gain[3],coeff; + int val, code, lines; + + DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); + + // no gain nor offset for AKM AFE + uint8_t reg04 = dev->interface->read_register(REG_0x04); + if ((reg04 & REG_0x04_FESET) == 0x02) { + return; + } + + /* coarse gain calibration is always done in color mode */ + channels = 3; + + /* follow CKSEL */ + if(dev->settings.xressettings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + try { + init_regs_for_scan_session(dev, sensor, ®s, session); + } catch (...) { + catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); }); + throw; + } + + sanei_genesys_set_motor_power(regs, false); + + dev->interface->write_registers(regs); + + total_size = pixels * channels * (16 / session.params.depth) * lines; + + std::vector line(total_size); + + set_fe(dev, sensor, AFE_SET); + begin_scan(dev, sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("coarse_gain_calibration"); + scanner_stop_action(*dev); + move_back_home(dev, true); + return; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl846_gain.pnm", line.data(), session.params.depth, + channels, pixels, lines); + } + + /* average value on each channel */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + for (i = pixels/4; i < (pixels*3/4); i++) + { + if (dev->model->is_cis) + val = line[i + j * pixels]; + else + val = line[i * channels + j]; + + max[j] += val; + } + max[j] = max[j] / (pixels/2); + + gain[j] = (static_cast(sensor.gain_white_ref) * coeff) / max[j]; + + /* turn logical gain value into gain code, checking for overflow */ + code = static_cast(283 - 208 / gain[j]); + if (code > 255) + code = 255; + else if (code < 0) + code = 0; + dev->frontend.set_gain(j, code); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], + dev->frontend.get_gain(j)); + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + scanner_stop_action(*dev); + + move_back_home(dev, true); +} + +bool CommandSetGl846::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const +{ + (void) dev; + return false; +} + +void CommandSetGl846::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const +{ + (void) dev; + (void) sensor; + (void) regs; + (void) channels; + (void) total_size; + throw SaneException("not implemented"); +} + +void CommandSetGl846::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + sanei_genesys_send_gamma_table(dev, sensor); +} + +void CommandSetGl846::wait_for_motor_stop(Genesys_Device* dev) const +{ + (void) dev; +} + +void CommandSetGl846::load_document(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl846::detect_document_end(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl846::eject_document(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl846::move_to_ta(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +std::unique_ptr create_gl846_cmd_set() +{ + return std::unique_ptr(new CommandSetGl846{}); +} + +} // namespace gl846 +} // namespace genesys diff --git a/backend/genesys/gl846.h b/backend/genesys/gl846.h new file mode 100644 index 0000000..258015a --- /dev/null +++ b/backend/genesys/gl846.h @@ -0,0 +1,218 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2012-2013 Stéphane Voltz + + 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 "genesys.h" +#include "command_set.h" + +#ifndef BACKEND_GENESYS_GL846_H +#define BACKEND_GENESYS_GL846_H + +namespace genesys { +namespace gl846 { + +typedef struct +{ + GpioId gpio_id; + uint8_t r6b; + uint8_t r6c; + uint8_t r6d; + uint8_t r6e; + uint8_t r6f; + uint8_t ra6; + uint8_t ra7; + uint8_t ra8; + uint8_t ra9; +} Gpio_Profile; + +static Gpio_Profile gpios[]={ + { GpioId::IMG101, 0x72, 0x1f, 0xa4, 0x13, 0xa7, 0x11, 0xff, 0x19, 0x05}, + { GpioId::PLUSTEK_OPTICBOOK_3800, 0x30, 0x01, 0x80, 0x2d, 0x80, 0x0c, 0x8f, 0x08, 0x04}, + { GpioId::UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +typedef struct +{ + const char *model; + uint8_t dramsel; + /* shading data address */ + uint8_t rd0; + uint8_t rd1; + uint8_t rd2; + /* scanned data address */ + uint8_t rx[24]; +} Memory_layout; + +static Memory_layout layouts[]={ + /* Image formula 101 */ + { + "canon-image-formula-101", + 0x8b, + 0x0a, 0x1b, 0x00, + { /* RED ODD START / RED ODD END */ + 0x00, 0xb0, 0x05, 0xe7, /* [0x00b0, 0x05e7] 1336*4000w */ + /* RED EVEN START / RED EVEN END */ + 0x05, 0xe8, 0x0b, 0x1f, /* [0x05e8, 0x0b1f] */ + /* GREEN ODD START / GREEN ODD END */ + 0x0b, 0x20, 0x10, 0x57, /* [0x0b20, 0x1057] */ + /* GREEN EVEN START / GREEN EVEN END */ + 0x10, 0x58, 0x15, 0x8f, /* [0x1058, 0x158f] */ + /* BLUE ODD START / BLUE ODD END */ + 0x15, 0x90, 0x1a, 0xc7, /* [0x1590,0x1ac7] */ + /* BLUE EVEN START / BLUE EVEN END */ + 0x1a, 0xc8, 0x1f, 0xff /* [0x1ac8,0x1fff] */ + } + }, + /* OpticBook 3800 */ + { + "plustek-opticbook-3800", + 0x2a, + 0x0a, 0x0a, 0x0a, + { /* RED ODD START / RED ODD END */ + 0x00, 0x68, 0x03, 0x00, + /* RED EVEN START / RED EVEN END */ + 0x03, 0x01, 0x05, 0x99, + /* GREEN ODD START / GREEN ODD END */ + 0x05, 0x9a, 0x08, 0x32, + /* GREEN EVEN START / GREEN EVEN END */ + 0x08, 0x33, 0x0a, 0xcb, + /* BLUE ODD START / BLUE ODD END */ + 0x0a, 0xcc, 0x0d, 0x64, + /* BLUE EVEN START / BLUE EVEN END */ + 0x0d, 0x65, 0x0f, 0xfd + } + }, + /* list terminating entry */ + { nullptr, 0, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } +}; + +class CommandSetGl846 : public CommandSet +{ +public: + ~CommandSetGl846() override = default; + + bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override; + + void init(Genesys_Device* dev) const override; + + void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const override; + + void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const override; + + void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override; + void set_powersaving(Genesys_Device* dev, int delay) const override; + void save_power(Genesys_Device* dev, bool enable) const override; + + void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, bool start_motor) const override; + + void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override; + + void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void search_start_position(Genesys_Device* dev) const override; + + void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const override; + + SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void wait_for_motor_stop(Genesys_Device* dev) const override; + + void move_back_home(Genesys_Device* dev, bool wait_until_home) const override; + + void update_hardware_sensors(struct Genesys_Scanner* s) const override; + + bool needs_update_home_sensor_gpio() const override { return true; } + + void update_home_sensor_gpio(Genesys_Device& dev) const override; + + void load_document(Genesys_Device* dev) const override; + + void detect_document_end(Genesys_Device* dev) const override; + + void eject_document(Genesys_Device* dev) const override; + + void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const override; + + void move_to_ta(Genesys_Device* dev) const override; + + void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data, + int size) const override; + + ScanSession calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const override; + + void asic_boot(Genesys_Device* dev, bool cold) const override; +}; + +enum SlopeTable +{ + SCAN_TABLE = 0, // table 1 at 0x4000 + BACKTRACK_TABLE = 1, // table 2 at 0x4800 + STOP_TABLE = 2, // table 3 at 0x5000 + FAST_TABLE = 3, // table 4 at 0x5800 + HOME_TABLE = 4, // table 5 at 0x6000 +}; + +} // namespace gl846 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL846_H diff --git a/backend/genesys/gl846_registers.h b/backend/genesys/gl846_registers.h new file mode 100644 index 0000000..39b3029 --- /dev/null +++ b/backend/genesys/gl846_registers.h @@ -0,0 +1,351 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL846_REGISTERS_H +#define BACKEND_GENESYS_GL846_REGISTERS_H + +#include + +namespace genesys { +namespace gl846 { + +using RegAddr = std::uint16_t; +using RegMask = std::uint8_t; +using RegShift = unsigned; + +static constexpr RegAddr REG_0x01 = 0x01; +static constexpr RegMask REG_0x01_CISSET = 0x80; +static constexpr RegMask REG_0x01_DOGENB = 0x40; +static constexpr RegMask REG_0x01_DVDSET = 0x20; +static constexpr RegMask REG_0x01_STAGGER = 0x10; +static constexpr RegMask REG_0x01_COMPENB = 0x08; +static constexpr RegMask REG_0x01_TRUEGRAY = 0x04; +static constexpr RegMask REG_0x01_SHDAREA = 0x02; +static constexpr RegMask REG_0x01_SCAN = 0x01; + +static constexpr RegAddr REG_0x02 = 0x02; +static constexpr RegMask REG_0x02_NOTHOME = 0x80; +static constexpr RegMask REG_0x02_ACDCDIS = 0x40; +static constexpr RegMask REG_0x02_AGOHOME = 0x20; +static constexpr RegMask REG_0x02_MTRPWR = 0x10; +static constexpr RegMask REG_0x02_FASTFED = 0x08; +static constexpr RegMask REG_0x02_MTRREV = 0x04; +static constexpr RegMask REG_0x02_HOMENEG = 0x02; +static constexpr RegMask REG_0x02_LONGCURV = 0x01; + +static constexpr RegAddr REG_0x03 = 0x03; +static constexpr RegMask REG_0x03_LAMPDOG = 0x80; +static constexpr RegMask REG_0x03_AVEENB = 0x40; +static constexpr RegMask REG_0x03_XPASEL = 0x20; +static constexpr RegMask REG_0x03_LAMPPWR = 0x10; +static constexpr RegMask REG_0x03_LAMPTIM = 0x0f; + +static constexpr RegAddr REG_0x04 = 0x04; +static constexpr RegMask REG_0x04_LINEART = 0x80; +static constexpr RegMask REG_0x04_BITSET = 0x40; +static constexpr RegMask REG_0x04_AFEMOD = 0x30; +static constexpr RegMask REG_0x04_FILTER = 0x0c; +static constexpr RegMask REG_0x04_FESET = 0x03; + +static constexpr RegShift REG_0x04S_AFEMOD = 4; + +static constexpr RegAddr REG_0x05 = 0x05; +static constexpr RegMask REG_0x05_DPIHW = 0xc0; +static constexpr RegMask REG_0x05_DPIHW_600 = 0x00; +static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40; +static constexpr RegMask REG_0x05_DPIHW_2400 = 0x80; +static constexpr RegMask REG_0x05_DPIHW_4800 = 0xc0; +static constexpr RegMask REG_0x05_MTLLAMP = 0x30; +static constexpr RegMask REG_0x05_GMMENB = 0x08; +static constexpr RegMask REG_0x05_MTLBASE = 0x03; + +static constexpr RegAddr REG_0x06 = 0x06; +static constexpr RegMask REG_0x06_SCANMOD = 0xe0; +static constexpr RegShift REG_0x06S_SCANMOD = 5; +static constexpr RegMask REG_0x06_PWRBIT = 0x10; +static constexpr RegMask REG_0x06_GAIN4 = 0x08; +static constexpr RegMask REG_0x06_OPTEST = 0x07; + +static constexpr RegMask REG_0x07_LAMPSIM = 0x80; + +static constexpr RegMask REG_0x08_DRAM2X = 0x80; +static constexpr RegMask REG_0x08_MPENB = 0x20; +static constexpr RegMask REG_0x08_CIS_LINE = 0x10; +static constexpr RegMask REG_0x08_IR1ENB = 0x08; +static constexpr RegMask REG_0x08_IR2ENB = 0x04; +static constexpr RegMask REG_0x08_ENB24M = 0x01; + +static constexpr RegMask REG_0x09_MCNTSET = 0xc0; +static constexpr RegMask REG_0x09_EVEN1ST = 0x20; +static constexpr RegMask REG_0x09_BLINE1ST = 0x10; +static constexpr RegMask REG_0x09_BACKSCAN = 0x08; +static constexpr RegMask REG_0x09_ENHANCE = 0x04; +static constexpr RegMask REG_0x09_SHORTTG = 0x02; +static constexpr RegMask REG_0x09_NWAIT = 0x01; + +static constexpr RegShift REG_0x09S_MCNTSET = 6; +static constexpr RegShift REG_0x09S_CLKSET = 4; + + +static constexpr RegAddr REG_0x0A_LPWMEN = 0x10; + +static constexpr RegAddr REG_0x0B = 0x0b; +static constexpr RegMask REG_0x0B_DRAMSEL = 0x07; +static constexpr RegMask REG_0x0B_ENBDRAM = 0x08; +static constexpr RegMask REG_0x0B_RFHDIS = 0x10; +static constexpr RegMask REG_0x0B_CLKSET = 0xe0; +static constexpr RegMask REG_0x0B_24MHZ = 0x00; +static constexpr RegMask REG_0x0B_30MHZ = 0x20; +static constexpr RegMask REG_0x0B_40MHZ = 0x40; +static constexpr RegMask REG_0x0B_48MHZ = 0x60; +static constexpr RegMask REG_0x0B_60MHZ = 0x80; + +static constexpr RegAddr REG_0x0C = 0x0c; +static constexpr RegMask REG_0x0C_CCDLMT = 0x0f; + +static constexpr RegAddr REG_0x0D = 0x0d; +static constexpr RegMask REG_0x0D_SCSYNC = 0x40; +static constexpr RegMask REG_0x0D_CLRERR = 0x20; +static constexpr RegMask REG_0x0D_FULLSTP = 0x10; +static constexpr RegMask REG_0x0D_SEND = 0x80; +static constexpr RegMask REG_0x0D_CLRMCNT = 0x04; +static constexpr RegMask REG_0x0D_CLRDOCJM = 0x02; +static constexpr RegMask REG_0x0D_CLRLNCNT = 0x01; + +static constexpr RegAddr REG_0x0F = 0x0f; + +static constexpr RegMask REG_0x16_CTRLHI = 0x80; +static constexpr RegMask REG_0x16_TOSHIBA = 0x40; +static constexpr RegMask REG_0x16_TGINV = 0x20; +static constexpr RegMask REG_0x16_CK1INV = 0x10; +static constexpr RegMask REG_0x16_CK2INV = 0x08; +static constexpr RegMask REG_0x16_CTRLINV = 0x04; +static constexpr RegMask REG_0x16_CKDIS = 0x02; +static constexpr RegMask REG_0x16_CTRLDIS = 0x01; + +static constexpr RegMask REG_0x17_TGMODE = 0xc0; +static constexpr RegMask REG_0x17_TGMODE_NO_DUMMY = 0x00; +static constexpr RegMask REG_0x17_TGMODE_REF = 0x40; +static constexpr RegMask REG_0x17_TGMODE_XPA = 0x80; +static constexpr RegMask REG_0x17_TGW = 0x3f; +static constexpr RegAddr REG_0x17S_TGW = 0; + +static constexpr RegAddr REG_0x18 = 0x18; +static constexpr RegMask REG_0x18_CNSET = 0x80; +static constexpr RegMask REG_0x18_DCKSEL = 0x60; +static constexpr RegMask REG_0x18_CKTOGGLE = 0x10; +static constexpr RegMask REG_0x18_CKDELAY = 0x0c; +static constexpr RegMask REG_0x18_CKSEL = 0x03; + +static constexpr RegMask REG_0x1A_SW2SET = 0x80; +static constexpr RegMask REG_0x1A_SW1SET = 0x40; +static constexpr RegMask REG_0x1A_MANUAL3 = 0x02; +static constexpr RegMask REG_0x1A_MANUAL1 = 0x01; +static constexpr RegMask REG_0x1A_CK4INV = 0x08; +static constexpr RegMask REG_0x1A_CK3INV = 0x04; +static constexpr RegMask REG_0x1A_LINECLP = 0x02; + +static constexpr RegAddr REG_0x1C = 0x1c; +static constexpr RegMask REG_0x1C_TGTIME = 0x07; + +static constexpr RegMask REG_0x1D_CK4LOW = 0x80; +static constexpr RegMask REG_0x1D_CK3LOW = 0x40; +static constexpr RegMask REG_0x1D_CK1LOW = 0x20; +static constexpr RegMask REG_0x1D_TGSHLD = 0x1f; +static constexpr RegShift REG_0x1DS_TGSHLD = 0; + + +static constexpr RegMask REG_0x1E_WDTIME = 0xf0; +static constexpr RegShift REG_0x1ES_WDTIME = 4; +static constexpr RegMask REG_0x1E_LINESEL = 0x0f; +static constexpr RegShift REG_0x1ES_LINESEL = 0; + +static constexpr RegAddr REG_FEDCNT = 0x1f; + +static constexpr RegAddr REG_0x24 = 0x1c; +static constexpr RegAddr REG_0x40 = 0x40; +static constexpr RegMask REG_0x40_DOCSNR = 0x80; +static constexpr RegMask REG_0x40_ADFSNR = 0x40; +static constexpr RegMask REG_0x40_COVERSNR = 0x20; +static constexpr RegMask REG_0x40_CHKVER = 0x10; +static constexpr RegMask REG_0x40_DOCJAM = 0x08; +static constexpr RegMask REG_0x40_HISPDFLG = 0x04; +static constexpr RegMask REG_0x40_MOTMFLG = 0x02; +static constexpr RegMask REG_0x40_DATAENB = 0x01; + +static constexpr RegMask REG_0x41_PWRBIT = 0x80; +static constexpr RegMask REG_0x41_BUFEMPTY = 0x40; +static constexpr RegMask REG_0x41_FEEDFSH = 0x20; +static constexpr RegMask REG_0x41_SCANFSH = 0x10; +static constexpr RegMask REG_0x41_HOMESNR = 0x08; +static constexpr RegMask REG_0x41_LAMPSTS = 0x04; +static constexpr RegMask REG_0x41_FEBUSY = 0x02; +static constexpr RegMask REG_0x41_MOTORENB = 0x01; + +static constexpr RegMask REG_0x58_VSMP = 0xf8; +static constexpr RegShift REG_0x58S_VSMP = 3; +static constexpr RegMask REG_0x58_VSMPW = 0x07; +static constexpr RegAddr REG_0x58S_VSMPW = 0; + +static constexpr RegMask REG_0x59_BSMP = 0xf8; +static constexpr RegAddr REG_0x59S_BSMP = 3; +static constexpr RegMask REG_0x59_BSMPW = 0x07; +static constexpr RegShift REG_0x59S_BSMPW = 0; + +static constexpr RegMask REG_0x5A_ADCLKINV = 0x80; +static constexpr RegMask REG_0x5A_RLCSEL = 0x40; +static constexpr RegMask REG_0x5A_CDSREF = 0x30; +static constexpr RegShift REG_0x5AS_CDSREF = 4; +static constexpr RegMask REG_0x5A_RLC = 0x0f; +static constexpr RegShift REG_0x5AS_RLC = 0; + +static constexpr RegMask REG_0x5E_DECSEL = 0xe0; +static constexpr RegShift REG_0x5ES_DECSEL = 5; +static constexpr RegMask REG_0x5E_STOPTIM = 0x1f; +static constexpr RegShift REG_0x5ES_STOPTIM = 0; + +static constexpr RegAddr REG_0x60 = 0x60; +static constexpr RegMask REG_0x60_Z1MOD = 0x1f; +static constexpr RegAddr REG_0x61 = 0x61; +static constexpr RegMask REG_0x61_Z1MOD = 0xff; +static constexpr RegAddr REG_0x62 = 0x62; +static constexpr RegMask REG_0x62_Z1MOD = 0xff; + +static constexpr RegAddr REG_0x63 = 0x63; +static constexpr RegMask REG_0x63_Z2MOD = 0x1f; +static constexpr RegAddr REG_0x64 = 0x64; +static constexpr RegMask REG_0x64_Z2MOD = 0xff; +static constexpr RegAddr REG_0x65 = 0x65; +static constexpr RegMask REG_0x65_Z2MOD = 0xff; + +static constexpr RegShift REG_0x60S_STEPSEL = 5; +static constexpr RegMask REG_0x60_STEPSEL = 0xe0; +static constexpr RegMask REG_0x60_FULLSTEP = 0x00; +static constexpr RegMask REG_0x60_HALFSTEP = 0x20; +static constexpr RegMask REG_0x60_EIGHTHSTEP = 0x60; +static constexpr RegMask REG_0x60_16THSTEP = 0x80; + +static constexpr RegShift REG_0x63S_FSTPSEL = 5; +static constexpr RegMask REG_0x63_FSTPSEL = 0xe0; +static constexpr RegMask REG_0x63_FULLSTEP = 0x00; +static constexpr RegMask REG_0x63_HALFSTEP = 0x20; +static constexpr RegMask REG_0x63_EIGHTHSTEP = 0x60; +static constexpr RegMask REG_0x63_16THSTEP = 0x80; + +static constexpr RegAddr REG_0x67 = 0x67; +static constexpr RegMask REG_0x67_MTRPWM = 0x80; + +static constexpr RegAddr REG_0x68 = 0x68; +static constexpr RegMask REG_0x68_FASTPWM = 0x80; + +static constexpr RegAddr REG_0x6B = 0x6b; +static constexpr RegMask REG_0x6B_MULTFILM = 0x80; +static constexpr RegMask REG_0x6B_GPOM13 = 0x40; +static constexpr RegMask REG_0x6B_GPOM12 = 0x20; +static constexpr RegMask REG_0x6B_GPOM11 = 0x10; +static constexpr RegMask REG_0x6B_GPO18 = 0x02; +static constexpr RegMask REG_0x6B_GPO17 = 0x01; + +static constexpr RegAddr REG_0x6C = 0x6c; +static constexpr RegMask REG_0x6C_GPIO16 = 0x80; +static constexpr RegMask REG_0x6C_GPIO15 = 0x40; +static constexpr RegMask REG_0x6C_GPIO14 = 0x20; +static constexpr RegMask REG_0x6C_GPIO13 = 0x10; +static constexpr RegMask REG_0x6C_GPIO12 = 0x08; +static constexpr RegMask REG_0x6C_GPIO11 = 0x04; +static constexpr RegMask REG_0x6C_GPIO10 = 0x02; +static constexpr RegMask REG_0x6C_GPIO9 = 0x01; +static constexpr RegMask REG_0x6C_GPIOH = 0xff; +static constexpr RegMask REG_0x6C_GPIOL = 0xff; + +static constexpr RegAddr REG_0x6D = 0x6d; +static constexpr RegAddr REG_0x6E = 0x6e; +static constexpr RegAddr REG_0x6F = 0x6f; +static constexpr RegAddr REG_0x7E = 0x7e; + +static constexpr RegMask REG_0x87_ACYCNRLC = 0x10; +static constexpr RegMask REG_0x87_ENOFFSET = 0x08; +static constexpr RegMask REG_0x87_LEDADD = 0x04; +static constexpr RegMask REG_0x87_CK4ADC = 0x02; +static constexpr RegMask REG_0x87_AUTOCONF = 0x01; + +static constexpr RegAddr REG_0x9E = 0x9e; +static constexpr RegAddr REG_0x9F = 0x9f; + +static constexpr RegAddr REG_0xA6 = 0xa6; +static constexpr RegAddr REG_0xA7 = 0xa7; +static constexpr RegAddr REG_0xA8 = 0xa8; +static constexpr RegAddr REG_0xA9 = 0xa9; +static constexpr RegAddr REG_0xAB = 0xab; + +static constexpr RegAddr REG_EXPR = 0x10; +static constexpr RegAddr REG_EXPG = 0x12; +static constexpr RegAddr REG_EXPB = 0x14; +static constexpr RegAddr REG_EXPDMY = 0x19; +static constexpr RegAddr REG_STEPNO = 0x21; +static constexpr RegAddr REG_FWDSTEP = 0x22; +static constexpr RegAddr REG_BWDSTEP = 0x23; +static constexpr RegAddr REG_FASTNO = 0x24; +static constexpr RegAddr REG_DPISET = 0x2c; +static constexpr RegAddr REG_STRPIXEL = 0x30; +static constexpr RegAddr REG_ENDPIXEL = 0x32; +static constexpr RegAddr REG_LINCNT = 0x25; +static constexpr RegAddr REG_MAXWD = 0x35; +static constexpr RegAddr REG_LPERIOD = 0x38; +static constexpr RegAddr REG_FEEDL = 0x3d; +static constexpr RegAddr REG_FMOVDEC = 0x5f; +static constexpr RegAddr REG_FSHDEC = 0x69; +static constexpr RegAddr REG_FMOVNO = 0x6a; +static constexpr RegAddr REG_CK1MAP = 0x74; +static constexpr RegAddr REG_CK3MAP = 0x77; +static constexpr RegAddr REG_CK4MAP = 0x7a; + +static constexpr RegAddr REG_0xF8 = 0xf8; +static constexpr RegMask REG_0xF8_MAXSEL = 0xf0; +static constexpr RegShift REG_0xF8_SMAXSEL = 4; +static constexpr RegMask REG_0xF8_MINSEL = 0x0f; + +} // namespace gl846 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL846_REGISTERS_H diff --git a/backend/genesys/gl847.cpp b/backend/genesys/gl847.cpp new file mode 100644 index 0000000..cb0b527 --- /dev/null +++ b/backend/genesys/gl847.cpp @@ -0,0 +1,2140 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "gl847.h" +#include "gl847_registers.h" +#include "test_settings.h" + +#include + +namespace genesys { +namespace gl847 { + +/** + * compute the step multiplier used + */ +static int +gl847_get_step_multiplier (Genesys_Register_Set * regs) +{ + GenesysRegister *r = sanei_genesys_get_address(regs, 0x9d); + int value = 1; + if (r != nullptr) + { + value = (r->value & 0x0f)>>1; + value = 1 << value; + } + DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); + return value; +} + +/** @brief sensor specific settings +*/ +static void gl847_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs) +{ + DBG_HELPER(dbg); + + for (const auto& reg : sensor.custom_regs) { + regs->set8(reg.address, reg.value); + } + + regs->set16(REG_EXPR, sensor.exposure.red); + regs->set16(REG_EXPG, sensor.exposure.green); + regs->set16(REG_EXPB, sensor.exposure.blue); + + dev->segment_order = sensor.segment_order; +} + + +/** @brief set all registers to default values . + * This function is called only once at the beginning and + * fills register startup values for registers reused across scans. + * Those that are rarely modified or not modified are written + * individually. + * @param dev device structure holding register set to initialize + */ +static void +gl847_init_registers (Genesys_Device * dev) +{ + DBG_HELPER(dbg); + int lide700=0; + uint8_t val; + + /* 700F class needs some different initial settings */ + if (dev->model->model_id == ModelId::CANON_LIDE_700F) { + lide700 = 1; + } + + dev->reg.clear(); + + dev->reg.init_reg(0x01, 0x82); + dev->reg.init_reg(0x02, 0x18); + dev->reg.init_reg(0x03, 0x50); + dev->reg.init_reg(0x04, 0x12); + dev->reg.init_reg(0x05, 0x80); + dev->reg.init_reg(0x06, 0x50); // FASTMODE + POWERBIT + dev->reg.init_reg(0x08, 0x10); + dev->reg.init_reg(0x09, 0x01); + dev->reg.init_reg(0x0a, 0x00); + dev->reg.init_reg(0x0b, 0x01); + dev->reg.init_reg(0x0c, 0x02); + + // LED exposures + dev->reg.init_reg(0x10, 0x00); + dev->reg.init_reg(0x11, 0x00); + dev->reg.init_reg(0x12, 0x00); + dev->reg.init_reg(0x13, 0x00); + dev->reg.init_reg(0x14, 0x00); + dev->reg.init_reg(0x15, 0x00); + + dev->reg.init_reg(0x16, 0x10); // SENSOR_DEF + dev->reg.init_reg(0x17, 0x08); // SENSOR_DEF + dev->reg.init_reg(0x18, 0x00); // SENSOR_DEF + + // EXPDMY + dev->reg.init_reg(0x19, 0x50); // SENSOR_DEF + + dev->reg.init_reg(0x1a, 0x34); // SENSOR_DEF + dev->reg.init_reg(0x1b, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x1c, 0x02); // SENSOR_DEF + dev->reg.init_reg(0x1d, 0x04); // SENSOR_DEF + dev->reg.init_reg(0x1e, 0x10); + dev->reg.init_reg(0x1f, 0x04); + dev->reg.init_reg(0x20, 0x02); + dev->reg.init_reg(0x21, 0x10); + dev->reg.init_reg(0x22, 0x7f); + dev->reg.init_reg(0x23, 0x7f); + dev->reg.init_reg(0x24, 0x10); + dev->reg.init_reg(0x25, 0x00); + dev->reg.init_reg(0x26, 0x00); + dev->reg.init_reg(0x27, 0x00); + dev->reg.init_reg(0x2c, 0x09); + dev->reg.init_reg(0x2d, 0x60); + dev->reg.init_reg(0x2e, 0x80); + dev->reg.init_reg(0x2f, 0x80); + dev->reg.init_reg(0x30, 0x00); + dev->reg.init_reg(0x31, 0x10); + dev->reg.init_reg(0x32, 0x15); + dev->reg.init_reg(0x33, 0x0e); + dev->reg.init_reg(0x34, 0x40); + dev->reg.init_reg(0x35, 0x00); + dev->reg.init_reg(0x36, 0x2a); + dev->reg.init_reg(0x37, 0x30); + dev->reg.init_reg(0x38, 0x2a); + dev->reg.init_reg(0x39, 0xf8); + dev->reg.init_reg(0x3d, 0x00); + dev->reg.init_reg(0x3e, 0x00); + dev->reg.init_reg(0x3f, 0x00); + dev->reg.init_reg(0x52, 0x03); // SENSOR_DEF + dev->reg.init_reg(0x53, 0x07); // SENSOR_DEF + dev->reg.init_reg(0x54, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x55, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x56, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x57, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x58, 0x2a); // SENSOR_DEF + dev->reg.init_reg(0x59, 0xe1); // SENSOR_DEF + dev->reg.init_reg(0x5a, 0x55); // SENSOR_DEF + dev->reg.init_reg(0x5e, 0x41); + dev->reg.init_reg(0x5f, 0x40); + dev->reg.init_reg(0x60, 0x00); + dev->reg.init_reg(0x61, 0x21); + dev->reg.init_reg(0x62, 0x40); + dev->reg.init_reg(0x63, 0x00); + dev->reg.init_reg(0x64, 0x21); + dev->reg.init_reg(0x65, 0x40); + dev->reg.init_reg(0x67, 0x80); + dev->reg.init_reg(0x68, 0x80); + dev->reg.init_reg(0x69, 0x20); + dev->reg.init_reg(0x6a, 0x20); + + // CK1MAP + dev->reg.init_reg(0x74, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x75, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x76, 0x3c); // SENSOR_DEF + + // CK3MAP + dev->reg.init_reg(0x77, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x78, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x79, 0x9f); // SENSOR_DEF + + // CK4MAP + dev->reg.init_reg(0x7a, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x7b, 0x00); // SENSOR_DEF + dev->reg.init_reg(0x7c, 0x55); // SENSOR_DEF + + dev->reg.init_reg(0x7d, 0x00); + + // NOTE: autoconf is a non working option + dev->reg.init_reg(0x87, 0x02); + dev->reg.init_reg(0x9d, 0x06); + dev->reg.init_reg(0xa2, 0x0f); + dev->reg.init_reg(0xbd, 0x18); + dev->reg.init_reg(0xfe, 0x08); + + // gamma[0] and gamma[256] values + dev->reg.init_reg(0xbe, 0x00); + dev->reg.init_reg(0xc5, 0x00); + dev->reg.init_reg(0xc6, 0x00); + dev->reg.init_reg(0xc7, 0x00); + dev->reg.init_reg(0xc8, 0x00); + dev->reg.init_reg(0xc9, 0x00); + dev->reg.init_reg(0xca, 0x00); + + /* LiDE 700 fixups */ + if (lide700) { + dev->reg.init_reg(0x5f, 0x04); + dev->reg.init_reg(0x7d, 0x80); + + /* we write to these registers only once */ + val=0; + dev->interface->write_register(REG_0x7E, val); + dev->interface->write_register(REG_0x9E, val); + dev->interface->write_register(REG_0x9F, val); + dev->interface->write_register(REG_0xAB, val); + } + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + sanei_genesys_set_dpihw(dev->reg, sensor, sensor.optical_res); + + /* initalize calibration reg */ + dev->calib_reg = dev->reg; +} + +/**@brief send slope table for motor movement + * Send slope_table in machine byte order + * @param dev device to send slope table + * @param table_nr index of the slope table in ASIC memory + * Must be in the [0-4] range. + * @param slope_table pointer to 16 bit values array of the slope table + * @param steps number of elements in the slope table + */ +static void gl847_send_slope_table(Genesys_Device* dev, int table_nr, + const std::vector& slope_table, + int steps) +{ + DBG_HELPER_ARGS(dbg, "table_nr = %d, steps = %d", table_nr, steps); + int i; + char msg[10000]; + + /* sanity check */ + if(table_nr<0 || table_nr>4) + { + throw SaneException("invalid table number %d", table_nr); + } + + std::vector table(steps * 2); + for (i = 0; i < steps; i++) + { + table[i * 2] = slope_table[i] & 0xff; + table[i * 2 + 1] = slope_table[i] >> 8; + } + + if (DBG_LEVEL >= DBG_io) + { + std::sprintf(msg, "write slope %d (%d)=", table_nr, steps); + for (i = 0; i < steps; i++) + { + std::sprintf(msg + std::strlen(msg), "%d", slope_table[i]); + } + DBG (DBG_io, "%s: %s\n", __func__, msg); + } + + if (dev->interface->is_mock()) { + dev->interface->record_slope_table(table_nr, slope_table); + } + // slope table addresses are fixed + dev->interface->write_ahb(0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); +} + +/** + * Set register values of Analog Device type frontend + * */ +static void gl847_set_ad_fe(Genesys_Device* dev, uint8_t set) +{ + DBG_HELPER(dbg); + int i; + + // wait for FE to be ready + auto status = scanner_read_status(*dev); + while (status.is_front_end_busy) { + dev->interface->sleep_ms(10); + status = scanner_read_status(*dev); + }; + + if (set == AFE_INIT) + { + DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, + static_cast(dev->model->adc_id)); + + dev->frontend = dev->frontend_initial; + } + + // reset DAC + dev->interface->write_fe_register(0x00, 0x80); + + // write them to analog frontend + dev->interface->write_fe_register(0x00, dev->frontend.regs.get_value(0x00)); + + dev->interface->write_fe_register(0x01, dev->frontend.regs.get_value(0x01)); + + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x02 + i, dev->frontend.get_gain(i)); + } + for (i = 0; i < 3; i++) { + dev->interface->write_fe_register(0x05 + i, dev->frontend.get_offset(i)); + } +} + +// Set values of analog frontend +void CommandSetGl847::set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const +{ + DBG_HELPER_ARGS(dbg, "%s", set == AFE_INIT ? "init" : + set == AFE_SET ? "set" : + set == AFE_POWER_SAVE ? "powersave" : "huh?"); + + (void) sensor; + + uint8_t val = dev->interface->read_register(REG_0x04); + uint8_t frontend_type = val & REG_0x04_FESET; + + // route to AD devices + if (frontend_type == 0x02) { + gl847_set_ad_fe(dev, set); + return; + } + + throw SaneException("unsupported frontend type %d", frontend_type); +} + + +// @brief set up motor related register for scan +static void gl847_init_motor_regs_scan(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const Motor_Profile& motor_profile, + unsigned int scan_exposure_time, + unsigned scan_yres, + unsigned int scan_lines, + unsigned int scan_dummy, + unsigned int feed_steps, + MotorFlag flags) +{ + DBG_HELPER_ARGS(dbg, "scan_exposure_time=%d, can_yres=%d, step_type=%d, scan_lines=%d, " + "scan_dummy=%d, feed_steps=%d, flags=%x", + scan_exposure_time, scan_yres, static_cast(motor_profile.step_type), + scan_lines, scan_dummy, feed_steps, static_cast(flags)); + int use_fast_fed; + unsigned int fast_dpi; + unsigned int feedl, dist; + GenesysRegister *r; + uint32_t z1, z2; + unsigned int min_restep = 0x20; + uint8_t val; + unsigned int ccdlmt,tgtime; + + unsigned step_multiplier = gl847_get_step_multiplier (reg); + + use_fast_fed=0; + /* no fast fed since feed works well */ + if (dev->settings.yres==4444 && feed_steps > 100 && (!has_flag(flags, MotorFlag::FEED))) + { + use_fast_fed=1; + } + DBG(DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); + + reg->set24(REG_LINCNT, scan_lines); + DBG(DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); + + /* compute register 02 value */ + r = sanei_genesys_get_address(reg, REG_0x02); + r->value = 0x00; + sanei_genesys_set_motor_power(*reg, true); + + if (use_fast_fed) { + r->value |= REG_0x02_FASTFED; + } else { + r->value &= ~REG_0x02_FASTFED; + } + + if (has_flag(flags, MotorFlag::AUTO_GO_HOME)) { + r->value |= REG_0x02_AGOHOME | REG_0x02_NOTHOME; + } + + if (has_flag(flags, MotorFlag::DISABLE_BUFFER_FULL_MOVE) + ||(scan_yres>=sensor.optical_res)) + { + r->value |= REG_0x02_ACDCDIS; + } + + if (has_flag(flags, MotorFlag::REVERSE)) { + r->value |= REG_0x02_MTRREV; + } else { + r->value &= ~REG_0x02_MTRREV; + } + + /* scan and backtracking slope table */ + auto scan_table = sanei_genesys_slope_table(dev->model->asic_type, scan_yres, + scan_exposure_time, dev->motor.base_ydpi, + step_multiplier, motor_profile); + gl847_send_slope_table(dev, SCAN_TABLE, scan_table.table, scan_table.steps_count); + gl847_send_slope_table(dev, BACKTRACK_TABLE, scan_table.table, scan_table.steps_count); + + /* fast table */ + fast_dpi=sanei_genesys_get_lowest_ydpi(dev); + StepType fast_step_type = motor_profile.step_type; + if (static_cast(motor_profile.step_type) >= static_cast(StepType::QUARTER)) { + fast_step_type = StepType::QUARTER; + } + + Motor_Profile fast_motor_profile = motor_profile; + fast_motor_profile.step_type = fast_step_type; + + auto fast_table = sanei_genesys_slope_table(dev->model->asic_type, fast_dpi, + scan_exposure_time, dev->motor.base_ydpi, + step_multiplier, fast_motor_profile); + + gl847_send_slope_table(dev, STOP_TABLE, fast_table.table, fast_table.steps_count); + gl847_send_slope_table(dev, FAST_TABLE, fast_table.table, fast_table.steps_count); + gl847_send_slope_table(dev, HOME_TABLE, fast_table.table, fast_table.steps_count); + + /* correct move distance by acceleration and deceleration amounts */ + feedl=feed_steps; + if (use_fast_fed) + { + feedl <<= static_cast(fast_step_type); + dist = (scan_table.steps_count + 2 * fast_table.steps_count); + /* TODO read and decode REG_0xAB */ + r = sanei_genesys_get_address (reg, 0x5e); + dist += (r->value & 31); + /* FEDCNT */ + r = sanei_genesys_get_address (reg, REG_FEDCNT); + dist += r->value; + } + else + { + feedl <<= static_cast(motor_profile.step_type); + dist = scan_table.steps_count; + if (has_flag(flags, MotorFlag::FEED)) { + dist *= 2; + } + } + DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); + + /* check for overflow */ + if (dist < feedl) { + feedl -= dist; + } else { + feedl = 0; + } + + reg->set24(REG_FEEDL, feedl); + DBG(DBG_io ,"%s: feedl=%d\n", __func__, feedl); + + r = sanei_genesys_get_address(reg, REG_0x0C); + ccdlmt = (r->value & REG_0x0C_CCDLMT) + 1; + + r = sanei_genesys_get_address(reg, REG_0x1C); + tgtime = 1<<(r->value & REG_0x1C_TGTIME); + + // hi res motor speed GPIO + uint8_t effective = dev->interface->read_register(REG_0x6C); + + // if quarter step, bipolar Vref2 + + if (motor_profile.step_type == StepType::QUARTER) { + val = effective & ~REG_0x6C_GPIO13; + } else if (static_cast(motor_profile.step_type) > static_cast(StepType::QUARTER)) { + val = effective | REG_0x6C_GPIO13; + } else { + val = effective; + } + dev->interface->write_register(REG_0x6C, val); + + // effective scan + effective = dev->interface->read_register(REG_0x6C); + val = effective | REG_0x6C_GPIO10; + dev->interface->write_register(REG_0x6C, val); + + min_restep = scan_table.steps_count / (2 * step_multiplier) - 1; + if (min_restep < 1) { + min_restep = 1; + } + r = sanei_genesys_get_address(reg, REG_FWDSTEP); + r->value = min_restep; + r = sanei_genesys_get_address(reg, REG_BWDSTEP); + r->value = min_restep; + + sanei_genesys_calculate_zmod(use_fast_fed, + scan_exposure_time*ccdlmt*tgtime, + scan_table.table, + scan_table.steps_count, + feedl, + min_restep * step_multiplier, + &z1, + &z2); + + DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); + reg->set24(REG_0x60, z1 | (static_cast(motor_profile.step_type) << (16+REG_0x60S_STEPSEL))); + + DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); + reg->set24(REG_0x63, z2 | (static_cast(motor_profile.step_type) << (16+REG_0x63S_FSTPSEL))); + + r = sanei_genesys_get_address (reg, 0x1e); + r->value &= 0xf0; /* 0 dummy lines */ + r->value |= scan_dummy; /* dummy lines */ + + r = sanei_genesys_get_address(reg, REG_0x67); + r->value = REG_0x67_MTRPWM; + + r = sanei_genesys_get_address(reg, REG_0x68); + r->value = REG_0x68_FASTPWM; + + reg->set8(REG_STEPNO, scan_table.steps_count / step_multiplier); + reg->set8(REG_FASTNO, scan_table.steps_count / step_multiplier); + reg->set8(REG_FSHDEC, scan_table.steps_count / step_multiplier); + reg->set8(REG_FMOVNO, fast_table.steps_count / step_multiplier); + reg->set8(REG_FMOVDEC, fast_table.steps_count / step_multiplier); +} + + +/** @brief set up registers related to sensor + * Set up the following registers + 0x01 + 0x03 + 0x10-0x015 R/G/B exposures + 0x19 EXPDMY + 0x2e BWHI + 0x2f BWLO + 0x04 + 0x87 + 0x05 + 0x2c,0x2d DPISET + 0x30,0x31 STRPIXEL + 0x32,0x33 ENDPIXEL + 0x35,0x36,0x37 MAXWD [25:2] (>>2) + 0x38,0x39 LPERIOD + 0x34 DUMMY + */ +static void gl847_init_optical_regs_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, unsigned int exposure_time, + const ScanSession& session) +{ + DBG_HELPER_ARGS(dbg, "exposure_time=%d", exposure_time); + unsigned dpihw; + GenesysRegister *r; + + // resolution is divided according to ccd_pixels_per_system_pixel() + unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel(); + DBG(DBG_io2, "%s: ccd_pixels_per_system_pixel=%d\n", __func__, ccd_pixels_per_system_pixel); + + // to manage high resolution device while keeping good low resolution scanning speed, we make + // hardware dpi vary + dpihw = sensor.get_register_hwdpi(session.params.xres * ccd_pixels_per_system_pixel); + DBG(DBG_io2, "%s: dpihw=%d\n", __func__, dpihw); + + gl847_setup_sensor(dev, sensor, reg); + + dev->cmd_set->set_fe(dev, sensor, AFE_SET); + + /* enable shading */ + regs_set_optical_off(dev->model->asic_type, *reg); + r = sanei_genesys_get_address(reg, REG_0x01); + r->value |= REG_0x01_SHDAREA; + + if (has_flag(session.params.flags, ScanFlag::DISABLE_SHADING) || + (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + r->value &= ~REG_0x01_DVDSET; + } + else + { + r->value |= REG_0x01_DVDSET; + } + + r = sanei_genesys_get_address (reg, REG_0x03); + r->value &= ~REG_0x03_AVEENB; + + sanei_genesys_set_lamp_power(dev, sensor, *reg, + !has_flag(session.params.flags, ScanFlag::DISABLE_LAMP)); + + /* BW threshold */ + r = sanei_genesys_get_address (reg, 0x2e); + r->value = dev->settings.threshold; + r = sanei_genesys_get_address (reg, 0x2f); + r->value = dev->settings.threshold; + + /* monochrome / color scan */ + r = sanei_genesys_get_address (reg, REG_0x04); + switch (session.params.depth) { + case 8: + r->value &= ~(REG_0x04_LINEART | REG_0x04_BITSET); + break; + case 16: + r->value &= ~REG_0x04_LINEART; + r->value |= REG_0x04_BITSET; + break; + } + + r->value &= ~(REG_0x04_FILTER | REG_0x04_AFEMOD); + if (session.params.channels == 1) + { + switch (session.params.color_filter) + { + + case ColorFilter::RED: + r->value |= 0x14; + break; + case ColorFilter::BLUE: + r->value |= 0x1c; + break; + case ColorFilter::GREEN: + r->value |= 0x18; + break; + default: + break; // should not happen + } + } else { + r->value |= 0x10; // mono + } + + sanei_genesys_set_dpihw(*reg, sensor, dpihw); + + if (should_enable_gamma(session, sensor)) { + reg->find_reg(REG_0x05).value |= REG_0x05_GMMENB; + } else { + reg->find_reg(REG_0x05).value &= ~REG_0x05_GMMENB; + } + + /* CIS scanners can do true gray by setting LEDADD */ + /* we set up LEDADD only when asked */ + if (dev->model->is_cis) { + r = sanei_genesys_get_address (reg, 0x87); + r->value &= ~REG_0x87_LEDADD; + if (session.enable_ledadd) { + r->value |= REG_0x87_LEDADD; + } + /* RGB weighting + r = sanei_genesys_get_address (reg, 0x01); + r->value &= ~REG_0x01_TRUEGRAY; + if (session.enable_ledadd) { + r->value |= REG_0x01_TRUEGRAY; + } + */ + } + + unsigned dpiset = session.params.xres * ccd_pixels_per_system_pixel; + reg->set16(REG_DPISET, dpiset); + DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); + + reg->set16(REG_STRPIXEL, session.pixel_startx); + reg->set16(REG_ENDPIXEL, session.pixel_endx); + + build_image_pipeline(dev, session); + + /* MAXWD is expressed in 4 words unit */ + // BUG: we shouldn't multiply by channels here + reg->set24(REG_MAXWD, (session.output_line_bytes_raw * session.params.channels >> 2)); + + reg->set16(REG_LPERIOD, exposure_time); + DBG(DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); + + r = sanei_genesys_get_address (reg, 0x34); + r->value = sensor.dummy_pixel; +} + +void CommandSetGl847::init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const +{ + DBG_HELPER(dbg); + session.assert_computed(); + + int move; + int exposure_time; + + int slope_dpi = 0; + int dummy = 0; + + dummy = 3 - session.params.channels; + +/* slope_dpi */ +/* cis color scan is effectively a gray scan with 3 gray lines per color + line and a FILTER of 0 */ + if (dev->model->is_cis) { + slope_dpi = session.params.yres * session.params.channels; + } else { + slope_dpi = session.params.yres; + } + + slope_dpi = slope_dpi * (1 + dummy); + + exposure_time = sensor.exposure_lperiod; + const auto& motor_profile = sanei_genesys_get_motor_profile(*gl847_motor_profiles, + dev->model->motor_id, + exposure_time); + + DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); + DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, + static_cast(motor_profile.step_type)); + + /* we enable true gray for cis scanners only, and just when doing + * scan since color calibration is OK for this mode + */ + gl847_init_optical_regs_scan(dev, sensor, reg, exposure_time, session); + + move = session.params.starty; + DBG(DBG_info, "%s: move=%d steps\n", __func__, move); + + MotorFlag mflags = MotorFlag::NONE; + if (has_flag(session.params.flags, ScanFlag::DISABLE_BUFFER_FULL_MOVE)) { + mflags |= MotorFlag::DISABLE_BUFFER_FULL_MOVE; + } + if (has_flag(session.params.flags, ScanFlag::FEEDING)) { + mflags |= MotorFlag::FEED; + } + if (has_flag(session.params.flags, ScanFlag::REVERSE)) { + mflags |= MotorFlag::REVERSE; + } + + gl847_init_motor_regs_scan(dev, sensor, reg, motor_profile, exposure_time, slope_dpi, + dev->model->is_cis ? session.output_line_count * session.params.channels + : session.output_line_count, + dummy, move, mflags); + + dev->read_buffer.clear(); + dev->read_buffer.alloc(session.buffer_size_read); + + dev->read_active = true; + + dev->session = session; + + dev->total_bytes_read = 0; + dev->total_bytes_to_read = session.output_line_bytes_requested * session.params.lines; + + DBG(DBG_info, "%s: total bytes to send = %zu\n", __func__, dev->total_bytes_to_read); +} + +ScanSession CommandSetGl847::calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const +{ + int start; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, settings); + + /* start */ + start = static_cast(dev->model->x_offset); + start = static_cast(start + settings.tl_x); + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = settings.xres; + session.params.yres = settings.yres; + session.params.startx = start; // not used + session.params.starty = 0; // not used + session.params.pixels = settings.pixels; + session.params.requested_pixels = settings.requested_pixels; + session.params.lines = settings.lines; + session.params.depth = settings.depth; + session.params.channels = settings.get_channels(); + session.params.scan_method = settings.scan_method; + session.params.scan_mode = settings.scan_mode; + session.params.color_filter = settings.color_filter; + session.params.flags = ScanFlag::NONE; + + compute_session(dev, session, sensor); + + return session; +} + +// for fast power saving methods only, like disabling certain amplifiers +void CommandSetGl847::save_power(Genesys_Device* dev, bool enable) const +{ + DBG_HELPER_ARGS(dbg, "enable = %d", enable); + (void) dev; +} + +void CommandSetGl847::set_powersaving(Genesys_Device* dev, int delay /* in minutes */) const +{ + (void) dev; + DBG_HELPER_ARGS(dbg, "delay = %d", delay); +} + +// Send the low-level scan command +void CommandSetGl847::begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, bool start_motor) const +{ + DBG_HELPER(dbg); + (void) sensor; + uint8_t val; + GenesysRegister *r; + + // clear GPIO 10 + if (dev->model->gpio_id != GpioId::CANON_LIDE_700F) { + val = dev->interface->read_register(REG_0x6C); + val &= ~REG_0x6C_GPIO10; + dev->interface->write_register(REG_0x6C, val); + } + + val = REG_0x0D_CLRLNCNT; + dev->interface->write_register(REG_0x0D, val); + val = REG_0x0D_CLRMCNT; + dev->interface->write_register(REG_0x0D, val); + + val = dev->interface->read_register(REG_0x01); + val |= REG_0x01_SCAN; + dev->interface->write_register(REG_0x01, val); + r = sanei_genesys_get_address (reg, REG_0x01); + r->value = val; + + scanner_start_action(*dev, start_motor); + + dev->advance_head_pos_by_session(ScanHeadId::PRIMARY); +} + + +// Send the stop scan command +void CommandSetGl847::end_scan(Genesys_Device* dev, Genesys_Register_Set* reg, + bool check_stop) const +{ + (void) reg; + DBG_HELPER_ARGS(dbg, "check_stop = %d", check_stop); + + if (!dev->model->is_sheetfed) { + scanner_stop_action(*dev); + } +} + +/** Park head + * Moves the slider to the home (top) position slowly + * @param dev device to park + * @param wait_until_home true to make the function waiting for head + * to be home before returning, if fals returne immediately +*/ +void CommandSetGl847::move_back_home(Genesys_Device* dev, bool wait_until_home) const +{ + scanner_move_back_home(*dev, wait_until_home); +} + +// Automatically set top-left edge of the scan area by scanning a 200x200 pixels area at 600 dpi +// from very top of scanner +void CommandSetGl847::search_start_position(Genesys_Device* dev) const +{ + DBG_HELPER(dbg); + int size; + Genesys_Register_Set local_reg; + + int pixels = 600; + int dpi = 300; + + local_reg = dev->reg; + + /* sets for a 200 lines * 600 pixels */ + /* normal scan with no shading */ + + // FIXME: the current approach of doing search only for one resolution does not work on scanners + // whith employ different sensors with potentially different settings. + const auto& sensor = sanei_genesys_find_sensor(dev, dpi, 1, dev->model->default_method); + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; /*we should give a small offset here~60 steps */ + session.params.pixels = 600; + session.params.lines = dev->model->search_lines; + session.params.depth = 8; + session.params.channels = 1; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::GREEN; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &local_reg, session); + + // send to scanner + dev->interface->write_registers(local_reg); + + size = pixels * dev->model->search_lines; + + std::vector data(size); + + begin_scan(dev, sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_start_position"); + end_scan(dev, &local_reg, true); + dev->reg = local_reg; + return; + } + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl847_search_position.pnm", data.data(), 8, 1, pixels, + dev->model->search_lines); + } + + end_scan(dev, &local_reg, true); + + /* update regs to copy ASIC internal state */ + dev->reg = local_reg; + + // TODO: find out where sanei_genesys_search_reference_point stores information, + // and use that correctly + for (auto& sensor_update : + sanei_genesys_find_sensors_all_for_write(dev, dev->model->default_method)) + { + sanei_genesys_search_reference_point(dev, sensor_update, data.data(), 0, dpi, pixels, + dev->model->search_lines); + } +} + +// sets up register for coarse gain calibration +// todo: check it for scanners using it +void CommandSetGl847::init_regs_for_coarse_calibration(Genesys_Device* dev, + const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = sensor.optical_res / sensor.ccd_pixels_per_system_pixel(); + session.params.lines = 20; + session.params.depth = 16; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, ®s, session); + + DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, + sensor.optical_res / sensor.ccd_pixels_per_system_pixel(), dev->settings.xres); + + dev->interface->write_registers(regs); +} + +// init registers for shading calibration +void CommandSetGl847::init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + + dev->calib_channels = 3; + + /* initial calibration reg values */ + regs = dev->reg; + + dev->calib_resolution = sensor.get_register_hwdpi(dev->settings.xres); + + const auto& calib_sensor = sanei_genesys_find_sensor(dev, dev->calib_resolution, + dev->calib_channels, + dev->settings.scan_method); + + dev->calib_total_bytes_to_read = 0; + dev->calib_lines = dev->model->shading_lines; + if (dev->calib_resolution == 4800) { + dev->calib_lines *= 2; + } + dev->calib_pixels = (calib_sensor.sensor_pixels * dev->calib_resolution) / + calib_sensor.optical_res; + + DBG(DBG_io, "%s: calib_lines = %zu\n", __func__, dev->calib_lines); + DBG(DBG_io, "%s: calib_pixels = %zu\n", __func__, dev->calib_pixels); + + ScanSession session; + session.params.xres = dev->calib_resolution; + session.params.yres = dev->motor.base_ydpi; + session.params.startx = 0; + session.params.starty = 20; + session.params.pixels = dev->calib_pixels; + session.params.lines = dev->calib_lines; + session.params.depth = 16; + session.params.channels = dev->calib_channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::DISABLE_BUFFER_FULL_MOVE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + dev->interface->write_registers(regs); + + /* we use GENESYS_FLAG_SHADING_REPARK */ + dev->set_head_pos_zero(ScanHeadId::PRIMARY); +} + +/** @brief set up registers for the actual scan + */ +void CommandSetGl847::init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + DBG_HELPER(dbg); + float move; + int move_dpi; + float start; + + debug_dump(DBG_info, dev->settings); + + /* steps to move to reach scanning area: + - first we move to physical start of scanning + either by a fixed steps amount from the black strip + or by a fixed amount from parking position, + minus the steps done during shading calibration + - then we move by the needed offset whitin physical + scanning area + + assumption: steps are expressed at maximum motor resolution + + we need: + float y_offset; + float y_size; + float y_offset_calib; + mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ + + /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is + relative from origin, else, it is from parking position */ + + move_dpi = dev->motor.base_ydpi; + + move = static_cast(dev->model->y_offset); + move = static_cast(move + dev->settings.tl_y); + move = static_cast((move * move_dpi) / MM_PER_INCH); + move -= dev->head_pos(ScanHeadId::PRIMARY); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* fast move to scan area */ + /* we don't move fast the whole distance since it would involve + * computing acceleration/deceleration distance for scan + * resolution. So leave a remainder for it so scan makes the final + * move tuning */ + if (dev->settings.get_channels() * dev->settings.yres >= 600 && move > 700) { + scanner_move(*dev, dev->model->default_method, static_cast(move - 500), + Direction::FORWARD); + move=500; + } + + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + DBG(DBG_info, "%s: move=%f steps\n", __func__, move); + + /* start */ + start = static_cast(dev->model->x_offset); + start = static_cast(start + dev->settings.tl_x); + start = static_cast((start * sensor.optical_res) / MM_PER_INCH); + + ScanSession session; + session.params.xres = dev->settings.xres; + session.params.yres = dev->settings.yres; + session.params.startx = static_cast(start); + session.params.starty = static_cast(move); + session.params.pixels = dev->settings.pixels; + session.params.requested_pixels = dev->settings.requested_pixels; + session.params.lines = dev->settings.lines; + session.params.depth = dev->settings.depth; + session.params.channels = dev->settings.get_channels(); + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = dev->settings.scan_mode; + session.params.color_filter = dev->settings.color_filter; + // backtracking isn't handled well, so don't enable it + session.params.flags = ScanFlag::DISABLE_BUFFER_FULL_MOVE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, &dev->reg, session); +} + + +/** + * Send shading calibration data. The buffer is considered to always hold values + * for all the channels. + */ +void CommandSetGl847::send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + uint8_t* data, int size) const +{ + DBG_HELPER_ARGS(dbg, "writing %d bytes of shading data", size); + uint32_t addr, length, i, x, factor, pixels; + uint32_t dpiset, dpihw; + uint8_t val,*ptr,*src; + + /* shading data is plit in 3 (up to 5 with IR) areas + write(0x10014000,0x00000dd8) + URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x.... + write(0x1003e000,0x00000dd8) + write(0x10068000,0x00000dd8) + */ + length = static_cast(size / 3); + std::uint32_t strpixel = dev->session.pixel_startx; + std::uint32_t endpixel = dev->session.pixel_endx; + + /* compute deletion factor */ + dpiset = dev->reg.get16(REG_DPISET); + dpihw = sensor.get_register_hwdpi(dpiset); + factor=dpihw/dpiset; + DBG(DBG_io2, "%s: factor=%d\n", __func__, factor); + + pixels=endpixel-strpixel; + + /* since we're using SHDAREA, substract startx coordinate from shading */ + strpixel -= (sensor.ccd_start_xoffset * 600) / sensor.optical_res; + + /* turn pixel value into bytes 2x16 bits words */ + strpixel*=2*2; + pixels*=2*2; + + dev->interface->record_key_value("shading_offset", std::to_string(strpixel)); + dev->interface->record_key_value("shading_pixels", std::to_string(pixels)); + dev->interface->record_key_value("shading_length", std::to_string(length)); + dev->interface->record_key_value("shading_factor", std::to_string(factor)); + + std::vector buffer(pixels, 0); + + DBG(DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n", __func__, pixels, pixels); + + /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address + * is 8192*reg value */ + + /* write actual color channel data */ + for(i=0;i<3;i++) + { + /* build up actual shading data by copying the part from the full width one + * to the one corresponding to SHDAREA */ + ptr = buffer.data(); + + /* iterate on both sensor segment */ + for(x=0;xinterface->read_register(0xd0+i); + addr = val * 8192 + 0x10000000; + dev->interface->write_ahb(addr, pixels, buffer.data()); + } +} + +/** @brief calibrates led exposure + * Calibrate exposure by scanning a white area until the used exposure gives + * data white enough. + * @param dev device to calibrate + */ +SensorExposure CommandSetGl847::led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + int num_pixels; + int total_size; + int used_res; + int i, j; + int val; + int channels; + int avg[3], top[3], bottom[3]; + int turn; + uint16_t exp[3]; + float move; + + move = static_cast(dev->model->y_offset_calib_white); + move = static_cast((move * (dev->motor.base_ydpi / 4)) / MM_PER_INCH); + if (move > 20) { + scanner_move(*dev, dev->model->default_method, static_cast(move), + Direction::FORWARD); + } + DBG(DBG_io, "%s: move=%f steps\n", __func__, move); + + /* offset calibration is always done in color mode */ + channels = 3; + used_res = sensor.get_register_hwdpi(dev->settings.xres); + const auto& calib_sensor = sanei_genesys_find_sensor(dev, used_res, channels, + dev->settings.scan_method); + num_pixels = (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res; + + /* initial calibration reg values */ + regs = dev->reg; + + ScanSession session; + session.params.xres = used_res; + session.params.yres = used_res; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = num_pixels; + session.params.lines = 1; + session.params.depth = 16; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, calib_sensor); + + init_regs_for_scan_session(dev, calib_sensor, ®s, session); + + total_size = num_pixels * channels * (session.params.depth/8) * 1; + std::vector line(total_size); + + // initial loop values and boundaries + exp[0] = calib_sensor.exposure.red; + exp[1] = calib_sensor.exposure.green; + exp[2] = calib_sensor.exposure.blue; + + bottom[0] = 28000; + bottom[1] = 28000; + bottom[2] = 28000; + + top[0] = 32000; + top[1] = 32000; + top[2] = 32000; + + turn = 0; + + /* no move during led calibration */ + bool acceptable = false; + sanei_genesys_set_motor_power(regs, false); + do + { + // set up exposure + regs.set16(REG_EXPR,exp[0]); + regs.set16(REG_EXPG,exp[1]); + regs.set16(REG_EXPB,exp[2]); + + // write registers and scan data + dev->interface->write_registers(regs); + + DBG(DBG_info, "%s: starting line reading\n", __func__); + begin_scan(dev, calib_sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("led_calibration"); + scanner_stop_action(*dev); + move_back_home(dev, true); + return calib_sensor.exposure; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + + // stop scanning + scanner_stop_action(*dev); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl847_led_%02d.pnm", turn); + sanei_genesys_write_pnm_file(fn, line.data(), session.params.depth, + channels, num_pixels, 1); + } + + /* compute average */ + for (j = 0; j < channels; j++) + { + avg[j] = 0; + for (i = 0; i < num_pixels; i++) + { + if (dev->model->is_cis) + val = + line[i * 2 + j * 2 * num_pixels + 1] * 256 + + line[i * 2 + j * 2 * num_pixels]; + else + val = + line[i * 2 * channels + 2 * j + 1] * 256 + + line[i * 2 * channels + 2 * j]; + avg[j] += val; + } + + avg[j] /= num_pixels; + } + + DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); + + /* check if exposure gives average within the boundaries */ + acceptable = true; + for(i=0;i<3;i++) + { + if (avg[i] < bottom[i] || avg[i] > top[i]) { + auto target = (bottom[i] + top[i]) / 2; + exp[i] = (exp[i] * target) / avg[i]; + acceptable = false; + } + } + + turn++; + } + while (!acceptable && turn < 100); + + DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); + + // set these values as final ones for scan + dev->reg.set16(REG_EXPR, exp[0]); + dev->reg.set16(REG_EXPG, exp[1]); + dev->reg.set16(REG_EXPB, exp[2]); + + // go back home + if (move>20) { + move_back_home(dev, true); + } + + return { exp[0], exp[1], exp[2] }; +} + +/** + * set up GPIO/GPOE for idle state + */ +static void gl847_init_gpio(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + int idx=0; + + /* search GPIO profile */ + while(gpios[idx].gpio_id != GpioId::UNKNOWN && dev->model->gpio_id != gpios[idx].gpio_id) { + idx++; + } + if (gpios[idx].gpio_id == GpioId::UNKNOWN) { + throw SaneException("failed to find GPIO profile for sensor_id=%d", + static_cast(dev->model->sensor_id)); + } + + dev->interface->write_register(REG_0xA7, gpios[idx].ra7); + dev->interface->write_register(REG_0xA6, gpios[idx].ra6); + + dev->interface->write_register(REG_0x6E, gpios[idx].r6e); + dev->interface->write_register(REG_0x6C, 0x00); + + dev->interface->write_register(REG_0x6B, gpios[idx].r6b); + dev->interface->write_register(REG_0x6C, gpios[idx].r6c); + dev->interface->write_register(REG_0x6D, gpios[idx].r6d); + dev->interface->write_register(REG_0x6E, gpios[idx].r6e); + dev->interface->write_register(REG_0x6F, gpios[idx].r6f); + + dev->interface->write_register(REG_0xA8, gpios[idx].ra8); + dev->interface->write_register(REG_0xA9, gpios[idx].ra9); +} + +/** + * set memory layout by filling values in dedicated registers + */ +static void gl847_init_memory_layout(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + int idx = 0; + uint8_t val; + + /* point to per model memory layout */ + idx = 0; + if (dev->model->model_id == ModelId::CANON_LIDE_100) { + idx = 0; + } + if (dev->model->model_id == ModelId::CANON_LIDE_200) { + idx = 1; + } + if (dev->model->model_id == ModelId::CANON_5600F) { + idx = 2; + } + if (dev->model->model_id == ModelId::CANON_LIDE_700F) { + idx = 3; + } + + /* CLKSET nd DRAMSEL */ + val = layouts[idx].dramsel; + dev->interface->write_register(REG_0x0B, val); + dev->reg.find_reg(0x0b).value = val; + + /* prevent further writings by bulk write register */ + dev->reg.remove_reg(0x0b); + + /* setup base address for shading data. */ + /* values must be multiplied by 8192=0x4000 to give address on AHB */ + /* R-Channel shading bank0 address setting for CIS */ + dev->interface->write_register(0xd0, layouts[idx].rd0); + /* G-Channel shading bank0 address setting for CIS */ + dev->interface->write_register(0xd1, layouts[idx].rd1); + /* B-Channel shading bank0 address setting for CIS */ + dev->interface->write_register(0xd2, layouts[idx].rd2); + + /* setup base address for scanned data. */ + /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ + /* R-Channel ODD image buffer 0x0124->0x92000 */ + /* size for each buffer is 0x16d*1k word */ + dev->interface->write_register(0xe0, layouts[idx].re0); + dev->interface->write_register(0xe1, layouts[idx].re1); + /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ + dev->interface->write_register(0xe2, layouts[idx].re2); + dev->interface->write_register(0xe3, layouts[idx].re3); + + /* R-Channel EVEN image buffer 0x0292 */ + dev->interface->write_register(0xe4, layouts[idx].re4); + dev->interface->write_register(0xe5, layouts[idx].re5); + /* R-Channel EVEN image buffer end-address 0x03ff*/ + dev->interface->write_register(0xe6, layouts[idx].re6); + dev->interface->write_register(0xe7, layouts[idx].re7); + + /* same for green, since CIS, same addresses */ + dev->interface->write_register(0xe8, layouts[idx].re0); + dev->interface->write_register(0xe9, layouts[idx].re1); + dev->interface->write_register(0xea, layouts[idx].re2); + dev->interface->write_register(0xeb, layouts[idx].re3); + dev->interface->write_register(0xec, layouts[idx].re4); + dev->interface->write_register(0xed, layouts[idx].re5); + dev->interface->write_register(0xee, layouts[idx].re6); + dev->interface->write_register(0xef, layouts[idx].re7); + +/* same for blue, since CIS, same addresses */ + dev->interface->write_register(0xf0, layouts[idx].re0); + dev->interface->write_register(0xf1, layouts[idx].re1); + dev->interface->write_register(0xf2, layouts[idx].re2); + dev->interface->write_register(0xf3, layouts[idx].re3); + dev->interface->write_register(0xf4, layouts[idx].re4); + dev->interface->write_register(0xf5, layouts[idx].re5); + dev->interface->write_register(0xf6, layouts[idx].re6); + dev->interface->write_register(0xf7, layouts[idx].re7); +} + +/* * + * initialize ASIC from power on condition + */ +void CommandSetGl847::asic_boot(Genesys_Device* dev, bool cold) const +{ + DBG_HELPER(dbg); + + // reset ASIC if cold boot + if (cold) { + dev->interface->write_register(0x0e, 0x01); + dev->interface->write_register(0x0e, 0x00); + } + + // test CHKVER + uint8_t val = dev->interface->read_register(REG_0x40); + if (val & REG_0x40_CHKVER) { + val = dev->interface->read_register(0x00); + DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); + } + + /* Set default values for registers */ + gl847_init_registers (dev); + + // Write initial registers + dev->interface->write_registers(dev->reg); + + /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ + val = dev->reg.find_reg(0x0b).value & REG_0x0B_DRAMSEL; + val = (val | REG_0x0B_ENBDRAM); + dev->interface->write_register(REG_0x0B, val); + dev->reg.find_reg(0x0b).value = val; + + /* CIS_LINE */ + dev->reg.init_reg(0x08, REG_0x08_CIS_LINE); + dev->interface->write_register(0x08, dev->reg.find_reg(0x08).value); + + // set up end access + dev->interface->write_0x8c(0x10, 0x0b); + dev->interface->write_0x8c(0x13, 0x0e); + + // setup gpio + gl847_init_gpio(dev); + + // setup internal memory layout + gl847_init_memory_layout (dev); + + dev->reg.init_reg(0xf8, 0x01); + dev->interface->write_register(0xf8, dev->reg.find_reg(0xf8).value); +} + +/** + * initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home + */ +void CommandSetGl847::init(Genesys_Device* dev) const +{ + DBG_INIT (); + DBG_HELPER(dbg); + + sanei_genesys_asic_init(dev, 0); +} + +void CommandSetGl847::update_hardware_sensors(Genesys_Scanner* s) const +{ + DBG_HELPER(dbg); + /* do what is needed to get a new set of events, but try to not lose + any of them. + */ + uint8_t val; + uint8_t scan, file, email, copy; + switch(s->dev->model->gpio_id) { + case GpioId::CANON_LIDE_700F: + scan=0x04; + file=0x02; + email=0x01; + copy=0x08; + break; + default: + scan=0x01; + file=0x02; + email=0x04; + copy=0x08; + } + val = s->dev->interface->read_register(REG_0x6D); + + s->buttons[BUTTON_SCAN_SW].write((val & scan) == 0); + s->buttons[BUTTON_FILE_SW].write((val & file) == 0); + s->buttons[BUTTON_EMAIL_SW].write((val & email) == 0); + s->buttons[BUTTON_COPY_SW].write((val & copy) == 0); +} + +void CommandSetGl847::update_home_sensor_gpio(Genesys_Device& dev) const +{ + DBG_HELPER(dbg); + + if (dev.model->gpio_id == GpioId::CANON_LIDE_700F) { + std::uint8_t val = dev.interface->read_register(REG_0x6C); + val &= ~REG_0x6C_GPIO10; + dev.interface->write_register(REG_0x6C, val); + } else { + std::uint8_t val = dev.interface->read_register(REG_0x6C); + val |= REG_0x6C_GPIO10; + dev.interface->write_register(REG_0x6C, val); + } +} + +/** @brief search for a full width black or white strip. + * This function searches for a black or white stripe across the scanning area. + * When searching backward, the searched area must completely be of the desired + * color since this area will be used for calibration which scans forward. + * @param dev scanner device + * @param forward true if searching forward, false if searching backward + * @param black true if searching for a black strip, false for a white strip + */ +void CommandSetGl847::search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, bool forward, + bool black) const +{ + DBG_HELPER_ARGS(dbg, "%s %s", black ? "black" : "white", forward ? "forward" : "reverse"); + unsigned int pixels, lines, channels; + Genesys_Register_Set local_reg; + size_t size; + unsigned int pass, count, found, x, y; + char title[80]; + + set_fe(dev, sensor, AFE_SET); + scanner_stop_action(*dev); + + // set up for a gray scan at lowest dpi + const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method); + unsigned dpi = resolution_settings.get_min_resolution_x(); + channels = 1; + /* 10 MM */ + /* lines = (10 * dpi) / MM_PER_INCH; */ + /* shading calibation is done with dev->motor.base_ydpi */ + lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; + pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + + local_reg = dev->reg; + + ScanSession session; + session.params.xres = dpi; + session.params.yres = dpi; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::GRAY; + session.params.color_filter = ColorFilter::RED; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA; + if (!forward) { + session.params.flags |= ScanFlag::REVERSE; + } + compute_session(dev, session, sensor); + + size = pixels * channels * lines * (session.params.depth / 8); + std::vector data(size); + + init_regs_for_scan_session(dev, sensor, &local_reg, session); + + dev->interface->write_registers(local_reg); + + begin_scan(dev, sensor, &local_reg, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("search_strip"); + scanner_stop_action(*dev); + return; + } + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + scanner_stop_action(*dev); + + pass = 0; + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl847_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", forward ? "fwd" : "bwd", pass); + sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, + channels, pixels, lines); + } + + /* loop until strip is found or maximum pass number done */ + found = 0; + while (pass < 20 && !found) + { + dev->interface->write_registers(local_reg); + + // now start scan + begin_scan(dev, sensor, &local_reg, true); + + wait_until_buffer_non_empty(dev); + + // now we're on target, we can read data + sanei_genesys_read_data_from_scanner(dev, data.data(), size); + + scanner_stop_action(*dev); + + if (DBG_LEVEL >= DBG_data) + { + std::sprintf(title, "gl847_search_strip_%s_%s%02d.pnm", + black ? "black" : "white", + forward ? "fwd" : "bwd", static_cast(pass)); + sanei_genesys_write_pnm_file(title, data.data(), session.params.depth, + channels, pixels, lines); + } + + /* search data to find black strip */ + /* when searching forward, we only need one line of the searched color since we + * will scan forward. But when doing backward search, we need all the area of the + * same color */ + if (forward) + { + for (y = 0; y < lines && !found; y++) + { + count = 0; + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + + /* at end of line, if count >= 3%, line is not fully of the desired color + * so we must go to next line of the buffer */ + /* count*100/pixels < 3 */ + if ((count * 100) / pixels < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, + pass, y); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + } + else /* since calibration scans are done forward, we need the whole area + to be of the required color when searching backward */ + { + count = 0; + for (y = 0; y < lines; y++) + { + /* count of white/black pixels depending on the color searched */ + for (x = 0; x < pixels; x++) + { + /* when searching for black, detect white pixels */ + if (black && data[y * pixels + x] > 90) + { + count++; + } + /* when searching for white, detect black pixels */ + if (!black && data[y * pixels + x] < 60) + { + count++; + } + } + } + + /* at end of area, if count >= 3%, area is not fully of the desired color + * so we must go to next buffer */ + if ((count * 100) / (pixels * lines) < 3) + { + found = 1; + DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); + } + else + { + DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, + (100 * count) / pixels); + } + } + pass++; + } + + if (found) + { + DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); + } + else + { + throw SaneException(SANE_STATUS_UNSUPPORTED, "%s strip not found", black ? "black" : "white"); + } +} + +/** + * average dark pixels of a 8 bits scan + */ +static int +dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, + unsigned int channels, unsigned int black) +{ + unsigned int i, j, k, average, count; + unsigned int avg[3]; + uint8_t val; + + /* computes average value on black margin */ + for (k = 0; k < channels; k++) + { + avg[k] = 0; + count = 0; + for (i = 0; i < lines; i++) + { + for (j = 0; j < black; j++) + { + val = data[i * channels * pixels + j + k]; + avg[k] += val; + count++; + } + } + if (count) + avg[k] /= count; + DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); + } + average = 0; + for (i = 0; i < channels; i++) + average += avg[i]; + average /= channels; + DBG(DBG_info, "%s: average = %d\n", __func__, average); + return average; +} + +void CommandSetGl847::offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const +{ + DBG_HELPER(dbg); + unsigned channels; + int pass = 0, avg, total_size; + int topavg, bottomavg, lines; + int top, bottom, black_pixels, pixels; + + // no gain nor offset for AKM AFE + uint8_t reg04 = dev->interface->read_register(REG_0x04); + if ((reg04 & REG_0x04_FESET) == 0x02) { + return; + } + + /* offset calibration is always done in color mode */ + channels = 3; + dev->calib_pixels = sensor.sensor_pixels; + lines=1; + pixels= (sensor.sensor_pixels * sensor.optical_res) / sensor.optical_res; + black_pixels = (sensor.black_pixels * sensor.optical_res) / sensor.optical_res; + DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); + + ScanSession session; + session.params.xres = sensor.optical_res; + session.params.yres = sensor.optical_res; + session.params.startx = 0; + session.params.starty = 0; + session.params.pixels = pixels; + session.params.lines = lines; + session.params.depth = 8; + session.params.channels = channels; + session.params.scan_method = dev->settings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + init_regs_for_scan_session(dev, sensor, ®s, session); + + sanei_genesys_set_motor_power(regs, false); + + /* allocate memory for scans */ + total_size = pixels * channels * lines * (session.params.depth / 8); /* colors * bytes_per_color * scan lines */ + + std::vector first_line(total_size); + std::vector second_line(total_size); + + /* init gain */ + dev->frontend.set_gain(0, 0); + dev->frontend.set_gain(1, 0); + dev->frontend.set_gain(2, 0); + + /* scan with no move */ + bottom = 10; + dev->frontend.set_offset(0, bottom); + dev->frontend.set_offset(1, bottom); + dev->frontend.set_offset(2, bottom); + + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting first line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("offset_calibration"); + return; + } + + sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size); + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl847_offset%03d.pnm", bottom); + sanei_genesys_write_pnm_file(fn, first_line.data(), session.params.depth, + channels, pixels, lines); + } + + bottomavg = dark_average (first_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); + + /* now top value */ + top = 255; + dev->frontend.set_offset(0, top); + dev->frontend.set_offset(1, top); + dev->frontend.set_offset(2, top); + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + + topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); + + /* loop until acceptable level */ + while ((pass < 32) && (top - bottom > 1)) + { + pass++; + + /* settings for new scan */ + dev->frontend.set_offset(0, (top + bottom) / 2); + dev->frontend.set_offset(1, (top + bottom) / 2); + dev->frontend.set_offset(2, (top + bottom) / 2); + + // scan with no move + set_fe(dev, sensor, AFE_SET); + dev->interface->write_registers(regs); + DBG(DBG_info, "%s: starting second line reading\n", __func__); + begin_scan(dev, sensor, ®s, true); + sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) + { + char fn[30]; + std::snprintf(fn, 30, "gl847_offset%03d.pnm", dev->frontend.get_offset(1)); + sanei_genesys_write_pnm_file(fn, second_line.data(), session.params.depth, + channels, pixels, lines); + } + + avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); + DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); + + /* compute new boundaries */ + if (topavg == avg) + { + topavg = avg; + top = dev->frontend.get_offset(1); + } + else + { + bottomavg = avg; + bottom = dev->frontend.get_offset(1); + } + } + DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, + dev->frontend.get_offset(0), + dev->frontend.get_offset(1), + dev->frontend.get_offset(2)); +} + +void CommandSetGl847::coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const +{ + DBG_HELPER_ARGS(dbg, "dpi = %d", dpi); + int pixels; + int total_size; + int i, j, channels; + int max[3]; + float gain[3],coeff; + int val, code, lines; + + // no gain nor offset for AKM AFE + uint8_t reg04 = dev->interface->read_register(REG_0x04); + if ((reg04 & REG_0x04_FESET) == 0x02) { + return; + } + + /* coarse gain calibration is always done in color mode */ + channels = 3; + + /* follow CKSEL */ + if(dev->settings.xressettings.scan_method; + session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; + session.params.color_filter = dev->settings.color_filter; + session.params.flags = ScanFlag::DISABLE_SHADING | + ScanFlag::DISABLE_GAMMA | + ScanFlag::SINGLE_LINE | + ScanFlag::IGNORE_LINE_DISTANCE; + compute_session(dev, session, sensor); + + try { + init_regs_for_scan_session(dev, sensor, ®s, session); + } catch (...) { + catch_all_exceptions(__func__, [&](){ sanei_genesys_set_motor_power(regs, false); }); + throw; + } + + sanei_genesys_set_motor_power(regs, false); + + dev->interface->write_registers(regs); + + total_size = pixels * channels * (16 / session.params.depth) * lines; + + std::vector line(total_size); + + set_fe(dev, sensor, AFE_SET); + begin_scan(dev, sensor, ®s, true); + + if (is_testing_mode()) { + dev->interface->test_checkpoint("coarse_gain_calibration"); + scanner_stop_action(*dev); + move_back_home(dev, true); + return; + } + + sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); + + if (DBG_LEVEL >= DBG_data) { + sanei_genesys_write_pnm_file("gl847_gain.pnm", line.data(), session.params.depth, + channels, pixels, lines); + } + + /* average value on each channel */ + for (j = 0; j < channels; j++) + { + max[j] = 0; + for (i = pixels/4; i < (pixels*3/4); i++) + { + if (dev->model->is_cis) { + val = line[i + j * pixels]; + } else { + val = line[i * channels + j]; + } + + max[j] += val; + } + max[j] = max[j] / (pixels/2); + + gain[j] = (static_cast(sensor.gain_white_ref) * coeff) / max[j]; + + /* turn logical gain value into gain code, checking for overflow */ + code = static_cast(283 - 208 / gain[j]); + if (code > 255) + code = 255; + else if (code < 0) + code = 0; + dev->frontend.set_gain(j, code); + + DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], + dev->frontend.get_gain(j)); + } + + if (dev->model->is_cis) { + uint8_t gain0 = dev->frontend.get_gain(0); + if (gain0 > dev->frontend.get_gain(1)) { + gain0 = dev->frontend.get_gain(1); + } + if (gain0 > dev->frontend.get_gain(2)) { + gain0 = dev->frontend.get_gain(2); + } + dev->frontend.set_gain(0, gain0); + dev->frontend.set_gain(1, gain0); + dev->frontend.set_gain(2, gain0); + } + + if (channels == 1) { + dev->frontend.set_gain(0, dev->frontend.get_gain(1)); + dev->frontend.set_gain(2, dev->frontend.get_gain(1)); + } + + scanner_stop_action(*dev); + + move_back_home(dev, true); +} + +bool CommandSetGl847::needs_home_before_init_regs_for_scan(Genesys_Device* dev) const +{ + (void) dev; + return false; +} + +void CommandSetGl847::init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const +{ + (void) dev; + (void) sensor; + (void) regs; + (void) channels; + (void) total_size; + throw SaneException("not implemented"); +} + +void CommandSetGl847::send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const +{ + sanei_genesys_send_gamma_table(dev, sensor); +} + +void CommandSetGl847::wait_for_motor_stop(Genesys_Device* dev) const +{ + (void) dev; +} + +void CommandSetGl847::load_document(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl847::detect_document_end(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl847::eject_document(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +void CommandSetGl847::move_to_ta(Genesys_Device* dev) const +{ + (void) dev; + throw SaneException("not implemented"); +} + +std::unique_ptr create_gl847_cmd_set() +{ + return std::unique_ptr(new CommandSetGl847{}); +} + +} // namespace gl847 +} // namespace genesys diff --git a/backend/genesys/gl847.h b/backend/genesys/gl847.h new file mode 100644 index 0000000..a51c293 --- /dev/null +++ b/backend/genesys/gl847.h @@ -0,0 +1,206 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL847_H +#define BACKEND_GENESYS_GL847_H + +#include "genesys.h" +#include "command_set.h" + +namespace genesys { +namespace gl847 { + +typedef struct +{ + GpioId gpio_id; + uint8_t r6b; + uint8_t r6c; + uint8_t r6d; + uint8_t r6e; + uint8_t r6f; + uint8_t ra6; + uint8_t ra7; + uint8_t ra8; + uint8_t ra9; +} Gpio_Profile; + +static Gpio_Profile gpios[]={ + { GpioId::CANON_LIDE_200, 0x02, 0xf9, 0x20, 0xff, 0x00, 0x04, 0x04, 0x00, 0x00}, + { GpioId::CANON_LIDE_700F, 0x06, 0xdb, 0xff, 0xff, 0x80, 0x15, 0x07, 0x20, 0x10}, + { GpioId::UNKNOWN, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, +}; + +typedef struct +{ + uint8_t dramsel; + uint8_t rd0; + uint8_t rd1; + uint8_t rd2; + uint8_t re0; + uint8_t re1; + uint8_t re2; + uint8_t re3; + uint8_t re4; + uint8_t re5; + uint8_t re6; + uint8_t re7; +} Memory_layout; + +static Memory_layout layouts[]={ + /* LIDE 100 */ + { + 0x29, + 0x0a, 0x15, 0x20, + 0x00, 0xac, 0x02, 0x55, 0x02, 0x56, 0x03, 0xff + }, + /* LIDE 200 */ + { + 0x29, + 0x0a, 0x1f, 0x34, + 0x01, 0x24, 0x02, 0x91, 0x02, 0x92, 0x03, 0xff + }, + /* 5600F */ + { + 0x29, + 0x0a, 0x1f, 0x34, + 0x01, 0x24, 0x02, 0x91, 0x02, 0x92, 0x03, 0xff + }, + /* LIDE 700F */ + { + 0x2a, + 0x0a, 0x33, 0x5c, + 0x02, 0x14, 0x09, 0x09, 0x09, 0x0a, 0x0f, 0xff + } +}; + +class CommandSetGl847 : public CommandSet +{ +public: + ~CommandSetGl847() override = default; + + bool needs_home_before_init_regs_for_scan(Genesys_Device* dev) const override; + + void init(Genesys_Device* dev) const override; + + void init_regs_for_warmup(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, int* channels, + int* total_size) const override; + + void init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_shading(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void init_regs_for_scan(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void init_regs_for_scan_session(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* reg, + const ScanSession& session) const override; + + void set_fe(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t set) const override; + void set_powersaving(Genesys_Device* dev, int delay) const override; + void save_power(Genesys_Device* dev, bool enable) const override; + + void begin_scan(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set* regs, bool start_motor) const override; + + void end_scan(Genesys_Device* dev, Genesys_Register_Set* regs, bool check_stop) const override; + + void send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) const override; + + void search_start_position(Genesys_Device* dev) const override; + + void offset_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void coarse_gain_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, int dpi) const override; + + SensorExposure led_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs) const override; + + void wait_for_motor_stop(Genesys_Device* dev) const override; + + void move_back_home(Genesys_Device* dev, bool wait_until_home) const override; + + void update_hardware_sensors(struct Genesys_Scanner* s) const override; + + bool needs_update_home_sensor_gpio() const override { return true; } + + void update_home_sensor_gpio(Genesys_Device& dev) const override; + + void load_document(Genesys_Device* dev) const override; + + void detect_document_end(Genesys_Device* dev) const override; + + void eject_document(Genesys_Device* dev) const override; + + void search_strip(Genesys_Device* dev, const Genesys_Sensor& sensor, + bool forward, bool black) const override; + + void move_to_ta(Genesys_Device* dev) const override; + + void send_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, uint8_t* data, + int size) const override; + + ScanSession calculate_scan_session(const Genesys_Device* dev, + const Genesys_Sensor& sensor, + const Genesys_Settings& settings) const override; + + void asic_boot(Genesys_Device* dev, bool cold) const override; +}; + +enum SlopeTable +{ + SCAN_TABLE = 0, // table 1 at 0x4000 + BACKTRACK_TABLE = 1, // table 2 at 0x4800 + STOP_TABLE = 2, // table 3 at 0x5000 + FAST_TABLE = 3, // table 4 at 0x5800 + HOME_TABLE = 4, // table 5 at 0x6000 +}; + +} // namespace gl847 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL847_H diff --git a/backend/genesys/gl847_registers.h b/backend/genesys/gl847_registers.h new file mode 100644 index 0000000..0603a6a --- /dev/null +++ b/backend/genesys/gl847_registers.h @@ -0,0 +1,333 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_GL847_REGISTERS_H +#define BACKEND_GENESYS_GL847_REGISTERS_H + +#include + +namespace genesys { +namespace gl847 { + +using RegAddr = std::uint16_t; +using RegMask = std::uint8_t; +using RegShift = unsigned; + +static constexpr RegAddr REG_0x01 = 0x01; +static constexpr RegMask REG_0x01_CISSET = 0x80; +static constexpr RegMask REG_0x01_DOGENB = 0x40; +static constexpr RegMask REG_0x01_DVDSET = 0x20; +static constexpr RegMask REG_0x01_STAGGER = 0x10; +static constexpr RegMask REG_0x01_COMPENB = 0x08; +static constexpr RegMask REG_0x01_TRUEGRAY = 0x04; +static constexpr RegMask REG_0x01_SHDAREA = 0x02; +static constexpr RegMask REG_0x01_SCAN = 0x01; + +static constexpr RegAddr REG_0x02 = 0x02; +static constexpr RegMask REG_0x02_NOTHOME = 0x80; +static constexpr RegMask REG_0x02_ACDCDIS = 0x40; +static constexpr RegMask REG_0x02_AGOHOME = 0x20; +static constexpr RegMask REG_0x02_MTRPWR = 0x10; +static constexpr RegMask REG_0x02_FASTFED = 0x08; +static constexpr RegMask REG_0x02_MTRREV = 0x04; +static constexpr RegMask REG_0x02_HOMENEG = 0x02; +static constexpr RegMask REG_0x02_LONGCURV = 0x01; + +static constexpr RegAddr REG_0x03 = 0x03; +static constexpr RegMask REG_0x03_LAMPDOG = 0x80; +static constexpr RegMask REG_0x03_AVEENB = 0x40; +static constexpr RegMask REG_0x03_XPASEL = 0x20; +static constexpr RegMask REG_0x03_LAMPPWR = 0x10; +static constexpr RegMask REG_0x03_LAMPTIM = 0x0f; + +static constexpr RegAddr REG_0x04 = 0x04; +static constexpr RegMask REG_0x04_LINEART = 0x80; +static constexpr RegMask REG_0x04_BITSET = 0x40; +static constexpr RegMask REG_0x04_AFEMOD = 0x30; +static constexpr RegMask REG_0x04_FILTER = 0x0c; +static constexpr RegMask REG_0x04_FESET = 0x03; +static constexpr RegShift REG_0x04S_AFEMOD = 4; + +static constexpr RegAddr REG_0x05 = 0x05; +static constexpr RegMask REG_0x05_DPIHW = 0xc0; +static constexpr RegMask REG_0x05_DPIHW_600 = 0x00; +static constexpr RegMask REG_0x05_DPIHW_1200 = 0x40; +static constexpr RegMask REG_0x05_DPIHW_2400 = 0x80; +static constexpr RegMask REG_0x05_DPIHW_4800 = 0xc0; +static constexpr RegMask REG_0x05_MTLLAMP = 0x30; +static constexpr RegMask REG_0x05_GMMENB = 0x08; +static constexpr RegMask REG_0x05_MTLBASE = 0x03; + +static constexpr RegAddr REG_0x06 = 0x06; +static constexpr RegMask REG_0x06_SCANMOD = 0xe0; +static constexpr RegMask REG_0x06S_SCANMOD = 5; +static constexpr RegMask REG_0x06_PWRBIT = 0x10; +static constexpr RegMask REG_0x06_GAIN4 = 0x08; +static constexpr RegMask REG_0x06_OPTEST = 0x07; + +static constexpr RegMask REG_0x07_LAMPSIM = 0x80; + +static constexpr RegMask REG_0x08_DRAM2X = 0x80; +static constexpr RegMask REG_0x08_MPENB = 0x20; +static constexpr RegMask REG_0x08_CIS_LINE = 0x10; +static constexpr RegMask REG_0x08_IR1ENB = 0x08; +static constexpr RegMask REG_0x08_IR2ENB = 0x04; +static constexpr RegMask REG_0x08_ENB24M = 0x01; + +static constexpr RegMask REG_0x09_MCNTSET = 0xc0; +static constexpr RegMask REG_0x09_EVEN1ST = 0x20; +static constexpr RegMask REG_0x09_BLINE1ST = 0x10; +static constexpr RegMask REG_0x09_BACKSCAN = 0x08; +static constexpr RegMask REG_0x09_ENHANCE = 0x04; +static constexpr RegMask REG_0x09_SHORTTG = 0x02; +static constexpr RegMask REG_0x09_NWAIT = 0x01; + +static constexpr RegShift REG_0x09S_MCNTSET = 6; +static constexpr RegShift REG_0x09S_CLKSET = 4; + +static constexpr RegMask REG_0x0A_LPWMEN = 0x10; + +static constexpr RegAddr REG_0x0B = 0x0b; +static constexpr RegMask REG_0x0B_DRAMSEL = 0x07; +static constexpr RegMask REG_0x0B_ENBDRAM = 0x08; +static constexpr RegMask REG_0x0B_RFHDIS = 0x10; +static constexpr RegMask REG_0x0B_CLKSET = 0xe0; +static constexpr RegMask REG_0x0B_24MHZ = 0x00; +static constexpr RegMask REG_0x0B_30MHZ = 0x20; +static constexpr RegMask REG_0x0B_40MHZ = 0x40; +static constexpr RegMask REG_0x0B_48MHZ = 0x60; +static constexpr RegMask REG_0x0B_60MHZ = 0x80; + +static constexpr RegAddr REG_0x0C = 0x0c; +static constexpr RegMask REG_0x0C_CCDLMT = 0x0f; + +static constexpr RegAddr REG_0x0D = 0x0d; +static constexpr RegMask REG_0x0D_FULLSTP = 0x10; +static constexpr RegMask REG_0x0D_SEND = 0x80; +static constexpr RegMask REG_0x0D_CLRMCNT = 0x04; +static constexpr RegMask REG_0x0D_CLRDOCJM = 0x02; +static constexpr RegMask REG_0x0D_CLRLNCNT = 0x01; + +static constexpr RegAddr REG_0x0F = 0x0f; + +static constexpr RegMask REG_0x16_CTRLHI = 0x80; +static constexpr RegMask REG_0x16_TOSHIBA = 0x40; +static constexpr RegMask REG_0x16_TGINV = 0x20; +static constexpr RegMask REG_0x16_CK1INV = 0x10; +static constexpr RegMask REG_0x16_CK2INV = 0x08; +static constexpr RegMask REG_0x16_CTRLINV = 0x04; +static constexpr RegMask REG_0x16_CKDIS = 0x02; +static constexpr RegMask REG_0x16_CTRLDIS = 0x01; + +static constexpr RegMask REG_0x17_TGMODE = 0xc0; +static constexpr RegMask REG_0x17_TGMODE_NO_DUMMY = 0x00; +static constexpr RegMask REG_0x17_TGMODE_REF = 0x40; +static constexpr RegMask REG_0x17_TGMODE_XPA = 0x80; +static constexpr RegMask REG_0x17_TGW = 0x3f; +static constexpr RegMask REG_0x17S_TGW = 0; + +static constexpr RegAddr REG_0x18 = 0x18; +static constexpr RegMask REG_0x18_CNSET = 0x80; +static constexpr RegMask REG_0x18_DCKSEL = 0x60; +static constexpr RegMask REG_0x18_CKTOGGLE = 0x10; +static constexpr RegMask REG_0x18_CKDELAY = 0x0c; +static constexpr RegMask REG_0x18_CKSEL = 0x03; + +static constexpr RegMask REG_0x1A_SW2SET = 0x80; +static constexpr RegMask REG_0x1A_SW1SET = 0x40; +static constexpr RegMask REG_0x1A_MANUAL3 = 0x02; +static constexpr RegMask REG_0x1A_MANUAL1 = 0x01; +static constexpr RegMask REG_0x1A_CK4INV = 0x08; +static constexpr RegMask REG_0x1A_CK3INV = 0x04; +static constexpr RegMask REG_0x1A_LINECLP = 0x02; + +static constexpr RegAddr REG_0x1C = 0x1c; +static constexpr RegMask REG_0x1C_TGTIME = 0x07; + +static constexpr RegMask REG_0x1D_CK4LOW = 0x80; +static constexpr RegMask REG_0x1D_CK3LOW = 0x40; +static constexpr RegMask REG_0x1D_CK1LOW = 0x20; +static constexpr RegMask REG_0x1D_TGSHLD = 0x1f; +static constexpr RegMask REG_0x1DS_TGSHLD = 0; + +static constexpr RegMask REG_0x1E_WDTIME = 0xf0; +static constexpr RegMask REG_0x1ES_WDTIME = 4; +static constexpr RegMask REG_0x1E_LINESEL = 0x0f; +static constexpr RegMask REG_0x1ES_LINESEL = 0; + +static constexpr RegAddr REG_FEDCNT = 0x1f; + +static constexpr RegAddr REG_0x24 = 0x1c; +static constexpr RegAddr REG_0x40 = 0x40; +static constexpr RegMask REG_0x40_CHKVER = 0x10; +static constexpr RegMask REG_0x40_HISPDFLG = 0x04; +static constexpr RegMask REG_0x40_MOTMFLG = 0x02; +static constexpr RegMask REG_0x40_DATAENB = 0x01; + +static constexpr RegMask REG_0x41_PWRBIT = 0x80; +static constexpr RegMask REG_0x41_BUFEMPTY = 0x40; +static constexpr RegMask REG_0x41_FEEDFSH = 0x20; +static constexpr RegMask REG_0x41_SCANFSH = 0x10; +static constexpr RegMask REG_0x41_HOMESNR = 0x08; +static constexpr RegMask REG_0x41_LAMPSTS = 0x04; +static constexpr RegMask REG_0x41_FEBUSY = 0x02; +static constexpr RegMask REG_0x41_MOTORENB = 0x01; + +static constexpr RegMask REG_0x58_VSMP = 0xf8; +static constexpr RegShift REG_0x58S_VSMP = 3; +static constexpr RegMask REG_0x58_VSMPW = 0x07; +static constexpr RegShift REG_0x58S_VSMPW = 0; + +static constexpr RegMask REG_0x59_BSMP = 0xf8; +static constexpr RegShift REG_0x59S_BSMP = 3; +static constexpr RegMask REG_0x59_BSMPW = 0x07; +static constexpr RegShift REG_0x59S_BSMPW = 0; + +static constexpr RegMask REG_0x5A_ADCLKINV = 0x80; +static constexpr RegMask REG_0x5A_RLCSEL = 0x40; +static constexpr RegMask REG_0x5A_CDSREF = 0x30; +static constexpr RegShift REG_0x5AS_CDSREF = 4; +static constexpr RegMask REG_0x5A_RLC = 0x0f; +static constexpr RegShift REG_0x5AS_RLC = 0; + +static constexpr RegMask REG_0x5E_DECSEL = 0xe0; +static constexpr RegShift REG_0x5ES_DECSEL = 5; +static constexpr RegMask REG_0x5E_STOPTIM = 0x1f; +static constexpr RegShift REG_0x5ES_STOPTIM = 0; + +static constexpr RegAddr REG_0x60 = 0x60; +static constexpr RegMask REG_0x60_Z1MOD = 0x1f; +static constexpr RegAddr REG_0x61 = 0x61; +static constexpr RegMask REG_0x61_Z1MOD = 0xff; +static constexpr RegAddr REG_0x62 = 0x62; +static constexpr RegMask REG_0x62_Z1MOD = 0xff; + +static constexpr RegAddr REG_0x63 = 0x63; +static constexpr RegMask REG_0x63_Z2MOD = 0x1f; +static constexpr RegAddr REG_0x64 = 0x64; +static constexpr RegMask REG_0x64_Z2MOD = 0xff; +static constexpr RegAddr REG_0x65 = 0x65; +static constexpr RegMask REG_0x65_Z2MOD = 0xff; + +static constexpr RegShift REG_0x60S_STEPSEL = 5; +static constexpr RegMask REG_0x60_STEPSEL = 0xe0; +static constexpr RegMask REG_0x60_FULLSTEP = 0x00; +static constexpr RegMask REG_0x60_HALFSTEP = 0x20; +static constexpr RegMask REG_0x60_EIGHTHSTEP = 0x60; +static constexpr RegMask REG_0x60_16THSTEP = 0x80; + +static constexpr RegShift REG_0x63S_FSTPSEL = 5; +static constexpr RegMask REG_0x63_FSTPSEL = 0xe0; +static constexpr RegMask REG_0x63_FULLSTEP = 0x00; +static constexpr RegMask REG_0x63_HALFSTEP = 0x20; +static constexpr RegMask REG_0x63_EIGHTHSTEP = 0x60; +static constexpr RegMask REG_0x63_16THSTEP = 0x80; + +static constexpr RegAddr REG_0x67 = 0x67; +static constexpr RegMask REG_0x67_MTRPWM = 0x80; + +static constexpr RegAddr REG_0x68 = 0x68; +static constexpr RegMask REG_0x68_FASTPWM = 0x80; + +static constexpr RegAddr REG_0x6B = 0x6b; +static constexpr RegMask REG_0x6B_MULTFILM = 0x80; +static constexpr RegMask REG_0x6B_GPOM13 = 0x40; +static constexpr RegMask REG_0x6B_GPOM12 = 0x20; +static constexpr RegMask REG_0x6B_GPOM11 = 0x10; +static constexpr RegMask REG_0x6B_GPO18 = 0x02; +static constexpr RegMask REG_0x6B_GPO17 = 0x01; + +static constexpr RegShift REG_0x6C = 0x6c; +static constexpr RegMask REG_0x6C_GPIO16 = 0x80; +static constexpr RegMask REG_0x6C_GPIO15 = 0x40; +static constexpr RegMask REG_0x6C_GPIO14 = 0x20; +static constexpr RegMask REG_0x6C_GPIO13 = 0x10; +static constexpr RegMask REG_0x6C_GPIO12 = 0x08; +static constexpr RegMask REG_0x6C_GPIO11 = 0x04; +static constexpr RegMask REG_0x6C_GPIO10 = 0x02; +static constexpr RegMask REG_0x6C_GPIO9 = 0x01; +static constexpr RegMask REG_0x6C_GPIOH = 0xff; +static constexpr RegMask REG_0x6C_GPIOL = 0xff; + +static constexpr RegAddr REG_0x6D = 0x6d; +static constexpr RegAddr REG_0x6E = 0x6e; +static constexpr RegAddr REG_0x6F = 0x6f; +static constexpr RegAddr REG_0x7E = 0x7e; + +static constexpr RegMask REG_0x87_LEDADD = 0x04; + +static constexpr RegAddr REG_0x9E = 0x9e; +static constexpr RegAddr REG_0x9F = 0x9f; + +static constexpr RegAddr REG_0xA6 = 0xa6; +static constexpr RegAddr REG_0xA7 = 0xa7; +static constexpr RegAddr REG_0xA8 = 0xa8; +static constexpr RegAddr REG_0xA9 = 0xa9; +static constexpr RegAddr REG_0xAB = 0xab; + +static constexpr RegAddr REG_EXPR = 0x10; +static constexpr RegAddr REG_EXPG = 0x12; +static constexpr RegAddr REG_EXPB = 0x14; +static constexpr RegAddr REG_EXPDMY = 0x19; +static constexpr RegAddr REG_STEPNO = 0x21; +static constexpr RegAddr REG_FWDSTEP = 0x22; +static constexpr RegAddr REG_BWDSTEP = 0x23; +static constexpr RegAddr REG_FASTNO = 0x24; +static constexpr RegAddr REG_DPISET = 0x2c; +static constexpr RegAddr REG_STRPIXEL = 0x30; +static constexpr RegAddr REG_ENDPIXEL = 0x32; +static constexpr RegAddr REG_LINCNT = 0x25; +static constexpr RegAddr REG_MAXWD = 0x35; +static constexpr RegAddr REG_LPERIOD = 0x38; +static constexpr RegAddr REG_FEEDL = 0x3d; +static constexpr RegAddr REG_FMOVDEC = 0x5f; +static constexpr RegAddr REG_FSHDEC = 0x69; +static constexpr RegAddr REG_FMOVNO = 0x6a; +static constexpr RegAddr REG_CK1MAP = 0x74; +static constexpr RegAddr REG_CK3MAP = 0x77; +static constexpr RegAddr REG_CK4MAP = 0x7a; + +} // namespace gl847 +} // namespace genesys + +#endif // BACKEND_GENESYS_GL847_REGISTERS_H diff --git a/backend/genesys/image.cpp b/backend/genesys/image.cpp new file mode 100644 index 0000000..7d386c6 --- /dev/null +++ b/backend/genesys/image.cpp @@ -0,0 +1,204 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "image.h" + +#include + +namespace genesys { + +Image::Image() = default; + +Image::Image(std::size_t width, std::size_t height, PixelFormat format) : + width_{width}, + height_{height}, + format_{format}, + row_bytes_{get_pixel_row_bytes(format_, width_)} +{ + data_.resize(get_row_bytes() * height); +} + +std::uint8_t* Image::get_row_ptr(std::size_t y) +{ + return data_.data() + row_bytes_ * y; +} + +const std::uint8_t* Image::get_row_ptr(std::size_t y) const +{ + return data_.data() + row_bytes_ * y; +} + +Pixel Image::get_pixel(std::size_t x, std::size_t y) const +{ + return get_pixel_from_row(get_row_ptr(y), x, format_); +} + +void Image::set_pixel(std::size_t x, std::size_t y, const Pixel& pixel) +{ + set_pixel_to_row(get_row_ptr(y), x, pixel, format_); +} + +RawPixel Image::get_raw_pixel(std::size_t x, std::size_t y) const +{ + return get_raw_pixel_from_row(get_row_ptr(y), x, format_); +} + +std::uint16_t Image::get_raw_channel(std::size_t x, std::size_t y, unsigned channel) const +{ + return get_raw_channel_from_row(get_row_ptr(y), x, channel, format_); +} + +void Image::set_raw_pixel(std::size_t x, std::size_t y, const RawPixel& pixel) +{ + set_raw_pixel_to_row(get_row_ptr(y), x, pixel, format_); +} + +void Image::resize(std::size_t width, std::size_t height, PixelFormat format) +{ + width_ = width; + height_ = height; + format_ = format; + row_bytes_ = get_pixel_row_bytes(format_, width_); + data_.resize(get_row_bytes() * height); +} + +template +void convert_pixel_row_impl2(const std::uint8_t* in_data, std::uint8_t* out_data, + std::size_t count) +{ + for (std::size_t i = 0; i < count; ++i) { + Pixel pixel = get_pixel_from_row(in_data, i, SrcFormat); + set_pixel_to_row(out_data, i, pixel, DstFormat); + } +} + +template +void convert_pixel_row_impl(const std::uint8_t* in_data, std::uint8_t* out_data, + PixelFormat out_format, std::size_t count) +{ + switch (out_format) { + case PixelFormat::I1: { + convert_pixel_row_impl2(in_data, out_data, count); + return; + } + case PixelFormat::RGB111: { + convert_pixel_row_impl2(in_data, out_data, count); + return; + } + case PixelFormat::I8: { + convert_pixel_row_impl2(in_data, out_data, count); + return; + } + case PixelFormat::RGB888: { + convert_pixel_row_impl2(in_data, out_data, count); + return; + } + case PixelFormat::BGR888: { + convert_pixel_row_impl2(in_data, out_data, count); + return; + } + case PixelFormat::I16: { + convert_pixel_row_impl2(in_data, out_data, count); + return; + } + case PixelFormat::RGB161616: { + convert_pixel_row_impl2(in_data, out_data, count); + return; + } + case PixelFormat::BGR161616: { + convert_pixel_row_impl2(in_data, out_data, count); + return; + } + default: + throw SaneException("Unknown pixel format %d", static_cast(out_format)); + } +} +void convert_pixel_row_format(const std::uint8_t* in_data, PixelFormat in_format, + std::uint8_t* out_data, PixelFormat out_format, std::size_t count) +{ + if (in_format == out_format) { + std::memcpy(out_data, in_data, get_pixel_row_bytes(in_format, count)); + return; + } + + switch (in_format) { + case PixelFormat::I1: { + convert_pixel_row_impl(in_data, out_data, out_format, count); + return; + } + case PixelFormat::RGB111: { + convert_pixel_row_impl(in_data, out_data, out_format, count); + return; + } + case PixelFormat::I8: { + convert_pixel_row_impl(in_data, out_data, out_format, count); + return; + } + case PixelFormat::RGB888: { + convert_pixel_row_impl(in_data, out_data, out_format, count); + return; + } + case PixelFormat::BGR888: { + convert_pixel_row_impl(in_data, out_data, out_format, count); + return; + } + case PixelFormat::I16: { + convert_pixel_row_impl(in_data, out_data, out_format, count); + return; + } + case PixelFormat::RGB161616: { + convert_pixel_row_impl(in_data, out_data, out_format, count); + return; + } + case PixelFormat::BGR161616: { + convert_pixel_row_impl(in_data, out_data, out_format, count); + return; + } + default: + throw SaneException("Unknown pixel format %d", static_cast(in_format)); + } +} + +} // namespace genesys diff --git a/backend/genesys/image.h b/backend/genesys/image.h new file mode 100644 index 0000000..c96b1bb --- /dev/null +++ b/backend/genesys/image.h @@ -0,0 +1,87 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_IMAGE_H +#define BACKEND_GENESYS_IMAGE_H + +#include "image_pixel.h" +#include + +namespace genesys { + +class Image +{ +public: + Image(); + Image(std::size_t width, std::size_t height, PixelFormat format); + + std::size_t get_width() const { return width_; } + std::size_t get_height() const { return height_; } + PixelFormat get_format() const { return format_; } + std::size_t get_row_bytes() const { return row_bytes_; } + + std::uint8_t* get_row_ptr(std::size_t y); + const std::uint8_t* get_row_ptr(std::size_t y) const; + + Pixel get_pixel(std::size_t x, std::size_t y) const; + void set_pixel(std::size_t x, std::size_t y, const Pixel& pixel); + + RawPixel get_raw_pixel(std::size_t x, std::size_t y) const; + std::uint16_t get_raw_channel(std::size_t x, std::size_t y, unsigned channel) const; + void set_raw_pixel(std::size_t x, std::size_t y, const RawPixel& pixel); + + void resize(std::size_t width, std::size_t height, PixelFormat format); +private: + std::size_t width_ = 0; + std::size_t height_ = 0; + PixelFormat format_ = PixelFormat::UNKNOWN; + std::size_t row_bytes_ = 0; + std::vector data_; +}; + +void convert_pixel_row_format(const std::uint8_t* in_data, PixelFormat in_format, + std::uint8_t* out_data, PixelFormat out_format, std::size_t count); + +} // namespace genesys + +#endif // ifndef BACKEND_GENESYS_IMAGE_H diff --git a/backend/genesys/image_buffer.cpp b/backend/genesys/image_buffer.cpp new file mode 100644 index 0000000..07c6987 --- /dev/null +++ b/backend/genesys/image_buffer.cpp @@ -0,0 +1,203 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "image_buffer.h" +#include "image.h" + +namespace genesys { + +ImageBuffer::ImageBuffer(std::size_t size, ProducerCallback producer) : + producer_{producer}, + size_{size}, + buffer_offset_{size} +{ + buffer_.resize(size_); +} + +bool ImageBuffer::get_data(std::size_t size, std::uint8_t* out_data) +{ + const std::uint8_t* out_data_end = out_data + size; + + auto copy_buffer = [&]() + { + std::size_t bytes_copy = std::min(out_data_end - out_data, available()); + std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy); + out_data += bytes_copy; + buffer_offset_ += bytes_copy; + }; + + // first, read remaining data from buffer + if (available() > 0) { + copy_buffer(); + } + + if (out_data == out_data_end) { + return true; + } + + // now the buffer is empty and there's more data to be read + bool got_data = true; + do { + buffer_offset_ = 0; + got_data &= producer_(size_, buffer_.data()); + + copy_buffer(); + } while(out_data < out_data_end && got_data); + + return got_data; +} + +void FakeBufferModel::push_step(std::size_t buffer_size, std::size_t row_bytes) +{ + sizes_.push_back(buffer_size); + available_sizes_.push_back(0); + row_bytes_.push_back(row_bytes); +} + +std::size_t FakeBufferModel::available_space() const +{ + if (sizes_.empty()) + throw SaneException("Model has not been setup"); + return sizes_.front() - available_sizes_.front(); +} + +void FakeBufferModel::simulate_read(std::size_t size) +{ + if (sizes_.empty()) { + throw SaneException("Model has not been setup"); + } + if (available_space() < size) { + throw SaneException("Attempted to simulate read of too much memory"); + } + + available_sizes_.front() += size; + + for (unsigned i = 1; i < sizes_.size(); ++i) { + auto avail_src = available_sizes_[i - 1]; + auto avail_dst = sizes_[i] - available_sizes_[i]; + + auto avail = (std::min(avail_src, avail_dst) / row_bytes_[i]) * row_bytes_[i]; + available_sizes_[i - 1] -= avail; + available_sizes_[i] += avail; + } + available_sizes_.back() = 0; +} + +ImageBufferGenesysUsb::ImageBufferGenesysUsb(std::size_t total_size, + const FakeBufferModel& buffer_model, + ProducerCallback producer) : + remaining_size_{total_size}, + buffer_model_{buffer_model}, + producer_{producer} +{} + +bool ImageBufferGenesysUsb::get_data(std::size_t size, std::uint8_t* out_data) +{ + const std::uint8_t* out_data_end = out_data + size; + + auto copy_buffer = [&]() + { + std::size_t bytes_copy = std::min(out_data_end - out_data, available()); + std::memcpy(out_data, buffer_.data() + buffer_offset_, bytes_copy); + out_data += bytes_copy; + buffer_offset_ += bytes_copy; + }; + + // first, read remaining data from buffer + if (available() > 0) { + copy_buffer(); + } + + if (out_data == out_data_end) { + return true; + } + + // now the buffer is empty and there's more data to be read + do { + if (remaining_size_ == 0) + return false; + + auto bytes_to_read = get_read_size(); + buffer_offset_ = 0; + buffer_end_ = bytes_to_read; + buffer_.resize(bytes_to_read); + + producer_(bytes_to_read, buffer_.data()); + + if (remaining_size_ < bytes_to_read) { + remaining_size_ = 0; + } else { + remaining_size_ -= bytes_to_read; + } + + copy_buffer(); + } while(out_data < out_data_end); + return true; +} + +std::size_t ImageBufferGenesysUsb::get_read_size() +{ + std::size_t size = buffer_model_.available_space(); + + // never read an odd number. exception: last read + // the chip internal counter does not count half words. + size &= ~1; + + // Some setups need the reads to be multiples of 256 bytes + size &= ~0xff; + + if (remaining_size_ < size) { + size = remaining_size_; + /*round up to a multiple of 256 bytes */ + size += (size & 0xff) ? 0x100 : 0x00; + size &= ~0xff; + } + + buffer_model_.simulate_read(size); + + return size; +} + +} // namespace genesys diff --git a/backend/genesys/image_buffer.h b/backend/genesys/image_buffer.h new file mode 100644 index 0000000..43c3eb7 --- /dev/null +++ b/backend/genesys/image_buffer.h @@ -0,0 +1,129 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_IMAGE_BUFFER_H +#define BACKEND_GENESYS_IMAGE_BUFFER_H + +#include "enums.h" +#include "row_buffer.h" +#include +#include + +namespace genesys { + +// This class allows reading from row-based source in smaller or larger chunks of data +class ImageBuffer +{ +public: + using ProducerCallback = std::function; + + ImageBuffer() {} + ImageBuffer(std::size_t size, ProducerCallback producer); + + std::size_t size() const { return size_; } + std::size_t available() const { return size_ - buffer_offset_; } + + bool get_data(std::size_t size, std::uint8_t* out_data); + +private: + ProducerCallback producer_; + std::size_t size_ = 0; + + std::size_t buffer_offset_ = 0; + std::vector buffer_; +}; + +class FakeBufferModel +{ +public: + FakeBufferModel() {} + + void push_step(std::size_t buffer_size, std::size_t row_bytes); + + std::size_t available_space() const; + + void simulate_read(std::size_t size); + +private: + std::vector sizes_; + std::vector available_sizes_; + std::vector row_bytes_; +}; + +// This class is similar to ImageBuffer, but preserves historical peculiarities of buffer handling +// in the backend to preserve exact behavior +class ImageBufferGenesysUsb +{ +public: + using ProducerCallback = std::function; + + ImageBufferGenesysUsb() {} + ImageBufferGenesysUsb(std::size_t total_size, const FakeBufferModel& buffer_model, + ProducerCallback producer); + + std::size_t remaining_size() const { return remaining_size_; } + + void set_remaining_size(std::size_t bytes) { remaining_size_ = bytes; } + + std::size_t available() const { return buffer_end_ - buffer_offset_; } + + bool get_data(std::size_t size, std::uint8_t* out_data); + +private: + + std::size_t get_read_size(); + + std::size_t remaining_size_ = 0; + + std::size_t buffer_offset_ = 0; + std::size_t buffer_end_ = 0; + std::vector buffer_; + + FakeBufferModel buffer_model_; + + ProducerCallback producer_; +}; + +} // namespace genesys + +#endif // BACKEND_GENESYS_IMAGE_BUFFER_H diff --git a/backend/genesys/image_pipeline.cpp b/backend/genesys/image_pipeline.cpp new file mode 100644 index 0000000..c01b7f4 --- /dev/null +++ b/backend/genesys/image_pipeline.cpp @@ -0,0 +1,839 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "image_pipeline.h" +#include "image.h" +#include "low.h" +#include +#include + +namespace genesys { + +ImagePipelineNode::~ImagePipelineNode() {} + +std::size_t ImagePipelineNodeBytesSource::consume_remaining_bytes(std::size_t bytes) +{ + if (bytes > remaining_bytes_) { + bytes = remaining_bytes_; + } + remaining_bytes_ -= bytes; + return bytes; +} + +bool ImagePipelineNodeCallableSource::get_next_row_data(std::uint8_t* out_data) +{ + bool got_data = producer_(get_row_bytes(), out_data); + if (!got_data) + eof_ = true; + return got_data; +} + +ImagePipelineNodeBufferedCallableSource::ImagePipelineNodeBufferedCallableSource( + std::size_t width, std::size_t height, PixelFormat format, std::size_t input_batch_size, + ProducerCallback producer) : + width_{width}, + height_{height}, + format_{format}, + buffer_{input_batch_size, producer} +{ + set_remaining_bytes(height_ * get_row_bytes()); +} + +bool ImagePipelineNodeBufferedCallableSource::get_next_row_data(std::uint8_t* out_data) +{ + if (curr_row_ >= get_height()) { + DBG(DBG_warn, "%s: reading out of bounds. Row %zu, height: %zu\n", __func__, + curr_row_, get_height()); + eof_ = true; + return false; + } + + bool got_data = true; + + auto row_bytes = get_row_bytes(); + auto bytes_to_ask = consume_remaining_bytes(row_bytes); + if (bytes_to_ask < row_bytes) { + got_data = false; + } + + got_data &= buffer_.get_data(bytes_to_ask, out_data); + curr_row_++; + if (!got_data) { + eof_ = true; + } + return got_data; +} + + +ImagePipelineNodeBufferedGenesysUsb::ImagePipelineNodeBufferedGenesysUsb( + std::size_t width, std::size_t height, PixelFormat format, std::size_t total_size, + const FakeBufferModel& buffer_model, ProducerCallback producer) : + width_{width}, + height_{height}, + format_{format}, + buffer_{total_size, buffer_model, producer} +{ + set_remaining_bytes(total_size); +} + +bool ImagePipelineNodeBufferedGenesysUsb::get_next_row_data(std::uint8_t* out_data) +{ + if (remaining_bytes() != buffer_.remaining_size() + buffer_.available()) { + buffer_.set_remaining_size(remaining_bytes() - buffer_.available()); + } + bool got_data = true; + + std::size_t row_bytes = get_row_bytes(); + std::size_t ask_bytes = consume_remaining_bytes(row_bytes); + if (ask_bytes < row_bytes) { + got_data = false; + } + got_data &= buffer_.get_data(ask_bytes, out_data); + if (!got_data) { + eof_ = true; + } + return got_data; +} + +ImagePipelineNodeArraySource::ImagePipelineNodeArraySource(std::size_t width, std::size_t height, + PixelFormat format, + std::vector data) : + width_{width}, + height_{height}, + format_{format}, + data_{std::move(data)}, + next_row_{0} +{ + auto size = get_row_bytes() * height_; + if (data_.size() < size) { + throw SaneException("The given array is too small (%zu bytes). Need at least %zu", + data_.size(), size); + } + set_remaining_bytes(size); +} + +bool ImagePipelineNodeArraySource::get_next_row_data(std::uint8_t* out_data) +{ + if (next_row_ >= height_) { + eof_ = true; + return false; + } + + bool got_data = true; + + auto row_bytes = get_row_bytes(); + auto bytes_to_ask = consume_remaining_bytes(row_bytes); + if (bytes_to_ask < row_bytes) { + got_data = false; + } + + std::memcpy(out_data, data_.data() + get_row_bytes() * next_row_, bytes_to_ask); + next_row_++; + + if (!got_data) { + eof_ = true; + } + return got_data; +} + + +ImagePipelineNodeImageSource::ImagePipelineNodeImageSource(const Image& source) : + source_{source} +{} + +bool ImagePipelineNodeImageSource::get_next_row_data(std::uint8_t* out_data) +{ + if (next_row_ >= get_height()) { + return false; + } + std::memcpy(out_data, source_.get_row_ptr(next_row_), get_row_bytes()); + next_row_++; + return true; +} + +bool ImagePipelineNodeFormatConvert::get_next_row_data(std::uint8_t* out_data) +{ + auto src_format = source_.get_format(); + if (src_format == dst_format_) { + return source_.get_next_row_data(out_data); + } + + buffer_.clear(); + buffer_.resize(source_.get_row_bytes()); + bool got_data = source_.get_next_row_data(buffer_.data()); + + convert_pixel_row_format(buffer_.data(), src_format, out_data, dst_format_, get_width()); + return got_data; +} + +ImagePipelineNodeDesegment::ImagePipelineNodeDesegment(ImagePipelineNode& source, + std::size_t output_width, + const std::vector& segment_order, + std::size_t segment_pixels, + std::size_t interleaved_lines, + std::size_t pixels_per_chunk) : + source_(source), + output_width_{output_width}, + segment_order_{segment_order}, + segment_pixels_{segment_pixels}, + interleaved_lines_{interleaved_lines}, + pixels_per_chunk_{pixels_per_chunk}, + buffer_{source_.get_row_bytes()} +{ + DBG_HELPER_ARGS(dbg, "segment_count=%zu, segment_size=%zu, interleaved_lines=%zu, " + "pixels_per_shunk=%zu", segment_order.size(), segment_pixels, + interleaved_lines, pixels_per_chunk); + + if (source_.get_height() % interleaved_lines_ > 0) { + throw SaneException("Height is not a multiple of the number of lines to interelave %zu/%zu", + source_.get_height(), interleaved_lines_); + } +} + +ImagePipelineNodeDesegment::ImagePipelineNodeDesegment(ImagePipelineNode& source, + std::size_t output_width, + std::size_t segment_count, + std::size_t segment_pixels, + std::size_t interleaved_lines, + std::size_t pixels_per_chunk) : + source_(source), + output_width_{output_width}, + segment_pixels_{segment_pixels}, + interleaved_lines_{interleaved_lines}, + pixels_per_chunk_{pixels_per_chunk}, + buffer_{source_.get_row_bytes()} +{ + DBG_HELPER_ARGS(dbg, "segment_count=%zu, segment_size=%zu, interleaved_lines=%zu, " + "pixels_per_shunk=%zu", segment_count, segment_pixels, interleaved_lines, + pixels_per_chunk); + + segment_order_.resize(segment_count); + std::iota(segment_order_.begin(), segment_order_.end(), 0); +} + +bool ImagePipelineNodeDesegment::get_next_row_data(uint8_t* out_data) +{ + bool got_data = true; + + buffer_.clear(); + for (std::size_t i = 0; i < interleaved_lines_; ++i) { + buffer_.push_back(); + got_data &= source_.get_next_row_data(buffer_.get_row_ptr(i)); + } + if (!buffer_.is_linear()) { + throw SaneException("Buffer is not linear"); + } + + auto format = get_format(); + auto segment_count = segment_order_.size(); + + const std::uint8_t* in_data = buffer_.get_row_ptr(0); + + std::size_t groups_count = output_width_ / (segment_order_.size() * pixels_per_chunk_); + + for (std::size_t igroup = 0; igroup < groups_count; ++igroup) { + for (std::size_t isegment = 0; isegment < segment_count; ++isegment) { + auto input_offset = igroup * pixels_per_chunk_; + input_offset += segment_pixels_ * segment_order_[isegment]; + auto output_offset = (igroup * segment_count + isegment) * pixels_per_chunk_; + + for (std::size_t ipixel = 0; ipixel < pixels_per_chunk_; ++ipixel) { + auto pixel = get_raw_pixel_from_row(in_data, input_offset + ipixel, format); + set_raw_pixel_to_row(out_data, output_offset + ipixel, pixel, format); + } + } + } + return got_data; +} + +ImagePipelineNodeDeinterleaveLines::ImagePipelineNodeDeinterleaveLines( + ImagePipelineNode& source, std::size_t interleaved_lines, std::size_t pixels_per_chunk) : + ImagePipelineNodeDesegment(source, source.get_width() * interleaved_lines, + interleaved_lines, source.get_width(), + interleaved_lines, pixels_per_chunk) +{} + +ImagePipelineNodeSwap16BitEndian::ImagePipelineNodeSwap16BitEndian(ImagePipelineNode& source) : + source_(source), + needs_swapping_{false} +{ + if (get_pixel_format_depth(source_.get_format()) == 16) { + needs_swapping_ = true; + } else { + DBG(DBG_info, "%s: this pipeline node does nothing for non 16-bit formats", __func__); + } +} + +bool ImagePipelineNodeSwap16BitEndian::get_next_row_data(std::uint8_t* out_data) +{ + bool got_data = source_.get_next_row_data(out_data); + if (needs_swapping_) { + std::size_t pixels = get_row_bytes() / 2; + for (std::size_t i = 0; i < pixels; ++i) { + std::swap(*out_data, *(out_data + 1)); + out_data += 2; + } + } + return got_data; +} + +ImagePipelineNodeMergeMonoLines::ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source, + ColorOrder color_order) : + source_(source), + buffer_(source_.get_row_bytes()) +{ + DBG_HELPER_ARGS(dbg, "color_order %d", static_cast(color_order)); + + output_format_ = get_output_format(source_.get_format(), color_order); +} + +bool ImagePipelineNodeMergeMonoLines::get_next_row_data(std::uint8_t* out_data) +{ + bool got_data = true; + + buffer_.clear(); + for (unsigned i = 0; i < 3; ++i) { + buffer_.push_back(); + got_data &= source_.get_next_row_data(buffer_.get_row_ptr(i)); + } + + const auto* row0 = buffer_.get_row_ptr(0); + const auto* row1 = buffer_.get_row_ptr(1); + const auto* row2 = buffer_.get_row_ptr(2); + + auto format = source_.get_format(); + + for (std::size_t x = 0, width = get_width(); x < width; ++x) { + std::uint16_t ch0 = get_raw_channel_from_row(row0, x, 0, format); + std::uint16_t ch1 = get_raw_channel_from_row(row1, x, 0, format); + std::uint16_t ch2 = get_raw_channel_from_row(row2, x, 0, format); + set_raw_channel_to_row(out_data, x, 0, ch0, output_format_); + set_raw_channel_to_row(out_data, x, 1, ch1, output_format_); + set_raw_channel_to_row(out_data, x, 2, ch2, output_format_); + } + return got_data; +} + +PixelFormat ImagePipelineNodeMergeMonoLines::get_output_format(PixelFormat input_format, + ColorOrder order) +{ + switch (input_format) { + case PixelFormat::I1: { + if (order == ColorOrder::RGB) { + return PixelFormat::RGB111; + } + break; + } + case PixelFormat::I8: { + if (order == ColorOrder::RGB) { + return PixelFormat::RGB888; + } + if (order == ColorOrder::BGR) { + return PixelFormat::BGR888; + } + break; + } + case PixelFormat::I16: { + if (order == ColorOrder::RGB) { + return PixelFormat::RGB161616; + } + if (order == ColorOrder::BGR) { + return PixelFormat::BGR161616; + } + break; + } + default: break; + } + throw SaneException("Unsupported format combidation %d %d", + static_cast(input_format), + static_cast(order)); +} + +ImagePipelineNodeSplitMonoLines::ImagePipelineNodeSplitMonoLines(ImagePipelineNode& source) : + source_(source), + next_channel_{0} +{ + output_format_ = get_output_format(source_.get_format()); +} + +bool ImagePipelineNodeSplitMonoLines::get_next_row_data(std::uint8_t* out_data) +{ + bool got_data = true; + + if (next_channel_ == 0) { + buffer_.resize(source_.get_row_bytes()); + got_data &= source_.get_next_row_data(buffer_.data()); + } + + const auto* row = buffer_.data(); + auto format = source_.get_format(); + + for (std::size_t x = 0, width = get_width(); x < width; ++x) { + std::uint16_t ch = get_raw_channel_from_row(row, x, next_channel_, format); + set_raw_channel_to_row(out_data, x, 0, ch, output_format_); + } + next_channel_ = (next_channel_ + 1) % 3; + + return got_data; +} + +PixelFormat ImagePipelineNodeSplitMonoLines::get_output_format(PixelFormat input_format) +{ + switch (input_format) { + case PixelFormat::RGB111: return PixelFormat::I1; + case PixelFormat::RGB888: + case PixelFormat::BGR888: return PixelFormat::I8; + case PixelFormat::RGB161616: + case PixelFormat::BGR161616: return PixelFormat::I16; + default: break; + } + throw SaneException("Unsupported input format %d", static_cast(input_format)); +} + +ImagePipelineNodeComponentShiftLines::ImagePipelineNodeComponentShiftLines( + ImagePipelineNode& source, unsigned shift_r, unsigned shift_g, unsigned shift_b) : + source_(source), + buffer_{source.get_row_bytes()} +{ + DBG_HELPER_ARGS(dbg, "shifts={%d, %d, %d}", shift_r, shift_g, shift_b); + + switch (source.get_format()) { + case PixelFormat::RGB111: + case PixelFormat::RGB888: + case PixelFormat::RGB161616: { + channel_shifts_ = { shift_r, shift_g, shift_b }; + break; + } + case PixelFormat::BGR888: + case PixelFormat::BGR161616: { + channel_shifts_ = { shift_b, shift_g, shift_r }; + break; + } + default: + throw SaneException("Unsupported input format %d", + static_cast(source.get_format())); + } + extra_height_ = *std::max_element(channel_shifts_.begin(), channel_shifts_.end()); +} + +bool ImagePipelineNodeComponentShiftLines::get_next_row_data(std::uint8_t* out_data) +{ + bool got_data = true; + + if (!buffer_.empty()) { + buffer_.pop_front(); + } + while (buffer_.height() < extra_height_ + 1) { + buffer_.push_back(); + got_data &= source_.get_next_row_data(buffer_.get_back_row_ptr()); + } + + auto format = get_format(); + const auto* row0 = buffer_.get_row_ptr(channel_shifts_[0]); + const auto* row1 = buffer_.get_row_ptr(channel_shifts_[1]); + const auto* row2 = buffer_.get_row_ptr(channel_shifts_[2]); + + for (std::size_t x = 0, width = get_width(); x < width; ++x) { + std::uint16_t ch0 = get_raw_channel_from_row(row0, x, 0, format); + std::uint16_t ch1 = get_raw_channel_from_row(row1, x, 1, format); + std::uint16_t ch2 = get_raw_channel_from_row(row2, x, 2, format); + set_raw_channel_to_row(out_data, x, 0, ch0, format); + set_raw_channel_to_row(out_data, x, 1, ch1, format); + set_raw_channel_to_row(out_data, x, 2, ch2, format); + } + return got_data; +} + +ImagePipelineNodePixelShiftLines::ImagePipelineNodePixelShiftLines( + ImagePipelineNode& source, const std::vector& shifts) : + source_(source), + pixel_shifts_{shifts}, + buffer_{get_row_bytes()} +{ + DBG_HELPER(dbg); + DBG(DBG_proc, "%s: shifts={", __func__); + for (auto el : pixel_shifts_) { + DBG(DBG_proc, " %zu", el); + } + DBG(DBG_proc, " }\n"); + + if (pixel_shifts_.size() > MAX_SHIFTS) { + throw SaneException("Unsupported number of shift configurations %zu", pixel_shifts_.size()); + } + + extra_height_ = *std::max_element(pixel_shifts_.begin(), pixel_shifts_.end()); +} + +bool ImagePipelineNodePixelShiftLines::get_next_row_data(std::uint8_t* out_data) +{ + bool got_data = true; + + if (!buffer_.empty()) { + buffer_.pop_front(); + } + while (buffer_.height() < extra_height_ + 1) { + buffer_.push_back(); + got_data &= source_.get_next_row_data(buffer_.get_back_row_ptr()); + } + + auto format = get_format(); + auto shift_count = pixel_shifts_.size(); + + std::array rows; + + for (std::size_t irow = 0; irow < shift_count; ++irow) { + rows[irow] = buffer_.get_row_ptr(pixel_shifts_[irow]); + } + + for (std::size_t x = 0, width = get_width(); x < width;) { + for (std::size_t irow = 0; irow < shift_count && x < width; irow++, x++) { + RawPixel pixel = get_raw_pixel_from_row(rows[irow], x, format); + set_raw_pixel_to_row(out_data, x, pixel, format); + } + } + return got_data; +} + +ImagePipelineNodeExtract::ImagePipelineNodeExtract(ImagePipelineNode& source, + std::size_t offset_x, std::size_t offset_y, + std::size_t width, std::size_t height) : + source_(source), + offset_x_{offset_x}, + offset_y_{offset_y}, + width_{width}, + height_{height} +{ + cached_line_.resize(source_.get_row_bytes()); +} + +ImagePipelineNodeExtract::~ImagePipelineNodeExtract() {} + +ImagePipelineNodeScaleRows::ImagePipelineNodeScaleRows(ImagePipelineNode& source, + std::size_t width) : + source_(source), + width_{width} +{ + cached_line_.resize(source_.get_row_bytes()); +} + +bool ImagePipelineNodeScaleRows::get_next_row_data(std::uint8_t* out_data) +{ + auto src_width = source_.get_width(); + auto dst_width = width_; + + bool got_data = source_.get_next_row_data(cached_line_.data()); + + const auto* src_data = cached_line_.data(); + auto format = get_format(); + auto channels = get_pixel_channels(format); + + if (src_width > dst_width) { + // average + std::uint32_t counter = src_width / 2; + unsigned src_x = 0; + for (unsigned dst_x = 0; dst_x < dst_width; dst_x++) { + unsigned avg[3] = {0, 0, 0}; + unsigned count = 0; + while (counter < src_width && src_x < src_width) { + counter += dst_width; + + for (unsigned c = 0; c < channels; c++) { + avg[c] += get_raw_channel_from_row(src_data, src_x, c, format); + } + + src_x++; + count++; + } + counter -= src_width; + + for (unsigned c = 0; c < channels; c++) { + set_raw_channel_to_row(out_data, dst_x, c, avg[c] / count, format); + } + } + } else { + // interpolate and copy pixels + std::uint32_t counter = dst_width / 2; + unsigned dst_x = 0; + + for (unsigned src_x = 0; src_x < src_width; src_x++) { + unsigned avg[3] = {0, 0, 0}; + for (unsigned c = 0; c < channels; c++) { + avg[c] += get_raw_channel_from_row(src_data, src_x, c, format); + } + while ((counter < dst_width || src_x + 1 == src_width) && dst_x < dst_width) { + counter += src_width; + + for (unsigned c = 0; c < channels; c++) { + set_raw_channel_to_row(out_data, dst_x, c, avg[c], format); + } + dst_x++; + } + counter -= dst_width; + } + } + return got_data; +} + +bool ImagePipelineNodeExtract::get_next_row_data(std::uint8_t* out_data) +{ + bool got_data = true; + + while (current_line_ < offset_y_) { + got_data &= source_.get_next_row_data(cached_line_.data()); + current_line_++; + } + if (current_line_ >= offset_y_ + source_.get_height()) { + std::fill(out_data, out_data + get_row_bytes(), 0); + current_line_++; + return got_data; + } + // now we're sure that the following holds: + // offset_y_ <= current_line_ < offset_y_ + source_.get_height()) + got_data &= source_.get_next_row_data(cached_line_.data()); + + auto format = get_format(); + auto x_src_width = source_.get_width() > offset_x_ ? source_.get_width() - offset_x_ : 0; + x_src_width = std::min(x_src_width, width_); + auto x_pad_after = width_ > x_src_width ? width_ - x_src_width : 0; + + if (get_pixel_format_depth(format) < 8) { + // we need to copy pixels one-by-one as there's no per-bit addressing + for (std::size_t i = 0; i < x_src_width; ++i) { + auto pixel = get_raw_pixel_from_row(cached_line_.data(), i + offset_x_, format); + set_raw_pixel_to_row(out_data, i, pixel, format); + } + for (std::size_t i = 0; i < x_pad_after; ++i) { + set_raw_pixel_to_row(out_data, i + x_src_width, RawPixel{}, format); + } + } else { + std::size_t bpp = get_pixel_format_depth(format) / 8; + if (x_src_width > 0) { + std::memcpy(out_data, cached_line_.data() + offset_x_ * bpp, + x_src_width * bpp); + } + if (x_pad_after > 0) { + std::fill(out_data + x_src_width * bpp, + out_data + (x_src_width + x_pad_after) * bpp, 0); + } + } + + current_line_++; + + return got_data; +} + +ImagePipelineNodeCalibrate::ImagePipelineNodeCalibrate(ImagePipelineNode& source, + const std::vector& bottom, + const std::vector& top) : + source_{source} +{ + auto size = std::min(bottom.size(), top.size()); + offset_.reserve(size); + multiplier_.reserve(size); + + for (std::size_t i = 0; i < size; ++i) { + offset_.push_back(bottom[i] / 65535.0f); + multiplier_.push_back(65535.0f / (top[i] - bottom[i])); + } +} + +bool ImagePipelineNodeCalibrate::get_next_row_data(std::uint8_t* out_data) +{ + bool ret = source_.get_next_row_data(out_data); + + auto format = get_format(); + auto depth = get_pixel_format_depth(format); + std::size_t max_value = 1; + switch (depth) { + case 8: max_value = 255; break; + case 16: max_value = 65535; break; + default: + throw SaneException("Unsupported depth for calibration %d", depth); + } + unsigned channels = get_pixel_channels(format); + + std::size_t max_calib_i = offset_.size(); + std::size_t curr_calib_i = 0; + + for (std::size_t x = 0, width = get_width(); x < width && curr_calib_i < max_calib_i; ++x) { + for (unsigned ch = 0; ch < channels && curr_calib_i < max_calib_i; ++ch) { + std::int32_t value = get_raw_channel_from_row(out_data, x, ch, format); + + float value_f = static_cast(value) / max_value; + value_f = (value_f - offset_[curr_calib_i]) * multiplier_[curr_calib_i]; + value_f = std::round(value_f * max_value); + value = clamp(static_cast(value_f), 0, max_value); + set_raw_channel_to_row(out_data, x, ch, value, format); + + curr_calib_i++; + } + } + return ret; +} + +ImagePipelineNodeDebug::ImagePipelineNodeDebug(ImagePipelineNode& source, + const std::string& path) : + source_(source), + path_{path}, + buffer_{source_.get_row_bytes()} +{} + +ImagePipelineNodeDebug::~ImagePipelineNodeDebug() +{ + catch_all_exceptions(__func__, [&]() + { + if (buffer_.empty()) + return; + + auto format = get_format(); + buffer_.linearize(); + sanei_genesys_write_pnm_file(path_.c_str(), buffer_.get_front_row_ptr(), + get_pixel_format_depth(format), + get_pixel_channels(format), + get_width(), buffer_.height()); + }); +} + +bool ImagePipelineNodeDebug::get_next_row_data(std::uint8_t* out_data) +{ + buffer_.push_back(); + bool got_data = source_.get_next_row_data(out_data); + std::memcpy(buffer_.get_back_row_ptr(), out_data, get_row_bytes()); + return got_data; +} + +std::size_t ImagePipelineStack::get_input_width() const +{ + ensure_node_exists(); + return nodes_.front()->get_width(); +} + +std::size_t ImagePipelineStack::get_input_height() const +{ + ensure_node_exists(); + return nodes_.front()->get_height(); +} + +PixelFormat ImagePipelineStack::get_input_format() const +{ + ensure_node_exists(); + return nodes_.front()->get_format(); +} + +std::size_t ImagePipelineStack::get_input_row_bytes() const +{ + ensure_node_exists(); + return nodes_.front()->get_row_bytes(); +} + +std::size_t ImagePipelineStack::get_output_width() const +{ + ensure_node_exists(); + return nodes_.back()->get_width(); +} + +std::size_t ImagePipelineStack::get_output_height() const +{ + ensure_node_exists(); + return nodes_.back()->get_height(); +} + +PixelFormat ImagePipelineStack::get_output_format() const +{ + ensure_node_exists(); + return nodes_.back()->get_format(); +} + +std::size_t ImagePipelineStack::get_output_row_bytes() const +{ + ensure_node_exists(); + return nodes_.back()->get_row_bytes(); +} + +void ImagePipelineStack::ensure_node_exists() const +{ + if (nodes_.empty()) { + throw SaneException("The pipeline does not contain any nodes"); + } +} + +void ImagePipelineStack::clear() +{ + // we need to destroy the nodes back to front, so that the destructors still have valid + // references to sources + for (auto it = nodes_.rbegin(); it != nodes_.rend(); ++it) { + it->reset(); + } + nodes_.clear(); +} + +std::vector ImagePipelineStack::get_all_data() +{ + auto row_bytes = get_output_row_bytes(); + auto height = get_output_height(); + + std::vector ret; + ret.resize(row_bytes * height); + + for (std::size_t i = 0; i < height; ++i) { + get_next_row_data(ret.data() + row_bytes * i); + } + return ret; +} + +Image ImagePipelineStack::get_image() +{ + auto height = get_output_height(); + + Image ret; + ret.resize(get_output_width(), height, get_output_format()); + + for (std::size_t i = 0; i < height; ++i) { + get_next_row_data(ret.get_row_ptr(i)); + } + return ret; +} + +} // namespace genesys diff --git a/backend/genesys/image_pipeline.h b/backend/genesys/image_pipeline.h new file mode 100644 index 0000000..2986837 --- /dev/null +++ b/backend/genesys/image_pipeline.h @@ -0,0 +1,572 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_IMAGE_PIPELINE_H +#define BACKEND_GENESYS_IMAGE_PIPELINE_H + +#include "image.h" +#include "image_pixel.h" +#include "image_buffer.h" + +#include +#include +#include + +namespace genesys { + +class ImagePipelineNode +{ +public: + virtual ~ImagePipelineNode(); + + virtual std::size_t get_width() const = 0; + virtual std::size_t get_height() const = 0; + virtual PixelFormat get_format() const = 0; + + std::size_t get_row_bytes() const + { + return get_pixel_row_bytes(get_format(), get_width()); + } + + virtual bool eof() const = 0; + + // returns true if the row was filled successfully, false otherwise (e.g. if not enough data + // was available. + virtual bool get_next_row_data(std::uint8_t* out_data) = 0; +}; + +class ImagePipelineNodeBytesSource : public ImagePipelineNode +{ +public: + std::size_t remaining_bytes() const { return remaining_bytes_; } + void set_remaining_bytes(std::size_t bytes) { remaining_bytes_ = bytes; } + + std::size_t consume_remaining_bytes(std::size_t bytes); + +private: + std::size_t remaining_bytes_ = 0; +}; + +// A pipeline node that produces data from a callable +class ImagePipelineNodeCallableSource : public ImagePipelineNode +{ +public: + using ProducerCallback = std::function; + + ImagePipelineNodeCallableSource(std::size_t width, std::size_t height, PixelFormat format, + ProducerCallback producer) : + producer_{producer}, + width_{width}, + height_{height}, + format_{format} + {} + + std::size_t get_width() const override { return width_; } + std::size_t get_height() const override { return height_; } + PixelFormat get_format() const override { return format_; } + + bool eof() const override { return eof_; } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ProducerCallback producer_; + std::size_t width_ = 0; + std::size_t height_ = 0; + PixelFormat format_ = PixelFormat::UNKNOWN; + bool eof_ = false; +}; + +// A pipeline node that produces data from a callable requesting fixed-size chunks. +class ImagePipelineNodeBufferedCallableSource : public ImagePipelineNodeBytesSource +{ +public: + using ProducerCallback = std::function; + + ImagePipelineNodeBufferedCallableSource(std::size_t width, std::size_t height, + PixelFormat format, std::size_t input_batch_size, + ProducerCallback producer); + + std::size_t get_width() const override { return width_; } + std::size_t get_height() const override { return height_; } + PixelFormat get_format() const override { return format_; } + + bool eof() const override { return eof_; } + + bool get_next_row_data(std::uint8_t* out_data) override; + + std::size_t buffer_size() const { return buffer_.size(); } + std::size_t buffer_available() const { return buffer_.available(); } + +private: + ProducerCallback producer_; + std::size_t width_ = 0; + std::size_t height_ = 0; + PixelFormat format_ = PixelFormat::UNKNOWN; + + bool eof_ = false; + std::size_t curr_row_ = 0; + + ImageBuffer buffer_; +}; + +class ImagePipelineNodeBufferedGenesysUsb : public ImagePipelineNodeBytesSource +{ +public: + using ProducerCallback = std::function; + + ImagePipelineNodeBufferedGenesysUsb(std::size_t width, std::size_t height, + PixelFormat format, std::size_t total_size, + const FakeBufferModel& buffer_model, + ProducerCallback producer); + + std::size_t get_width() const override { return width_; } + std::size_t get_height() const override { return height_; } + PixelFormat get_format() const override { return format_; } + + bool eof() const override { return eof_; } + + bool get_next_row_data(std::uint8_t* out_data) override; + + std::size_t buffer_available() const { return buffer_.available(); } + +private: + ProducerCallback producer_; + std::size_t width_ = 0; + std::size_t height_ = 0; + PixelFormat format_ = PixelFormat::UNKNOWN; + + bool eof_ = false; + + ImageBufferGenesysUsb buffer_; +}; + +// A pipeline node that produces data from the given array. +class ImagePipelineNodeArraySource : public ImagePipelineNodeBytesSource +{ +public: + ImagePipelineNodeArraySource(std::size_t width, std::size_t height, PixelFormat format, + std::vector data); + + std::size_t get_width() const override { return width_; } + std::size_t get_height() const override { return height_; } + PixelFormat get_format() const override { return format_; } + + bool eof() const override { return eof_; } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + std::size_t width_ = 0; + std::size_t height_ = 0; + PixelFormat format_ = PixelFormat::UNKNOWN; + + bool eof_ = false; + + std::vector data_; + std::size_t next_row_ = 0; +}; + + +/// A pipeline node that produces data from the given image +class ImagePipelineNodeImageSource : public ImagePipelineNode +{ +public: + ImagePipelineNodeImageSource(const Image& source); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return next_row_ >= get_height(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + const Image& source_; + std::size_t next_row_ = 0; +}; + +// A pipeline node that converts between pixel formats +class ImagePipelineNodeFormatConvert : public ImagePipelineNode +{ +public: + ImagePipelineNodeFormatConvert(ImagePipelineNode& source, PixelFormat dst_format) : + source_(source), + dst_format_{dst_format} + {} + + ~ImagePipelineNodeFormatConvert() override = default; + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return dst_format_; } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + PixelFormat dst_format_; + std::vector buffer_; +}; + +// A pipeline node that handles data that comes out of segmented sensors. Note that the width of +// the output data does not necessarily match the input data width, because in many cases almost +// all width of the image needs to be read in order to desegment it. +class ImagePipelineNodeDesegment : public ImagePipelineNode +{ +public: + ImagePipelineNodeDesegment(ImagePipelineNode& source, + std::size_t output_width, + const std::vector& segment_order, + std::size_t segment_pixels, + std::size_t interleaved_lines, + std::size_t pixels_per_chunk); + + ImagePipelineNodeDesegment(ImagePipelineNode& source, + std::size_t output_width, + std::size_t segment_count, + std::size_t segment_pixels, + std::size_t interleaved_lines, + std::size_t pixels_per_chunk); + + ~ImagePipelineNodeDesegment() override = default; + + std::size_t get_width() const override { return output_width_; } + std::size_t get_height() const override { return source_.get_height() / interleaved_lines_; } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + std::size_t output_width_; + std::vector segment_order_; + std::size_t segment_pixels_ = 0; + std::size_t interleaved_lines_ = 0; + std::size_t pixels_per_chunk_ = 0; + + RowBuffer buffer_; +}; + +// A pipeline node that deinterleaves data on multiple lines +class ImagePipelineNodeDeinterleaveLines : public ImagePipelineNodeDesegment +{ +public: + ImagePipelineNodeDeinterleaveLines(ImagePipelineNode& source, + std::size_t interleaved_lines, + std::size_t pixels_per_chunk); +}; + +// A pipeline that swaps bytes in 16-bit components on big-endian systems +class ImagePipelineNodeSwap16BitEndian : public ImagePipelineNode +{ +public: + ImagePipelineNodeSwap16BitEndian(ImagePipelineNode& source); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + bool needs_swapping_ = false; +}; + +// A pipeline node that merges 3 mono lines into a color channel +class ImagePipelineNodeMergeMonoLines : public ImagePipelineNode +{ +public: + ImagePipelineNodeMergeMonoLines(ImagePipelineNode& source, + ColorOrder color_order); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height() / 3; } + PixelFormat get_format() const override { return output_format_; } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + static PixelFormat get_output_format(PixelFormat input_format, ColorOrder order); + + ImagePipelineNode& source_; + PixelFormat output_format_ = PixelFormat::UNKNOWN; + + RowBuffer buffer_; +}; + +// A pipeline node that splits a color channel into 3 mono lines +class ImagePipelineNodeSplitMonoLines : public ImagePipelineNode +{ +public: + ImagePipelineNodeSplitMonoLines(ImagePipelineNode& source); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height() * 3; } + PixelFormat get_format() const override { return output_format_; } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + static PixelFormat get_output_format(PixelFormat input_format); + + ImagePipelineNode& source_; + PixelFormat output_format_ = PixelFormat::UNKNOWN; + + std::vector buffer_; + unsigned next_channel_ = 0; +}; + +// A pipeline node that shifts colors across lines by the given offsets +class ImagePipelineNodeComponentShiftLines : public ImagePipelineNode +{ +public: + ImagePipelineNodeComponentShiftLines(ImagePipelineNode& source, + unsigned shift_r, unsigned shift_g, unsigned shift_b); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height() - extra_height_; } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + std::size_t extra_height_ = 0; + + std::array channel_shifts_; + + RowBuffer buffer_; +}; + +// A pipeline node that shifts pixels across lines by the given offsets (performs unstaggering) +class ImagePipelineNodePixelShiftLines : public ImagePipelineNode +{ +public: + constexpr static std::size_t MAX_SHIFTS = 2; + + ImagePipelineNodePixelShiftLines(ImagePipelineNode& source, + const std::vector& shifts); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height() - extra_height_; } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + std::size_t extra_height_ = 0; + + std::vector pixel_shifts_; + + RowBuffer buffer_; +}; + +// A pipeline node that extracts a sub-image from the image. Padding and cropping is done as needed. +// The class can't pad to the left of the image currently, as only positive offsets are accepted. +class ImagePipelineNodeExtract : public ImagePipelineNode +{ +public: + ImagePipelineNodeExtract(ImagePipelineNode& source, + std::size_t offset_x, std::size_t offset_y, + std::size_t width, std::size_t height); + + ~ImagePipelineNodeExtract() override; + + std::size_t get_width() const override { return width_; } + std::size_t get_height() const override { return height_; } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + std::size_t offset_x_ = 0; + std::size_t offset_y_ = 0; + std::size_t width_ = 0; + std::size_t height_ = 0; + + std::size_t current_line_ = 0; + std::vector cached_line_; +}; + +// A pipeline node that scales rows to the specified width by using a point filter +class ImagePipelineNodeScaleRows : public ImagePipelineNode +{ +public: + ImagePipelineNodeScaleRows(ImagePipelineNode& source, std::size_t width); + + std::size_t get_width() const override { return width_; } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + std::size_t width_ = 0; + + std::vector cached_line_; +}; + +// A pipeline node that mimics the calibration behavior on Genesys chips +class ImagePipelineNodeCalibrate : public ImagePipelineNode +{ +public: + + ImagePipelineNodeCalibrate(ImagePipelineNode& source, const std::vector& bottom, + const std::vector& top); + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + + std::vector offset_; + std::vector multiplier_; +}; + +class ImagePipelineNodeDebug : public ImagePipelineNode +{ +public: + ImagePipelineNodeDebug(ImagePipelineNode& source, const std::string& path); + ~ImagePipelineNodeDebug() override; + + std::size_t get_width() const override { return source_.get_width(); } + std::size_t get_height() const override { return source_.get_height(); } + PixelFormat get_format() const override { return source_.get_format(); } + + bool eof() const override { return source_.eof(); } + + bool get_next_row_data(std::uint8_t* out_data) override; + +private: + ImagePipelineNode& source_; + std::string path_; + RowBuffer buffer_; +}; + +class ImagePipelineStack +{ +public: + ImagePipelineStack() {} + ~ImagePipelineStack() { clear(); } + + std::size_t get_input_width() const; + std::size_t get_input_height() const; + PixelFormat get_input_format() const; + std::size_t get_input_row_bytes() const; + + std::size_t get_output_width() const; + std::size_t get_output_height() const; + PixelFormat get_output_format() const; + std::size_t get_output_row_bytes() const; + + ImagePipelineNode& front() { return *(nodes_.front().get()); } + + bool eof() const { return nodes_.back()->eof(); } + + void clear(); + + template + void push_first_node(Args&&... args) + { + if (!nodes_.empty()) { + throw SaneException("Trying to append first node when there are existing nodes"); + } + nodes_.emplace_back(std::unique_ptr(new Node(std::forward(args)...))); + } + + template + void push_node(Args&&... args) + { + ensure_node_exists(); + nodes_.emplace_back(std::unique_ptr(new Node(*nodes_.back(), + std::forward(args)...))); + } + + bool get_next_row_data(std::uint8_t* out_data) + { + return nodes_.back()->get_next_row_data(out_data); + } + + std::vector get_all_data(); + + Image get_image(); + +private: + void ensure_node_exists() const; + + std::vector> nodes_; +}; + +} // namespace genesys + +#endif // ifndef BACKEND_GENESYS_IMAGE_PIPELINE_H diff --git a/backend/genesys/image_pixel.cpp b/backend/genesys/image_pixel.cpp new file mode 100644 index 0000000..1b83e12 --- /dev/null +++ b/backend/genesys/image_pixel.cpp @@ -0,0 +1,509 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "image.h" + +#include + +namespace genesys { + +struct PixelFormatDesc +{ + PixelFormat format; + unsigned depth; + unsigned channels; + ColorOrder order; +}; + +const PixelFormatDesc s_known_pixel_formats[] = { + { PixelFormat::I1, 1, 1, ColorOrder::RGB }, + { PixelFormat::I8, 8, 1, ColorOrder::RGB }, + { PixelFormat::I16, 16, 1, ColorOrder::RGB }, + { PixelFormat::RGB111, 1, 3, ColorOrder::RGB }, + { PixelFormat::RGB888, 8, 3, ColorOrder::RGB }, + { PixelFormat::RGB161616, 16, 3, ColorOrder::RGB }, + { PixelFormat::BGR888, 8, 3, ColorOrder::BGR }, + { PixelFormat::BGR161616, 16, 3, ColorOrder::BGR }, +}; + + +ColorOrder get_pixel_format_color_order(PixelFormat format) +{ + for (const auto& desc : s_known_pixel_formats) { + if (desc.format == format) + return desc.order; + } + throw SaneException("Unknown pixel format %d", static_cast(format)); +} + + +unsigned get_pixel_format_depth(PixelFormat format) +{ + for (const auto& desc : s_known_pixel_formats) { + if (desc.format == format) + return desc.depth; + } + throw SaneException("Unknown pixel format %d", static_cast(format)); +} + +unsigned get_pixel_channels(PixelFormat format) +{ + for (const auto& desc : s_known_pixel_formats) { + if (desc.format == format) + return desc.channels; + } + throw SaneException("Unknown pixel format %d", static_cast(format)); +} + +std::size_t get_pixel_row_bytes(PixelFormat format, std::size_t width) +{ + std::size_t depth = get_pixel_format_depth(format) * get_pixel_channels(format); + std::size_t total_bits = depth * width; + return total_bits / 8 + ((total_bits % 8 > 0) ? 1 : 0); +} + +std::size_t get_pixels_from_row_bytes(PixelFormat format, std::size_t row_bytes) +{ + std::size_t depth = get_pixel_format_depth(format) * get_pixel_channels(format); + return (row_bytes * 8) / depth; +} + +PixelFormat create_pixel_format(unsigned depth, unsigned channels, ColorOrder order) +{ + for (const auto& desc : s_known_pixel_formats) { + if (desc.depth == depth && desc.channels == channels && desc.order == order) { + return desc.format; + } + } + throw SaneException("Unknown pixel format %d %d %d", depth, channels, + static_cast(order)); +} + +static inline unsigned read_bit(const std::uint8_t* data, std::size_t x) +{ + return (data[x / 8] >> (7 - (x % 8))) & 0x1; +} + +static inline void write_bit(std::uint8_t* data, std::size_t x, unsigned value) +{ + value = (value & 0x1) << (7 - (x % 8)); + std::uint8_t mask = 0x1 << (7 - (x % 8)); + + data[x / 8] = (data[x / 8] & ~mask) | (value & mask); +} + +Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x, PixelFormat format) +{ + switch (format) { + case PixelFormat::I1: { + std::uint16_t val = read_bit(data, x) ? 0xffff : 0x0000; + return Pixel(val, val, val); + } + case PixelFormat::RGB111: { + x *= 3; + std::uint16_t r = read_bit(data, x) ? 0xffff : 0x0000; + std::uint16_t g = read_bit(data, x + 1) ? 0xffff : 0x0000; + std::uint16_t b = read_bit(data, x + 2) ? 0xffff : 0x0000; + return Pixel(r, g, b); + } + case PixelFormat::I8: { + std::uint16_t val = std::uint16_t(data[x]) | (data[x] << 8); + return Pixel(val, val, val); + } + case PixelFormat::I16: { + x *= 2; + std::uint16_t val = std::uint16_t(data[x]) | (data[x + 1] << 8); + return Pixel(val, val, val); + } + case PixelFormat::RGB888: { + x *= 3; + std::uint16_t r = std::uint16_t(data[x]) | (data[x] << 8); + std::uint16_t g = std::uint16_t(data[x + 1]) | (data[x + 1] << 8); + std::uint16_t b = std::uint16_t(data[x + 2]) | (data[x + 2] << 8); + return Pixel(r, g, b); + } + case PixelFormat::BGR888: { + x *= 3; + std::uint16_t b = std::uint16_t(data[x]) | (data[x] << 8); + std::uint16_t g = std::uint16_t(data[x + 1]) | (data[x + 1] << 8); + std::uint16_t r = std::uint16_t(data[x + 2]) | (data[x + 2] << 8); + return Pixel(r, g, b); + } + case PixelFormat::RGB161616: { + x *= 6; + std::uint16_t r = std::uint16_t(data[x]) | (data[x + 1] << 8); + std::uint16_t g = std::uint16_t(data[x + 2]) | (data[x + 3] << 8); + std::uint16_t b = std::uint16_t(data[x + 4]) | (data[x + 5] << 8); + return Pixel(r, g, b); + } + case PixelFormat::BGR161616: { + x *= 6; + std::uint16_t b = std::uint16_t(data[x]) | (data[x + 1] << 8); + std::uint16_t g = std::uint16_t(data[x + 2]) | (data[x + 3] << 8); + std::uint16_t r = std::uint16_t(data[x + 4]) | (data[x + 5] << 8); + return Pixel(r, g, b); + } + default: + throw SaneException("Unknown pixel format %d", static_cast(format)); + } +} + +void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel, PixelFormat format) +{ + switch (format) { + case PixelFormat::I1: + write_bit(data, x, pixel.r & 0x8000 ? 1 : 0); + return; + case PixelFormat::RGB111: { + x *= 3; + write_bit(data, x, pixel.r & 0x8000 ? 1 : 0); + write_bit(data, x + 1,pixel.g & 0x8000 ? 1 : 0); + write_bit(data, x + 2, pixel.b & 0x8000 ? 1 : 0); + return; + } + case PixelFormat::I8: { + float val = (pixel.r >> 8) * 0.3f; + val += (pixel.g >> 8) * 0.59f; + val += (pixel.b >> 8) * 0.11f; + data[x] = static_cast(val); + return; + } + case PixelFormat::I16: { + x *= 2; + float val = pixel.r * 0.3f; + val += pixel.g * 0.59f; + val += pixel.b * 0.11f; + auto val16 = static_cast(val); + data[x] = val16 & 0xff; + data[x + 1] = (val16 >> 8) & 0xff; + return; + } + case PixelFormat::RGB888: { + x *= 3; + data[x] = pixel.r >> 8; + data[x + 1] = pixel.g >> 8; + data[x + 2] = pixel.b >> 8; + return; + } + case PixelFormat::BGR888: { + x *= 3; + data[x] = pixel.b >> 8; + data[x + 1] = pixel.g >> 8; + data[x + 2] = pixel.r >> 8; + return; + } + case PixelFormat::RGB161616: { + x *= 6; + data[x] = pixel.r & 0xff; + data[x + 1] = (pixel.r >> 8) & 0xff; + data[x + 2] = pixel.g & 0xff; + data[x + 3] = (pixel.g >> 8) & 0xff; + data[x + 4] = pixel.b & 0xff; + data[x + 5] = (pixel.b >> 8) & 0xff; + return; + } + case PixelFormat::BGR161616: + x *= 6; + data[x] = pixel.b & 0xff; + data[x + 1] = (pixel.b >> 8) & 0xff; + data[x + 2] = pixel.g & 0xff; + data[x + 3] = (pixel.g >> 8) & 0xff; + data[x + 4] = pixel.r & 0xff; + data[x + 5] = (pixel.r >> 8) & 0xff; + return; + default: + throw SaneException("Unknown pixel format %d", static_cast(format)); + } +} + +RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x, PixelFormat format) +{ + switch (format) { + case PixelFormat::I1: + return RawPixel(read_bit(data, x)); + case PixelFormat::RGB111: { + x *= 3; + return RawPixel(read_bit(data, x) << 2 | + (read_bit(data, x + 1) << 1) | + (read_bit(data, x + 2))); + } + case PixelFormat::I8: + return RawPixel(data[x]); + case PixelFormat::I16: { + x *= 2; + return RawPixel(data[x], data[x + 1]); + } + case PixelFormat::RGB888: + case PixelFormat::BGR888: { + x *= 3; + return RawPixel(data[x], data[x + 1], data[x + 2]); + } + case PixelFormat::RGB161616: + case PixelFormat::BGR161616: { + x *= 6; + return RawPixel(data[x], data[x + 1], data[x + 2], + data[x + 3], data[x + 4], data[x + 5]); + } + default: + throw SaneException("Unknown pixel format %d", static_cast(format)); + } +} + +void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel, PixelFormat format) +{ + switch (format) { + case PixelFormat::I1: + write_bit(data, x, pixel.data[0] & 0x1); + return; + case PixelFormat::RGB111: { + x *= 3; + write_bit(data, x, (pixel.data[0] >> 2) & 0x1); + write_bit(data, x + 1, (pixel.data[0] >> 1) & 0x1); + write_bit(data, x + 2, (pixel.data[0]) & 0x1); + return; + } + case PixelFormat::I8: + data[x] = pixel.data[0]; + return; + case PixelFormat::I16: { + x *= 2; + data[x] = pixel.data[0]; + data[x + 1] = pixel.data[1]; + return; + } + case PixelFormat::RGB888: + case PixelFormat::BGR888: { + x *= 3; + data[x] = pixel.data[0]; + data[x + 1] = pixel.data[1]; + data[x + 2] = pixel.data[2]; + return; + } + case PixelFormat::RGB161616: + case PixelFormat::BGR161616: { + x *= 6; + data[x] = pixel.data[0]; + data[x + 1] = pixel.data[1]; + data[x + 2] = pixel.data[2]; + data[x + 3] = pixel.data[3]; + data[x + 4] = pixel.data[4]; + data[x + 5] = pixel.data[5]; + return; + } + default: + throw SaneException("Unknown pixel format %d", static_cast(format)); + } +} + +std::uint16_t get_raw_channel_from_row(const std::uint8_t* data, std::size_t x, unsigned channel, + PixelFormat format) +{ + switch (format) { + case PixelFormat::I1: + return read_bit(data, x); + case PixelFormat::RGB111: + return read_bit(data, x * 3 + channel); + case PixelFormat::I8: + return data[x]; + case PixelFormat::I16: { + x *= 2; + return data[x] | (data[x + 1] << 8); + } + case PixelFormat::RGB888: + case PixelFormat::BGR888: + return data[x * 3 + channel]; + case PixelFormat::RGB161616: + case PixelFormat::BGR161616: + return data[x * 6 + channel * 2] | (data[x * 6 + channel * 2 + 1]) << 8; + default: + throw SaneException("Unknown pixel format %d", static_cast(format)); + } +} + +void set_raw_channel_to_row(std::uint8_t* data, std::size_t x, unsigned channel, + std::uint16_t pixel, PixelFormat format) +{ + switch (format) { + case PixelFormat::I1: + write_bit(data, x, pixel & 0x1); + return; + case PixelFormat::RGB111: { + write_bit(data, x * 3 + channel, pixel & 0x1); + return; + } + case PixelFormat::I8: + data[x] = pixel; + return; + case PixelFormat::I16: { + x *= 2; + data[x] = pixel; + data[x + 1] = pixel >> 8; + return; + } + case PixelFormat::RGB888: + case PixelFormat::BGR888: { + x *= 3; + data[x + channel] = pixel; + return; + } + case PixelFormat::RGB161616: + case PixelFormat::BGR161616: { + x *= 6; + data[x + channel * 2] = pixel; + data[x + channel * 2 + 1] = pixel >> 8; + return; + } + default: + throw SaneException("Unknown pixel format %d", static_cast(format)); + } +} + +template +Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x) +{ + return get_pixel_from_row(data, x, Format); +} + +template +void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel) +{ + set_pixel_to_row(data, x, pixel, Format); +} + +template +RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x) +{ + return get_raw_pixel_from_row(data, x, Format); +} + +template +void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel) +{ + set_raw_pixel_to_row(data, x, pixel, Format); +} + +template +std::uint16_t get_raw_channel_from_row(const std::uint8_t* data, std::size_t x, unsigned channel) +{ + return get_raw_channel_from_row(data, x, channel, Format); +} + +template +void set_raw_channel_to_row(std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel) +{ + set_raw_channel_to_row(data, x, channel, pixel, Format); +} + +template Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); +template Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); +template Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); +template Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); +template Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); +template Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); +template Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); +template Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); + +template RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); +template RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); +template RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); +template RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); +template RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); +template RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); +template RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); +template RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); + +template std::uint16_t get_raw_channel_from_row( + const std::uint8_t* data, std::size_t x, unsigned channel); +template std::uint16_t get_raw_channel_from_row( + const std::uint8_t* data, std::size_t x, unsigned channel); +template std::uint16_t get_raw_channel_from_row( + const std::uint8_t* data, std::size_t x, unsigned channel); +template std::uint16_t get_raw_channel_from_row( + const std::uint8_t* data, std::size_t x, unsigned channel); +template std::uint16_t get_raw_channel_from_row( + const std::uint8_t* data, std::size_t x, unsigned channel); +template std::uint16_t get_raw_channel_from_row( + const std::uint8_t* data, std::size_t x, unsigned channel); +template std::uint16_t get_raw_channel_from_row( + const std::uint8_t* data, std::size_t x, unsigned channel); +template std::uint16_t get_raw_channel_from_row + (const std::uint8_t* data, std::size_t x, unsigned channel); + +template void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel); +template void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel); +template void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel); +template void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel); +template void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel); +template void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel); +template void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel); +template void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel); + +template void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); +template void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); +template void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); +template void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); +template void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); +template void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); +template void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); +template void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); + +template void set_raw_channel_to_row( + std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel); +template void set_raw_channel_to_row( + std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel); +template void set_raw_channel_to_row( + std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel); +template void set_raw_channel_to_row( + std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel); +template void set_raw_channel_to_row( + std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel); +template void set_raw_channel_to_row( + std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel); +template void set_raw_channel_to_row( + std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel); +template void set_raw_channel_to_row( + std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel); + +} // namespace genesys diff --git a/backend/genesys/image_pixel.h b/backend/genesys/image_pixel.h new file mode 100644 index 0000000..2dda271 --- /dev/null +++ b/backend/genesys/image_pixel.h @@ -0,0 +1,144 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_IMAGE_PIXEL_H +#define BACKEND_GENESYS_IMAGE_PIXEL_H + +#include "enums.h" +#include +#include +#include + +namespace genesys { + +enum class PixelFormat +{ + UNKNOWN, + I1, + RGB111, + I8, + RGB888, + BGR888, + I16, + RGB161616, + BGR161616, +}; + +struct Pixel +{ + Pixel() = default; + Pixel(std::uint16_t red, std::uint16_t green, std::uint16_t blue) : + r{red}, g{green}, b{blue} {} + + std::uint16_t r = 0; + std::uint16_t g = 0; + std::uint16_t b = 0; + + bool operator==(const Pixel& other) const + { + return r == other.r && g == other.g && b == other.b; + } +}; + +struct RawPixel +{ + RawPixel() = default; + RawPixel(std::uint8_t d0) : data{d0, 0, 0, 0, 0, 0} {} + RawPixel(std::uint8_t d0, std::uint8_t d1) : data{d0, d1, 0, 0, 0, 0} {} + RawPixel(std::uint8_t d0, std::uint8_t d1, std::uint8_t d2) : data{d0, d1, d2, 0, 0, 0} {} + RawPixel(std::uint8_t d0, std::uint8_t d1, std::uint8_t d2, + std::uint8_t d3, std::uint8_t d4, std::uint8_t d5) : data{d0, d1, d2, d3, d4, d5} {} + std::uint8_t data[6] = {}; + + bool operator==(const RawPixel& other) const + { + return std::equal(std::begin(data), std::end(data), + std::begin(other.data)); + } +}; + +ColorOrder get_pixel_format_color_order(PixelFormat format); +unsigned get_pixel_format_depth(PixelFormat format); +unsigned get_pixel_channels(PixelFormat format); +std::size_t get_pixel_row_bytes(PixelFormat format, std::size_t width); + +std::size_t get_pixels_from_row_bytes(PixelFormat format, std::size_t row_bytes); + +PixelFormat create_pixel_format(unsigned depth, unsigned channels, ColorOrder order); + +// retrieves or sets the logical pixel values in 16-bit range. +Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x, PixelFormat format); +void set_pixel_to_row(std::uint8_t* data, std::size_t x, Pixel pixel, PixelFormat format); + +// retrieves or sets the physical pixel values. The low bytes of the RawPixel are interpreted as +// the retrieved values / values to set +RawPixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x, PixelFormat format); +void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel, PixelFormat format); + +// retrieves or sets the physical value of specific channel of the pixel. The channels are numbered +// in the same order as the pixel is laid out in memory, that is, whichever channel comes first +// has the index 0. E.g. 0-th channel in RGB888 is the red byte, but in BGR888 is the blue byte. +std::uint16_t get_raw_channel_from_row(const std::uint8_t* data, std::size_t x, unsigned channel, + PixelFormat format); +void set_raw_channel_to_row(std::uint8_t* data, std::size_t x, unsigned channel, std::uint16_t pixel, + PixelFormat format); + +template +Pixel get_pixel_from_row(const std::uint8_t* data, std::size_t x); +template +void set_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); + +template +Pixel get_raw_pixel_from_row(const std::uint8_t* data, std::size_t x); +template +void set_raw_pixel_to_row(std::uint8_t* data, std::size_t x, RawPixel pixel); + +template +std::uint16_t get_raw_channel_from_row(const std::uint8_t* data, std::size_t x, unsigned channel); +template +void set_raw_channel_to_row(std::uint8_t* data, std::size_t x, unsigned channel, + std::uint16_t pixel); + +} // namespace genesys + +#endif // BACKEND_GENESYS_IMAGE_PIXEL_H diff --git a/backend/genesys/low.cpp b/backend/genesys/low.cpp new file mode 100644 index 0000000..7937fcc --- /dev/null +++ b/backend/genesys/low.cpp @@ -0,0 +1,1994 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2010-2013 Stéphane Voltz + + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "low.h" +#include "assert.h" +#include "test_settings.h" + +#include "gl124_registers.h" +#include "gl646_registers.h" +#include "gl841_registers.h" +#include "gl843_registers.h" +#include "gl846_registers.h" +#include "gl847_registers.h" +#include "gl646_registers.h" + +#include +#include +#include + +/* ------------------------------------------------------------------------ */ +/* functions calling ASIC specific functions */ +/* ------------------------------------------------------------------------ */ + +namespace genesys { + +/** + * setup the hardware dependent functions + */ + +namespace gl124 { std::unique_ptr create_gl124_cmd_set(); } +namespace gl646 { std::unique_ptr create_gl646_cmd_set(); } +namespace gl841 { std::unique_ptr create_gl841_cmd_set(); } +namespace gl843 { std::unique_ptr create_gl843_cmd_set(); } +namespace gl846 { std::unique_ptr create_gl846_cmd_set(); } +namespace gl847 { std::unique_ptr create_gl847_cmd_set(); } + +void sanei_genesys_init_cmd_set(Genesys_Device* dev) +{ + DBG_INIT (); + DBG_HELPER(dbg); + switch (dev->model->asic_type) { + case AsicType::GL646: dev->cmd_set = gl646::create_gl646_cmd_set(); break; + case AsicType::GL841: dev->cmd_set = gl841::create_gl841_cmd_set(); break; + case AsicType::GL843: dev->cmd_set = gl843::create_gl843_cmd_set(); break; + case AsicType::GL845: // since only a few reg bits differs we handle both together + case AsicType::GL846: dev->cmd_set = gl846::create_gl846_cmd_set(); break; + case AsicType::GL847: dev->cmd_set = gl847::create_gl847_cmd_set(); break; + case AsicType::GL124: dev->cmd_set = gl124::create_gl124_cmd_set(); break; + default: throw SaneException(SANE_STATUS_INVAL, "unknown ASIC type"); + } +} + +/* ------------------------------------------------------------------------ */ +/* General IO and debugging functions */ +/* ------------------------------------------------------------------------ */ + +void sanei_genesys_write_file(const char* filename, const std::uint8_t* data, std::size_t length) +{ + DBG_HELPER(dbg); + std::FILE* out = std::fopen(filename, "w"); + if (!out) { + throw SaneException("could not open %s for writing: %s", filename, strerror(errno)); + } + std::fwrite(data, 1, length, out); + std::fclose(out); +} + +// Write data to a pnm file (e.g. calibration). For debugging only +// data is RGB or grey, with little endian byte order +void sanei_genesys_write_pnm_file(const char* filename, const std::uint8_t* data, int depth, + int channels, int pixels_per_line, int lines) +{ + DBG_HELPER_ARGS(dbg, "depth=%d, channels=%d, ppl=%d, lines=%d", depth, channels, + pixels_per_line, lines); + int count; + + std::FILE* out = std::fopen(filename, "w"); + if (!out) + { + throw SaneException("could not open %s for writing: %s\n", filename, strerror(errno)); + } + if(depth==1) + { + fprintf (out, "P4\n%d\n%d\n", pixels_per_line, lines); + } + else + { + std::fprintf(out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', pixels_per_line, lines, + static_cast(std::pow(static_cast(2), + static_cast(depth - 1)))); + } + if (channels == 3) + { + for (count = 0; count < (pixels_per_line * lines * 3); count++) + { + if (depth == 16) + fputc (*(data + 1), out); + fputc (*(data++), out); + if (depth == 16) + data++; + } + } + else + { + if (depth==1) + { + pixels_per_line/=8; + } + for (count = 0; count < (pixels_per_line * lines); count++) + { + switch (depth) + { + case 8: + fputc (*(data + count), out); + break; + case 16: + fputc (*(data + 1), out); + fputc (*(data), out); + data += 2; + break; + default: + fputc(data[count], out); + break; + } + } + } + std::fclose(out); +} + +void sanei_genesys_write_pnm_file16(const char* filename, const uint16_t* data, unsigned channels, + unsigned pixels_per_line, unsigned lines) +{ + DBG_HELPER_ARGS(dbg, "channels=%d, ppl=%d, lines=%d", channels, + pixels_per_line, lines); + + std::FILE* out = std::fopen(filename, "w"); + if (!out) { + throw SaneException("could not open %s for writing: %s\n", filename, strerror(errno)); + } + std::fprintf(out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', + pixels_per_line, lines, 256 * 256 - 1); + + for (unsigned count = 0; count < (pixels_per_line * lines * channels); count++) { + fputc(*data >> 8, out); + fputc(*data & 0xff, out); + data++; + } + std::fclose(out); +} + +bool is_supported_write_pnm_file_image_format(PixelFormat format) +{ + switch (format) { + case PixelFormat::I1: + case PixelFormat::RGB111: + case PixelFormat::I8: + case PixelFormat::RGB888: + case PixelFormat::I16: + case PixelFormat::RGB161616: + return true; + default: + return false; + } +} + +void sanei_genesys_write_pnm_file(const char* filename, const Image& image) +{ + if (!is_supported_write_pnm_file_image_format(image.get_format())) { + throw SaneException("Unsupported format %d", static_cast(image.get_format())); + } + + sanei_genesys_write_pnm_file(filename, image.get_row_ptr(0), + get_pixel_format_depth(image.get_format()), + get_pixel_channels(image.get_format()), + image.get_width(), image.get_height()); +} + +/* ------------------------------------------------------------------------ */ +/* Read and write RAM, registers and AFE */ +/* ------------------------------------------------------------------------ */ + +unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type) +{ + /* Genesys supports 0xFE00 maximum size in general, wheraus GL646 supports + 0xFFC0. We use 0xF000 because that's the packet limit in the Linux usbmon + USB capture stack. By default it limits packet size to b_size / 5 where + b_size is the size of the ring buffer. By default it's 300*1024, so the + packet is limited 61440 without any visibility to acquiring software. + */ + if (asic_type == AsicType::GL124 || + asic_type == AsicType::GL846 || + asic_type == AsicType::GL847) + { + return 0xeff0; + } + return 0xf000; +} + +// Set address for writing data +void sanei_genesys_set_buffer_address(Genesys_Device* dev, uint32_t addr) +{ + DBG_HELPER(dbg); + + if (dev->model->asic_type==AsicType::GL847 || + dev->model->asic_type==AsicType::GL845 || + dev->model->asic_type==AsicType::GL846 || + dev->model->asic_type==AsicType::GL124) + { + DBG(DBG_warn, "%s: shouldn't be used for GL846+ ASICs\n", __func__); + return; + } + + DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xfffffff0); + + addr = addr >> 4; + + dev->interface->write_register(0x2b, (addr & 0xff)); + + addr = addr >> 8; + dev->interface->write_register(0x2a, (addr & 0xff)); +} + +/* ------------------------------------------------------------------------ */ +/* Medium level functions */ +/* ------------------------------------------------------------------------ */ + +Status scanner_read_status(Genesys_Device& dev) +{ + DBG_HELPER(dbg); + std::uint16_t address = 0; + + switch (dev.model->asic_type) { + case AsicType::GL124: address = 0x101; break; + case AsicType::GL646: + case AsicType::GL841: + case AsicType::GL843: + case AsicType::GL845: + case AsicType::GL846: + case AsicType::GL847: address = 0x41; break; + default: throw SaneException("Unsupported asic type"); + } + + // same for all chips + constexpr std::uint8_t PWRBIT = 0x80; + constexpr std::uint8_t BUFEMPTY = 0x40; + constexpr std::uint8_t FEEDFSH = 0x20; + constexpr std::uint8_t SCANFSH = 0x10; + constexpr std::uint8_t HOMESNR = 0x08; + constexpr std::uint8_t LAMPSTS = 0x04; + constexpr std::uint8_t FEBUSY = 0x02; + constexpr std::uint8_t MOTORENB = 0x01; + + auto value = dev.interface->read_register(address); + Status status; + status.is_replugged = !(value & PWRBIT); + status.is_buffer_empty = value & BUFEMPTY; + status.is_feeding_finished = value & FEEDFSH; + status.is_scanning_finished = value & SCANFSH; + status.is_at_home = value & HOMESNR; + status.is_lamp_on = value & LAMPSTS; + status.is_front_end_busy = value & FEBUSY; + status.is_motor_enabled = value & MOTORENB; + + if (DBG_LEVEL >= DBG_io) { + debug_print_status(dbg, status); + } + + return status; +} + +Status scanner_read_reliable_status(Genesys_Device& dev) +{ + DBG_HELPER(dbg); + + scanner_read_status(dev); + dev.interface->sleep_ms(100); + return scanner_read_status(dev); +} + +void scanner_read_print_status(Genesys_Device& dev) +{ + scanner_read_status(dev); +} + +/** + * decodes and prints content of status register + * @param val value read from status register + */ +void debug_print_status(DebugMessageHelper& dbg, Status val) +{ + std::stringstream str; + str << val; + dbg.vlog(DBG_info, "status=%s\n", str.str().c_str()); +} + +#if 0 +/* returns pixels per line from register set */ +/*candidate for moving into chip specific files?*/ +static int +genesys_pixels_per_line (Genesys_Register_Set * reg) +{ + int pixels_per_line; + + pixels_per_line = reg->get8(0x32) * 256 + reg->get8(0x33); + pixels_per_line -= (reg->get8(0x30) * 256 + reg->get8(0x31)); + + return pixels_per_line; +} + +/* returns dpiset from register set */ +/*candidate for moving into chip specific files?*/ +static int +genesys_dpiset (Genesys_Register_Set * reg) +{ + return reg->get8(0x2c) * 256 + reg->get8(0x2d); +} +#endif + +/** read the number of valid words in scanner's RAM + * ie registers 42-43-44 + */ +// candidate for moving into chip specific files? +void sanei_genesys_read_valid_words(Genesys_Device* dev, unsigned int* words) +{ + DBG_HELPER(dbg); + + switch (dev->model->asic_type) + { + case AsicType::GL124: + *words = dev->interface->read_register(0x102) & 0x03; + *words = *words * 256 + dev->interface->read_register(0x103); + *words = *words * 256 + dev->interface->read_register(0x104); + *words = *words * 256 + dev->interface->read_register(0x105); + break; + + case AsicType::GL845: + case AsicType::GL846: + *words = dev->interface->read_register(0x42) & 0x02; + *words = *words * 256 + dev->interface->read_register(0x43); + *words = *words * 256 + dev->interface->read_register(0x44); + *words = *words * 256 + dev->interface->read_register(0x45); + break; + + case AsicType::GL847: + *words = dev->interface->read_register(0x42) & 0x03; + *words = *words * 256 + dev->interface->read_register(0x43); + *words = *words * 256 + dev->interface->read_register(0x44); + *words = *words * 256 + dev->interface->read_register(0x45); + break; + + default: + *words = dev->interface->read_register(0x44); + *words += dev->interface->read_register(0x43) * 256; + if (dev->model->asic_type == AsicType::GL646) { + *words += ((dev->interface->read_register(0x42) & 0x03) * 256 * 256); + } else { + *words += ((dev->interface->read_register(0x42) & 0x0f) * 256 * 256); + } + } + + DBG(DBG_proc, "%s: %d words\n", __func__, *words); +} + +/** read the number of lines scanned + * ie registers 4b-4c-4d + */ +void sanei_genesys_read_scancnt(Genesys_Device* dev, unsigned int* words) +{ + DBG_HELPER(dbg); + + if (dev->model->asic_type == AsicType::GL124) { + *words = (dev->interface->read_register(0x10b) & 0x0f) << 16; + *words += (dev->interface->read_register(0x10c) << 8); + *words += dev->interface->read_register(0x10d); + } + else + { + *words = dev->interface->read_register(0x4d); + *words += dev->interface->read_register(0x4c) * 256; + if (dev->model->asic_type == AsicType::GL646) { + *words += ((dev->interface->read_register(0x4b) & 0x03) * 256 * 256); + } else { + *words += ((dev->interface->read_register(0x4b) & 0x0f) * 256 * 256); + } + } + + DBG(DBG_proc, "%s: %d lines\n", __func__, *words); +} + +/** @brief Check if the scanner's internal data buffer is empty + * @param *dev device to test for data + * @param *empty return value + * @return empty will be set to true if there is no scanned data. + **/ +bool sanei_genesys_is_buffer_empty(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + + dev->interface->sleep_ms(1); + + auto status = scanner_read_status(*dev); + + if (status.is_buffer_empty) { + /* fix timing issue on USB3 (or just may be too fast) hardware + * spotted by John S. Weber + */ + dev->interface->sleep_ms(1); + DBG(DBG_io2, "%s: buffer is empty\n", __func__); + return true; + } + + + DBG(DBG_io, "%s: buffer is filled\n", __func__); + return false; +} + +void wait_until_buffer_non_empty(Genesys_Device* dev, bool check_status_twice) +{ + // FIXME: reduce MAX_RETRIES once tests are updated + const unsigned MAX_RETRIES = 100000; + for (unsigned i = 0; i < MAX_RETRIES; ++i) { + + if (check_status_twice) { + // FIXME: this only to preserve previous behavior, can be removed + scanner_read_status(*dev); + } + + bool empty = sanei_genesys_is_buffer_empty(dev); + dev->interface->sleep_ms(10); + if (!empty) + return; + } + throw SaneException(SANE_STATUS_IO_ERROR, "failed to read data"); +} + +void wait_until_has_valid_words(Genesys_Device* dev) +{ + unsigned words = 0; + unsigned sleep_time_ms = 10; + + for (unsigned wait_ms = 0; wait_ms < 50000; wait_ms += sleep_time_ms) { + sanei_genesys_read_valid_words(dev, &words); + if (words != 0) + break; + dev->interface->sleep_ms(sleep_time_ms); + } + + if (words == 0) { + throw SaneException(SANE_STATUS_IO_ERROR, "timeout, buffer does not get filled"); + } +} + +// Read data (e.g scanned image) from scan buffer +void sanei_genesys_read_data_from_scanner(Genesys_Device* dev, uint8_t* data, size_t size) +{ + DBG_HELPER_ARGS(dbg, "size = %zu bytes", size); + + if (size & 1) + DBG(DBG_info, "WARNING %s: odd number of bytes\n", __func__); + + wait_until_has_valid_words(dev); + + dev->interface->bulk_read_data(0x45, data, size); +} + +Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session, + std::size_t total_bytes) +{ + DBG_HELPER(dbg); + + auto format = create_pixel_format(session.params.depth, + dev->model->is_cis ? 1 : session.params.channels, + dev->model->line_mode_color_order); + + auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw); + auto height = session.output_line_count * (dev->model->is_cis ? session.params.channels : 1); + + Image image(width, height, format); + + auto max_bytes = image.get_row_bytes() * height; + if (total_bytes > max_bytes) { + throw SaneException("Trying to read too much data %zu (max %zu)", total_bytes, max_bytes); + } + if (total_bytes != max_bytes) { + DBG(DBG_info, "WARNING %s: trying to read not enough data (%zu, full fill %zu\n", __func__, + total_bytes, max_bytes); + } + + sanei_genesys_read_data_from_scanner(dev, image.get_row_ptr(0), total_bytes); + + ImagePipelineStack pipeline; + pipeline.push_first_node(image); + + if ((dev->model->flags & GENESYS_FLAG_16BIT_DATA_INVERTED) && session.params.depth == 16) { + dev->pipeline.push_node(); + } + +#ifdef WORDS_BIGENDIAN + if (depth == 16) { + dev->pipeline.push_node(); + } +#endif + + if (dev->model->is_cis && session.params.channels == 3) { + dev->pipeline.push_node(dev->model->line_mode_color_order); + } + + if (dev->pipeline.get_output_format() == PixelFormat::BGR888) { + dev->pipeline.push_node(PixelFormat::RGB888); + } + + if (dev->pipeline.get_output_format() == PixelFormat::BGR161616) { + dev->pipeline.push_node(PixelFormat::RGB161616); + } + + return pipeline.get_image(); +} + +void sanei_genesys_read_feed_steps(Genesys_Device* dev, unsigned int* steps) +{ + DBG_HELPER(dbg); + + if (dev->model->asic_type == AsicType::GL124) { + *steps = (dev->interface->read_register(0x108) & 0x1f) << 16; + *steps += (dev->interface->read_register(0x109) << 8); + *steps += dev->interface->read_register(0x10a); + } + else + { + *steps = dev->interface->read_register(0x4a); + *steps += dev->interface->read_register(0x49) * 256; + if (dev->model->asic_type == AsicType::GL646) { + *steps += ((dev->interface->read_register(0x48) & 0x03) * 256 * 256); + } else if (dev->model->asic_type == AsicType::GL841) { + *steps += ((dev->interface->read_register(0x48) & 0x0f) * 256 * 256); + } else { + *steps += ((dev->interface->read_register(0x48) & 0x1f) * 256 * 256); + } + } + + DBG(DBG_proc, "%s: %d steps\n", __func__, *steps); +} + +void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, bool set) +{ + static const uint8_t REG_0x03_LAMPPWR = 0x10; + + if (set) { + regs.find_reg(0x03).value |= REG_0x03_LAMPPWR; + + if (dev->model->asic_type == AsicType::GL841) { + regs_set_exposure(dev->model->asic_type, regs, + sanei_genesys_fixup_exposure(sensor.exposure)); + regs.set8(0x19, 0x50); + } + + if (dev->model->asic_type == AsicType::GL843) { + regs_set_exposure(dev->model->asic_type, regs, sensor.exposure); + + // we don't actually turn on lamp on infrared scan + if ((dev->model->model_id == ModelId::CANON_8400F || + dev->model->model_id == ModelId::CANON_8600F || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) && + dev->settings.scan_method == ScanMethod::TRANSPARENCY_INFRARED) + { + regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR; + } + } + } else { + regs.find_reg(0x03).value &= ~REG_0x03_LAMPPWR; + + if (dev->model->asic_type == AsicType::GL841) { + regs_set_exposure(dev->model->asic_type, regs, {0x0101, 0x0101, 0x0101}); + regs.set8(0x19, 0xff); + } + + if (dev->model->asic_type == AsicType::GL843) { + if (dev->model->model_id == ModelId::PANASONIC_KV_SS080 || + dev->model->model_id == ModelId::HP_SCANJET_4850C || + dev->model->model_id == ModelId::HP_SCANJET_G4010 || + dev->model->model_id == ModelId::HP_SCANJET_G4050) + { + // BUG: datasheet says we shouldn't set exposure to zero + regs_set_exposure(dev->model->asic_type, regs, {0, 0, 0}); + } + } + } + regs.state.is_lamp_on = set; +} + +void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set) +{ + static const uint8_t REG_0x02_MTRPWR = 0x10; + + if (set) { + regs.find_reg(0x02).value |= REG_0x02_MTRPWR; + } else { + regs.find_reg(0x02).value &= ~REG_0x02_MTRPWR; + } + regs.state.is_motor_on = set; +} + +bool should_enable_gamma(const ScanSession& session, const Genesys_Sensor& sensor) +{ + if ((session.params.flags & ScanFlag::DISABLE_GAMMA) != ScanFlag::NONE) { + return false; + } + if (sensor.gamma[0] == 1.0f || sensor.gamma[1] == 1.0f || sensor.gamma[2] == 1.0f) { + return false; + } + if (session.params.depth == 16) + return false; + + return true; +} + +std::vector get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, + int color) +{ + if (!dev->gamma_override_tables[color].empty()) { + return dev->gamma_override_tables[color]; + } else { + std::vector ret; + sanei_genesys_create_default_gamma_table(dev, ret, sensor.gamma[color]); + return ret; + } +} + +/** @brief generates gamma buffer to transfer + * Generates gamma table buffer to send to ASIC. Applies + * contrast and brightness if set. + * @param dev device to set up + * @param bits number of bits used by gamma + * @param max value for gamma + * @param size of the gamma table + * @param gamma allocated gamma buffer to fill + */ +void sanei_genesys_generate_gamma_buffer(Genesys_Device* dev, + const Genesys_Sensor& sensor, + int bits, + int max, + int size, + uint8_t* gamma) +{ + DBG_HELPER(dbg); + std::vector rgamma = get_gamma_table(dev, sensor, GENESYS_RED); + std::vector ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN); + std::vector bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE); + + if(dev->settings.contrast!=0 || dev->settings.brightness!=0) + { + std::vector lut(65536); + sanei_genesys_load_lut(reinterpret_cast(lut.data()), + bits, + bits, + 0, + max, + dev->settings.contrast, + dev->settings.brightness); + for (int i = 0; i < size; i++) + { + uint16_t value=rgamma[i]; + value=lut[value]; + gamma[i * 2 + size * 0 + 0] = value & 0xff; + gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff; + + value=ggamma[i]; + value=lut[value]; + gamma[i * 2 + size * 2 + 0] = value & 0xff; + gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff; + + value=bgamma[i]; + value=lut[value]; + gamma[i * 2 + size * 4 + 0] = value & 0xff; + gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff; + } + } + else + { + for (int i = 0; i < size; i++) + { + uint16_t value=rgamma[i]; + gamma[i * 2 + size * 0 + 0] = value & 0xff; + gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff; + + value=ggamma[i]; + gamma[i * 2 + size * 2 + 0] = value & 0xff; + gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff; + + value=bgamma[i]; + gamma[i * 2 + size * 4 + 0] = value & 0xff; + gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff; + } + } +} + + +/** @brief send gamma table to scanner + * This function sends generic gamma table (ie ones built with + * provided gamma) or the user defined one if provided by + * fontend. Used by gl846+ ASICs + * @param dev device to write to + */ +void sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + int size; + int i; + + size = 256 + 1; + + /* allocate temporary gamma tables: 16 bits words, 3 channels */ + std::vector gamma(size * 2 * 3, 255); + + sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data()); + + // loop sending gamma tables NOTE: 0x01000000 not 0x10000000 + for (i = 0; i < 3; i++) { + // clear corresponding GMM_N bit + uint8_t val = dev->interface->read_register(0xbd); + val &= ~(0x01 << i); + dev->interface->write_register(0xbd, val); + + // clear corresponding GMM_F bit + val = dev->interface->read_register(0xbe); + val &= ~(0x01 << i); + dev->interface->write_register(0xbe, val); + + // FIXME: currently the last word of each gamma table is not initialied, so to work around + // unstable data, just set it to 0 which is the most likely value of uninitialized memory + // (proper value is probably 0xff) + gamma[size * 2 * i + size * 2 - 2] = 0; + gamma[size * 2 * i + size * 2 - 1] = 0; + + /* set GMM_Z */ + dev->interface->write_register(0xc5+2*i, gamma[size*2*i+1]); + dev->interface->write_register(0xc6+2*i, gamma[size*2*i]); + + dev->interface->write_ahb(0x01000000 + 0x200 * i, (size-1) * 2, + gamma.data() + i * size * 2+2); + } +} + +static unsigned align_int_up(unsigned num, unsigned alignment) +{ + unsigned mask = alignment - 1; + if (num & mask) + num = (num & ~mask) + alignment; + return num; +} + +void compute_session_buffer_sizes(AsicType asic, ScanSession& s) +{ + size_t line_bytes = s.output_line_bytes; + size_t line_bytes_stagger = s.output_line_bytes; + + if (asic != AsicType::GL646) { + // BUG: this is historical artifact and should be removed. Note that buffer sizes affect + // how often we request the scanner for data and thus change the USB traffic. + line_bytes_stagger = + multiply_by_depth_ceil(s.optical_pixels, s.params.depth) * s.params.channels; + } + + struct BufferConfig { + size_t* result_size = nullptr; + size_t lines = 0; + size_t lines_mult = 0; + size_t max_size = 0; // does not apply if 0 + size_t stagger_lines = 0; + + BufferConfig() = default; + BufferConfig(std::size_t* rs, std::size_t l, std::size_t lm, std::size_t ms, + std::size_t sl) : + result_size{rs}, + lines{l}, + lines_mult{lm}, + max_size{ms}, + stagger_lines{sl} + {} + }; + + std::array configs; + if (asic == AsicType::GL124 || asic == AsicType::GL843) { + configs = { { + { &s.buffer_size_read, 32, 1, 0, s.max_color_shift_lines + s.num_staggered_lines }, + { &s.buffer_size_lines, 32, 1, 0, s.max_color_shift_lines + s.num_staggered_lines }, + { &s.buffer_size_shrink, 16, 1, 0, 0 }, + { &s.buffer_size_out, 8, 1, 0, 0 }, + } }; + } else if (asic == AsicType::GL841) { + size_t max_buf = sanei_genesys_get_bulk_max_size(asic); + configs = { { + { &s.buffer_size_read, 8, 2, max_buf, s.max_color_shift_lines + s.num_staggered_lines }, + { &s.buffer_size_lines, 8, 2, max_buf, s.max_color_shift_lines + s.num_staggered_lines }, + { &s.buffer_size_shrink, 8, 1, max_buf, 0 }, + { &s.buffer_size_out, 8, 1, 0, 0 }, + } }; + } else { + configs = { { + { &s.buffer_size_read, 16, 1, 0, s.max_color_shift_lines + s.num_staggered_lines }, + { &s.buffer_size_lines, 16, 1, 0, s.max_color_shift_lines + s.num_staggered_lines }, + { &s.buffer_size_shrink, 8, 1, 0, 0 }, + { &s.buffer_size_out, 8, 1, 0, 0 }, + } }; + } + + for (BufferConfig& config : configs) { + size_t buf_size = line_bytes * config.lines; + if (config.max_size > 0 && buf_size > config.max_size) { + buf_size = (config.max_size / line_bytes) * line_bytes; + } + buf_size *= config.lines_mult; + buf_size += line_bytes_stagger * config.stagger_lines; + *config.result_size = buf_size; + } +} + +void compute_session_pipeline(const Genesys_Device* dev, ScanSession& s) +{ + auto channels = s.params.channels; + auto depth = s.params.depth; + + s.pipeline_needs_reorder = true; + if (channels != 3 && depth != 16) { + s.pipeline_needs_reorder = false; + } +#ifndef WORDS_BIGENDIAN + if (channels != 3 && depth == 16) { + s.pipeline_needs_reorder = false; + } + if (channels == 3 && depth == 16 && !dev->model->is_cis && + dev->model->line_mode_color_order == ColorOrder::RGB) + { + s.pipeline_needs_reorder = false; + } +#endif + if (channels == 3 && depth == 8 && !dev->model->is_cis && + dev->model->line_mode_color_order == ColorOrder::RGB) + { + s.pipeline_needs_reorder = false; + } + s.pipeline_needs_ccd = s.max_color_shift_lines + s.num_staggered_lines > 0; + s.pipeline_needs_shrink = dev->settings.requested_pixels != s.output_pixels; +} + +void compute_session_pixel_offsets(const Genesys_Device* dev, ScanSession& s, + const Genesys_Sensor& sensor) +{ + unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel(); + + if (dev->model->asic_type == AsicType::GL646) { + + // startx cannot be below dummy pixel value + s.pixel_startx = sensor.dummy_pixel; + if (has_flag(s.params.flags, ScanFlag::USE_XCORRECTION) && sensor.ccd_start_xoffset > 0) { + s.pixel_startx = sensor.ccd_start_xoffset; + } + s.pixel_startx += s.params.startx; + + if (sensor.stagger_config.stagger_at_resolution(s.params.xres, s.params.yres) > 0) { + s.pixel_startx |= 1; + } + + s.pixel_endx = s.pixel_startx + s.optical_pixels; + + s.pixel_startx /= sensor.ccd_pixels_per_system_pixel() * s.ccd_size_divisor; + s.pixel_endx /= sensor.ccd_pixels_per_system_pixel() * s.ccd_size_divisor; + + } else if (dev->model->asic_type == AsicType::GL841) { + s.pixel_startx = ((sensor.ccd_start_xoffset + s.params.startx) * s.optical_resolution) + / sensor.optical_res; + + s.pixel_startx += sensor.dummy_pixel + 1; + + if (s.num_staggered_lines > 0 && (s.pixel_startx & 1) == 0) { + s.pixel_startx++; + } + + /* In case of SHDAREA, we need to align start on pixel average factor, startx is + different than 0 only when calling for function to setup for scan, where shading data + needs to be align. + + NOTE: we can check the value of the register here, because we don't set this bit + anywhere except in initialization. + */ + const uint8_t REG_0x01_SHDAREA = 0x02; + if ((dev->reg.find_reg(0x01).value & REG_0x01_SHDAREA) != 0) { + unsigned average_factor = s.optical_resolution / s.params.xres; + s.pixel_startx = align_multiple_floor(s.pixel_startx, average_factor); + } + + s.pixel_endx = s.pixel_startx + s.optical_pixels; + + } else if (dev->model->asic_type == AsicType::GL843) { + + s.pixel_startx = (s.params.startx + sensor.dummy_pixel) / ccd_pixels_per_system_pixel; + s.pixel_endx = s.pixel_startx + s.optical_pixels / ccd_pixels_per_system_pixel; + + s.pixel_startx /= s.hwdpi_divisor; + s.pixel_endx /= s.hwdpi_divisor; + + // in case of stagger we have to start at an odd coordinate + bool stagger_starts_even = dev->model->model_id == ModelId::CANON_8400F; + if (s.num_staggered_lines > 0) { + if (!stagger_starts_even && (s.pixel_startx & 1) == 0) { + s.pixel_startx++; + s.pixel_endx++; + } else if (stagger_starts_even && (s.pixel_startx & 1) != 0) { + s.pixel_startx++; + s.pixel_endx++; + } + } + + } else if (dev->model->asic_type == AsicType::GL845 || + dev->model->asic_type == AsicType::GL846 || + dev->model->asic_type == AsicType::GL847) + { + s.pixel_startx = s.params.startx; + + if (s.num_staggered_lines > 0) { + s.pixel_startx |= 1; + } + + s.pixel_startx += sensor.ccd_start_xoffset * ccd_pixels_per_system_pixel; + s.pixel_endx = s.pixel_startx + s.optical_pixels_raw; + + s.pixel_startx /= s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel; + s.pixel_endx /= s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel; + + } else if (dev->model->asic_type == AsicType::GL124) { + s.pixel_startx = s.params.startx; + + if (s.num_staggered_lines > 0) { + s.pixel_startx |= 1; + } + + s.pixel_startx /= ccd_pixels_per_system_pixel; + // FIXME: should we add sensor.dummy_pxel to pixel_startx at this point? + s.pixel_endx = s.pixel_startx + s.optical_pixels / ccd_pixels_per_system_pixel; + + s.pixel_startx /= s.hwdpi_divisor * s.segment_count; + s.pixel_endx /= s.hwdpi_divisor * s.segment_count; + + std::uint32_t segcnt = (sensor.custom_regs.get_value(gl124::REG_SEGCNT) << 16) + + (sensor.custom_regs.get_value(gl124::REG_SEGCNT + 1) << 8) + + sensor.custom_regs.get_value(gl124::REG_SEGCNT + 2); + if (s.pixel_endx == segcnt) { + s.pixel_endx = 0; + } + } + + s.pixel_count_multiplier = sensor.pixel_count_multiplier; + + s.pixel_startx *= sensor.pixel_count_multiplier; + s.pixel_endx *= sensor.pixel_count_multiplier; +} + +void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor) +{ + DBG_HELPER(dbg); + + (void) dev; + s.params.assert_valid(); + + if (s.params.depth != 8 && s.params.depth != 16) { + throw SaneException("Unsupported depth setting %d", s.params.depth); + } + + unsigned ccd_pixels_per_system_pixel = sensor.ccd_pixels_per_system_pixel(); + + // compute optical and output resolutions + + if (dev->model->asic_type == AsicType::GL843) { + // FIXME: this may be incorrect, but need more scanners to test + s.hwdpi_divisor = sensor.get_hwdpi_divisor_for_dpi(s.params.xres); + } else { + s.hwdpi_divisor = sensor.get_hwdpi_divisor_for_dpi(s.params.xres * ccd_pixels_per_system_pixel); + } + + s.ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(s.params.xres); + + if (dev->model->asic_type == AsicType::GL646) { + s.optical_resolution = sensor.optical_res; + } else { + s.optical_resolution = sensor.optical_res / s.ccd_size_divisor; + } + s.output_resolution = s.params.xres; + + if (s.output_resolution > s.optical_resolution) { + throw std::runtime_error("output resolution higher than optical resolution"); + } + + // compute the number of optical pixels that will be acquired by the chip + s.optical_pixels = (s.params.pixels * s.optical_resolution) / s.output_resolution; + if (s.optical_pixels * s.output_resolution < s.params.pixels * s.optical_resolution) { + s.optical_pixels++; + } + + if (dev->model->asic_type == AsicType::GL841) { + if (s.optical_pixels & 1) + s.optical_pixels++; + } + + if (dev->model->asic_type == AsicType::GL646 && s.params.xres == 400) { + s.optical_pixels = (s.optical_pixels / 6) * 6; + } + + if (dev->model->asic_type == AsicType::GL843) { + // ensure the number of optical pixels is divisible by 2. + // In quarter-CCD mode optical_pixels is 4x larger than the actual physical number + s.optical_pixels = align_int_up(s.optical_pixels, 2 * s.ccd_size_divisor); + + if (dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7200I || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7300 || + dev->model->model_id == ModelId::PLUSTEK_OPTICFILM_7500I) + { + s.optical_pixels = align_int_up(s.optical_pixels, 16); + } + } + + // after all adjustments on the optical pixels have been made, compute the number of pixels + // to retrieve from the chip + s.output_pixels = (s.optical_pixels * s.output_resolution) / s.optical_resolution; + + // Note: staggering is not applied for calibration. Staggering starts at 2400 dpi + s.num_staggered_lines = 0; + if (!has_flag(s.params.flags, ScanFlag::IGNORE_LINE_DISTANCE)) + { + s.num_staggered_lines = sensor.stagger_config.stagger_at_resolution(s.params.xres, + s.params.yres); + } + + s.color_shift_lines_r = dev->model->ld_shift_r; + s.color_shift_lines_g = dev->model->ld_shift_g; + s.color_shift_lines_b = dev->model->ld_shift_b; + + if (dev->model->motor_id == MotorId::G4050 && s.params.yres > 600) { + // it seems base_dpi of the G4050 motor is changed above 600 dpi + s.color_shift_lines_r = (s.color_shift_lines_r * 3800) / dev->motor.base_ydpi; + s.color_shift_lines_g = (s.color_shift_lines_g * 3800) / dev->motor.base_ydpi; + s.color_shift_lines_b = (s.color_shift_lines_b * 3800) / dev->motor.base_ydpi; + } + + s.color_shift_lines_r = (s.color_shift_lines_r * s.params.yres) / dev->motor.base_ydpi; + s.color_shift_lines_g = (s.color_shift_lines_g * s.params.yres) / dev->motor.base_ydpi; + s.color_shift_lines_b = (s.color_shift_lines_b * s.params.yres) / dev->motor.base_ydpi; + + s.max_color_shift_lines = 0; + if (s.params.channels > 1 && !has_flag(s.params.flags, ScanFlag::IGNORE_LINE_DISTANCE)) { + s.max_color_shift_lines = std::max(s.color_shift_lines_r, std::max(s.color_shift_lines_g, + s.color_shift_lines_b)); + } + + s.output_line_count = s.params.lines + s.max_color_shift_lines + s.num_staggered_lines; + + s.output_channel_bytes = multiply_by_depth_ceil(s.output_pixels, s.params.depth); + s.output_line_bytes = s.output_channel_bytes * s.params.channels; + + s.segment_count = sensor.get_segment_count(); + + s.optical_pixels_raw = s.optical_pixels; + s.output_line_bytes_raw = s.output_line_bytes; + s.conseq_pixel_dist = 0; + + if (dev->model->asic_type == AsicType::GL845 || + dev->model->asic_type == AsicType::GL846 || + dev->model->asic_type == AsicType::GL847) + { + if (s.segment_count > 1) { + s.conseq_pixel_dist = sensor.segment_size; + + // in case of multi-segments sensor, we have to add the width of the sensor crossed by + // the scan area + unsigned extra_segment_scan_area = align_multiple_ceil(s.conseq_pixel_dist, 2); + extra_segment_scan_area *= s.segment_count - 1; + extra_segment_scan_area *= s.hwdpi_divisor * s.segment_count; + extra_segment_scan_area *= ccd_pixels_per_system_pixel; + + s.optical_pixels_raw += extra_segment_scan_area; + } + + s.output_line_bytes_raw = multiply_by_depth_ceil( + (s.optical_pixels_raw * s.output_resolution) / sensor.optical_res / s.segment_count, + s.params.depth); + } + + if (dev->model->asic_type == AsicType::GL841) { + if (dev->model->is_cis) { + s.output_line_bytes_raw = s.output_channel_bytes; + } + } + + if (dev->model->asic_type == AsicType::GL124) { + if (dev->model->is_cis) { + s.output_line_bytes_raw = s.output_channel_bytes; + } + s.conseq_pixel_dist = s.output_pixels / s.ccd_size_divisor / s.segment_count; + } + + if (dev->model->asic_type == AsicType::GL843) { + s.conseq_pixel_dist = s.output_pixels / s.segment_count; + } + + s.output_segment_pixel_group_count = 0; + if (dev->model->asic_type == AsicType::GL124 || + dev->model->asic_type == AsicType::GL843) + { + s.output_segment_pixel_group_count = multiply_by_depth_ceil( + s.output_pixels / s.ccd_size_divisor / s.segment_count, s.params.depth); + } + if (dev->model->asic_type == AsicType::GL845 || + dev->model->asic_type == AsicType::GL846 || + dev->model->asic_type == AsicType::GL847) + { + s.output_segment_pixel_group_count = multiply_by_depth_ceil( + s.optical_pixels / (s.hwdpi_divisor * s.segment_count * ccd_pixels_per_system_pixel), + s.params.depth); + } + + s.output_line_bytes_requested = multiply_by_depth_ceil( + s.params.get_requested_pixels() * s.params.channels, s.params.depth); + + s.output_total_bytes_raw = s.output_line_bytes_raw * s.output_line_count; + s.output_total_bytes = s.output_line_bytes * s.output_line_count; + + compute_session_buffer_sizes(dev->model->asic_type, s); + compute_session_pipeline(dev, s); + compute_session_pixel_offsets(dev, s, sensor); + + if (dev->model->asic_type == AsicType::GL124 || + dev->model->asic_type == AsicType::GL845 || + dev->model->asic_type == AsicType::GL846) + { + s.enable_ledadd = (s.params.channels == 1 && dev->model->is_cis && dev->settings.true_gray); + } + + if (dev->model->asic_type == AsicType::GL841 || + dev->model->asic_type == AsicType::GL843) + { + // no 16 bit gamma for this ASIC + if (s.params.depth == 16) { + s.params.flags |= ScanFlag::DISABLE_GAMMA; + } + } + + s.computed = true; + + DBG(DBG_info, "%s ", __func__); + debug_dump(DBG_info, s); +} + +static std::size_t get_usb_buffer_read_size(AsicType asic, const ScanSession& session) +{ + switch (asic) { + case AsicType::GL646: + // buffer not used on this chip set + return 1; + + case AsicType::GL124: + // BUG: we shouldn't multiply by channels here nor divide by ccd_size_divisor + return session.output_line_bytes_raw / session.ccd_size_divisor * session.params.channels; + + case AsicType::GL845: + case AsicType::GL846: + case AsicType::GL847: + // BUG: we shouldn't multiply by channels here + return session.output_line_bytes_raw * session.params.channels; + + case AsicType::GL843: + return session.output_line_bytes_raw * 2; + + default: + throw SaneException("Unknown asic type"); + } +} + +static FakeBufferModel get_fake_usb_buffer_model(const ScanSession& session) +{ + FakeBufferModel model; + model.push_step(session.buffer_size_read, 1); + + if (session.pipeline_needs_reorder) { + model.push_step(session.buffer_size_lines, session.output_line_bytes); + } + if (session.pipeline_needs_ccd) { + model.push_step(session.buffer_size_shrink, session.output_line_bytes); + } + if (session.pipeline_needs_shrink) { + model.push_step(session.buffer_size_out, session.output_line_bytes); + } + + return model; +} + +void build_image_pipeline(Genesys_Device* dev, const ScanSession& session) +{ + static unsigned s_pipeline_index = 0; + + s_pipeline_index++; + + auto format = create_pixel_format(session.params.depth, + dev->model->is_cis ? 1 : session.params.channels, + dev->model->line_mode_color_order); + auto depth = get_pixel_format_depth(format); + auto width = get_pixels_from_row_bytes(format, session.output_line_bytes_raw); + + auto read_data_from_usb = [dev](std::size_t size, std::uint8_t* data) + { + dev->interface->bulk_read_data(0x45, data, size); + return true; + }; + + auto lines = session.output_line_count * (dev->model->is_cis ? session.params.channels : 1); + + dev->pipeline.clear(); + + // FIXME: here we are complicating things for the time being to preserve the existing behaviour + // This allows to be sure that the changes to the image pipeline have not introduced + // regressions. + + if (session.segment_count > 1) { + // BUG: we're reading one line too much + dev->pipeline.push_first_node( + width, lines + 1, format, + get_usb_buffer_read_size(dev->model->asic_type, session), read_data_from_usb); + + auto output_width = session.output_segment_pixel_group_count * session.segment_count; + dev->pipeline.push_node(output_width, dev->segment_order, + session.conseq_pixel_dist, + 1, 1); + } else { + auto read_bytes_left_after_deseg = session.output_line_bytes * session.output_line_count; + if (dev->model->asic_type == AsicType::GL646) { + read_bytes_left_after_deseg *= dev->model->is_cis ? session.params.channels : 1; + } + + dev->pipeline.push_first_node( + width, lines, format, read_bytes_left_after_deseg, + get_fake_usb_buffer_model(session), read_data_from_usb); + } + + if (DBG_LEVEL >= DBG_io2) { + dev->pipeline.push_node("gl_pipeline_" + + std::to_string(s_pipeline_index) + + "_0_before_swap.pnm"); + } + + if ((dev->model->flags & GENESYS_FLAG_16BIT_DATA_INVERTED) && depth == 16) { + dev->pipeline.push_node(); + } + +#ifdef WORDS_BIGENDIAN + if (depth == 16) { + dev->pipeline.push_node(); + } +#endif + + if (DBG_LEVEL >= DBG_io2) { + dev->pipeline.push_node("gl_pipeline_" + + std::to_string(s_pipeline_index) + + "_1_after_swap.pnm"); + } + + if (dev->model->is_cis && session.params.channels == 3) { + dev->pipeline.push_node(dev->model->line_mode_color_order); + } + + if (dev->pipeline.get_output_format() == PixelFormat::BGR888) { + dev->pipeline.push_node(PixelFormat::RGB888); + } + + if (dev->pipeline.get_output_format() == PixelFormat::BGR161616) { + dev->pipeline.push_node(PixelFormat::RGB161616); + } + + if (session.max_color_shift_lines > 0 && session.params.channels == 3) { + dev->pipeline.push_node( + session.color_shift_lines_r, + session.color_shift_lines_g, + session.color_shift_lines_b); + } + + if (DBG_LEVEL >= DBG_io2) { + dev->pipeline.push_node("gl_pipeline_" + + std::to_string(s_pipeline_index) + + "_2_after_shift.pnm"); + } + + if (session.num_staggered_lines > 0) { + std::vector shifts{0, session.num_staggered_lines}; + dev->pipeline.push_node(shifts); + } + + if (DBG_LEVEL >= DBG_io2) { + dev->pipeline.push_node("gl_pipeline_" + + std::to_string(s_pipeline_index) + + "_3_after_stagger.pnm"); + } + + if ((dev->model->flags & GENESYS_FLAG_CALIBRATION_HOST_SIDE) && + !(dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) + { + dev->pipeline.push_node(dev->dark_average_data, + dev->white_average_data); + + if (DBG_LEVEL >= DBG_io2) { + dev->pipeline.push_node("gl_pipeline_" + + std::to_string(s_pipeline_index) + + "_4_after_calibrate.pnm"); + } + } + + if (session.output_pixels != session.params.get_requested_pixels()) { + dev->pipeline.push_node(session.params.get_requested_pixels()); + } + + auto read_from_pipeline = [dev](std::size_t size, std::uint8_t* out_data) + { + (void) size; // will be always equal to dev->pipeline.get_output_row_bytes() + return dev->pipeline.get_next_row_data(out_data); + }; + dev->pipeline_buffer = ImageBuffer{dev->pipeline.get_output_row_bytes(), + read_from_pipeline}; +} + +std::uint8_t compute_frontend_gain_wolfson(float value, float target_value) +{ + /* the flow of data through the frontend ADC is as follows (see e.g. WM8192 datasheet) + input + -> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) -> + -> apply gain (o = i * 208/(283-PGA[7:0]) + -> ADC + + Here we have some input data that was acquired with zero gain (PGA==0). + We want to compute gain such that the output would approach full ADC range (controlled by + target_value). + + We want to solve the following for {PGA}: + + {value} = {input} * 208 / (283 - 0) + {target_value} = {input} * 208 / (283 - {PGA}) + + The solution is the following equation: + + {PGA} = 283 * (1 - {value} / {target_value}) + */ + float gain = value / target_value; + int code = static_cast(283 * (1 - gain)); + return clamp(code, 0, 255); +} + +std::uint8_t compute_frontend_gain_analog_devices(float value, float target_value) +{ + /* The flow of data through the frontend ADC is as follows (see e.g. AD9826 datasheet) + input + -> apply offset (o = i + 300mV * (OFFSET[8] ? 1 : -1) * (OFFSET[7:0] / 127) + -> apply gain (o = i * 6 / (1 + 5 * ( 63 - PGA[5:0] ) / 63 ) ) + -> ADC + + We want to solve the following for {PGA}: + + {value} = {input} * 6 / (1 + 5 * ( 63 - 0) / 63 ) ) + {target_value} = {input} * 6 / (1 + 5 * ( 63 - {PGA}) / 63 ) ) + + The solution is the following equation: + + {PGA} = (378 / 5) * ({target_value} - {value} / {target_value}) + */ + int code = static_cast((378.0f / 5.0f) * ((target_value - value) / target_value)); + return clamp(code, 0, 63); +} + +std::uint8_t compute_frontend_gain(float value, float target_value, + FrontendType frontend_type) +{ + if (frontend_type == FrontendType::WOLFSON) { + return compute_frontend_gain_wolfson(value, target_value); + } + if (frontend_type == FrontendType::ANALOG_DEVICES) { + return compute_frontend_gain_analog_devices(value, target_value); + } + throw SaneException("Unknown frontend to compute gain for"); +} + +/** @brief initialize device + * Initialize backend and ASIC : registers, motor tables, and gamma tables + * then ensure scanner's head is at home. Designed for gl846+ ASICs. + * Detects cold boot (ie first boot since device plugged) in this case + * an extensice setup up is done at hardware level. + * + * @param dev device to initialize + * @param max_regs umber of maximum used registers + */ +void sanei_genesys_asic_init(Genesys_Device* dev, bool /*max_regs*/) +{ + DBG_HELPER(dbg); + + uint8_t val; + bool cold = true; + + // URB 16 control 0xc0 0x0c 0x8e 0x0b len 1 read 0x00 */ + dev->interface->get_usb_device().control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, + VALUE_GET_REGISTER, 0x00, 1, &val); + + DBG (DBG_io2, "%s: value=0x%02x\n", __func__, val); + DBG (DBG_info, "%s: device is %s\n", __func__, (val & 0x08) ? "USB 1.0" : "USB2.0"); + if (val & 0x08) + { + dev->usb_mode = 1; + } + else + { + dev->usb_mode = 2; + } + + /* Check if the device has already been initialized and powered up. We read register 0x06 and + check PWRBIT, if reset scanner has been freshly powered up. This bit will be set to later + so that following reads can detect power down/up cycle + */ + if (!is_testing_mode()) { + if (dev->interface->read_register(0x06) & 0x10) { + cold = false; + } + } + DBG (DBG_info, "%s: device is %s\n", __func__, cold ? "cold" : "warm"); + + /* don't do anything if backend is initialized and hardware hasn't been + * replug */ + if (dev->already_initialized && !cold) + { + DBG (DBG_info, "%s: already initialized, nothing to do\n", __func__); + return; + } + + // set up hardware and registers + dev->cmd_set->asic_boot(dev, cold); + + /* now hardware part is OK, set up device struct */ + dev->white_average_data.clear(); + dev->dark_average_data.clear(); + + dev->settings.color_filter = ColorFilter::RED; + + /* duplicate initial values into calibration registers */ + dev->calib_reg = dev->reg; + + const auto& sensor = sanei_genesys_find_sensor_any(dev); + + // Set analog frontend + dev->cmd_set->set_fe(dev, sensor, AFE_INIT); + + dev->already_initialized = true; + + // Move to home if needed + dev->cmd_set->move_back_home(dev, true); + dev->set_head_pos_zero(ScanHeadId::PRIMARY); + + // Set powersaving (default = 15 minutes) + dev->cmd_set->set_powersaving(dev, 15); +} + +void scanner_start_action(Genesys_Device& dev, bool start_motor) +{ + DBG_HELPER(dbg); + switch (dev.model->asic_type) { + case AsicType::GL646: + case AsicType::GL841: + case AsicType::GL843: + case AsicType::GL845: + case AsicType::GL846: + case AsicType::GL847: + case AsicType::GL124: + break; + default: + throw SaneException("Unsupported chip"); + } + + if (start_motor) { + dev.interface->write_register(0x0f, 0x01); + } else { + dev.interface->write_register(0x0f, 0); + } +} + +void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, const Genesys_Sensor& sensor, + unsigned dpihw) +{ + // same across GL646, GL841, GL843, GL846, GL847, GL124 + const uint8_t REG_0x05_DPIHW_MASK = 0xc0; + const uint8_t REG_0x05_DPIHW_600 = 0x00; + const uint8_t REG_0x05_DPIHW_1200 = 0x40; + const uint8_t REG_0x05_DPIHW_2400 = 0x80; + const uint8_t REG_0x05_DPIHW_4800 = 0xc0; + + if (sensor.register_dpihw_override != 0) { + dpihw = sensor.register_dpihw_override; + } + + uint8_t dpihw_setting; + switch (dpihw) { + case 600: + dpihw_setting = REG_0x05_DPIHW_600; + break; + case 1200: + dpihw_setting = REG_0x05_DPIHW_1200; + break; + case 2400: + dpihw_setting = REG_0x05_DPIHW_2400; + break; + case 4800: + dpihw_setting = REG_0x05_DPIHW_4800; + break; + default: + throw SaneException("Unknown dpihw value: %d", dpihw); + } + regs.set8_mask(0x05, dpihw_setting, REG_0x05_DPIHW_MASK); +} + +void regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs, + const SensorExposure& exposure) +{ + switch (asic_type) { + case AsicType::GL124: { + regs.set24(gl124::REG_EXPR, exposure.red); + regs.set24(gl124::REG_EXPG, exposure.green); + regs.set24(gl124::REG_EXPB, exposure.blue); + break; + } + case AsicType::GL646: { + regs.set16(gl646::REG_EXPR, exposure.red); + regs.set16(gl646::REG_EXPG, exposure.green); + regs.set16(gl646::REG_EXPB, exposure.blue); + break; + } + case AsicType::GL841: { + regs.set16(gl841::REG_EXPR, exposure.red); + regs.set16(gl841::REG_EXPG, exposure.green); + regs.set16(gl841::REG_EXPB, exposure.blue); + break; + } + case AsicType::GL843: { + regs.set16(gl843::REG_EXPR, exposure.red); + regs.set16(gl843::REG_EXPG, exposure.green); + regs.set16(gl843::REG_EXPB, exposure.blue); + break; + } + case AsicType::GL845: + case AsicType::GL846: { + regs.set16(gl846::REG_EXPR, exposure.red); + regs.set16(gl846::REG_EXPG, exposure.green); + regs.set16(gl846::REG_EXPB, exposure.blue); + break; + } + case AsicType::GL847: { + regs.set16(gl847::REG_EXPR, exposure.red); + regs.set16(gl847::REG_EXPG, exposure.green); + regs.set16(gl847::REG_EXPB, exposure.blue); + break; + } + default: + throw SaneException("Unsupported asic"); + } +} + +void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs) +{ + DBG_HELPER(dbg); + switch (asic_type) { + case AsicType::GL646: { + regs.find_reg(gl646::REG_0x01).value &= ~gl646::REG_0x01_SCAN; + break; + } + case AsicType::GL841: { + regs.find_reg(gl841::REG_0x01).value &= ~gl841::REG_0x01_SCAN; + break; + } + case AsicType::GL843: { + regs.find_reg(gl843::REG_0x01).value &= ~gl843::REG_0x01_SCAN; + break; + } + case AsicType::GL845: + case AsicType::GL846: { + regs.find_reg(gl846::REG_0x01).value &= ~gl846::REG_0x01_SCAN; + break; + } + case AsicType::GL847: { + regs.find_reg(gl847::REG_0x01).value &= ~gl847::REG_0x01_SCAN; + break; + } + case AsicType::GL124: { + regs.find_reg(gl124::REG_0x01).value &= ~gl124::REG_0x01_SCAN; + break; + } + default: + throw SaneException("Unsupported asic"); + } +} + +bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& regs) +{ + switch (asic_type) { + case AsicType::GL646: + return static_cast(regs.get8(gl646::REG_0x06) & gl646::REG_0x06_GAIN4); + case AsicType::GL841: + return static_cast(regs.get8(gl841::REG_0x06) & gl841::REG_0x06_GAIN4); + case AsicType::GL843: + return static_cast(regs.get8(gl843::REG_0x06) & gl843::REG_0x06_GAIN4); + case AsicType::GL845: + case AsicType::GL846: + return static_cast(regs.get8(gl846::REG_0x06) & gl846::REG_0x06_GAIN4); + case AsicType::GL847: + return static_cast(regs.get8(gl847::REG_0x06) & gl847::REG_0x06_GAIN4); + case AsicType::GL124: + return static_cast(regs.get8(gl124::REG_0x06) & gl124::REG_0x06_GAIN4); + default: + throw SaneException("Unsupported chipset"); + } +} + +/** + * Wait for the scanning head to park + */ +void sanei_genesys_wait_for_home(Genesys_Device* dev) +{ + DBG_HELPER(dbg); + + /* clear the parking status whatever the outcome of the function */ + dev->parking = false; + + if (is_testing_mode()) { + return; + } + + // read initial status, if head isn't at home and motor is on we are parking, so we wait. + // gl847/gl124 need 2 reads for reliable results + auto status = scanner_read_status(*dev); + dev->interface->sleep_ms(10); + status = scanner_read_status(*dev); + + if (status.is_at_home) { + DBG (DBG_info, + "%s: already at home\n", __func__); + return; + } + + unsigned timeout_ms = 200000; + unsigned elapsed_ms = 0; + do + { + dev->interface->sleep_ms(100); + elapsed_ms += 100; + + status = scanner_read_status(*dev); + } while (elapsed_ms < timeout_ms && !status.is_at_home); + + /* if after the timeout, head is still not parked, error out */ + if (elapsed_ms >= timeout_ms && !status.is_at_home) { + DBG (DBG_error, "%s: failed to reach park position in %dseconds\n", __func__, + timeout_ms / 1000); + throw SaneException(SANE_STATUS_IO_ERROR, "failed to reach park position"); + } +} + +/** @brief motor profile + * search for the database of motor profiles and get the best one. Each + * profile is at full step and at a reference exposure. Use first entry + * by default. + * @param motors motor profile database + * @param motor_type motor id + * @param exposure exposure time + * @return a pointer to a Motor_Profile struct + */ +const Motor_Profile& sanei_genesys_get_motor_profile(const std::vector& motors, + MotorId motor_id, int exposure) +{ + int idx; + + idx=-1; + for (std::size_t i = 0; i < motors.size(); ++i) { + // exact match + if (motors[i].motor_id == motor_id && motors[i].exposure==exposure) { + return motors[i]; + } + + // closest match + if (motors[i].motor_id == motor_id) { + /* if profile exposure is higher than the required one, + * the entry is a candidate for the closest match */ + if (motors[i].exposure == 0 || motors[i].exposure >= exposure) + { + if(idx<0) + { + /* no match found yet */ + idx=i; + } + else + { + /* test for better match */ + if(motors[i].exposuremodel->get_resolution_settings(dev->settings.scan_method); + return resolution_settings.get_min_resolution_y(); +} + +/** @brief returns the lowest possible dpi for the device + * Parses device entry to find lowest motor or sensor dpi. + * @param dev device description + * @return lowest motor resolution + */ +int sanei_genesys_get_lowest_dpi(Genesys_Device *dev) +{ + const auto& resolution_settings = dev->model->get_resolution_settings(dev->settings.scan_method); + return std::min(resolution_settings.get_min_resolution_x(), + resolution_settings.get_min_resolution_y()); +} + +/** @brief check is a cache entry may be used + * Compares current settings with the cache entry and return + * true if they are compatible. + * A calibration cache is compatible if color mode and x dpi match the user + * requested scan. In the case of CIS scanners, dpi isn't a criteria. + * flatbed cache entries are considred too old and then expires if they + * are older than the expiration time option, forcing calibration at least once + * then given time. */ +bool sanei_genesys_is_compatible_calibration(Genesys_Device* dev, + const ScanSession& session, + const Genesys_Calibration_Cache* cache, + bool for_overwrite) +{ + DBG_HELPER(dbg); +#ifdef HAVE_SYS_TIME_H + struct timeval time; +#endif + + bool compatible = true; + + const auto& dev_params = session.params; + + if (dev_params.scan_method != cache->params.scan_method) { + dbg.vlog(DBG_io, "incompatible: scan_method %d vs. %d\n", + static_cast(dev_params.scan_method), + static_cast(cache->params.scan_method)); + compatible = false; + } + + if (dev_params.xres != cache->params.xres) { + dbg.vlog(DBG_io, "incompatible: params.xres %d vs. %d\n", + dev_params.xres, cache->params.xres); + compatible = false; + } + + if (dev_params.yres != cache->params.yres) { + // exposure depends on selected sensor and we select the sensor according to yres + dbg.vlog(DBG_io, "incompatible: params.yres %d vs. %d\n", + dev_params.yres, cache->params.yres); + compatible = false; + } + + if (dev_params.channels != cache->params.channels) { + // exposure depends on total number of pixels at least on gl841 + dbg.vlog(DBG_io, "incompatible: params.channels %d vs. %d\n", + dev_params.channels, cache->params.channels); + compatible = false; + } + + if (dev_params.startx != cache->params.startx) { + // exposure depends on total number of pixels at least on gl841 + dbg.vlog(DBG_io, "incompatible: params.startx %d vs. %d\n", + dev_params.startx, cache->params.startx); + compatible = false; + } + + if (dev_params.pixels != cache->params.pixels) { + // exposure depends on total number of pixels at least on gl841 + dbg.vlog(DBG_io, "incompatible: params.pixels %d vs. %d\n", + dev_params.pixels, cache->params.pixels); + compatible = false; + } + + if (!compatible) + { + DBG (DBG_proc, "%s: completed, non compatible cache\n", __func__); + return false; + } + + /* a cache entry expires after afetr expiration time for non sheetfed scanners */ + /* this is not taken into account when overwriting cache entries */ +#ifdef HAVE_SYS_TIME_H + if (!for_overwrite && dev->settings.expiration_time >=0) + { + gettimeofday(&time, nullptr); + if ((time.tv_sec - cache->last_calibration > dev->settings.expiration_time*60) + && !dev->model->is_sheetfed + && (dev->settings.scan_method == ScanMethod::FLATBED)) + { + DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __func__); + return false; + } + } +#endif + + return true; +} + +/** @brief build lookup table for digital enhancements + * 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. + * @param lut pointer where to store the generated lut + * @param in_bits number of bits for in values + * @param out_bits number of bits of out values + * @param out_min minimal out value + * @param out_max maximal out value + * @param slope slope of the generated data + * @param offset offset of the generated data + */ +void sanei_genesys_load_lut(unsigned char* lut, + int in_bits, int out_bits, + int out_min, int out_max, + int slope, int offset) +{ + DBG_HELPER(dbg); + int i, j; + double shift, rise; + int max_in_val = (1 << in_bits) - 1; + int max_out_val = (1 << out_bits) - 1; + uint8_t *lut_p8 = lut; + uint16_t* lut_p16 = reinterpret_cast(lut); + + /* slope is converted to rise per unit run: + * first [-127,127] to [-.999,.999] + * then to [-PI/4,PI/4] then [0,PI/2] + * then take the tangent (T.O.A) + * then multiply by the normal linear slope + * because the table may not be square, i.e. 1024x256*/ + auto pi_4 = M_PI / 4.0; + rise = std::tan(static_cast(slope) / 128 * pi_4 + pi_4) * max_out_val / max_in_val; + + /* line must stay vertically centered, so figure + * out vertical offset at central input value */ + shift = static_cast(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 += static_cast(offset) / 127 * max_out_val / 2; + + for (i = 0; i <= max_in_val; i++) + { + j = static_cast(rise * i + shift); + + /* cap data to required range */ + if (j < out_min) + { + j = out_min; + } + else if (j > out_max) + { + j = out_max; + } + + /* copy result according to bit depth */ + if (out_bits <= 8) + { + *lut_p8 = j; + lut_p8++; + } + else + { + *lut_p16 = j; + lut_p16++; + } + } +} + +} // namespace genesys diff --git a/backend/genesys/low.h b/backend/genesys/low.h new file mode 100644 index 0000000..d7f5dd2 --- /dev/null +++ b/backend/genesys/low.h @@ -0,0 +1,525 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003 Oliver Rauch + Copyright (C) 2003, 2004 Henning Meier-Geinitz + Copyright (C) 2004, 2005 Gerhard Jaeger + Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2006 Laurent Charpentier + Parts of the structs have been taken from the gt68xx backend by + Sergey Vlasov et al. + + 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. +*/ + +#ifndef GENESYS_LOW_H +#define GENESYS_LOW_H + + +#include "../include/sane/config.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_MKDIR +#include +#include +#endif + +#include "../include/sane/sane.h" +#include "../include/sane/sanei.h" +#include "../include/sane/saneopts.h" + +#include "../include/sane/sanei_backend.h" +#include "../include/sane/sanei_usb.h" + +#include "../include/_stdint.h" + +#include "device.h" +#include "enums.h" +#include "error.h" +#include "fwd.h" +#include "usb_device.h" +#include "sensor.h" +#include "serialize.h" +#include "settings.h" +#include "static_init.h" +#include "status.h" +#include "register.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GENESYS_RED 0 +#define GENESYS_GREEN 1 +#define GENESYS_BLUE 2 + +/* Flags */ +#define GENESYS_FLAG_UNTESTED (1 << 0) /**< Print a warning for these scanners */ +#define GENESYS_FLAG_14BIT_GAMMA (1 << 1) /**< use 14bit Gamma table instead of 12 */ +#define GENESYS_FLAG_XPA (1 << 3) +#define GENESYS_FLAG_SKIP_WARMUP (1 << 4) /**< skip genesys_warmup() */ +/** @brief offset calibration flag + * signals that the scanner does offset calibration. In this case off_calibration() and + * coarse_gain_calibration() functions must be implemented + */ +#define GENESYS_FLAG_OFFSET_CALIBRATION (1 << 5) +#define GENESYS_FLAG_SEARCH_START (1 << 6) /**< do start search before scanning */ +#define GENESYS_FLAG_REPARK (1 << 7) /**< repark head (and check for lock) by + moving without scanning */ +#define GENESYS_FLAG_DARK_CALIBRATION (1 << 8) /**< do dark calibration */ + +#define GENESYS_FLAG_MUST_WAIT (1 << 10) /**< tells wether the scanner must wait for the head when parking */ + + +#define GENESYS_FLAG_HAS_UTA (1 << 11) /**< scanner has a transparency adapter */ + +#define GENESYS_FLAG_DARK_WHITE_CALIBRATION (1 << 12) /**< yet another calibration method. does white and dark shading in one run, depending on a black and a white strip*/ +#define GENESYS_FLAG_CUSTOM_GAMMA (1 << 13) /**< allow custom gamma tables */ +#define GENESYS_FLAG_NO_CALIBRATION (1 << 14) /**< allow scanners to use skip the calibration, needed for sheetfed scanners */ +#define GENESYS_FLAG_SIS_SENSOR (1 << 16) /**< handling of multi-segments sensors in software */ +#define GENESYS_FLAG_SHADING_NO_MOVE (1 << 17) /**< scanner doesn't move sensor during shading calibration */ +#define GENESYS_FLAG_SHADING_REPARK (1 << 18) /**< repark head between shading scans */ +#define GENESYS_FLAG_FULL_HWDPI_MODE (1 << 19) /**< scanner always use maximum hw dpi to setup the sensor */ +// scanner has infrared transparency scanning capability +#define GENESYS_FLAG_HAS_UTA_INFRARED (1 << 20) +// scanner calibration is handled on the host side +#define GENESYS_FLAG_CALIBRATION_HOST_SIDE (1 << 21) +#define GENESYS_FLAG_16BIT_DATA_INVERTED (1 << 22) + +#define GENESYS_HAS_NO_BUTTONS 0 /**< scanner has no supported button */ +#define GENESYS_HAS_SCAN_SW (1 << 0) /**< scanner has SCAN button */ +#define GENESYS_HAS_FILE_SW (1 << 1) /**< scanner has FILE button */ +#define GENESYS_HAS_COPY_SW (1 << 2) /**< scanner has COPY button */ +#define GENESYS_HAS_EMAIL_SW (1 << 3) /**< scanner has EMAIL button */ +#define GENESYS_HAS_PAGE_LOADED_SW (1 << 4) /**< scanner has paper in detection */ +#define GENESYS_HAS_OCR_SW (1 << 5) /**< scanner has OCR button */ +#define GENESYS_HAS_POWER_SW (1 << 6) /**< scanner has power button */ +#define GENESYS_HAS_CALIBRATE (1 << 7) /**< scanner has 'calibrate' software button to start calibration */ +#define GENESYS_HAS_EXTRA_SW (1 << 8) /**< scanner has extra function button */ + +/* USB control message values */ +#define REQUEST_TYPE_IN (USB_TYPE_VENDOR | USB_DIR_IN) +#define REQUEST_TYPE_OUT (USB_TYPE_VENDOR | USB_DIR_OUT) +#define REQUEST_REGISTER 0x0c +#define REQUEST_BUFFER 0x04 +#define VALUE_BUFFER 0x82 +#define VALUE_SET_REGISTER 0x83 +#define VALUE_READ_REGISTER 0x84 +#define VALUE_WRITE_REGISTER 0x85 +#define VALUE_INIT 0x87 +#define GPIO_OUTPUT_ENABLE 0x89 +#define GPIO_READ 0x8a +#define GPIO_WRITE 0x8b +#define VALUE_BUF_ENDACCESS 0x8c +#define VALUE_GET_REGISTER 0x8e +#define INDEX 0x00 + +/* todo: used? +#define VALUE_READ_STATUS 0x86 +*/ + +/* Read/write bulk data/registers */ +#define BULK_OUT 0x01 +#define BULK_IN 0x00 +#define BULK_RAM 0x00 +#define BULK_REGISTER 0x11 + +#define BULKOUT_MAXSIZE 0xF000 + +/* AFE values */ +#define AFE_INIT 1 +#define AFE_SET 2 +#define AFE_POWER_SAVE 4 + +#define LOWORD(x) ((uint16_t)((x) & 0xffff)) +#define HIWORD(x) ((uint16_t)((x) >> 16)) +#define LOBYTE(x) ((uint8_t)((x) & 0xFF)) +#define HIBYTE(x) ((uint8_t)((x) >> 8)) + +/* Global constants */ +/* TODO: emove this leftover of early backend days */ +#define MOTOR_SPEED_MAX 350 +#define DARK_VALUE 0 + +#define MAX_RESOLUTIONS 13 +#define MAX_DPI 4 + +namespace genesys { + +struct Genesys_USB_Device_Entry { + + Genesys_USB_Device_Entry(unsigned v, unsigned p, const Genesys_Model& m) : + vendor(v), product(p), model(m) + {} + + // USB vendor identifier + std::uint16_t vendor; + // USB product identifier + std::uint16_t product; + // Scanner model information + Genesys_Model model; +}; + +/** + * structure for motor database + */ +struct Motor_Profile +{ + MotorId motor_id; + int exposure; // used only to select the wanted motor + StepType step_type; // default step type for given exposure + MotorSlope slope; +}; + +extern StaticInit> gl843_motor_profiles; +extern StaticInit> gl846_motor_profiles; +extern StaticInit> gl847_motor_profiles; +extern StaticInit> gl124_motor_profiles; + +/*--------------------------------------------------------------------------*/ +/* common functions needed by low level specific functions */ +/*--------------------------------------------------------------------------*/ + +inline GenesysRegister* sanei_genesys_get_address(Genesys_Register_Set* regs, uint16_t addr) +{ + auto* ret = regs->find_reg_address(addr); + if (ret == nullptr) { + DBG(DBG_error, "%s: failed to find address for register 0x%02x, crash expected !\n", + __func__, addr); + } + return ret; +} + +extern void sanei_genesys_init_cmd_set(Genesys_Device* dev); + +// reads the status of the scanner +Status scanner_read_status(Genesys_Device& dev); + +// reads the status of the scanner reliably. This is done by reading the status twice. The first +// read sometimes returns the home sensor as engaged when this is not true. +Status scanner_read_reliable_status(Genesys_Device& dev); + +// reads and prints the scanner status +void scanner_read_print_status(Genesys_Device& dev); + +void debug_print_status(DebugMessageHelper& dbg, Status status); + +extern void sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t size, + uint8_t* data); + +extern void sanei_genesys_init_structs (Genesys_Device * dev); + +const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev); +const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, unsigned dpi, + unsigned channels, ScanMethod scan_method); +bool sanei_genesys_has_sensor(Genesys_Device* dev, unsigned dpi, unsigned channels, + ScanMethod scan_method); +Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, unsigned dpi, + unsigned channels, ScanMethod scan_method); + +std::vector> + sanei_genesys_find_sensors_all(Genesys_Device* dev, ScanMethod scan_method); +std::vector> + sanei_genesys_find_sensors_all_for_write(Genesys_Device* dev, ScanMethod scan_method); + +extern void sanei_genesys_init_shading_data(Genesys_Device* dev, const Genesys_Sensor& sensor, + int pixels_per_line); + +extern void sanei_genesys_read_valid_words(Genesys_Device* dev, unsigned int* steps); + +extern void sanei_genesys_read_scancnt(Genesys_Device* dev, unsigned int* steps); + +extern void sanei_genesys_read_feed_steps(Genesys_Device* dev, unsigned int* steps); + +void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor, + Genesys_Register_Set& regs, bool set); + +void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set); + +bool should_enable_gamma(const ScanSession& session, const Genesys_Sensor& sensor); + +/** Calculates the values of the Z{1,2}MOD registers. They are a phase correction to synchronize + with the line clock during acceleration and deceleration. + + two_table is true if moving is done by two tables, false otherwise. + + acceleration_steps is the number of steps for acceleration, i.e. the number written to + REG_STEPNO. + + move_steps number of steps to move, i.e. the number written to REG_FEEDL. + + buffer_acceleration_steps, the number of steps for acceleration when buffer condition is met, + i.e. the number written to REG_FWDSTEP. +*/ +void sanei_genesys_calculate_zmod(bool two_table, + uint32_t exposure_time, + const std::vector& slope_table, + unsigned acceleration_steps, + unsigned move_steps, + unsigned buffer_acceleration_steps, + uint32_t* out_z1, uint32_t* out_z2); + +extern void sanei_genesys_set_buffer_address(Genesys_Device* dev, uint32_t addr); + +unsigned sanei_genesys_get_bulk_max_size(AsicType asic_type); + +SANE_Int sanei_genesys_exposure_time2(Genesys_Device * dev, float ydpi, StepType step_type, + int endpixel, int led_exposure); + +MotorSlopeTable sanei_genesys_create_slope_table3(AsicType asic_type, const Genesys_Motor& motor, + StepType step_type, int exposure_time, + unsigned yres); + +void sanei_genesys_create_default_gamma_table(Genesys_Device* dev, + std::vector& gamma_table, float gamma); + +std::vector get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, + int color); + +void sanei_genesys_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor); + +extern void sanei_genesys_stop_motor(Genesys_Device* dev); + +extern void sanei_genesys_search_reference_point(Genesys_Device* dev, Genesys_Sensor& sensor, + const uint8_t* src_data, int start_pixel, int dpi, + int width, int height); + +// moves the scan head by the specified steps at the motor base dpi +void scanner_move(Genesys_Device& dev, ScanMethod scan_method, unsigned steps, Direction direction); + +void scanner_move_back_home(Genesys_Device& dev, bool wait_until_home); +void scanner_move_back_home_ta(Genesys_Device& dev); + +void scanner_clear_scan_and_feed_counts(Genesys_Device& dev); + +extern void sanei_genesys_write_file(const char* filename, const std::uint8_t* data, + std::size_t length); + +extern void sanei_genesys_write_pnm_file(const char* filename, const std::uint8_t* data, int depth, + int channels, int pixels_per_line, int lines); + +void sanei_genesys_write_pnm_file(const char* filename, const Image& image); + +extern void sanei_genesys_write_pnm_file16(const char* filename, const uint16_t *data, unsigned channels, + unsigned pixels_per_line, unsigned lines); + +void wait_until_buffer_non_empty(Genesys_Device* dev, bool check_status_twice = false); + +extern void sanei_genesys_read_data_from_scanner(Genesys_Device* dev, uint8_t* data, size_t size); + +Image read_unshuffled_image_from_scanner(Genesys_Device* dev, const ScanSession& session, + std::size_t total_bytes); + +void regs_set_exposure(AsicType asic_type, Genesys_Register_Set& regs, + const SensorExposure& exposure); + +void regs_set_optical_off(AsicType asic_type, Genesys_Register_Set& regs); + +void sanei_genesys_set_dpihw(Genesys_Register_Set& regs, const Genesys_Sensor& sensor, + unsigned dpihw); + +inline uint16_t sanei_genesys_fixup_exposure_value(uint16_t value) +{ + if ((value & 0xff00) == 0) { + value |= 0x100; + } + if ((value & 0x00ff) == 0) { + value |= 0x1; + } + return value; +} + +inline SensorExposure sanei_genesys_fixup_exposure(SensorExposure exposure) +{ + exposure.red = sanei_genesys_fixup_exposure_value(exposure.red); + exposure.green = sanei_genesys_fixup_exposure_value(exposure.green); + exposure.blue = sanei_genesys_fixup_exposure_value(exposure.blue); + return exposure; +} + +bool get_registers_gain4_bit(AsicType asic_type, const Genesys_Register_Set& regs); + +extern void sanei_genesys_wait_for_home(Genesys_Device* dev); + +extern void sanei_genesys_asic_init(Genesys_Device* dev, bool cold); + +void scanner_start_action(Genesys_Device& dev, bool start_motor); +void scanner_stop_action(Genesys_Device& dev); +void scanner_stop_action_no_move(Genesys_Device& dev, Genesys_Register_Set& regs); + +bool scanner_is_motor_stopped(Genesys_Device& dev); + +const Motor_Profile& sanei_genesys_get_motor_profile(const std::vector& motors, + MotorId motor_id, int exposure); + +MotorSlopeTable sanei_genesys_slope_table(AsicType asic_type, int dpi, int exposure, int base_dpi, + unsigned step_multiplier, + const Motor_Profile& motor_profile); + +MotorSlopeTable create_slope_table_fastest(AsicType asic_type, unsigned step_multiplier, + const Motor_Profile& motor_profile); + +/** @brief find lowest motor resolution for the device. + * Parses the resolution list for motor and + * returns the lowest value. + * @param dev for which to find the lowest motor resolution + * @return the lowest available motor resolution for the device + */ +extern +int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev); + +/** @brief find lowest resolution for the device. + * Parses the resolution list for motor and sensor and + * returns the lowest value. + * @param dev for which to find the lowest resolution + * @return the lowest available resolution for the device + */ +extern +int sanei_genesys_get_lowest_dpi(Genesys_Device *dev); + +bool sanei_genesys_is_compatible_calibration(Genesys_Device* dev, + const ScanSession& session, + const Genesys_Calibration_Cache* cache, + bool for_overwrite); + +extern void sanei_genesys_load_lut(unsigned char* lut, + int in_bits, int out_bits, + int out_min, int out_max, + int slope, int offset); + +extern void sanei_genesys_generate_gamma_buffer(Genesys_Device* dev, + const Genesys_Sensor& sensor, + int bits, + int max, + int size, + uint8_t* gamma); + +void compute_session(const Genesys_Device* dev, ScanSession& s, const Genesys_Sensor& sensor); + +void build_image_pipeline(Genesys_Device* dev, const ScanSession& session); + +std::uint8_t compute_frontend_gain(float value, float target_value, + FrontendType frontend_type); + +template +inline T abs_diff(T a, T b) +{ + if (a < b) { + return b - a; + } else { + return a - b; + } +} + +inline uint64_t align_multiple_floor(uint64_t x, uint64_t multiple) +{ + return (x / multiple) * multiple; +} + +inline uint64_t align_multiple_ceil(uint64_t x, uint64_t multiple) +{ + return ((x + multiple - 1) / multiple) * multiple; +} + +inline uint64_t multiply_by_depth_ceil(uint64_t pixels, uint64_t depth) +{ + if (depth == 1) { + return (pixels / 8) + ((pixels % 8) ? 1 : 0); + } else { + return pixels * (depth / 8); + } +} + +template +inline T clamp(const T& value, const T& lo, const T& hi) +{ + if (value < lo) + return lo; + if (value > hi) + return hi; + return value; +} + +/*---------------------------------------------------------------------------*/ +/* ASIC specific functions declarations */ +/*---------------------------------------------------------------------------*/ + +extern StaticInit> s_sensors; +extern StaticInit> s_frontends; +extern StaticInit> s_gpo; +extern StaticInit> s_motors; +extern StaticInit> s_usb_devices; + +void genesys_init_sensor_tables(); +void genesys_init_frontend_tables(); +void genesys_init_gpo_tables(); +void genesys_init_motor_tables(); +void genesys_init_motor_profile_tables(); +void genesys_init_usb_device_tables(); + +template +void debug_dump(unsigned level, const T& value) +{ + std::stringstream out; + out << value; + DBG(level, "%s\n", out.str().c_str()); +} + +} // namespace genesys + +#endif /* not GENESYS_LOW_H */ diff --git a/backend/genesys/motor.cpp b/backend/genesys/motor.cpp new file mode 100644 index 0000000..910266a --- /dev/null +++ b/backend/genesys/motor.cpp @@ -0,0 +1,180 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "motor.h" +#include "utilities.h" +#include + +namespace genesys { + +unsigned MotorSlope::get_table_step_shifted(unsigned step, StepType step_type) const +{ + // first two steps are always equal to the initial speed + if (step < 2) { + return initial_speed_w >> static_cast(step_type); + } + step--; + + float initial_speed_v = 1.0f / initial_speed_w; + float speed_v = std::sqrt(initial_speed_v * initial_speed_v + 2 * acceleration * step); + return static_cast(1.0f / speed_v) >> static_cast(step_type); +} + +float compute_acceleration_for_steps(unsigned initial_w, unsigned max_w, unsigned steps) +{ + float initial_speed_v = 1.0f / static_cast(initial_w); + float max_speed_v = 1.0f / static_cast(max_w); + return (max_speed_v * max_speed_v - initial_speed_v * initial_speed_v) / (2 * steps); +} + + +MotorSlope MotorSlope::create_from_steps(unsigned initial_w, unsigned max_w, + unsigned steps) +{ + MotorSlope slope; + slope.initial_speed_w = initial_w; + slope.max_speed_w = max_w; + slope.acceleration = compute_acceleration_for_steps(initial_w, max_w, steps); + return slope; +} + +void MotorSlopeTable::slice_steps(unsigned count) +{ + if (count >= table.size() || count > steps_count) { + throw SaneException("Excepssive steps count"); + } + steps_count = count; +} + +unsigned get_slope_table_max_size(AsicType asic_type) +{ + switch (asic_type) { + case AsicType::GL646: + case AsicType::GL841: return 255; + case AsicType::GL843: + case AsicType::GL845: + case AsicType::GL846: + case AsicType::GL847: + case AsicType::GL124: return 1024; + default: + throw SaneException("Unknown asic type"); + } +} + +MotorSlopeTable create_slope_table(const MotorSlope& slope, unsigned target_speed_w, + StepType step_type, unsigned steps_alignment, + unsigned min_size, unsigned max_size) +{ + DBG_HELPER_ARGS(dbg, "target_speed_w: %d, step_type: %d, steps_alignment: %d, min_size: %d", + target_speed_w, static_cast(step_type), steps_alignment, min_size); + MotorSlopeTable table; + + unsigned step_shift = static_cast(step_type); + + unsigned target_speed_shifted_w = target_speed_w >> step_shift; + unsigned max_speed_shifted_w = slope.max_speed_w >> step_shift; + + if (target_speed_shifted_w < max_speed_shifted_w) { + dbg.log(DBG_warn, "failed to reach target speed"); + } + + unsigned final_speed = std::max(target_speed_shifted_w, max_speed_shifted_w); + + table.table.reserve(max_size); + + while (table.table.size() < max_size - 1) { + unsigned current = slope.get_table_step_shifted(table.table.size(), step_type); + if (current <= final_speed) { + break; + } + table.table.push_back(current); + table.pixeltime_sum += current; + } + + // make sure the target speed (or the max speed if target speed is too high) is present in + // the table + table.table.push_back(final_speed); + table.pixeltime_sum += table.table.back(); + + // fill the table up to the specified size + while (table.table.size() < max_size - 1 && + (table.table.size() % steps_alignment != 0 || table.table.size() < min_size)) + { + table.table.push_back(table.table.back()); + table.pixeltime_sum += table.table.back(); + } + + table.steps_count = table.table.size(); + + // fill the rest of the table with the final speed + table.table.resize(max_size, final_speed); + + return table; +} + +std::ostream& operator<<(std::ostream& out, const MotorSlope& slope) +{ + out << "MotorSlope{\n" + << " initial_speed_w: " << slope.initial_speed_w << '\n' + << " max_speed_w: " << slope.max_speed_w << '\n' + << " a: " << slope.acceleration << '\n' + << '}'; + return out; +} + +std::ostream& operator<<(std::ostream& out, const Genesys_Motor& motor) +{ + out << "Genesys_Motor{\n" + << " id: " << static_cast(motor.id) << '\n' + << " base_ydpi: " << motor.base_ydpi << '\n' + << " optical_ydpi: " << motor.optical_ydpi << '\n' + << " slopes: " + << format_indent_braced_list(4, format_vector_indent_braced(4, "MotorSlope", + motor.slopes)) + << '}'; + return out; +} + +} // namespace genesys diff --git a/backend/genesys/motor.h b/backend/genesys/motor.h new file mode 100644 index 0000000..d80da6d --- /dev/null +++ b/backend/genesys/motor.h @@ -0,0 +1,177 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_MOTOR_H +#define BACKEND_GENESYS_MOTOR_H + +#include +#include +#include "enums.h" + +namespace genesys { + +/* Describes a motor acceleration curve. + + Definitions: + v - speed in steps per pixeltime + w - speed in pixel times per step. w = 1 / v + a - acceleration in steps per pixeltime squared + s - distance travelled in steps + t - time in pixeltime + + The physical mode defines the curve in physical quantities. We asssume that the scanner head + accelerates from standstill to the target speed uniformly. Then: + + v(t) = v(0) + a * t (2) + + Where `a` is acceleration, `t` is time. Also we can calculate the travelled distance `s`: + + s(t) = v(0) * t + a * t^2 / 2 (3) + + The actual motor slope is defined as the duration of each motor step. That means we need to + define speed in terms of travelled distance. + + Solving (3) for `t` gives: + + sqrt( v(0)^2 + 2 * a * s ) - v(0) + t(s) = --------------------------------- (4) + a + + Combining (4) and (2) will yield: + + v(s) = sqrt( v(0)^2 + 2 * a * s ) (5) + + The data in the slope struct MotorSlope corresponds to the above in the following way: + + maximum_start_speed is `w(0) = 1/v(0)` + + maximum_speed is defines maximum speed which should not be exceeded + + minimum_steps is not used + + g is `a` + + Given the start and target speeds on a known motor curve, `a` can be computed as follows: + + v(t1)^2 - v(t0)^2 + a = ----------------- (6) + 2 * s + + Here `v(t0)` and `v(t1)` are the start and target speeds and `s` is the number of step required + to reach the target speeds. +*/ +struct MotorSlope +{ + // initial speed in pixeltime per step + unsigned initial_speed_w = 0; + + // max speed in pixeltime per step + unsigned max_speed_w = 0; + + // maximum number of steps in the table + unsigned max_step_count; + + // acceleration in steps per pixeltime squared. + float acceleration = 0; + + unsigned get_table_step_shifted(unsigned step, StepType step_type) const; + + static MotorSlope create_from_steps(unsigned initial_w, unsigned max_w, + unsigned steps); +}; + +struct MotorSlopeTable +{ + std::vector table; + unsigned steps_count = 0; + unsigned pixeltime_sum = 0; + + void slice_steps(unsigned count); +}; + +unsigned get_slope_table_max_size(AsicType asic_type); + +MotorSlopeTable create_slope_table(const MotorSlope& slope, unsigned target_speed_w, + StepType step_type, unsigned steps_alignment, + unsigned min_size, unsigned max_size); + +std::ostream& operator<<(std::ostream& out, const MotorSlope& slope); + + +struct Genesys_Motor +{ + Genesys_Motor() = default; + + // id of the motor description + MotorId id = MotorId::UNKNOWN; + // motor base steps. Unit: 1/inch + int base_ydpi = 0; + // maximum resolution in y-direction. Unit: 1/inch + int optical_ydpi = 0; + // slopes to derive individual slopes from + std::vector slopes; + + MotorSlope& get_slope(StepType step_type) + { + return slopes[static_cast(step_type)]; + } + + const MotorSlope& get_slope(StepType step_type) const + { + return slopes[static_cast(step_type)]; + } + + StepType max_step_type() const + { + if (slopes.empty()) { + throw std::runtime_error("Slopes table is empty"); + } + return static_cast(slopes.size() - 1); + } +}; + +std::ostream& operator<<(std::ostream& out, const Genesys_Motor& motor); + +} // namespace genesys + +#endif // BACKEND_GENESYS_MOTOR_H diff --git a/backend/genesys/register.h b/backend/genesys/register.h new file mode 100644 index 0000000..bbc7ec8 --- /dev/null +++ b/backend/genesys/register.h @@ -0,0 +1,537 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_REGISTER_H +#define BACKEND_GENESYS_REGISTER_H + +#include "utilities.h" + +#include +#include +#include +#include +#include +#include +#include + +namespace genesys { + +template +struct Register +{ + std::uint16_t address = 0; + Value value = 0; +}; + +using GenesysRegister = Register; + +template +inline bool operator<(const Register& lhs, const Register& rhs) +{ + return lhs.address < rhs.address; +} + +struct GenesysRegisterSetState +{ + bool is_lamp_on = false; + bool is_xpa_on = false; + bool is_motor_on = false; + bool is_xpa_motor_on = false; +}; + +template +class RegisterContainer +{ +public: + + enum Options { + SEQUENTIAL = 1 + }; + + using RegisterType = Register; + using ContainerType = std::vector; + using iterator = typename ContainerType::iterator; + using const_iterator = typename ContainerType::const_iterator; + + RegisterContainer() = default; + + RegisterContainer(Options opts) : RegisterContainer() + { + if ((opts & SEQUENTIAL) == SEQUENTIAL) { + sorted_ = false; + } + } + + void init_reg(std::uint16_t address, Value default_value) + { + if (find_reg_index(address) >= 0) { + set(address, default_value); + return; + } + RegisterType reg; + reg.address = address; + reg.value = default_value; + registers_.push_back(reg); + if (sorted_) + std::sort(registers_.begin(), registers_.end()); + } + + bool has_reg(std::uint16_t address) const + { + return find_reg_index(address) >= 0; + } + + void remove_reg(std::uint16_t address) + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + registers_.erase(registers_.begin() + i); + } + + RegisterType& find_reg(std::uint16_t address) + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + return registers_[i]; + } + + const RegisterType& find_reg(std::uint16_t address) const + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + return registers_[i]; + } + + void set(std::uint16_t address, Value value) + { + find_reg(address).value = value; + } + + Value get(std::uint16_t address) const + { + return find_reg(address).value; + } + + void reserve(std::size_t size) { registers_.reserve(size); } + void clear() { registers_.clear(); } + std::size_t size() const { return registers_.size(); } + + iterator begin() { return registers_.begin(); } + const_iterator begin() const { return registers_.begin(); } + + iterator end() { return registers_.end(); } + const_iterator end() const { return registers_.end(); } + +private: + int find_reg_index(std::uint16_t address) const + { + if (!sorted_) { + for (std::size_t i = 0; i < registers_.size(); i++) { + if (registers_[i].address == address) { + return i; + } + } + return -1; + } + + RegisterType search; + search.address = address; + auto it = std::lower_bound(registers_.begin(), registers_.end(), search); + if (it == registers_.end()) + return -1; + if (it->address != address) + return -1; + return std::distance(registers_.begin(), it); + } + + // registers are stored in a sorted vector + bool sorted_ = true; + std::vector registers_; +}; + +template +std::ostream& operator<<(std::ostream& out, const RegisterContainer& container) +{ + StreamStateSaver state_saver{out}; + + out << "RegisterContainer{\n"; + out << std::hex; + out.fill('0'); + + for (const auto& reg : container) { + unsigned address_width = sizeof(reg.address) * 2; + unsigned value_width = sizeof(reg.value) * 2; + + out << " 0x" << std::setw(address_width) << static_cast(reg.address) + << " = 0x" << std::setw(value_width) << static_cast(reg.value) << '\n'; + } + out << "}"; + return out; +} + +class Genesys_Register_Set +{ +public: + static constexpr unsigned MAX_REGS = 256; + + using ContainerType = RegisterContainer; + using iterator = typename ContainerType::iterator; + using const_iterator = typename ContainerType::const_iterator; + + // FIXME: this shouldn't live here, but in a separate struct that contains Genesys_Register_Set + GenesysRegisterSetState state; + + enum Options { + SEQUENTIAL = 1 + }; + + Genesys_Register_Set() + { + registers_.reserve(MAX_REGS); + } + + // by default the register set is sorted by address. In certain cases it's importand to send + // the registers in certain order: use the SEQUENTIAL option for that + Genesys_Register_Set(Options opts) : registers_{static_cast(opts)} + { + registers_.reserve(MAX_REGS); + } + + const ContainerType& registers() const + { + return registers_; + } + + void init_reg(std::uint16_t address, std::uint8_t default_value) + { + registers_.init_reg(address, default_value); + } + + bool has_reg(std::uint16_t address) const { return registers_.has_reg(address); } + + void remove_reg(std::uint16_t address) { registers_.remove_reg(address); } + + GenesysRegister& find_reg(std::uint16_t address) + { + return registers_.find_reg(address); + } + + const GenesysRegister& find_reg(std::uint16_t address) const + { + return registers_.find_reg(address); + } + + GenesysRegister* find_reg_address(std::uint16_t address) + { + return &find_reg(address); + } + + const GenesysRegister* find_reg_address(std::uint16_t address) const + { + return &find_reg(address); + } + + void set8(std::uint16_t address, std::uint8_t value) + { + find_reg(address).value = value; + } + + void set8_mask(std::uint16_t address, std::uint8_t value, std::uint8_t mask) + { + auto& reg = find_reg(address); + reg.value = (reg.value & ~mask) | value; + } + + void set16(std::uint16_t address, std::uint16_t value) + { + find_reg(address).value = (value >> 8) & 0xff; + find_reg(address + 1).value = value & 0xff; + } + + void set24(std::uint16_t address, std::uint32_t value) + { + find_reg(address).value = (value >> 16) & 0xff; + find_reg(address + 1).value = (value >> 8) & 0xff; + find_reg(address + 2).value = value & 0xff; + } + + std::uint8_t get8(std::uint16_t address) const + { + return find_reg(address).value; + } + + std::uint16_t get16(std::uint16_t address) const + { + return (find_reg(address).value << 8) | find_reg(address + 1).value; + } + + std::uint32_t get24(std::uint16_t address) const + { + return (find_reg(address).value << 16) | + (find_reg(address + 1).value << 8) | + find_reg(address + 2).value; + } + + void clear() { registers_.clear(); } + std::size_t size() const { return registers_.size(); } + + iterator begin() { return registers_.begin(); } + const_iterator begin() const { return registers_.begin(); } + + iterator end() { return registers_.end(); } + const_iterator end() const { return registers_.end(); } + +private: + + // registers are stored in a sorted vector + ContainerType registers_; +}; + +inline std::ostream& operator<<(std::ostream& out, const Genesys_Register_Set& regs) +{ + out << regs.registers(); + return out; +} + +template +struct RegisterSetting +{ + using ValueType = Value; + using AddressType = std::uint16_t; + + RegisterSetting() = default; + + RegisterSetting(AddressType p_address, ValueType p_value) : + address(p_address), value(p_value) + {} + + RegisterSetting(AddressType p_address, ValueType p_value, ValueType p_mask) : + address(p_address), value(p_value), mask(p_mask) + {} + + AddressType address = 0; + ValueType value = 0; + ValueType mask = 0xff; + + bool operator==(const RegisterSetting& other) const + { + return address == other.address && value == other.value && mask == other.mask; + } +}; + +using GenesysRegisterSetting = RegisterSetting; +using GenesysRegisterSetting16 = RegisterSetting; + +template +void serialize(Stream& str, RegisterSetting& reg) +{ + serialize(str, reg.address); + serialize(str, reg.value); + serialize(str, reg.mask); +} + +template +class RegisterSettingSet +{ +public: + using ValueType = Value; + using SettingType = RegisterSetting; + using AddressType = typename SettingType::AddressType; + + using container = std::vector; + using iterator = typename container::iterator; + using const_iterator = typename container::const_iterator; + + RegisterSettingSet() = default; + RegisterSettingSet(std::initializer_list ilist) : + registers_(ilist) + {} + + iterator begin() { return registers_.begin(); } + const_iterator begin() const { return registers_.begin(); } + iterator end() { return registers_.end(); } + const_iterator end() const { return registers_.end(); } + + SettingType& operator[](std::size_t i) { return registers_[i]; } + const SettingType& operator[](std::size_t i) const { return registers_[i]; } + + std::size_t size() const { return registers_.size(); } + bool empty() const { return registers_.empty(); } + void clear() { registers_.clear(); } + + void push_back(SettingType reg) { registers_.push_back(reg); } + + void merge(const RegisterSettingSet& other) + { + for (const auto& reg : other) { + set_value(reg.address, reg.value); + } + } + + SettingType& find_reg(AddressType address) + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + return registers_[i]; + } + + const SettingType& find_reg(AddressType address) const + { + int i = find_reg_index(address); + if (i < 0) { + throw std::runtime_error("the register does not exist"); + } + return registers_[i]; + } + + ValueType get_value(AddressType address) const + { + int index = find_reg_index(address); + if (index >= 0) { + return registers_[index].value; + } + throw std::out_of_range("Unknown register"); + } + + void set_value(AddressType address, ValueType value) + { + int index = find_reg_index(address); + if (index >= 0) { + registers_[index].value = value; + return; + } + push_back(SettingType(address, value)); + } + + template + friend void serialize(std::istream& str, RegisterSettingSet& reg); + template + friend void serialize(std::ostream& str, RegisterSettingSet& reg); + + bool operator==(const RegisterSettingSet& other) const + { + return registers_ == other.registers_; + } + +private: + + int find_reg_index(AddressType address) const + { + for (std::size_t i = 0; i < registers_.size(); i++) { + if (registers_[i].address == address) { + return i; + } + } + return -1; + } + + std::vector registers_; +}; + +using GenesysRegisterSettingSet = RegisterSettingSet; +using GenesysRegisterSettingSet16 = RegisterSettingSet; + +template +std::ostream& operator<<(std::ostream& out, const RegisterSettingSet& container) +{ + StreamStateSaver state_saver{out}; + + out << "RegisterSettingSet{\n"; + out << std::hex; + out.fill('0'); + + for (const auto& reg : container) { + unsigned address_width = sizeof(reg.address) * 2; + unsigned value_width = sizeof(reg.value) * 2; + unsigned mask_width = sizeof(reg.mask) * 2; + + out << " 0x" << std::setw(address_width) << static_cast(reg.address) + << " = 0x" << std::setw(value_width) << static_cast(reg.value) + << " & 0x" << std::setw(mask_width) << static_cast(reg.mask) << '\n'; + } + out << "}"; + return out; +} + +template +inline void serialize(std::istream& str, RegisterSettingSet& reg) +{ + using AddressType = typename RegisterSetting::AddressType; + + reg.clear(); + const std::size_t max_register_address = 1 << (sizeof(AddressType) * CHAR_BIT); + serialize(str, reg.registers_, max_register_address); +} + +template +inline void serialize(std::ostream& str, RegisterSettingSet& reg) +{ + serialize(str, reg.registers_); +} + +template +void apply_registers_ordered(const RegisterSettingSet& set, + std::initializer_list order, F f) +{ + for (std::uint16_t addr : order) { + f(set.find_reg(addr)); + } + for (const auto& reg : set) { + if (std::find(order.begin(), order.end(), reg.address) != order.end()) { + continue; + } + f(reg); + } +} + +} // namespace genesys + +#endif // BACKEND_GENESYS_REGISTER_H diff --git a/backend/genesys/register_cache.h b/backend/genesys/register_cache.h new file mode 100644 index 0000000..dce701a --- /dev/null +++ b/backend/genesys/register_cache.h @@ -0,0 +1,92 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_REGISTER_CACHE_H +#define BACKEND_GENESYS_REGISTER_CACHE_H + +#include "register.h" + +namespace genesys { + +template +class RegisterCache +{ +public: + void update(std::uint16_t address, Value value) + { + if (regs_.has_reg(address)) { + regs_.set(address, value); + } else { + regs_.init_reg(address, value); + } + } + + void update(const Genesys_Register_Set& regs) + { + for (const auto& reg : regs) { + update(reg.address, reg.value); + } + } + + Value get(std::uint16_t address) const + { + return regs_.get(address); + } + +private: + RegisterContainer regs_; + + template + friend std::ostream& operator<<(std::ostream& out, const RegisterCache& cache); +}; + +template +std::ostream& operator<<(std::ostream& out, const RegisterCache& cache) +{ + out << cache.regs_; + return out; +} + +} // namespace genesys + +#endif // BACKEND_GENESYS_LINE_BUFFER_H diff --git a/backend/genesys/row_buffer.h b/backend/genesys/row_buffer.h new file mode 100644 index 0000000..e1a0c82 --- /dev/null +++ b/backend/genesys/row_buffer.h @@ -0,0 +1,214 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_LINE_BUFFER_H +#define BACKEND_GENESYS_LINE_BUFFER_H + +#include "error.h" + +#include +#include +#include +#include + +namespace genesys { + +class RowBuffer +{ +public: + RowBuffer(std::size_t line_bytes) : row_bytes_{line_bytes} {} + RowBuffer(const RowBuffer&) = default; + RowBuffer& operator=(const RowBuffer&) = default; + ~RowBuffer() = default; + + const std::uint8_t* get_row_ptr(std::size_t y) const + { + if (y >= height()) { + throw SaneException("y %zu is out of range", y); + } + return data_.data() + row_bytes_ * get_row_index(y); + } + + std::uint8_t* get_row_ptr(std::size_t y) + { + if (y >= height()) { + throw SaneException("y %zu is out of range", y); + } + return data_.data() + row_bytes_ * get_row_index(y); + } + + const std::uint8_t* get_front_row_ptr() const { return get_row_ptr(0); } + std::uint8_t* get_front_row_ptr() { return get_row_ptr(0); } + const std::uint8_t* get_back_row_ptr() const { return get_row_ptr(height() - 1); } + std::uint8_t* get_back_row_ptr() { return get_row_ptr(height() - 1); } + + bool empty() const { return is_linear_ && first_ == last_; } + + bool full() + { + if (is_linear_) { + return last_ == buffer_end_; + } + return first_ == last_; + } + + bool is_linear() const { return is_linear_; } + + void linearize() + { + if (!is_linear_) { + std::rotate(data_.begin(), data_.begin() + row_bytes_ * first_, data_.end()); + last_ = height(); + first_ = 0; + is_linear_ = true; + } + } + + void pop_front() + { + if (empty()) { + throw SaneException("Trying to pop out of empty() line buffer"); + } + + first_++; + if (first_ == last_) { + first_ = 0; + last_ = 0; + is_linear_ = true; + } else if (first_ == buffer_end_) { + first_ = 0; + is_linear_ = true; + } + } + + void push_front() + { + if (height() + 1 >= height_capacity()) { + ensure_capacity(std::max(1, height() * 2)); + } + + if (first_ == 0) { + is_linear_ = false; + first_ = buffer_end_; + } + first_--; + } + + void pop_back() + { + if (empty()) { + throw SaneException("Trying to pop out of empty() line buffer"); + } + if (last_ == 0) { + last_ = buffer_end_; + is_linear_ = true; + } + last_--; + if (first_ == last_) { + first_ = 0; + last_ = 0; + is_linear_ = true; + } + } + + void push_back() + { + if (height() + 1 >= height_capacity()) { + ensure_capacity(std::max(1, height() * 2)); + } + + if (last_ == buffer_end_) { + is_linear_ = false; + last_ = 0; + } + last_++; + } + + std::size_t row_bytes() const { return row_bytes_; } + + std::size_t height() const + { + if (!is_linear_) { + return last_ + buffer_end_ - first_; + } + return last_ - first_; + } + + std::size_t height_capacity() const { return buffer_end_; } + + void clear() + { + first_ = 0; + last_ = 0; + } + +private: + std::size_t get_row_index(std::size_t index) const + { + if (index >= buffer_end_ - first_) { + return index - (buffer_end_ - first_); + } + return index + first_; + } + + void ensure_capacity(std::size_t capacity) + { + if (capacity < height_capacity()) + return; + linearize(); + data_.resize(capacity * row_bytes_); + buffer_end_ = capacity; + } + +private: + std::size_t row_bytes_ = 0; + std::size_t first_ = 0; + std::size_t last_ = 0; + std::size_t buffer_end_ = 0; + bool is_linear_ = true; + std::vector data_; +}; + +} // namespace genesys + +#endif // BACKEND_GENESYS_LINE_BUFFER_H diff --git a/backend/genesys/scanner_interface.cpp b/backend/genesys/scanner_interface.cpp new file mode 100644 index 0000000..0b60b66 --- /dev/null +++ b/backend/genesys/scanner_interface.cpp @@ -0,0 +1,52 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "scanner_interface.h" + +namespace genesys { + +ScannerInterface::~ScannerInterface() = default; + +} // namespace genesys diff --git a/backend/genesys/scanner_interface.h b/backend/genesys/scanner_interface.h new file mode 100644 index 0000000..03c7132 --- /dev/null +++ b/backend/genesys/scanner_interface.h @@ -0,0 +1,112 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_SCANNER_INTERFACE_H +#define BACKEND_GENESYS_SCANNER_INTERFACE_H + +#include "fwd.h" +#include +#include +#include +#include + +namespace genesys { + +// Represents an interface through which all low level operations are performed. +class ScannerInterface +{ +public: + enum Flags { + FLAG_NONE = 0, + FLAG_SWAP_REGISTERS = 1 << 0, + FLAG_SMALL_ADDRESS = 1 << 1 + }; + + virtual ~ScannerInterface(); + + virtual bool is_mock() const = 0; + + virtual std::uint8_t read_register(std::uint16_t address) = 0; + virtual void write_register(std::uint16_t address, std::uint8_t value) = 0; + virtual void write_registers(const Genesys_Register_Set& regs) = 0; + + virtual void write_0x8c(std::uint8_t index, std::uint8_t value) = 0; + virtual void bulk_read_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) = 0; + virtual void bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) = 0; + + // GL646, GL841, GL843 have different ways to write to RAM and to gamma tables + // FIXME: remove flags when updating tests + virtual void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags = FLAG_NONE) = 0; + + virtual void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags = FLAG_NONE) = 0; + + // GL845, GL846, GL847 and GL124 have a uniform way to write to RAM tables + virtual void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) = 0; + + virtual std::uint16_t read_fe_register(std::uint8_t address) = 0; + virtual void write_fe_register(std::uint8_t address, std::uint16_t value) = 0; + + virtual IUsbDevice& get_usb_device() = 0; + + // sleeps the specified number of microseconds. Will not sleep if testing mode is enabled. + virtual void sleep_us(unsigned microseconds) = 0; + + void sleep_ms(unsigned milliseconds) + { + sleep_us(milliseconds * 1000); + } + + virtual void record_progress_message(const char* msg) = 0; + + virtual void record_slope_table(unsigned table_nr, const std::vector& steps) = 0; + + virtual void record_key_value(const std::string& key, const std::string& value) = 0; + + virtual void test_checkpoint(const std::string& name) = 0; +}; + +} // namespace genesys + +#endif diff --git a/backend/genesys/scanner_interface_usb.cpp b/backend/genesys/scanner_interface_usb.cpp new file mode 100644 index 0000000..d4d83dd --- /dev/null +++ b/backend/genesys/scanner_interface_usb.cpp @@ -0,0 +1,515 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "scanner_interface_usb.h" +#include "low.h" +#include + +namespace genesys { + +ScannerInterfaceUsb::~ScannerInterfaceUsb() = default; + +ScannerInterfaceUsb::ScannerInterfaceUsb(Genesys_Device* dev) : dev_{dev} {} + +bool ScannerInterfaceUsb::is_mock() const +{ + return false; +} + +std::uint8_t ScannerInterfaceUsb::read_register(std::uint16_t address) +{ + DBG_HELPER(dbg); + + std::uint8_t value = 0; + + if (dev_->model->asic_type == AsicType::GL847 || + dev_->model->asic_type == AsicType::GL845 || + dev_->model->asic_type == AsicType::GL846 || + dev_->model->asic_type == AsicType::GL124) + { + std::uint8_t value2x8[2]; + std::uint16_t address16 = 0x22 + (address << 8); + + std::uint16_t usb_value = VALUE_GET_REGISTER; + if (address > 0xff) { + usb_value |= 0x100; + } + + usb_dev_.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, usb_value, address16, 2, value2x8); + + // check usb link status + if (value2x8[1] != 0x55) { + throw SaneException(SANE_STATUS_IO_ERROR, "invalid read, scanner unplugged?"); + } + + DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value2x8[0]); + + value = value2x8[0]; + + } else { + + if (address > 0xff) { + throw SaneException("Invalid register address 0x%04x", address); + } + + std::uint8_t address8 = address & 0xff; + + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, &address8); + usb_dev_.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_READ_REGISTER, INDEX, + 1, &value); + } + + DBG(DBG_proc, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value); + return value; +} + +void ScannerInterfaceUsb::write_register(std::uint16_t address, std::uint8_t value) +{ + DBG_HELPER_ARGS(dbg, "address: 0x%04x, value: 0x%02x", static_cast(address), + static_cast(value)); + + if (dev_->model->asic_type == AsicType::GL847 || + dev_->model->asic_type == AsicType::GL845 || + dev_->model->asic_type == AsicType::GL846 || + dev_->model->asic_type == AsicType::GL124) + { + std::uint8_t buffer[2]; + + buffer[0] = address & 0xff; + buffer[1] = value; + + std::uint16_t usb_value = VALUE_SET_REGISTER; + if (address > 0xff) { + usb_value |= 0x100; + } + + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, usb_value, INDEX, + 2, buffer); + + } else { + if (address > 0xff) { + throw SaneException("Invalid register address 0x%04x", address); + } + + std::uint8_t address8 = address & 0xff; + + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, &address8); + + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_WRITE_REGISTER, INDEX, + 1, &value); + + } + DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, address, value); +} + +void ScannerInterfaceUsb::write_registers(const Genesys_Register_Set& regs) +{ + DBG_HELPER(dbg); + if (dev_->model->asic_type == AsicType::GL646 || + dev_->model->asic_type == AsicType::GL841) + { + uint8_t outdata[8]; + std::vector buffer; + buffer.reserve(regs.size() * 2); + + /* copy registers and values in data buffer */ + for (const auto& r : regs) { + buffer.push_back(r.address); + buffer.push_back(r.value); + } + + DBG(DBG_io, "%s (elems= %zu, size = %zu)\n", __func__, regs.size(), buffer.size()); + + if (dev_->model->asic_type == AsicType::GL646) { + outdata[0] = BULK_OUT; + outdata[1] = BULK_REGISTER; + outdata[2] = 0x00; + outdata[3] = 0x00; + outdata[4] = (buffer.size() & 0xff); + outdata[5] = ((buffer.size() >> 8) & 0xff); + outdata[6] = ((buffer.size() >> 16) & 0xff); + outdata[7] = ((buffer.size() >> 24) & 0xff); + + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, INDEX, + sizeof(outdata), outdata); + + size_t write_size = buffer.size(); + + usb_dev_.bulk_write(buffer.data(), &write_size); + } else { + for (std::size_t i = 0; i < regs.size();) { + std::size_t c = regs.size() - i; + if (c > 32) /*32 is max on GL841. checked that.*/ + c = 32; + + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER, + INDEX, c * 2, buffer.data() + i * 2); + + i += c; + } + } + } else { + for (const auto& r : regs) { + write_register(r.address, r.value); + } + } + + DBG(DBG_io, "%s: wrote %zu registers\n", __func__, regs.size()); +} + +void ScannerInterfaceUsb::write_0x8c(std::uint8_t index, std::uint8_t value) +{ + DBG_HELPER_ARGS(dbg, "0x%02x,0x%02x", index, value); + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_BUF_ENDACCESS, index, 1, &value); +} + +static void bulk_read_data_send_header(UsbDevice& usb_dev, AsicType asic_type, size_t size) +{ + DBG_HELPER(dbg); + + uint8_t outdata[8]; + if (asic_type == AsicType::GL124 || + asic_type == AsicType::GL846 || + asic_type == AsicType::GL847) + { + // hard coded 0x10000000 address + outdata[0] = 0; + outdata[1] = 0; + outdata[2] = 0; + outdata[3] = 0x10; + } else if (asic_type == AsicType::GL841 || + asic_type == AsicType::GL843) { + outdata[0] = BULK_IN; + outdata[1] = BULK_RAM; + outdata[2] = 0x82; // + outdata[3] = 0x00; + } else { + outdata[0] = BULK_IN; + outdata[1] = BULK_RAM; + outdata[2] = 0x00; + outdata[3] = 0x00; + } + + /* data size to transfer */ + outdata[4] = (size & 0xff); + outdata[5] = ((size >> 8) & 0xff); + outdata[6] = ((size >> 16) & 0xff); + outdata[7] = ((size >> 24) & 0xff); + + usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, + sizeof(outdata), outdata); +} + +void ScannerInterfaceUsb::bulk_read_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) +{ + // currently supported: GL646, GL841, GL843, GL846, GL847, GL124 + DBG_HELPER(dbg); + + unsigned is_addr_used = 1; + unsigned has_header_before_each_chunk = 0; + if (dev_->model->asic_type == AsicType::GL124 || + dev_->model->asic_type == AsicType::GL846 || + dev_->model->asic_type == AsicType::GL847) + { + is_addr_used = 0; + has_header_before_each_chunk = 1; + } + + if (is_addr_used) { + DBG(DBG_io, "%s: requesting %zu bytes from 0x%02x addr\n", __func__, size, addr); + } else { + DBG(DBG_io, "%s: requesting %zu bytes\n", __func__, size); + } + + if (size == 0) + return; + + if (is_addr_used) { + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, 0x00, + 1, &addr); + } + + std::size_t target_size = size; + + std::size_t max_in_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type); + + if (!has_header_before_each_chunk) { + bulk_read_data_send_header(usb_dev_, dev_->model->asic_type, size); + } + + // loop until computed data size is read + while (target_size > 0) { + std::size_t block_size = std::min(target_size, max_in_size); + + if (has_header_before_each_chunk) { + bulk_read_data_send_header(usb_dev_, dev_->model->asic_type, block_size); + } + + DBG(DBG_io2, "%s: trying to read %zu bytes of data\n", __func__, block_size); + + usb_dev_.bulk_read(data, &block_size); + + DBG(DBG_io2, "%s: read %zu bytes, %zu remaining\n", __func__, block_size, target_size - block_size); + + target_size -= block_size; + data += block_size; + } +} + +void ScannerInterfaceUsb::bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t len) +{ + DBG_HELPER_ARGS(dbg, "writing %zu bytes", len); + + // supported: GL646, GL841, GL843 + std::size_t size; + std::uint8_t outdata[8]; + + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, + 1, &addr); + + std::size_t max_out_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type); + + while (len) { + if (len > max_out_size) + size = max_out_size; + else + size = len; + + if (dev_->model->asic_type == AsicType::GL841) { + outdata[0] = BULK_OUT; + outdata[1] = BULK_RAM; + // both 0x82 and 0x00 works on GL841. + outdata[2] = 0x82; + outdata[3] = 0x00; + } else { + outdata[0] = BULK_OUT; + outdata[1] = BULK_RAM; + // 8600F uses 0x82, but 0x00 works too. 8400F uses 0x02 for certain transactions. + outdata[2] = 0x00; + outdata[3] = 0x00; + } + + outdata[4] = (size & 0xff); + outdata[5] = ((size >> 8) & 0xff); + outdata[6] = ((size >> 16) & 0xff); + outdata[7] = ((size >> 24) & 0xff); + + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, + sizeof(outdata), outdata); + + usb_dev_.bulk_write(data, &size); + + DBG(DBG_io2, "%s: wrote %zu bytes, %zu remaining\n", __func__, size, len - size); + + len -= size; + data += size; + } +} + +void ScannerInterfaceUsb::write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags) +{ + DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size); + if (dev_->model->asic_type != AsicType::GL646 && + dev_->model->asic_type != AsicType::GL841 && + dev_->model->asic_type != AsicType::GL843) + { + throw SaneException("Unsupported transfer mode"); + } + + if (dev_->model->asic_type == AsicType::GL843) { + if (flags & FLAG_SWAP_REGISTERS) { + if (!(flags & FLAG_SMALL_ADDRESS)) { + write_register(0x29, ((addr >> 20) & 0xff)); + } + write_register(0x2a, ((addr >> 12) & 0xff)); + write_register(0x2b, ((addr >> 4) & 0xff)); + } else { + write_register(0x2b, ((addr >> 4) & 0xff)); + write_register(0x2a, ((addr >> 12) & 0xff)); + if (!(flags & FLAG_SMALL_ADDRESS)) { + write_register(0x29, ((addr >> 20) & 0xff)); + } + } + } else { + write_register(0x2b, ((addr >> 4) & 0xff)); + write_register(0x2a, ((addr >> 12) & 0xff)); + } + bulk_write_data(type, data, size); +} + +void ScannerInterfaceUsb::write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags) +{ + DBG_HELPER_ARGS(dbg, "type: 0x%02x, addr: 0x%08x, size: 0x%08zx", type, addr, size); + if (dev_->model->asic_type != AsicType::GL646 && + dev_->model->asic_type != AsicType::GL841 && + dev_->model->asic_type != AsicType::GL843) + { + throw SaneException("Unsupported transfer mode"); + } + + if (flags & FLAG_SWAP_REGISTERS) { + write_register(0x5b, ((addr >> 12) & 0xff)); + write_register(0x5c, ((addr >> 4) & 0xff)); + } else { + write_register(0x5c, ((addr >> 4) & 0xff)); + write_register(0x5b, ((addr >> 12) & 0xff)); + } + bulk_write_data(type, data, size); +} + +void ScannerInterfaceUsb::write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) +{ + DBG_HELPER_ARGS(dbg, "address: 0x%08x, size: %d", static_cast(addr), + static_cast(size)); + + if (dev_->model->asic_type != AsicType::GL845 && + dev_->model->asic_type != AsicType::GL846 && + dev_->model->asic_type != AsicType::GL847 && + dev_->model->asic_type != AsicType::GL124) + { + throw SaneException("Unsupported transfer type"); + } + std::uint8_t outdata[8]; + outdata[0] = addr & 0xff; + outdata[1] = ((addr >> 8) & 0xff); + outdata[2] = ((addr >> 16) & 0xff); + outdata[3] = ((addr >> 24) & 0xff); + outdata[4] = (size & 0xff); + outdata[5] = ((size >> 8) & 0xff); + outdata[6] = ((size >> 16) & 0xff); + outdata[7] = ((size >> 24) & 0xff); + + // write addr and size for AHB + usb_dev_.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x01, 8, outdata); + + std::size_t max_out_size = sanei_genesys_get_bulk_max_size(dev_->model->asic_type); + + // write actual data + std::size_t written = 0; + do { + std::size_t block_size = std::min(size - written, max_out_size); + + usb_dev_.bulk_write(data + written, &block_size); + + written += block_size; + } while (written < size); +} + +std::uint16_t ScannerInterfaceUsb::read_fe_register(std::uint8_t address) +{ + DBG_HELPER(dbg); + Genesys_Register_Set reg; + + reg.init_reg(0x50, address); + + // set up read address + write_registers(reg); + + // read data + std::uint16_t value = read_register(0x46) << 8; + value |= read_register(0x47); + + DBG(DBG_io, "%s (0x%02x, 0x%04x)\n", __func__, address, value); + return value; +} + +void ScannerInterfaceUsb::write_fe_register(std::uint8_t address, std::uint16_t value) +{ + DBG_HELPER_ARGS(dbg, "0x%02x, 0x%04x", address, value); + Genesys_Register_Set reg(Genesys_Register_Set::SEQUENTIAL); + + reg.init_reg(0x51, address); + if (dev_->model->asic_type == AsicType::GL124) { + reg.init_reg(0x5d, (value / 256) & 0xff); + reg.init_reg(0x5e, value & 0xff); + } else { + reg.init_reg(0x3a, (value / 256) & 0xff); + reg.init_reg(0x3b, value & 0xff); + } + + write_registers(reg); +} + +IUsbDevice& ScannerInterfaceUsb::get_usb_device() +{ + return usb_dev_; +} + +void ScannerInterfaceUsb::sleep_us(unsigned microseconds) +{ + if (sanei_usb_is_replay_mode_enabled()) { + return; + } + std::this_thread::sleep_for(std::chrono::microseconds{microseconds}); +} + +void ScannerInterfaceUsb::record_progress_message(const char* msg) +{ + sanei_usb_testing_record_message(msg); +} + +void ScannerInterfaceUsb::record_slope_table(unsigned table_nr, + const std::vector& steps) +{ + (void) table_nr; + (void) steps; +} + +void ScannerInterfaceUsb::record_key_value(const std::string& key, const std::string& value) +{ + (void) key; + (void) value; +} + +void ScannerInterfaceUsb::test_checkpoint(const std::string& name) +{ + (void) name; +} + +} // namespace genesys diff --git a/backend/genesys/scanner_interface_usb.h b/backend/genesys/scanner_interface_usb.h new file mode 100644 index 0000000..06b51ff --- /dev/null +++ b/backend/genesys/scanner_interface_usb.h @@ -0,0 +1,98 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_SCANNER_INTERFACE_USB_H +#define BACKEND_GENESYS_SCANNER_INTERFACE_USB_H + +#include "scanner_interface.h" +#include "usb_device.h" + +namespace genesys { + +class ScannerInterfaceUsb : public ScannerInterface +{ +public: + ScannerInterfaceUsb(Genesys_Device* dev); + + ~ScannerInterfaceUsb() override; + + bool is_mock() const override; + + std::uint8_t read_register(std::uint16_t address) override; + void write_register(std::uint16_t address, std::uint8_t value) override; + void write_registers(const Genesys_Register_Set& regs) override; + + void write_0x8c(std::uint8_t index, std::uint8_t value) override; + void bulk_read_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) override; + void bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) override; + + void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags) override; + void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags) override; + + void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) override; + + std::uint16_t read_fe_register(std::uint8_t address) override; + void write_fe_register(std::uint8_t address, std::uint16_t value) override; + + IUsbDevice& get_usb_device() override; + + void sleep_us(unsigned microseconds) override; + + void record_progress_message(const char* msg) override; + + void record_slope_table(unsigned table_nr, const std::vector& steps) override; + + void record_key_value(const std::string& key, const std::string& value) override; + + void test_checkpoint(const std::string& name) override; + +private: + Genesys_Device* dev_; + UsbDevice usb_dev_; +}; + +} // namespace genesys + +#endif diff --git a/backend/genesys/sensor.cpp b/backend/genesys/sensor.cpp new file mode 100644 index 0000000..e54af65 --- /dev/null +++ b/backend/genesys/sensor.cpp @@ -0,0 +1,160 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "sensor.h" +#include "utilities.h" +#include + +namespace genesys { + +std::ostream& operator<<(std::ostream& out, const StaggerConfig& config) +{ + out << "StaggerConfig{\n" + << " min_resolution: " << config.min_resolution() << '\n' + << " lines_at_min: " << config.lines_at_min() << '\n' + << "}"; + return out; +} + +std::ostream& operator<<(std::ostream& out, const FrontendType& type) +{ + switch (type) { + case FrontendType::UNKNOWN: out << "UNKNOWN"; break; + case FrontendType::WOLFSON: out << "WOLFSON"; break; + case FrontendType::ANALOG_DEVICES: out << "ANALOG_DEVICES"; break; + default: out << "(unknown value)"; + } + return out; +} + +std::ostream& operator<<(std::ostream& out, const GenesysFrontendLayout& layout) +{ + StreamStateSaver state_saver{out}; + + out << "GenesysFrontendLayout{\n" + << " type: " << layout.type << '\n' + << std::hex + << " offset_addr[0]: " << layout.offset_addr[0] << '\n' + << " offset_addr[1]: " << layout.offset_addr[1] << '\n' + << " offset_addr[2]: " << layout.offset_addr[2] << '\n' + << " gain_addr[0]: " << layout.gain_addr[0] << '\n' + << " gain_addr[1]: " << layout.gain_addr[1] << '\n' + << " gain_addr[2]: " << layout.gain_addr[2] << '\n' + << '}'; + return out; +} + +std::ostream& operator<<(std::ostream& out, const Genesys_Frontend& frontend) +{ + StreamStateSaver state_saver{out}; + + out << "Genesys_Frontend{\n" + << " id: " << static_cast(frontend.id) << '\n' + << " regs: " << format_indent_braced_list(4, frontend.regs) << '\n' + << std::hex + << " reg2[0]: " << frontend.reg2[0] << '\n' + << " reg2[1]: " << frontend.reg2[1] << '\n' + << " reg2[2]: " << frontend.reg2[2] << '\n' + << " layout: " << format_indent_braced_list(4, frontend.layout) << '\n' + << '}'; + return out; +} + +std::ostream& operator<<(std::ostream& out, const SensorExposure& exposure) +{ + out << "SensorExposure{\n" + << " red: " << exposure.red << '\n' + << " green: " << exposure.green << '\n' + << " blue: " << exposure.blue << '\n' + << '}'; + return out; +} + +std::ostream& operator<<(std::ostream& out, const ResolutionFilter& resolutions) +{ + if (resolutions.matches_any()) { + out << "ANY"; + return out; + } + out << format_vector_unsigned(4, resolutions.resolutions()); + return out; +} + +std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor) +{ + out << "Genesys_Sensor{\n" + << " sensor_id: " << static_cast(sensor.sensor_id) << '\n' + << " optical_res: " << sensor.optical_res << '\n' + << " resolutions: " << format_indent_braced_list(4, sensor.resolutions) << '\n' + << " channels: " << format_vector_unsigned(4, sensor.channels) << '\n' + << " method: " << sensor.method << '\n' + << " register_dpihw_override: " << sensor.register_dpihw_override << '\n' + << " logical_dpihw_override: " << sensor.logical_dpihw_override << '\n' + << " dpiset_override: " << sensor.dpiset_override << '\n' + << " ccd_size_divisor: " << sensor.ccd_size_divisor << '\n' + << " pixel_count_multiplier: " << sensor.pixel_count_multiplier << '\n' + << " black_pixels: " << sensor.black_pixels << '\n' + << " dummy_pixel: " << sensor.dummy_pixel << '\n' + << " ccd_start_xoffset: " << sensor.ccd_start_xoffset << '\n' + << " sensor_pixels: " << sensor.sensor_pixels << '\n' + << " fau_gain_white_ref: " << sensor.fau_gain_white_ref << '\n' + << " gain_white_ref: " << sensor.gain_white_ref << '\n' + << " exposure: " << format_indent_braced_list(4, sensor.exposure) << '\n' + << " exposure_lperiod: " << sensor.exposure_lperiod << '\n' + << " segment_size: " << sensor.segment_size << '\n' + << " segment_order: " + << format_indent_braced_list(4, format_vector_unsigned(4, sensor.segment_order)) << '\n' + << " stagger_config: " << format_indent_braced_list(4, sensor.stagger_config) << '\n' + << " custom_base_regs: " << format_indent_braced_list(4, sensor.custom_base_regs) << '\n' + << " custom_regs: " << format_indent_braced_list(4, sensor.custom_regs) << '\n' + << " custom_fe_regs: " << format_indent_braced_list(4, sensor.custom_fe_regs) << '\n' + << " gamma.red: " << sensor.gamma[0] << '\n' + << " gamma.green: " << sensor.gamma[1] << '\n' + << " gamma.blue: " << sensor.gamma[2] << '\n' + << "}"; + return out; +} + +} // namespace genesys diff --git a/backend/genesys/sensor.h b/backend/genesys/sensor.h new file mode 100644 index 0000000..e70728e --- /dev/null +++ b/backend/genesys/sensor.h @@ -0,0 +1,470 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_SENSOR_H +#define BACKEND_GENESYS_SENSOR_H + +#include "enums.h" +#include "register.h" +#include "serialize.h" +#include +#include + +namespace genesys { + +template +struct AssignableArray : public std::array { + AssignableArray() = default; + AssignableArray(const AssignableArray&) = default; + AssignableArray& operator=(const AssignableArray&) = default; + + AssignableArray& operator=(std::initializer_list init) + { + if (init.size() != std::array::size()) + throw std::runtime_error("An array of incorrect size assigned"); + std::copy(init.begin(), init.end(), std::array::begin()); + return *this; + } +}; + + +class StaggerConfig +{ +public: + StaggerConfig() = default; + StaggerConfig(unsigned min_resolution, unsigned lines_at_min) : + min_resolution_{min_resolution}, + lines_at_min_{lines_at_min} + { + } + + unsigned stagger_at_resolution(unsigned xresolution, unsigned yresolution) const + { + if (min_resolution_ == 0 || xresolution < min_resolution_) + return 0; + return yresolution / min_resolution_ * lines_at_min_; + } + + unsigned min_resolution() const { return min_resolution_; } + unsigned lines_at_min() const { return lines_at_min_; } + + bool operator==(const StaggerConfig& other) const + { + return min_resolution_ == other.min_resolution_ && + lines_at_min_ == other.lines_at_min_; + } + +private: + unsigned min_resolution_ = 0; + unsigned lines_at_min_ = 0; + + template + friend void serialize(Stream& str, StaggerConfig& x); +}; + +template +void serialize(Stream& str, StaggerConfig& x) +{ + serialize(str, x.min_resolution_); + serialize(str, x.lines_at_min_); +} + +std::ostream& operator<<(std::ostream& out, const StaggerConfig& config); + + +enum class FrontendType : unsigned +{ + UNKNOWN, + WOLFSON, + ANALOG_DEVICES +}; + +inline void serialize(std::istream& str, FrontendType& x) +{ + unsigned value; + serialize(str, value); + x = static_cast(value); +} + +inline void serialize(std::ostream& str, FrontendType& x) +{ + unsigned value = static_cast(x); + serialize(str, value); +} + +std::ostream& operator<<(std::ostream& out, const FrontendType& type); + +struct GenesysFrontendLayout +{ + FrontendType type = FrontendType::UNKNOWN; + std::array offset_addr = {}; + std::array gain_addr = {}; + + bool operator==(const GenesysFrontendLayout& other) const + { + return type == other.type && + offset_addr == other.offset_addr && + gain_addr == other.gain_addr; + } +}; + +template +void serialize(Stream& str, GenesysFrontendLayout& x) +{ + serialize(str, x.type); + serialize_newline(str); + serialize(str, x.offset_addr); + serialize_newline(str); + serialize(str, x.gain_addr); +} + +std::ostream& operator<<(std::ostream& out, const GenesysFrontendLayout& layout); + +/** @brief Data structure to set up analog frontend. + The analog frontend converts analog value from image sensor to digital value. It has its own + control registers which are set up with this structure. The values are written using + fe_write_data. + */ +struct Genesys_Frontend +{ + Genesys_Frontend() = default; + + // id of the frontend description + AdcId id = AdcId::UNKNOWN; + + // all registers of the frontend. Note that the registers can hold 9-bit values + RegisterSettingSet regs; + + // extra control registers + std::array reg2 = {}; + + GenesysFrontendLayout layout; + + void set_offset(unsigned which, std::uint16_t value) + { + regs.set_value(layout.offset_addr[which], value); + } + + void set_gain(unsigned which, std::uint16_t value) + { + regs.set_value(layout.gain_addr[which], value); + } + + std::uint16_t get_offset(unsigned which) const + { + return regs.get_value(layout.offset_addr[which]); + } + + std::uint16_t get_gain(unsigned which) const + { + return regs.get_value(layout.gain_addr[which]); + } + + bool operator==(const Genesys_Frontend& other) const + { + return id == other.id && + regs == other.regs && + reg2 == other.reg2 && + layout == other.layout; + } +}; + +std::ostream& operator<<(std::ostream& out, const Genesys_Frontend& frontend); + +template +void serialize(Stream& str, Genesys_Frontend& x) +{ + serialize(str, x.id); + serialize_newline(str); + serialize(str, x.regs); + serialize_newline(str); + serialize(str, x.reg2); + serialize_newline(str); + serialize(str, x.layout); +} + +struct SensorExposure { + std::uint16_t red = 0; + std::uint16_t green = 0; + std::uint16_t blue = 0; + + SensorExposure() = default; + SensorExposure(std::uint16_t r, std::uint16_t g, std::uint16_t b) : + red{r}, green{g}, blue{b} + {} + + bool operator==(const SensorExposure& other) const + { + return red == other.red && green == other.green && blue == other.blue; + } +}; + +std::ostream& operator<<(std::ostream& out, const SensorExposure& exposure); + + +class ResolutionFilter +{ +public: + struct Any {}; + static constexpr Any ANY{}; + + ResolutionFilter() : matches_any_{false} {} + ResolutionFilter(Any) : matches_any_{true} {} + ResolutionFilter(std::initializer_list resolutions) : + matches_any_{false}, + resolutions_{resolutions} + {} + + bool matches(unsigned resolution) const + { + if (matches_any_) + return true; + auto it = std::find(resolutions_.begin(), resolutions_.end(), resolution); + return it != resolutions_.end(); + } + + bool operator==(const ResolutionFilter& other) const + { + return matches_any_ == other.matches_any_ && resolutions_ == other.resolutions_; + } + + bool matches_any() const { return matches_any_; } + const std::vector& resolutions() const { return resolutions_; } + +private: + bool matches_any_ = false; + std::vector resolutions_; + + template + friend void serialize(Stream& str, ResolutionFilter& x); +}; + +std::ostream& operator<<(std::ostream& out, const ResolutionFilter& resolutions); + +template +void serialize(Stream& str, ResolutionFilter& x) +{ + serialize(str, x.matches_any_); + serialize_newline(str); + serialize(str, x.resolutions_); +} + + +struct Genesys_Sensor { + + Genesys_Sensor() = default; + ~Genesys_Sensor() = default; + + // id of the sensor description + SensorId sensor_id = SensorId::UNKNOWN; + + // sensor resolution in CCD pixels. Note that we may read more than one CCD pixel per logical + // pixel, see ccd_pixels_per_system_pixel() + unsigned optical_res = 0; + + // the resolution list that the sensor is usable at. + ResolutionFilter resolutions = ResolutionFilter::ANY; + + // the channel list that the sensor is usable at + std::vector channels = { 1, 3 }; + + // the scan method used with the sensor + ScanMethod method = ScanMethod::FLATBED; + + // The scanner may be setup to use a custom dpihw that does not correspond to any actual + // resolution. The value zero does not set the override. + unsigned register_dpihw_override = 0; + + // The scanner may be setup to use a custom logical dpihw that does not correspond to any actual + // resolution. The value zero does not set the override. + unsigned logical_dpihw_override = 0; + + // The scanner may be setup to use a custom dpiset value that does not correspond to any actual + // resolution. The value zero does not set the override. + unsigned dpiset_override = 0; + + // CCD may present itself as half or quarter-size CCD on certain resolutions + int ccd_size_divisor = 1; + + // Some scanners need an additional multiplier over the scan coordinates + int pixel_count_multiplier = 1; + + int black_pixels = 0; + // value of the dummy register + int dummy_pixel = 0; + // last pixel of CCD margin at optical resolution + int ccd_start_xoffset = 0; + // total pixels used by the sensor + int sensor_pixels = 0; + // TA CCD target code (reference gain) + int fau_gain_white_ref = 0; + // CCD target code (reference gain) + int gain_white_ref = 0; + + // red, green and blue initial exposure values + SensorExposure exposure; + + int exposure_lperiod = -1; + + // the number of pixels in a single segment. + // only on gl843 + unsigned segment_size = 0; + + // the order of the segments, if any, for the sensor. If the sensor is not segmented or uses + // only single segment, this array can be empty + // only on gl843 + std::vector segment_order; + + // some CCDs use two arrays of pixels for double resolution. On such CCDs when scanning at + // high-enough resolution, every other pixel column is shifted + StaggerConfig stagger_config; + + GenesysRegisterSettingSet custom_base_regs; // gl646-specific + GenesysRegisterSettingSet custom_regs; + GenesysRegisterSettingSet custom_fe_regs; + + // red, green and blue gamma coefficient for default gamma tables + AssignableArray gamma; + + std::function get_logical_hwdpi_fun; + std::function get_register_hwdpi_fun; + std::function get_ccd_size_divisor_fun; + std::function get_hwdpi_divisor_fun; + + unsigned get_logical_hwdpi(unsigned xres) const { return get_logical_hwdpi_fun(*this, xres); } + unsigned get_register_hwdpi(unsigned xres) const { return get_register_hwdpi_fun(*this, xres); } + unsigned get_ccd_size_divisor_for_dpi(unsigned xres) const + { + return get_ccd_size_divisor_fun(*this, xres); + } + unsigned get_hwdpi_divisor_for_dpi(unsigned xres) const + { + return get_hwdpi_divisor_fun(*this, xres); + } + + // how many CCD pixels are processed per system pixel time. This corresponds to CKSEL + 1 + unsigned ccd_pixels_per_system_pixel() const + { + // same on GL646, GL841, GL843, GL846, GL847, GL124 + constexpr unsigned REG_CKSEL = 0x03; + return (custom_regs.get_value(0x18) & REG_CKSEL) + 1; + } + + bool matches_channel_count(unsigned count) const + { + return std::find(channels.begin(), channels.end(), count) != channels.end(); + } + + unsigned get_segment_count() const + { + if (segment_order.size() < 2) + return 1; + return segment_order.size(); + } + + bool operator==(const Genesys_Sensor& other) const + { + return sensor_id == other.sensor_id && + optical_res == other.optical_res && + resolutions == other.resolutions && + method == other.method && + ccd_size_divisor == other.ccd_size_divisor && + black_pixels == other.black_pixels && + dummy_pixel == other.dummy_pixel && + ccd_start_xoffset == other.ccd_start_xoffset && + sensor_pixels == other.sensor_pixels && + fau_gain_white_ref == other.fau_gain_white_ref && + gain_white_ref == other.gain_white_ref && + exposure == other.exposure && + exposure_lperiod == other.exposure_lperiod && + segment_size == other.segment_size && + segment_order == other.segment_order && + stagger_config == other.stagger_config && + custom_base_regs == other.custom_base_regs && + custom_regs == other.custom_regs && + custom_fe_regs == other.custom_fe_regs && + gamma == other.gamma; + } +}; + +template +void serialize(Stream& str, Genesys_Sensor& x) +{ + serialize(str, x.sensor_id); + serialize(str, x.optical_res); + serialize(str, x.resolutions); + serialize(str, x.method); + serialize(str, x.ccd_size_divisor); + serialize(str, x.black_pixels); + serialize(str, x.dummy_pixel); + serialize(str, x.ccd_start_xoffset); + serialize(str, x.sensor_pixels); + serialize(str, x.fau_gain_white_ref); + serialize(str, x.gain_white_ref); + serialize_newline(str); + serialize(str, x.exposure.blue); + serialize(str, x.exposure.green); + serialize(str, x.exposure.red); + serialize(str, x.exposure_lperiod); + serialize_newline(str); + serialize(str, x.segment_size); + serialize_newline(str); + serialize(str, x.segment_order); + serialize_newline(str); + serialize(str, x.stagger_config); + serialize_newline(str); + serialize(str, x.custom_base_regs); + serialize_newline(str); + serialize(str, x.custom_regs); + serialize_newline(str); + serialize(str, x.custom_fe_regs); + serialize_newline(str); + serialize(str, x.gamma); + serialize_newline(str); +} + +std::ostream& operator<<(std::ostream& out, const Genesys_Sensor& sensor); + +} // namespace genesys + +#endif // BACKEND_GENESYS_SENSOR_H diff --git a/backend/genesys/serialize.cpp b/backend/genesys/serialize.cpp new file mode 100644 index 0000000..e69de29 diff --git a/backend/genesys/serialize.h b/backend/genesys/serialize.h new file mode 100644 index 0000000..ed40a4e --- /dev/null +++ b/backend/genesys/serialize.h @@ -0,0 +1,150 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_SERIALIZE_H +#define BACKEND_GENESYS_SERIALIZE_H + +#include "error.h" +#include +#include +#include +#include +#include + +namespace genesys { + +// it would be best to use something like boost.serialization + +inline void serialize_newline(std::ostream& str) { str << '\n'; } +inline void serialize_newline(std::istream& str) { (void) str; } + +inline void serialize(std::ostream& str, bool x) { str << static_cast(x) << " "; } +inline void serialize(std::istream& str, bool& x) { unsigned v; str >> v; x = v; } +inline void serialize(std::ostream& str, char x) { str << static_cast(x) << " "; } +inline void serialize(std::istream& str, char& x) { int v; str >> v; x = v; } +inline void serialize(std::ostream& str, unsigned char x) { str << static_cast(x) << " "; } +inline void serialize(std::istream& str, unsigned char& x) { unsigned v; str >> v; x = v; } +inline void serialize(std::ostream& str, signed char x) { str << static_cast(x) << " "; } +inline void serialize(std::istream& str, signed char& x) { int v; str >> v; x = v; } +inline void serialize(std::ostream& str, short x) { str << x << " "; } +inline void serialize(std::istream& str, short& x) { str >> x; } +inline void serialize(std::ostream& str, unsigned short x) { str << x << " "; } +inline void serialize(std::istream& str, unsigned short& x) { str >> x; } +inline void serialize(std::ostream& str, int x) { str << x << " "; } +inline void serialize(std::istream& str, int& x) { str >> x; } +inline void serialize(std::ostream& str, unsigned int x) { str << x << " "; } +inline void serialize(std::istream& str, unsigned int& x) { str >> x; } +inline void serialize(std::ostream& str, long x) { str << x << " "; } +inline void serialize(std::istream& str, long& x) { str >> x; } +inline void serialize(std::ostream& str, unsigned long x) { str << x << " "; } +inline void serialize(std::istream& str, unsigned long& x) { str >> x; } +inline void serialize(std::ostream& str, long long x) { str << x << " "; } +inline void serialize(std::istream& str, long long& x) { str >> x; } +inline void serialize(std::ostream& str, unsigned long long x) { str << x << " "; } +inline void serialize(std::istream& str, unsigned long long& x) { str >> x; } +inline void serialize(std::ostream& str, float x) { str << x << " "; } +inline void serialize(std::istream& str, float& x) { str >> x; } +inline void serialize(std::ostream& str, double x) { str << x << " "; } +inline void serialize(std::istream& str, double& x) { str >> x; } +inline void serialize(std::ostream& str, const std::string& x) { str << x << " "; } +inline void serialize(std::istream& str, std::string& x) { str >> x; } + +template +void serialize(std::ostream& str, std::vector& x) +{ + serialize(str, x.size()); + serialize_newline(str); + + for (auto& item : x) { + serialize(str, item); + serialize_newline(str); + } +} + +template +void serialize(std::istream& str, std::vector& x, + size_t max_size = std::numeric_limits::max()) +{ + size_t new_size; + serialize(str, new_size); + + if (new_size > max_size) { + throw SaneException("Too large std::vector to deserialize"); + } + x.reserve(new_size); + for (size_t i = 0; i < new_size; ++i) { + T item; + serialize(str, item); + x.push_back(item); + } +} + +template +void serialize(std::ostream& str, std::array& x) +{ + serialize(str, x.size()); + serialize_newline(str); + + for (auto& item : x) { + serialize(str, item); + serialize_newline(str); + } +} + +template +void serialize(std::istream& str, std::array& x) +{ + size_t new_size; + serialize(str, new_size); + + if (new_size > Size) { + throw SaneException("Incorrect std::array size to deserialize"); + } + for (auto& item : x) { + serialize(str, item); + } +} + +} // namespace genesys + +#endif diff --git a/backend/genesys/settings.cpp b/backend/genesys/settings.cpp new file mode 100644 index 0000000..41c66de --- /dev/null +++ b/backend/genesys/settings.cpp @@ -0,0 +1,142 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "settings.h" +#include "utilities.h" +#include + +namespace genesys { + +std::ostream& operator<<(std::ostream& out, const Genesys_Settings& settings) +{ + StreamStateSaver state_saver{out}; + + out << "Genesys_Settings{\n" + << " xres: " << settings.xres << " yres: " << settings.yres << '\n' + << " lines: " << settings.lines << '\n' + << " pixels per line (actual): " << settings.pixels << '\n' + << " pixels per line (requested): " << settings.requested_pixels << '\n' + << " depth: " << settings.depth << '\n'; + auto prec = out.precision(); + out.precision(3); + out << " tl_x: " << settings.tl_x << " tl_y: " << settings.tl_y << '\n'; + out.precision(prec); + out << " scan_mode: " << settings.scan_mode << '\n' + << '}'; + return out; +} + +std::ostream& operator<<(std::ostream& out, const SetupParams& params) +{ + StreamStateSaver state_saver{out}; + + out << "SetupParams{\n" + << " xres: " << params.xres << " yres: " << params.yres << '\n' + << " lines: " << params.lines << '\n' + << " pixels per line (actual): " << params.pixels << '\n' + << " pixels per line (requested): " << params.requested_pixels << '\n' + << " depth: " << params.depth << '\n' + << " channels: " << params.channels << '\n' + << " startx: " << params.startx << " starty: " << params.starty << '\n' + << " scan_mode: " << params.scan_mode << '\n' + << " color_filter: " << params.color_filter << '\n' + << " flags: " << params.flags << '\n' + << "}"; + return out; +} + +std::ostream& operator<<(std::ostream& out, const ScanSession& session) +{ + out << "ScanSession{\n" + << " computed: " << session.computed << '\n' + << " hwdpi_divisor: " << session.hwdpi_divisor << '\n' + << " ccd_size_divisor: " << session.ccd_size_divisor << '\n' + << " optical_resolution: " << session.optical_resolution << '\n' + << " optical_pixels: " << session.optical_pixels << '\n' + << " optical_pixels_raw: " << session.optical_pixels_raw << '\n' + << " output_resolution: " << session.output_resolution << '\n' + << " output_pixels: " << session.output_pixels << '\n' + << " output_line_bytes: " << session.output_line_bytes << '\n' + << " output_line_bytes_raw: " << session.output_line_bytes_raw << '\n' + << " output_line_count: " << session.output_line_count << '\n' + << " num_staggered_lines: " << session.num_staggered_lines << '\n' + << " color_shift_lines_r: " << session.color_shift_lines_r << '\n' + << " color_shift_lines_g: " << session.color_shift_lines_g << '\n' + << " color_shift_lines_b: " << session.color_shift_lines_b << '\n' + << " max_color_shift_lines: " << session.max_color_shift_lines << '\n' + << " enable_ledadd: " << session.enable_ledadd << '\n' + << " segment_count: " << session.segment_count << '\n' + << " pixel_startx: " << session.pixel_startx << '\n' + << " pixel_endx: " << session.pixel_endx << '\n' + << " conseq_pixel_dist: " << session.conseq_pixel_dist << '\n' + << " output_segment_pixel_group_count: " + << session.output_segment_pixel_group_count << '\n' + << " buffer_size_read: " << session.buffer_size_read << '\n' + << " buffer_size_read: " << session.buffer_size_lines << '\n' + << " buffer_size_shrink: " << session.buffer_size_shrink << '\n' + << " buffer_size_out: " << session.buffer_size_out << '\n' + << " filters: " + << (session.pipeline_needs_reorder ? " reorder": "") + << (session.pipeline_needs_ccd ? " ccd": "") + << (session.pipeline_needs_shrink ? " shrink": "") << '\n' + << " params: " << format_indent_braced_list(4, session.params) << '\n' + << "}"; + return out; +} + +std::ostream& operator<<(std::ostream& out, const SANE_Parameters& params) +{ + out << "SANE_Parameters{\n" + << " format: " << static_cast(params.format) << '\n' + << " last_frame: " << params.last_frame << '\n' + << " bytes_per_line: " << params.bytes_per_line << '\n' + << " pixels_per_line: " << params.pixels_per_line << '\n' + << " lines: " << params.lines << '\n' + << " depth: " << params.depth << '\n' + << '}'; + return out; +} + +} // namespace genesys diff --git a/backend/genesys/settings.h b/backend/genesys/settings.h new file mode 100644 index 0000000..a697e60 --- /dev/null +++ b/backend/genesys/settings.h @@ -0,0 +1,328 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_SETTINGS_H +#define BACKEND_GENESYS_SETTINGS_H + +#include "enums.h" +#include "serialize.h" + +namespace genesys { + +struct Genesys_Settings +{ + ScanMethod scan_method = ScanMethod::FLATBED; + ScanColorMode scan_mode = ScanColorMode::LINEART; + + // horizontal dpi + unsigned xres = 0; + // vertical dpi + unsigned yres = 0; + + //x start on scan table in mm + double tl_x = 0; + // y start on scan table in mm + double tl_y = 0; + + // number of lines at scan resolution + unsigned int lines = 0; + // number of pixels expected from the scanner + unsigned int pixels = 0; + // number of pixels expected by the frontend + unsigned requested_pixels = 0; + + // bit depth of the scan + unsigned int depth = 0; + + ColorFilter color_filter = ColorFilter::NONE; + + // true if scan is true gray, false if monochrome scan + int true_gray = 0; + + // lineart threshold + int threshold = 0; + + // lineart threshold curve for dynamic rasterization + int threshold_curve = 0; + + // Disable interpolation for xres::max(); + + // resolution in x direction + unsigned xres = NOT_SET; + // resolution in y direction + unsigned yres = NOT_SET; + // start pixel in X direction, from dummy_pixel + 1 + unsigned startx = NOT_SET; + // start pixel in Y direction, counted according to base_ydpi + unsigned starty = NOT_SET; + // the number of pixels in X direction. Note that each logical pixel may correspond to more + // than one CCD pixel, see CKSEL and GenesysSensor::ccd_pixels_per_system_pixel() + unsigned pixels = NOT_SET; + + // the number of pixels in the X direction as requested by the frontend. This will be different + // from `pixels` if the X resolution requested by the frontend is different than the actual + // resolution. This is only needed to compute dev->total_bytes_to_read. If 0, then the value + // is the same as pixels. + // TODO: move the computation of total_bytes_to_read to a higher layer. + unsigned requested_pixels = 0; + + // the number of pixels in Y direction + unsigned lines = NOT_SET; + // the depth of the scan in bits. Allowed are 1, 8, 16 + unsigned depth = NOT_SET; + // the number of channels + unsigned channels = NOT_SET; + + ScanMethod scan_method = static_cast(NOT_SET); + + ScanColorMode scan_mode = static_cast(NOT_SET); + + ColorFilter color_filter = static_cast(NOT_SET); + + ScanFlag flags; + + unsigned get_requested_pixels() const + { + if (requested_pixels != 0) { + return requested_pixels; + } + return pixels; + } + + void assert_valid() const + { + if (xres == NOT_SET || yres == NOT_SET || startx == NOT_SET || starty == NOT_SET || + pixels == NOT_SET || lines == NOT_SET ||depth == NOT_SET || channels == NOT_SET || + scan_method == static_cast(NOT_SET) || + scan_mode == static_cast(NOT_SET) || + color_filter == static_cast(NOT_SET)) + { + throw std::runtime_error("SetupParams are not valid"); + } + } + + bool operator==(const SetupParams& other) const + { + return xres == other.xres && + yres == other.yres && + startx == other.startx && + starty == other.starty && + pixels == other.pixels && + requested_pixels == other.requested_pixels && + lines == other.lines && + depth == other.depth && + channels == other.channels && + scan_method == other.scan_method && + scan_mode == other.scan_mode && + color_filter == other.color_filter && + flags == other.flags; + } +}; + +std::ostream& operator<<(std::ostream& out, const SetupParams& params); + +template +void serialize(Stream& str, SetupParams& x) +{ + serialize(str, x.xres); + serialize(str, x.yres); + serialize(str, x.startx); + serialize(str, x.starty); + serialize(str, x.pixels); + serialize(str, x.requested_pixels); + serialize(str, x.lines); + serialize(str, x.depth); + serialize(str, x.channels); + serialize(str, x.scan_method); + serialize(str, x.scan_mode); + serialize(str, x.color_filter); + serialize(str, x.flags); +} + +struct ScanSession { + SetupParams params; + + // whether the session setup has been computed via compute_session() + bool computed = false; + + // specifies the reduction (if any) of hardware dpi on the Genesys chip side. + // except gl646 + unsigned hwdpi_divisor = 1; + + // specifies the reduction (if any) of CCD effective dpi which is performed by latching the + // data coming from CCD in such a way that 1/2 or 3/4 of pixel data is ignored. + unsigned ccd_size_divisor = 1; + + // the optical resolution of the scanner. + unsigned optical_resolution = 0; + + // the number of pixels at the optical resolution, not including segmentation overhead. + unsigned optical_pixels = 0; + + // the number of pixels at the optical resolution, including segmentation overhead. + // only on gl846, g847 + unsigned optical_pixels_raw = 0; + + // the resolution of the output data. + // gl843-only + unsigned output_resolution = 0; + + // the number of pixels in output data (after desegmentation) + unsigned output_pixels = 0; + + // the number of bytes in the output of a channel of a single line (after desegmentation) + unsigned output_channel_bytes = 0; + + // the number of bytes in the output of a single line (after desegmentation) + unsigned output_line_bytes = 0; + + // the number of bytes per line in the output data from the scanner (before desegmentation) + // Equal to output_line_bytes if sensor does not have segments + unsigned output_line_bytes_raw = 0; + + // the number of bytes per line as requested by the frontend + unsigned output_line_bytes_requested = 0; + + // the number of lines in the output of the scanner. This must be larger than the user + // requested number due to line staggering and color channel shifting. + unsigned output_line_count = 0; + + // the total number of bytes to read from the scanner (before desegmentation) + unsigned output_total_bytes_raw = 0; + + // the total number of bytes to read from the scanner (after desegmentation) + unsigned output_total_bytes = 0; + + // the number of staggered lines (i.e. lines that overlap during scanning due to line being + // thinner than the CCD element) + unsigned num_staggered_lines = 0; + + // the number of lines that color channels shift due to different physical positions of + // different color channels. + unsigned max_color_shift_lines = 0; + + // actual line shift of the red color + unsigned color_shift_lines_r = 0; + // actual line shift of the green color + unsigned color_shift_lines_g = 0; + // actual line shift of the blue color + unsigned color_shift_lines_b = 0; + + // the number of scanner segments used in the current scan + unsigned segment_count = 1; + + // the physical pixel positions that are sent to the registers + unsigned pixel_startx = 0; + unsigned pixel_endx = 0; + + // certain scanners require the logical pixel count to be multiplied on certain resolutions + unsigned pixel_count_multiplier = 1; + + // Distance in pixels between consecutive pixels, e.g. between odd and even pixels. Note that + // the number of segments can be large. + // only on gl124, gl846, gl847 + unsigned conseq_pixel_dist = 0; + + // The number of "even" pixels to scan. This corresponds to the number of pixels that will be + // scanned from a single segment + // only on gl124, gl846, gl847 + unsigned output_segment_pixel_group_count = 0; + + // The number of bytes to skip at start of line during desegmentation. + // Currently it's always zero. + unsigned output_segment_start_offset = 0; + + // the sizes of the corresponding buffers + size_t buffer_size_read = 0; + size_t buffer_size_lines = 0; + size_t buffer_size_shrink = 0; + size_t buffer_size_out = 0; + + // whether to enable ledadd functionality + bool enable_ledadd = false; + + // what pipeline modifications are needed + bool pipeline_needs_reorder = false; + bool pipeline_needs_ccd = false; + bool pipeline_needs_shrink = false; + + void assert_computed() const + { + if (!computed) { + throw std::runtime_error("ScanSession is not computed"); + } + } +}; + +std::ostream& operator<<(std::ostream& out, const ScanSession& session); + +std::ostream& operator<<(std::ostream& out, const SANE_Parameters& params); + +} // namespace genesys + +#endif // BACKEND_GENESYS_SETTINGS_H diff --git a/backend/genesys/static_init.cpp b/backend/genesys/static_init.cpp new file mode 100644 index 0000000..c0f3748 --- /dev/null +++ b/backend/genesys/static_init.cpp @@ -0,0 +1,70 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "static_init.h" +#include + +namespace genesys { + +static std::unique_ptr>> s_functions_run_at_backend_exit; + +void add_function_to_run_at_backend_exit(const std::function& function) +{ + if (!s_functions_run_at_backend_exit) + s_functions_run_at_backend_exit.reset(new std::vector>()); + s_functions_run_at_backend_exit->push_back(std::move(function)); +} + +void run_functions_at_backend_exit() +{ + for (auto it = s_functions_run_at_backend_exit->rbegin(); + it != s_functions_run_at_backend_exit->rend(); ++it) + { + (*it)(); + } + s_functions_run_at_backend_exit.reset(); +} + +} // namespace genesys diff --git a/backend/genesys/static_init.h b/backend/genesys/static_init.h new file mode 100644 index 0000000..3ffa62c --- /dev/null +++ b/backend/genesys/static_init.h @@ -0,0 +1,88 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_STATIC_INIT_H +#define BACKEND_GENESYS_STATIC_INIT_H + +#include +#include + +namespace genesys { + +void add_function_to_run_at_backend_exit(const std::function& function); + +// calls functions added via add_function_to_run_at_backend_exit() in reverse order of being +// added. +void run_functions_at_backend_exit(); + +template +class StaticInit { +public: + StaticInit() = default; + StaticInit(const StaticInit&) = delete; + StaticInit& operator=(const StaticInit&) = delete; + + template + void init(Args&& ... args) + { + ptr_ = std::unique_ptr(new T(std::forward(args)...)); + add_function_to_run_at_backend_exit([this](){ deinit(); }); + } + + void deinit() + { + ptr_.reset(); + } + + const T* operator->() const { return ptr_.get(); } + T* operator->() { return ptr_.get(); } + const T& operator*() const { return *ptr_.get(); } + T& operator*() { return *ptr_.get(); } + +private: + std::unique_ptr ptr_; +}; + +} // namespace genesys + +#endif // BACKEND_GENESYS_STATIC_INIT_H diff --git a/backend/genesys/status.cpp b/backend/genesys/status.cpp new file mode 100644 index 0000000..7f883b0 --- /dev/null +++ b/backend/genesys/status.cpp @@ -0,0 +1,66 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "status.h" +#include + +namespace genesys { + +std::ostream& operator<<(std::ostream& out, Status status) +{ + out << "Status{\n" + << " replugged: " << (status.is_replugged ? "yes" : "no") << '\n' + << " is_buffer_empty: " << (status.is_buffer_empty ? "yes" : "no") << '\n' + << " is_feeding_finished: " << (status.is_feeding_finished ? "yes" : "no") << '\n' + << " is_scanning_finished: " << (status.is_scanning_finished ? "yes" : "no") << '\n' + << " is_at_home: " << (status.is_at_home ? "yes" : "no") << '\n' + << " is_lamp_on: " << (status.is_lamp_on ? "yes" : "no") << '\n' + << " is_front_end_busy: " << (status.is_front_end_busy ? "yes" : "no") << '\n' + << " is_motor_enabled: " << (status.is_motor_enabled ? "yes" : "no") << '\n' + << "}\n"; + return out; +} + +} // namespace genesys diff --git a/backend/genesys/status.h b/backend/genesys/status.h new file mode 100644 index 0000000..91f4692 --- /dev/null +++ b/backend/genesys/status.h @@ -0,0 +1,68 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_STATUS_H +#define BACKEND_GENESYS_STATUS_H + +#include + +namespace genesys { + +/// Represents the scanner status register +struct Status +{ + bool is_replugged = false; + bool is_buffer_empty = false; + bool is_feeding_finished = false; + bool is_scanning_finished = false; + bool is_at_home = false; + bool is_lamp_on = false; + bool is_front_end_busy = false; + bool is_motor_enabled = false; +}; + +std::ostream& operator<<(std::ostream& out, Status status); + +} // namespace genesys + +#endif // BACKEND_GENESYS_STATUS_H diff --git a/backend/genesys/tables_frontend.cpp b/backend/genesys/tables_frontend.cpp new file mode 100644 index 0000000..1edf32f --- /dev/null +++ b/backend/genesys/tables_frontend.cpp @@ -0,0 +1,653 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "low.h" + +namespace genesys { + +StaticInit> s_frontends; + +void genesys_init_frontend_tables() +{ + s_frontends.init(); + + GenesysFrontendLayout wolfson_layout; + wolfson_layout.type = FrontendType::WOLFSON; + wolfson_layout.offset_addr = { 0x20, 0x21, 0x22 }; + wolfson_layout.gain_addr = { 0x28, 0x29, 0x2a }; + + GenesysFrontendLayout analog_devices; + analog_devices.type = FrontendType::ANALOG_DEVICES; + + + Genesys_Frontend fe; + fe.id = AdcId::WOLFSON_UMAX; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x11 }, + { 0x20, 0x80 }, + { 0x21, 0x80 }, + { 0x22, 0x80 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x02 }, + { 0x29, 0x02 }, + { 0x2a, 0x02 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::WOLFSON_ST12; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x03 }, + { 0x20, 0xc8 }, + { 0x21, 0xc8 }, + { 0x22, 0xc8 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x04 }, + { 0x29, 0x04 }, + { 0x2a, 0x04 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::WOLFSON_ST24; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x21 }, + { 0x20, 0xc8 }, + { 0x21, 0xc8 }, + { 0x22, 0xc8 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x06 }, + { 0x29, 0x06 }, + { 0x2a, 0x06 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::WOLFSON_5345; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x12 }, + { 0x20, 0xb8 }, + { 0x21, 0xb8 }, + { 0x22, 0xb8 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x04 }, + { 0x29, 0x04 }, + { 0x2a, 0x04 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + // reg3=0x02 for 50-600 dpi, 0x32 (0x12 also works well) at 1200 + fe = Genesys_Frontend(); + fe.id = AdcId::WOLFSON_HP2400; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x02 }, + { 0x20, 0xb4 }, + { 0x21, 0xb6 }, + { 0x22, 0xbc }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x06 }, + { 0x29, 0x09 }, + { 0x2a, 0x08 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::WOLFSON_HP2300; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x04 }, + { 0x03, 0x02 }, + { 0x20, 0xbe }, + { 0x21, 0xbe }, + { 0x22, 0xbe }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x04 }, + { 0x29, 0x04 }, + { 0x2a, 0x04 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_LIDE_35; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x3d }, + { 0x02, 0x08 }, + { 0x03, 0x00 }, + { 0x20, 0xe1 }, + { 0x21, 0xe1 }, + { 0x22, 0xe1 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x93 }, + { 0x29, 0x93 }, + { 0x2a, 0x93 }, + }; + fe.reg2 = {0x00, 0x19, 0x06}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::AD_XP200; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x58 }, + { 0x01, 0x80 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x09 }, + { 0x21, 0x09 }, + { 0x22, 0x09 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x09 }, + { 0x29, 0x09 }, + { 0x2a, 0x09 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::WOLFSON_XP300; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x35 }, + { 0x02, 0x20 }, + { 0x03, 0x14 }, + { 0x20, 0xe1 }, + { 0x21, 0xe1 }, + { 0x22, 0xe1 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x93 }, + { 0x29, 0x93 }, + { 0x2a, 0x93 }, + }; + fe.reg2 = {0x07, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::WOLFSON_HP3670; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x03 }, + { 0x02, 0x05 }, + { 0x03, 0x32 }, + { 0x20, 0xba }, + { 0x21, 0xb8 }, + { 0x22, 0xb8 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x06 }, + { 0x29, 0x05 }, + { 0x2a, 0x04 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::WOLFSON_DSM600; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x35 }, + { 0x02, 0x20 }, + { 0x03, 0x14 }, + { 0x20, 0x85 }, + { 0x21, 0x85 }, + { 0x22, 0x85 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0xa0 }, + { 0x29, 0xa0 }, + { 0x2a, 0xa0 }, + }; + fe.reg2 = {0x07, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_LIDE_200; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x9d }, + { 0x01, 0x91 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x3f }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x32 }, + { 0x29, 0x04 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_LIDE_700F; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x9d }, + { 0x01, 0x9e }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x3f }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x2f }, + { 0x29, 0x04 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::KVSS080; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x0f }, + { 0x20, 0x80 }, + { 0x21, 0x80 }, + { 0x22, 0x80 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x4b }, + { 0x29, 0x4b }, + { 0x2a, 0x4b }, + }; + fe.reg2 = {0x00,0x00,0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::G4050; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x1f }, + { 0x20, 0x45 }, + { 0x21, 0x45 }, + { 0x22, 0x45 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x4b }, + { 0x29, 0x4b }, + { 0x2a, 0x4b }, + }; + fe.reg2 = {0x00,0x00,0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_LIDE_110; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x80 }, + { 0x01, 0x8a }, + { 0x02, 0x23 }, + { 0x03, 0x4c }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0xca }, + { 0x26, 0x94 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + /** @brief GL124 special case + * for GL124 based scanners, this struct is "abused" + * in fact the fields are map like below to AFE registers + * (from Texas Instrument or alike ?) + */ + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_LIDE_120; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x80 }, + { 0x01, 0xa3 }, + { 0x02, 0x2b }, + { 0x03, 0x4c }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, // actual address 0x05 + { 0x25, 0xca }, // actual address 0x06 + { 0x26, 0x95 }, // actual address 0x07 + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::PLUSTEK_OPTICPRO_3600; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x70 }, + { 0x01, 0x80 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x3f }, + { 0x29, 0x3d }, + { 0x2a, 0x3d }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::PLUSTEK_OPTICFILM_7200I; + fe.layout = analog_devices; + fe.regs = { + { 0x00, 0xf8 }, + { 0x01, 0x80 }, + { 0x02, 0x0a }, + { 0x03, 0x06 }, + { 0x04, 0x0f }, + { 0x05, 0x56 }, + { 0x06, 0x64 }, + { 0x07, 0x56 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::PLUSTEK_OPTICFILM_7300; + fe.layout = analog_devices; + fe.regs = { + { 0x00, 0xf8 }, + { 0x01, 0x80 }, + { 0x02, 0x10 }, + { 0x03, 0x06 }, + { 0x04, 0x06 }, + { 0x05, 0x09 }, + { 0x06, 0x0a }, + { 0x07, 0x0102 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::PLUSTEK_OPTICFILM_7500I; + fe.layout = analog_devices; + fe.regs = { + { 0x00, 0xf8 }, + { 0x01, 0x80 }, + { 0x02, 0x1d }, + { 0x03, 0x17 }, + { 0x04, 0x13 }, + { 0x05, 0x00 }, + { 0x06, 0x00 }, + { 0x07, 0x0111 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_4400F; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x2f }, + { 0x20, 0x6d }, + { 0x21, 0x67 }, + { 0x22, 0x5b }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0xd8 }, + { 0x29, 0xd1 }, + { 0x2a, 0xb9 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_8400F; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x0f }, + { 0x20, 0x60 }, + { 0x21, 0x5c }, + { 0x22, 0x6c }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x8a }, + { 0x29, 0x9f }, + { 0x2a, 0xc2 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_8600F; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x00 }, + { 0x01, 0x23 }, + { 0x02, 0x24 }, + { 0x03, 0x2f }, + { 0x20, 0x67 }, + { 0x21, 0x69 }, + { 0x22, 0x68 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0xdb }, + { 0x29, 0xda }, + { 0x2a, 0xd7 }, + }; + fe.reg2 = { 0x00, 0x00, 0x00 }; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::IMG101; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x78 }, + { 0x01, 0xf0 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + fe = Genesys_Frontend(); + fe.id = AdcId::PLUSTEK_OPTICBOOK_3800; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x78 }, + { 0x01, 0xf0 }, + { 0x02, 0x00 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); + + + /* reg0: control 74 data, 70 no data + * reg3: offset + * reg6: gain + * reg0 , reg3, reg6 */ + fe = Genesys_Frontend(); + fe.id = AdcId::CANON_LIDE_80; + fe.layout = wolfson_layout; + fe.regs = { + { 0x00, 0x70 }, + { 0x01, 0x16 }, + { 0x02, 0x60 }, + { 0x03, 0x00 }, + { 0x20, 0x00 }, + { 0x21, 0x00 }, + { 0x22, 0x00 }, + { 0x24, 0x00 }, + { 0x25, 0x00 }, + { 0x26, 0x00 }, + { 0x28, 0x00 }, + { 0x29, 0x00 }, + { 0x2a, 0x00 }, + }; + fe.reg2 = {0x00, 0x00, 0x00}; + s_frontends->push_back(fe); +} + +} // namespace genesys diff --git a/backend/genesys/tables_gpo.cpp b/backend/genesys/tables_gpo.cpp new file mode 100644 index 0000000..2c9ad5e --- /dev/null +++ b/backend/genesys/tables_gpo.cpp @@ -0,0 +1,415 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "low.h" + +namespace genesys { + +StaticInit> s_gpo; + +void genesys_init_gpo_tables() +{ + s_gpo.init(); + + Genesys_Gpo gpo; + gpo.id = GpioId::UMAX; + gpo.regs = { + { 0x66, 0x11 }, + { 0x67, 0x00 }, + { 0x68, 0x51 }, + { 0x69, 0x20 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::ST12; + gpo.regs = { + { 0x66, 0x11 }, + { 0x67, 0x00 }, + { 0x68, 0x51 }, + { 0x69, 0x20 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::ST24; + gpo.regs = { + { 0x66, 0x00 }, + { 0x67, 0x00 }, + { 0x68, 0x51 }, + { 0x69, 0x20 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::MD_5345; // bits 11-12 are for bipolar V-ref input voltage + gpo.regs = { + { 0x66, 0x30 }, + { 0x67, 0x18 }, + { 0x68, 0xa0 }, + { 0x69, 0x18 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::HP2400; + gpo.regs = { + { 0x66, 0x30 }, + { 0x67, 0x00 }, + { 0x68, 0x31 }, + { 0x69, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::HP2300; + gpo.regs = { + { 0x66, 0x00 }, + { 0x67, 0x00 }, + { 0x68, 0x00 }, + { 0x69, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_LIDE_35; + gpo.regs = { + { 0x6c, 0x02 }, + { 0x6d, 0x80 }, + { 0x6e, 0xef }, + { 0x6f, 0x80 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::XP200; + gpo.regs = { + { 0x66, 0x30 }, + { 0x67, 0x00 }, + { 0x68, 0xb0 }, + { 0x69, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::HP3670; + gpo.regs = { + { 0x66, 0x00 }, + { 0x67, 0x00 }, + { 0x68, 0x00 }, + { 0x69, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::XP300; + gpo.regs = { + { 0x6c, 0x09 }, + { 0x6d, 0xc6 }, + { 0x6e, 0xbb }, + { 0x6f, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::DP665; + gpo.regs = { + { 0x6c, 0x18 }, + { 0x6d, 0x00 }, + { 0x6e, 0xbb }, + { 0x6f, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::DP685; + gpo.regs = { + { 0x6c, 0x3f }, + { 0x6d, 0x46 }, + { 0x6e, 0xfb }, + { 0x6f, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_LIDE_200; + gpo.regs = { + { 0x6c, 0xfb }, // 0xfb when idle , 0xf9/0xe9 (1200) when scanning + { 0x6d, 0x20 }, + { 0x6e, 0xff }, + { 0x6f, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_LIDE_700F; + gpo.regs = { + { 0x6c, 0xdb }, + { 0x6d, 0xff }, + { 0x6e, 0xff }, + { 0x6f, 0x80 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::KVSS080; + gpo.regs = { + { 0x6c, 0xf5 }, + { 0x6d, 0x20 }, + { 0x6e, 0x7e }, + { 0x6f, 0xa1 }, + { 0xa6, 0x06 }, + { 0xa7, 0x0f }, + { 0xa8, 0x00 }, + { 0xa9, 0x08 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::G4050; + gpo.regs = { + { 0x6c, 0x20 }, + { 0x6d, 0x00 }, + { 0x6e, 0xfc }, + { 0x6f, 0x00 }, + { 0xa6, 0x08 }, + { 0xa7, 0x1e }, + { 0xa8, 0x3e }, + { 0xa9, 0x06 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::HP_N6310; + gpo.regs = { + { 0x6c, 0xa3 }, + { 0x6d, 0x00 }, + { 0x6e, 0x7f }, + { 0x6f, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_LIDE_110; + gpo.regs = { + { 0x6c, 0xfb }, + { 0x6d, 0x20 }, + { 0x6e, 0xff }, + { 0x6f, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_LIDE_120; + gpo.regs = { + { 0x6c, 0xfb }, + { 0x6d, 0x20 }, + { 0x6e, 0xff }, + { 0x6f, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_LIDE_210; + gpo.regs = { + { 0x6c, 0xfb }, + { 0x6d, 0x20 }, + { 0x6e, 0xff }, + { 0x6f, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::PLUSTEK_OPTICPRO_3600; + gpo.regs = { + { 0x6c, 0x02 }, + { 0x6d, 0x00 }, + { 0x6e, 0x1e }, + { 0x6f, 0x80 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::PLUSTEK_OPTICFILM_7200I; + gpo.regs = { + { 0x6c, 0x4c }, + { 0x6d, 0x80 }, + { 0x6e, 0x4c }, + { 0x6f, 0x80 }, + { 0xa6, 0x00 }, + { 0xa7, 0x07 }, + { 0xa8, 0x20 }, + { 0xa9, 0x01 }, + }; + s_gpo->push_back(gpo); + + gpo = Genesys_Gpo(); + gpo.id = GpioId::PLUSTEK_OPTICFILM_7300; + gpo.regs = { + { 0x6c, 0x4c }, + { 0x6d, 0x00 }, + { 0x6e, 0x4c }, + { 0x6f, 0x80 }, + { 0xa6, 0x00 }, + { 0xa7, 0x07 }, + { 0xa8, 0x20 }, + { 0xa9, 0x01 }, + }; + s_gpo->push_back(gpo); + + gpo = Genesys_Gpo(); + gpo.id = GpioId::PLUSTEK_OPTICFILM_7500I; + gpo.regs = { + { 0x6c, 0x4c }, + { 0x6d, 0x00 }, + { 0x6e, 0x4c }, + { 0x6f, 0x80 }, + { 0xa6, 0x00 }, + { 0xa7, 0x07 }, + { 0xa8, 0x20 }, + { 0xa9, 0x01 }, + }; + s_gpo->push_back(gpo); + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_4400F; + gpo.regs = { + { 0x6c, 0x01 }, + { 0x6d, 0x7f }, + { 0x6e, 0xff }, + { 0x6f, 0x00 }, + { 0xa6, 0x00 }, + { 0xa7, 0xff }, + { 0xa8, 0x07 }, + { 0xa9, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_8400F; + gpo.regs = { + { 0x6c, 0x9a }, + { 0x6d, 0xdf }, + { 0x6e, 0xfe }, + { 0x6f, 0x60 }, + { 0xa6, 0x00 }, + { 0xa7, 0x03 }, + { 0xa8, 0x00 }, + { 0xa9, 0x02 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_8600F; + gpo.regs = { + { 0x6c, 0x20 }, + { 0x6d, 0x7c }, + { 0x6e, 0xff }, + { 0x6f, 0x00 }, + { 0xa6, 0x00 }, + { 0xa7, 0xff }, + { 0xa8, 0x00 }, + { 0xa9, 0x00 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::IMG101; + gpo.regs = { + { 0x6c, 0x41 }, + { 0x6d, 0xa4 }, + { 0x6e, 0x13 }, + { 0x6f, 0xa7 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::PLUSTEK_OPTICBOOK_3800; + gpo.regs = { + { 0x6c, 0x41 }, + { 0x6d, 0xa4 }, + { 0x6e, 0x13 }, + { 0x6f, 0xa7 }, + }; + s_gpo->push_back(gpo); + + + gpo = Genesys_Gpo(); + gpo.id = GpioId::CANON_LIDE_80; + gpo.regs = { + { 0x6c, 0x28 }, + { 0x6d, 0x90 }, + { 0x6e, 0x75 }, + { 0x6f, 0x80 }, + }; + s_gpo->push_back(gpo); +} + +} // namespace genesys diff --git a/backend/genesys/tables_model.cpp b/backend/genesys/tables_model.cpp new file mode 100644 index 0000000..0b3a0af --- /dev/null +++ b/backend/genesys/tables_model.cpp @@ -0,0 +1,2958 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2003 Oliver Rauch + Copyright (C) 2003-2005 Henning Meier-Geinitz + Copyright (C) 2004, 2005 Gerhard Jaeger + Copyright (C) 2004-2013 Stéphane Voltz + Copyright (C) 2005-2009 Pierre Willenbrock + Copyright (C) 2007 Luke + Copyright (C) 2010 Jack McGill + Copyright (C) 2010 Andrey Loginov , + xerox travelscan device entry + Copyright (C) 2010 Chris Berry and Michael Rickmann + for Plustek Opticbook 3600 support + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "low.h" + +namespace genesys { + +StaticInit> s_usb_devices; + +void genesys_init_usb_device_tables() +{ + s_usb_devices.init(); + + Genesys_Model model; + model.name = "umax-astra-4500"; + model.vendor = "UMAX"; + model.model = "Astra 4500"; + model.model_id = ModelId::UMAX_ASTRA_4500; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 150, 75 }, + { 2400, 1200, 600, 300, 150, 75 } + } + }; + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 3.5; + model.y_offset = 7.5; + model.x_size = 218.0; + model.y_size = 299.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 1.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 8; + model.ld_shift_b = 16; + + model.line_mode_color_order = ColorOrder::BGR; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_UMAX; + model.adc_id = AdcId::WOLFSON_UMAX; + model.gpio_id = GpioId::UMAX; + model.motor_id = MotorId::UMAX; + model.flags = GENESYS_FLAG_UNTESTED; + model.buttons = GENESYS_HAS_NO_BUTTONS; + model.shading_lines = 20; + model.shading_ta_lines = 0; + model.search_lines = 200; + + s_usb_devices->emplace_back(0x0638, 0x0a10, model); + + + model = Genesys_Model(); + model.name = "canon-lide-50"; + model.vendor = "Canon"; + model.model = "LiDE 35/40/50"; + model.model_id = ModelId::CANON_LIDE_50; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 200, 150, 75 }, + { 2400, 1200, 600, 300, 200, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.42; + model.y_offset = 7.9; + model.x_size = 218.0; + model.y_size = 299.0; + + model.y_offset_calib_white = 6.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_35; + model.adc_id = AdcId::CANON_LIDE_35; + model.gpio_id = GpioId::CANON_LIDE_35; + model.motor_id = MotorId::CANON_LIDE_35; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_WHITE_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_FILE_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_COPY_SW; + model.shading_lines = 280; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x2213, model); + + + model = Genesys_Model(); + model.name = "panasonic-kv-ss080"; + model.vendor = "Panasonic"; + model.model = "KV-SS080"; + model.model_id = ModelId::PANASONIC_KV_SS080; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, /* 500, 400,*/ 300, 200, 150, 100, 75 }, + { 1200, 600, /* 500, 400, */ 300, 200, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 7.2; + model.y_offset = 14.7; + model.x_size = 217.7; + model.y_size = 300.0; + + model.y_offset_calib_white = 9.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 0.0; + model.y_size_ta = 0.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 8; + model.ld_shift_b = 16; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_KVSS080; + model.adc_id = AdcId::KVSS080; + model.gpio_id = GpioId::KVSS080; + model.motor_id = MotorId::KVSS080; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x04da, 0x100f, model); + + + model = Genesys_Model(); + model.name = "hewlett-packard-scanjet-4850c"; + model.vendor = "Hewlett Packard"; + model.model = "ScanJet 4850C"; + model.model_id = ModelId::HP_SCANJET_4850C; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 2400, 1200, 600, 400, 300, 200, 150, 100 }, + { 2400, 1200, 600, 400, 300, 200, 150, 100 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 7.9; + model.y_offset = 10.0; + model.x_size = 219.6; + model.y_size = 314.5; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_HP_4850C; + model.adc_id = AdcId::G4050; + model.gpio_id = GpioId::G4050; + model.motor_id = MotorId::G4050; + model.flags = GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 100; + s_usb_devices->emplace_back(0x03f0, 0x1b05, model); + + + model = Genesys_Model(); + model.name = "hewlett-packard-scanjet-g4010"; + model.vendor = "Hewlett Packard"; + model.model = "ScanJet G4010"; + model.model_id = ModelId::HP_SCANJET_G4010; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 2400, 1200, 600, 400, 300, 200, 150, 100 }, + { 2400, 1200, 600, 400, 300, 200, 150, 100 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 8.0; + model.y_offset = 13.00; + model.x_size = 217.9; + model.y_size = 315.0; + + model.y_offset_calib_white = 3.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_G4050; + model.adc_id = AdcId::G4050; + model.gpio_id = GpioId::G4050; + model.motor_id = MotorId::G4050; + model.flags = GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x03f0, 0x4505, model); + + + model = Genesys_Model(); + model.name = "hewlett-packard-scanjet-g4050"; + model.vendor = "Hewlett Packard"; + model.model = "ScanJet G4050"; + model.model_id = ModelId::HP_SCANJET_G4050; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 2400, 1200, 600, 400, 300, 200, 150, 100 }, + { 2400, 1200, 600, 400, 300, 200, 150, 100 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 8.0; + model.y_offset = 10.00; + model.x_size = 217.9; + model.y_size = 315.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 8.0; + model.y_offset_ta = 13.00; + model.x_size_ta = 217.9; + model.y_size_ta = 250.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 40.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_G4050; + model.adc_id = AdcId::G4050; + model.gpio_id = GpioId::G4050; + model.motor_id = MotorId::G4050; + model.flags = GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x03f0, 0x4605, model); + + + model = Genesys_Model(); + model.name = "canon-canoscan-4400f"; + model.vendor = "Canon"; + model.model = "Canoscan 4400f"; + model.model_id = ModelId::CANON_4400F; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300 }, + { 1200, 600, 300 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 6.0; + model.y_offset = 12.00; + model.x_size = 215.9; + model.y_size = 297.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 8.0; + model.y_offset_ta = 13.00; + model.x_size_ta = 217.9; + model.y_size_ta = 250.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 40.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 96; + model.ld_shift_g = 48; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_CANON_4400F; + model.adc_id = AdcId::CANON_4400F; + model.gpio_id = GpioId::CANON_4400F; + model.motor_id = MotorId::CANON_4400F; + model.flags = GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_FULL_HWDPI_MODE | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SHADING_REPARK; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x04a9, 0x2228, model); + + + model = Genesys_Model(); + model.name = "canon-canoscan-8400f"; + model.vendor = "Canon"; + model.model = "Canoscan 8400f"; + model.model_id = ModelId::CANON_8400F; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 3200, 1600, 800, 400 }, + { 3200, 1600, 800, 400 }, + }, { + { ScanMethod::TRANSPARENCY }, + { 3200, 1600, 800, 400 }, + { 3200, 1600, 800, 400 }, + }, { + { ScanMethod::TRANSPARENCY_INFRARED }, + { 3200, 1600, 800, 400 }, + { 3200, 1600, 800, 400 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 3.5; + model.y_offset = 17.00; + model.x_size = 219.9; + model.y_size = 300.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 10.0; + + model.x_offset_ta = 75.0; + model.y_offset_ta = 45.00; + model.x_size_ta = 75.0; + model.y_size_ta = 230.0; + + model.y_offset_sensor_to_ta = 22.0; + model.y_offset_calib_white_ta = 25.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_CANON_8400F; + model.adc_id = AdcId::CANON_8400F; + model.gpio_id = GpioId::CANON_8400F; + model.motor_id = MotorId::CANON_8400F; + model.flags = GENESYS_FLAG_HAS_UTA | + GENESYS_FLAG_HAS_UTA_INFRARED | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_FULL_HWDPI_MODE | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SHADING_REPARK; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW; + model.shading_lines = 100; + model.shading_ta_lines = 50; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x04a9, 0x221e, model); + + + model = Genesys_Model(); + model.name = "canon-canoscan-8600f"; + model.vendor = "Canon"; + model.model = "Canoscan 8600f"; + model.model_id = ModelId::CANON_8600F; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300 }, + { 1200, 600, 300 }, + }, { + { ScanMethod::TRANSPARENCY, ScanMethod::TRANSPARENCY_INFRARED }, + { 4800, 2400, 1200, 600, 300 }, + { 4800, 2400, 1200, 600, 300 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 24.0; + model.y_offset = 10.0; + model.x_size = 216.0; + model.y_size = 297.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 8.0; + + model.x_offset_ta = 85.0; + model.y_offset_ta = 26.0; + model.x_size_ta = 70.0; + model.y_size_ta = 230.0; + + model.y_offset_sensor_to_ta = 11.5; + model.y_offset_calib_white_ta = 14.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 48; + model.ld_shift_b = 96; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_CANON_8600F; + model.adc_id = AdcId::CANON_8600F; + model.gpio_id = GpioId::CANON_8600F; + model.motor_id = MotorId::CANON_8600F; + model.flags = GENESYS_FLAG_HAS_UTA | + GENESYS_FLAG_HAS_UTA_INFRARED | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_FULL_HWDPI_MODE | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SHADING_REPARK; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW; + model.shading_lines = 50; + model.shading_ta_lines = 50; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x04a9, 0x2229, model); + + + model = Genesys_Model(); + model.name = "canon-lide-100"; + model.vendor = "Canon"; + model.model = "LiDE 100"; + model.model_id = ModelId::CANON_LIDE_100; + model.asic_type = AsicType::GL847; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 2400, 1200, 600, 300, 200, 150, 100, 75 }, + { 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 1.1; + model.y_offset = 8.3; + model.x_size = 216.07; + model.y_size = 299.0; + + model.y_offset_calib_white = 1.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_100; + model.adc_id = AdcId::CANON_LIDE_200; + model.gpio_id = GpioId::CANON_LIDE_200; + model.motor_id = MotorId::CANON_LIDE_100; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_SIS_SENSOR | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_FILE_SW; + model.shading_lines = 50; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x1904, model); + + + model = Genesys_Model(); + model.name = "canon-lide-110"; + model.vendor = "Canon"; + model.model = "LiDE 110"; + model.model_id = ModelId::CANON_LIDE_110; + model.asic_type = AsicType::GL124; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 }, + { 4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 2.2; + model.y_offset = 9.0; + model.x_size = 216.70; + model.y_size = 300.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_110; + model.adc_id = AdcId::CANON_LIDE_110; + model.gpio_id = GpioId::CANON_LIDE_110; + model.motor_id = MotorId::CANON_LIDE_110; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_FILE_SW; + model.shading_lines = 25; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x1909, model); + + + model = Genesys_Model(); + model.name = "canon-lide-120"; + model.vendor = "Canon"; + model.model = "LiDE 120"; + model.model_id = ModelId::CANON_LIDE_120; + model.asic_type = AsicType::GL124; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 2400, 1200, 600, 300, 150, 100, 75 }, + { 4800, 2400, 1200, 600, 300, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 8.0; + model.x_size = 216.0; + model.y_size = 300.0; + + model.y_offset_calib_white = 1.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + model.line_mode_color_order = ColorOrder::RGB; + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_120; + model.adc_id = AdcId::CANON_LIDE_120; + model.gpio_id = GpioId::CANON_LIDE_120; + model.motor_id = MotorId::CANON_LIDE_120; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_FILE_SW; + model.shading_lines = 50; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x190e, model); + + + model = Genesys_Model(); + model.name = "canon-lide-210"; + model.vendor = "Canon"; + model.model = "LiDE 210"; + model.model_id = ModelId::CANON_LIDE_210; + model.asic_type = AsicType::GL124; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + // BUG: 4800 resolution crashes + { /*4800,*/ 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 }, + { /*4800,*/ 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 2.2; + model.y_offset = 8.7; + model.x_size = 216.70; + model.y_size = 297.5; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_210; + model.adc_id = AdcId::CANON_LIDE_110; + model.gpio_id = GpioId::CANON_LIDE_210; + model.motor_id = MotorId::CANON_LIDE_210; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_FILE_SW | + GENESYS_HAS_EXTRA_SW; + model.shading_lines = 60; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x190a, model); + + + model = Genesys_Model(); + model.name = "canon-lide-220"; + model.vendor = "Canon"; + model.model = "LiDE 220"; + model.model_id = ModelId::CANON_LIDE_220; + model.asic_type = AsicType::GL124; // or a compatible one + + model.resolutions = { + { + { ScanMethod::FLATBED }, + // BUG: 4800 resolution crashes + { /*4800,*/ 2400, 1200, 600, 300, 150, 100, 75 }, + { /*4800,*/ 2400, 1200, 600, 300, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 2.2; + model.y_offset = 8.7; + model.x_size = 216.70; + model.y_size = 297.5; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_220; + model.adc_id = AdcId::CANON_LIDE_110; + model.gpio_id = GpioId::CANON_LIDE_210; + model.motor_id = MotorId::CANON_LIDE_210; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_FILE_SW | + GENESYS_HAS_EXTRA_SW; + model.shading_lines = 60; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x190f, model); + + + model = Genesys_Model(); + model.name = "canon-5600f"; + model.vendor = "Canon"; + model.model = "5600F"; + model.model_id = ModelId::CANON_5600F; + model.asic_type = AsicType::GL847; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 75 }, + { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 1.1; + model.y_offset = 8.3; + model.x_size = 216.07; + model.y_size = 299.0; + + model.y_offset_calib_white = 3.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_200; + model.adc_id = AdcId::CANON_LIDE_200; + model.gpio_id = GpioId::CANON_LIDE_200; + model.motor_id = MotorId::CANON_LIDE_200; + model.flags = GENESYS_FLAG_UNTESTED | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_SIS_SENSOR | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_FILE_SW; + model.shading_lines = 50; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x1906, model); + + + model = Genesys_Model(); + model.name = "canon-lide-700f"; + model.vendor = "Canon"; + model.model = "LiDE 700F"; + model.model_id = ModelId::CANON_LIDE_700F; + model.asic_type = AsicType::GL847; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 }, + { 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 3.1; + model.y_offset = 8.1; + model.x_size = 216.07; + model.y_size = 297.0; + + model.y_offset_calib_white = 1.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_700F; + model.adc_id = AdcId::CANON_LIDE_700F; + model.gpio_id = GpioId::CANON_LIDE_700F; + model.motor_id = MotorId::CANON_LIDE_700; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_SIS_SENSOR | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_FILE_SW; + model.shading_lines = 70; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x1907, model); + + + model = Genesys_Model(); + model.name = "canon-lide-200"; + model.vendor = "Canon"; + model.model = "LiDE 200"; + model.model_id = ModelId::CANON_LIDE_200; + model.asic_type = AsicType::GL847; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 }, + { 4800, 2400, 1200, 600, 300, 200, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 1.1; + model.y_offset = 8.3; + model.x_size = 216.07; + model.y_size = 299.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_200; + model.adc_id = AdcId::CANON_LIDE_200; + model.gpio_id = GpioId::CANON_LIDE_200; + model.motor_id = MotorId::CANON_LIDE_200; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_SIS_SENSOR | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_FILE_SW; + model.shading_lines = 50; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x1905, model); + + + model = Genesys_Model(); + model.name = "canon-lide-60"; + model.vendor = "Canon"; + model.model = "LiDE 60"; + model.model_id = ModelId::CANON_LIDE_60; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 150, 75 }, + { 2400, 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.42; + model.y_offset = 7.9; + model.x_size = 218.0; + model.y_size = 299.0; + + model.y_offset_calib_white = 6.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_35; + model.adc_id = AdcId::CANON_LIDE_35; + model.gpio_id = GpioId::CANON_LIDE_35; + model.motor_id = MotorId::CANON_LIDE_35; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_WHITE_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + + model.buttons = GENESYS_HAS_COPY_SW | + GENESYS_HAS_SCAN_SW | + GENESYS_HAS_FILE_SW | + GENESYS_HAS_EMAIL_SW; + model.shading_lines = 300; + model.shading_ta_lines = 0; + model.search_lines = 400; + // this is completely untested + s_usb_devices->emplace_back(0x04a9, 0x221c, model); + + + model = Genesys_Model(); + model.name = "canon-lide-80"; + model.vendor = "Canon"; + model.model = "LiDE 80"; + model.model_id = ModelId::CANON_LIDE_80; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 150, 100, 75 }, + { 2400, 1200, 600, 300, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + model.x_offset = 0.42; + model.y_offset = 7.90; + model.x_size = 216.07; + model.y_size = 299.0; + + model.y_offset_calib_white = 4.5; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = false; + model.sensor_id = SensorId::CIS_CANON_LIDE_80; + model.adc_id = AdcId::CANON_LIDE_80; + model.gpio_id = GpioId::CANON_LIDE_80; + model.motor_id = MotorId::CANON_LIDE_80; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_WHITE_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | + GENESYS_HAS_FILE_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_COPY_SW; + model.shading_lines = 160; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a9, 0x2214, model); + + + model = Genesys_Model(); + model.name = "hewlett-packard-scanjet-2300c"; + model.vendor = "Hewlett Packard"; + model.model = "ScanJet 2300c"; + model.model_id = ModelId::HP_SCANJET_2300C; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 2.0; + model.y_offset = 7.5; + model.x_size = 215.9; + model.y_size = 295.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 1.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 16; + model.ld_shift_g = 8; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_HP2300; + model.adc_id = AdcId::WOLFSON_HP2300; + model.gpio_id = GpioId::HP2300; + model.motor_id = MotorId::HP2300; + model.flags = GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_SEARCH_START | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW; + model.shading_lines = 40; + model.shading_ta_lines = 0; + model.search_lines = 132; + + s_usb_devices->emplace_back(0x03f0, 0x0901, model); + + + model = Genesys_Model(); + model.name = "hewlett-packard-scanjet-2400c"; + model.vendor = "Hewlett Packard"; + model.model = "ScanJet 2400c"; + model.model_id = ModelId::HP_SCANJET_2400C; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 150, 100, 50 }, + { 1200, 600, 300, 150, 100, 50 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 6.5; + model.y_offset = 2.5; + model.x_size = 220.0; + model.y_size = 297.2; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 1.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_HP2400; + model.adc_id = AdcId::WOLFSON_HP2400; + model.gpio_id = GpioId::HP2400; + model.motor_id = MotorId::HP2400; + model.flags = GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW; + model.shading_lines = 20; + model.shading_ta_lines = 0; + model.search_lines = 132; + + s_usb_devices->emplace_back(0x03f0, 0x0a01, model); + + + model = Genesys_Model(); + model.name = "visioneer-strobe-xp200"; + model.vendor = "Visioneer"; + model.model = "Strobe XP200"; + model.model_id = ModelId::VISIONEER_STROBE_XP200; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 200, 100, 75 }, + { 600, 300, 200, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.5; + model.y_offset = 16.0; + model.x_size = 215.9; + model.y_size = 297.2; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CIS_XP200; + model.adc_id = AdcId::AD_XP200; + model.gpio_id = GpioId::XP200; + model.motor_id = MotorId::XP200; + model.flags = GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 120; + model.shading_ta_lines = 0; + model.search_lines = 132; + + s_usb_devices->emplace_back(0x04a7, 0x0426, model); + + + model = Genesys_Model(); + model.name = "hewlett-packard-scanjet-3670"; + model.vendor = "Hewlett Packard"; + model.model = "ScanJet 3670"; + model.model_id = ModelId::HP_SCANJET_3670; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 150, 100, 75, 50 }, + { 1200, 600, 300, 150, 100, 75, 50 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 8.5; + model.y_offset = 11.0; + model.x_size = 215.9; + model.y_size = 300.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 1.0; + + model.x_offset_ta = 104.0; + model.y_offset_ta = 55.6; + model.x_size_ta = 25.6; + model.y_size_ta = 78.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 76.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_HP3670; + model.adc_id = AdcId::WOLFSON_HP3670; + model.gpio_id = GpioId::HP3670; + model.motor_id = MotorId::HP3670; + model.flags = GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_XPA | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW; + model.shading_lines = 20; + model.shading_ta_lines = 0; + model.search_lines = 200; + + s_usb_devices->emplace_back(0x03f0, 0x1405, model); + + + model = Genesys_Model(); + model.name = "plustek-opticpro-st12"; + model.vendor = "Plustek"; + model.model = "OpticPro ST12"; + model.model_id = ModelId::PLUSTEK_OPTICPRO_ST12; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 3.5; + model.y_offset = 7.5; + model.x_size = 218.0; + model.y_size = 299.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 1.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 8; + model.ld_shift_b = 16; + + model.line_mode_color_order = ColorOrder::BGR; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_ST12; + model.adc_id = AdcId::WOLFSON_ST12; + model.gpio_id = GpioId::ST12; + model.motor_id = MotorId::UMAX; + model.flags = GENESYS_FLAG_UNTESTED | GENESYS_FLAG_14BIT_GAMMA; + model.buttons = GENESYS_HAS_NO_BUTTONS; + model.shading_lines = 20; + model.shading_ta_lines = 0; + model.search_lines = 200; + + s_usb_devices->emplace_back(0x07b3, 0x0600, model); + + model = Genesys_Model(); + model.name = "plustek-opticpro-st24"; + model.vendor = "Plustek"; + model.model = "OpticPro ST24"; + model.model_id = ModelId::PLUSTEK_OPTICPRO_ST24; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 150, 75 }, + { 2400, 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 3.5; + model.y_offset = 7.5; + model.x_size = 218.0; + model.y_size = 299.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 1.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 8; + model.ld_shift_b = 16; + + model.line_mode_color_order = ColorOrder::BGR; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_ST24; + model.adc_id = AdcId::WOLFSON_ST24; + model.gpio_id = GpioId::ST24; + model.motor_id = MotorId::ST24; + model.flags = GENESYS_FLAG_UNTESTED | + GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SEARCH_START | + GENESYS_FLAG_OFFSET_CALIBRATION; + model.buttons = GENESYS_HAS_NO_BUTTONS; + model.shading_lines = 20; + model.shading_ta_lines = 0; + model.search_lines = 200; + + s_usb_devices->emplace_back(0x07b3, 0x0601, model); + + model = Genesys_Model(); + model.name = "medion-md5345-model"; + model.vendor = "Medion"; + model.model = "MD5345/MD6228/MD6471"; + model.model_id = ModelId::MEDION_MD5345; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 400, 300, 200, 150, 100, 75, 50 }, + { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.30; + model.y_offset = 0.80; + model.x_size = 220.0; + model.y_size = 296.4; + + model.y_offset_calib_white = 0.00; + model.x_offset_calib_black = 0.00; + + model.x_offset_ta = 0.00; + model.y_offset_ta = 0.00; + model.x_size_ta = 0.00; + model.y_size_ta = 0.00; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.00; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 48; + model.ld_shift_g = 24; + model.ld_shift_b = 0; + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_5345; + model.adc_id = AdcId::WOLFSON_5345; + model.gpio_id = GpioId::MD_5345; + model.motor_id = MotorId::MD_5345; + model.flags = GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_SEARCH_START | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_SHADING_NO_MOVE | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_POWER_SW | + GENESYS_HAS_OCR_SW | + GENESYS_HAS_SCAN_SW; + model.shading_lines = 40; + model.shading_ta_lines = 0; + model.search_lines = 200; + + s_usb_devices->emplace_back(0x0461, 0x0377, model); + + model = Genesys_Model(); + model.name = "visioneer-strobe-xp300"; + model.vendor = "Visioneer"; + model.model = "Strobe XP300"; + model.model_id = ModelId::VISIONEER_STROBE_XP300; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 1.0; + model.x_size = 435.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 26.5; + // this is larger than needed -- accounts for second sensor head, which is a calibration item + model.eject_feed = 0.0; + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_XP300; + model.adc_id = AdcId::WOLFSON_XP300; + model.gpio_id = GpioId::XP300; + model.motor_id = MotorId::XP300; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a7, 0x0474, model); + + model = Genesys_Model(); + model.name = "syscan-docketport-665"; + model.vendor = "Syscan/Ambir"; + model.model = "DocketPORT 665"; + model.model_id = ModelId::SYSCAN_DOCKETPORT_665; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 108.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 17.5; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_DP665; + model.adc_id = AdcId::WOLFSON_XP300; + model.gpio_id = GpioId::DP665; + model.motor_id = MotorId::DP665; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x0a82, 0x4803, model); + + model = Genesys_Model(); + model.name = "visioneer-roadwarrior"; + model.vendor = "Visioneer"; + model.model = "Readwarrior"; + model.model_id = ModelId::VISIONEER_ROADWARRIOR; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 220.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 16.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_ROADWARRIOR; + model.adc_id = AdcId::WOLFSON_XP300; + model.gpio_id = GpioId::DP665; + model.motor_id = MotorId::ROADWARRIOR; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a7, 0x0494, model); + + model = Genesys_Model(); + model.name = "syscan-docketport-465"; + model.vendor = "Syscan"; + model.model = "DocketPORT 465"; + model.model_id = ModelId::SYSCAN_DOCKETPORT_465; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 220.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 16.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_ROADWARRIOR; + model.adc_id = AdcId::WOLFSON_XP300; + model.gpio_id = GpioId::DP665; + model.motor_id = MotorId::ROADWARRIOR; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_NO_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_UNTESTED; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW; + model.shading_lines = 300; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x0a82, 0x4802, model); + + + model = Genesys_Model(); + model.name = "visioneer-xp100-revision3"; + model.vendor = "Visioneer"; + model.model = "XP100 Revision 3"; + model.model_id = ModelId::VISIONEER_STROBE_XP100_REVISION3; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 220.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 16.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_ROADWARRIOR; + model.adc_id = AdcId::WOLFSON_XP300; + model.gpio_id = GpioId::DP665; + model.motor_id = MotorId::ROADWARRIOR; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a7, 0x049b, model); + + model = Genesys_Model(); + model.name = "pentax-dsmobile-600"; + model.vendor = "Pentax"; + model.model = "DSmobile 600"; + model.model_id = ModelId::PENTAX_DSMOBILE_600; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 220.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 16.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_DSMOBILE600; + model.adc_id = AdcId::WOLFSON_DSM600; + model.gpio_id = GpioId::DP665; + model.motor_id = MotorId::DSMOBILE_600; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x0a17, 0x3210, model); + // clone, only usb id is different + s_usb_devices->emplace_back(0x04f9, 0x2038, model); + + model = Genesys_Model(); + model.name = "syscan-docketport-467"; + model.vendor = "Syscan"; + model.model = "DocketPORT 467"; + model.model_id = ModelId::SYSCAN_DOCKETPORT_467; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 220.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 16.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_DSMOBILE600; + model.adc_id = AdcId::WOLFSON_DSM600; + model.gpio_id = GpioId::DP665; + model.motor_id = MotorId::DSMOBILE_600; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x1dcc, 0x4812, model); + + model = Genesys_Model(); + model.name = "syscan-docketport-685"; + model.vendor = "Syscan/Ambir"; + model.model = "DocketPORT 685"; + model.model_id = ModelId::SYSCAN_DOCKETPORT_685; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 1.0; + model.x_size = 212.0; + model.y_size = 500; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 26.5; + // this is larger than needed -- accounts for second sensor head, which is a calibration item + model.eject_feed = 0.0; + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_DP685; + model.adc_id = AdcId::WOLFSON_DSM600; + model.gpio_id = GpioId::DP685; + model.motor_id = MotorId::XP300; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + + s_usb_devices->emplace_back(0x0a82, 0x480c, model); + + + model = Genesys_Model(); + model.name = "syscan-docketport-485"; + model.vendor = "Syscan/Ambir"; + model.model = "DocketPORT 485"; + model.model_id = ModelId::SYSCAN_DOCKETPORT_485; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 1.0; + model.x_size = 435.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 26.5; + // this is larger than needed -- accounts for second sensor head, which is a calibration item + model.eject_feed = 0.0; + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_XP300; + model.adc_id = AdcId::WOLFSON_XP300; + model.gpio_id = GpioId::XP300; + model.motor_id = MotorId::XP300; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x0a82, 0x4800, model); + + + model = Genesys_Model(); + model.name = "dct-docketport-487"; + model.vendor = "DCT"; + model.model = "DocketPORT 487"; + model.model_id = ModelId::DCT_DOCKETPORT_487; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.0; + model.y_offset = 1.0; + model.x_size = 435.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 26.5; + // this is larger than needed -- accounts for second sensor head, which is a calibration item + model.eject_feed = 0.0; + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_XP300; + model.adc_id = AdcId::WOLFSON_XP300; + model.gpio_id = GpioId::XP300; + model.motor_id = MotorId::XP300; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_UNTESTED; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x1dcc, 0x4810, model); + + + model = Genesys_Model(); + model.name = "visioneer-7100-model"; + model.vendor = "Visioneer"; + model.model = "OneTouch 7100"; + model.model_id = ModelId::VISIONEER_7100; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 400, 300, 200, 150, 100, 75, 50 }, + { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 4.00; + model.y_offset = 0.80; + model.x_size = 215.9; + model.y_size = 296.4; + + model.y_offset_calib_white = 0.00; + model.x_offset_calib_black = 0.00; + + model.x_offset_ta = 0.00; + model.y_offset_ta = 0.00; + model.x_size_ta = 0.00; + model.y_size_ta = 0.00; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.00; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 48; + model.ld_shift_g = 24; + model.ld_shift_b = 0; + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_5345; + model.adc_id = AdcId::WOLFSON_5345; + model.gpio_id = GpioId::MD_5345; + model.motor_id = MotorId::MD_5345; + model.flags = GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_SEARCH_START | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_POWER_SW | + GENESYS_HAS_OCR_SW | + GENESYS_HAS_SCAN_SW; + model.shading_lines = 40; + model.shading_ta_lines = 0; + model.search_lines = 200; + + s_usb_devices->emplace_back(0x04a7, 0x0229, model); + + + model = Genesys_Model(); + model.name = "xerox-2400-model"; + model.vendor = "Xerox"; + model.model = "OneTouch 2400"; + model.model_id = ModelId::XEROX_2400; + model.asic_type = AsicType::GL646; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 400, 300, 200, 150, 100, 75, 50 }, + { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 4.00; + model.y_offset = 0.80; + model.x_size = 215.9; + model.y_size = 296.4; + + model.y_offset_calib_white = 0.00; + model.x_offset_calib_black = 0.00; + + model.x_offset_ta = 0.00; + model.y_offset_ta = 0.00; + model.x_size_ta = 0.00; + model.y_size_ta = 0.00; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.00; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 48; + model.ld_shift_g = 24; + model.ld_shift_b = 0; + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_5345; + model.adc_id = AdcId::WOLFSON_5345; + model.gpio_id = GpioId::MD_5345; + model.motor_id = MotorId::MD_5345; + model.flags = GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_SEARCH_START | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_COPY_SW | + GENESYS_HAS_EMAIL_SW | + GENESYS_HAS_POWER_SW | + GENESYS_HAS_OCR_SW | + GENESYS_HAS_SCAN_SW; + model.shading_lines = 40; + model.shading_ta_lines = 0; + model.search_lines = 200; + + s_usb_devices->emplace_back(0x0461, 0x038b, model); + + + model = Genesys_Model(); + model.name = "xerox-travelscanner"; + model.vendor = "Xerox"; + model.model = "Travelscanner 100"; + model.model_id = ModelId::XEROX_TRAVELSCANNER_100; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 600, 300, 150, 75 }, + { 1200, 600, 300, 150, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 4.0; + model.y_offset = 0.0; + model.x_size = 220.0; + model.y_size = 511; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 16.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = true; + model.is_sheetfed = true; + model.sensor_id = SensorId::CCD_ROADWARRIOR; + model.adc_id = AdcId::WOLFSON_XP300; + model.gpio_id = GpioId::DP665; + model.motor_id = MotorId::ROADWARRIOR; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION; + model.buttons = GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 400; + + s_usb_devices->emplace_back(0x04a7, 0x04ac, model); + + + model = Genesys_Model(); + model.name = "plustek-opticbook-3600"; + model.vendor = "PLUSTEK"; + model.model = "OpticBook 3600"; + model.model_id = ModelId::PLUSTEK_OPTICPRO_3600; + model.asic_type = AsicType::GL841; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { /*1200,*/ 600, 400, 300, 200, 150, 100, 75 }, + { /*2400,*/ 1200, 600, 400, 300, 200, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 0.42; + model.y_offset = 6.75; + model.x_size = 216.0; + model.y_size = 297.0; + + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 0.0; + model.y_size_ta = 0.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_PLUSTEK_OPTICPRO_3600; + model.adc_id = AdcId::PLUSTEK_OPTICPRO_3600; + model.gpio_id = GpioId::PLUSTEK_OPTICPRO_3600; + model.motor_id = MotorId::PLUSTEK_OPTICPRO_3600; + model.flags = GENESYS_FLAG_UNTESTED | // not fully working yet + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION; + model.buttons = GENESYS_HAS_NO_BUTTONS; + model.shading_lines = 7; + model.shading_ta_lines = 0; + model.search_lines = 200; + + s_usb_devices->emplace_back(0x07b3, 0x0900, model); + + + model = Genesys_Model(); + model.name = "plustek-opticfilm-7200i"; + model.vendor = "PLUSTEK"; + model.model = "OpticFilm 7200i"; + model.model_id = ModelId::PLUSTEK_OPTICFILM_7200I; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::TRANSPARENCY, ScanMethod::TRANSPARENCY_INFRARED }, + { 7200, 3600, 1800, 900 }, + { 7200, 3600, 1800, 900 }, + } + }; + + model.bpp_gray_values = { 16 }; + model.bpp_color_values = { 16 }; + model.default_method = ScanMethod::TRANSPARENCY; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 36.0; + model.y_size = 44.0; + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 6.5; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 29.0; + model.x_size_ta = 36.0; + model.y_size_ta = 24.0; + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_black_ta = 6.5; + model.y_offset_calib_white_ta = 0.0; + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 12; + model.ld_shift_b = 24; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + + model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200I; + model.adc_id = AdcId::PLUSTEK_OPTICFILM_7200I; + model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7200I; + model.motor_id = MotorId::PLUSTEK_OPTICFILM_7200I; + + model.flags = GENESYS_FLAG_HAS_UTA | + GENESYS_FLAG_HAS_UTA_INFRARED | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_HAS_NO_BUTTONS | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CALIBRATION_HOST_SIDE | + GENESYS_FLAG_16BIT_DATA_INVERTED; + + model.shading_lines = 7; + model.shading_ta_lines = 50; + model.search_lines = 200; + s_usb_devices->emplace_back(0x07b3, 0x0c04, model); + + + model = Genesys_Model(); + model.name = "plustek-opticfilm-7300"; + model.vendor = "PLUSTEK"; + model.model = "OpticFilm 7300"; + model.model_id = ModelId::PLUSTEK_OPTICFILM_7300; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::TRANSPARENCY }, + { 7200, 3600, 1800, 900 }, + { 7200, 3600, 1800, 900 }, + } + }; + + model.bpp_gray_values = { 16 }; + model.bpp_color_values = { 16 }; + model.default_method = ScanMethod::TRANSPARENCY; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 36.0; + model.y_size = 44.0; + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 6.5; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 29.0; + model.x_size_ta = 36.0; + model.y_size_ta = 24.0; + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_black_ta = 6.5; + model.y_offset_calib_white_ta = 0.0; + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 12; + model.ld_shift_b = 24; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + + model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7300; + model.adc_id = AdcId::PLUSTEK_OPTICFILM_7300; + model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7300; + model.motor_id = MotorId::PLUSTEK_OPTICFILM_7300; + + model.flags = GENESYS_FLAG_HAS_UTA | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_HAS_NO_BUTTONS | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CALIBRATION_HOST_SIDE; + + model.shading_lines = 7; + model.shading_ta_lines = 50; + model.search_lines = 200; + s_usb_devices->emplace_back(0x07b3, 0x0c12, model); + + + model = Genesys_Model(); + model.name = "plustek-opticfilm-7500i"; + model.vendor = "PLUSTEK"; + model.model = "OpticFilm 7500i"; + model.model_id = ModelId::PLUSTEK_OPTICFILM_7500I; + model.asic_type = AsicType::GL843; + + model.resolutions = { + { + { ScanMethod::TRANSPARENCY, ScanMethod::TRANSPARENCY_INFRARED }, + { 7200, 3600, 1800, 900 }, + { 7200, 3600, 1800, 900 }, + } + }; + + model.bpp_gray_values = { 16 }; + model.bpp_color_values = { 16 }; + model.default_method = ScanMethod::TRANSPARENCY; + + model.x_offset = 0.0; + model.y_offset = 0.0; + model.x_size = 36.0; + model.y_size = 44.0; + model.y_offset_calib_white = 0.0; + model.x_offset_calib_black = 6.5; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 29.0; + model.x_size_ta = 36.0; + model.y_size_ta = 24.0; + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_black_ta = 6.5; + model.y_offset_calib_white_ta = 0.0; + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 12; + model.ld_shift_b = 24; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + + model.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7500I; + model.adc_id = AdcId::PLUSTEK_OPTICFILM_7500I; + model.gpio_id = GpioId::PLUSTEK_OPTICFILM_7500I; + model.motor_id = MotorId::PLUSTEK_OPTICFILM_7500I; + + model.flags = GENESYS_FLAG_HAS_UTA | + GENESYS_FLAG_HAS_UTA_INFRARED | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_HAS_NO_BUTTONS | + GENESYS_FLAG_SHADING_REPARK | + GENESYS_FLAG_CALIBRATION_HOST_SIDE; + + model.shading_lines = 7; + model.shading_ta_lines = 50; + model.search_lines = 200; + s_usb_devices->emplace_back(0x07b3, 0x0c13, model); + + + model = Genesys_Model(); + model.name = "hewlett-packard-scanjet-N6310"; + model.vendor = "Hewlett Packard"; + model.model = "ScanJet N6310"; + model.model_id = ModelId::HP_SCANJET_N6310; + model.asic_type = AsicType::GL847; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 2400, 1200, 600, 400, 300, 200, 150, 100, 75 }, + { 2400, 1200, 600, 400, 300, 200, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 6; + model.y_offset = 2; + model.x_size = 216; + model.y_size = 511; + + model.y_offset_calib_white = 3.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 100.0; + model.y_size_ta = 100.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0; + + model.post_scan = 0; + model.eject_feed = 0; + + model.ld_shift_r = 0; + model.ld_shift_g = 0; + model.ld_shift_b = 0; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_HP_N6310; + model.adc_id = AdcId::CANON_LIDE_200; // Not defined yet for N6310 + model.gpio_id = GpioId::HP_N6310; + model.motor_id = MotorId::CANON_LIDE_200; // Not defined yet for N6310 + model.flags = GENESYS_FLAG_UNTESTED | + GENESYS_FLAG_14BIT_GAMMA | + GENESYS_FLAG_DARK_CALIBRATION | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_NO_CALIBRATION; + + model.buttons = GENESYS_HAS_NO_BUTTONS; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x03f0, 0x4705, model); + + + model = Genesys_Model(); + model.name = "plustek-opticbook-3800"; + model.vendor = "PLUSTEK"; + model.model = "OpticBook 3800"; + model.model_id = ModelId::PLUSTEK_OPTICBOOK_3800; + model.asic_type = AsicType::GL845; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 150, 100, 75 }, + { 1200, 600, 300, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 7.2; + model.y_offset = 14.7; + model.x_size = 217.7; + model.y_size = 300.0; + + model.y_offset_calib_white = 9.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 0.0; + model.y_size_ta = 0.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_PLUSTEK_OPTICBOOK_3800; + model.adc_id = AdcId::PLUSTEK_OPTICBOOK_3800; + model.gpio_id = GpioId::PLUSTEK_OPTICBOOK_3800; + model.motor_id = MotorId::PLUSTEK_OPTICBOOK_3800; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA; + model.buttons = GENESYS_HAS_NO_BUTTONS; // TODO there are 4 buttons to support + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x07b3, 0x1300, model); + + + model = Genesys_Model(); + model.name = "canon-image-formula-101"; + model.vendor = "Canon"; + model.model = "Image Formula 101"; + model.model_id = ModelId::CANON_IMAGE_FORMULA_101; + model.asic_type = AsicType::GL846; + + model.resolutions = { + { + { ScanMethod::FLATBED }, + { 1200, 600, 300, 150, 100, 75 }, + { 1200, 600, 300, 150, 100, 75 }, + } + }; + + model.bpp_gray_values = { 8, 16 }; + model.bpp_color_values = { 8, 16 }; + + model.x_offset = 7.2; + model.y_offset = 14.7; + model.x_size = 217.7; + model.y_size = 300.0; + + model.y_offset_calib_white = 9.0; + model.x_offset_calib_black = 0.0; + + model.x_offset_ta = 0.0; + model.y_offset_ta = 0.0; + model.x_size_ta = 0.0; + model.y_size_ta = 0.0; + + model.y_offset_sensor_to_ta = 0.0; + model.y_offset_calib_white_ta = 0.0; + + model.post_scan = 0.0; + model.eject_feed = 0.0; + + model.ld_shift_r = 0; + model.ld_shift_g = 24; + model.ld_shift_b = 48; + + model.line_mode_color_order = ColorOrder::RGB; + + model.is_cis = false; + model.is_sheetfed = false; + model.sensor_id = SensorId::CCD_IMG101; + model.adc_id = AdcId::IMG101; + model.gpio_id = GpioId::IMG101; + model.motor_id = MotorId::IMG101; + model.flags = GENESYS_FLAG_SKIP_WARMUP | + GENESYS_FLAG_OFFSET_CALIBRATION | + GENESYS_FLAG_CUSTOM_GAMMA | + GENESYS_FLAG_UNTESTED; + model.buttons = GENESYS_HAS_NO_BUTTONS ; + model.shading_lines = 100; + model.shading_ta_lines = 0; + model.search_lines = 100; + + s_usb_devices->emplace_back(0x1083, 0x162e, model); + } + +} // namespace genesys diff --git a/backend/genesys/tables_motor.cpp b/backend/genesys/tables_motor.cpp new file mode 100644 index 0000000..2484d2d --- /dev/null +++ b/backend/genesys/tables_motor.cpp @@ -0,0 +1,325 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "low.h" + +namespace genesys { + +StaticInit> s_motors; + +void genesys_init_motor_tables() +{ + s_motors.init(); + + Genesys_Motor motor; + motor.id = MotorId::UMAX; + motor.base_ydpi = 1200; + motor.optical_ydpi = 2400; + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128)); + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::MD_5345; // MD5345/6228/6471 + motor.base_ydpi = 1200; + motor.optical_ydpi = 2400; + motor.slopes.push_back(MotorSlope::create_from_steps(2000, 1375, 128)); + motor.slopes.push_back(MotorSlope::create_from_steps(2000, 1375, 128)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::ST24; + motor.base_ydpi = 2400; + motor.optical_ydpi = 2400; + motor.slopes.push_back(MotorSlope::create_from_steps(2289, 2100, 128)); + motor.slopes.push_back(MotorSlope::create_from_steps(2289, 2100, 128)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::HP3670; + motor.base_ydpi = 1200; + motor.optical_ydpi = 1200; + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128)); + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::HP2400; + motor.base_ydpi = 1200; + motor.optical_ydpi = 1200; + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128)); + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 3000, 128)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::HP2300; + motor.base_ydpi = 600; + motor.optical_ydpi = 1200; + motor.slopes.push_back(MotorSlope::create_from_steps(3200, 1200, 128)); + motor.slopes.push_back(MotorSlope::create_from_steps(3200, 1200, 128)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_LIDE_35; + motor.base_ydpi = 1200; + motor.optical_ydpi = 2400; + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60)); + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1400, 60)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::XP200; + motor.base_ydpi = 600; + motor.optical_ydpi = 600; + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60)); + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::XP300; + motor.base_ydpi = 300; + motor.optical_ydpi = 600; + // works best with GPIO10, GPIO14 off + motor.slopes.push_back(MotorSlope::create_from_steps(3700, 3700, 2)); + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::DP665; + motor.base_ydpi = 750; + motor.optical_ydpi = 1500; + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 2500, 10)); + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::ROADWARRIOR; + motor.base_ydpi = 750; + motor.optical_ydpi = 1500; + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 2600, 10)); + motor.slopes.push_back(MotorSlope::create_from_steps(11000, 11000, 2)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::DSMOBILE_600; + motor.base_ydpi = 750; + motor.optical_ydpi = 1500; + motor.slopes.push_back(MotorSlope::create_from_steps(6666, 3700, 8)); + motor.slopes.push_back(MotorSlope::create_from_steps(6666, 3700, 8)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_LIDE_100; + motor.base_ydpi = 1200; + motor.optical_ydpi = 6400; + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127)); + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127)); + motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_LIDE_200; + motor.base_ydpi = 1200; + motor.optical_ydpi = 6400; + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127)); + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127)); + motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_LIDE_700; + motor.base_ydpi = 1200; + motor.optical_ydpi = 6400; + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 127)); + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1500, 127)); + motor.slopes.push_back(MotorSlope::create_from_steps(3 * 2712, 3 * 2712, 16)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::KVSS080; + motor.base_ydpi = 1200; + motor.optical_ydpi = 1200; + motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(22222, 500, 246)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::G4050; + motor.base_ydpi = 2400; + motor.optical_ydpi = 9600; + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_4400F; + motor.base_ydpi = 2400; + motor.optical_ydpi = 9600; + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_8400F; + motor.base_ydpi = 1600; + motor.optical_ydpi = 6400; + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_8600F; + motor.base_ydpi = 2400; + motor.optical_ydpi = 9600; + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + motor.slopes.push_back(MotorSlope::create_from_steps(3961, 240, 246)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_LIDE_110; + motor.base_ydpi = 4800; + motor.optical_ydpi = 9600; + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_LIDE_120; + motor.base_ydpi = 4800; + motor.optical_ydpi = 9600; + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_LIDE_210; + motor.base_ydpi = 4800; + motor.optical_ydpi = 9600; + motor.slopes.push_back(MotorSlope::create_from_steps(3000, 1000, 256)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::PLUSTEK_OPTICPRO_3600; + motor.base_ydpi = 1200; + motor.optical_ydpi = 2400; + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60)); + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::PLUSTEK_OPTICFILM_7200I; + motor.base_ydpi = 3600; + motor.optical_ydpi = 3600; + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::PLUSTEK_OPTICFILM_7300; + motor.base_ydpi = 3600; + motor.optical_ydpi = 3600; + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::PLUSTEK_OPTICFILM_7500I; + motor.base_ydpi = 3600; + motor.optical_ydpi = 3600; + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::IMG101; + motor.base_ydpi = 600; + motor.optical_ydpi = 1200; + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60)); + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::PLUSTEK_OPTICBOOK_3800; + motor.base_ydpi = 600; + motor.optical_ydpi = 1200; + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 1300, 60)); + motor.slopes.push_back(MotorSlope::create_from_steps(3500, 3250, 60)); + s_motors->push_back(std::move(motor)); + + + motor = Genesys_Motor(); + motor.id = MotorId::CANON_LIDE_80; + motor.base_ydpi = 2400; + motor.optical_ydpi = 4800; // 9600 + motor.slopes.push_back(MotorSlope::create_from_steps(9560, 1912, 31)); + s_motors->push_back(std::move(motor)); +} + +} // namespace genesys diff --git a/backend/genesys/tables_motor_profile.cpp b/backend/genesys/tables_motor_profile.cpp new file mode 100644 index 0000000..18f7271 --- /dev/null +++ b/backend/genesys/tables_motor_profile.cpp @@ -0,0 +1,380 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "low.h" + +namespace genesys { + +StaticInit> gl843_motor_profiles; + +void genesys_init_motor_profile_tables_gl843() +{ + gl843_motor_profiles.init(); + + auto profile = Motor_Profile(); + profile.motor_id = MotorId::KVSS080; + profile.exposure = 8000; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(44444, 500, 489); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::G4050; + profile.exposure = 8016; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(7842, 320, 602); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::G4050; + profile.exposure = 15624; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(9422, 254, 1004); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::G4050; + profile.exposure = 42752; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(42752, 1706, 610); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::G4050; + profile.exposure = 56064; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(28032, 2238, 604); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_4400F; + profile.exposure = 11640; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(49152, 484, 1014); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_8400F; + profile.exposure = 50000; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(8743, 300, 794); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_8600F; + profile.exposure = 0x59d8; + profile.step_type = StepType::QUARTER; + // FIXME: if the exposure is lower then we'll select another motor + profile.slope = MotorSlope::create_from_steps(54612, 1500, 219); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7200I; + profile.exposure = 0; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(39682, 1191, 15); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7300; + profile.exposure = 0x2f44; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(31250, 1512, 6); + gl843_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::PLUSTEK_OPTICFILM_7500I; + profile.exposure = 0; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(31250, 1375, 7); + gl843_motor_profiles->push_back(profile); +} + +StaticInit> gl846_motor_profiles; + +void genesys_init_motor_profile_tables_gl846() +{ + gl846_motor_profiles.init(); + + auto profile = Motor_Profile(); + profile.motor_id = MotorId::IMG101; + profile.exposure = 11000; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(22000, 1000, 1017); + + gl846_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::PLUSTEK_OPTICBOOK_3800; + profile.exposure = 11000; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(22000, 1000, 1017); + gl846_motor_profiles->push_back(profile); +} + +/** + * database of motor profiles + */ + +StaticInit> gl847_motor_profiles; + +void genesys_init_motor_profile_tables_gl847() +{ + gl847_motor_profiles.init(); + + auto profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_100; + profile.exposure = 2848; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_100; + profile.exposure = 1424; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_100; + profile.exposure = 1432; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_100; + profile.exposure = 2712; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(46876, 534, 279); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_100; + profile.exposure = 5280; + profile.step_type = StepType::EIGHTH; + profile.slope = MotorSlope::create_from_steps(31680, 534, 247); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_200; + profile.exposure = 2848; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_200; + profile.exposure = 1424; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_200; + profile.exposure = 1432; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_200; + profile.exposure = 2712; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(46876, 534, 279); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_200; + profile.exposure = 5280; + profile.step_type = StepType::EIGHTH; + profile.slope = MotorSlope::create_from_steps(31680, 534, 247); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_200; + profile.exposure = 10416; + profile.step_type = StepType::EIGHTH; + profile.slope = MotorSlope::create_from_steps(31680, 534, 247); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_700; + profile.exposure = 2848; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_700; + profile.exposure = 1424; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_700; + profile.exposure = 1504; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 534, 255); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_700; + profile.exposure = 2696; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(46876, 2022, 127); + gl847_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_700; + profile.exposure = 10576; + profile.step_type = StepType::EIGHTH; + profile.slope = MotorSlope::create_from_steps(46876, 15864, 2); + gl847_motor_profiles->push_back(profile); +} + +StaticInit> gl124_motor_profiles; + +void genesys_init_motor_profile_tables_gl124() +{ + gl124_motor_profiles.init(); + + // NEXT LPERIOD=PREVIOUS*2-192 + Motor_Profile profile; + profile.motor_id = MotorId::CANON_LIDE_110; + profile.exposure = 2768; + profile.step_type = StepType::FULL; + profile.slope = MotorSlope::create_from_steps(62496, 335, 255); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_110; + profile.exposure = 5360; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(62496, 335, 469); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_110; + profile.exposure = 10528; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(62496, 2632, 3); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_110; + profile.exposure = 20864; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(62496, 10432, 3); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_120; + profile.exposure = 4608; + profile.step_type = StepType::FULL; + profile.slope = MotorSlope::create_from_steps(62496, 864, 127); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_120; + profile.exposure = 5360; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(62496, 2010, 63); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_120; + profile.exposure = 10528; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(62464, 2632, 3); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_120; + profile.exposure = 20864; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(62592, 10432, 5); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_210; + profile.exposure = 2768; + profile.step_type = StepType::FULL; + profile.slope = MotorSlope::create_from_steps(62496, 335, 255); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_210; + profile.exposure = 5360; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(62496, 335, 469); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_210; + profile.exposure = 10528; + profile.step_type = StepType::HALF; + profile.slope = MotorSlope::create_from_steps(62496, 2632, 3); + gl124_motor_profiles->push_back(profile); + + profile = Motor_Profile(); + profile.motor_id = MotorId::CANON_LIDE_210; + profile.exposure = 20864; + profile.step_type = StepType::QUARTER; + profile.slope = MotorSlope::create_from_steps(62496, 10432, 4); + gl124_motor_profiles->push_back(profile); +} + +void genesys_init_motor_profile_tables() +{ + genesys_init_motor_profile_tables_gl843(); + genesys_init_motor_profile_tables_gl846(); + genesys_init_motor_profile_tables_gl847(); + genesys_init_motor_profile_tables_gl124(); +} + +} // namespace genesys diff --git a/backend/genesys/tables_sensor.cpp b/backend/genesys/tables_sensor.cpp new file mode 100644 index 0000000..bbbe441 --- /dev/null +++ b/backend/genesys/tables_sensor.cpp @@ -0,0 +1,3668 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "low.h" + +namespace genesys { + +inline unsigned default_get_logical_hwdpi(const Genesys_Sensor& sensor, unsigned xres) +{ + if (sensor.logical_dpihw_override) + return sensor.logical_dpihw_override; + + // can't be below 600 dpi + if (xres <= 600) { + return 600; + } + if (xres <= static_cast(sensor.optical_res) / 4) { + return sensor.optical_res / 4; + } + if (xres <= static_cast(sensor.optical_res) / 2) { + return sensor.optical_res / 2; + } + return sensor.optical_res; +} + +inline unsigned get_sensor_optical_with_ccd_divisor(const Genesys_Sensor& sensor, unsigned xres) +{ + unsigned hwres = sensor.optical_res / sensor.get_ccd_size_divisor_for_dpi(xres); + + if (xres <= hwres / 4) { + return hwres / 4; + } + if (xres <= hwres / 2) { + return hwres / 2; + } + return hwres; +} + +inline unsigned default_get_ccd_size_divisor_for_dpi(const Genesys_Sensor& sensor, unsigned xres) +{ + if (sensor.ccd_size_divisor >= 4 && xres * 4 <= static_cast(sensor.optical_res)) { + return 4; + } + if (sensor.ccd_size_divisor >= 2 && xres * 2 <= static_cast(sensor.optical_res)) { + return 2; + } + return 1; +} + +inline unsigned get_ccd_size_divisor_exact(const Genesys_Sensor& sensor, unsigned xres) +{ + (void) xres; + return sensor.ccd_size_divisor; +} + +inline unsigned get_ccd_size_divisor_gl124(const Genesys_Sensor& sensor, unsigned xres) +{ + // we have 2 domains for ccd: xres below or above half ccd max dpi + if (xres <= 300 && sensor.ccd_size_divisor > 1) { + return 2; + } + return 1; +} + +inline unsigned default_get_hwdpi_divisor_for_dpi(const Genesys_Sensor& sensor, unsigned xres) +{ + return sensor.optical_res / default_get_logical_hwdpi(sensor, xres); +} + +StaticInit> s_sensors; + +void genesys_init_sensor_tables() +{ + s_sensors.init(); + + Genesys_Sensor sensor; + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_UMAX; + sensor.optical_res = 1200; + sensor.black_pixels = 48; + sensor.dummy_pixel = 64; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10800; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x01 }, + { 0x09, 0x03 }, + { 0x0a, 0x05 }, + { 0x0b, 0x07 }, + { 0x16, 0x33 }, + { 0x17, 0x05 }, + { 0x18, 0x31 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x13 }, + { 0x53, 0x17 }, + { 0x54, 0x03 }, + { 0x55, 0x07 }, + { 0x56, 0x0b }, + { 0x57, 0x0f }, + { 0x58, 0x23 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_ST12; + sensor.optical_res = 600; + sensor.black_pixels = 48; + sensor.dummy_pixel = 85; + sensor.ccd_start_xoffset = 152; + sensor.sensor_pixels = 5416; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x02 }, + { 0x09, 0x00 }, + { 0x0a, 0x06 }, + { 0x0b, 0x04 }, + { 0x16, 0x2b }, + { 0x17, 0x08 }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x0c }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_ST24; + sensor.optical_res = 1200; + sensor.black_pixels = 48; + sensor.dummy_pixel = 64; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10800; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x0e }, + { 0x09, 0x0c }, + { 0x0a, 0x00 }, + { 0x0b, 0x0c }, + { 0x16, 0x33 }, + { 0x17, 0x08 }, + { 0x18, 0x31 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x17 }, + { 0x53, 0x03 }, + { 0x54, 0x07 }, + { 0x55, 0x0b }, + { 0x56, 0x0f }, + { 0x57, 0x13 }, + { 0x58, 0x03 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_5345; + sensor.optical_res = 1200; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 48; + sensor.dummy_pixel = 16; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10872; + sensor.fau_gain_white_ref = 190; + sensor.gain_white_ref = 190; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.stagger_config = StaggerConfig{ 1200, 4 }; // FIXME: may be incorrect + sensor.custom_base_regs = { + { 0x08, 0x0d }, + { 0x09, 0x0f }, + { 0x0a, 0x11 }, + { 0x0b, 0x13 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x30 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x23 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = { 2.38f, 2.35f, 2.34f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + unsigned exposure_lperiod; + unsigned ccd_size_divisor; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 50 }, 12000, 2, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x28 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 75 }, 11000, 2, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x28 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 100 }, 11000, 2, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x28 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 150 }, 11000, 2, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x28 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 200 }, 11000, 2, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x28 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 300 }, 11000, 2, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x28 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 400 }, 11000, 2, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x28 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 600 }, 11000, 2, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x28 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 1200 }, 11000, 1, { + { 0x08, 0x0d }, + { 0x09, 0x0f }, + { 0x0a, 0x11 }, + { 0x0b, 0x13 }, + { 0x16, 0x0b }, + { 0x17, 0x0a }, + { 0x18, 0x30 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x03 }, + { 0x52, 0x03 }, + { 0x53, 0x07 }, + { 0x54, 0x0b }, + { 0x55, 0x0f }, + { 0x56, 0x13 }, + { 0x57, 0x17 }, + { 0x58, 0x23 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + }; + + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.ccd_size_divisor = setting.ccd_size_divisor; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_HP2400; + sensor.optical_res = 1200; + sensor.black_pixels = 48; + sensor.dummy_pixel = 15; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10872; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.stagger_config = StaggerConfig{1200, 4}; // FIXME: may be incorrect + sensor.custom_base_regs = { + { 0x08, 0x14 }, + { 0x09, 0x15 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0xbf }, + { 0x17, 0x08 }, + { 0x18, 0x3f }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x0b }, + { 0x53, 0x0f }, + { 0x54, 0x13 }, + { 0x55, 0x17 }, + { 0x56, 0x03 }, + { 0x57, 0x07 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x0e }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = { 2.1f, 2.1f, 2.1f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + unsigned exposure_lperiod; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 50 }, 7211, { + { 0x08, 0x14 }, + { 0x09, 0x15 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0xbf }, + { 0x17, 0x08 }, + { 0x18, 0x3f }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x0b }, + { 0x53, 0x0f }, + { 0x54, 0x13 }, + { 0x55, 0x17 }, + { 0x56, 0x03 }, + { 0x57, 0x07 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 100 }, 7211, { + { 0x08, 0x14 }, + { 0x09, 0x15 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0xbf }, + { 0x17, 0x08 }, + { 0x18, 0x3f }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x0b }, + { 0x53, 0x0f }, + { 0x54, 0x13 }, + { 0x55, 0x17 }, + { 0x56, 0x03 }, + { 0x57, 0x07 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 150 }, 7211, { + { 0x08, 0x14 }, + { 0x09, 0x15 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0xbf }, + { 0x17, 0x08 }, + { 0x18, 0x3f }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x0b }, + { 0x53, 0x0f }, + { 0x54, 0x13 }, + { 0x55, 0x17 }, + { 0x56, 0x03 }, + { 0x57, 0x07 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 300 }, 8751, { + { 0x08, 0x14 }, + { 0x09, 0x15 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0xbf }, + { 0x17, 0x08 }, + { 0x18, 0x3f }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x0b }, + { 0x53, 0x0f }, + { 0x54, 0x13 }, + { 0x55, 0x17 }, + { 0x56, 0x03 }, + { 0x57, 0x07 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 600 }, 18760, { + { 0x08, 0x0e }, + { 0x09, 0x0f }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0xbf }, + { 0x17, 0x08 }, + { 0x18, 0x31 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x03 }, + { 0x53, 0x07 }, + { 0x54, 0x0b }, + { 0x55, 0x0f }, + { 0x56, 0x13 }, + { 0x57, 0x17 }, + { 0x58, 0x23 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 1200 }, 21749, { + { 0x08, 0x02 }, + { 0x09, 0x04 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0xbf }, + { 0x17, 0x08 }, + { 0x18, 0x30 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x42 }, + { 0x52, 0x0b }, + { 0x53, 0x0f }, + { 0x54, 0x13 }, + { 0x55, 0x17 }, + { 0x56, 0x03 }, + { 0x57, 0x07 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x0e }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + }; + + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_HP2300; + sensor.optical_res = 600; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 48; + sensor.dummy_pixel = 20; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 5368; + sensor.fau_gain_white_ref = 180; + sensor.gain_white_ref = 180; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_base_regs = { + { 0x08, 0x16 }, + { 0x09, 0x00 }, + { 0x0a, 0x01 }, + { 0x0b, 0x03 }, + { 0x16, 0xb7 }, + { 0x17, 0x0a }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x6a }, + { 0x1b, 0x8a }, + { 0x1c, 0x00 }, + { 0x1d, 0x05 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x06 }, + { 0x5c, 0x0b }, + { 0x5d, 0x10 }, + { 0x5e, 0x16 }, + }; + sensor.gamma = { 2.1f, 2.1f, 2.1f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + unsigned exposure_lperiod; + unsigned ccd_size_divisor; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 75 }, 4480, 2, { + { 0x08, 0x16 }, + { 0x09, 0x00 }, + { 0x0a, 0x01 }, + { 0x0b, 0x03 }, + { 0x16, 0xb7 }, + { 0x17, 0x0a }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x6a }, + { 0x1b, 0x8a }, + { 0x1c, 0x00 }, + { 0x1d, 0x85 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x06 }, + { 0x5c, 0x0b }, + { 0x5d, 0x10 }, + { 0x5e, 0x16 } + } + }, + { { 150 }, 4350, 2, { + { 0x08, 0x16 }, + { 0x09, 0x00 }, + { 0x0a, 0x01 }, + { 0x0b, 0x03 }, + { 0x16, 0xb7 }, + { 0x17, 0x0a }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x6a }, + { 0x1b, 0x8a }, + { 0x1c, 0x00 }, + { 0x1d, 0x85 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x06 }, + { 0x5c, 0x0b }, + { 0x5d, 0x10 }, + { 0x5e, 0x16 } + } + }, + { { 300 }, 4350, 2, { + { 0x08, 0x16 }, + { 0x09, 0x00 }, + { 0x0a, 0x01 }, + { 0x0b, 0x03 }, + { 0x16, 0xb7 }, + { 0x17, 0x0a }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x6a }, + { 0x1b, 0x8a }, + { 0x1c, 0x00 }, + { 0x1d, 0x85 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x06 }, + { 0x5c, 0x0b }, + { 0x5d, 0x10 }, + { 0x5e, 0x16 } + } + }, + { { 600 }, 8700, 1, { + { 0x08, 0x01 }, + { 0x09, 0x03 }, + { 0x0a, 0x04 }, + { 0x0b, 0x06 }, + { 0x16, 0xb7 }, + { 0x17, 0x0a }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x6a }, + { 0x1b, 0x8a }, + { 0x1c, 0x00 }, + { 0x1d, 0x05 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x06 }, + { 0x5c, 0x0b }, + { 0x5d, 0x10 }, + { 0x5e, 0x16 } + } + }, + }; + + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.ccd_size_divisor = setting.ccd_size_divisor; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_35; + sensor.optical_res = 1200; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 87; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10400; + sensor.fau_gain_white_ref = 0; + sensor.gain_white_ref = 0; + sensor.exposure = { 0x0400, 0x0400, 0x0400 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x00 }, + { 0x19, 0x50 }, + { 0x1a, 0x00 }, // TODO: 1a-1d: these do no harm, but may be neccessery for CCD + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x02 }, + { 0x52, 0x05 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x07 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x3a }, + { 0x59, 0x03 }, + { 0x5a, 0x40 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_XP200; + sensor.optical_res = 600; + sensor.black_pixels = 5; + sensor.dummy_pixel = 38; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 5200; + sensor.fau_gain_white_ref = 200; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1450, 0x0c80, 0x0a28 }; + sensor.custom_base_regs = { + { 0x08, 0x16 }, + { 0x09, 0x00 }, + { 0x0a, 0x01 }, + { 0x0b, 0x03 }, + { 0x16, 0xb7 }, + { 0x17, 0x0a }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x6a }, + { 0x1b, 0x8a }, + { 0x1c, 0x00 }, + { 0x1d, 0x05 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x06 }, + { 0x5c, 0x0b }, + { 0x5d, 0x10 }, + { 0x5e, 0x16 }, + }; + sensor.custom_regs = { + { 0x08, 0x06 }, + { 0x09, 0x07 }, + { 0x0a, 0x0a }, + { 0x0b, 0x04 }, + { 0x16, 0x24 }, + { 0x17, 0x04 }, + { 0x18, 0x00 }, + { 0x19, 0x2a }, + { 0x1a, 0x0a }, + { 0x1b, 0x0a }, + { 0x1c, 0x00 }, + { 0x1d, 0x11 }, + { 0x52, 0x08 }, + { 0x53, 0x02 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x1a }, + { 0x59, 0x51 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + }; + sensor.gamma = { 2.1f, 2.1f, 2.1f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + std::vector channels; + unsigned exposure_lperiod; + SensorExposure exposure; + }; + + CustomSensorSettings custom_settings[] = { + { { 75 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e } }, + { { 100 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e } }, + { { 200 }, { 3 }, 5700, { 0x1644, 0x0c80, 0x092e } }, + { { 300 }, { 3 }, 9000, { 0x1644, 0x0c80, 0x092e } }, + { { 600 }, { 3 }, 16000, { 0x1644, 0x0c80, 0x092e } }, + { { 75 }, { 1 }, 16000, { 0x050a, 0x0fa0, 0x1010 } }, + { { 100 }, { 1 }, 7800, { 0x050a, 0x0fa0, 0x1010 } }, + { { 200 }, { 1 }, 11000, { 0x050a, 0x0fa0, 0x1010 } }, + { { 300 }, { 1 }, 13000, { 0x050a, 0x0fa0, 0x1010 } }, + { { 600 }, { 1 }, 24000, { 0x050a, 0x0fa0, 0x1010 } }, + }; + + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.resolutions = setting.resolutions; + sensor.channels = setting.channels; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.exposure = setting.exposure; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_HP3670; + sensor.optical_res = 1200; + sensor.black_pixels = 48; + sensor.dummy_pixel = 16; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10872; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0, 0, 0 }; + sensor.stagger_config = StaggerConfig{1200, 4}; // FIXME: may be incorrect + sensor.custom_base_regs = { + { 0x08, 0x00 }, + { 0x09, 0x0a }, + { 0x0a, 0x0b }, + { 0x0b, 0x0d }, + { 0x16, 0x33 }, + { 0x17, 0x07 }, + { 0x18, 0x20 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x00 }, + { 0x5a, 0x15 }, + { 0x5b, 0x05 }, + { 0x5c, 0x0a }, + { 0x5d, 0x0f }, + { 0x5e, 0x00 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + unsigned exposure_lperiod; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 50 }, 5758, { + { 0x08, 0x00 }, + { 0x09, 0x0a }, + { 0x0a, 0x0b }, + { 0x0b, 0x0d }, + { 0x16, 0x33 }, + { 0x17, 0x07 }, + { 0x18, 0x33 }, + { 0x19, 0x2a }, + { 0x1a, 0x02 }, + { 0x1b, 0x13 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x15 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x05 }, + { 0x5c, 0x0a }, + { 0x5d, 0x0f }, + { 0x5e, 0x00 } + } + }, + { { 75 }, 4879, { + { 0x08, 0x00 }, + { 0x09, 0x0a }, + { 0x0a, 0x0b }, + { 0x0b, 0x0d }, + { 0x16, 0x33 }, + { 0x17, 0x07 }, + { 0x18, 0x33 }, + { 0x19, 0x2a }, + { 0x1a, 0x02 }, + { 0x1b, 0x13 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x15 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x05 }, + { 0x5c, 0x0a }, + { 0x5d, 0x0f }, + { 0x5e, 0x00 } + } + }, + { { 100 }, 4487, { + { 0x08, 0x00 }, + { 0x09, 0x0a }, + { 0x0a, 0x0b }, + { 0x0b, 0x0d }, + { 0x16, 0x33 }, + { 0x17, 0x07 }, + { 0x18, 0x33 }, + { 0x19, 0x2a }, + { 0x1a, 0x02 }, + { 0x1b, 0x13 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x15 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x05 }, + { 0x5c, 0x0a }, + { 0x5d, 0x0f }, + { 0x5e, 0x00 } + } + }, + { { 150 }, 4879, { + { 0x08, 0x00 }, + { 0x09, 0x0a }, + { 0x0a, 0x0b }, + { 0x0b, 0x0d }, + { 0x16, 0x33 }, + { 0x17, 0x07 }, + { 0x18, 0x33 }, + { 0x19, 0x2a }, + { 0x1a, 0x02 }, + { 0x1b, 0x13 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x15 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x05 }, + { 0x5c, 0x0a }, + { 0x5d, 0x0f }, + { 0x5e, 0x00 } + } + }, + { { 300 }, 4503, { + { 0x08, 0x00 }, + { 0x09, 0x0a }, + { 0x0a, 0x0b }, + { 0x0b, 0x0d }, + { 0x16, 0x33 }, + { 0x17, 0x07 }, + { 0x18, 0x33 }, + { 0x19, 0x2a }, + { 0x1a, 0x02 }, + { 0x1b, 0x13 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x0f }, + { 0x53, 0x13 }, + { 0x54, 0x17 }, + { 0x55, 0x03 }, + { 0x56, 0x07 }, + { 0x57, 0x0b }, + { 0x58, 0x83 }, + { 0x59, 0x15 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x05 }, + { 0x5c, 0x0a }, + { 0x5d, 0x0f }, + { 0x5e, 0x00 } + } + }, + { { 600 }, 10251, { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x06 }, + { 0x0b, 0x08 }, + { 0x16, 0x33 }, + { 0x17, 0x07 }, + { 0x18, 0x31 }, + { 0x19, 0x2a }, + { 0x1a, 0x02 }, + { 0x1b, 0x0e }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x0b }, + { 0x53, 0x0f }, + { 0x54, 0x13 }, + { 0x55, 0x17 }, + { 0x56, 0x03 }, + { 0x57, 0x07 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x02 }, + { 0x5c, 0x0e }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + { { 1200 }, 12750, { + { 0x08, 0x0d }, + { 0x09, 0x0f }, + { 0x0a, 0x11 }, + { 0x0b, 0x13 }, + { 0x16, 0x2b }, + { 0x17, 0x07 }, + { 0x18, 0x30 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x43 }, + { 0x52, 0x03 }, + { 0x53, 0x07 }, + { 0x54, 0x0b }, + { 0x55, 0x0f }, + { 0x56, 0x13 }, + { 0x57, 0x17 }, + { 0x58, 0x23 }, + { 0x59, 0x00 }, + { 0x5a, 0xc1 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x00 } + } + }, + }; + + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_DP665; + sensor.optical_res = 600; + sensor.black_pixels = 27; + sensor.dummy_pixel = 27; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 2496; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1100, 0x1100, 0x1100 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_ROADWARRIOR; + sensor.optical_res = 600; + sensor.black_pixels = 27; + sensor.dummy_pixel = 27; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 5200; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1100, 0x1100, 0x1100 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_DSMOBILE600; + sensor.optical_res = 600; + sensor.black_pixels = 28; + sensor.dummy_pixel = 28; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 5200; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1544, 0x1544, 0x1544 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_XP300; + sensor.optical_res = 600; + sensor.black_pixels = 27; + sensor.dummy_pixel = 27; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10240; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1100, 0x1100, 0x1100 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_DP685; + sensor.optical_res = 600; + sensor.black_pixels = 27; + sensor.dummy_pixel = 27; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 5020; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x1100, 0x1100, 0x1100 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x00 }, + { 0x17, 0x02 }, + { 0x18, 0x04 }, + { 0x19, 0x50 }, + { 0x1a, 0x10 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x02 }, + { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x05 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x54 }, + { 0x59, 0x03 }, + { 0x5a, 0x00 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x01 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_200; + sensor.optical_res = 4800; + sensor.black_pixels = 87*4; + sensor.dummy_pixel = 16*4; + sensor.ccd_start_xoffset = 320*8; + sensor.sensor_pixels = 5136*8; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.gamma = { 2.2f, 2.2f, 2.2f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + SensorExposure exposure; + unsigned segment_size; + std::vector segment_order; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + // Note: Windows driver uses 1424 lperiod and enables dummy line (0x17) + { { 75, 100, 150, 200 }, 2848, { 304, 203, 180 }, 5136, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + // Note: Windows driver uses 788 lperiod and enables dummy line (0x17) + { { 300, 400 }, 1424, { 304, 203, 180 }, 5136, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 600 }, 1432, { 492, 326, 296 }, 5136, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 1200 }, 2712, { 935, 592, 538 }, 5136, { 0, 1 }, { + { 0x16, 0x10 }, { 0x17, 0x08 }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 2400 }, 5280, { 1777, 1125, 979 }, 5136, { 0, 2, 1, 3 }, { + { 0x16, 0x10 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 4800 }, 10416, { 3377, 2138, 1780 }, 5136, { 0, 2, 4, 6, 1, 3, 5, 7 }, { + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + } + }; + + for (const auto& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.exposure = setting.exposure; + sensor.segment_size = setting.segment_size; + sensor.segment_order = setting.segment_order; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_700F; + sensor.optical_res = 4800; + sensor.black_pixels = 73*8; // black pixels 73 at 600 dpi + sensor.dummy_pixel = 16*8; + // 384 at 600 dpi + sensor.ccd_start_xoffset = 384*8; + // 8x5570 segments, 5187+1 for rounding + sensor.sensor_pixels = 5188*8; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + SensorExposure exposure; + unsigned segment_size; + std::vector segment_order; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 75, 100, 150, 200 }, 2848, { 465, 310, 239 }, 5187, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 300 }, 1424, { 465, 310, 239 }, 5187, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 600 }, 1504, { 465, 310, 239 }, 5187, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 1200 }, 2696, { 1464, 844, 555 }, 5187, { 0, 1 }, { + { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 2400 }, 10576, { 2798, 1558, 972 }, 5187, { 0, 1, 2, 3 }, { + { 0x16, 0x10 }, { 0x17, 0x08 }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 4800 }, 10576, { 2798, 1558, 972 }, 5187, { 0, 1, 4, 5, 2, 3, 6, 7 }, { + { 0x16, 0x10 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x07 }, { 0x53, 0x03 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x87 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0xf9 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + } + }; + + for (const auto& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.exposure = setting.exposure; + sensor.segment_size = setting.segment_size; + sensor.segment_order = setting.segment_order; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_100; + sensor.optical_res = 2400; + sensor.black_pixels = 87*4; + sensor.dummy_pixel = 16*4; + sensor.ccd_start_xoffset = 320*4; + sensor.sensor_pixels = 5136*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x01c1, 0x0126, 0x00e5 }; + sensor.gamma = { 2.2f, 2.2f, 2.2f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + SensorExposure exposure; + unsigned segment_size; + std::vector segment_order; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 75, 100, 150, 200 }, 2304, { 423, 294, 242 }, 5136, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 300 }, 1728, { 423, 294, 242 }, 5136, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 600 }, 1432, { 423, 294, 242 }, 5136, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x0a }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + }, + }, + { { 1200 }, 2712, { 791, 542, 403 }, 5136, {0, 1}, { + { 0x16, 0x10 }, { 0x17, 0x08 }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + }, + { { 2400 }, 5280, { 1504, 1030, 766 }, 5136, {0, 2, 1, 3}, { + { 0x16, 0x10 }, { 0x17, 0x06 }, { 0x18, 0x00 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x04 }, + { 0x52, 0x03 }, { 0x53, 0x07 }, { 0x54, 0x00 }, { 0x55, 0x00 }, + { 0x56, 0x00 }, { 0x57, 0x00 }, { 0x58, 0x2a }, { 0x59, 0xe1 }, { 0x5a, 0x55 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + } + } + }; + + for (const auto& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.exposure = setting.exposure; + sensor.segment_size = setting.segment_size; + sensor.segment_order = setting.segment_order; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_KVSS080; + sensor.optical_res = 600; + sensor.black_pixels = 38; + sensor.dummy_pixel = 38; + sensor.ccd_start_xoffset = 152; + sensor.sensor_pixels = 5376; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.exposure_lperiod = 8000; + sensor.custom_regs = { + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, + { 0x0c, 0x00 }, + { 0x70, 0x01 }, + { 0x71, 0x03 }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x1c }, + { 0x18, 0x00 }, + { 0x19, 0x2a }, + { 0x1a, 0x2c }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x04 }, + { 0x52, 0x0c }, + { 0x53, 0x0f }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x09 }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0xc0 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_G4050; + sensor.optical_res = 4800; + sensor.black_pixels = 50*8; + // 31 at 600 dpi dummy_pixels 58 at 1200 + sensor.dummy_pixel = 58; + sensor.ccd_start_xoffset = 152; + sensor.sensor_pixels = 5360*8; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x2c09, 0x22b8, 0x10f0 }; + sensor.stagger_config = StaggerConfig{ 2400, 4 }; // FIXME: may be incorrect + sensor.custom_regs = {}; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + ScanMethod method; + GenesysRegisterSettingSet extra_custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 100, 150, 200, 300, 400, 600 }, 8016, ScanMethod::FLATBED, { + { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff }, + { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, + { 0x0c, 0x00 }, + { 0x70, 0x00 }, + { 0x71, 0x02 }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x00 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x08 }, + { 0x52, 0x0b }, + { 0x53, 0x0e }, + { 0x54, 0x11 }, + { 0x55, 0x02 }, + { 0x56, 0x05 }, + { 0x57, 0x08 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + } + }, + { { 1200 }, 56064, ScanMethod::FLATBED, { + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x01 }, { 0x79, 0xff }, + { 0x7a, 0x00 }, { 0x7b, 0x01 }, { 0x7c, 0xff }, + { 0x0c, 0x20 }, + { 0x70, 0x08 }, + { 0x71, 0x0c }, + { 0x9e, 0xc0 }, + { 0xaa, 0x05 }, + { 0x16, 0x3b }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x38 }, + { 0x1b, 0x10 }, + { 0x1c, 0x00 }, + { 0x1d, 0x08 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0e }, + { 0x57, 0x11 }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + } + }, + { { 2400 }, 56064, ScanMethod::FLATBED, { + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + { 0x0c, 0x20 }, + { 0x70, 0x08 }, + { 0x71, 0x0a }, + { 0x9e, 0xc0 }, + { 0xaa, 0x05 }, + { 0x16, 0x3b }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x38 }, + { 0x1b, 0x10 }, + { 0x1c, 0xc0 }, + { 0x1d, 0x08 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0e }, + { 0x57, 0x11 }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + } + }, + { { 4800 }, 42752, ScanMethod::FLATBED, { + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + { 0x0c, 0x21 }, + { 0x70, 0x08 }, + { 0x71, 0x0a }, + { 0x9e, 0xc0 }, + { 0xaa, 0x07 }, + { 0x16, 0x3b }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x38 }, + { 0x1b, 0x10 }, + { 0x1c, 0xc1 }, + { 0x1d, 0x08 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0e }, + { 0x57, 0x11 }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + } + }, + { ResolutionFilter::ANY, 15624, ScanMethod::TRANSPARENCY, { + { 0x74, 0x00 }, { 0x75, 0x1c }, { 0x76, 0x7f }, + { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, + { 0x0c, 0x00 }, + { 0x70, 0x00 }, + { 0x71, 0x02 }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x4c }, + { 0x18, 0x01 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x08 }, + { 0x52, 0x0e }, + { 0x53, 0x11 }, + { 0x54, 0x02 }, + { 0x55, 0x05 }, + { 0x56, 0x08 }, + { 0x57, 0x0b }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0xc0 }, + } + } + }; + + auto base_custom_regs = sensor.custom_regs; + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.method = setting.method; + sensor.custom_regs = base_custom_regs; + sensor.custom_regs.merge(setting.extra_custom_regs); + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_HP_4850C; + sensor.optical_res = 4800; + sensor.black_pixels = 100; + sensor.dummy_pixel = 58; + sensor.ccd_start_xoffset = 152; + sensor.sensor_pixels = 5360*8; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x2c09, 0x22b8, 0x10f0 }; + sensor.stagger_config = StaggerConfig{ 2400, 4 }; // FIXME: may be incorrect + sensor.custom_regs = {}; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + ScanMethod method; + GenesysRegisterSettingSet extra_custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 100, 150, 200, 300, 400, 600 }, 8016, ScanMethod::FLATBED, { + { 0x0c, 0x00 }, + { 0x16, 0x33 }, { 0x17, 0x0c }, { 0x18, 0x00 }, { 0x19, 0x2a }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x08 }, + { 0x52, 0x0b }, { 0x53, 0x0e }, { 0x54, 0x11 }, { 0x55, 0x02 }, + { 0x56, 0x05 }, { 0x57, 0x08 }, { 0x58, 0x63 }, { 0x59, 0x00 }, { 0x5a, 0x40 }, + { 0x70, 0x00 }, { 0x71, 0x02 }, + { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff }, + { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + } + }, + { { 1200 }, 56064, ScanMethod::FLATBED, { + { 0x0c, 0x20 }, + { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a }, + { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0x00 }, { 0x1d, 0x08 }, + { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b }, + { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 }, + { 0x70, 0x08 }, { 0x71, 0x0c }, + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x01 }, { 0x79, 0xff }, + { 0x7a, 0x00 }, { 0x7b, 0x01 }, { 0x7c, 0xff }, + { 0x9e, 0xc0 }, + { 0xaa, 0x05 }, + } + }, + { { 2400 }, 56064, ScanMethod::FLATBED, { + { 0x0c, 0x20 }, + { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a }, + { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0xc0 }, { 0x1d, 0x08 }, + { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b }, + { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 }, + { 0x70, 0x08 }, { 0x71, 0x0a }, + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + { 0x9e, 0xc0 }, + { 0xaa, 0x05 }, + } + }, + { { 4800 }, 42752, ScanMethod::FLATBED, { + { 0x0c, 0x21 }, + { 0x16, 0x3b }, { 0x17, 0x0c }, { 0x18, 0x10 }, { 0x19, 0x2a }, + { 0x1a, 0x38 }, { 0x1b, 0x10 }, { 0x1c, 0xc1 }, { 0x1d, 0x08 }, + { 0x52, 0x02 }, { 0x53, 0x05 }, { 0x54, 0x08 }, { 0x55, 0x0b }, + { 0x56, 0x0e }, { 0x57, 0x11 }, { 0x58, 0x1b }, { 0x59, 0x00 }, { 0x5a, 0x40 }, + { 0x70, 0x08 }, { 0x71, 0x0a }, + { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + { 0x9e, 0xc0 }, + { 0xaa, 0x07 }, + } + }, + { ResolutionFilter::ANY, 15624, ScanMethod::TRANSPARENCY, { + { 0x0c, 0x00 }, + { 0x16, 0x33 }, { 0x17, 0x4c }, { 0x18, 0x01 }, { 0x19, 0x2a }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x08 }, + { 0x52, 0x0e }, { 0x53, 0x11 }, { 0x54, 0x02 }, { 0x55, 0x05 }, + { 0x56, 0x08 }, { 0x57, 0x0b }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0xc0 }, + { 0x70, 0x00 }, { 0x71, 0x02 }, + { 0x74, 0x00 }, { 0x75, 0x1c }, { 0x76, 0x7f }, + { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, + { 0x9e, 0x00 }, + { 0xaa, 0x00 }, + } + } + }; + + auto base_custom_regs = sensor.custom_regs; + for (const CustomSensorSettings& setting : custom_settings) + { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.method = setting.method; + sensor.custom_regs = base_custom_regs; + sensor.custom_regs.merge(setting.extra_custom_regs); + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_CANON_4400F; + sensor.optical_res = 4800; + sensor.ccd_size_divisor = 4; + sensor.black_pixels = 50*8; + // 31 at 600 dpi, 58 at 1200 dpi + sensor.dummy_pixel = 20; + sensor.ccd_start_xoffset = 152; + // 5360 max at 600 dpi + sensor.sensor_pixels = 5700 * 8; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = get_sensor_optical_with_ccd_divisor; + sensor.get_register_hwdpi_fun = [](const Genesys_Sensor&, unsigned) { return 4800; }; + sensor.get_hwdpi_divisor_fun = [](const Genesys_Sensor&, unsigned) { return 1; }; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + std::vector methods; + GenesysRegisterSettingSet extra_custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 300, 600, 1200 }, 11640, { ScanMethod::FLATBED }, { + { 0x16, 0x13 }, + { 0x17, 0x0a }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x6b }, + { 0x52, 0x0a }, + { 0x53, 0x0d }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x08 }, + { 0x58, 0x5b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x01 }, { 0x73, 0x03 }, + { 0x74, 0x00 }, { 0x75, 0xf8 }, { 0x76, 0x38 }, + { 0x77, 0x00 }, { 0x78, 0xfc }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0xa4 }, + { 0x9e, 0x2d }, + } + }, + { { 300, 600, 1200 }, 33300, { ScanMethod::TRANSPARENCY }, { + { 0x16, 0x13 }, + { 0x17, 0x0a }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x6b }, + { 0x52, 0x0a }, + { 0x53, 0x0d }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x08 }, + { 0x58, 0x5b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x00 }, { 0x73, 0x02 }, + { 0x74, 0x00 }, { 0x75, 0xf8 }, { 0x76, 0x38 }, + { 0x77, 0x00 }, { 0x78, 0xfc }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0xa4 }, + { 0x9e, 0x2d }, + } + }, + { { 2400 }, 33300, { ScanMethod::TRANSPARENCY }, { + { 0x16, 0x13 }, + { 0x17, 0x0a }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x01 }, + { 0x1d, 0x75 }, + { 0x52, 0x0b }, + { 0x53, 0x0d }, + { 0x54, 0x00 }, + { 0x55, 0x03 }, + { 0x56, 0x06 }, + { 0x57, 0x09 }, + { 0x58, 0x53 }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 }, + { 0x74, 0x00 }, { 0x75, 0xff }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0xff }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x54 }, { 0x7c, 0x92 }, + { 0x9e, 0x2d }, + } + }, + { { 4800 }, 33300, { ScanMethod::TRANSPARENCY }, { + { 0x16, 0x13 }, + { 0x17, 0x0a }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x61 }, + { 0x1d, 0x75 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0d }, + { 0x57, 0x0f }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x08 }, { 0x71, 0x0a }, { 0x72, 0x0a }, { 0x73, 0x0c }, + { 0x74, 0x00 }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x00 }, { 0x7b, 0x54 }, { 0x7c, 0x92 }, + { 0x9e, 0x2d }, + } + } + }; + + for (const CustomSensorSettings& setting : custom_settings) + { + for (auto method : setting.methods) { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.method = method; + sensor.custom_regs = setting.extra_custom_regs; + s_sensors->push_back(sensor); + } + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_CANON_8400F; + sensor.optical_res = 3200; + sensor.register_dpihw_override = 4800; + sensor.ccd_size_divisor = 1; + sensor.black_pixels = 50*8; + // 31 at 600 dpi, 58 at 1200 dpi + sensor.dummy_pixel = 20; + sensor.ccd_start_xoffset = 152; + sensor.sensor_pixels = 27200; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; + sensor.stagger_config = StaggerConfig{ 3200, 6 }; + sensor.custom_regs = {}; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = get_sensor_optical_with_ccd_divisor; + sensor.get_register_hwdpi_fun = [](const Genesys_Sensor&, unsigned) { return 4800; }; + sensor.get_hwdpi_divisor_fun = [](const Genesys_Sensor&, unsigned) { return 1; }; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + unsigned dpiset_override; + unsigned pixel_count_multiplier; + int exposure_lperiod; + std::vector methods; + GenesysRegisterSettingSet extra_custom_regs; + GenesysRegisterSettingSet custom_fe_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 400 }, 2400, 1, 7200, { ScanMethod::FLATBED }, { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x13 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x84 }, + { 0x1e, 0xa0 }, + { 0x52, 0x0d }, + { 0x53, 0x10 }, + { 0x54, 0x01 }, + { 0x55, 0x04 }, + { 0x56, 0x07 }, + { 0x57, 0x0a }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x03 }, { 0x73, 0x04 }, + { 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x01 }, { 0x7b, 0xb6 }, { 0x7c, 0xdb }, + { 0x80, 0x2a }, + }, {} + }, + { { 800 }, 4800, 1, 7200, { ScanMethod::FLATBED }, { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x13 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x84 }, + { 0x1e, 0xa0 }, + { 0x52, 0x0d }, + { 0x53, 0x10 }, + { 0x54, 0x01 }, + { 0x55, 0x04 }, + { 0x56, 0x07 }, + { 0x57, 0x0a }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x03 }, { 0x73, 0x04 }, + { 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x01 }, { 0x7b, 0xb6 }, { 0x7c, 0xdb }, + { 0x80, 0x20 }, + }, {} + }, + { { 1600 }, 4800, 1, 14400, { ScanMethod::FLATBED }, { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x11 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x84 }, + { 0x1e, 0xa1 }, + { 0x52, 0x0b }, + { 0x53, 0x0e }, + { 0x54, 0x11 }, + { 0x55, 0x02 }, + { 0x56, 0x05 }, + { 0x57, 0x08 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x03 }, + { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x02 }, { 0x7b, 0x49 }, { 0x7c, 0x24 }, + { 0x80, 0x28 }, + }, { + { 0x03, 0x1f }, + } + }, + { { 3200 }, 4800, 1, 28800, { ScanMethod::FLATBED }, { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x84 }, + { 0x1e, 0xa1 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0e }, + { 0x57, 0x11 }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x09 }, { 0x71, 0x0a }, { 0x72, 0x0b }, { 0x73, 0x0c }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x02 }, { 0x7b, 0x49 }, { 0x7c, 0x24 }, + { 0x80, 0x2b }, + }, { + { 0x03, 0x1f }, + }, + }, + { { 400 }, 2400, 1, 14400, { ScanMethod::TRANSPARENCY, + ScanMethod::TRANSPARENCY_INFRARED }, { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x13 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x84 }, + { 0x1e, 0xa0 }, + { 0x52, 0x0d }, + { 0x53, 0x10 }, + { 0x54, 0x01 }, + { 0x55, 0x04 }, + { 0x56, 0x07 }, + { 0x57, 0x0a }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x03 }, { 0x73, 0x04 }, + { 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x01 }, { 0x7b, 0xb6 }, { 0x7c, 0xdb }, + { 0x80, 0x20 }, + }, {} + }, + { { 800 }, 4800, 1, 14400, { ScanMethod::TRANSPARENCY, + ScanMethod::TRANSPARENCY_INFRARED }, { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x13 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x84 }, + { 0x1e, 0xa0 }, + { 0x52, 0x0d }, + { 0x53, 0x10 }, + { 0x54, 0x01 }, + { 0x55, 0x04 }, + { 0x56, 0x07 }, + { 0x57, 0x0a }, + { 0x58, 0x6b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x01 }, { 0x71, 0x02 }, { 0x72, 0x03 }, { 0x73, 0x04 }, + { 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x01 }, { 0x7b, 0xb6 }, { 0x7c, 0xdb }, + { 0x80, 0x20 }, + }, {} + }, + { { 1600 }, 4800, 1, 28800, { ScanMethod::TRANSPARENCY, + ScanMethod::TRANSPARENCY_INFRARED }, { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x11 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x84 }, + { 0x1e, 0xa0 }, + { 0x52, 0x0b }, + { 0x53, 0x0e }, + { 0x54, 0x11 }, + { 0x55, 0x02 }, + { 0x56, 0x05 }, + { 0x57, 0x08 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x00 }, { 0x71, 0x01 }, { 0x72, 0x02 }, { 0x73, 0x03 }, + { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x02 }, { 0x7b, 0x49 }, { 0x7c, 0x24 }, + { 0x80, 0x29 }, + }, { + { 0x03, 0x1f }, + }, + }, + { { 3200 }, 4800, 1, 28800, { ScanMethod::TRANSPARENCY, + ScanMethod::TRANSPARENCY_INFRARED }, { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x84 }, + { 0x1e, 0xa0 }, + { 0x52, 0x02 }, + { 0x53, 0x05 }, + { 0x54, 0x08 }, + { 0x55, 0x0b }, + { 0x56, 0x0e }, + { 0x57, 0x11 }, + { 0x58, 0x1b }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + { 0x70, 0x09 }, { 0x71, 0x0a }, { 0x72, 0x0b }, { 0x73, 0x0c }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x02 }, { 0x7b, 0x49 }, { 0x7c, 0x24 }, + { 0x80, 0x2b }, + }, { + { 0x03, 0x1f }, + }, + }, + }; + + for (const CustomSensorSettings& setting : custom_settings) + { + for (auto method : setting.methods) { + sensor.resolutions = setting.resolutions; + sensor.dpiset_override = setting.dpiset_override; + sensor.pixel_count_multiplier = setting.pixel_count_multiplier; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.method = method; + sensor.custom_regs = setting.extra_custom_regs; + sensor.custom_fe_regs = setting.custom_fe_regs; + s_sensors->push_back(sensor); + } + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_CANON_8600F; + sensor.optical_res = 4800; + sensor.ccd_size_divisor = 4; + sensor.black_pixels = 31; + sensor.dummy_pixel = 20; + sensor.ccd_start_xoffset = 0; // not used at the moment + // 11372 pixels at 1200 dpi + sensor.sensor_pixels = 11372*4; + sensor.fau_gain_white_ref = 160; + sensor.gain_white_ref = 160; + sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; + sensor.stagger_config = StaggerConfig{4800, 8}; + sensor.custom_regs = {}; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = get_sensor_optical_with_ccd_divisor; + sensor.get_register_hwdpi_fun = [](const Genesys_Sensor&, unsigned) { return 4800; }; + sensor.get_hwdpi_divisor_fun = [](const Genesys_Sensor&, unsigned) { return 1; }; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + std::vector methods; + GenesysRegisterSettingSet extra_custom_regs; + GenesysRegisterSettingSet custom_fe_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 300, 600, 1200 }, 24000, { ScanMethod::FLATBED }, { + { 0x0c, 0x00 }, + { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b }, + { 0x52, 0x0c }, { 0x53, 0x0f }, { 0x54, 0x00 }, { 0x55, 0x03 }, + { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 }, + { 0x56, 0x06 }, { 0x57, 0x09 }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 }, + { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 }, + { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + }, + {}, + }, + { { 300, 600, 1200 }, 45000, { ScanMethod::TRANSPARENCY, + ScanMethod::TRANSPARENCY_INFRARED }, { + { 0x0c, 0x00 }, + { 0x16, 0x13 }, { 0x17, 0x0a }, { 0x18, 0x10 }, { 0x19, 0x2a }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x00 }, { 0x1d, 0x6b }, + { 0x52, 0x0c }, { 0x53, 0x0f }, { 0x54, 0x00 }, { 0x55, 0x03 }, + { 0x56, 0x06 }, { 0x57, 0x09 }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 }, + { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 }, + { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 }, + { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + }, + {}, + }, + { { 2400 }, 45000, { ScanMethod::TRANSPARENCY, + ScanMethod::TRANSPARENCY_INFRARED }, { + { 0x0c, 0x00 }, + { 0x16, 0x13 }, { 0x17, 0x15 }, { 0x18, 0x10 }, { 0x19, 0x2a }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x01 }, { 0x1d, 0x75 }, + { 0x52, 0x0c }, { 0x53, 0x0f }, { 0x54, 0x00 }, { 0x55, 0x03 }, + { 0x56, 0x06 }, { 0x57, 0x09 }, { 0x58, 0x6b }, { 0x59, 0x00 }, { 0x5a, 0x40 }, + { 0x70, 0x00 }, { 0x71, 0x02 }, { 0x72, 0x02 }, { 0x73, 0x04 }, + { 0x74, 0x03 }, { 0x75, 0xfe }, { 0x76, 0x00 }, + { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + }, + {}, + }, + { { 4800 }, 45000, { ScanMethod::TRANSPARENCY, + ScanMethod::TRANSPARENCY_INFRARED }, { + { 0x0c, 0x00 }, + { 0x16, 0x13 }, { 0x17, 0x15 }, { 0x18, 0x10 }, { 0x19, 0x2a }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x61 }, { 0x1d, 0x75 }, + { 0x52, 0x03 }, { 0x53, 0x06 }, { 0x54, 0x09 }, { 0x55, 0x0c }, + { 0x56, 0x0f }, { 0x57, 0x00 }, { 0x58, 0x23 }, { 0x59, 0x00 }, { 0x5a, 0x40 }, + { 0x70, 0x0a }, { 0x71, 0x0c }, { 0x72, 0x0c }, { 0x73, 0x0e }, + { 0x74, 0x03 }, { 0x75, 0xff }, { 0x76, 0xff }, + { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, + { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, + { 0x9e, 0x2d }, + { 0xaa, 0x00 }, + }, + { { 0x03, 0x1f }, + }, + }, + }; + + for (const CustomSensorSettings& setting : custom_settings) { + for (auto method : setting.methods) { + sensor.resolutions = setting.resolutions; + sensor.method = method; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.custom_regs = setting.extra_custom_regs; + sensor.custom_fe_regs = setting.custom_fe_regs; + s_sensors->push_back(sensor); + } + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_HP_N6310; + sensor.optical_res = 2400; + // sensor.ccd_size_divisor = 2; Possibly half CCD, needs checking + sensor.black_pixels = 96; + sensor.dummy_pixel = 26; + sensor.ccd_start_xoffset = 128; + sensor.sensor_pixels = 42720; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x16, 0x33 }, + { 0x17, 0x0c }, + { 0x18, 0x02 }, + { 0x19, 0x2a }, + { 0x1a, 0x30 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x08 }, + { 0x52, 0x0b }, + { 0x53, 0x0e }, + { 0x54, 0x11 }, + { 0x55, 0x02 }, + { 0x56, 0x05 }, + { 0x57, 0x08 }, + { 0x58, 0x63 }, + { 0x59, 0x00 }, + { 0x5a, 0x40 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_110; + sensor.optical_res = 2400; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 16; + sensor.ccd_start_xoffset = 303; + sensor.sensor_pixels = 5168*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.gamma = { 2.2f, 2.2f, 2.2f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_gl124; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + SensorExposure exposure; + std::vector segment_order; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 75, 100, 150 }, 4608, { 462, 609, 453 }, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + { 0x70, 0x06 }, { 0x71, 0x08 }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 }, + { 0x96, 0x00 }, { 0x97, 0x9a }, + { 0x98, 0x21 }, + } + }, + { { 300 }, 4608, { 462, 609, 453 }, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x0c }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + { 0x70, 0x06 }, { 0x71, 0x08 }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 }, + { 0x96, 0x00 }, { 0x97, 0x9a }, + { 0x98, 0x21 }, + } + }, + { { 600 }, 5360, { 823, 1117, 805 }, std::vector{}, { + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x0a }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + { 0x70, 0x06 }, { 0x71, 0x08 }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x21 }, + }, + }, + { { 1200 }, 10528, { 6071, 6670, 6042 }, { 0, 1 }, { + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 },{ 0x20, 0x08 }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + { 0x70, 0x06 }, { 0x71, 0x08 }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x12 }, { 0x89, 0x47 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x22 }, + } + }, + { { 2400 }, 20864, { 7451, 8661, 7405 }, { 0, 2, 1, 3 }, { + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x06 }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + { 0x70, 0x06 }, { 0x71, 0x08 }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x12 }, { 0x89, 0x47 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x24 }, + } + } + }; + + for (const auto& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.exposure = setting.exposure; + sensor.segment_order = setting.segment_order; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_120; + sensor.optical_res = 2400; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 16; + sensor.ccd_start_xoffset = 303; + // SEGCNT at 600 DPI by number of segments + sensor.sensor_pixels = 5104*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.gamma = { 2.2f, 2.2f, 2.2f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_gl124; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + SensorExposure exposure; + std::vector segment_order; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 75, 100, 150, 300 }, 4608, { 1244, 1294, 1144 }, std::vector{}, { + { 0x16, 0x15 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 }, + { 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x3a }, { 0x5b, 0x00 }, { 0x5c, 0x00 }, + { 0x61, 0x20 }, + { 0x70, 0x00 }, { 0x71, 0x1f }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x5e }, + { 0x93, 0x00 }, { 0x94, 0x09 }, { 0x95, 0xf8 }, + { 0x96, 0x00 }, { 0x97, 0x70 }, + { 0x98, 0x21 }, + }, + }, + { { 600 }, 5360, { 2394, 2444, 2144 }, std::vector{}, { + { 0x16, 0x11 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 }, + { 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x3a }, { 0x5b, 0x00 }, { 0x5c, 0x00 }, + { 0x61, 0x20 }, + { 0x70, 0x1f }, { 0x71, 0x1f }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x5e }, + { 0x93, 0x00 }, { 0x94, 0x13 }, { 0x95, 0xf0 }, + { 0x96, 0x00 }, { 0x97, 0x8b }, + { 0x98, 0x21 }, + }, + }, + { { 1200 }, 10528, { 4694, 4644, 4094 }, std::vector{}, { + { 0x16, 0x15 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 }, + { 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x3a }, { 0x5b, 0x00 }, { 0x5c, 0x00 }, + { 0x61, 0x20 }, + { 0x70, 0x1f }, { 0x71, 0x1f }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x5e }, + { 0x93, 0x00 }, { 0x94, 0x27 }, { 0x95, 0xe0 }, + { 0x96, 0x00 }, { 0x97, 0xc0 }, + { 0x98, 0x21 }, + }, + }, + { { 2400 }, 20864, { 8944, 8144, 7994 }, std::vector{}, { + { 0x16, 0x11 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x00 }, { 0x20, 0x02 }, + { 0x52, 0x04 }, { 0x53, 0x06 }, { 0x54, 0x00 }, { 0x55, 0x02 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x3a }, { 0x5b, 0x00 }, { 0x5c, 0x00 }, + { 0x61, 0x20 }, + { 0x70, 0x00 }, { 0x71, 0x1f }, { 0x72, 0x08 }, { 0x73, 0x0a }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x5e }, + { 0x93, 0x00 }, { 0x94, 0x4f }, { 0x95, 0xc0 }, + { 0x96, 0x01 }, { 0x97, 0x2a }, + { 0x98, 0x21 }, + } + }, + }; + + for (const auto& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.exposure = setting.exposure; + sensor.segment_order = setting.segment_order; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_210; + sensor.optical_res = 2400; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 16; + sensor.ccd_start_xoffset = 303; + sensor.sensor_pixels = 5168*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.gamma = { 2.2f, 2.2f, 2.2f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_gl124; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + SensorExposure exposure; + std::vector segment_order; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 75, 100, 150, 300 }, 2768, { 388, 574, 393 }, std::vector{}, { + // { 0x16, 0x00 }, // FIXME: check if default value is different + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + // { 0x70, 0x00 }, // FIXME: check if default value is different + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 }, + { 0x96, 0x00 }, { 0x97, 0x9a }, + { 0x98, 0x21 }, + } + }, + { { 600 }, 5360, { 388, 574, 393 }, std::vector{}, { + // { 0x16, 0x00 }, // FIXME: check if default value is different + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0a }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + // { 0x70, 0x00 }, // FIXME: check if default value is different + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x21 }, + } + }, + { { 1200 }, 10528, { 388, 574, 393 }, {0, 1}, { + // { 0x16, 0x00 }, // FIXME: check if default value is different + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x08 }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + // { 0x70, 0x00 }, // FIXME: check if default value is different + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x22 }, + }, + }, + { { 2400 }, 20864, { 6839, 8401, 6859 }, {0, 2, 1, 3}, { + // { 0x16, 0x00 }, // FIXME: check if default value is different + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x06 }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + // { 0x70, 0x00 }, // FIXME: check if default value is different + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x1e }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x12 }, { 0x89, 0x47 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x24 }, + }, + } + }; + + for (const auto& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.exposure = setting.exposure; + sensor.segment_order = setting.segment_order; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_220; + sensor.optical_res = 2400; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 16; + sensor.ccd_start_xoffset = 303; + sensor.sensor_pixels = 5168*4; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.gamma = { 2.2f, 2.2f, 2.2f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_gl124; + + { + struct CustomSensorSettings { + ResolutionFilter resolutions; + int exposure_lperiod; + SensorExposure exposure; + std::vector segment_order; + GenesysRegisterSettingSet custom_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 75, 100, 150, 300 }, 2768, { 388, 574, 393 }, std::vector{}, { + // { 0x16, 0x00 }, // FIXME: check if default value is different + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0c }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + // { 0x70, 0x00 }, // FIXME: check if default value is different + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x0a }, { 0x95, 0x18 }, + { 0x96, 0x00 }, { 0x97, 0x9a }, + { 0x98, 0x21 }, + } + }, + { { 600 }, 5360, { 388, 574, 393 }, std::vector{}, { + // { 0x16, 0x00 }, // FIXME: check if default value is different + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x0a }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + // { 0x70, 0x00 }, // FIXME: check if default value is different + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x21 }, + } + }, + { { 1200 }, 10528, { 388, 574, 393 }, {0, 1}, { + // { 0x16, 0x00 }, // FIXME: check if default value is different + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x08 }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + // { 0x70, 0x00 }, // FIXME: check if default value is different + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x00 }, { 0x89, 0x65 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x22 }, + } + }, + { { 2400 }, 20864, { 6839, 8401, 6859 }, {0, 2, 1, 3}, { + // { 0x16, 0x00 }, // FIXME: check if default value is different + { 0x16, 0x10 }, { 0x17, 0x04 }, { 0x18, 0x00 }, { 0x19, 0x01 }, + { 0x1a, 0x30 }, { 0x1b, 0x00 }, { 0x1c, 0x02 }, { 0x1d, 0x01 }, { 0x20, 0x06 }, + { 0x52, 0x00 }, { 0x53, 0x02 }, { 0x54, 0x04 }, { 0x55, 0x06 }, + { 0x56, 0x04 }, { 0x57, 0x04 }, { 0x58, 0x04 }, { 0x59, 0x04 }, + { 0x5a, 0x1a }, { 0x5b, 0x00 }, { 0x5c, 0xc0 }, + { 0x61, 0x20 }, + // { 0x70, 0x00 }, // FIXME: check if default value is different + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x0f }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + { 0x88, 0x12 }, { 0x89, 0x47 }, + { 0x93, 0x00 }, { 0x94, 0x14 }, { 0x95, 0x30 }, + { 0x96, 0x00 }, { 0x97, 0xa3 }, + { 0x98, 0x24 }, + }, + } + }; + + for (const auto& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.exposure = setting.exposure; + sensor.segment_order = setting.segment_order; + sensor.custom_regs = setting.custom_regs; + s_sensors->push_back(sensor); + } + } + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICPRO_3600; + sensor.optical_res = 1200; + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 87; + sensor.dummy_pixel = 87; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10100; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x0b, 0x00 }, + { 0x16, 0x33 }, + { 0x17, 0x0b }, + { 0x18, 0x11 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0xc4 }, + { 0x52, 0x07 }, // [GB](HI|LOW) not needed for cis + { 0x53, 0x0a }, + { 0x54, 0x0c }, + { 0x55, 0x00 }, + { 0x56, 0x02 }, + { 0x57, 0x06 }, + { 0x58, 0x22 }, + { 0x59, 0x69 }, + { 0x5a, 0x40 }, + { 0x5b, 0x00 }, // TODO: 5b-5e + { 0x5c, 0x00 }, + { 0x5d, 0x00 }, + { 0x5e, 0x02 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7200I; + sensor.optical_res = 7200; + sensor.register_dpihw_override = 1200; + sensor.black_pixels = 88; // TODO + sensor.dummy_pixel = 20; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10200; // TODO + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.stagger_config = StaggerConfig{7200, 4}; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x16, 0x23 }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x21 }, + { 0x1d, 0x84 }, + { 0x52, 0x0a }, + { 0x53, 0x0d }, + { 0x54, 0x10 }, + { 0x55, 0x01 }, + { 0x56, 0x04 }, + { 0x57, 0x07 }, + { 0x58, 0x3a }, + { 0x59, 0x81 }, + { 0x5a, 0xc0 }, + { 0x70, 0x0a }, + { 0x71, 0x0b }, + { 0x72, 0x0c }, + { 0x73, 0x0d }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + { + struct CustomSensorSettings + { + ResolutionFilter resolutions; + ScanMethod method; + unsigned ccd_size_divisor; + unsigned logical_dpihw_override; + unsigned pixel_count_multiplier; + unsigned exposure_lperiod; + unsigned dpiset_override; + GenesysRegisterSettingSet custom_fe_regs; + }; + + CustomSensorSettings custom_settings[] = { + { { 900 }, ScanMethod::TRANSPARENCY, 1, 900, 8, 0x2538, 150, {} }, + { { 1800 }, ScanMethod::TRANSPARENCY, 1, 1800, 4, 0x2538, 300, {} }, + { { 3600 }, ScanMethod::TRANSPARENCY, 1, 3600, 2, 0x2538, 600, {} }, + { { 7200 }, ScanMethod::TRANSPARENCY, 1, 7200, 1, 0x19c8, 1200, { + { 0x02, 0x1b }, + { 0x03, 0x14 }, + { 0x04, 0x20 }, + } + }, + { { 900 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 900, 8, 0x1f54, 150, {} }, + { { 1800 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 1800, 4, 0x1f54, 300, {} }, + { { 3600 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 3600, 2, 0x1f54, 600, {} }, + { { 7200 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 7200, 1, 0x1f54, 1200, {} }, + }; + + for (const CustomSensorSettings& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.method = setting.method; + sensor.ccd_size_divisor = setting.ccd_size_divisor; + sensor.logical_dpihw_override = setting.logical_dpihw_override; + sensor.pixel_count_multiplier = setting.pixel_count_multiplier; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.dpiset_override = setting.dpiset_override; + sensor.custom_fe_regs = setting.custom_fe_regs; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7300; + sensor.optical_res = 7200; + sensor.method = ScanMethod::TRANSPARENCY; + sensor.register_dpihw_override = 1200; + sensor.black_pixels = 88; // TODO + sensor.dummy_pixel = 20; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10200; // TODO + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.exposure_lperiod = 0x2f44; + sensor.stagger_config = StaggerConfig{7200, 4}; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x16, 0x27 }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x84 }, + { 0x52, 0x0a }, + { 0x53, 0x0d }, + { 0x54, 0x0f }, + { 0x55, 0x01 }, + { 0x56, 0x04 }, + { 0x57, 0x07 }, + { 0x58, 0x31 }, + { 0x59, 0x79 }, + { 0x5a, 0xc0 }, + { 0x70, 0x0c }, + { 0x71, 0x0d }, + { 0x72, 0x0e }, + { 0x73, 0x0f }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + { + struct CustomSensorSettings + { + ResolutionFilter resolutions; + unsigned ccd_size_divisor; + unsigned logical_dpihw_override; + unsigned pixel_count_multiplier; + unsigned dpiset_override; + }; + + CustomSensorSettings custom_settings[] = { + { { 900 }, 1, 900, 8, 150 }, + { { 1800 }, 1, 1800, 4, 300 }, + { { 3600 }, 1, 3600, 2, 600 }, + { { 7200 }, 1, 7200, 1, 1200 }, + }; + + for (const CustomSensorSettings& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.ccd_size_divisor = setting.ccd_size_divisor; + sensor.logical_dpihw_override = setting.logical_dpihw_override; + sensor.pixel_count_multiplier = setting.pixel_count_multiplier; + sensor.dpiset_override = setting.dpiset_override; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICFILM_7500I; + sensor.optical_res = 7200; + sensor.register_dpihw_override = 1200; + sensor.black_pixels = 88; // TODO + sensor.dummy_pixel = 20; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10200; // TODO + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 230; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.stagger_config = StaggerConfig{7200, 4}; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x00 }, + { 0x0a, 0x00 }, + { 0x16, 0x27 }, + { 0x17, 0x0c }, + { 0x18, 0x10 }, + { 0x19, 0x2a }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x20 }, + { 0x1d, 0x84 }, + { 0x52, 0x0a }, + { 0x53, 0x0d }, + { 0x54, 0x0f }, + { 0x55, 0x01 }, + { 0x56, 0x04 }, + { 0x57, 0x07 }, + { 0x58, 0x31 }, + { 0x59, 0x79 }, + { 0x5a, 0xc0 }, + { 0x70, 0x0c }, + { 0x71, 0x0d }, + { 0x72, 0x0e }, + { 0x73, 0x0f }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = get_ccd_size_divisor_exact; + { + struct CustomSensorSettings + { + ResolutionFilter resolutions; + ScanMethod method; + unsigned ccd_size_divisor; + unsigned logical_dpihw_override; + unsigned pixel_count_multiplier; + unsigned exposure_lperiod; + unsigned dpiset_override; + }; + + CustomSensorSettings custom_settings[] = { + { { 900 }, ScanMethod::TRANSPARENCY, 1, 900, 8, 0x2f44, 150 }, + { { 1800 }, ScanMethod::TRANSPARENCY, 1, 1800, 4, 0x2f44, 300 }, + { { 3600 }, ScanMethod::TRANSPARENCY, 1, 3600, 2, 0x2f44, 600 }, + { { 7200 }, ScanMethod::TRANSPARENCY, 1, 7200, 1, 0x2f44, 1200 }, + { { 900 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 900, 8, 0x2af8, 150 }, + { { 1800 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 1800, 4, 0x2af8, 300 }, + { { 3600 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 3600, 2, 0x2af8, 600 }, + { { 7200 }, ScanMethod::TRANSPARENCY_INFRARED, 1, 7200, 1, 0x2af8, 1200 }, + }; + + for (const CustomSensorSettings& setting : custom_settings) { + sensor.resolutions = setting.resolutions; + sensor.method = setting.method; + sensor.ccd_size_divisor = setting.ccd_size_divisor; + sensor.logical_dpihw_override = setting.logical_dpihw_override; + sensor.pixel_count_multiplier = setting.pixel_count_multiplier; + sensor.exposure_lperiod = setting.exposure_lperiod; + sensor.dpiset_override = setting.dpiset_override; + s_sensors->push_back(sensor); + } + } + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_IMG101; + sensor.resolutions = { 75, 100, 150, 300, 600, 1200 }; + sensor.exposure_lperiod = 11000; + sensor.segment_size = 5136; + sensor.segment_order = {0, 1}; + sensor.optical_res = 1200; + sensor.black_pixels = 31; + sensor.dummy_pixel = 31; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10800; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0x0000, 0x0000, 0x0000 }; + sensor.custom_regs = { + { 0x16, 0xbb }, { 0x17, 0x13 }, { 0x18, 0x10 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x06 }, + { 0x52, 0x02 }, { 0x53, 0x04 }, { 0x54, 0x06 }, { 0x55, 0x08 }, + { 0x56, 0x0a }, { 0x57, 0x00 }, { 0x58, 0x59 }, { 0x59, 0x31 }, { 0x5a, 0x40 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + }; + sensor.gamma = { 1.7f, 1.7f, 1.7f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CCD_PLUSTEK_OPTICBOOK_3800; + sensor.resolutions = { 75, 100, 150, 300, 600, 1200 }; + sensor.exposure_lperiod = 11000; + sensor.optical_res = 1200; + sensor.black_pixels = 31; + sensor.dummy_pixel = 31; + sensor.ccd_start_xoffset = 0; + sensor.sensor_pixels = 10200; + sensor.fau_gain_white_ref = 210; + sensor.gain_white_ref = 200; + sensor.exposure = { 0, 0, 0 }; + sensor.custom_regs = { + { 0x16, 0xbb }, { 0x17, 0x13 }, { 0x18, 0x10 }, { 0x19, 0xff }, + { 0x1a, 0x34 }, { 0x1b, 0x00 }, { 0x1c, 0x20 }, { 0x1d, 0x06 }, + { 0x52, 0x02 }, { 0x53, 0x04 }, { 0x54, 0x06 }, { 0x55, 0x08 }, + { 0x56, 0x0a }, { 0x57, 0x00 }, { 0x58, 0x59 }, { 0x59, 0x31 }, { 0x5a, 0x40 }, + { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x3c }, + { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x9f }, + { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x55 }, + }; + sensor.gamma = { 1.7f, 1.7f, 1.7f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); + + + sensor = Genesys_Sensor(); + sensor.sensor_id = SensorId::CIS_CANON_LIDE_80; + sensor.optical_res = 1200; // real hardware limit is 2400 + sensor.ccd_size_divisor = 2; + sensor.black_pixels = 20; + sensor.dummy_pixel = 6; + // tuned to give 3*8 multiple startx coordinate during shading calibration + sensor.ccd_start_xoffset = 34; // 14=>3, 20=>2 + // 10400, too wide=>10288 in shading data 10240~ + // 10208 too short for shading, max shading data = 10240 pixels, endpix-startpix=10208 + sensor.sensor_pixels = 10240; + sensor.fau_gain_white_ref = 150; + sensor.gain_white_ref = 150; + // maps to 0x70-0x73 for GL841 + sensor.exposure = { 0x1000, 0x1000, 0x0500 }; + sensor.custom_regs = { + { 0x08, 0x00 }, + { 0x09, 0x05 }, + { 0x0a, 0x07 }, + { 0x0b, 0x09 }, + { 0x16, 0x00 }, + { 0x17, 0x01 }, + { 0x18, 0x00 }, + { 0x19, 0x06 }, + { 0x1a, 0x00 }, + { 0x1b, 0x00 }, + { 0x1c, 0x00 }, + { 0x1d, 0x04 }, + { 0x52, 0x03 }, + { 0x53, 0x07 }, + { 0x54, 0x00 }, + { 0x55, 0x00 }, + { 0x56, 0x00 }, + { 0x57, 0x00 }, + { 0x58, 0x29 }, + { 0x59, 0x69 }, + { 0x5a, 0x55 }, + { 0x5b, 0x00 }, + { 0x5c, 0x00 }, + { 0x5d, 0x20 }, + { 0x5e, 0x41 }, + }; + sensor.gamma = { 1.0f, 1.0f, 1.0f }; + sensor.get_logical_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_register_hwdpi_fun = default_get_logical_hwdpi; + sensor.get_hwdpi_divisor_fun = default_get_hwdpi_divisor_for_dpi; + sensor.get_ccd_size_divisor_fun = default_get_ccd_size_divisor_for_dpi; + s_sensors->push_back(sensor); +} + +} // namespace genesys diff --git a/backend/genesys/test_scanner_interface.cpp b/backend/genesys/test_scanner_interface.cpp new file mode 100644 index 0000000..12f726f --- /dev/null +++ b/backend/genesys/test_scanner_interface.cpp @@ -0,0 +1,229 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "test_scanner_interface.h" +#include "device.h" +#include + +namespace genesys { + +TestScannerInterface::TestScannerInterface(Genesys_Device* dev) : dev_{dev} +{ + // initialize status registers + if (dev_->model->asic_type == AsicType::GL124) { + write_register(0x101, 0x00); + } else { + write_register(0x41, 0x00); + } + if (dev_->model->asic_type == AsicType::GL841 || + dev_->model->asic_type == AsicType::GL843 || + dev_->model->asic_type == AsicType::GL845 || + dev_->model->asic_type == AsicType::GL846 || + dev_->model->asic_type == AsicType::GL847) + { + write_register(0x40, 0x00); + } + + // initialize other registers that we read on init + if (dev_->model->asic_type == AsicType::GL124) { + write_register(0x33, 0x00); + write_register(0xbd, 0x00); + write_register(0xbe, 0x00); + write_register(0x100, 0x00); + } + + if (dev_->model->asic_type == AsicType::GL845 || + dev_->model->asic_type == AsicType::GL846 || + dev_->model->asic_type == AsicType::GL847) + { + write_register(0xbd, 0x00); + write_register(0xbe, 0x00); + + write_register(0xd0, 0x00); + write_register(0xd1, 0x01); + write_register(0xd2, 0x02); + write_register(0xd3, 0x03); + write_register(0xd4, 0x04); + write_register(0xd5, 0x05); + write_register(0xd6, 0x06); + write_register(0xd7, 0x07); + write_register(0xd8, 0x08); + write_register(0xd9, 0x09); + } +} + +TestScannerInterface::~TestScannerInterface() = default; + +bool TestScannerInterface::is_mock() const +{ + return true; +} + +std::uint8_t TestScannerInterface::read_register(std::uint16_t address) +{ + return cached_regs_.get(address); +} + +void TestScannerInterface::write_register(std::uint16_t address, std::uint8_t value) +{ + cached_regs_.update(address, value); +} + +void TestScannerInterface::write_registers(const Genesys_Register_Set& regs) +{ + cached_regs_.update(regs); +} + + +void TestScannerInterface::write_0x8c(std::uint8_t index, std::uint8_t value) +{ + (void) index; + (void) value; +} + +void TestScannerInterface::bulk_read_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) +{ + (void) addr; + std::memset(data, 0, size); +} + +void TestScannerInterface::bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) +{ + (void) addr; + (void) data; + (void) size; +} + +void TestScannerInterface::write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags) +{ + (void) type; + (void) addr; + (void) data; + (void) size; + (void) flags; +} + +void TestScannerInterface::write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags) +{ + (void) type; + (void) addr; + (void) data; + (void) size; + (void) flags; +} + +void TestScannerInterface::write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) +{ + (void) addr; + (void) size; + (void) data; +} + +std::uint16_t TestScannerInterface::read_fe_register(std::uint8_t address) +{ + return cached_fe_regs_.get(address); +} + +void TestScannerInterface::write_fe_register(std::uint8_t address, std::uint16_t value) +{ + cached_fe_regs_.update(address, value); +} + +IUsbDevice& TestScannerInterface::get_usb_device() +{ + return usb_dev_; +} + +void TestScannerInterface::sleep_us(unsigned microseconds) +{ + (void) microseconds; +} + +void TestScannerInterface::record_slope_table(unsigned table_nr, + const std::vector& steps) +{ + slope_tables_[table_nr] = steps; +} + +std::map>& TestScannerInterface::recorded_slope_tables() +{ + return slope_tables_; +} + +void TestScannerInterface::record_progress_message(const char* msg) +{ + last_progress_message_ = msg; +} + +const std::string& TestScannerInterface::last_progress_message() const +{ + return last_progress_message_; +} + +void TestScannerInterface::record_key_value(const std::string& key, const std::string& value) +{ + key_values_[key] = value; +} + +std::map& TestScannerInterface::recorded_key_values() +{ + return key_values_; +} + +void TestScannerInterface::test_checkpoint(const std::string& name) +{ + if (checkpoint_callback_) { + checkpoint_callback_(*dev_, *this, name); + } +} + +void TestScannerInterface::set_checkpoint_callback(TestCheckpointCallback callback) +{ + checkpoint_callback_ = callback; +} + +} // namespace genesys diff --git a/backend/genesys/test_scanner_interface.h b/backend/genesys/test_scanner_interface.h new file mode 100644 index 0000000..acf0f6d --- /dev/null +++ b/backend/genesys/test_scanner_interface.h @@ -0,0 +1,122 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_TEST_SCANNER_INTERFACE_H +#define BACKEND_GENESYS_TEST_SCANNER_INTERFACE_H + +#include "scanner_interface.h" +#include "register_cache.h" +#include "test_usb_device.h" +#include "test_settings.h" + +#include + +namespace genesys { + +class TestScannerInterface : public ScannerInterface +{ +public: + TestScannerInterface(Genesys_Device* dev); + + ~TestScannerInterface() override; + + bool is_mock() const override; + + const RegisterCache& cached_regs() const { return cached_regs_; } + const RegisterCache& cached_fe_regs() const { return cached_fe_regs_; } + + std::uint8_t read_register(std::uint16_t address) override; + void write_register(std::uint16_t address, std::uint8_t value) override; + void write_registers(const Genesys_Register_Set& regs) override; + + void write_0x8c(std::uint8_t index, std::uint8_t value) override; + void bulk_read_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) override; + void bulk_write_data(std::uint8_t addr, std::uint8_t* data, std::size_t size) override; + + void write_buffer(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags) override; + void write_gamma(std::uint8_t type, std::uint32_t addr, std::uint8_t* data, + std::size_t size, Flags flags) override; + void write_ahb(std::uint32_t addr, std::uint32_t size, std::uint8_t* data) override; + + std::uint16_t read_fe_register(std::uint8_t address) override; + void write_fe_register(std::uint8_t address, std::uint16_t value) override; + + IUsbDevice& get_usb_device() override; + + void sleep_us(unsigned microseconds) override; + + void record_progress_message(const char* msg) override; + + const std::string& last_progress_message() const; + + void record_slope_table(unsigned table_nr, const std::vector& steps) override; + + std::map>& recorded_slope_tables(); + + void record_key_value(const std::string& key, const std::string& value) override; + + std::map& recorded_key_values(); + + void test_checkpoint(const std::string& name) override; + + void set_checkpoint_callback(TestCheckpointCallback callback); + +private: + Genesys_Device* dev_; + + RegisterCache cached_regs_; + RegisterCache cached_fe_regs_; + TestUsbDevice usb_dev_; + + TestCheckpointCallback checkpoint_callback_; + + std::map> slope_tables_; + + std::string last_progress_message_; + std::map key_values_; +}; + +} // namespace genesys + +#endif diff --git a/backend/genesys/test_settings.cpp b/backend/genesys/test_settings.cpp new file mode 100644 index 0000000..425f09c --- /dev/null +++ b/backend/genesys/test_settings.cpp @@ -0,0 +1,106 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "test_settings.h" + +namespace genesys { + +namespace { + +bool s_testing_mode = false; +std::uint16_t s_vendor_id = 0; +std::uint16_t s_product_id = 0; +TestCheckpointCallback s_checkpoint_callback; + +} // namespace + +bool is_testing_mode() +{ + return s_testing_mode; +} + +void disable_testing_mode() +{ + s_testing_mode = false; + s_vendor_id = 0; + s_product_id = 0; + +} + +void enable_testing_mode(std::uint16_t vendor_id, std::uint16_t product_id, + TestCheckpointCallback checkpoint_callback) +{ + s_testing_mode = true; + s_vendor_id = vendor_id; + s_product_id = product_id; + s_checkpoint_callback = checkpoint_callback; +} + +std::uint16_t get_testing_vendor_id() +{ + return s_vendor_id; +} + +std::uint16_t get_testing_product_id() +{ + return s_product_id; +} + +std::string get_testing_device_name() +{ + std::string name; + unsigned max_size = 50; + name.resize(max_size); + name.resize(std::snprintf(&name.front(), max_size, "test device:0x%04x:0x%04x", + s_vendor_id, s_product_id)); + return name; +} + +TestCheckpointCallback get_testing_checkpoint_callback() +{ + return s_checkpoint_callback; +} + +} // namespace genesys diff --git a/backend/genesys/test_settings.h b/backend/genesys/test_settings.h new file mode 100644 index 0000000..8ac03e0 --- /dev/null +++ b/backend/genesys/test_settings.h @@ -0,0 +1,70 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_TEST_SETTINGS_H +#define BACKEND_GENESYS_TEST_SETTINGS_H + +#include "scanner_interface.h" +#include "register_cache.h" +#include "test_usb_device.h" +#include + +namespace genesys { + +using TestCheckpointCallback = std::function; + +bool is_testing_mode(); +void disable_testing_mode(); +void enable_testing_mode(std::uint16_t vendor_id, std::uint16_t product_id, + TestCheckpointCallback checkpoint_callback); +std::uint16_t get_testing_vendor_id(); +std::uint16_t get_testing_product_id(); +std::string get_testing_device_name(); +TestCheckpointCallback get_testing_checkpoint_callback(); + + +} // namespace genesys + +#endif // BACKEND_GENESYS_TEST_SETTINGS_H diff --git a/backend/genesys/test_usb_device.cpp b/backend/genesys/test_usb_device.cpp new file mode 100644 index 0000000..de2399e --- /dev/null +++ b/backend/genesys/test_usb_device.cpp @@ -0,0 +1,141 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "test_usb_device.h" +#include "low.h" + +namespace genesys { + +TestUsbDevice::TestUsbDevice(std::uint16_t vendor, std::uint16_t product) : + vendor_{vendor}, + product_{product} +{ +} + +TestUsbDevice::~TestUsbDevice() +{ + if (is_open()) { + DBG(DBG_error, "TestUsbDevice not closed; closing automatically"); + close(); + } +} + +void TestUsbDevice::open(const char* dev_name) +{ + DBG_HELPER(dbg); + + if (is_open()) { + throw SaneException("device already open"); + } + name_ = dev_name; + is_open_ = true; +} + +void TestUsbDevice::clear_halt() +{ + DBG_HELPER(dbg); + assert_is_open(); +} + +void TestUsbDevice::reset() +{ + DBG_HELPER(dbg); + assert_is_open(); +} + +void TestUsbDevice::close() +{ + DBG_HELPER(dbg); + assert_is_open(); + + is_open_ = false; + name_ = ""; +} + +void TestUsbDevice::get_vendor_product(int& vendor, int& product) +{ + DBG_HELPER(dbg); + assert_is_open(); + vendor = vendor_; + product = product_; +} + +void TestUsbDevice::control_msg(int rtype, int reg, int value, int index, int length, + std::uint8_t* data) +{ + (void) reg; + (void) value; + (void) index; + DBG_HELPER(dbg); + assert_is_open(); + if (rtype == REQUEST_TYPE_IN) { + std::memset(data, 0, length); + } +} + +void TestUsbDevice::bulk_read(std::uint8_t* buffer, std::size_t* size) +{ + + DBG_HELPER(dbg); + assert_is_open(); + std::memset(buffer, 0, *size); +} + +void TestUsbDevice::bulk_write(const std::uint8_t* buffer, std::size_t* size) +{ + (void) buffer; + (void) size; + DBG_HELPER(dbg); + assert_is_open(); +} + +void TestUsbDevice::assert_is_open() const +{ + if (!is_open()) { + throw SaneException("device not open"); + } +} + +} // namespace genesys diff --git a/backend/genesys/test_usb_device.h b/backend/genesys/test_usb_device.h new file mode 100644 index 0000000..abbd78a --- /dev/null +++ b/backend/genesys/test_usb_device.h @@ -0,0 +1,85 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_TEST_USB_DEVICE_H +#define BACKEND_GENESYS_TEST_USB_DEVICE_H + +#include "usb_device.h" + +namespace genesys { + +class TestUsbDevice : public IUsbDevice { +public: + TestUsbDevice(std::uint16_t vendor, std::uint16_t product); + TestUsbDevice() = default; + + ~TestUsbDevice() override; + + bool is_open() const override { return is_open_; } + + const std::string& name() const override { return name_; } + + void open(const char* dev_name) override; + + void clear_halt() override; + void reset() override; + void close() override; + + void get_vendor_product(int& vendor, int& product) override; + + void control_msg(int rtype, int reg, int value, int index, int length, + std::uint8_t* data) override; + void bulk_read(std::uint8_t* buffer, std::size_t* size) override; + void bulk_write(const std::uint8_t* buffer, std::size_t* size) override; +private: + void assert_is_open() const; + + std::string name_; + bool is_open_ = false; + std::uint16_t vendor_ = 0; + std::uint16_t product_ = 0; +}; + +} // namespace genesys + +#endif // BACKEND_GENESYS_TEST_USB_DEVICE_H diff --git a/backend/genesys/usb_device.cpp b/backend/genesys/usb_device.cpp new file mode 100644 index 0000000..2d02219 --- /dev/null +++ b/backend/genesys/usb_device.cpp @@ -0,0 +1,147 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#define DEBUG_DECLARE_ONLY + +#include "usb_device.h" + +namespace genesys { + +IUsbDevice::~IUsbDevice() = default; + +UsbDevice::~UsbDevice() +{ + if (is_open()) { + DBG(DBG_error, "UsbDevice not closed; closing automatically"); + close(); + } +} + +void UsbDevice::open(const char* dev_name) +{ + DBG_HELPER(dbg); + + if (is_open()) { + throw SaneException("device already open"); + } + int device_num = 0; + + dbg.status("open device"); + TIE(sanei_usb_open(dev_name, &device_num)); + + name_ = dev_name; + device_num_ = device_num; + is_open_ = true; +} + +void UsbDevice::clear_halt() +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_clear_halt(device_num_)); +} + +void UsbDevice::reset() +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_reset(device_num_)); +} + +void UsbDevice::close() +{ + DBG_HELPER(dbg); + assert_is_open(); + + // we can't do much if closing fails, so we close the device on our side regardless of the + // function succeeds + int device_num = device_num_; + + set_not_open(); + sanei_usb_close(device_num); +} + +void UsbDevice::get_vendor_product(int& vendor, int& product) +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_get_vendor_product(device_num_, &vendor, &product)); +} + +void UsbDevice::control_msg(int rtype, int reg, int value, int index, int length, + std::uint8_t* data) +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_control_msg(device_num_, rtype, reg, value, index, length, data)); +} + +void UsbDevice::bulk_read(std::uint8_t* buffer, std::size_t* size) +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_read_bulk(device_num_, buffer, size)); +} + +void UsbDevice::bulk_write(const std::uint8_t* buffer, std::size_t* size) +{ + DBG_HELPER(dbg); + assert_is_open(); + TIE(sanei_usb_write_bulk(device_num_, buffer, size)); +} + +void UsbDevice::assert_is_open() const +{ + if (!is_open()) { + throw SaneException("device not open"); + } +} + +void UsbDevice::set_not_open() +{ + device_num_ = 0; + is_open_ = false; + name_ = ""; +} + +} // namespace genesys diff --git a/backend/genesys/usb_device.h b/backend/genesys/usb_device.h new file mode 100644 index 0000000..265c57c --- /dev/null +++ b/backend/genesys/usb_device.h @@ -0,0 +1,118 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_USB_DEVICE_H +#define BACKEND_GENESYS_USB_DEVICE_H + +#include "error.h" +#include "../include/sane/sanei_usb.h" + +#include +#include + +namespace genesys { + +class IUsbDevice { +public: + IUsbDevice() = default; + + IUsbDevice(const IUsbDevice& other) = delete; + IUsbDevice& operator=(const IUsbDevice&) = delete; + + virtual ~IUsbDevice(); + + virtual bool is_open() const = 0; + + virtual const std::string& name() const = 0; + + virtual void open(const char* dev_name) = 0; + + virtual void clear_halt() = 0; + virtual void reset() = 0; + virtual void close() = 0; + + virtual void get_vendor_product(int& vendor, int& product) = 0; + + virtual void control_msg(int rtype, int reg, int value, int index, int length, + std::uint8_t* data) = 0; + virtual void bulk_read(std::uint8_t* buffer, std::size_t* size) = 0; + virtual void bulk_write(const std::uint8_t* buffer, std::size_t* size) = 0; + +}; + +class UsbDevice : public IUsbDevice { +public: + UsbDevice() = default; + + ~UsbDevice() override; + + bool is_open() const override { return is_open_; } + + const std::string& name() const override { return name_; } + + void open(const char* dev_name) override; + + void clear_halt() override; + void reset() override; + void close() override; + + void get_vendor_product(int& vendor, int& product) override; + + void control_msg(int rtype, int reg, int value, int index, int length, + std::uint8_t* data) override; + void bulk_read(std::uint8_t* buffer, std::size_t* size) override; + void bulk_write(const std::uint8_t* buffer, std::size_t* size) override; + +private: + + void assert_is_open() const; + void set_not_open(); + + std::string name_; + bool is_open_ = false; + int device_num_ = 0; +}; + +} // namespace genesys + +#endif // BACKEND_GENESYS_USB_DEVICE_H diff --git a/backend/genesys/utilities.h b/backend/genesys/utilities.h new file mode 100644 index 0000000..1e268b5 --- /dev/null +++ b/backend/genesys/utilities.h @@ -0,0 +1,180 @@ +/* sane - Scanner Access Now Easy. + + Copyright (C) 2019 Povilas Kanapickas + + 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. +*/ + +#ifndef BACKEND_GENESYS_UTILITIES_H +#define BACKEND_GENESYS_UTILITIES_H + +#include "error.h" +#include +#include +#include +#include + +namespace genesys { + +template +void compute_array_percentile_approx(T* result, const T* data, + std::size_t line_count, std::size_t elements_per_line, + float percentile) +{ + if (line_count == 0) { + throw SaneException("invalid line count"); + } + + if (line_count == 1) { + std::copy(data, data + elements_per_line, result); + return; + } + + std::vector column_elems; + column_elems.resize(line_count, 0); + + std::size_t select_elem = std::min(static_cast(line_count * percentile), + line_count - 1); + + auto select_it = column_elems.begin() + select_elem; + + for (std::size_t ix = 0; ix < elements_per_line; ++ix) { + for (std::size_t iy = 0; iy < line_count; ++iy) { + column_elems[iy] = data[iy * elements_per_line + ix]; + } + + std::nth_element(column_elems.begin(), select_it, column_elems.end()); + + *result++ = *select_it; + } +} + +template +class BasicStreamStateSaver +{ +public: + explicit BasicStreamStateSaver(std::basic_ios& stream) : + stream_{stream} + { + flags_ = stream_.flags(); + width_ = stream_.width(); + precision_ = stream_.precision(); + fill_ = stream_.fill(); + } + + ~BasicStreamStateSaver() + { + stream_.flags(flags_); + stream_.width(width_); + stream_.precision(precision_); + stream_.fill(fill_); + } + + BasicStreamStateSaver(const BasicStreamStateSaver&) = delete; + BasicStreamStateSaver& operator=(const BasicStreamStateSaver&) = delete; + +private: + std::basic_ios& stream_; + std::ios_base::fmtflags flags_; + std::streamsize width_ = 0; + std::streamsize precision_ = 0; + Char fill_ = ' '; +}; + +using StreamStateSaver = BasicStreamStateSaver>; + +template +std::string format_indent_braced_list(unsigned indent, const T& x) +{ + std::string indent_str(indent, ' '); + std::ostringstream out; + out << x; + auto formatted_str = out.str(); + if (formatted_str.empty()) { + return formatted_str; + } + + std::string out_str; + for (std::size_t i = 0; i < formatted_str.size(); ++i) { + out_str += formatted_str[i]; + + if (formatted_str[i] == '\n' && + i < formatted_str.size() - 1 && + formatted_str[i + 1] != '\n') + { + out_str += indent_str; + } + } + return out_str; +} + +template +std::string format_vector_unsigned(unsigned indent, const std::vector& arg) +{ + std::ostringstream out; + std::string indent_str(indent, ' '); + + out << "std::vector{ "; + for (const auto& el : arg) { + out << indent_str << static_cast(el) << "\n"; + } + out << "}"; + return out.str(); +} + +template +std::string format_vector_indent_braced(unsigned indent, const char* type, + const std::vector& arg) +{ + if (arg.empty()) { + return "{}"; + } + std::string indent_str(indent, ' '); + std::stringstream out; + out << "std::vector<" << type << ">{\n"; + for (const auto& item : arg) { + out << indent_str << format_indent_braced_list(indent, item) << '\n'; + } + out << "}"; + return out.str(); +} + +} // namespace genesys + +#endif // BACKEND_GENESYS_UTILITIES_H diff --git a/backend/genesys_conv.cc b/backend/genesys_conv.cc deleted file mode 100644 index 06fd4e0..0000000 --- a/backend/genesys_conv.cc +++ /dev/null @@ -1,474 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2005, 2006 Pierre Willenbrock - Copyright (C) 2010-2013 Stéphane Voltz - - 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. -*/ - -/* - * Conversion filters for genesys backend - */ - - -/*8 bit*/ -#define SINGLE_BYTE -#define BYTES_PER_COMPONENT 1 -#define COMPONENT_TYPE uint8_t - -#define FUNC_NAME(f) f ## _8 - -#include "genesys_conv_hlp.cc" - -#undef FUNC_NAME - -#undef COMPONENT_TYPE -#undef BYTES_PER_COMPONENT -#undef SINGLE_BYTE - -/*16 bit*/ -#define DOUBLE_BYTE -#define BYTES_PER_COMPONENT 2 -#define COMPONENT_TYPE uint16_t - -#define FUNC_NAME(f) f ## _16 - -#include "genesys_conv_hlp.cc" - -#undef FUNC_NAME - -#undef COMPONENT_TYPE -#undef BYTES_PER_COMPONENT -#undef DOUBLE_BYTE - -static SANE_Status -genesys_reverse_bits( - uint8_t *src_data, - uint8_t *dst_data, - size_t bytes) -{ - size_t i; - for(i = 0; i < bytes; i++) { - *dst_data++ = ~ *src_data++; - } - return SANE_STATUS_GOOD; -} - -/** - * uses the threshold/threshold_curve to control software binarization - * This code was taken from the epjistsu backend by m. allan noah - * @param dev device set up for the scan - * @param src pointer to raw data - * @param dst pointer where to store result - * @param width width of the processed line - * */ -static SANE_Status -binarize_line(Genesys_Device * dev, uint8_t *src, uint8_t *dst, int width) -{ - int j, windowX, sum = 0; - int thresh; - int offset, addCol, dropCol; - unsigned char mask; - - int x; - uint8_t min, max; - - /* 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); - } - - /* ~1mm works best, but the window needs to have odd # of pixels */ - windowX = (6 * dev->settings.xres) / 150; - if (!(windowX % 2)) - windowX++; - - /* second, prefill the sliding sum */ - for (j = 0; j < windowX; j++) - sum += src[j]; - - /* third, walk the input buffer, update the sliding sum, */ - /* determine threshold, output bits */ - for (j = 0; j < width; j++) - { - /* output image location */ - offset = j % 8; - mask = 0x80 >> offset; - thresh = dev->settings.threshold; - - /* move sum/update threshold only if there is a curve */ - if (dev->settings.threshold_curve) - { - addCol = j + windowX / 2; - dropCol = addCol - windowX; - - if (dropCol >= 0 && addCol < width) - { - sum -= src[dropCol]; - sum += src[addCol]; - } - thresh = dev->lineart_lut[sum / windowX]; - } - - /* use average to lookup threshold */ - if (src[j] > thresh) - *dst &= ~mask; /* white */ - else - *dst |= mask; /* black */ - - if (offset == 7) - dst++; - } - - return SANE_STATUS_GOOD; -} - -/** - * software lineart using data from a 8 bit gray scan. We assume true gray - * or monochrome scan as input. - */ -static SANE_Status -genesys_gray_lineart( - Genesys_Device *dev, - uint8_t *src_data, - uint8_t *dst_data, - size_t pixels, - size_t lines, - uint8_t threshold) -{ - size_t y; - - DBG(DBG_io2, "%s: converting %lu lines of %lu pixels\n", __func__, (unsigned long)lines, - (unsigned long)pixels); - DBG(DBG_io2, "%s: threshold=%d\n", __func__, threshold); - - for (y = 0; y < lines; y++) - { - binarize_line (dev, src_data + y * pixels, dst_data, pixels); - dst_data += pixels / 8; - } - return SANE_STATUS_GOOD; -} - -/** @brief shrink or grow scanned data to fit the final scan size - * This function shrinks the scanned data it the required resolution is lower than the hardware one, - * or grows it in case it is the opposite like when motor resolution is higher than - * sensor's one. - */ -static SANE_Status -genesys_shrink_lines_1 ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int src_pixels, - unsigned int dst_pixels, - unsigned int channels) -{ - unsigned int dst_x, src_x, y, c, cnt; - unsigned int avg[3], val; - uint8_t *src = (uint8_t *) src_data; - uint8_t *dst = (uint8_t *) dst_data; - - /* choose between case where me must reduce or grow the scanned data */ - if (src_pixels > dst_pixels) - { - /* shrink data */ - /* TODO action must be taken at bit level, no bytes */ - src_pixels /= 8; - dst_pixels /= 8; - /*take first _byte_ */ - for (y = 0; y < lines; y++) - { - cnt = src_pixels / 2; - src_x = 0; - for (dst_x = 0; dst_x < dst_pixels; dst_x++) - { - while (cnt < src_pixels && src_x < src_pixels) - { - cnt += dst_pixels; - - for (c = 0; c < channels; c++) - avg[c] = *src++; - src_x++; - } - cnt -= src_pixels; - - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - } - } - } - else - { - /* common case where y res is double x res */ - for (y = 0; y < lines; y++) - { - if (2 * src_pixels == dst_pixels) - { - /* double and interleave on line */ - for (c = 0; c < src_pixels/8; c++) - { - /* first 4 bits */ - val = 0; - val |= (*src & 0x80) >> 0; /* X___ ____ --> X___ ____ */ - val |= (*src & 0x80) >> 1; /* X___ ____ --> _X__ ____ */ - val |= (*src & 0x40) >> 1; /* _X__ ____ --> __X_ ____ */ - val |= (*src & 0x40) >> 2; /* _X__ ____ --> ___X ____ */ - val |= (*src & 0x20) >> 2; /* __X_ ____ --> ____ X___ */ - val |= (*src & 0x20) >> 3; /* __X_ ____ --> ____ _X__ */ - val |= (*src & 0x10) >> 3; /* ___X ____ --> ____ __X_ */ - val |= (*src & 0x10) >> 4; /* ___X ____ --> ____ ___X */ - *dst = val; - dst++; - - /* last for bits */ - val = 0; - val |= (*src & 0x08) << 4; /* ____ X___ --> X___ ____ */ - val |= (*src & 0x08) << 3; /* ____ X___ --> _X__ ____ */ - val |= (*src & 0x04) << 3; /* ____ _X__ --> __X_ ____ */ - val |= (*src & 0x04) << 2; /* ____ _X__ --> ___X ____ */ - val |= (*src & 0x02) << 2; /* ____ __X_ --> ____ X___ */ - val |= (*src & 0x02) << 1; /* ____ __X_ --> ____ _X__ */ - val |= (*src & 0x01) << 1; /* ____ ___X --> ____ __X_ */ - val |= (*src & 0x01) << 0; /* ____ ___X --> ____ ___X */ - *dst = val; - dst++; - src++; - } - } - else - { - /* TODO: since depth is 1, we must interpolate bit within bytes */ - DBG (DBG_warn, "%s: inaccurate bit expansion!\n", __func__); - cnt = dst_pixels / 2; - dst_x = 0; - for (src_x = 0; src_x < src_pixels; src_x++) - { - for (c = 0; c < channels; c++) - avg[c] = *src++; - while (cnt < dst_pixels && dst_x < dst_pixels) - { - cnt += src_pixels; - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - dst_x++; - } - cnt -= dst_pixels; - } - } - } - } - - return SANE_STATUS_GOOD; -} - - -/** Look in image for likely left/right/bottom paper edges, then crop image. - * Since failing to crop isn't fatal, we always return SANE_STATUS_GOOD . - */ -static SANE_Status -genesys_crop(Genesys_Scanner *s) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Device *dev = s->dev; - int top = 0; - int bottom = 0; - int left = 0; - int right = 0; - - DBG (DBG_proc, "%s: start\n", __func__); - - /* first find edges if any */ - status = sanei_magic_findEdges (&s->params, - dev->img_buffer.data(), - dev->settings.xres, - dev->settings.yres, - &top, - &bottom, - &left, - &right); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_info, "%s: bad or no edges, bailing\n", __func__); - return SANE_STATUS_GOOD; - } - DBG (DBG_io, "%s: t:%d b:%d l:%d r:%d\n", __func__, top, bottom, left, - right); - - /* now crop the image */ - status = - sanei_magic_crop (&(s->params), dev->img_buffer.data(), top, bottom, left, right); - if (status) - { - DBG (DBG_warn, "%s: failed to crop\n", __func__); - return SANE_STATUS_GOOD; - } - - /* update counters to new image size */ - dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; - - DBG (DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} - -/** Look in image for likely upper and left paper edges, then rotate - * image so that upper left corner of paper is upper left of image. - * @return since failure doens't prevent scanning, we always return - * SANE_STATUS_GOOD - */ -static SANE_Status -genesys_deskew(Genesys_Scanner *s, const Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Device *dev = s->dev; - - int x = 0, y = 0, bg; - double slope = 0; - - DBG (DBG_proc, "%s: start\n", __func__); - - bg=0; - if(s->params.format==SANE_FRAME_GRAY && s->params.depth == 1) - { - bg=0xff; - } - status = sanei_magic_findSkew (&s->params, - dev->img_buffer.data(), - sensor.optical_res, - sensor.optical_res, - &x, - &y, - &slope); - if (status!=SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: bad findSkew, bailing\n", __func__); - return SANE_STATUS_GOOD; - } - DBG(DBG_info, "%s: slope=%f => %f\n",__func__,slope, (slope/M_PI_2)*90); - /* rotate image slope is in [-PI/2,PI/2] - * positive values rotate trigonometric direction wise */ - status = sanei_magic_rotate (&s->params, - dev->img_buffer.data(), - x, - y, - slope, - bg); - if (status!=SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: rotate error: %s", __func__, sane_strstatus(status)); - } - - DBG (DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} - -/** remove lone dots - * @return since failure doens't prevent scanning, we always return - * SANE_STATUS_GOOD - */ -static SANE_Status -genesys_despeck(Genesys_Scanner *s) -{ - if(sanei_magic_despeck(&s->params, - s->dev->img_buffer.data(), - s->despeck)!=SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: bad despeck, bailing\n",__func__); - } - - return SANE_STATUS_GOOD; -} - -/** Look if image needs rotation and apply it - * */ -static SANE_Status -genesys_derotate (Genesys_Scanner * s) -{ - SANE_Status status = SANE_STATUS_GOOD; - int angle = 0; - - DBGSTART; - status = sanei_magic_findTurn (&s->params, - s->dev->img_buffer.data(), - s->resolution, - s->resolution, - &angle); - - if (status) - { - DBG (DBG_warn, "%s: failed : %d\n", __func__, status); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* apply rotation angle found */ - status = sanei_magic_turn (&s->params, s->dev->img_buffer.data(), angle); - if (status) - { - DBG (DBG_warn, "%s: failed : %d\n", __func__, status); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* update counters to new image size */ - s->dev->total_bytes_to_read = s->params.bytes_per_line * s->params.lines; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_conv_hlp.cc b/backend/genesys_conv_hlp.cc deleted file mode 100644 index 7663a87..0000000 --- a/backend/genesys_conv_hlp.cc +++ /dev/null @@ -1,345 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2005 Pierre Willenbrock - - 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. -*/ - -/* - * Conversion filters for genesys backend - */ - -static SANE_Status -FUNC_NAME(genesys_reorder_components_cis) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int pixels) -{ - unsigned int x, y; - uint8_t *src[3]; - uint8_t *dst = dst_data; - unsigned int rest = pixels * 2 * BYTES_PER_COMPONENT; - - src[0] = src_data + pixels * BYTES_PER_COMPONENT * 0; - src[1] = src_data + pixels * BYTES_PER_COMPONENT * 1; - src[2] = src_data + pixels * BYTES_PER_COMPONENT * 2; - - for(y = 0; y < lines; y++) { - for(x = 0; x < pixels; x++) { - -#ifndef DOUBLE_BYTE - *dst++ = *src[0]++; - *dst++ = *src[1]++; - *dst++ = *src[2]++; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = *src[0]++; - *dst++ = *src[0]++; - *dst++ = *src[1]++; - *dst++ = *src[1]++; - *dst++ = *src[2]++; - *dst++ = *src[2]++; -# else - *dst++ = src[0][1]; - *dst++ = src[0][0]; - *dst++ = src[1][1]; - *dst++ = src[1][0]; - *dst++ = src[2][1]; - *dst++ = src[2][0]; - src[0] += 2; - src[1] += 2; - src[2] += 2; -# endif -#endif - } - - src[0] += rest; - src[1] += rest; - src[2] += rest; - } - return SANE_STATUS_GOOD; -} - -static SANE_Status -FUNC_NAME(genesys_reorder_components_cis_bgr) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int pixels) -{ - unsigned int x, y; - uint8_t *src[3]; - uint8_t *dst = dst_data; - unsigned int rest = pixels * 2 * BYTES_PER_COMPONENT; - - src[0] = src_data + pixels * BYTES_PER_COMPONENT * 0; - src[1] = src_data + pixels * BYTES_PER_COMPONENT * 1; - src[2] = src_data + pixels * BYTES_PER_COMPONENT * 2; - - for(y = 0; y < lines; y++) { - for(x = 0; x < pixels; x++) { -#ifndef DOUBLE_BYTE - *dst++ = *src[2]++; - *dst++ = *src[1]++; - *dst++ = *src[0]++; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = *src[2]++; - *dst++ = *src[2]++; - *dst++ = *src[1]++; - *dst++ = *src[1]++; - *dst++ = *src[0]++; - *dst++ = *src[0]++; -# else - *dst++ = src[2][1]; - *dst++ = src[2][0]; - *dst++ = src[1][1]; - *dst++ = src[1][0]; - *dst++ = src[0][1]; - *dst++ = src[0][0]; - src[0] += 2; - src[1] += 2; - src[2] += 2; -# endif -#endif - } - - src[0] += rest; - src[1] += rest; - src[2] += rest; - } - return SANE_STATUS_GOOD; -} - -static SANE_Status -FUNC_NAME(genesys_reorder_components_bgr) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int pixels) -{ - unsigned int c; - uint8_t *src = src_data; - uint8_t *dst = dst_data; - - for(c = 0; c < lines * pixels; c++) { - -#ifndef DOUBLE_BYTE - *dst++ = src[2]; - *dst++ = src[1]; - *dst++ = src[0]; - src += 3; -#else -# ifndef WORDS_BIGENDIAN - *dst++ = src[2 * 2 + 0]; - *dst++ = src[2 * 2 + 1]; - *dst++ = src[1 * 2 + 0]; - *dst++ = src[1 * 2 + 1]; - *dst++ = src[0 * 2 + 0]; - *dst++ = src[0 * 2 + 1]; -# else - *dst++ = src[2 * 2 + 1]; - *dst++ = src[2 * 2 + 0]; - *dst++ = src[1 * 2 + 1]; - *dst++ = src[1 * 2 + 0]; - *dst++ = src[0 * 2 + 1]; - *dst++ = src[0 * 2 + 0]; -# endif - src += 3 * 2; -#endif - - } - return SANE_STATUS_GOOD; -} - -#if defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN) -static SANE_Status -FUNC_NAME(genesys_reorder_components_endian) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int pixels, - unsigned int channels) -{ - unsigned int c; - uint8_t *src = src_data; - uint8_t *dst = dst_data; - - for(c = 0; c < lines * pixels * channels; c++) { - *dst++ = src[1]; - *dst++ = src[0]; - src += 2; - } -return SANE_STATUS_GOOD; -} -#endif /*defined(DOUBLE_BYTE) && defined(WORDS_BIGENDIAN)*/ - - -static SANE_Status -FUNC_NAME(genesys_reverse_ccd) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int components_per_line, - unsigned int *ccd_shift, - unsigned int component_count) -{ - unsigned int x, y, c; - COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; - COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; - COMPONENT_TYPE *srcp; - COMPONENT_TYPE *dstp; - unsigned int pitch = components_per_line; - unsigned int ccd_shift_pitch[12]; - unsigned int *csp; - - for (c = 0; c < component_count; c++) - ccd_shift_pitch[c] = ccd_shift[c] * pitch; - -/* - * cache efficiency: - we are processing a single line component_count times, so it should fit - into the cpu cache for maximum efficiency. our lines take - maximum 252kb(3 channels, 16bit, 2400dpi, full gl841 shading range) - * instruction efficiency: - the innermost loop runs long and consists of 3 adds, one compare, - 2 derefences. - */ -/* - for (y = 0; y < lines; y++) { - csp = ccd_shift_pitch; - for (c = 0; c < component_count; c++) { - srcp = src + c + *csp++; - dstp = dst + c; - for (x = 0; x < pitch; x += component_count) { - *dstp = *srcp; - srcp += component_count; - dstp += component_count; - } - } - dst += pitch; - src += pitch; - } - */ -/* - * cache efficency: - here only line_dist_pitch needs to stay in cache. 12*4 = 48 bytes - * instruction efficiency: - we have a short running inner loop, consisting of 4 incs, 2 compare, 1 add, - 2 dereference and 1 indexed dereference. - the enclosing loop is long running, consisting of 1 add, 1 compare. - */ - srcp = src; - dstp = dst; - for (y = 0; y < lines; y++) { - for (x = 0; x < pitch; x += component_count) { - csp = ccd_shift_pitch; - for (c = 0; c < component_count && c + x < pitch; c++) { - *dstp = srcp[*csp++]; - dstp++; - srcp++; - } - } - } - return SANE_STATUS_GOOD; -} - -static SANE_Status -FUNC_NAME(genesys_shrink_lines) ( - uint8_t *src_data, - uint8_t *dst_data, - unsigned int lines, - unsigned int src_pixels, - unsigned int dst_pixels, - unsigned int channels) -{ - unsigned int dst_x, src_x, y, c, cnt; - unsigned int avg[3]; - unsigned int count; - COMPONENT_TYPE *src = (COMPONENT_TYPE *)src_data; - COMPONENT_TYPE *dst = (COMPONENT_TYPE *)dst_data; - - if (src_pixels > dst_pixels) { -/*average*/ - for (c = 0; c < channels; c++) - avg[c] = 0; - for(y = 0; y < lines; y++) { - cnt = src_pixels / 2; - src_x = 0; - for (dst_x = 0; dst_x < dst_pixels; dst_x++) { - count = 0; - while (cnt < src_pixels && src_x < src_pixels) { - cnt += dst_pixels; - - for (c = 0; c < channels; c++) - avg[c] += *src++; - src_x++; - count++; - } - cnt -= src_pixels; - - for (c = 0; c < channels; c++) { - *dst++ = avg[c] / count; - avg[c] = 0; - } - } - } - } else { -/*interpolate. copy pixels*/ - for(y = 0; y < lines; y++) { - cnt = dst_pixels / 2; - dst_x = 0; - for (src_x = 0; src_x < src_pixels; src_x++) { - for (c = 0; c < channels; c++) - avg[c] = *src++; - while ((cnt < dst_pixels || src_x + 1 == src_pixels) && - dst_x < dst_pixels) { - cnt += src_pixels; - - for (c = 0; c < channels; c++) - *dst++ = avg[c]; - dst_x++; - } - cnt -= dst_pixels; - } - } - } - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_devices.cc b/backend/genesys_devices.cc deleted file mode 100644 index b4ae5ca..0000000 --- a/backend/genesys_devices.cc +++ /dev/null @@ -1,5165 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003 Oliver Rauch - Copyright (C) 2003-2005 Henning Meier-Geinitz - Copyright (C) 2004, 2005 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2007 Luke - Copyright (C) 2010 Jack McGill - Copyright (C) 2010 Andrey Loginov , - xerox travelscan device entry - Copyright (C) 2010 Chris Berry and Michael Rickmann - for Plustek Opticbook 3600 support - - 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. -*/ - -/* ------------------------------------------------------------------------ */ -/* Some setup DAC and CCD tables */ -/* ------------------------------------------------------------------------ */ - -#include "genesys_low.h" - -StaticInit> s_frontends; - -void genesys_init_frontend_tables() -{ - s_frontends.init(); - - GenesysFrontendLayout wolfson_layout; - wolfson_layout.offset_addr = { 0x20, 0x21, 0x22 }; - wolfson_layout.gain_addr = { 0x28, 0x29, 0x2a }; - - Genesys_Frontend fe; - fe.fe_id = DAC_WOLFSON_UMAX; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x03 }, - { 0x02, 0x05 }, - { 0x03, 0x11 }, - { 0x20, 0x80 }, - { 0x21, 0x80 }, - { 0x22, 0x80 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x02 }, - { 0x29, 0x02 }, - { 0x2a, 0x02 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_WOLFSON_ST12; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x03 }, - { 0x02, 0x05 }, - { 0x03, 0x03 }, - { 0x20, 0xc8 }, - { 0x21, 0xc8 }, - { 0x22, 0xc8 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x04 }, - { 0x29, 0x04 }, - { 0x2a, 0x04 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_WOLFSON_ST24; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x03 }, - { 0x02, 0x05 }, - { 0x03, 0x21 }, - { 0x20, 0xc8 }, - { 0x21, 0xc8 }, - { 0x22, 0xc8 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x06 }, - { 0x29, 0x06 }, - { 0x2a, 0x06 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_WOLFSON_5345; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x03 }, - { 0x02, 0x05 }, - { 0x03, 0x12 }, - { 0x20, 0xb8 }, - { 0x21, 0xb8 }, - { 0x22, 0xb8 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x04 }, - { 0x29, 0x04 }, - { 0x2a, 0x04 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - // reg3=0x02 for 50-600 dpi, 0x32 (0x12 also works well) at 1200 - fe = Genesys_Frontend(); - fe.fe_id = DAC_WOLFSON_HP2400; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x03 }, - { 0x02, 0x05 }, - { 0x03, 0x02 }, - { 0x20, 0xb4 }, - { 0x21, 0xb6 }, - { 0x22, 0xbc }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x06 }, - { 0x29, 0x09 }, - { 0x2a, 0x08 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_WOLFSON_HP2300; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x03 }, - { 0x02, 0x04 }, - { 0x03, 0x02 }, - { 0x20, 0xbe }, - { 0x21, 0xbe }, - { 0x22, 0xbe }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x04 }, - { 0x29, 0x04 }, - { 0x2a, 0x04 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_CANONLIDE35; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x3d }, - { 0x02, 0x08 }, - { 0x03, 0x00 }, - { 0x20, 0xe1 }, - { 0x21, 0xe1 }, - { 0x22, 0xe1 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x93 }, - { 0x29, 0x93 }, - { 0x2a, 0x93 }, - }; - fe.reg2 = {0x00, 0x19, 0x06}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_AD_XP200; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x58 }, - { 0x01, 0x80 }, - { 0x02, 0x00 }, - { 0x03, 0x00 }, - { 0x20, 0x09 }, - { 0x21, 0x09 }, - { 0x22, 0x09 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x09 }, - { 0x29, 0x09 }, - { 0x2a, 0x09 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_WOLFSON_XP300; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x35 }, - { 0x02, 0x20 }, - { 0x03, 0x14 }, - { 0x20, 0xe1 }, - { 0x21, 0xe1 }, - { 0x22, 0xe1 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x93 }, - { 0x29, 0x93 }, - { 0x2a, 0x93 }, - }; - fe.reg2 = {0x07, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_WOLFSON_HP3670; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x03 }, - { 0x02, 0x05 }, - { 0x03, 0x32 }, - { 0x20, 0xba }, - { 0x21, 0xb8 }, - { 0x22, 0xb8 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x06 }, - { 0x29, 0x05 }, - { 0x2a, 0x04 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_WOLFSON_DSM600; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x35 }, - { 0x02, 0x20 }, - { 0x03, 0x14 }, - { 0x20, 0x85 }, - { 0x21, 0x85 }, - { 0x22, 0x85 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0xa0 }, - { 0x29, 0xa0 }, - { 0x2a, 0xa0 }, - }; - fe.reg2 = {0x07, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_CANONLIDE200; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x9d }, - { 0x01, 0x91 }, - { 0x02, 0x00 }, - { 0x03, 0x00 }, - { 0x20, 0x00 }, - { 0x21, 0x3f }, - { 0x22, 0x00 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x32 }, - { 0x29, 0x04 }, - { 0x2a, 0x00 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_CANONLIDE700; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x9d }, - { 0x01, 0x9e }, - { 0x02, 0x00 }, - { 0x03, 0x00 }, - { 0x20, 0x00 }, - { 0x21, 0x3f }, - { 0x22, 0x00 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x2f }, - { 0x29, 0x04 }, - { 0x2a, 0x00 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_KVSS080; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x23 }, - { 0x02, 0x24 }, - { 0x03, 0x0f }, - { 0x20, 0x80 }, - { 0x21, 0x80 }, - { 0x22, 0x80 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x4b }, - { 0x29, 0x4b }, - { 0x2a, 0x4b }, - }; - fe.reg2 = {0x00,0x00,0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_G4050; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x23 }, - { 0x02, 0x24 }, - { 0x03, 0x1f }, - { 0x20, 0x45 }, - { 0x21, 0x45 }, - { 0x22, 0x45 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x4b }, - { 0x29, 0x4b }, - { 0x2a, 0x4b }, - }; - fe.reg2 = {0x00,0x00,0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_CANONLIDE110; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x80 }, - { 0x01, 0x8a }, - { 0x02, 0x23 }, - { 0x03, 0x4c }, - { 0x20, 0x00 }, - { 0x21, 0x00 }, - { 0x22, 0x00 }, - { 0x24, 0x00 }, - { 0x25, 0xca }, - { 0x26, 0x94 }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - /** @brief GL124 special case - * for GL124 based scanners, this struct is "abused" - * in fact the fields are map like below to AFE registers - * (from Texas Instrument or alike ?) - */ - fe = Genesys_Frontend(); - fe.fe_id = DAC_CANONLIDE120; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x80 }, - { 0x01, 0xa3 }, - { 0x02, 0x2b }, - { 0x03, 0x4c }, - { 0x20, 0x00 }, - { 0x21, 0x00 }, - { 0x22, 0x00 }, - { 0x24, 0x00 }, // actual address 0x05 - { 0x25, 0xca }, // actual address 0x06 - { 0x26, 0x95 }, // actual address 0x07 - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_PLUSTEK_3600; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x70 }, - { 0x01, 0x80 }, - { 0x02, 0x00 }, - { 0x03, 0x00 }, - { 0x20, 0x00 }, - { 0x21, 0x00 }, - { 0x22, 0x00 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x3f }, - { 0x29, 0x3d }, - { 0x2a, 0x3d }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_CS8400F; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x23 }, - { 0x02, 0x24 }, - { 0x03, 0x0f }, - { 0x20, 0x60 }, - { 0x21, 0x5c }, - { 0x22, 0x6c }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x8a }, - { 0x29, 0x9f }, - { 0x2a, 0xc2 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_CS8600F; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x00 }, - { 0x01, 0x23 }, - { 0x02, 0x24 }, - { 0x03, 0x2f }, - { 0x20, 0x67 }, - { 0x21, 0x69 }, - { 0x22, 0x68 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0xdb }, - { 0x29, 0xda }, - { 0x2a, 0xd7 }, - }; - fe.reg2 = { 0x00, 0x00, 0x00 }; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_IMG101; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x78 }, - { 0x01, 0xf0 }, - { 0x02, 0x00 }, - { 0x03, 0x00 }, - { 0x20, 0x00 }, - { 0x21, 0x00 }, - { 0x22, 0x00 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - fe = Genesys_Frontend(); - fe.fe_id = DAC_PLUSTEK3800; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x78 }, - { 0x01, 0xf0 }, - { 0x02, 0x00 }, - { 0x03, 0x00 }, - { 0x20, 0x00 }, - { 0x21, 0x00 }, - { 0x22, 0x00 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); - - - /* reg0: control 74 data, 70 no data - * reg3: offset - * reg6: gain - * reg0 , reg3, reg6 */ - fe = Genesys_Frontend(); - fe.fe_id = DAC_CANONLIDE80; - fe.layout = wolfson_layout; - fe.regs = { - { 0x00, 0x70 }, - { 0x01, 0x16 }, - { 0x02, 0x60 }, - { 0x03, 0x00 }, - { 0x20, 0x00 }, - { 0x21, 0x00 }, - { 0x22, 0x00 }, - { 0x24, 0x00 }, - { 0x25, 0x00 }, - { 0x26, 0x00 }, - { 0x28, 0x00 }, - { 0x29, 0x00 }, - { 0x2a, 0x00 }, - }; - fe.reg2 = {0x00, 0x00, 0x00}; - s_frontends->push_back(fe); -} - - -/** for setting up the sensor-specific settings: - * Optical Resolution, number of black pixels, number of dummy pixels, - * CCD_start_xoffset, and overall number of sensor pixels - * registers 0x08-0x0b, 0x10-0x1d and 0x52-0x5e - */ -StaticInit> s_sensors; - -void genesys_init_sensor_tables() -{ - s_sensors.init(); - - Genesys_Sensor sensor; - sensor.sensor_id = CCD_UMAX; - sensor.optical_res = 1200; - sensor.black_pixels = 48; - sensor.dummy_pixel = 64; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10800; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 230; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x01 }, - { 0x09, 0x03 }, - { 0x0a, 0x05 }, - { 0x0b, 0x07 }, - { 0x16, 0x33 }, - { 0x17, 0x05 }, - { 0x18, 0x31 }, - { 0x19, 0x2a }, - { 0x1a, 0x00 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x02 }, - { 0x52, 0x13 }, - { 0x53, 0x17 }, - { 0x54, 0x03 }, - { 0x55, 0x07 }, - { 0x56, 0x0b }, - { 0x57, 0x0f }, - { 0x58, 0x23 }, - { 0x59, 0x00 }, - { 0x5a, 0xc1 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_ST12; - sensor.optical_res = 600; - sensor.black_pixels = 48; - sensor.dummy_pixel = 85; - sensor.CCD_start_xoffset = 152; - sensor.sensor_pixels = 5416; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 230; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x02 }, - { 0x09, 0x00 }, - { 0x0a, 0x06 }, - { 0x0b, 0x04 }, - { 0x16, 0x2b }, - { 0x17, 0x08 }, - { 0x18, 0x20 }, - { 0x19, 0x2a }, - { 0x1a, 0x00 }, - { 0x1b, 0x00 }, - { 0x1c, 0x0c }, - { 0x1d, 0x03 }, - { 0x52, 0x0f }, - { 0x53, 0x13 }, - { 0x54, 0x17 }, - { 0x55, 0x03 }, - { 0x56, 0x07 }, - { 0x57, 0x0b }, - { 0x58, 0x83 }, - { 0x59, 0x00 }, - { 0x5a, 0xc1 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_ST24; - sensor.optical_res = 1200; - sensor.black_pixels = 48; - sensor.dummy_pixel = 64; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10800; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 230; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x0e }, - { 0x09, 0x0c }, - { 0x0a, 0x00 }, - { 0x0b, 0x0c }, - { 0x16, 0x33 }, - { 0x17, 0x08 }, - { 0x18, 0x31 }, - { 0x19, 0x2a }, - { 0x1a, 0x00 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x02 }, - { 0x52, 0x17 }, - { 0x53, 0x03 }, - { 0x54, 0x07 }, - { 0x55, 0x0b }, - { 0x56, 0x0f }, - { 0x57, 0x13 }, - { 0x58, 0x03 }, - { 0x59, 0x00 }, - { 0x5a, 0xc1 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_5345; - sensor.optical_res = 1200; - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 48; - sensor.dummy_pixel = 16; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10872; - sensor.fau_gain_white_ref = 190; - sensor.gain_white_ref = 190; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x0d }, - { 0x09, 0x0f }, - { 0x0a, 0x11 }, - { 0x0b, 0x13 }, - { 0x16, 0x0b }, - { 0x17, 0x0a }, - { 0x18, 0x30 }, - { 0x19, 0x2a }, - { 0x1a, 0x00 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x03 }, - { 0x52, 0x0f }, - { 0x53, 0x13 }, - { 0x54, 0x17 }, - { 0x55, 0x03 }, - { 0x56, 0x07 }, - { 0x57, 0x0b }, - { 0x58, 0x23 }, - { 0x59, 0x00 }, - { 0x5a, 0xc1 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {2.38, 2.35, 2.34}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_HP2400; - sensor.optical_res = 1200, - sensor.black_pixels = 48; - sensor.dummy_pixel = 15; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10872; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x14 }, - { 0x09, 0x15 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0xbf }, - { 0x17, 0x08 }, - { 0x18, 0x3f }, - { 0x19, 0x2a }, - { 0x1a, 0x00 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x02 }, - { 0x52, 0x0b }, - { 0x53, 0x0f }, - { 0x54, 0x13 }, - { 0x55, 0x17 }, - { 0x56, 0x03 }, - { 0x57, 0x07 }, - { 0x58, 0x63 }, - { 0x59, 0x00 }, - { 0x5a, 0xc1 }, - { 0x5b, 0x00 }, - { 0x5c, 0x0e }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {2.1, 2.1, 2.1}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_HP2300; - sensor.optical_res = 600; - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 48; - sensor.dummy_pixel = 20; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 5368; - sensor.fau_gain_white_ref = 180; - sensor.gain_white_ref = 180; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x16 }, - { 0x09, 0x00 }, - { 0x0a, 0x01 }, - { 0x0b, 0x03 }, - { 0x16, 0xb7 }, - { 0x17, 0x0a }, - { 0x18, 0x20 }, - { 0x19, 0x2a }, - { 0x1a, 0x6a }, - { 0x1b, 0x8a }, - { 0x1c, 0x00 }, - { 0x1d, 0x05 }, - { 0x52, 0x0f }, - { 0x53, 0x13 }, - { 0x54, 0x17 }, - { 0x55, 0x03 }, - { 0x56, 0x07 }, - { 0x57, 0x0b }, - { 0x58, 0x83 }, - { 0x59, 0x00 }, - { 0x5a, 0xc1 }, - { 0x5b, 0x06 }, - { 0x5c, 0x0b }, - { 0x5d, 0x10 }, - { 0x5e, 0x16 }, - }; - sensor.gamma = {2.1, 2.1, 2.1}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_CANONLIDE35; - sensor.optical_res = 1200; - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 87; - sensor.dummy_pixel = 87; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10400; - sensor.fau_gain_white_ref = 0; - sensor.gain_white_ref = 0; - sensor.exposure = { 0x0400, 0x0400, 0x0400 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x00 }, - { 0x17, 0x02 }, - { 0x18, 0x00 }, - { 0x19, 0x50 }, - { 0x1a, 0x00 }, // TODO: 1a-1d: these do no harm, but may be neccessery for CCD - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x02 }, - { 0x52, 0x05 }, // [GB](HI|LOW) not needed for cis - { 0x53, 0x07 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x3a }, - { 0x59, 0x03 }, - { 0x5a, 0x40 }, - { 0x5b, 0x00 }, // TODO: 5b-5e - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_XP200; - sensor.optical_res = 600; - sensor.black_pixels = 5; - sensor.dummy_pixel = 38; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 5200; - sensor.fau_gain_white_ref = 200; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x1450, 0x0c80, 0x0a28 }; - sensor.custom_regs = { - { 0x08, 0x16 }, - { 0x09, 0x00 }, - { 0x0a, 0x01 }, - { 0x0b, 0x03 }, - { 0x16, 0xb7 }, - { 0x17, 0x0a }, - { 0x18, 0x20 }, - { 0x19, 0x2a }, - { 0x1a, 0x6a }, - { 0x1b, 0x8a }, - { 0x1c, 0x00 }, - { 0x1d, 0x05 }, - { 0x52, 0x0f }, - { 0x53, 0x13 }, - { 0x54, 0x17 }, - { 0x55, 0x03 }, - { 0x56, 0x07 }, - { 0x57, 0x0b }, - { 0x58, 0x83 }, - { 0x59, 0x00 }, - { 0x5a, 0xc1 }, - { 0x5b, 0x06 }, - { 0x5c, 0x0b }, - { 0x5d, 0x10 }, - { 0x5e, 0x16 }, - }; - sensor.gamma = {2.1, 2.1, 2.1}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_HP3670; - sensor.optical_res = 1200; - sensor.black_pixels = 48; - sensor.dummy_pixel = 16; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10872; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x0a }, - { 0x0a, 0x0b }, - { 0x0b, 0x0d }, - { 0x16, 0x33 }, - { 0x17, 0x07 }, - { 0x18, 0x20 }, - { 0x19, 0x2a }, - { 0x1a, 0x00 }, - { 0x1b, 0x00 }, - { 0x1c, 0xc0 }, - { 0x1d, 0x43 }, - { 0x52, 0x0f }, - { 0x53, 0x13 }, - { 0x54, 0x17 }, - { 0x55, 0x03 }, - { 0x56, 0x07 }, - { 0x57, 0x0b }, - { 0x58, 0x83 }, - { 0x59, 0x00 }, - { 0x5a, 0x15 }, - { 0x5b, 0x05 }, - { 0x5c, 0x0a }, - { 0x5d, 0x0f }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_DP665; - sensor.optical_res = 600; - sensor.black_pixels = 27; - sensor.dummy_pixel = 27; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 2496; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x1100, 0x1100, 0x1100 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x00 }, - { 0x17, 0x02 }, - { 0x18, 0x04 }, - { 0x19, 0x50 }, - { 0x1a, 0x10 }, - { 0x1b, 0x00 }, - { 0x1c, 0x20 }, - { 0x1d, 0x02 }, - { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis - { 0x53, 0x05 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x54 }, - { 0x59, 0x03 }, - { 0x5a, 0x00 }, - { 0x5b, 0x00 }, // TODO: 5b-5e - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x01 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_ROADWARRIOR; - sensor.optical_res = 600; - sensor.black_pixels = 27; - sensor.dummy_pixel = 27; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 5200; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x1100, 0x1100, 0x1100 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x00 }, - { 0x17, 0x02 }, - { 0x18, 0x04 }, - { 0x19, 0x50 }, - { 0x1a, 0x10 }, - { 0x1b, 0x00 }, - { 0x1c, 0x20 }, - { 0x1d, 0x02 }, - { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis - { 0x53, 0x05 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x54 }, - { 0x59, 0x03 }, - { 0x5a, 0x00 }, - { 0x5b, 0x00 }, // TODO: 5b-5e - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x01 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_DSMOBILE600; - sensor.optical_res = 600; - sensor.black_pixels = 28; - sensor.dummy_pixel = 28; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 5200; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x1544, 0x1544, 0x1544 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x00 }, - { 0x17, 0x02 }, - { 0x18, 0x04 }, - { 0x19, 0x50 }, - { 0x1a, 0x10 }, - { 0x1b, 0x00 }, - { 0x1c, 0x20 }, - { 0x1d, 0x02 }, - { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis - { 0x53, 0x05 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x54 }, - { 0x59, 0x03 }, - { 0x5a, 0x00 }, - { 0x5b, 0x00 }, // TODO: 5b-5e - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x01 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_XP300; - sensor.optical_res = 600; - sensor.black_pixels = 27; - sensor.dummy_pixel = 27; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10240; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x1100, 0x1100, 0x1100 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x00 }, - { 0x17, 0x02 }, - { 0x18, 0x04 }, - { 0x19, 0x50 }, - { 0x1a, 0x10 }, - { 0x1b, 0x00 }, - { 0x1c, 0x20 }, - { 0x1d, 0x02 }, - { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis - { 0x53, 0x05 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x54 }, - { 0x59, 0x03 }, - { 0x5a, 0x00 }, - { 0x5b, 0x00 }, // TODO: 5b-5e - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x01 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_DP685; - sensor.optical_res = 600; - sensor.black_pixels = 27; - sensor.dummy_pixel = 27; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 5020; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x1100, 0x1100, 0x1100 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x00 }, - { 0x17, 0x02 }, - { 0x18, 0x04 }, - { 0x19, 0x50 }, - { 0x1a, 0x10 }, - { 0x1b, 0x00 }, - { 0x1c, 0x20 }, - { 0x1d, 0x02 }, - { 0x52, 0x04 }, // [GB](HI|LOW) not needed for cis - { 0x53, 0x05 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x54 }, - { 0x59, 0x03 }, - { 0x5a, 0x00 }, - { 0x5b, 0x00 }, // TODO: 5b-5e - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x01 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_CANONLIDE200; - sensor.optical_res = 4800; - sensor.black_pixels = 87*4; - sensor.dummy_pixel = 16*4; - sensor.CCD_start_xoffset = 320*8; - sensor.sensor_pixels = 5136*8; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x10 }, - { 0x17, 0x08 }, - { 0x18, 0x00 }, - { 0x19, 0xff }, - { 0x1a, 0x34 }, - { 0x1b, 0x00 }, - { 0x1c, 0x02 }, - { 0x1d, 0x04 }, - { 0x52, 0x03 }, - { 0x53, 0x07 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x2a }, - { 0x59, 0xe1 }, - { 0x5a, 0x55 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x41 }, - }; - sensor.gamma = {1.7, 1.7, 1.7}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_CANONLIDE700; - sensor.optical_res = 4800; - sensor.black_pixels = 73*8; // black pixels 73 at 600 dpi - sensor.dummy_pixel = 16*8; - // 384 at 600 dpi - sensor.CCD_start_xoffset = 384*8; - // 8x5570 segments, 5187+1 for rounding - sensor.sensor_pixels = 5188*8; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x10 }, - { 0x17, 0x08 }, - { 0x18, 0x00 }, - { 0x19, 0xff }, - { 0x1a, 0x34 }, - { 0x1b, 0x00 }, - { 0x1c, 0x02 }, - { 0x1d, 0x04 }, - { 0x52, 0x07 }, - { 0x53, 0x03 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x2a }, - { 0x59, 0xe1 }, - { 0x5a, 0x55 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x41 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_CANONLIDE100; - sensor.optical_res = 2400; - sensor.black_pixels = 87*4, /* black pixels */ - sensor.dummy_pixel = 16*4; - sensor.CCD_start_xoffset = 320*4; - sensor.sensor_pixels = 5136*4; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x01c1, 0x0126, 0x00e5 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x10 }, - { 0x17, 0x08 }, - { 0x18, 0x00 }, - { 0x19, 0x50 }, - { 0x1a, 0x34 }, - { 0x1b, 0x00 }, - { 0x1c, 0x02 }, - { 0x1d, 0x04 }, - { 0x52, 0x03 }, - { 0x53, 0x07 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x2a }, - { 0x59, 0xe1 }, - { 0x5a, 0x55 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x41 }, - }; - sensor.gamma = {1.7, 1.7, 1.7}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_KVSS080; - sensor.optical_res = 600; - sensor.black_pixels = 38; - sensor.dummy_pixel = 38; - sensor.CCD_start_xoffset = 152; - sensor.sensor_pixels = 5376; - sensor.fau_gain_white_ref = 160; - sensor.gain_white_ref = 160; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.exposure_lperiod = 8000; - sensor.custom_regs = { - { 0x74, 0x00 }, { 0x75, 0x00 }, { 0x76, 0x00 }, - { 0x77, 0x00 }, { 0x78, 0xff }, { 0x79, 0xff }, - { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, - { 0x0c, 0x00 }, - { 0x70, 0x01 }, - { 0x71, 0x03 }, - { 0x9e, 0x00 }, - { 0xaa, 0x00 }, - { 0x16, 0x33 }, - { 0x17, 0x1c }, - { 0x18, 0x00 }, - { 0x19, 0x2a }, - { 0x1a, 0x2c }, - { 0x1b, 0x00 }, - { 0x1c, 0x20 }, - { 0x1d, 0x04 }, - { 0x52, 0x0c }, - { 0x53, 0x0f }, - { 0x54, 0x00 }, - { 0x55, 0x03 }, - { 0x56, 0x06 }, - { 0x57, 0x09 }, - { 0x58, 0x6b }, - { 0x59, 0x00 }, - { 0x5a, 0xc0 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_G4050; - sensor.optical_res = 4800; - sensor.black_pixels = 50*8; - // 31 at 600 dpi dummy_pixels 58 at 1200 - sensor.dummy_pixel = 58; - sensor.CCD_start_xoffset = 152; - sensor.sensor_pixels = 5360*8; - sensor.fau_gain_white_ref = 160; - sensor.gain_white_ref = 160; - sensor.exposure = { 0x2c09, 0x22b8, 0x10f0 }; - sensor.custom_regs = {}; - sensor.gamma = {1.0, 1.0, 1.0}; - - { - struct CustomSensorSettings { - int min_resolution; - int max_resolution; - int exposure_lperiod; - ScanMethod method; - GenesysRegisterSettingSet extra_custom_regs; - }; - - CustomSensorSettings custom_settings[] = { - { -1, 600, 8016, ScanMethod::FLATBED, { - { 0x74, 0x00 }, { 0x75, 0x01 }, { 0x76, 0xff }, - { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, - { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, - { 0x0c, 0x00 }, - { 0x70, 0x00 }, - { 0x71, 0x02 }, - { 0x9e, 0x00 }, - { 0xaa, 0x00 }, - { 0x16, 0x33 }, - { 0x17, 0x0c }, - { 0x18, 0x00 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x08 }, - { 0x52, 0x0b }, - { 0x53, 0x0e }, - { 0x54, 0x11 }, - { 0x55, 0x02 }, - { 0x56, 0x05 }, - { 0x57, 0x08 }, - { 0x58, 0x63 }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - } - }, - { 1200, 1200, 56064, ScanMethod::FLATBED, { - { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, - { 0x77, 0x00 }, { 0x78, 0x01 }, { 0x79, 0xff }, - { 0x7a, 0x00 }, { 0x7b, 0x01 }, { 0x7c, 0xff }, - { 0x0c, 0x20 }, - { 0x70, 0x08 }, - { 0x71, 0x0c }, - { 0x9e, 0xc0 }, - { 0xaa, 0x05 }, - { 0x16, 0x3b }, - { 0x17, 0x0c }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x38 }, - { 0x1b, 0x10 }, - { 0x1c, 0x00 }, - { 0x1d, 0x08 }, - { 0x52, 0x02 }, - { 0x53, 0x05 }, - { 0x54, 0x08 }, - { 0x55, 0x0b }, - { 0x56, 0x0e }, - { 0x57, 0x11 }, - { 0x58, 0x1b }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - } - }, - { 2400, 2400, 56064, ScanMethod::FLATBED, { - { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, - { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, - { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, - { 0x0c, 0x20 }, - { 0x70, 0x08 }, - { 0x71, 0x0a }, - { 0x9e, 0xc0 }, - { 0xaa, 0x05 }, - { 0x16, 0x3b }, - { 0x17, 0x0c }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x38 }, - { 0x1b, 0x10 }, - { 0x1c, 0xc0 }, - { 0x1d, 0x08 }, - { 0x52, 0x02 }, - { 0x53, 0x05 }, - { 0x54, 0x08 }, - { 0x55, 0x0b }, - { 0x56, 0x0e }, - { 0x57, 0x11 }, - { 0x58, 0x1b }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - } - }, - { 4800, 4800, 42752, ScanMethod::FLATBED, { - { 0x74, 0x0f }, { 0x75, 0xff }, { 0x76, 0xff }, - { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, - { 0x7a, 0x00 }, { 0x7b, 0x00 }, { 0x7c, 0x00 }, - { 0x0c, 0x21 }, - { 0x70, 0x08 }, - { 0x71, 0x0a }, - { 0x9e, 0xc0 }, - { 0xaa, 0x07 }, - { 0x16, 0x3b }, - { 0x17, 0x0c }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x38 }, - { 0x1b, 0x10 }, - { 0x1c, 0xc1 }, - { 0x1d, 0x08 }, - { 0x52, 0x02 }, - { 0x53, 0x05 }, - { 0x54, 0x08 }, - { 0x55, 0x0b }, - { 0x56, 0x0e }, - { 0x57, 0x11 }, - { 0x58, 0x1b }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - } - }, - { -1, -1, 15624, ScanMethod::TRANSPARENCY, { - { 0x74, 0x00 }, { 0x75, 0x1c }, { 0x76, 0x7f }, - { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, - { 0x7a, 0x03 }, { 0x7b, 0xff }, { 0x7c, 0xff }, - { 0x0c, 0x00 }, - { 0x70, 0x00 }, - { 0x71, 0x02 }, - { 0x9e, 0x00 }, - { 0xaa, 0x00 }, - { 0x16, 0x33 }, - { 0x17, 0x4c }, - { 0x18, 0x01 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x08 }, - { 0x52, 0x0e }, - { 0x53, 0x11 }, - { 0x54, 0x02 }, - { 0x55, 0x05 }, - { 0x56, 0x08 }, - { 0x57, 0x0b }, - { 0x58, 0x6b }, - { 0x59, 0x00 }, - { 0x5a, 0xc0 }, - } - } - }; - - auto base_custom_regs = sensor.custom_regs; - for (const CustomSensorSettings& setting : custom_settings) - { - sensor.min_resolution = setting.min_resolution; - sensor.max_resolution = setting.max_resolution; - sensor.exposure_lperiod = setting.exposure_lperiod; - sensor.method = setting.method; - sensor.custom_regs = base_custom_regs; - sensor.custom_regs.merge(setting.extra_custom_regs); - s_sensors->push_back(sensor); - } - } - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_CS4400F; - sensor.optical_res = 4800; - sensor.ccd_size_divisor = 4; - sensor.black_pixels = 50*8; - // 31 at 600 dpi, 58 at 1200 dpi - sensor.dummy_pixel = 20; - sensor.CCD_start_xoffset = 152; - // 5360 max at 600 dpi - sensor.sensor_pixels = 5360*8; - sensor.fau_gain_white_ref = 160; - sensor.gain_white_ref = 160; - sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; - sensor.exposure_lperiod = 11640; - sensor.custom_regs = { - { 0x74, 0x00 }, { 0x75, 0xf8 }, { 0x76, 0x38 }, - { 0x77, 0x00 }, { 0x78, 0xfc }, { 0x79, 0x00 }, - { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0xa4 }, - { 0x0c, 0x00 }, - { 0x70, 0x00 }, - { 0x71, 0x02 }, - { 0x9e, 0x2d }, - { 0xaa, 0x00 }, - { 0x16, 0x13 }, - { 0x17, 0x0a }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x6b }, - { 0x52, 0x0a }, - { 0x53, 0x0d }, - { 0x54, 0x00 }, - { 0x55, 0x03 }, - { 0x56, 0x06 }, - { 0x57, 0x08 }, - { 0x58, 0x5b }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_CS8400F; - sensor.optical_res = 4800; - sensor.black_pixels = 50*8; - // 31 at 600 dpi, 58 at 1200 dpi - sensor.dummy_pixel = 20; - sensor.CCD_start_xoffset = 152; - // 5360 max at 600 dpi - sensor.sensor_pixels = 5360*8; - sensor.fau_gain_white_ref = 160; - sensor.gain_white_ref = 160; - sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; - sensor.exposure_lperiod = 7200; - sensor.custom_regs = { - { 0x74, 0x00 }, { 0x75, 0x0e }, { 0x76, 0x3f }, - { 0x77, 0x00 }, { 0x78, 0x00 }, { 0x79, 0x00 }, - { 0x7a, 0x01 }, { 0x7b, 0xb6 }, { 0x7c, 0xdb }, - { 0x0c, 0x00 }, - { 0x70, 0x01 }, - { 0x71, 0x02 }, - { 0x9e, 0x00 }, - { 0xaa, 0x00 }, - { 0x16, 0x33 }, - { 0x17, 0x0c }, - { 0x18, 0x13 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x84 }, - { 0x52, 0x0d }, - { 0x53, 0x10 }, - { 0x54, 0x01 }, - { 0x55, 0x04 }, - { 0x56, 0x07 }, - { 0x57, 0x0a }, - { 0x58, 0x6b }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_CS8600F; - sensor.optical_res = 4800; - sensor.ccd_size_divisor = 4; - sensor.black_pixels = 31; - sensor.dummy_pixel = 20; - sensor.CCD_start_xoffset = 0; // not used at the moment - // 11372 pixels at 1200 dpi - sensor.sensor_pixels = 11372*4; - sensor.fau_gain_white_ref = 160; - sensor.gain_white_ref = 160; - sensor.exposure = { 0x9c40, 0x9c40, 0x9c40 }; - sensor.custom_regs = {}; - sensor.gamma = {1.0, 1.0, 1.0}; - - { - struct CustomSensorSettings { - int min_resolution; - int max_resolution; - int exposure_lperiod; - ScanMethod method; - GenesysRegisterSettingSet extra_custom_regs; - GenesysRegisterSettingSet custom_fe_regs; - }; - - CustomSensorSettings custom_settings[] = { - { -1, 1200, 24000, ScanMethod::FLATBED, { - { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 }, - { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, - { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, - { 0x0c, 0x00 }, - { 0x70, 0x00 }, - { 0x71, 0x02 }, - { 0x9e, 0x2d }, - { 0xaa, 0x00 }, - { 0x16, 0x13 }, - { 0x17, 0x0a }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x6b }, - { 0x52, 0x0c }, - { 0x53, 0x0f }, - { 0x54, 0x00 }, - { 0x55, 0x03 }, - { 0x56, 0x06 }, - { 0x57, 0x09 }, - { 0x58, 0x6b }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - }, - {}, - }, - { -1, 1200, 24000, ScanMethod::TRANSPARENCY, { - { 0x74, 0x03 }, { 0x75, 0xf0 }, { 0x76, 0xf0 }, - { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, - { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, - { 0x0c, 0x00 }, - { 0x70, 0x00 }, - { 0x71, 0x02 }, - { 0x9e, 0x2d }, - { 0xaa, 0x00 }, - { 0x16, 0x13 }, - { 0x17, 0x0a }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x6b }, - { 0x52, 0x0c }, - { 0x53, 0x0f }, - { 0x54, 0x00 }, - { 0x55, 0x03 }, - { 0x56, 0x06 }, - { 0x57, 0x09 }, - { 0x58, 0x6b }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - }, - {}, - }, - { 2400, 2400, 24000, ScanMethod::TRANSPARENCY, { - { 0x74, 0x03 }, { 0x75, 0xfe }, { 0x76, 0x00 }, - { 0x77, 0x03 }, { 0x78, 0xfe }, { 0x79, 0x00 }, - { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, - { 0x0c, 0x00 }, - { 0x70, 0x00 }, - { 0x71, 0x02 }, - { 0x9e, 0x2d }, - { 0xaa, 0x00 }, - { 0x16, 0x13 }, - { 0x17, 0x15 }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x01 }, - { 0x1d, 0x75 }, - { 0x52, 0x0c }, - { 0x53, 0x0f }, - { 0x54, 0x00 }, - { 0x55, 0x03 }, - { 0x56, 0x06 }, - { 0x57, 0x09 }, - { 0x58, 0x6b }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - }, - {}, - }, - { 4800, 4800, 24000, ScanMethod::TRANSPARENCY, { - { 0x74, 0x03 }, { 0x75, 0xff }, { 0x76, 0xff }, - { 0x77, 0x03 }, { 0x78, 0xff }, { 0x79, 0xff }, - { 0x7a, 0x00 }, { 0x7b, 0x92 }, { 0x7c, 0x49 }, - { 0x0c, 0x00 }, - { 0x70, 0x0a }, - { 0x71, 0x0c }, - { 0x72, 0x0c }, - { 0x73, 0x0e }, - { 0x9e, 0x2d }, - { 0xaa, 0x00 }, - { 0x16, 0x13 }, - { 0x17, 0x15 }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x61 }, - { 0x1d, 0x75 }, - { 0x52, 0x03 }, - { 0x53, 0x06 }, - { 0x54, 0x09 }, - { 0x55, 0x0c }, - { 0x56, 0x0f }, - { 0x57, 0x00 }, - { 0x58, 0x23 }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - }, - { { 0x03, 0x1f }, - }, - }, - }; - - auto base_custom_regs = sensor.custom_regs; - for (const CustomSensorSettings& setting : custom_settings) - { - sensor.min_resolution = setting.min_resolution; - sensor.max_resolution = setting.max_resolution; - sensor.method = setting.method; - sensor.exposure_lperiod = setting.exposure_lperiod; - sensor.custom_regs = base_custom_regs; - sensor.custom_regs.merge(setting.extra_custom_regs); - sensor.custom_fe_regs = setting.custom_fe_regs; - s_sensors->push_back(sensor); - } - } - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_HP_N6310; - sensor.optical_res = 2400; - // sensor.ccd_size_divisor = 2; Possibly half CCD, needs checking - sensor.black_pixels = 96; - sensor.dummy_pixel = 26; - sensor.CCD_start_xoffset = 128; - sensor.sensor_pixels = 42720; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 230; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x10 }, - { 0x0a, 0x10 }, - { 0x0b, 0x0c }, - { 0x16, 0x33 }, - { 0x17, 0x0c }, - { 0x18, 0x02 }, - { 0x19, 0x2a }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x08 }, - { 0x52, 0x0b }, - { 0x53, 0x0e }, - { 0x54, 0x11 }, - { 0x55, 0x02 }, - { 0x56, 0x05 }, - { 0x57, 0x08 }, - { 0x58, 0x63 }, - { 0x59, 0x00 }, - { 0x5a, 0x40 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x06 }, - { 0x5e, 0x6f }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_CANONLIDE110; - sensor.optical_res = 2400; - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 87; - sensor.dummy_pixel = 16; - sensor.CCD_start_xoffset = 303; - sensor.sensor_pixels = 5168*4; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x10 }, - { 0x17, 0x04 }, - { 0x18, 0x00 }, - { 0x19, 0x01 }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x02 }, - { 0x1d, 0x01 }, - { 0x52, 0x00 }, - { 0x53, 0x02 }, - { 0x54, 0x04 }, - { 0x55, 0x06 }, - { 0x56, 0x04 }, - { 0x57, 0x04 }, - { 0x58, 0x04 }, - { 0x59, 0x04 }, - { 0x5a, 0x1a }, - { 0x5b, 0x00 }, - { 0x5c, 0xc0 }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {2.1, 2.1, 2.1}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_CANONLIDE120; - sensor.optical_res = 2400; - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 87; - sensor.dummy_pixel = 16; - sensor.CCD_start_xoffset = 303; - // SEGCNT at 600 DPI by number of segments - sensor.sensor_pixels = 5104*4; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x15 }, - { 0x17, 0x04 }, - { 0x18, 0x00 }, - { 0x19, 0x01 }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x02 }, - { 0x1d, 0x01 }, - { 0x52, 0x04 }, - { 0x53, 0x06 }, - { 0x54, 0x00 }, - { 0x55, 0x02 }, - { 0x56, 0x04 }, - { 0x57, 0x04 }, - { 0x58, 0x04 }, - { 0x59, 0x04 }, - { 0x5a, 0x3a }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x1f }, - }; - sensor.gamma = {2.1, 2.1, 2.1}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_CANONLIDE210; - sensor.optical_res = 2400; - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 87; - sensor.dummy_pixel = 16; - sensor.CCD_start_xoffset = 303; - sensor.sensor_pixels = 5168*4; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x10 }, - { 0x17, 0x04 }, - { 0x18, 0x00 }, - { 0x19, 0x01 }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x02 }, - { 0x1d, 0x01 }, - { 0x52, 0x00 }, - { 0x53, 0x02 }, - { 0x54, 0x04 }, - { 0x55, 0x06 }, - { 0x56, 0x04 }, - { 0x57, 0x04 }, - { 0x58, 0x04 }, - { 0x59, 0x04 }, - { 0x5a, 0x1a }, - { 0x5b, 0x00 }, - { 0x5c, 0xc0 }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {2.1, 2.1, 2.1}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_CANONLIDE220; - sensor.optical_res = 2400; - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 87; - sensor.dummy_pixel = 16; - sensor.CCD_start_xoffset = 303; - sensor.sensor_pixels = 5168*4; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x10 }, - { 0x17, 0x04 }, - { 0x18, 0x00 }, - { 0x19, 0x01 }, - { 0x1a, 0x30 }, - { 0x1b, 0x00 }, - { 0x1c, 0x02 }, - { 0x1d, 0x01 }, - { 0x52, 0x00 }, - { 0x53, 0x02 }, - { 0x54, 0x04 }, - { 0x55, 0x06 }, - { 0x56, 0x04 }, - { 0x57, 0x04 }, - { 0x58, 0x04 }, - { 0x59, 0x04 }, - { 0x5a, 0x1a }, - { 0x5b, 0x00 }, - { 0x5c, 0xc0 }, - { 0x5d, 0x00 }, - { 0x5e, 0x00 }, - }; - sensor.gamma = {2.1, 2.1, 2.1}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_PLUSTEK_3600; - sensor.optical_res = 1200; - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 87; - sensor.dummy_pixel = 87; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10100; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 230; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x00 }, - { 0x16, 0x33 }, - { 0x17, 0x0b }, - { 0x18, 0x11 }, - { 0x19, 0x2a }, - { 0x1a, 0x00 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0xc4 }, - { 0x52, 0x07 }, // [GB](HI|LOW) not needed for cis - { 0x53, 0x0a }, - { 0x54, 0x0c }, - { 0x55, 0x00 }, - { 0x56, 0x02 }, - { 0x57, 0x06 }, - { 0x58, 0x22 }, - { 0x59, 0x69 }, - { 0x5a, 0x40 }, - { 0x5b, 0x00 }, // TODO: 5b-5e - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x02 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_IMG101; - sensor.optical_res = 1200; - sensor.black_pixels = 31; - sensor.dummy_pixel = 31; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10800; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x60 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x8b }, - { 0x16, 0xbb }, - { 0x17, 0x13 }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x34 }, - { 0x1b, 0x00 }, - { 0x1c, 0x20 }, - { 0x1d, 0x06 }, - { 0x52, 0x02 }, - { 0x53, 0x04 }, - { 0x54, 0x06 }, - { 0x55, 0x08 }, - { 0x56, 0x0a }, - { 0x57, 0x00 }, - { 0x58, 0x59 }, - { 0x59, 0x31 }, - { 0x5a, 0x40 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x1f }, - }; - sensor.gamma = {1.7, 1.7, 1.7}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CCD_PLUSTEK3800; - sensor.optical_res = 1200; - sensor.black_pixels = 31; - sensor.dummy_pixel = 31; - sensor.CCD_start_xoffset = 0; - sensor.sensor_pixels = 10200; - sensor.fau_gain_white_ref = 210; - sensor.gain_white_ref = 200; - sensor.exposure = { 0x0000, 0x0000, 0x0000 }; - sensor.custom_regs = { - { 0x08, 0x60 }, - { 0x09, 0x00 }, - { 0x0a, 0x00 }, - { 0x0b, 0x8b }, - { 0x16, 0xbb }, - { 0x17, 0x13 }, - { 0x18, 0x10 }, - { 0x19, 0x2a }, - { 0x1a, 0x34 }, - { 0x1b, 0x00 }, - { 0x1c, 0x20 }, - { 0x1d, 0x06 }, - { 0x52, 0x02 }, - { 0x53, 0x04 }, - { 0x54, 0x06 }, - { 0x55, 0x08 }, - { 0x56, 0x0a }, - { 0x57, 0x00 }, - { 0x58, 0x59 }, - { 0x59, 0x31 }, - { 0x5a, 0x40 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x00 }, - { 0x5e, 0x1f }, - }; - sensor.gamma = {1.7, 1.7, 1.7}; - s_sensors->push_back(sensor); - - - sensor = Genesys_Sensor(); - sensor.sensor_id = CIS_CANONLIDE80, - sensor.optical_res = 1200; // real hardware limit is 2400 - sensor.ccd_size_divisor = 2; - sensor.black_pixels = 20; - sensor.dummy_pixel = 6; - // tuned to give 3*8 multiple startx coordinate during shading calibration - sensor.CCD_start_xoffset = 34; // 14=>3, 20=>2 - // 10400, too wide=>10288 in shading data 10240~ - // 10208 too short for shading, max shading data = 10240 pixels, endpix-startpix=10208 - sensor.sensor_pixels = 10240; - sensor.fau_gain_white_ref = 150; - sensor.gain_white_ref = 150; - // maps to 0x70-0x73 for GL841 - sensor.exposure = { 0x1000, 0x1000, 0x0500 }; - sensor.custom_regs = { - { 0x08, 0x00 }, - { 0x09, 0x05 }, - { 0x0a, 0x07 }, - { 0x0b, 0x09 }, - { 0x16, 0x00 }, - { 0x17, 0x01 }, - { 0x18, 0x00 }, - { 0x19, 0x06 }, - { 0x1a, 0x00 }, - { 0x1b, 0x00 }, - { 0x1c, 0x00 }, - { 0x1d, 0x04 }, - { 0x52, 0x03 }, - { 0x53, 0x07 }, - { 0x54, 0x00 }, - { 0x55, 0x00 }, - { 0x56, 0x00 }, - { 0x57, 0x00 }, - { 0x58, 0x29 }, - { 0x59, 0x69 }, - { 0x5a, 0x55 }, - { 0x5b, 0x00 }, - { 0x5c, 0x00 }, - { 0x5d, 0x20 }, - { 0x5e, 0x41 }, - }; - sensor.gamma = {1.0, 1.0, 1.0}; - s_sensors->push_back(sensor); -} - -/** for General Purpose Output specific settings: - * initial GPO value (registers 0x66-0x67/0x6c-0x6d) - * GPO enable mask (registers 0x68-0x69/0x6e-0x6f) - * The first register is for GPIO9-GPIO16, the second for GPIO1-GPIO8 - */ -static Genesys_Gpo Gpo[] = { - /* UMAX */ - {GPO_UMAX, - {0x11, 0x00} - , - {0x51, 0x20} - , - } - , - /* Plustek OpticPro S12/ST12 */ - {GPO_ST12, - {0x11, 0x00} - , - {0x51, 0x20} - , - } - , - /* Plustek OpticPro S24/ST24 */ - {GPO_ST24, - {0x00, 0x00} - , - {0x51, 0x20} - , - } - , - /* MD5345/MD6471 */ - {GPO_5345, - {0x30, 0x18} - , /* bits 11-12 are for bipolar V-ref input voltage */ - {0xa0, 0x18} - , - } - , - /* HP2400C */ - {GPO_HP2400, - {0x30, 0x00} - , - {0x31, 0x00} - , - } - , - /* HP2300C */ - {GPO_HP2300, - {0x00, 0x00} - , - {0x00, 0x00} - , - } - , - /* CANONLIDE35 */ - {GPO_CANONLIDE35, - {0x02, 0x80} - , - {0xef, 0x80} - , - } - , - /* 7: XP200 */ - {GPO_XP200, - {0x30, 0x00} - , - {0xb0, 0x00} - , - }, - /* HP3670 */ - {GPO_HP3670, - {0x00, 0x00} - , - {0x00, 0x00} - } - , - /* 8: XP300 */ - {GPO_XP300, - {0x09, 0xc6}, - {0xbb, 0x00}, - } - , - /* Syscan DP 665 */ - { - GPO_DP665, - {0x18, 0x00},/*0x19,0x00*/ - {0xbb, 0x00}, - } - , - /* Syscan DP 685 */ - { - GPO_DP685, - {0x3f, 0x46}, /* 6c, 6d */ - {0xfb, 0x00}, /* 6e, 6f */ - }, - /* CANONLIDE200 */ - {GPO_CANONLIDE200, - {0xfb, 0x20}, /* 0xfb when idle , 0xf9/0xe9 (1200) when scanning */ - {0xff, 0x00}, - }, - /* CANONLIDE700 */ - {GPO_CANONLIDE700, - {0xdb, 0xff}, - {0xff, 0x80}, - }, - {GPO_KVSS080, - {0xf5, 0x20}, - {0x7e, 0xa1}, - } - , - {GPO_G4050, - {0x20, 0x00}, - {0xfc, 0x00}, - } - , - /* HP N6310 */ - {GPO_HP_N6310, - {0xa3, 0x00}, - {0x7f, 0x00}, - } - , - /* CANONLIDE110 */ - {GPO_CANONLIDE110, - {0xfb, 0x20}, - {0xff, 0x00}, - } - , - /* CANONLIDE120 */ - {GPO_CANONLIDE120, - {0xfb, 0x20}, - {0xff, 0x00}, - } - , - /* CANONLIDE210 */ - {GPO_CANONLIDE210, - {0xfb, 0x20}, - {0xff, 0x00}, - } - , - /* Plustek 3600 */ - {GPO_PLUSTEK_3600, - {0x02, 0x00}, - {0x1e, 0x80}, - } - /* CanoScan 4400f */ - , - {GPO_CS4400F, - {0x01, 0x7f}, - {0xff, 0x00}, - } - /* CanoScan 8400f */ - , - {GPO_CS8400F, - {0x9a, 0xdf}, - {0xfe, 0x60}, - } - /* CanoScan 8600F */ - , - { GPO_CS8600F, - { 0x20, 0x7c }, - { 0xff, 0x00 }, - } - /* Canon Image formula 101 */ - , - {GPO_IMG101, - {0x41, 0xa4}, - {0x13, 0xa7} - } - /* Plustek OpticBook 3800 */ - , - {GPO_PLUSTEK3800, - {0x41, 0xa4}, - {0x13, 0xa7} - }, - /* Canon LiDE 80 */ - { - GPO_CANONLIDE80, - {0x28, 0x90}, - {0x75, 0x80}, - } -}; - -static Genesys_Motor Motor[] = { - /* UMAX */ - {MOTOR_UMAX, - 1200, /* motor base steps */ - 2400, /* maximum motor resolution */ - 1, /* maximum step mode */ - 1, /* number of power modes*/ - {{{ - 11000, /* maximum start speed */ - 3000, /* maximum end speed */ - 128, /* step count */ - 1.0, /* nonlinearity */ - }, - { - 11000, - 3000, - 128, - 1.0, - },},}, - }, - {MOTOR_5345, /* MD5345/6228/6471 */ - 1200, - 2400, - 1, - 1, - {{{ - 2000, - 1375, - 128, - 0.5, - }, - { - 2000, - 1375, - 128, - 0.5, - },},}, - }, - {MOTOR_ST24, /* ST24 */ - 2400, - 2400, - 1, - 1, - {{{ - 2289, - 2100, - 128, - 0.3, - }, - { - 2289, - 2100, - 128, - 0.3, - },},}, - }, - {MOTOR_HP3670, /* HP 3670 */ - 1200, - 2400, - 1, - 1, - {{{ - 11000, /* start speed */ - 3000, /* max speed */ - 128, /* min steps */ - 0.25, - }, - { - 11000, - 3000, - 128, - 0.5, - },},}, - }, - {MOTOR_HP2400, /* HP 2400c */ - 1200, - 1200, - 1, - 1, - {{{ - 11000, /* start speed */ - 3000, /* max speed */ - 128, /* min steps */ - 0.25, - }, - { - 11000, - 3000, - 128, - 0.5, - },},}, - }, - {MOTOR_HP2300, /* HP 2300c */ - 600, /* 600/1200 */ - 1200, - 1, - 1, - {{{ - 3200, - 1200, - 128, - 0.5, - }, - { - 3200, - 1200, - 128, - 0.5, - },},}, - }, - {MOTOR_CANONLIDE35, /* Canon LiDE 35 */ - 1200, - 2400, - 1, - 1, - {{{ 3500, 1300, 60, 0.8, }, - { 3500, 1400, 60, 0.8, },},}, - }, - {MOTOR_XP200, /* Strobe XP200 */ - 600, - 600, - 1, - 1, - {{{ - 3500, - 1300, - 60, - 0.25, - }, - { - 3500, - 1400, - 60, - 0.5, - },},}, - }, - {MOTOR_XP300, /* 7: Visioneer Strobe XP300 */ - 300, - 600, - 1, - 1, - {{{ /* works best with GPIO10, GPIO14 off */ - 3700, - 3700, - 2, - 0.8, - }, - { - 11000, - 11000, - 2, - 0.8, - },},}, - }, - {MOTOR_DP665, /* Syscan DP 665 */ - 750, - 1500, - 1, - 1, - {{{ - 3000, - 2500, - 10, - 0.8, - }, - { - 11000, - 11000, - 2, - 0.8, - },},}, - }, - {MOTOR_ROADWARRIOR, /* Visioneer Roadwarrior */ - 750, - 1500, - 1, - 1, - {{{ - 3000, - 2600, - 10, - 0.8, - }, - { - 11000, - 11000, - 2, - 0.8, - },},}, - }, - {MOTOR_DSMOBILE_600, /* Pentax DSmobile 600 */ - 750, - 1500, - 2, - 1, - {{{ - 6666, - 3700, - 8, - 0.8, - }, - { - 6666, - 3700, - 8, - 0.8, - },},}, - }, - {MOTOR_CANONLIDE100, /* Canon LiDE 100 */ - 1200, - 6400, - 2, /* maximum step type count */ - 1, /* maximum power modes count */ - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ - }, - }, - }, - {MOTOR_CANONLIDE200, /* Canon LiDE 200 */ - 1200, - 6400, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ - }, - }, - }, - {MOTOR_CANONLIDE700, /* Canon LiDE 700 */ - 1200, - 6400, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 127, 0.50}, /* full step */ - { 3000, 1500, 127, 0.50}, /* half step */ - { 3*2712, 3*2712, 16, 0.80}, /* quarter step 0.75*2712 */ - }, - }, - }, - {MOTOR_KVSS080, - 1200, - 1200, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 22222, 500, 246, 0.5 }, /* max speed / dpi * base dpi => exposure */ - { 22222, 500, 246, 0.5 }, - { 22222, 500, 246, 0.5 }, - }, - }, - }, - {MOTOR_G4050, - 2400, - 9600, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3961, 240, 246, 0.8 }, /* full step */ - { 3961, 240, 246, 0.8 }, /* half step */ - { 3961, 240, 246, 0.8 }, /* quarter step */ - }, - }, - }, - {MOTOR_CS8400F, - 2400, - 9600, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3961, 240, 246, 0.8 }, /* full step */ - { 3961, 240, 246, 0.8 }, /* half step */ - { 3961, 240, 246, 0.8 }, /* quarter step */ - }, - }, - }, - { - MOTOR_CS8600F, - 2400, - 9600, - 2, - 1, - { /* motor slopes */ - { /* power mode 0 */ - { 3961, 240, 246, 0.8 }, /* full step */ - { 3961, 240, 246, 0.8 }, /* half step */ - { 3961, 240, 246, 0.8 }, /* quarter step */ - }, - }, - }, - {MOTOR_CANONLIDE110, /* Canon LiDE 110 */ - 4800, - 9600, - 1, /* maximum step type count */ - 1, /* maximum power modes count */ - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 256, 0.50}, /* full step */ - }, - }, - }, - {MOTOR_CANONLIDE120, /* Canon LiDE 120 */ - 4800, - 9600, - 1, /* maximum step type count */ - 1, /* maximum power modes count */ - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 256, 0.50}, /* full step */ - }, - }, - }, - {MOTOR_CANONLIDE210, /* Canon LiDE 210 */ - 4800, - 9600, - 1, /* maximum step type count */ - 1, /* maximum power modes count */ - { /* motor slopes */ - { /* power mode 0 */ - { 3000, 1000, 256, 0.50}, /* full step */ - }, - }, - }, - {MOTOR_PLUSTEK_3600, /* PLUSTEK 3600 */ - 1200, - 2400, - 1, - 1, - { - { - { 3500, 1300, 60, 0.8 }, - { 3500, 3250, 60, 0.8 }, - }, - },}, - {MOTOR_IMG101, /* Canon Image Formula 101 */ - 600, - 1200, - 1, - 1, - { - { - { 3500, 1300, 60, 0.8 }, - { 3500, 3250, 60, 0.8 }, - }, - },}, - {MOTOR_PLUSTEK3800, /* Plustek OpticBook 3800 */ - 600, - 1200, - 1, - 1, - { - { - { 3500, 1300, 60, 0.8 }, - { 3500, 3250, 60, 0.8 }, - }, - },}, - {MOTOR_CANONLIDE80, - 2400, /* 2400 ???? */ - 4800, /* 9600 ???? */ - 1, /* max step type */ - 1, /* power mode count */ - { - { /* start speed, max end speed, step number */ - /* maximum speed (second field) is used to compute exposure as seen by motor */ - /* exposure=max speed/ slope dpi * base dpi */ - /* 5144 = max pixels at 600 dpi */ - /* 1288=(5144+8)*ydpi(=300)/base_dpi(=1200) , where 5152 is exposure */ - /* 6440=9660/(1932/1288) */ - { 9560, 1912, 31, 0.8 }, - }, - },}, -}; - -/* here we have the various device settings... - */ -static Genesys_Model umax_astra_4500_model = { - "umax-astra-4500", /* Name */ - "UMAX", /* Device vendor string */ - "Astra 4500", /* Device model name */ - MODEL_UMAX_ASTRA_4500, - GENESYS_GL646, - NULL, - - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_UMAX, - DAC_WOLFSON_UMAX, - GPO_UMAX, - MOTOR_UMAX, - GENESYS_FLAG_UNTESTED, /* Which flags are needed for this scanner? */ - /* untested, values set by hmg */ - GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ - 20, - 0, // shading_ta_lines - 200 -}; - -static Genesys_Model canon_lide_50_model = { - "canon-lide-50", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 35/40/50", /* Device model name */ - MODEL_CANON_LIDE_50, - GENESYS_GL841, - NULL, - - { 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 240, 200, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.42), /* Start of scan area in mm (x) */ - SANE_FIX (7.9), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (6.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_CANONLIDE35, - DAC_CANONLIDE35, - GPO_CANONLIDE35, - MOTOR_CANONLIDE35, - GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_DARK_WHITE_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | - GENESYS_HAS_FILE_SW | - GENESYS_HAS_EMAIL_SW | - GENESYS_HAS_COPY_SW, - 280, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model panasonic_kvss080_model = { - "panasonic-kv-ss080", /* Name */ - "Panasonic", /* Device vendor string */ - "KV-SS080", /* Device model name */ - MODEL_PANASONIC_KV_SS080, - GENESYS_GL843, - NULL, - - { 600, /* 500, 400,*/ 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - { 1200, 600, /* 500, 400, */ 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_KVSS080, - DAC_KVSS080, - GPO_KVSS080, - MOTOR_KVSS080, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW , - 100, - 0, // shading_ta_lines - 100 -}; - -static Genesys_Model hp4850c_model = { - "hewlett-packard-scanjet-4850c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 4850C", /* Device model name */ - MODEL_HP_SCANJET_4850C, - GENESYS_GL843, - NULL, - - {2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (7.9), /* Start of scan area in mm (x) */ - SANE_FIX (5.9), /* Start of scan area in mm (y) */ - SANE_FIX (219.6), /* Size of scan area in mm (x) */ - SANE_FIX (314.5), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_G4050, - DAC_G4050, - GPO_G4050, - MOTOR_G4050, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 0, // shading_ta_lines - 100 -}; - -static Genesys_Model hpg4010_model = { - "hewlett-packard-scanjet-g4010", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet G4010", /* Device model name */ - MODEL_HP_SCANJET_G4010, - GENESYS_GL843, - NULL, - - { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (8.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_G4050, - DAC_G4050, - GPO_G4050, - MOTOR_G4050, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 0, // shading_ta_lines - 100 -}; - -static Genesys_Model hpg4050_model = { - "hewlett-packard-scanjet-g4050", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet G4050", /* Device model name */ - MODEL_HP_SCANJET_G4050, - GENESYS_GL843, - NULL, - - { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - { 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (8.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_G4050, - DAC_G4050, - GPO_G4050, - MOTOR_G4050, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 0, // shading_ta_lines - 100 -}; - - -static Genesys_Model canon_4400f_model = { - "canon-canoscan-4400f", /* Name */ - "Canon", /* Device vendor string */ - "Canoscan 4400f", /* Device model name */ - MODEL_CANON_CANOSCAN_4400F, - GENESYS_GL843, - NULL, - - { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (6.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_CS4400F, - DAC_G4050, - GPO_CS4400F, - MOTOR_G4050, - GENESYS_FLAG_NO_CALIBRATION | - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_FULL_HWDPI_MODE | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 0, // shading_ta_lines - 100 -}; - - -static Genesys_Model canon_8400f_model = { - "canon-canoscan-8400f", /* Name */ - "Canon", /* Device vendor string */ - "Canoscan 8400f", /* Device model name */ - MODEL_CANON_CANOSCAN_8400F, - GENESYS_GL843, - NULL, - - { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - { 4800, 2400, 1200, 600, 400, 300, 200, 150, 100, 0}, - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (4.0), /* Start of scan area in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (315.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (8.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (13.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (217.9), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (250.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (40.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in line number */ - /* 0 38 76 OK 1200/2400 */ - /* 0 24 48 OK [100,600] dpi */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_CS8400F, - DAC_CS8400F, - GPO_CS8400F, - MOTOR_CS8400F, - GENESYS_FLAG_NO_CALIBRATION | - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_FULL_HWDPI_MODE | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 100, - 0, // shading_ta_lines - 100 -}; - - -static Genesys_Model canon_8600f_model = { - "canon-canoscan-8600f", // name - "Canon", // Device vendor string - "Canoscan 8600f", // Device model name - MODEL_CANON_CANOSCAN_8600F, - GENESYS_GL843, // ASIC type - NULL, - - { 4800, 2400, 1200, 600, 400, 300, 0}, // TODO: resolutions for non-XPA mode - { 4800, 2400, 1200, 600, 400, 300, 0}, // TODO: resolutions for non-XPA mode - { 16, 8, 0 }, // possible depths in gray mode - { 16, 8, 0 }, // possible depths in color mode - - SANE_FIX(24.0), // Start of scan area in mm (x) - SANE_FIX(10.0), // Start of scan area in mm (y) - SANE_FIX(216.0), // Size of scan area in mm (x) - SANE_FIX(297.0), // Size of scan area in mm (y) - - SANE_FIX(0.0), // Start of white strip in mm (y) - SANE_FIX(8.0), // Start of black mark in mm (x) - - SANE_FIX(95.0), // x_offset_ta - SANE_FIX(26.0), // y_offset_ta - SANE_FIX(70.0), // x_size_ta - SANE_FIX(230.0), // y_size_ta - - SANE_FIX(12.5), // y_offset_calib - - SANE_FIX(0.0), // Size of scan area after paper sensor stops - // sensing document in mm - SANE_FIX(0.0), // Amount of feeding needed to eject document - // after finishing scanning in mm - - 0, 48, 96, // RGB CCD Line-distance correction in line number - - COLOR_ORDER_RGB, // Order of the CCD/CIS colors - - SANE_FALSE, // Is this a CIS scanner? - SANE_FALSE, // Is this a sheetfed scanner? - CCD_CS8600F, - DAC_CS8600F, - GPO_CS8600F, - MOTOR_CS8600F, - GENESYS_FLAG_HAS_UTA | - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_STAGGERED_LINE | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_DARK_CALIBRATION | - GENESYS_FLAG_FULL_HWDPI_MODE | - GENESYS_FLAG_CUSTOM_GAMMA | - GENESYS_FLAG_SHADING_REPARK, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_COPY_SW, - 50, // shading_lines - 50, // shading_ta_lines - 100 -}; - - -static Genesys_Model canon_lide_100_model = { - "canon-lide-100", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 100", /* Device model name */ - MODEL_CANON_LIDE_100, - GENESYS_GL847, - NULL, - - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE100, - DAC_CANONLIDE200, - GPO_CANONLIDE200, - MOTOR_CANONLIDE100, - /* Which flags are needed for this scanner? */ - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_SIS_SENSOR - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model canon_lide_110_model = { - "canon-lide-110", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 110", /* Device model name */ - MODEL_CANON_LIDE_110, - GENESYS_GL124, - NULL, - - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (9.0), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE110, - DAC_CANONLIDE110, - GPO_CANONLIDE110, - MOTOR_CANONLIDE110, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model canon_lide_120_model = { - "canon-lide-120", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 120", /* Device model name */ - MODEL_CANON_LIDE_120, - GENESYS_GL124, - NULL, - - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (8.0), /* Start of scan area in mm (y) */ - SANE_FIX (216.0), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE120, - DAC_CANONLIDE120, - GPO_CANONLIDE120, - MOTOR_CANONLIDE120, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 0, // shading_ta_lines - 400 -}; - - -static Genesys_Model canon_lide_210_model = { - "canon-lide-210", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 210", /* Device model name */ - MODEL_CANON_LIDE_210, - GENESYS_GL124, - NULL, - - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, /* 400,*/ 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (8.7), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (297.5), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE210, - DAC_CANONLIDE110, - GPO_CANONLIDE210, - MOTOR_CANONLIDE210, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_EXTRA_SW, - 60, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model canon_lide_220_model = { - "canon-lide-220", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 220", /* Device model name */ - MODEL_CANON_LIDE_220, - GENESYS_GL124, /* or a compatible one */ - NULL, - - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (2.2), /* Start of scan area in mm (x) */ - SANE_FIX (8.7), /* Start of scan area in mm (y) */ - SANE_FIX (216.70), /* Size of scan area in mm (x) */ - SANE_FIX (297.5), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE220, - DAC_CANONLIDE110, - GPO_CANONLIDE210, - MOTOR_CANONLIDE210, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW | GENESYS_HAS_EXTRA_SW, - 60, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model canon_5600f_model = { - "canon-5600f", /* Name */ - "Canon", /* Device vendor string */ - "5600F", /* Device model name */ - MODEL_CANON_CANOSCAN_5600F, - GENESYS_GL847, - NULL, - - {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE200, - DAC_CANONLIDE200, - GPO_CANONLIDE200, - MOTOR_CANONLIDE200, - GENESYS_FLAG_UNTESTED /* not working yet */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_SIS_SENSOR - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model canon_lide_700f_model = { - "canon-lide-700f", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 700F", /* Device model name */ - MODEL_CANON_LIDE_700F, - GENESYS_GL847, - NULL, - - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (3.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.1), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (297.0), /* Size of scan area in mm (y) */ - - SANE_FIX (1.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE700, - DAC_CANONLIDE700, - GPO_CANONLIDE700, - MOTOR_CANONLIDE700, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_SIS_SENSOR - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 70, - 0, // shading_ta_lines - 400 -}; - - - -static Genesys_Model canon_lide_200_model = { - "canon-lide-200", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 200", /* Device model name */ - MODEL_CANON_LIDE_200, - GENESYS_GL847, - NULL, - - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {4800, 2400, 1200, 600, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (1.1), /* Start of scan area in mm (x) */ - SANE_FIX (8.3), /* Start of scan area in mm (y) */ - SANE_FIX (216.07), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE200, - DAC_CANONLIDE200, - GPO_CANONLIDE200, - MOTOR_CANONLIDE200, - GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_SIS_SENSOR - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_SHADING_REPARK - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_FILE_SW, - 50, - 0, // shading_ta_lines - 400 -}; - - -static Genesys_Model canon_lide_60_model = { - "canon-lide-60", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 60", /* Device model name */ - MODEL_CANON_LIDE_60, - GENESYS_GL841, - NULL, - - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.42), /* Start of scan area in mm (x) */ - SANE_FIX (7.9), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (6.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_CANONLIDE35, - DAC_CANONLIDE35, - GPO_CANONLIDE35, - MOTOR_CANONLIDE35, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_WHITE_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - - GENESYS_HAS_COPY_SW /* Has four buttons: COPY, SCAN, PDF, EMAIL */ - | GENESYS_HAS_SCAN_SW - | GENESYS_HAS_FILE_SW - | GENESYS_HAS_EMAIL_SW, - 300, - 0, // shading_ta_lines - 400 -}; /* this is completely untested -- hmg */ - -static Genesys_Model canon_lide_80_model = { - "canon-lide-80", /* Name */ - "Canon", /* Device vendor string */ - "LiDE 80", /* Device model name */ - MODEL_CANON_LIDE_80, - GENESYS_GL841, - NULL, - - { 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 240, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - SANE_FIX (0.42), /* Start of scan area in mm (x) 0.42 */ - SANE_FIX (7.90), /* Start of scan area in mm (y) 7.90 */ - SANE_FIX (216.07), /* Size of scan area in mm (x) 218.00 */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (4.5), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CIS_CANONLIDE80, - DAC_CANONLIDE80, - GPO_CANONLIDE80, - MOTOR_CANONLIDE80, - GENESYS_FLAG_LAZY_INIT | /* Which flags are needed for this scanner? */ - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_DARK_WHITE_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | - GENESYS_HAS_FILE_SW | - GENESYS_HAS_EMAIL_SW | - GENESYS_HAS_COPY_SW, - 160, /* 280 @2400 */ - 0, // shading_ta_lines - 400 -}; - - -static Genesys_Model hp2300c_model = { - "hewlett-packard-scanjet-2300c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 2300c", /* Device model name */ - MODEL_HP_SCANJET_2300C, - GENESYS_GL646, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions, motor can go up to 1200 dpi */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (2.0), /* Start of scan area in mm (x_offset) */ - SANE_FIX (7.5), /* Start of scan area in mm (y_offset) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (295.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 16, 8, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_HP2300, - DAC_WOLFSON_HP2300, - GPO_HP2300, - MOTOR_HP2300, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_COPY_SW, - 40, - 0, // shading_ta_lines - 132 -}; - -static -Genesys_Model hp2400c_model = { - "hewlett-packard-scanjet-2400c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 2400c", /* Device model name */ - MODEL_HP_SCANJET_2400C, - GENESYS_GL646, - NULL, - - {1200, 600, 300, 150, 100, 50, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (6.5), /* Start of scan area in mm (x) */ - SANE_FIX (2.5), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (297.2), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_HP2400, - DAC_WOLFSON_HP2400, - GPO_HP2400, - MOTOR_HP2400, - GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW, - 20, - 0, // shading_ta_lines - 132 -}; - -static -Genesys_Model visioneer_xp200_model = { - "visioneer-strobe-xp200", /* Name */ - "Visioneer", /* Device vendor string */ - "Strobe XP200", /* Device model name */ - MODEL_VISIONEER_STROBE_XP200, - GENESYS_GL646, - NULL, - - {600, 300, 200, 100, 75, 0}, /* possible x-resolutions */ - {600, 300, 200, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.5), /* Start of scan area in mm (x) */ - SANE_FIX (16.0), /* Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (297.2), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CIS_XP200, - DAC_AD_XP200, /* Analog Device frontend */ - GPO_XP200, - MOTOR_XP200, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 120, - 0, // shading_ta_lines - 132 -}; - -static Genesys_Model hp3670c_model = { - "hewlett-packard-scanjet-3670c", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet 3670c", /* Device model name */ - MODEL_HP_SCANJET_3670C, - GENESYS_GL646, - NULL, - - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (8.5), /* Start of scan area in mm (x) */ - SANE_FIX (11.0), /* Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (104.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (55.6), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (25.6), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (78.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (76.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_HP3670, - DAC_WOLFSON_HP3670, - GPO_HP3670, - MOTOR_HP3670, - GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_XPA - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_SCAN_SW, - 20, - 0, // shading_ta_lines - 200 -}; - -static Genesys_Model plustek_st12_model = { - "plustek-opticpro-st12", /* Name */ - "Plustek", /* Device vendor string */ - "OpticPro ST12", /* Device model name */ - MODEL_PLUSTEK_OPTICPRO_ST12, - GENESYS_GL646, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_ST12, - DAC_WOLFSON_ST12, - GPO_ST12, - MOTOR_UMAX, - GENESYS_FLAG_UNTESTED | GENESYS_FLAG_14BIT_GAMMA, /* Which flags are needed for this scanner? */ - GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ - 20, - 0, // shading_ta_lines - 200 -}; - -static Genesys_Model plustek_st24_model = { - "plustek-opticpro-st24", /* Name */ - "Plustek", /* Device vendor string */ - "OpticPro ST24", /* Device model name */ - MODEL_PLUSTEK_OPTICPRO_ST24, - GENESYS_GL646, - NULL, - - {1200, 600, 300, 150, 75, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (3.5), /* Start of scan area in mm (x) */ - SANE_FIX (7.5), /* Start of scan area in mm (y) */ - SANE_FIX (218.0), /* Size of scan area in mm (x) */ - SANE_FIX (299.0), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (1.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 8, 16, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_BGR, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_ST24, - DAC_WOLFSON_ST24, - GPO_ST24, - MOTOR_ST24, - GENESYS_FLAG_UNTESTED - | GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_OFFSET_CALIBRATION, - GENESYS_HAS_NO_BUTTONS, /* no buttons supported */ - 20, - 0, // shading_ta_lines - 200 -}; - -static Genesys_Model medion_md5345_model = { - "medion-md5345-model", /* Name */ - "Medion", /* Device vendor string */ - "MD5345/MD6228/MD6471", /* Device model name */ - MODEL_MEDION_MD5345, - GENESYS_GL646, - NULL, - - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX ( 0.30), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ - - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_5345, - DAC_WOLFSON_5345, - GPO_5345, - MOTOR_5345, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_SHADING_NO_MOVE - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, - 40, - 0, // shading_ta_lines - 200 -}; - -static Genesys_Model visioneer_xp300_model = { - "visioneer-strobe-xp300", /* Name */ - "Visioneer", /* Device vendor string */ - "Strobe XP300", /* Device model name */ - MODEL_VISIONEER_STROBE_XP300, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (26.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - /* this is larger than needed -- accounts for second sensor head, which is a - calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_XP300, - DAC_WOLFSON_XP300, - GPO_XP300, - MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model syscan_docketport_665_model = { - "syscan-docketport-665", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 665", /* Device model name */ - MODEL_SYSCAN_DOCKETPORT_665, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (108.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (17.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_DP665, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_DP665, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model visioneer_roadwarrior_model = { - "visioneer-roadwarrior", /* Name */ - "Visioneer", /* Device vendor string */ - "Readwarrior", /* Device model name */ - MODEL_VISIONEER_ROADWARRIOR, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_ROADWARRIOR, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model syscan_docketport_465_model = { - "syscan-docketport-465", /* Name */ - "Syscan", /* Device vendor string */ - "DocketPORT 465", /* Device model name */ - MODEL_SYSCAN_DOCKETPORT_465, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_ROADWARRIOR, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_NO_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_UNTESTED, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW, - 300, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model visioneer_xp100_r3_model = { - "visioneer-xp100-revision3", /* Name */ - "Visioneer", /* Device vendor string */ - "XP100 Revision 3", /* Device model name */ - MODEL_VISIONEER_STROBE_XP100_REVISION3, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_ROADWARRIOR, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model pentax_dsmobile_600_model = { - "pentax-dsmobile-600", /* Name */ - "Pentax", /* Device vendor string */ - "DSmobile 600", /* Device model name */ - MODEL_PENTAX_DSMOBILE_600, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_DSMOBILE600, - DAC_WOLFSON_DSM600, - GPO_DP665, - MOTOR_DSMOBILE_600, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model syscan_docketport_467_model = { - "syscan-docketport-467", /* Name */ - "Syscan", /* Device vendor string */ - "DocketPORT 467", /* Device model name */ - MODEL_SYSCAN_DOCKETPORT_467, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_DSMOBILE600, - DAC_WOLFSON_DSM600, - GPO_DP665, - MOTOR_DSMOBILE_600, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model syscan_docketport_685_model = { - "syscan-docketport-685", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 685", /* Device model name */ - MODEL_SYSCAN_DOCKETPORT_685, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (212.0), /* Size of scan area in mm (x) */ - SANE_FIX (500), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (26.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - /* this is larger than needed -- accounts for second sensor head, which is a - calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_DP685, - DAC_WOLFSON_DSM600, - GPO_DP685, - MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model syscan_docketport_485_model = { - "syscan-docketport-485", /* Name */ - "Syscan/Ambir", /* Device vendor string */ - "DocketPORT 485", /* Device model name */ - MODEL_SYSCAN_DOCKETPORT_485, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (26.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - /* this is larger than needed -- accounts for second sensor head, which is a - calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_XP300, - DAC_WOLFSON_XP300, - GPO_XP300, - MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model dct_docketport_487_model = { - "dct-docketport-487", /* Name */ - "DCT", /* Device vendor string */ - "DocketPORT 487", /* Device model name */ - MODEL_DCT_DOCKETPORT_487, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.0), /* Start of scan area in mm (x) */ - SANE_FIX (1.0), /* Start of scan area in mm (y) */ - SANE_FIX (435.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (26.5), /* Size of scan area after paper sensor stops - sensing document in mm */ - /* this is larger than needed -- accounts for second sensor head, which is a - calibration item */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_XP300, - DAC_WOLFSON_XP300, - GPO_XP300, - MOTOR_XP300, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_UNTESTED, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model visioneer_7100_model = { - "visioneer-7100-model", /* Name */ - "Visioneer", /* Device vendor string */ - "OneTouch 7100", /* Device model name */ - MODEL_VISIONEER_7100, - GENESYS_GL646, - NULL, - - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ - - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ -/* 48, 24, 0, */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_5345, - DAC_WOLFSON_5345, - GPO_5345, - MOTOR_5345, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, - 40, - 0, // shading_ta_lines - 200 -}; - -static Genesys_Model xerox_2400_model = { - "xerox-2400-model", /* Name */ - "Xerox", /* Device vendor string */ - "OneTouch 2400", /* Device model name */ - MODEL_XEROX_2400, - GENESYS_GL646, - NULL, - - {1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible x-resolutions */ - {2400, 1200, 600, 400, 300, 200, 150, 100, 75, 50, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX ( 4.00), /* Start of scan area in mm (x) */ - SANE_FIX ( 0.80), /* 2.79 < Start of scan area in mm (y) */ - SANE_FIX (215.9), /* Size of scan area in mm (x) */ - SANE_FIX (296.4), /* Size of scan area in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in mm (y) */ - SANE_FIX (0.00), /* Start of black mark in mm (x) */ - - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.00), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.00), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 48, 24, 0, /* RGB CCD Line-distance correction in pixel */ -/* 48, 24, 0, */ - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_5345, - DAC_WOLFSON_5345, - GPO_5345, - MOTOR_5345, - GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_SEARCH_START - | GENESYS_FLAG_STAGGERED_LINE - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_COPY_SW | GENESYS_HAS_EMAIL_SW | GENESYS_HAS_POWER_SW | GENESYS_HAS_OCR_SW | GENESYS_HAS_SCAN_SW, - 40, - 0, // shading_ta_lines - 200 -}; - - -static Genesys_Model xerox_travelscanner_model = { - "xerox-travelscanner", /* Name */ - "Xerox", /* Device vendor string */ - "Travelscanner 100", /* Device model name */ - MODEL_XEROX_TRAVELSCANNER_100, - GENESYS_GL841, - NULL, - - {600, 300, 150, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (4.0), /* Start of scan area in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in mm (y) */ - SANE_FIX (220.0), /* Size of scan area in mm (x) */ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (16.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_TRUE, /* Is this a CIS scanner? */ - SANE_TRUE, /* Is this a sheetfed scanner? */ - CCD_ROADWARRIOR, - DAC_WOLFSON_XP300, - GPO_DP665, - MOTOR_ROADWARRIOR, - GENESYS_FLAG_LAZY_INIT /* Which flags are needed for this scanner? */ - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION, - GENESYS_HAS_SCAN_SW | GENESYS_HAS_PAGE_LOADED_SW | GENESYS_HAS_CALIBRATE, - 100, - 0, // shading_ta_lines - 400 -}; - -static Genesys_Model plustek_3600_model = { - "plustek-opticbook-3600", /* Name */ - "PLUSTEK", /* Device vendor string */ - "OpticBook 3600", /* Device model name */ - MODEL_PLUSTEK_OPTICPRO_3600, - GENESYS_GL841, - NULL, - {/*1200,*/ 600, 400, 300, 200, 150, 100, 75, 0}, /* possible x-resolutions */ - {/*2400,*/ 1200, 600, 400, 300, 200, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (0.42),/*SANE_FIX (0.42), Start of scan area in mm (x) */ - SANE_FIX (6.75),/*SANE_FIX (7.9), Start of scan area in mm (y) */ - SANE_FIX (216.0),/*SANE_FIX (216.0), Size of scan area in mm (x) */ - SANE_FIX (297.0),/*SANE_FIX (297.0), Size of scan area in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_PLUSTEK_3600, - DAC_PLUSTEK_3600, - GPO_PLUSTEK_3600, - MOTOR_PLUSTEK_3600, - GENESYS_FLAG_UNTESTED /* not fully working yet */ - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_LAZY_INIT,/* - | GENESYS_FLAG_NO_CALIBRATION,*/ - GENESYS_HAS_NO_BUTTONS, - 7, - 0, // shading_ta_lines - 200 -}; - -static Genesys_Model hpn6310_model = { - "hewlett-packard-scanjet-N6310", /* Name */ - "Hewlett Packard", /* Device vendor string */ - "ScanJet N6310", /* Device model name */ - MODEL_HP_SCANJET_N6310, - GENESYS_GL847, - NULL, - - { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 0}, - { 2400, 1200, 600, 400, 300, 200, 150, 100, 75, 0}, - - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (6), /* Start of scan area in mm (x) */ - SANE_FIX (2), /* Start of scan area in mm (y) */ - SANE_FIX (216), /* Size of scan area in mm (x) 5148 pixels at 600 dpi*/ - SANE_FIX (511), /* Size of scan area in mm (y) */ - - SANE_FIX (3.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (100.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 0, 0, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_HP_N6310, - DAC_CANONLIDE200, /*Not defined yet for N6310 */ - GPO_HP_N6310, - MOTOR_CANONLIDE200, /*Not defined yet for N6310 */ - GENESYS_FLAG_UNTESTED /* not fully working yet */ - | GENESYS_FLAG_LAZY_INIT - | GENESYS_FLAG_14BIT_GAMMA - | GENESYS_FLAG_DARK_CALIBRATION - | GENESYS_FLAG_OFFSET_CALIBRATION - | GENESYS_FLAG_CUSTOM_GAMMA - | GENESYS_FLAG_SKIP_WARMUP - | GENESYS_FLAG_NO_CALIBRATION, - - GENESYS_HAS_NO_BUTTONS, - 100, - 0, // shading_ta_lines - 100 -}; - - -static Genesys_Model plustek_3800_model = { - "plustek-opticbook-3800", /* Name */ - "PLUSTEK", /* Device vendor string */ - "OpticBook 3800", /* Device model name */ - MODEL_PLUSTEK_OPTICBOOK_3800, - GENESYS_GL845, - NULL, - - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_PLUSTEK3800, - DAC_PLUSTEK3800, - GPO_PLUSTEK3800, - MOTOR_PLUSTEK3800, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_NO_BUTTONS, /* TODO there are 4 buttons to support */ - 100, - 0, // shading_ta_lines - 100 -}; - - -static Genesys_Model canon_formula101_model = { - "canon-image-formula-101", /* Name */ - "Canon", /* Device vendor string */ - "Image Formula 101", /* Device model name */ - MODEL_CANON_IMAGE_FORMULA_101, - GENESYS_GL846, - NULL, - - {1200, 600, 300, 150, 100, 75, 0}, /* possible x-resolutions */ - {1200, 600, 300, 150, 100, 75, 0}, /* possible y-resolutions */ - {16, 8, 0}, /* possible depths in gray mode */ - {16, 8, 0}, /* possible depths in color mode */ - - SANE_FIX (7.2), /* Start of scan area in mm (x) */ - SANE_FIX (14.7), /* Start of scan area in mm (y) */ - SANE_FIX (217.7), /* Size of scan area in mm (x) */ - SANE_FIX (300.0), /* Size of scan area in mm (y) */ - - SANE_FIX (9.0), /* Start of white strip in mm (y) */ - SANE_FIX (0.0), /* Start of black mark in mm (x) */ - - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Start of scan area in TA mode in mm (y) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (x) */ - SANE_FIX (0.0), /* Size of scan area in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Start of white strip in TA mode in mm (y) */ - - SANE_FIX (0.0), /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_FIX (0.0), /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - 0, 24, 48, /* RGB CCD Line-distance correction in pixel */ - - COLOR_ORDER_RGB, /* Order of the CCD/CIS colors */ - - SANE_FALSE, /* Is this a CIS scanner? */ - SANE_FALSE, /* Is this a sheetfed scanner? */ - CCD_IMG101, - DAC_IMG101, - GPO_IMG101, - MOTOR_IMG101, - GENESYS_FLAG_LAZY_INIT | - GENESYS_FLAG_SKIP_WARMUP | - GENESYS_FLAG_OFFSET_CALIBRATION | - GENESYS_FLAG_CUSTOM_GAMMA, - GENESYS_HAS_NO_BUTTONS , - 100, - 0, // shading_ta_lines - 100 -}; - - -static Genesys_USB_Device_Entry genesys_usb_device_list[] = { - /* GL646 devices */ - {0x03f0, 0x0901, &hp2300c_model}, - {0x03f0, 0x0a01, &hp2400c_model}, - {0x03f0, 0x1405, &hp3670c_model}, - {0x0461, 0x0377, &medion_md5345_model}, - {0x04a7, 0x0229, &visioneer_7100_model}, - {0x0461, 0x038b, &xerox_2400_model}, - {0x04a7, 0x0426, &visioneer_xp200_model}, - {0x0638, 0x0a10, &umax_astra_4500_model}, - {0x07b3, 0x0600, &plustek_st12_model}, - {0x07b3, 0x0601, &plustek_st24_model}, - /* GL841 devices */ - {0x04a7, 0x0474, &visioneer_xp300_model}, - {0x04a7, 0x0494, &visioneer_roadwarrior_model}, - {0x04a7, 0x049b, &visioneer_xp100_r3_model}, - {0x04a7, 0x04ac, &xerox_travelscanner_model}, - {0x04a9, 0x2213, &canon_lide_50_model}, - {0x04a9, 0x221c, &canon_lide_60_model}, - {0x04a9, 0x2214, &canon_lide_80_model}, - {0x07b3, 0x0900, &plustek_3600_model}, - {0x0a17, 0x3210, &pentax_dsmobile_600_model}, - {0x04f9, 0x2038, &pentax_dsmobile_600_model}, /* clone, only usb id is different */ - {0x0a82, 0x4800, &syscan_docketport_485_model}, - {0x0a82, 0x4802, &syscan_docketport_465_model}, - {0x0a82, 0x4803, &syscan_docketport_665_model}, - {0x0a82, 0x480c, &syscan_docketport_685_model}, - {0x1dcc, 0x4810, &dct_docketport_487_model}, - {0x1dcc, 0x4812, &syscan_docketport_467_model}, - /* GL843 devices */ - {0x04da, 0x100f, &panasonic_kvss080_model}, - {0x03f0, 0x1b05, &hp4850c_model}, - {0x03f0, 0x4505, &hpg4010_model}, - {0x03f0, 0x4605, &hpg4050_model}, - {0x04a9, 0x2228, &canon_4400f_model}, - {0x04a9, 0x221e, &canon_8400f_model}, - {0x04a9, 0x2229, &canon_8600f_model}, - /* GL845 devices */ - {0x07b3, 0x1300, &plustek_3800_model}, - /* GL846 devices */ - {0x1083, 0x162e, &canon_formula101_model}, - /* GL847 devices */ - {0x04a9, 0x1904, &canon_lide_100_model}, - {0x04a9, 0x1905, &canon_lide_200_model}, - {0x04a9, 0x1906, &canon_5600f_model}, - {0x04a9, 0x1907, &canon_lide_700f_model}, - {0x03f0, 0x4705, &hpn6310_model}, - /* GL124 devices */ - {0x04a9, 0x1909, &canon_lide_110_model}, - {0x04a9, 0x190e, &canon_lide_120_model}, - {0x04a9, 0x190a, &canon_lide_210_model}, - {0x04a9, 0x190f, &canon_lide_220_model}, - {0, 0, NULL} -}; - -#define MAX_SCANNERS (sizeof(genesys_usb_device_list) / \ - sizeof(genesys_usb_device_list[0])) diff --git a/backend/genesys_error.cc b/backend/genesys_error.cc deleted file mode 100644 index c98a490..0000000 --- a/backend/genesys_error.cc +++ /dev/null @@ -1,115 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2019 Povilas Kanapickas - - 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. -*/ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_error.h" -#include -#include - -extern "C" void sanei_debug_msg(int level, int max_level, const char *be, const char *fmt, - va_list ap); - -#if (defined(__GNUC__) || defined(__CLANG__)) && (defined(__linux__) || defined(__APPLE__)) -extern "C" char* __cxa_get_globals(); -#endif - -static unsigned num_uncaught_exceptions() -{ -#if __cplusplus >= 201703L - int count = std::uncaught_exceptions(); - return count >= 0 ? count : 0; -#elif (defined(__GNUC__) || defined(__CLANG__)) && (defined(__linux__) || defined(__APPLE__)) - // the format of the __cxa_eh_globals struct is enshrined into the Itanium C++ ABI and it's - // very unlikely we'll get issues referencing it directly - char* cxa_eh_globals_ptr = __cxa_get_globals(); - return *reinterpret_cast(cxa_eh_globals_ptr + sizeof(void*)); -#else - return std::uncaught_exception() ? 1 : 0; -#endif -} - -DebugMessageHelper::DebugMessageHelper(const char* func) -{ - func_ = func; - num_exceptions_on_enter_ = num_uncaught_exceptions(); - msg_[0] = '\0'; - DBG(DBG_proc, "%s: start\n", func_); -} - -DebugMessageHelper::DebugMessageHelper(const char* func, const char* format, ...) -{ - func_ = func; - num_exceptions_on_enter_ = num_uncaught_exceptions(); - msg_[0] = '\0'; - DBG(DBG_proc, "%s: start\n", func_); - DBG(DBG_proc, "%s: ", func_); - - std::va_list args; - va_start(args, format); - sanei_debug_msg(DBG_proc, DBG_LEVEL, STRINGIFY(BACKEND_NAME), format, args); - va_end(args); - DBG(DBG_proc, "\n"); -} - - -DebugMessageHelper::~DebugMessageHelper() -{ - if (num_exceptions_on_enter_ < num_uncaught_exceptions()) { - if (msg_[0] != '\0') { - DBG(DBG_error, "%s: failed during %s\n", func_, msg_); - } else { - DBG(DBG_error, "%s: failed\n", func_); - } - } else { - DBG(DBG_proc, "%s: completed\n", func_); - } -} - -void DebugMessageHelper::vstatus(const char* format, ...) -{ - std::va_list args; - va_start(args, format); - std::vsnprintf(msg_, MAX_BUF_SIZE, format, args); - va_end(args); -} diff --git a/backend/genesys_error.h b/backend/genesys_error.h deleted file mode 100644 index d456581..0000000 --- a/backend/genesys_error.h +++ /dev/null @@ -1,202 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2019 Povilas Kanapickas - - 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. -*/ - -#ifndef BACKEND_GENESYS_ERROR_H -#define BACKEND_GENESYS_ERROR_H - -#include "../include/sane/config.h" -#include "../include/sane/sane.h" -#include "../include/sane/sanei_backend.h" - -#include -#include -#include - -#define DBG_error0 0 /* errors/warnings printed even with devuglevel 0 */ -#define DBG_error 1 /* fatal errors */ -#define DBG_init 2 /* initialization and scanning time messages */ -#define DBG_warn 3 /* warnings and non-fatal errors */ -#define DBG_info 4 /* informational messages */ -#define DBG_proc 5 /* starting/finishing functions */ -#define DBG_io 6 /* io functions */ -#define DBG_io2 7 /* io functions that are called very often */ -#define DBG_data 8 /* log image data */ - -class SaneException : std::exception { -public: - SaneException(SANE_Status status) : status_(status) - { - set_msg(nullptr); - } - - SaneException(SANE_Status status, const char* msg) : status_(status) - { - set_msg(msg); - } - - SaneException(const char* msg) : SaneException(SANE_STATUS_INVAL, msg) {} - - SANE_Status status() const { return status_; } - virtual const char* what() const noexcept override { return msg_.c_str(); } - -private: - - void set_msg(const char* msg) - { - const char* status_msg = sane_strstatus(status_); - std::size_t status_msg_len = std::strlen(status_msg); - - if (msg) { - std::size_t msg_len = std::strlen(msg); - msg_.reserve(msg_len + status_msg_len + 3); - msg_ = msg; - msg_ += " : "; - msg_ += status_msg; - return; - } - - msg_.reserve(status_msg_len); - msg_ = status_msg; - } - - std::string msg_; - SANE_Status status_; -}; - -/** - * call a function and return on error - */ -#define RIE(function) \ - do { status = function; \ - if (status != SANE_STATUS_GOOD) \ - { \ - DBG(DBG_error, "%s: %s\n", __func__, sane_strstatus (status)); \ - return status; \ - } \ - } while (SANE_FALSE) - -// call a function and throw an exception on error -#define TIE(function) \ - do { \ - SANE_Status tmp_status = function; \ - if (tmp_status != SANE_STATUS_GOOD) { \ - throw SaneException(tmp_status); \ - } \ - } while (false) - -#define DBGSTART DBG (DBG_proc, "%s start\n", __func__); -#define DBGCOMPLETED DBG (DBG_proc, "%s completed\n", __func__); - -class DebugMessageHelper { -public: - static constexpr unsigned MAX_BUF_SIZE = 120; - - DebugMessageHelper(const char* func); - DebugMessageHelper(const char* func, const char* format, ...) - #ifdef __GNUC__ - __attribute__((format(printf, 3, 4))) - #endif - ; - - ~DebugMessageHelper(); - - void status(const char* msg) { vstatus("%s", msg); } - void vstatus(const char* format, ...) - #ifdef __GNUC__ - __attribute__((format(printf, 2, 3))) - #endif - ; - - void clear() { msg_[0] = '\n'; } - -private: - const char* func_ = nullptr; - char msg_[MAX_BUF_SIZE]; - unsigned num_exceptions_on_enter_ = 0; -}; - -#define DBG_HELPER(var) DebugMessageHelper var(__func__) -#define DBG_HELPER_ARGS(var, ...) DebugMessageHelper var(__func__, __VA_ARGS__) - -template -SANE_Status wrap_exceptions_to_status_code(const char* func, F&& function) -{ - try { - return function(); - } catch (const SaneException& exc) { - return exc.status(); - } catch (const std::bad_alloc& exc) { - return SANE_STATUS_NO_MEM; - } catch (const std::exception& exc) { - DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what()); - return SANE_STATUS_INVAL; - } catch (...) { - DBG(DBG_error, "%s: got unknown uncaught exception\n", func); - return SANE_STATUS_INVAL; - } -} - -template -void catch_all_exceptions(const char* func, F&& function) -{ - try { - function(); - } catch (const SaneException& exc) { - DBG(DBG_error, "%s: got exception: %s\n", func, exc.what()); - } catch (const std::bad_alloc& exc) { - DBG(DBG_error, "%s: got exception: could not allocate memory: %s\n", func, exc.what()); - } catch (const std::exception& exc) { - DBG(DBG_error, "%s: got uncaught exception: %s\n", func, exc.what()); - } catch (...) { - DBG(DBG_error, "%s: got unknown uncaught exception\n", func); - } -} - -inline void wrap_status_code_to_exception(SANE_Status status) -{ - if (status == SANE_STATUS_GOOD) - return; - throw SaneException(status); -} - -#endif // BACKEND_GENESYS_ERROR_H diff --git a/backend/genesys_gl124.cc b/backend/genesys_gl124.cc deleted file mode 100644 index a535d58..0000000 --- a/backend/genesys_gl124.cc +++ /dev/null @@ -1,3592 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2016 Stéphane Voltz - - - 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. -*/ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_gl124.h" - -#include - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool gl124_get_fast_feed_bit(Genesys_Register_Set* regs) -{ - return (bool)(regs->get8(REG02) & REG02_FASTFED); -} - -static SANE_Bool gl124_get_filter_bit(Genesys_Register_Set* regs) -{ - return (bool)(regs->get8(REG04) & REG04_FILTER); -} - -static SANE_Bool gl124_get_lineart_bit(Genesys_Register_Set* regs) -{ - return (bool)(regs->get8(REG04) & REG04_LINEART); -} - -static SANE_Bool gl124_get_bitset_bit(Genesys_Register_Set* regs) -{ - return (bool)(regs->get8(REG04) & REG04_BITSET); -} - -static SANE_Bool gl124_get_gain4_bit (Genesys_Register_Set * regs) -{ - return (bool)(regs->get8(REG06) & REG06_GAIN4); -} - -static SANE_Bool -gl124_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl124_test_motor_flag_bit (SANE_Byte val) -{ - if (val & MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** @brief sensor profile - * search for the database of motor profiles and get the best one. Each - * profile is at a specific dpihw. Use LiDE 110 table by default. - * @param sensor_type sensor id - * @param dpi hardware dpi for the scan - * @param half_ccd flag to signal half ccd mode - * @return a pointer to a Sensor_Profile struct - */ -static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi, int half_ccd) -{ - unsigned int i; - int idx; - - i=0; - idx=-1; - while(i=dpi - && sensors[i].dpi 1) - { - return SANE_TRUE; - } - return SANE_FALSE; -} - -/** @brief set all registers to default values . - * This function is called only once at the beginning and - * fills register startup values for registers reused across scans. - * Those that are rarely modified or not modified are written - * individually. - * @param dev device structure holding register set to initialize - */ -static void -gl124_init_registers (Genesys_Device * dev) -{ - DBGSTART; - - dev->reg.clear(); - - /* default to LiDE 110 */ - SETREG (0x01,0xa2); /* + REG01_SHDAREA */ - SETREG (0x02,0x90); - SETREG (0x03,0x50); - SETREG (0x04,0x03); - SETREG (0x05,0x00); - if(dev->model->ccd_type==CIS_CANONLIDE120) - { - SETREG (0x06,0x50); - SETREG (0x07,0x00); - } - else - { - SETREG (0x03,0x50 & ~REG03_AVEENB); - SETREG (0x06,0x50 | REG06_GAIN4); - } - SETREG (0x09,0x00); - SETREG (0x0a,0xc0); - SETREG (0x0b,0x2a); - SETREG (0x0c,0x12); - SETREG (0x11,0x00); - SETREG (0x12,0x00); - SETREG (0x13,0x0f); - SETREG (0x14,0x00); - SETREG (0x15,0x80); - SETREG (0x16,0x10); - SETREG (0x17,0x04); - SETREG (0x18,0x00); - SETREG (0x19,0x01); - SETREG (0x1a,0x30); - SETREG (0x1b,0x00); - SETREG (0x1c,0x00); - SETREG (0x1d,0x01); - SETREG (0x1e,0x10); - SETREG (0x1f,0x00); - SETREG (0x20,0x15); - SETREG (0x21,0x00); - if(dev->model->ccd_type!=CIS_CANONLIDE120) - { - SETREG (0x22,0x02); - } - else - { - SETREG (0x22,0x14); - } - SETREG (0x23,0x00); - SETREG (0x24,0x00); - SETREG (0x25,0x00); - SETREG (0x26,0x0d); - SETREG (0x27,0x48); - SETREG (0x28,0x00); - SETREG (0x29,0x56); - SETREG (0x2a,0x5e); - SETREG (0x2b,0x02); - SETREG (0x2c,0x02); - SETREG (0x2d,0x58); - SETREG (0x3b,0x00); - SETREG (0x3c,0x00); - SETREG (0x3d,0x00); - SETREG (0x3e,0x00); - SETREG (0x3f,0x02); - SETREG (0x40,0x00); - SETREG (0x41,0x00); - SETREG (0x42,0x00); - SETREG (0x43,0x00); - SETREG (0x44,0x00); - SETREG (0x45,0x00); - SETREG (0x46,0x00); - SETREG (0x47,0x00); - SETREG (0x48,0x00); - SETREG (0x49,0x00); - SETREG (0x4f,0x00); - SETREG (0x52,0x00); - SETREG (0x53,0x02); - SETREG (0x54,0x04); - SETREG (0x55,0x06); - SETREG (0x56,0x04); - SETREG (0x57,0x04); - SETREG (0x58,0x04); - SETREG (0x59,0x04); - SETREG (0x5a,0x1a); - SETREG (0x5b,0x00); - SETREG (0x5c,0xc0); - SETREG (0x5f,0x00); - SETREG (0x60,0x02); - SETREG (0x61,0x00); - SETREG (0x62,0x00); - SETREG (0x63,0x00); - SETREG (0x64,0x00); - SETREG (0x65,0x00); - SETREG (0x66,0x00); - SETREG (0x67,0x00); - SETREG (0x68,0x00); - SETREG (0x69,0x00); - SETREG (0x6a,0x00); - SETREG (0x6b,0x00); - SETREG (0x6c,0x00); - SETREG (0x6e,0x00); - SETREG (0x6f,0x00); - if(dev->model->ccd_type!=CIS_CANONLIDE120) - { - SETREG (0x6d,0xd0); - SETREG (0x71,0x08); - } - else - { - SETREG (0x6d,0x00); - SETREG (0x71,0x1f); - } - SETREG (0x70,0x00); - SETREG (0x72,0x08); - SETREG (0x73,0x0a); - - /* CKxMAP */ - SETREG (0x74,0x00); - SETREG (0x75,0x00); - SETREG (0x76,0x3c); - SETREG (0x77,0x00); - SETREG (0x78,0x00); - SETREG (0x79,0x9f); - SETREG (0x7a,0x00); - SETREG (0x7b,0x00); - SETREG (0x7c,0x55); - - SETREG (0x7d,0x00); - SETREG (0x7e,0x08); - SETREG (0x7f,0x58); - if(dev->model->ccd_type!=CIS_CANONLIDE120) - { - SETREG (0x80,0x00); - SETREG (0x81,0x14); - } - else - { - SETREG (0x80,0x00); - SETREG (0x81,0x10); - } - - /* STRPIXEL */ - SETREG (0x82,0x00); - SETREG (0x83,0x00); - SETREG (0x84,0x00); - /* ENDPIXEL */ - SETREG (0x85,0x00); - SETREG (0x86,0x00); - SETREG (0x87,0x00); - - SETREG (0x88,0x00); - SETREG (0x89,0x65); - SETREG (0x8a,0x00); - SETREG (0x8b,0x00); - SETREG (0x8c,0x00); - SETREG (0x8d,0x00); - SETREG (0x8e,0x00); - SETREG (0x8f,0x00); - SETREG (0x90,0x00); - SETREG (0x91,0x00); - SETREG (0x92,0x00); - SETREG (0x93,0x00); - SETREG (0x94,0x14); - SETREG (0x95,0x30); - SETREG (0x96,0x00); - SETREG (0x97,0x90); - SETREG (0x98,0x01); - SETREG (0x99,0x1f); - SETREG (0x9a,0x00); - SETREG (0x9b,0x80); - SETREG (0x9c,0x80); - SETREG (0x9d,0x3f); - SETREG (0x9e,0x00); - SETREG (0x9f,0x00); - SETREG (0xa0,0x20); - SETREG (0xa1,0x30); - SETREG (0xa2,0x00); - SETREG (0xa3,0x20); - SETREG (0xa4,0x01); - SETREG (0xa5,0x00); - SETREG (0xa6,0x00); - SETREG (0xa7,0x08); - SETREG (0xa8,0x00); - SETREG (0xa9,0x08); - SETREG (0xaa,0x01); - SETREG (0xab,0x00); - SETREG (0xac,0x00); - SETREG (0xad,0x40); - SETREG (0xae,0x01); - SETREG (0xaf,0x00); - SETREG (0xb0,0x00); - SETREG (0xb1,0x40); - SETREG (0xb2,0x00); - SETREG (0xb3,0x09); - SETREG (0xb4,0x5b); - SETREG (0xb5,0x00); - SETREG (0xb6,0x10); - SETREG (0xb7,0x3f); - SETREG (0xb8,0x00); - SETREG (0xbb,0x00); - SETREG (0xbc,0xff); - SETREG (0xbd,0x00); - SETREG (0xbe,0x07); - SETREG (0xc3,0x00); - SETREG (0xc4,0x00); - - /* gamma - SETREG (0xc5,0x00); - SETREG (0xc6,0x00); - SETREG (0xc7,0x00); - SETREG (0xc8,0x00); - SETREG (0xc9,0x00); - SETREG (0xca,0x00); - SETREG (0xcb,0x00); - SETREG (0xcc,0x00); - SETREG (0xcd,0x00); - SETREG (0xce,0x00); - */ - if(dev->model->ccd_type==CIS_CANONLIDE120) - { - SETREG (0xc5,0x20); - SETREG (0xc6,0xeb); - SETREG (0xc7,0x20); - SETREG (0xc8,0xeb); - SETREG (0xc9,0x20); - SETREG (0xca,0xeb); - } - - /* memory layout - SETREG (0xd0,0x0a); - SETREG (0xd1,0x1f); - SETREG (0xd2,0x34); */ - SETREG (0xd3,0x00); - SETREG (0xd4,0x00); - SETREG (0xd5,0x00); - SETREG (0xd6,0x00); - SETREG (0xd7,0x00); - SETREG (0xd8,0x00); - SETREG (0xd9,0x00); - - /* memory layout - SETREG (0xe0,0x00); - SETREG (0xe1,0x48); - SETREG (0xe2,0x15); - SETREG (0xe3,0x90); - SETREG (0xe4,0x15); - SETREG (0xe5,0x91); - SETREG (0xe6,0x2a); - SETREG (0xe7,0xd9); - SETREG (0xe8,0x2a); - SETREG (0xe9,0xad); - SETREG (0xea,0x40); - SETREG (0xeb,0x22); - SETREG (0xec,0x40); - SETREG (0xed,0x23); - SETREG (0xee,0x55); - SETREG (0xef,0x6b); - SETREG (0xf0,0x55); - SETREG (0xf1,0x6c); - SETREG (0xf2,0x6a); - SETREG (0xf3,0xb4); - SETREG (0xf4,0x6a); - SETREG (0xf5,0xb5); - SETREG (0xf6,0x7f); - SETREG (0xf7,0xfd);*/ - - SETREG (0xf8,0x01); /* other value is 0x05 */ - SETREG (0xf9,0x00); - SETREG (0xfa,0x00); - SETREG (0xfb,0x00); - SETREG (0xfc,0x00); - SETREG (0xff,0x00); - - /* fine tune upon device description */ - dev->reg.find_reg(0x05).value &= ~REG05_DPIHW; - switch (sanei_genesys_find_sensor_any(dev).optical_res) - { - case 600: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; - break; - case 4800: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_4800; - break; - } - - dev->calib_reg = dev->reg; - - DBGCOMPLETED; -} - -/**@brief send slope table for motor movement - * Send slope_table in machine byte order - * @param dev device to send slope table - * @param table_nr index of the slope table in ASIC memory - * Must be in the [0-4] range. - * @param slope_table pointer to 16 bit values array of the slope table - * @param steps number of elemnts in the slope table - */ -static SANE_Status -gl124_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - char msg[10000]; - - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, - table_nr, steps); - - /* sanity check */ - if(table_nr<0 || table_nr>4) - { - DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); - return SANE_STATUS_INVAL; - } - - std::vector table(steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), ",%d", slope_table[i]); - } - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - /* slope table addresses are fixed */ - status = sanei_genesys_write_ahb(dev, 0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: write to AHB failed writing slope table %d (%s)\n", - __func__, table_nr, sane_strstatus (status)); - } - - DBGCOMPLETED; - return status; -} - -/** @brief * Set register values of 'special' ti type frontend - * Registers value are taken from the frontend register data - * set. - * @param dev device owning the AFE - * @param set flag AFE_INIT to specify the AFE must be reset before writing data - * */ -static SANE_Status -gl124_set_ti_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - - DBGSTART; - if (set == AFE_INIT) - { - DBG (DBG_proc, "%s: setting DAC %u\n", __func__, dev->model->dac_type); - - dev->frontend = dev->frontend_initial; - } - - /* start writing to DAC */ - status = sanei_genesys_fe_write_data (dev, 0x00, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* write values to analog frontend */ - for (uint16_t addr = 0x01; addr < 0x04; addr++) - { - status = sanei_genesys_fe_write_data(dev, addr, dev->frontend.regs.get_value(addr)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write reg %d: %s\n", __func__, addr, - sane_strstatus(status)); - return status; - } - } - - status = sanei_genesys_fe_write_data (dev, 0x04, 0x00); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg4: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* these are not really sign for this AFE */ - for (i = 0; i < 3; i++) - { - status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.regs.get_value(0x24 + i)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write reg %d: %s\n", __func__, i+5, - sane_strstatus (status)); - return status; - } - } - - /* close writing to DAC */ - if(dev->model->dac_type == DAC_CANONLIDE120) - { - status = sanei_genesys_fe_write_data (dev, 0x00, 0x01); - } - else - { - status = sanei_genesys_fe_write_data (dev, 0x00, 0x11); - } - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - - return status; -} - - -/* Set values of analog frontend */ -static SANE_Status -gl124_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) -{ - (void) sensor; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - DBG(DBG_proc, "%s (%s)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?"); - - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - dev->frontend = dev->frontend_initial; - } - - RIE (sanei_genesys_read_register (dev, REG0A, &val)); - - /* route to correct analog FE */ - switch ((val & REG0A_SIFSEL)>>REG0AS_SIFSEL) - { - case 3: - status=gl124_set_ti_fe (dev, set); - break; - case 0: - case 1: - case 2: - default: - DBG(DBG_error, "%s: unsupported analog FE 0x%02x\n", __func__, val); - status=SANE_STATUS_INVAL; - break; - } - - DBGCOMPLETED; - return status; -} - - -/**@brief compute exposure to use - * compute the sensor exposure based on target resolution - * @param dev pointer to device description - * @param xres sensor's required resolution - * @param half_ccd flag for half ccd mode - */ -static int gl124_compute_exposure(Genesys_Device *dev, int xres, int half_ccd) -{ - Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, xres, half_ccd); - return sensor_profile->exposure; -} - - -static SANE_Status -gl124_init_motor_regs_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - ScanColorMode scan_mode, - unsigned int flags) -{ - SANE_Status status = SANE_STATUS_GOOD; - int use_fast_fed; - unsigned int lincnt, fast_dpi; - uint16_t scan_table[SLOPE_TABLE_SIZE]; - uint16_t fast_table[SLOPE_TABLE_SIZE]; - int scan_steps,fast_steps,factor; - unsigned int feedl,dist; - uint32_t z1, z2; - float yres; - int min_speed; - unsigned int linesel; - - DBGSTART; - DBG(DBG_info, "%s : scan_exposure_time=%d, scan_yres=%g, scan_step_type=%d, scan_lines=%d, " - "scan_dummy=%d, feed_steps=%d, scan_mode=%d, flags=%x\n", __func__, scan_exposure_time, - scan_yres, scan_step_type, scan_lines, scan_dummy, feed_steps, - static_cast(scan_mode), flags); - - /* we never use fast fed since we do manual feed for the scans */ - use_fast_fed=0; - factor=1; - - /* enforce motor minimal scan speed - * @TODO extend motor struct for this value */ - if (scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - min_speed = 900; - } - else - { - switch(dev->model->motor_type) - { - case MOTOR_CANONLIDE110: - min_speed = 600; - break; - case MOTOR_CANONLIDE120: - min_speed = 900; - break; - default: - min_speed = 900; - break; - } - } - - /* compute min_speed and linesel */ - if(scan_yres 0 */ - if(linesel==0) - { - linesel=1; - yres=scan_yres*2; - } - } - else - { - yres=scan_yres; - linesel=0; - } - - DBG (DBG_io2, "%s: final yres=%f, linesel=%d\n", __func__, yres, linesel); - - lincnt=scan_lines*(linesel+1); - sanei_genesys_set_triple(reg,REG_LINCNT,lincnt); - DBG (DBG_io, "%s: lincnt=%d\n", __func__, lincnt); - - /* compute register 02 value */ - uint8_t r02 = REG02_NOTHOME; - - if (use_fast_fed) { - r02 |= REG02_FASTFED; - } else { - r02 &= ~REG02_FASTFED; - } - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r02 |= REG02_AGOHOME; - - if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - ||(yres>=sensor.optical_res)) - { - r02 |= REG02_ACDCDIS; - } - - reg->set8(REG02, r02); - sanei_genesys_set_motor_power(*reg, true); - - /* SCANFED */ - sanei_genesys_set_double(reg,REG_SCANFED,4); - - /* scan and backtracking slope table */ - sanei_genesys_slope_table(scan_table, - &scan_steps, - yres, - scan_exposure_time, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - motors); - RIE(gl124_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps)); - RIE(gl124_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps)); - - /* STEPNO */ - sanei_genesys_set_double(reg,REG_STEPNO,scan_steps); - - /* fast table */ - fast_dpi=yres; - - /* - if (scan_mode != ScanColorMode::COLOR_SINGLE_PASS) - { - fast_dpi*=3; - } - */ - sanei_genesys_slope_table(fast_table, - &fast_steps, - fast_dpi, - scan_exposure_time, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - motors); - RIE(gl124_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps)); - RIE(gl124_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps)); - - /* FASTNO */ - sanei_genesys_set_double(reg,REG_FASTNO,fast_steps); - - /* FSHDEC */ - sanei_genesys_set_double(reg,REG_FSHDEC,fast_steps); - - /* FMOVNO */ - sanei_genesys_set_double(reg,REG_FMOVNO,fast_steps); - - /* substract acceleration distance from feedl */ - feedl=feed_steps; - feedl<<=scan_step_type; - - dist = scan_steps; - if (flags & MOTOR_FLAG_FEED) - dist *=2; - if (use_fast_fed) - { - dist += fast_steps*2; - } - DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); - - /* get sure we don't use insane value */ - if(distset8_mask(REG1D, linesel, REG1D_LINESEL); - reg->set8(REGA0, (scan_step_type << REGA0S_STEPSEL) | (scan_step_type << REGA0S_FSTPSEL)); - - /* FMOVDEC */ - sanei_genesys_set_double(reg,REG_FMOVDEC,fast_steps); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** @brief copy sensor specific settings - * Set up register set for the given sensor resolution. Values are from the device table - * in genesys_devices.c for registers: - * [0x16 ... 0x1d] - * [0x52 ... 0x5e] - * Other come from the specific device sensor table in genesys_gl124.h: - * 0x18, 0x20, 0x61, 0x98 and - * @param dev device to set up - * @param regs register set to modify - * @param dpi resolution of the sensor during scan - * @param half_ccd flag for half ccd mode - * */ -static void gl124_setup_sensor(Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, int dpi, int half_ccd) -{ - int dpihw; - uint32_t exp; - - DBGSTART; - - // we start at 6, 0-5 is a 16 bits cache for exposure - for (uint16_t addr = 0x16; addr < 0x1e; addr++) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - // skip writing 5d,5e which is AFE address because - // they are not defined in register set */ - for (uint16_t addr = 0x52; addr < 0x52 + 11; addr++) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - /* set EXPDUMMY and CKxMAP */ - dpihw = sanei_genesys_compute_dpihw(dev, sensor, dpi); - Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); - - regs->set8(0x18, sensor_profile->reg18); - regs->set8(0x20, sensor_profile->reg20); - regs->set8(0x61, sensor_profile->reg61); - regs->set8(0x98, sensor_profile->reg98); - if (sensor_profile->reg16 != 0) { - regs->set8(0x16, sensor_profile->reg16); - } - if (sensor_profile->reg70 != 0) { - regs->set8(0x70, sensor_profile->reg70); - } - - - sanei_genesys_set_triple(regs,REG_SEGCNT,sensor_profile->segcnt); - sanei_genesys_set_double(regs,REG_TG0CNT,sensor_profile->tg0cnt); - sanei_genesys_set_double(regs,REG_EXPDMY,sensor_profile->expdummy); - - /* if no calibration has been done, set default values for exposures */ - exp = sensor.exposure.red; - if(exp==0) - { - exp=sensor_profile->expr; - } - sanei_genesys_set_triple(regs,REG_EXPR,exp); - - exp =sensor.exposure.green; - if(exp==0) - { - exp=sensor_profile->expg; - } - sanei_genesys_set_triple(regs,REG_EXPG,exp); - - exp = sensor.exposure.blue; - if(exp==0) - { - exp=sensor_profile->expb; - } - sanei_genesys_set_triple(regs,REG_EXPB,exp); - - sanei_genesys_set_triple(regs,REG_CK1MAP,sensor_profile->ck1map); - sanei_genesys_set_triple(regs,REG_CK3MAP,sensor_profile->ck3map); - sanei_genesys_set_triple(regs,REG_CK4MAP,sensor_profile->ck4map); - - /* order of the sub-segments */ - dev->order=sensor_profile->order; - - DBGCOMPLETED; -} - -/** @brief setup optical related registers - * start and pixels are expressed in optical sensor resolution coordinate - * space. - * @param dev scanner device to use - * @param reg registers to set up - * @param exposure_time exposure time to use - * @param used_res scanning resolution used, may differ from - * scan's one - * @param start logical start pixel coordinate - * @param pixels logical number of pixels to use - * @param channels number of color channels (currently 1 or 3) - * @param depth bit depth of the scan (1, 8 or 16) - * @param half_ccd SANE_TRUE if sensor's timings are such that x coordinates - * must be halved - * @param color_filter color channel to use as gray data - * @param flags optical flags (@see ) - * @return SANE_STATUS_GOOD if OK - */ -static SANE_Status -gl124_init_optical_regs_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int exposure_time, - int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, - ColorFilter color_filter, - int flags) -{ - unsigned int words_per_line, segcnt; - unsigned int startx, endx, used_pixels, segnb; - unsigned int dpiset, cksel, dpihw, factor; - unsigned int bytes; - GenesysRegister *r; - SANE_Status status = SANE_STATUS_GOOD; - uint32_t expmax, exp; - - DBG(DBG_proc, "%s : exposure_time=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", __func__, exposure_time, used_res, start, pixels, channels, depth, - half_ccd, flags); - - /* resolution is divided according to CKSEL */ - r = sanei_genesys_get_address (reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - DBG (DBG_io2, "%s: cksel=%d\n", __func__, cksel); - - /* to manage high resolution device while keeping good - * low resolution scanning speed, we make hardware dpi vary */ - dpihw=sanei_genesys_compute_dpihw(dev, sensor, used_res * cksel); - factor=sensor.optical_res/dpihw; - DBG (DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); - - /* sensor parameters */ - gl124_setup_sensor(dev, sensor, reg, dpihw, half_ccd); - dpiset = used_res * cksel; - - /* start and end coordinate in optical dpi coordinates */ - /* startx = start/cksel + sensor.dummy_pixel; XXX STEF XXX */ - startx = start/cksel; - used_pixels=pixels/cksel; - endx = startx + used_pixels; - - /* pixel coordinate factor correction when used dpihw is not maximal one */ - startx/=factor; - endx/=factor; - used_pixels=endx-startx; - - status = gl124_set_fe(dev, sensor, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set frontend: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, REG01); - r->value &= ~REG01_SCAN; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - r->value &= ~REG01_DVDSET; - } - else - { - r->value |= REG01_DVDSET; - } - r->value &= ~REG01_SCAN; - - r = sanei_genesys_get_address (reg, REG03); - if((dev->model->ccd_type!=CIS_CANONLIDE120)&&(used_res>=600)) - { - r->value &= ~REG03_AVEENB; - DBG (DBG_io, "%s: disabling AVEENB\n", __func__); - } - else - { - r->value |= ~REG03_AVEENB; - DBG (DBG_io, "%s: enabling AVEENB\n", __func__); - } - - sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); - - /* BW threshold */ - RIE (sanei_genesys_write_register (dev, REG114, dev->settings.threshold)); - RIE (sanei_genesys_write_register (dev, REG115, dev->settings.threshold)); - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, REG04); - switch (depth) - { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - r->value &= ~REG04_FILTER; - if (channels == 1) - { - switch (color_filter) - { - case ColorFilter::RED: - r->value |= 0x10; - break; - case ColorFilter::BLUE: - r->value |= 0x30; - break; - case ColorFilter::GREEN: - r->value |= 0x20; - break; - default: - break; // should not happen - } - } - - /* register 05 */ - r = sanei_genesys_get_address (reg, REG05); - - /* set up dpihw */ - r->value &= ~REG05_DPIHW; - switch(dpihw) - { - case 600: - r->value |= REG05_DPIHW_600; - break; - case 1200: - r->value |= REG05_DPIHW_1200; - break; - case 2400: - r->value |= REG05_DPIHW_2400; - break; - case 4800: - r->value |= REG05_DPIHW_4800; - break; - } - - /* enable gamma tables */ - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - if(half_ccd) - { - sanei_genesys_set_double(reg,REG_DPISET,dpiset*2); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset*2); - } - else - { - sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); - } - - r = sanei_genesys_get_address (reg, REG06); - r->value |= REG06_GAIN4; - - /* CIS scanners can do true gray by setting LEDADD */ - /* we set up LEDADD only when asked */ - if (dev->model->is_cis == SANE_TRUE) - { - r = sanei_genesys_get_address (reg, REG60); - r->value &= ~REG60_LEDADD; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG60_LEDADD; - sanei_genesys_get_triple(reg,REG_EXPR,&expmax); - sanei_genesys_get_triple(reg,REG_EXPG,&exp); - if(exp>expmax) - { - expmax=exp; - } - sanei_genesys_get_triple(reg,REG_EXPB,&exp); - if(exp>expmax) - { - expmax=exp; - } - sanei_genesys_set_triple(&dev->reg,REG_EXPR,expmax); - sanei_genesys_set_triple(&dev->reg,REG_EXPG,expmax); - sanei_genesys_set_triple(&dev->reg,REG_EXPB,expmax); - } - /* RGB weighting, REG_TRUER,G and B are to be set */ - r = sanei_genesys_get_address (reg, 0x01); - r->value &= ~REG01_TRUEGRAY; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG01_TRUEGRAY; - sanei_genesys_write_register (dev, REG_TRUER, 0x80); - sanei_genesys_write_register (dev, REG_TRUEG, 0x80); - sanei_genesys_write_register (dev, REG_TRUEB, 0x80); - } - } - - /* segment number */ - r = sanei_genesys_get_address (reg, 0x98); - segnb = r->value & 0x0f; - - sanei_genesys_set_triple(reg,REG_STRPIXEL,startx/segnb); - DBG (DBG_io2, "%s: strpixel used=%d\n", __func__, startx/segnb); - sanei_genesys_get_triple(reg,REG_SEGCNT,&segcnt); - if(endx/segnb==segcnt) - { - endx=0; - } - sanei_genesys_set_triple(reg,REG_ENDPIXEL,endx/segnb); - DBG (DBG_io2, "%s: endpixel used=%d\n", __func__, endx/segnb); - - /* words(16bit) before gamma, conversion to 8 bit or lineart */ - words_per_line = (used_pixels * dpiset) / dpihw; - bytes = depth / 8; - if (depth == 1) - { - words_per_line = (words_per_line >> 3) + ((words_per_line & 7) ? 1 : 0); - } - else - { - words_per_line *= bytes; - } - - dev->bpl = words_per_line; - dev->cur = 0; - dev->skip = 0; - dev->len = dev->bpl/segnb; - dev->dist = dev->bpl/segnb; - dev->segnb = segnb; - dev->line_count = 0; - dev->line_interp = 0; - - DBG (DBG_io2, "%s: used_pixels =%d\n", __func__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->line_interp=%lu\n", __func__, (unsigned long)dev->line_interp); - - words_per_line *= channels; - dev->wpl = words_per_line; - - /* allocate buffer for odd/even pixels handling */ - dev->oe_buffer.clear(); - dev->oe_buffer.alloc(dev->wpl); - - /* MAXWD is expressed in 2 words unit */ - sanei_genesys_set_triple(reg,REG_MAXWD,(words_per_line)); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); - - sanei_genesys_set_triple(reg,REG_LPERIOD,exposure_time); - DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); - - sanei_genesys_set_double(reg,REG_DUMMY,sensor.dummy_pixel); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -static SANE_Status -gl124_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set* reg, - SetupParams& params) -{ - params.assert_valid(); - - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; - unsigned int oflags, mflags; /**> optical and motor flags */ - int exposure_time; - int stagger; - - int dummy = 0; - int slope_dpi = 0; - int scan_step_type = 1; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - unsigned optical_res; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - - half_ccd=compute_half_ccd(sensor, params.xres); - - /* optical_res */ - optical_res = sensor.optical_res; - if (half_ccd) - optical_res /= 2; - DBG (DBG_info, "%s: optical_res=%d\n", __func__, optical_res); - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "gl124_init_scan_regs : stagger=%d lines\n", stagger); - - /** @brief compute used resolution */ - if (params.flags & SCAN_FLAG_USE_OPTICAL_RES) - { - used_res = optical_res; - } - else - { - /* resolution is choosen from a fixed list and can be used directly, - * unless we have ydpi higher than sensor's maximum one */ - if(params.xres>optical_res) - used_res=optical_res; - else - used_res = params.xres; - } - - /* compute scan parameters values */ - /* pixels are allways given at full optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - /* add x coordinates */ - start = params.startx; - - if (stagger > 0) - start |= 1; - - /* compute correct pixels number */ - used_pixels = (params.pixels * optical_res) / params.xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); - - /* round up pixels number if needed */ - if (used_pixels * params.xres < params.pixels * optical_res) - used_pixels++; - - /* we want even number of pixels here */ - if(used_pixels & 1) - used_pixels++; - - /* slope_dpi */ - /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = params.yres * params.channels; - else - slope_dpi = params.yres; - - /* scan_step_type */ - if(params.flags & SCAN_FLAG_FEEDING) - { - scan_step_type=0; - exposure_time=MOVE_EXPOSURE; - } - else - { - exposure_time = gl124_compute_exposure (dev, used_res, half_ccd); - scan_step_type = sanei_genesys_compute_step_type(motors, dev->model->motor_type, exposure_time); - } - - DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); - - /*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if (params.flags & SCAN_FLAG_DYNAMIC_LINEART) { - params.depth = 8; - } - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - oflags = 0; - if (params.flags & SCAN_FLAG_DISABLE_SHADING) - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - if (params.flags & SCAN_FLAG_DISABLE_GAMMA) - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - if (params.flags & SCAN_FLAG_DISABLE_LAMP) - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - if (params.flags & SCAN_FLAG_CALIBRATION) - oflags |= OPTICAL_FLAG_DISABLE_DOUBLE; - - if (dev->model->is_cis && dev->settings.true_gray) - { - oflags |= OPTICAL_FLAG_ENABLE_LEDADD; - } - - /* now _LOGICAL_ optical values used are known, setup registers */ - status = gl124_init_optical_regs_scan (dev, - sensor, - reg, - exposure_time, - used_res, - start, - used_pixels, - params.channels, - params.depth, - half_ccd, - params.color_filter, - oflags); - if (status != SANE_STATUS_GOOD) - return status; - - /*** motor parameters ***/ - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,params.channels,params.yres,params.flags); - - /* lines to scan */ - lincnt = params.lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = params.starty; - DBG(DBG_info, "%s: move=%d steps\n", __func__, move); - - mflags=0; - if(params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) - mflags|=MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; - if(params.flags & SCAN_FLAG_FEEDING) - mflags|=MOTOR_FLAG_FEED; - - status = gl124_init_motor_regs_scan (dev, sensor, - reg, - exposure_time, - slope_dpi, - scan_step_type, - dev->model->is_cis ? lincnt * params.channels : lincnt, - dummy, - move, - params.scan_mode, - mflags); - if (status != SANE_STATUS_GOOD) - return status; - - /*** prepares data reordering ***/ - - /* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * params.channels * params.depth) / 8; - - /* since we don't have sheetfed scanners to handle, - * use huge read buffer */ - /* TODO find the best size according to settings */ - requested_buffer_size = 16 * bytes_per_line; - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * params.channels * params.depth) / 8; - - dev->read_buffer.clear(); - dev->read_buffer.alloc(read_buffer_size); - - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(read_buffer_size); - - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(requested_buffer_size); - - dev->out_buffer.clear(); - dev->out_buffer.alloc((8 * dev->settings.pixels * params.channels * params.depth) / 8); - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG(DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - dev->total_bytes_read = 0; - if (params.depth == 1) - dev->total_bytes_to_read = - ((dev->settings.pixels * dev->settings.lines) / 8 + - (((dev->settings.pixels * dev->settings.lines) % 8) ? 1 : 0)) * - params.channels; - else - dev->total_bytes_to_read = - dev->settings.pixels * dev->settings.lines * params.channels * (params.depth / 8); - - DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static void -gl124_calculate_current_setup (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int depth; - int start; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure_time; - int stagger; - SANE_Bool half_ccd; - - int max_shift, dpihw; - - int optical_res; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - /* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * sensor.optical_res) / MM_PER_INCH; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; - params.starty = 0; // not used - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = 0; - - half_ccd=compute_half_ccd(sensor, params.xres); - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - - /* optical_res */ - optical_res = sensor.optical_res; - - if (params.xres <= (unsigned) optical_res) - used_res = params.xres; - else - used_res=optical_res; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - - /* compute correct pixels number */ - used_pixels = (params.pixels * optical_res) / params.xres; - DBG (DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); - - /* exposure */ - exposure_time = gl124_compute_exposure (dev, params.xres, half_ccd); - DBG (DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); - - /* compute hw dpi for sensor */ - dpihw=sanei_genesys_compute_dpihw(dev, sensor,used_res); - - Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); - dev->segnb=sensor_profile->reg98 & 0x0f; - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG (DBG_info, "%s: stagger=%d lines\n", __func__, stagger); - - /* lincnt */ - lincnt = params.lines + max_shift + stagger; - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG (DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBGCOMPLETED; -} - -/** - * for fast power saving methods only, like disabling certain amplifiers - * @param dev device to use - * @param enable true to set inot powersaving - * */ -static SANE_Status -gl124_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl124_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - GenesysRegister *r; - - DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); - - r = sanei_genesys_get_address (&dev->reg, REG03); - r->value &= ~0xf0; - if(delay<15) - { - r->value |= delay; - } - else - { - r->value |= 0x0f; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl124_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -static SANE_Status -gl124_stop_action (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val40, val; - unsigned int loop; - - DBGSTART; - - /* post scan gpio : without that HOMSNR is unreliable */ - gl124_homsnr_gpio(dev); - - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - status = sanei_genesys_read_register (dev, REG100, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read reg100: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG100_DATAENB) && !(val40 & REG100_MOTMFLG)) - { - DBG (DBG_info, "%s: already stopped\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* ends scan */ - val = dev->reg.get8(REG01); - val &= ~REG01_SCAN; - dev->reg.set8(REG01, val); - status = sanei_genesys_write_register (dev, REG01, val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write register 01: %s\n", __func__, - sane_strstatus (status)); - return status; - } - sanei_genesys_sleep_ms(100); - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - status = sanei_genesys_read_register (dev, REG100, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG100_DATAENB) && !(val40 & REG100_MOTMFLG) - && !(val & MOTORENB)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - sanei_genesys_sleep_ms(100); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - - -/** @brief setup GPIOs for scan - * Setup GPIO values to drive motor (or light) needed for the - * target resolution - * @param *dev device to set up - * @param resolution dpi of the target scan - * @return SANE_STATUS_GOOD unless REG32 cannot be read - */ -static SANE_Status -gl124_setup_scan_gpio(Genesys_Device *dev, int resolution) -{ -SANE_Status status = SANE_STATUS_GOOD; -uint8_t val; - - DBGSTART; - RIE (sanei_genesys_read_register (dev, REG32, &val)); - - /* LiDE 110, 210 and 220 cases */ - if(dev->model->gpo_type != GPO_CANONLIDE120) - { - if(resolution>=dev->motor.base_ydpi/2) - { - val &= 0xf7; - } - else if(resolution>=dev->motor.base_ydpi/4) - { - val &= 0xef; - } - else - { - val |= 0x10; - } - } - /* 120 : <=300 => 0x53 */ - else - { /* base_ydpi is 4800 */ - if(resolution<=300) - { - val &= 0xf7; - } - else if(resolution<=600) - { - val |= 0x08; - } - else if(resolution<=1200) - { - val &= 0xef; - val |= 0x08; - } - else - { - val &= 0xf7; - } - } - val |= 0x02; - RIE (sanei_genesys_write_register (dev, REG32, val)); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Send the low-level scan command */ -/* todo : is this that useful ? */ -static SANE_Status -gl124_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - (void) sensor; - - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - DBGSTART; - if (reg == NULL) - return SANE_STATUS_INVAL; - - /* set up GPIO for scan */ - RIE(gl124_setup_scan_gpio(dev,dev->settings.yres)); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* enable scan and motor */ - RIE (sanei_genesys_read_register (dev, REG01, &val)); - val |= REG01_SCAN; - RIE (sanei_genesys_write_register (dev, REG01, val)); - - if (start_motor) - { - RIE (sanei_genesys_write_register (dev, REG0F, 1)); - } - else - { - RIE (sanei_genesys_write_register (dev, REG0F, 0)); - } - - DBGCOMPLETED; - return status; -} - - -/* Send the stop scan command */ -static SANE_Status -gl124_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); - if (reg == NULL) - return SANE_STATUS_INVAL; - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl124_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - - -/** rewind scan - * Move back by the same amount of distance than previous scan. - * @param dev device to rewind - * @returns SANE_STATUS_GOOD on success - */ -static -SANE_Status gl124_rewind(Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t byte; - - DBGSTART; - - /* set motor reverse */ - RIE (sanei_genesys_read_register (dev, 0x02, &byte)); - byte |= 0x04; - RIE (sanei_genesys_write_register(dev, 0x02, byte)); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - /* and start scan, then wait completion */ - RIE (gl124_begin_scan (dev, sensor, &dev->reg, SANE_TRUE)); - do - { - sanei_genesys_sleep_ms(100); - RIE (sanei_genesys_read_register (dev, REG100, &byte)); - } - while(byte & REG100_MOTMFLG); - RIE (gl124_end_scan (dev, &dev->reg, SANE_TRUE)); - - /* restore direction */ - RIE (sanei_genesys_read_register (dev, 0x02, &byte)); - byte &= 0xfb; - RIE (sanei_genesys_write_register(dev, 0x02, byte)); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** Park head - * Moves the slider to the home (top) position slowly - * @param dev device to park - * @param wait_until_home true to make the function waiting for head - * to be home before returning, if fals returne immediately - * @returns SANE_STATUS_GOO on success */ -static -SANE_Status -gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - uint8_t val; - float resolution; - int loop = 0; - - DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); - - /* post scan gpio : without that HOMSNR is unreliable */ - gl124_homsnr_gpio(dev); - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - sanei_genesys_sleep_ms(100); - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - /* is sensor at home? */ - if (val & HOMESNR) - { - DBG (DBG_info, "%s: already at home, completed\n", __func__); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* feed a little first */ - if (dev->model->model_id == MODEL_CANON_LIDE_210) - { - status = gl124_feed (dev, 20, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to do initial feed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - local_reg = dev->reg; - resolution=sanei_genesys_get_lowest_dpi(dev); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 100; - params.starty = 30000; - params.pixels = 100; - params.lines = 100; - params.depth = 8; - params.channels = 1; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::RED; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl124_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse and no scan */ - r = sanei_genesys_get_address(&local_reg, REG02); - r->value |= REG02_MTRREV; - - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - - RIE(gl124_setup_scan_gpio(dev,resolution)); - - try { - status = gl124_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl124_stop_action (dev); - } catch (...) {} - try { - // restore original registers - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - if (status != SANE_STATUS_GOOD) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl124_stop_action (dev); - } catch (...) {} - /* restore original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - /* post scan gpio : without that HOMSNR is unreliable */ - gl124_homsnr_gpio(dev); - - if (wait_until_home) - { - - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - if (val & HOMESNR) /* home sensor */ - { - DBG(DBG_info, "%s: reached home position\n", __func__); - DBGCOMPLETED; - dev->scanhead_position_in_steps = 0; - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl124_stop_action (dev); - DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - DBG(DBG_info, "%s: scanhead is still moving\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move - * @param reverse true is moving backward - * */ -static SANE_Status -gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - float resolution; - uint8_t val; - - DBGSTART; - DBG (DBG_io, "%s: steps=%d\n", __func__, steps); - - /* prepare local registers */ - local_reg = dev->reg; - - resolution=sanei_genesys_get_lowest_ydpi(dev); - const auto& sensor = sanei_genesys_find_sensor(dev, resolution); - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 0; - params.starty = steps; - params.pixels = 100; - params.lines = 3; - params.depth = 8; - params.channels = 3; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_FEEDING | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl124_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus (status)); - DBGCOMPLETED; - return status; - } - - /* set exposure to zero */ - sanei_genesys_set_triple(&local_reg,REG_EXPR,0); - sanei_genesys_set_triple(&local_reg,REG_EXPG,0); - sanei_genesys_set_triple(&local_reg,REG_EXPB,0); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); - - /* set up for no scan */ - r = sanei_genesys_get_address (&local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* set up for reverse if needed */ - if(reverse) - { - r = sanei_genesys_get_address (&local_reg, REG02); - r->value |= REG02_MTRREV; - } - - /* send registers */ - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - - status = gl124_start_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); - gl124_stop_action (dev); - - /* restore original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - /* wait until feed count reaches the required value, but do not - * exceed 30s */ - do - { - status = sanei_genesys_get_status (dev, &val); - } - while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); - - /* then stop scanning */ - RIE(gl124_stop_action (dev)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl124_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg = dev->reg; - int steps; - - int pixels = 600; - int dpi = 300; - - DBGSTART; - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - // FIXME: the current approach of doing search only for one resolution does not work on scanners - // whith employ different sensors with potentially different settings. - auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); - - SetupParams params; - params.xres = dpi; - params.yres = dpi; - params.startx = 0; - params.starty = 0; /*we should give a small offset here~60 steps */ - params.pixels = 600; - params.lines = dev->model->search_lines; - params.depth = 8; - params.channels = 1; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::GREEN; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; - - status = gl124_init_scan_regs(dev, sensor, &local_reg, params); - - if (status!=SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to init scan registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* send to scanner */ - status = dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - size = pixels * dev->model->search_lines; - - std::vector data(size); - - status = gl124_begin_scan (dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl124_search_position.pnm", data.data(), 8, 1, pixels, - dev->model->search_lines); - - status = gl124_end_scan (dev, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* update regs to copy ASIC internal state */ - dev->reg = local_reg; - - status = - sanei_genesys_search_reference_point (dev, sensor, data.data(), 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl124_init_regs_for_coarse_calibration(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t channels; - uint8_t cksel; - - DBGSTART; - cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) { - channels = 3; - } else { - channels = 1; - } - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = 0; - params.starty = 0; - params.pixels = sensor.optical_res / cksel; - params.lines = 20; - params.depth = 16; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_FEEDING | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl124_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_set_motor_power(regs, false); - - DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, - sensor.optical_res / cksel, dev->settings.xres); - - status = dev->model->cmd_set->bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -/* shading calibration is done at dpihw */ -static SANE_Status -gl124_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - int move, resolution, dpihw, factor; - - DBGSTART; - - /* initial calibration reg values */ - regs = dev->reg; - - dev->calib_channels = 3; - dev->calib_lines = dev->model->shading_lines; - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); - if(dpihw>=2400) - { - dev->calib_lines *= 2; - } - resolution=dpihw; - - /* if half CCD mode, use half resolution */ - if(compute_half_ccd(sensor, dev->settings.xres)==SANE_TRUE) - { - resolution /= 2; - dev->calib_lines /= 2; - } - dev->calib_resolution = resolution; - dev->calib_total_bytes_to_read = 0; - factor=sensor.optical_res/resolution; - dev->calib_pixels = sensor.sensor_pixels/factor; - - /* distance to move to reach white target at high resolution */ - move=0; - if(dev->settings.yres>=1200) - { - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; - } - DBG (DBG_io, "%s: move=%d steps\n", __func__, move); - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 0; - params.starty = move; - params.pixels = dev->calib_pixels; - params.lines = dev->calib_lines; - params.depth = 16; - params.channels = dev->calib_channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = ColorFilter::RED; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl124_init_scan_regs(dev, sensor, ®s, params); - - sanei_genesys_set_motor_power(regs, false); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - dev->scanhead_position_in_steps += dev->calib_lines + move; - - status = dev->model->cmd_set->bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to bulk write registers: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static void gl124_wait_for_motor_stop(Genesys_Device* dev) -{ - DBG_HELPER(dbg); - uint8_t val40, val; - - TIE(sanei_genesys_get_status(dev, &val)); - TIE(sanei_genesys_read_register(dev, REG100, &val40)); - - if ((val & MOTORENB) == 0 && (val40 & REG100_MOTMFLG) == 0) - return; - - do { - sanei_genesys_sleep_ms(10); - TIE(sanei_genesys_get_status(dev, &val)); - TIE(sanei_genesys_read_register(dev, REG100, &val40)); - } while ((val & MOTORENB) ||(val40 & REG100_MOTMFLG)); - sanei_genesys_sleep_ms(50); -} - -/** @brief set up registers for the actual scan - */ -static SANE_Status -gl124_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - /* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - /* y (motor) distance to move to reach scanned area */ - move_dpi = dev->motor.base_ydpi/4; - move = SANE_UNFIX (dev->model->y_offset); - move += dev->settings.tl_y; - move = (move * move_dpi) / MM_PER_INCH; - DBG (DBG_info, "%s: move=%f steps\n", __func__, move); - - if(channels*dev->settings.yres>=600 && move>700) - { - status = gl124_feed (dev, move-500, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to move to scan area\n",__func__); - return status; - } - move=500; - } - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - if(compute_half_ccd(sensor, dev->settings.xres)==SANE_TRUE) - { - start /=2; - } - start = (start * sensor.optical_res) / MM_PER_INCH; - - flags = 0; - - /* enable emulated lineart from gray data */ - if(dev->settings.scan_mode == ScanColorMode::LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; - params.starty = move; - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = flags; - - status = gl124_init_scan_regs(dev, sensor, &dev->reg, params); - - if (status != SANE_STATUS_GOOD) - return status; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -static SANE_Status -gl124_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t addr, length, strpixel ,endpixel, x, factor, segcnt, pixels, i; - uint32_t lines, channels; - uint16_t dpiset,dpihw; - uint8_t val,*ptr,*src; - - DBGSTART; - DBG( DBG_io2, "%s: writing %d bytes of shading data\n",__func__,size); - - /* logical size of a color as seen by generic code of the frontend */ - length = (uint32_t) (size / 3); - sanei_genesys_get_triple(&dev->reg,REG_STRPIXEL,&strpixel); - sanei_genesys_get_triple(&dev->reg,REG_ENDPIXEL,&endpixel); - sanei_genesys_get_triple(&dev->reg,REG_SEGCNT,&segcnt); - if(endpixel==0) - { - endpixel=segcnt; - } - DBG( DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, SEGCNT=%d\n",__func__,strpixel,endpixel,endpixel-strpixel,segcnt); - - /* compute deletion factor */ - sanei_genesys_get_double(&dev->reg,REG_DPISET,&dpiset); - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpiset); - factor=dpihw/dpiset; - DBG( DBG_io2, "%s: factor=%d\n",__func__,factor); - - /* binary data logging */ - if(DBG_LEVEL>=DBG_data) - { - dev->binary=fopen("binary.pnm","wb"); - sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &lines); - channels=dev->current_setup.channels; - if(dev->binary!=NULL) - { - fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels*dev->segnb,lines/channels,255); - } - } - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; /* 2 words of 2 bytes */ - endpixel*=2*2; - segcnt*=2*2; - pixels=endpixel-strpixel; - - DBG( DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n",__func__,length, length/4); - std::vector buffer(pixels * dev->segnb, 0); - - /* write actual red data */ - for(i=0;i<3;i++) - { - /* copy data to work buffer and process it */ - /* coefficent destination */ - ptr = buffer.data(); - - /* iterate on both sensor segment */ - for(x=0;xsegnb) - { - case 1: - ptr[0+pixels*0]=src[0+segcnt*0]; - ptr[1+pixels*0]=src[1+segcnt*0]; - ptr[2+pixels*0]=src[2+segcnt*0]; - ptr[3+pixels*0]=src[3+segcnt*0]; - break; - case 2: - ptr[0+pixels*0]=src[0+segcnt*0]; - ptr[1+pixels*0]=src[1+segcnt*0]; - ptr[2+pixels*0]=src[2+segcnt*0]; - ptr[3+pixels*0]=src[3+segcnt*0]; - ptr[0+pixels*1]=src[0+segcnt*1]; - ptr[1+pixels*1]=src[1+segcnt*1]; - ptr[2+pixels*1]=src[2+segcnt*1]; - ptr[3+pixels*1]=src[3+segcnt*1]; - break; - case 4: - ptr[0+pixels*0]=src[0+segcnt*0]; - ptr[1+pixels*0]=src[1+segcnt*0]; - ptr[2+pixels*0]=src[2+segcnt*0]; - ptr[3+pixels*0]=src[3+segcnt*0]; - ptr[0+pixels*1]=src[0+segcnt*2]; - ptr[1+pixels*1]=src[1+segcnt*2]; - ptr[2+pixels*1]=src[2+segcnt*2]; - ptr[3+pixels*1]=src[3+segcnt*2]; - ptr[0+pixels*2]=src[0+segcnt*1]; - ptr[1+pixels*2]=src[1+segcnt*1]; - ptr[2+pixels*2]=src[2+segcnt*1]; - ptr[3+pixels*2]=src[3+segcnt*1]; - ptr[0+pixels*3]=src[0+segcnt*3]; - ptr[1+pixels*3]=src[1+segcnt*3]; - ptr[2+pixels*3]=src[2+segcnt*3]; - ptr[3+pixels*3]=src[3+segcnt*3]; - break; - } - - /* next shading coefficient */ - ptr+=4; - } - RIE (sanei_genesys_read_register (dev, 0xd0+i, &val)); - addr = val * 8192 + 0x10000000; - status = sanei_genesys_write_ahb(dev, addr, pixels*dev->segnb, buffer.data()); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s; write to AHB failed (%s)\n", __func__, sane_strstatus(status)); - return status; - } - } - - DBGCOMPLETED; - - return status; -} - - -/** @brief move to calibration area - * This functions moves scanning head to calibration area - * by doing a 600 dpi scan - * @param dev scanner device - * @return SANE_STATUS_GOOD on success, else the error code - */ -static SANE_Status -move_to_calibration_area (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - int pixels; - int size; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - pixels = (sensor.sensor_pixels*600)/sensor.optical_res; - - /* initial calibration reg values */ - regs = dev->reg; - - SetupParams params; - params.xres = 600; - params.yres = 600; - params.startx = 0; - params.starty = 0; - params.pixels = pixels; - params.lines = 1; - params.depth = 8; - params.channels = 3; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl124_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - size = pixels * 3; - std::vector line(size); - - /* write registers and scan data */ - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - - DBG (DBG_info, "%s: starting line reading\n", __func__); - RIE(gl124_begin_scan (dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), size)); - - /* stop scanning */ - RIE(gl124_stop_action (dev)); - - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file("gl124_movetocalarea.pnm", line.data(), 8, 3, pixels, 1); - } - - DBGCOMPLETED; - return status; -} - -/* this function does the led calibration by scanning one line of the calibration - area below scanner's top on white strip. - --needs working coarse/gain -*/ -static SANE_Status -gl124_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs) -{ - int num_pixels; - int total_size; - int resolution; - int dpihw; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels, depth; - int avg[3]; - int turn; - uint16_t exp[3],target; - SANE_Bool acceptable; - SANE_Bool half_ccd; - - DBGSTART; - - /* move to calibration area */ - move_to_calibration_area(dev, sensor, regs); - - /* offset calibration is always done in 16 bit depth color mode */ - channels = 3; - depth=16; - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); - half_ccd=compute_half_ccd(sensor, dev->settings.xres); - if(half_ccd==SANE_TRUE) - { - resolution = dpihw/2; - } - else - { - resolution = dpihw; - } - Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw, half_ccd); - num_pixels = (sensor.sensor_pixels*resolution)/sensor.optical_res; - - /* initial calibration reg values */ - regs = dev->reg; - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 0; - params.starty = 0; - params.pixels = num_pixels; - params.lines = 1; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl124_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus (status)); - return status; - } - - total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ - std::vector line(total_size); - - /* initial loop values and boundaries */ - exp[0]=sensor_profile->expr; - exp[1]=sensor_profile->expg; - exp[2]=sensor_profile->expb; - target=sensor.gain_white_ref*256; - - turn = 0; - - /* no move during led calibration */ - sanei_genesys_set_motor_power(regs, false); - do - { - /* set up exposure */ - sanei_genesys_set_triple(®s,REG_EXPR,exp[0]); - sanei_genesys_set_triple(®s,REG_EXPG,exp[1]); - sanei_genesys_set_triple(®s,REG_EXPB,exp[2]); - - /* write registers and scan data */ - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - - DBG(DBG_info, "%s: starting line reading\n", __func__); - RIE(gl124_begin_scan (dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, line.data(), total_size)); - - /* stop scanning */ - RIE(gl124_stop_action (dev)); - - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl124_led_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), depth, channels, num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - /* check if exposure gives average within the boundaries */ - acceptable = SANE_TRUE; - for(i=0;i<3;i++) - { - /* we accept +- 2% delta from target */ - if(abs(avg[i]-target)>target/50) - { - exp[i]=(exp[i]*target)/avg[i]; - acceptable = SANE_FALSE; - } - } - - turn++; - } - while (!acceptable && turn < 100); - - DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); - - /* set these values as final ones for scan */ - sanei_genesys_set_triple(&dev->reg,REG_EXPR,exp[0]); - sanei_genesys_set_triple(&dev->reg,REG_EXPG,exp[1]); - sanei_genesys_set_triple(&dev->reg,REG_EXPB,exp[2]); - - /* store in this struct since it is the one used by cache calibration */ - sensor.exposure.red = exp[0]; - sensor.exposure.green = exp[1]; - sensor.exposure.blue = exp[2]; - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a 8 bits scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black) -{ - unsigned int i, j, k, average, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average value on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG(DBG_info, "%s: average = %d\n", __func__, average); - return average; -} - - -static SANE_Status -gl124_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t reg0a; - unsigned int channels, bpp; - int pass = 0, avg, total_size; - int topavg, bottomavg, resolution, lines; - int top, bottom, black_pixels, pixels; - - DBGSTART; - - /* no gain nor offset for TI AFE */ - RIE (sanei_genesys_read_register (dev, REG0A, ®0a)); - if(((reg0a & REG0A_SIFSEL)>>REG0AS_SIFSEL)==3) - { - DBGCOMPLETED; - return status; - } - - /* offset calibration is always done in color mode */ - channels = 3; - resolution=sensor.optical_res; - dev->calib_pixels = sensor.sensor_pixels; - lines=1; - bpp=8; - pixels= (sensor.sensor_pixels*resolution) / sensor.optical_res; - black_pixels = (sensor.black_pixels * resolution) / sensor.optical_res; - DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 0; - params.starty = 0; - params.pixels = pixels; - params.lines = lines; - params.depth = bpp; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl124_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_set_motor_power(regs, false); - - /* allocate memory for scans */ - total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ - - std::vector first_line(total_size); - std::vector second_line(total_size); - - /* init gain */ - dev->frontend.set_gain(0, 0); - dev->frontend.set_gain(1, 0); - dev->frontend.set_gain(2, 0); - - /* scan with no move */ - bottom = 10; - dev->frontend.set_offset(0, bottom); - dev->frontend.set_offset(1, bottom); - dev->frontend.set_offset(2, bottom); - - RIE(gl124_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting first line reading\n", __func__); - RIE(gl124_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); - if (DBG_LEVEL >= DBG_data) - { - char title[30]; - snprintf(title, 30, "gl124_offset%03d.pnm", bottom); - sanei_genesys_write_pnm_file(title, first_line.data(), bpp, channels, pixels, lines); - } - - bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); - - /* now top value */ - top = 255; - dev->frontend.set_offset(0, top); - dev->frontend.set_offset(1, top); - dev->frontend.set_offset(2, top); - RIE(gl124_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(gl124_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); - - topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.set_offset(0, (top + bottom) / 2); - dev->frontend.set_offset(1, (top + bottom) / 2); - dev->frontend.set_offset(2, (top + bottom) / 2); - - /* scan with no move */ - RIE(gl124_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(gl124_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) - { - char title[30]; - snprintf(title, 30, "gl124_offset%03d.pnm", dev->frontend.get_offset(1)); - sanei_genesys_write_pnm_file(title, second_line.data(), bpp, channels, pixels, lines); - } - - avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.get_offset(1); - } - else - { - bottomavg = avg; - bottom = dev->frontend.get_offset(1); - } - } - DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* alternative coarse gain calibration - this on uses the settings from offset_calibration and - uses only one scanline - */ -/* - with offset and coarse calibration we only want to get our input range into - a reasonable shape. the fine calibration of the upper and lower bounds will - be done with shading. - */ -static SANE_Status -gl124_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, int dpi) -{ - int pixels; - int total_size; - uint8_t reg0a; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3],coeff; - int val, code, lines; - int resolution; - int bpp; - - DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); - - /* no gain nor offset for TI AFE */ - RIE (sanei_genesys_read_register (dev, REG0A, ®0a)); - if(((reg0a & REG0A_SIFSEL)>>REG0AS_SIFSEL)==3) - { - DBGCOMPLETED; - return status; - } - - /* coarse gain calibration is always done in color mode */ - channels = 3; - - /* follow CKSEL */ - if(dev->settings.xressettings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - try { - status = gl124_init_scan_regs(dev, sensor, ®s, params); - } catch (...) { - try { - sanei_genesys_set_motor_power(regs, false); - } catch (...) {} - throw; - } - - sanei_genesys_set_motor_power(regs, false); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - RIE (dev->model->cmd_set->bulk_write_register(dev, regs)); - - total_size = pixels * channels * (16/bpp) * lines; - - std::vector line(total_size); - - RIE(gl124_set_fe(dev, sensor, AFE_SET)); - RIE(gl124_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl124_gain.pnm", line.data(), bpp, channels, pixels, lines); - - /* average value on each channel */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = pixels/4; i < (pixels*3/4); i++) - { - if(bpp==16) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * pixels + 1] * 256 + - line[i * 2 + j * 2 * pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - } - else - { - if (dev->model->is_cis) - val = line[i + j * pixels]; - else - val = line[i * channels + j]; - } - - max[j] += val; - } - max[j] = max[j] / (pixels/2); - - gain[j] = ((float) sensor.gain_white_ref*coeff) / max[j]; - - /* turn logical gain value into gain code, checking for overflow */ - code = 283 - 208 / gain[j]; - if (code > 255) - code = 255; - else if (code < 0) - code = 0; - dev->frontend.set_gain(j, code); - - DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], - gain[j], dev->frontend.get_gain(j)); - } - - if (dev->model->is_cis) { - uint8_t gain0 = dev->frontend.get_gain(0); - if (gain0 > dev->frontend.get_gain(1)) { - gain0 = dev->frontend.get_gain(1); - } - if (gain0 > dev->frontend.get_gain(2)) { - gain0 = dev->frontend.get_gain(2); - } - dev->frontend.set_gain(0, gain0); - dev->frontend.set_gain(1, gain0); - dev->frontend.set_gain(2, gain0); - } - - if (channels == 1) { - dev->frontend.set_gain(0, dev->frontend.get_gain(1)); - dev->frontend.set_gain(2, dev->frontend.get_gain(1)); - } - - RIE (gl124_stop_action (dev)); - - status = gl124_slow_back_home (dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - -/* - * wait for lamp warmup by scanning the same line until difference - * between 2 scans is below a threshold - */ -static SANE_Status -gl124_init_regs_for_warmup (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - int *channels, int *total_size) -{ - int num_pixels; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - if (dev == NULL || reg == NULL || channels == NULL || total_size == NULL) - return SANE_STATUS_INVAL; - - *channels=3; - - *reg = dev->reg; - - SetupParams params; - params.xres = sensor.optical_res; - params.yres = dev->motor.base_ydpi; - params.startx = sensor.sensor_pixels / 4; - params.starty = 0; - params.pixels = sensor.sensor_pixels / 2; - params.lines = 1; - params.depth = 8; - params.channels = *channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl124_init_scan_regs(dev, sensor, reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - num_pixels = dev->current_setup.pixels; - - *total_size = num_pixels * 3 * 1; /* colors * bytes_per_color * scan lines */ - - sanei_genesys_set_motor_power(*reg, false); - RIE (dev->model->cmd_set->bulk_write_register(dev, *reg)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief default GPIO values - * set up GPIO/GPOE for idle state - * @param dev device to set up - * @return SANE_STATUS_GOOD unless a GPIO register cannot be written - */ -static SANE_Status -gl124_init_gpio (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx; - - DBGSTART; - - /* per model GPIO layout */ - if (dev->model->model_id == MODEL_CANON_LIDE_110) - { - idx = 0; - } - else if (dev->model->model_id == MODEL_CANON_LIDE_120) - { - idx = 2; - } - else - { /* canon LiDE 210 and 220 case */ - idx = 1; - } - - RIE (sanei_genesys_write_register (dev, REG31, gpios[idx].r31)); - RIE (sanei_genesys_write_register (dev, REG32, gpios[idx].r32)); - RIE (sanei_genesys_write_register (dev, REG33, gpios[idx].r33)); - RIE (sanei_genesys_write_register (dev, REG34, gpios[idx].r34)); - RIE (sanei_genesys_write_register (dev, REG35, gpios[idx].r35)); - RIE (sanei_genesys_write_register (dev, REG36, gpios[idx].r36)); - RIE (sanei_genesys_write_register (dev, REG38, gpios[idx].r38)); - - DBGCOMPLETED; - return status; -} - -/** - * set memory layout by filling values in dedicated registers - */ -static SANE_Status -gl124_init_memory_layout (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx = 0; - - DBGSTART; - - /* point to per model memory layout */ - if (dev->model->model_id == MODEL_CANON_LIDE_110 ||dev->model->model_id == MODEL_CANON_LIDE_120) - { - idx = 0; - } - else - { /* canon LiDE 210 and 220 case */ - idx = 1; - } - - /* setup base address for shading data. */ - /* values must be multiplied by 8192=0x4000 to give address on AHB */ - /* R-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd0, layouts[idx].rd0); - /* G-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd1, layouts[idx].rd1); - /* B-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd2, layouts[idx].rd2); - - /* setup base address for scanned data. */ - /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ - /* R-Channel ODD image buffer 0x0124->0x92000 */ - /* size for each buffer is 0x16d*1k word */ - sanei_genesys_write_register (dev, 0xe0, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xe1, layouts[idx].re1); - /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ - sanei_genesys_write_register (dev, 0xe2, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xe3, layouts[idx].re3); - - /* R-Channel EVEN image buffer 0x0292 */ - sanei_genesys_write_register (dev, 0xe4, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xe5, layouts[idx].re5); - /* R-Channel EVEN image buffer end-address 0x03ff*/ - sanei_genesys_write_register (dev, 0xe6, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xe7, layouts[idx].re7); - - /* same for green, since CIS, same addresses */ - sanei_genesys_write_register (dev, 0xe8, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xe9, layouts[idx].re1); - sanei_genesys_write_register (dev, 0xea, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xeb, layouts[idx].re3); - sanei_genesys_write_register (dev, 0xec, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xed, layouts[idx].re5); - sanei_genesys_write_register (dev, 0xee, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xef, layouts[idx].re7); - -/* same for blue, since CIS, same addresses */ - sanei_genesys_write_register (dev, 0xf0, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xf1, layouts[idx].re1); - sanei_genesys_write_register (dev, 0xf2, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xf3, layouts[idx].re3); - sanei_genesys_write_register (dev, 0xf4, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xf5, layouts[idx].re5); - sanei_genesys_write_register (dev, 0xf6, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xf7, layouts[idx].re7); - - DBGCOMPLETED; - return status; -} - -/** - * initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -static SANE_Status -gl124_init(Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG_INIT (); - DBGSTART; - - status=sanei_genesys_asic_init(dev, 0); - - DBGCOMPLETED; - return status; -} - - -/* * - * initialize ASIC from power on condition - */ -static SANE_Status -gl124_boot (Genesys_Device * dev, SANE_Bool cold) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - DBGSTART; - - /* reset ASIC in case of cold boot */ - if(cold) - { - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - } - - /* enable GPOE 17 */ - RIE (sanei_genesys_write_register (dev, 0x36, 0x01)); - - /* set GPIO 17 */ - RIE (sanei_genesys_read_register (dev, 0x33, &val)); - val |= 0x01; - RIE (sanei_genesys_write_register (dev, 0x33, val)); - - /* test CHKVER */ - RIE (sanei_genesys_read_register (dev, REG100, &val)); - if (val & REG100_CHKVER) - { - RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); - } - - /* Set default values for registers */ - gl124_init_registers (dev); - - /* Write initial registers */ - RIE (dev->model->cmd_set->bulk_write_register(dev, dev->reg)); - - /* tune reg 0B */ - val = REG0B_30MHZ | REG0B_ENBDRAM | REG0B_64M; - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg.remove_reg(0x0b); - - /* set up end access */ - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0b)); - RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); - - /* CIS_LINE */ - SETREG (0x08, REG08_CIS_LINE); - RIE (sanei_genesys_write_register (dev, 0x08, dev->reg.find_reg(0x08).value)); - - /* setup gpio */ - RIE (gl124_init_gpio (dev)); - - /* setup internal memory layout */ - RIE (gl124_init_memory_layout (dev)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl124_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not loose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val=0; - - RIE (sanei_genesys_read_register (s->dev, REG31, &val)); - - /* TODO : for the next scanner special case, - * add another per scanner button profile struct to avoid growing - * hard-coded button mapping here. - */ - if((s->dev->model->gpo_type == GPO_CANONLIDE110) - ||(s->dev->model->gpo_type == GPO_CANONLIDE120)) - { - s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); - s->buttons[BUTTON_FILE_SW].write((val & 0x08) == 0); - s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); - s->buttons[BUTTON_COPY_SW].write((val & 0x02) == 0); - } - else - { /* LiDE 210 case */ - s->buttons[BUTTON_EXTRA_SW].write((val & 0x01) == 0); - s->buttons[BUTTON_SCAN_SW].write((val & 0x02) == 0); - s->buttons[BUTTON_COPY_SW].write((val & 0x04) == 0); - s->buttons[BUTTON_EMAIL_SW].write((val & 0x08) == 0); - s->buttons[BUTTON_FILE_SW].write((val & 0x10) == 0); - } - return status; -} - - -/** the gl124 command set */ -static Genesys_Command_Set gl124_cmd_set = { - "gl124-generic", /* the name of this set */ - - [](Genesys_Device* dev) -> bool { (void) dev; return true; }, - - gl124_init, - gl124_init_regs_for_warmup, - gl124_init_regs_for_coarse_calibration, - gl124_init_regs_for_shading, - gl124_init_regs_for_scan, - - gl124_get_filter_bit, - gl124_get_lineart_bit, - gl124_get_bitset_bit, - gl124_get_gain4_bit, - gl124_get_fast_feed_bit, - gl124_test_buffer_empty_bit, - gl124_test_motor_flag_bit, - - gl124_set_fe, - gl124_set_powersaving, - gl124_save_power, - - gl124_begin_scan, - gl124_end_scan, - - sanei_genesys_send_gamma_table, - - gl124_search_start_position, - - gl124_offset_calibration, - gl124_coarse_gain_calibration, - gl124_led_calibration, - - gl124_wait_for_motor_stop, - gl124_slow_back_home, - gl124_rewind, - - sanei_genesys_bulk_write_register, - NULL, - sanei_genesys_bulk_read_data, - - gl124_update_hardware_sensors, - - /* no sheetfed support for now */ - NULL, - NULL, - NULL, - NULL, - - sanei_genesys_is_compatible_calibration, - NULL, - gl124_send_shading_data, - gl124_calculate_current_setup, - gl124_boot -}; - -SANE_Status -sanei_gl124_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl124_cmd_set; - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_gl124.h b/backend/genesys_gl124.h deleted file mode 100644 index 751321d..0000000 --- a/backend/genesys_gl124.h +++ /dev/null @@ -1,489 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2016 Stéphane Voltz - - 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 "genesys.h" - -#define REG01 0x01 -#define REG01_CISSET 0x80 -#define REG01_DOGENB 0x40 -#define REG01_DVDSET 0x20 -#define REG01_STAGGER 0x10 -#define REG01_COMPENB 0x08 -#define REG01_TRUEGRAY 0x04 -#define REG01_SHDAREA 0x02 -#define REG01_SCAN 0x01 - -#define REG02 0x02 -#define REG02_NOTHOME 0x80 -#define REG02_ACDCDIS 0x40 -#define REG02_AGOHOME 0x20 -#define REG02_MTRPWR 0x10 -#define REG02_FASTFED 0x08 -#define REG02_MTRREV 0x04 -#define REG02_HOMENEG 0x02 -#define REG02_LONGCURV 0x01 - -#define REG03 0x03 -#define REG03_LAMPDOG 0x80 -#define REG03_AVEENB 0x40 -#define REG03_XPASEL 0x20 -#define REG03_LAMPPWR 0x10 -#define REG03_LAMPTIM 0x0f - -#define REG04 0x04 -#define REG04_LINEART 0x80 -#define REG04_BITSET 0x40 -#define REG04_FILTER 0x30 -#define REG04_AFEMOD 0x07 - -#define REG05 0x05 -#define REG05_DPIHW 0xc0 -#define REG05_DPIHW_600 0x00 -#define REG05_DPIHW_1200 0x40 -#define REG05_DPIHW_2400 0x80 -#define REG05_DPIHW_4800 0xc0 -#define REG05_MTLLAMP 0x30 -#define REG05_GMMENB 0x08 -#define REG05_ENB20M 0x04 -#define REG05_MTLBASE 0x03 - -#define REG06 0x06 -#define REG06_SCANMOD 0xe0 -#define REG06S_SCANMOD 5 -#define REG06_PWRBIT 0x10 -#define REG06_GAIN4 0x08 -#define REG06_OPTEST 0x07 - -#define REG07_LAMPSIM 0x80 - -#define REG08_DRAM2X 0x80 -#define REG08_MPENB 0x20 -#define REG08_CIS_LINE 0x10 -#define REG08_IR2_ENB 0x08 -#define REG08_IR1_ENB 0x04 -#define REG08_ENB24M 0x01 - -#define REG09_MCNTSET 0xc0 -#define REG09_EVEN1ST 0x20 -#define REG09_BLINE1ST 0x10 -#define REG09_BACKSCAN 0x08 -#define REG09_OUTINV 0x04 -#define REG09_SHORTTG 0x02 - -#define REG09S_MCNTSET 6 -#define REG09S_CLKSET 4 - -#define REG0A 0x0a -#define REG0A_SIFSEL 0xc0 -#define REG0AS_SIFSEL 6 -#define REG0A_SHEETFED 0x20 -#define REG0A_LPWMEN 0x10 - -#define REG0B 0x0b -#define REG0B_DRAMSEL 0x07 -#define REG0B_16M 0x01 -#define REG0B_64M 0x02 -#define REG0B_128M 0x03 -#define REG0B_256M 0x04 -#define REG0B_512M 0x05 -#define REG0B_1G 0x06 -#define REG0B_ENBDRAM 0x08 -#define REG0B_RFHDIS 0x10 -#define REG0B_CLKSET 0xe0 -#define REG0B_24MHZ 0x00 -#define REG0B_30MHZ 0x20 -#define REG0B_40MHZ 0x40 -#define REG0B_48MHZ 0x60 -#define REG0B_60MHZ 0x80 - -#define REG0D 0x0d -#define REG0D_MTRP_RDY 0x80 -#define REG0D_FULLSTP 0x10 -#define REG0D_CLRMCNT 0x04 -#define REG0D_CLRDOCJM 0x02 -#define REG0D_CLRLNCNT 0x01 - -#define REG0F 0x0f - -#define REG16_CTRLHI 0x80 -#define REG16_TOSHIBA 0x40 -#define REG16_TGINV 0x20 -#define REG16_CK1INV 0x10 -#define REG16_CK2INV 0x08 -#define REG16_CTRLINV 0x04 -#define REG16_CKDIS 0x02 -#define REG16_CTRLDIS 0x01 - -#define REG17_TGMODE 0xc0 -#define REG17_SNRSYN 0x0f - -#define REG18 0x18 -#define REG18_CNSET 0x80 -#define REG18_DCKSEL 0x60 -#define REG18_CKTOGGLE 0x10 -#define REG18_CKDELAY 0x0c -#define REG18_CKSEL 0x03 - -#define REG1A_SW2SET 0x80 -#define REG1A_SW1SET 0x40 -#define REG1A_MANUAL3 0x02 -#define REG1A_MANUAL1 0x01 -#define REG1A_CK4INV 0x08 -#define REG1A_CK3INV 0x04 -#define REG1A_LINECLP 0x02 - -#define REG1C_TBTIME 0x07 - -#define REG1D 0x1d -#define REG1D_CK4LOW 0x80 -#define REG1D_CK3LOW 0x40 -#define REG1D_CK1LOW 0x20 -#define REG1D_LINESEL 0x1f -#define REG1DS_LINESEL 0 - -#define REG1E 0x1e -#define REG1E_WDTIME 0xf0 -#define REG1ES_WDTIME 4 -#define REG1E_WDTIME 0xf0 - -#define REG30 0x30 -#define REG31 0x31 -#define REG32 0x32 -#define REG32_GPIO16 0x80 -#define REG32_GPIO15 0x40 -#define REG32_GPIO14 0x20 -#define REG32_GPIO13 0x10 -#define REG32_GPIO12 0x08 -#define REG32_GPIO11 0x04 -#define REG32_GPIO10 0x02 -#define REG32_GPIO9 0x01 -#define REG33 0x33 -#define REG34 0x34 -#define REG35 0x35 -#define REG36 0x36 -#define REG37 0x37 -#define REG38 0x38 -#define REG39 0x39 - -#define REG60 0x60 -#define REG60_LED4TG 0x80 -#define REG60_YENB 0x40 -#define REG60_YBIT 0x20 -#define REG60_ACYNCNRLC 0x10 -#define REG60_ENOFFSET 0x08 -#define REG60_LEDADD 0x04 -#define REG60_CK4ADC 0x02 -#define REG60_AUTOCONF 0x01 - -#define REG80 0x80 -#define REG81 0x81 - -#define REGA0 0xa0 -#define REGA0_FSTPSEL 0x28 -#define REGA0S_FSTPSEL 3 -#define REGA0_STEPSEL 0x03 -#define REGA0S_STEPSEL 0 - -#define REGA1 0xa1 -#define REGA2 0xa2 -#define REGA3 0xa3 -#define REGA4 0xa4 -#define REGA5 0xa5 -#define REGA6 0xa6 -#define REGA7 0xa7 -#define REGA8 0xa8 -#define REGA9 0xa9 -#define REGAA 0xaa -#define REGAB 0xab -#define REGAC 0xac -#define REGAD 0xad -#define REGAE 0xae -#define REGAF 0xaf -#define REGB0 0xb0 -#define REGB1 0xb1 - -#define REGB2 0xb2 -#define REGB2_Z1MOD 0x1f -#define REGB3 0xb3 -#define REGB3_Z1MOD 0xff -#define REGB4 0xb4 -#define REGB4_Z1MOD 0xff - -#define REGB5 0xb5 -#define REGB5_Z2MOD 0x1f -#define REGB6 0xb6 -#define REGB6_Z2MOD 0xff -#define REGB7 0xb7 -#define REGB7_Z2MOD 0xff - -#define REG100 0x100 -#define REG100_DOCSNR 0x80 -#define REG100_ADFSNR 0x40 -#define REG100_COVERSNR 0x20 -#define REG100_CHKVER 0x10 -#define REG100_DOCJAM 0x08 -#define REG100_HISPDFLG 0x04 -#define REG100_MOTMFLG 0x02 -#define REG100_DATAENB 0x01 - -#define REG114 0x114 -#define REG115 0x115 - -#define REG_LINCNT 0x25 -#define REG_MAXWD 0x28 -#define REG_DPISET 0x2c -#define REG_FEEDL 0x3d -#define REG_CK1MAP 0x74 -#define REG_CK3MAP 0x77 -#define REG_CK4MAP 0x7a -#define REG_LPERIOD 0x7d -#define REG_DUMMY 0x80 -#define REG_STRPIXEL 0x82 -#define REG_ENDPIXEL 0x85 -#define REG_EXPDMY 0x88 -#define REG_EXPR 0x8a -#define REG_EXPG 0x8d -#define REG_EXPB 0x90 -#define REG_SEGCNT 0x93 -#define REG_TG0CNT 0x96 -#define REG_SCANFED 0xa2 -#define REG_STEPNO 0xa4 -#define REG_FWDSTEP 0xa6 -#define REG_BWDSTEP 0xa8 -#define REG_FASTNO 0xaa -#define REG_FSHDEC 0xac -#define REG_FMOVNO 0xae -#define REG_FMOVDEC 0xb0 -#define REG_Z1MOD 0xb2 -#define REG_Z2MOD 0xb5 - -#define REG_TRUER 0x110 -#define REG_TRUEG 0x111 -#define REG_TRUEB 0x112 - -#define SETREG(adr,val) { dev->reg.init_reg(adr, val); } - -typedef struct -{ - uint8_t r31; - uint8_t r32; - uint8_t r33; - uint8_t r34; - uint8_t r35; - uint8_t r36; - uint8_t r38; -} Gpio_layout; - -/** @brief gpio layout - * describes initial gpio settings for a given model - * registers 0x31 to 0x38 - */ -static Gpio_layout gpios[]={ - /* LiDE 110 */ - { /* 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x38 */ - 0x9f, 0x59, 0x01, 0x80, 0x5f, 0x01, 0x00 - }, - /* LiDE 210 */ - { - 0x9f, 0x59, 0x01, 0x80, 0x5f, 0x01, 0x00 - }, - /* LiDE 120 */ - { - 0x9f, 0x53, 0x01, 0x80, 0x5f, 0x01, 0x00 - }, -}; - -typedef struct -{ - uint8_t rd0; - uint8_t rd1; - uint8_t rd2; - uint8_t re0; - uint8_t re1; - uint8_t re2; - uint8_t re3; - uint8_t re4; - uint8_t re5; - uint8_t re6; - uint8_t re7; -} Memory_layout; - -static Memory_layout layouts[]={ - /* LIDE 110, 120 */ - { /* 0xd0 0xd1 0xd2 */ - 0x0a, 0x15, 0x20, - /* 0xe0 0xe1 0xe2 0xe3 0xe4 0xe5 0xe6 0xe7 */ - 0x00, 0xac, 0x08, 0x55, 0x08, 0x56, 0x0f, 0xff - }, - /* LIDE 210, 220 */ - { - 0x0a, 0x1f, 0x34, - 0x01, 0x24, 0x08, 0x91, 0x08, 0x92, 0x0f, 0xff - } -}; - -/** @brief structure for sensor settings - * this structure describes the sensor settings to use for a given - * exposure. Data settings are identified by - * - sensor id - * - sensor hardware dpi - * - half ccd mode - */ -typedef struct { - int sensor_type; /**> sensor id */ - int dpi; /**> maximum dpi for which data are valid */ - int half_ccd; /**> half ccd mode */ - int exposure; /**> exposure */ - int ck1map; /**> CK1MAP */ - int ck3map; /**> CK3MAP */ - int ck4map; /**> CK4MAP */ - int segcnt; /**> SEGCNT */ - int tg0cnt; /**> TG0CNT */ - int expdummy; /**> exposure dummy */ - int expr; /**> initial red exposure */ - int expg; /**> initial green exposure */ - int expb; /**> initial blue exposure */ - size_t *order; /**> order of sub-segments */ - uint8_t reg18; /**> register 0x18 value */ - uint8_t reg20; /**> register 0x20 value */ - uint8_t reg61; /**> register 0x61 value */ - uint8_t reg98; /**> register 0x98 value */ - uint8_t reg16; /**> register 0x16 value */ - uint8_t reg70; /**> register 0x70 value */ -} Sensor_Profile; - -static size_t order_01[]={0,1}; -static size_t order_0213[]={0,2,1,3}; - -/** @brief database of sensor profiles - * database of sensor profiles giving for each sensor and a given resolution, the period, and timings - * to setup the sensor for the scan. - */ -static Sensor_Profile sensors[]={ - /* LiDE 110 */ - {CIS_CANONLIDE110, 600, 1, 2768, 0x1e, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21, 0x00, 0x00}, - {CIS_CANONLIDE110, 600, 0, 5360, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21, 0x00, 0x00}, - {CIS_CANONLIDE110, 1200, 0, 10528, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22, 0x00, 0x00}, - {CIS_CANONLIDE110, 2400, 0, 20864, 0x1e, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24, 0x00, 0x00}, - - /* LiDE 120 */ - {CIS_CANONLIDE120, 600, 1, 4608, 0x0f, 0x00, 0x55, 2552, 112, 94, 894, 1044, 994, NULL , 0x00, 0x02, 0x20, 0x21, 0x15, 0x00}, - {CIS_CANONLIDE120, 600, 0, 5360, 0x0f, 0x00, 0x55, 5104, 139, 94, 1644, 1994, 1844, NULL , 0x00, 0x02, 0x20, 0x21, 0x11, 0x1f}, - {CIS_CANONLIDE120, 1200, 0, 10528, 0x0f, 0x00, 0x55,10208, 192, 94, 3194, 3794, 3594, NULL , 0x00, 0x02, 0x20, 0x21, 0x15, 0x1f}, - {CIS_CANONLIDE120, 2400, 0, 20864, 0x0f, 0x00, 0x55,20416, 298, 94, 6244, 7544, 7094, NULL , 0x00, 0x02, 0x20, 0x21, 0x11, 0x00}, - - /* LiDE 210 */ - {CIS_CANONLIDE210, 600, 1, 2768, 0x1e, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21, 0x00, 0x00}, - {CIS_CANONLIDE210, 600, 0, 5360, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21, 0x00, 0x00}, - {CIS_CANONLIDE210, 1200, 0, 10528, 0x1e, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22, 0x00, 0x00}, - {CIS_CANONLIDE210, 2400, 0, 20864, 0x1e, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24, 0x00, 0x00}, - - /* LiDE 220 */ - {CIS_CANONLIDE220, 600, 1, 2768, 0x0f, 0x9f, 0x55, 2584, 154, 101, 388, 574, 393, NULL , 0x00, 0x0c, 0x20, 0x21, 0x00, 0x00}, - {CIS_CANONLIDE220, 600, 0, 5360, 0x0f, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, NULL , 0x00, 0x0a, 0x20, 0x21, 0x00, 0x00}, - {CIS_CANONLIDE220, 1200, 0, 10528, 0x0f, 0x9f, 0x55, 5168, 163, 101, 388, 574, 393, order_01 , 0x00, 0x08, 0x20, 0x22, 0x00, 0x00}, - {CIS_CANONLIDE220, 2400, 0, 20864, 0x0f, 0x9f, 0x55, 5168, 163, 4679, 6839, 8401, 6859, order_0213, 0x00, 0x06, 0x20, 0x24, 0x00, 0x00}, -}; - - -#define MOVE_DPI 200 -#define MOVE_EXPOSURE 2304 -/** @brief reference slope tables - * slope table directly extracted from USB logs, with a 'termination' value of 0. - */ -static uint32_t lide210_fast[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2051, 1432, 1372, 1323, 1280, 1246, 1216, 1188, 1163, 1142, 1121, 1101, 1084, 1068, 1051, 1036, 1020, 1007, 995, 983, 971, 959, 949, 938, 929, 917, 908, 900, 891, 882, 874, 866, 857, 849, 843, 835, 829, 821, 816, 808, 802, 795, 789, 784, 778, 773, 765, 760, 755, 749, 744, 739, 734, 731, 726, 721, 716, 711, 707, 702, 698, 693, 690, 685, 682, 677, 672, 669, 665, 662, 657, 654, 650, 647, 644, 639, 637, 632, 629, 626, 622, 619, 617, 614, 610, 607, 604, 601, 599, 595, 592, 589, 587, 584, 581, 579, 576, 572, 570, 567, 564, 562, 559, 557, 554, 552, 549, 547, 544, 542, 539, 538, 536, 533, 531, 529, 526, 524, 522, 519, 518, 516, 513, 511, 509, 506, 505, 503, 501, 498, 497, 495, 493, 491, 490, 487, 485, 483, 482, 480, 477, 476, 474, 472, 470, 469, 467, 465, 464, 462, 460, 458, 456, 455, 453, 451, 450, 448, 447, 445, 444, 442, 440, 439, 437, 436, 434, 433, 431, 430, 428, 427, 425, 423, 422, 420, 419, 417, 417, 415, 414, 413, 411, 410, 408, 407, 405, 404, 402, 401, 400, 399, 398, 396, 395, 393, 392, 391, 390, 389, 387, 386, 385, 383, 382, 381, 380, 379, 377, 376, 375, 374, 373, 371, 370, 369, 368, 367, 366, 364, 363, 363, 361, 360, 359, 358, 357, 356, 355, 353, 352, 352, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 335, 335, 0}; -static uint32_t lide110_ok[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2051, 1961, 1901, 1852, 1809, 1775, 1745, 1717, 1692, 1671, 1650, 1630, 1613, 1597, 1580, 1565, 1549, 1536, 1524, 1512, 1500, 1488, 1478, 1467, 1458, 1446, 1437, 1429, 1420, 1411, 1403, 1395, 1386, 1378, 1372, 1364, 1358, 1350, 1345, 1337, 1331, 1324, 1318, 1313, 1307, 1302, 1294, 1289, 1284, 1278, 1273, 1268, 1263, 1260, 1255, 1250, 1245, 1240, 1236, 1231, 1227, 1222, 1219, 1214, 1211, 1206, 1201, 1198, 1194, 1191, 1186, 1183, 1179, 1176, 1173, 1168, 1166, 1161, 1158, 1155, 1151, 1148, 1146, 1143, 1139, 1136, 1133, 1130, 1128, 1124, 1121, 1118, 1116, 1113, 1110, 1108, 1105, 1101, 1099, 1096, 1093, 1091, 1088, 1086, 1083, 1081, 1078, 1076, 1073, 1071, 1068, 1067, 1065, 1062, 1060, 1058, 1055, 1053, 1051, 1048, 1047, 1045, 1042, 1040, 1038, 1035, 1034, 1032, 1030, 1027, 1026, 1024, 1022, 1020, 1019, 1016, 1014, 1012, 1011, 1009, 1006, 1005, 1003, 1001, 999, 998, 996, 994, 993, 991, 989, 987, 985, 984, 982, 980, 979, 977, 976, 974, 973, 971, 969, 968, 966, 965, 963, 962, 960, 959, 957, 956, 954, 952, 951, 949, 948, 946, 946, 944, 943, 942, 940, 939, 937, 936, 934, 933, 931, 930, 929, 928, 927, 925, 924, 922, 921, 920, 919, 918, 916, 915, 914, 912, 911, 910, 909, 908, 906, 905, 904, 903, 902, 900, 899, 898, 897, 896, 895, 893, 892, 892, 890, 889, 888, 887, 886, 885, 884, 882, 881, 881, 879, 878, 877, 876, 875, 874, 873, 872, 871, 870, 869, 868, 867, 864, 857, 849, 843, 835, 829, 821, 816, 808, 802, 795, 789, 784, 778, 773, 765, 760, 755, 749, 744, 739, 734, 731, 726, 721, 716, 711, 707, 702, 698, 693, 690, 685, 682, 677, 672, 669, 665, 662, 657, 654, 650, 647, 644, 639, 637, 632, 629, 626, 622, 619, 617, 614, 610, 607, 604, 601, 599, 595, 592, 589, 587, 584, 581, 579, 576, 572, 570, 567, 564, 562, 559, 557, 554, 552, 549, 547, 544, 542, 539, 538, 536, 533, 531, 529, 526, 524, 522, 519, 518, 516, 513, 511, 509, 506, 505, 503, 501, 498, 497, 495, 493, 491, 490, 487, 485, 483, 482, 480, 477, 476, 474, 472, 470, 469, 467, 465, 464, 462, 460, 458, 456, 455, 453, 451, 450, 448, 447, 445, 444, 442, 440, 439, 437, 436, 434, 433, 431, 430, 428, 427, 425, 423, 422, 420, 419, 417, 417, 415, 414, 413, 411, 410, 408, 407, 405, 404, 402, 401, 400, 399, 398, 396, 395, 393, 392, 391, 390, 389, 387, 386, 385, 383, 382, 381, 380, 379, 377, 376, 375, 374, 373, 371, 370, 369, 368, 367, 366, 364, 363, 363, 361, 360, 359, 358, 357, 356, 355, 353, 352, 352, 350, 349, 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, 338, 335, 335, 0}; -static uint32_t lide120_fast[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 1957, 1845, 1768, 1710, 1665, 1624, 1588, 1557, 1529, 1504, 1481, 1458, 1440, 1420, 1403, 1386, 1370, 1356, 1343, 1329, 1316, 1303, 1293, 1280, 1270, 1260, 1250, 1241, 1231, 1222, 1214, 1206, 1197, 1189, 1182, 1174, 1167, 1160, 1153, 1147, 1140, 1133, 1128, 1121, 1116, 1110, 1104, 1099, 1093, 1088, 1082, 1077, 1072, 1067, 1062, 1058, 1053, 1049, 1045, 1040, 1035, 1032, 1027, 1023, 1020, 1015, 1012, 1008, 1004, 1000, 997, 993, 989, 985, 982, 979, 975, 972, 969, 966, 963, 959, 956, 953, 950, 947, 945, 942, 939, 936, 933, 930, 928, 925, 922, 920, 917, 914, 911, 909, 907, 904, 902, 899, 897, 895, 892, 890, 888, 886, 883, 881, 879, 876, 874, 872, 870, 864, 864, 0}; -static uint32_t lide120_ok[] = { 62496, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2286, 2264, 2248, 2232, 2221, 2211, 2205, 2195, 2190, 2180, 2175, 2170, 2160, 2155, 2150, 2145, 2140, 2135, 2130, 2125, 2121, 2116, 2111, 2106, 2106, 2102, 2097, 2092, 2087, 2087, 2083, 2078, 2074, 2074, 2069, 2064, 2064, 2060, 2055, 2055, 2051, 2051, 2046, 2042, 2042, 2038, 2038, 2033, 2029, 2029, 2024, 2024, 2020, 2010, 2010, 670*2, 0}; -static uint32_t lide110_slow[] = { 62496, 7896, 2632, 0}; -static uint32_t lide120_slow[] = { 62464, 7896, 2632, 0}; -static uint32_t lide110_max[] = { 62496, 31296, 10432, 0}; -static uint32_t lide120_max[] = { 62592, 62592, 41728, 31296, 10432, 0}; -static uint32_t lide210_max[] = { 62496, 31296, 20864, 10432, 0}; - -/* NEXT LPERIOD=PREVIOUS*2-192 */ -/** @brief database of motor profiles - * database of motor profiles, for each exposure deigned for the sensor, gives the reference slope table to use - * for scan. - */ -static Motor_Profile motors[]={ - {MOTOR_CANONLIDE110, 2768, 0, lide210_fast}, - {MOTOR_CANONLIDE110, 5360, 1, lide110_ok}, - {MOTOR_CANONLIDE110, 10528, 1, lide110_slow}, - {MOTOR_CANONLIDE110, 20864, 2, lide110_max}, - {MOTOR_CANONLIDE120, 4608, 0, lide120_fast}, - {MOTOR_CANONLIDE120, 5360, 1, lide120_ok}, - {MOTOR_CANONLIDE120, 10528, 2, lide120_slow}, - {MOTOR_CANONLIDE120, 20864, 2, lide120_max}, - {MOTOR_CANONLIDE210, 2768, 0, lide210_fast}, - {MOTOR_CANONLIDE210, 5360, 1, lide110_ok}, - {MOTOR_CANONLIDE210, 10528, 1, lide110_slow}, - {MOTOR_CANONLIDE210, 20864, 2, lide210_max}, - {0, 0, 0, NULL}, -}; - -static -SANE_Status gl124_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, SetupParams& params); - -static SANE_Status gl124_start_action (Genesys_Device * dev); -static SANE_Status -gl124_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SANE_Bool start_motor); -static SANE_Status -gl124_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop); -static SANE_Status -gl124_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); -static SANE_Status gl124_init(Genesys_Device * dev); -static SANE_Status gl124_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * data, int size); - -static SANE_Status gl124_feed (Genesys_Device * dev, unsigned int steps, int reverse); - -static SANE_Status -gl124_stop_action (Genesys_Device * dev); - -static SANE_Status -gl124_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps); diff --git a/backend/genesys_gl646.cc b/backend/genesys_gl646.cc deleted file mode 100644 index b2b9f62..0000000 --- a/backend/genesys_gl646.cc +++ /dev/null @@ -1,4911 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003 Oliver Rauch - Copyright (C) 2003, 2004 Henning Meier-Geinitz - Copyright (C) 2004 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2007 Luke - Copyright (C) 2011 Alexey Osipov for HP2400 description - and tuning - - 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. -*/ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_gl646.h" - -#include - -/** - * reads value from gpio endpoint - */ -static void gl646_gpio_read(UsbDevice& usb_dev, uint8_t* value) -{ - DBG_HELPER(dbg); - usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, GPIO_READ, INDEX, 1, value); -} - -/** - * writes the given value to gpio endpoint - */ -static void gl646_gpio_write(UsbDevice& usb_dev, uint8_t value) -{ - DBG_HELPER_ARGS(dbg, "(0x%02x)", value); - usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_WRITE, INDEX, 1, &value); -} - -/** - * writes the given value to gpio output enable endpoint - */ -static void gl646_gpio_output_enable(UsbDevice& usb_dev, uint8_t value) -{ - DBG_HELPER_ARGS(dbg, "(0x%02x)", value); - usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, GPIO_OUTPUT_ENABLE, INDEX, 1, &value); -} - -/* Read bulk data (e.g. scanned data) */ -static SANE_Status -gl646_bulk_read_data (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len) -{ - SANE_Status status = sanei_genesys_bulk_read_data(dev, addr, data, len); - if (status != SANE_STATUS_GOOD) { - return status; - } - if (dev->model->is_sheetfed == SANE_TRUE) { - gl646_detect_document_end (dev); - } - return status; -} - -static SANE_Bool -gl646_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_filter_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_lineart_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_bitset_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_get_gain4_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl646_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTMFLG) - return SANE_TRUE; - return SANE_FALSE; -} - -/** - * decodes and prints content of status (0x41) register - * @param val value read from reg41 - */ -static void -print_status (uint8_t val) -{ - char msg[80]; - - sprintf (msg, "%s%s%s%s%s%s%s%s", - val & REG41_PWRBIT ? "PWRBIT " : "", - val & REG41_BUFEMPTY ? "BUFEMPTY " : "", - val & REG41_FEEDFSH ? "FEEDFSH " : "", - val & REG41_SCANFSH ? "SCANFSH " : "", - val & REG41_HOMESNR ? "HOMESNR " : "", - val & REG41_LAMPSTS ? "LAMPSTS " : "", - val & REG41_FEBUSY ? "FEBUSY " : "", - val & REG41_MOTMFLG ? "MOTMFLG" : ""); - DBG(DBG_info, "status=%s\n", msg); -} - -/** - * start scanner's motor - * @param dev scanner's device - */ -static SANE_Status -gl646_start_motor (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - - -/** - * stop scanner's motor - * @param dev scanner's device - */ -static SANE_Status -gl646_stop_motor (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x00); -} - - -/** - * find the lowest resolution for the sensor in the given mode. - * @param sensor id of the sensor - * @param color true is color mode - * @return the closest resolution for the sensor and mode - */ -static int -get_lowest_resolution(int sensor_id, unsigned channels) -{ - int i, nb; - int dpi; - - i = 0; - dpi = 9600; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* computes distance and keep mode if it is closer than previous */ - if (sensor_id == sensor_master[i].sensor - && sensor_master[i].channels == channels) - { - if (sensor_master[i].dpi < dpi) - { - dpi = sensor_master[i].dpi; - } - } - i++; - } - DBG(DBG_info, "%s: %d\n", __func__, dpi); - return dpi; -} - -/** - * find the closest match in mode tables for the given resolution and scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return the closest resolution for the sensor and mode - */ -static int -get_closest_resolution(int sensor_id, int required, unsigned channels) -{ - int i, nb; - int dist, dpi; - - i = 0; - dpi = 0; - dist = 9600; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor_id == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].channels == channels) - { - DBG(DBG_info, "%s: match found for %d\n", __func__, required); - return required; - } - /* computes distance and keep mode if it is closer than previous */ - if (sensor_id == sensor_master[i].sensor - && sensor_master[i].channels == channels) - { - if (abs (sensor_master[i].dpi - required) < dist) - { - dpi = sensor_master[i].dpi; - dist = abs (sensor_master[i].dpi - required); - } - } - i++; - } - DBG(DBG_info, "%s: closest match for %d is %d\n", __func__, required, dpi); - return dpi; -} - -/** - * Computes if sensor will be set up for half ccd pixels for the given - * scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return SANE_TRUE if half ccd is used - */ -static SANE_Bool is_half_ccd(int sensor_id, int required, unsigned channels) -{ - int i, nb; - - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor_id == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].channels == channels) - { - DBG(DBG_io, "%s: match found for %d (half_ccd=%d)\n", __func__, required, - sensor_master[i].half_ccd); - return sensor_master[i].half_ccd; - } - i++; - } - DBG(DBG_info, "%s: failed to find match for %d dpi\n", __func__, required); - return SANE_FALSE; -} - -/** - * Returns the cksel values used by the required scan mode. - * @param sensor id of the sensor - * @param required required resolution - * @param color true is color mode - * @return cksel value for mode - */ -static int get_cksel(int sensor_id, int required, unsigned channels) -{ - int i, nb; - - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - /* exit on perfect match */ - if (sensor_id == sensor_master[i].sensor - && sensor_master[i].dpi == required - && sensor_master[i].channels == channels) - { - DBG(DBG_io, "%s: match found for %d (cksel=%d)\n", __func__, required, - sensor_master[i].cksel); - return sensor_master[i].cksel; - } - i++; - } - DBG(DBG_error, "%s: failed to find match for %d dpi\n", __func__, required); - /* fail safe fallback */ - return 1; -} - -/** - * Setup register and motor tables for a scan at the - * given resolution and color mode. TODO try to not use any filed from - * the device. - * @param dev pointer to a struct describing the device - * @param regs register set to fill - * @param slope_table1 first motor table to fill - * @param slope_table2 second motor table to fill - * @return SANE_STATUS_GOOD if registers could be set, SANE_STATUS_INVAL if - * conditions can't be met. - * @note No harcoded SENSOR or MOTOR 'names' should be present and - * registers are set from settings tables and flags related - * to the hardware capabilities. - * */ -static SANE_Status -gl646_setup_registers (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, - SetupParams& params, - uint16_t * slope_table1, - uint16_t * slope_table2, - bool xcorrection) -{ - int resolution = params.xres; - uint32_t move = params.starty; - uint32_t linecnt = params.lines; - - uint32_t startx = 0; - /* pixels are allways given at full CCD optical resolution */ - /* use detected left margin and fixed value */ - if (xcorrection == SANE_TRUE) { - if (sensor.CCD_start_xoffset > 0) { - startx = sensor.CCD_start_xoffset; - } else { - startx = sensor.dummy_pixel; - } - } else { - // startx cannot be below dummy pixel value - startx = sensor.dummy_pixel; - } - - /* add x coordinates : expressed in sensor max dpi */ - startx += params.startx; - - /* stagger works with odd start cordinates */ - if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) { - startx |= 1; - } - - uint32_t pixels = (params.pixels * sensor.optical_res) / params.xres; - /* special requirement for 400 dpi on 1200 dpi sensors */ - if (params.xres == 400) - { - pixels = (pixels / 6) * 6; - } - /* TODO check for pixel width overflow */ - uint32_t endx = startx + pixels; - - SANE_Status status = SANE_STATUS_GOOD; - int i, nb; - Sensor_Master *sensor_mst = NULL; - Motor_Master *motor = NULL; - Sensor_Settings *settings = NULL; - GenesysRegister *r; - unsigned int used1, used2, vfinal; - unsigned int bpp; /**> bytes per pixel */ - uint32_t z1, z2; - uint16_t ex, sx; - int stagger, words_per_line, max_shift; - size_t requested_buffer_size; - size_t read_buffer_size; - SANE_Bool half_ccd = SANE_FALSE; - SANE_Int xresolution; - int feedl; - - DBG(DBG_proc, "%s: start\n", __func__); - DBG(DBG_info, "%s: startx=%d, endx=%d, linecnt=%d\n", __func__, startx, endx, linecnt); - - /* x resolution is capped by sensor's capability */ - if (resolution > sensor.optical_res) - { - xresolution = sensor.optical_res; - } - else - { - xresolution = resolution; - } - - /* for the given resolution, search for master - * sensor mode setting */ - i = 0; - nb = sizeof (sensor_master) / sizeof (Sensor_Master); - while (i < nb) - { - if (dev->model->ccd_type == sensor_master[i].sensor - && sensor_master[i].dpi == xresolution - && sensor_master[i].channels == params.channels) - { - sensor_mst = &sensor_master[i]; - } - i++; - } - if (sensor_mst == NULL) - { - DBG(DBG_error, "%s: unable to find settings for sensor %d at %d dpi channels=%d\n", __func__, - dev->model->ccd_type, xresolution, params.channels); - return SANE_STATUS_INVAL; - } - - /* for the given resolution, search for master - * motor mode setting */ - i = 0; - nb = sizeof (motor_master) / sizeof (Motor_Master); - while (i < nb) - { - if (dev->model->motor_type == motor_master[i].motor - && motor_master[i].dpi == resolution - && motor_master[i].channels == params.channels) - { - motor = &motor_master[i]; - } - i++; - } - if (motor == NULL) - { - DBG(DBG_error, "%s: unable to find settings for motor %d at %d dpi, color=%d\n", __func__, - dev->model->motor_type, resolution, params.channels); - return SANE_STATUS_INVAL; - } - - /* now we can search for the specific sensor settings */ - i = 0; - nb = sizeof (sensor_settings) / sizeof (Sensor_Settings); - while (i < nb) - { - if (sensor_mst->sensor == sensor_settings[i].sensor - && sensor_mst->cksel == sensor_settings[i].cksel) - { - settings = &sensor_settings[i]; - } - i++; - } - if (settings == NULL) - { - DBG(DBG_error, "%s: unable to find settings for sensor %d with '%d' ccd timing\n", __func__, - sensor_mst->sensor, sensor_mst->cksel); - return SANE_STATUS_INVAL; - } - - /* half_ccd if manual clock programming or dpi is half dpiset */ - half_ccd = sensor_mst->half_ccd; - - /* now apply values from settings to registers */ - if (sensor_mst->regs_0x10_0x15 != NULL) - { - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = sensor_mst->regs_0x10_0x15[i]; - } - } - else - { - for (i = 0; i < 6; i++) - { - r = sanei_genesys_get_address (regs, 0x10 + i); - r->value = 0; - } - } - - for (i = 0; i < 4; i++) - { - r = sanei_genesys_get_address (regs, 0x08 + i); - if (half_ccd == SANE_TRUE) - r->value = settings->manual_0x08_0x0b[i]; - else - r->value = settings->regs_0x08_0x0b[i]; - } - - for (i = 0; i < 8; i++) - { - r = sanei_genesys_get_address (regs, 0x16 + i); - r->value = settings->regs_0x16_0x1d[i]; - } - - for (i = 0; i < 13; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - r->value = settings->regs_0x52_0x5e[i]; - } - if (half_ccd == SANE_TRUE) - { - for (i = 0; i < 7; i++) - { - r = sanei_genesys_get_address (regs, 0x52 + i); - r->value = settings->manual_0x52_0x58[i]; - } - } - - /* now generate slope tables : we are not using generate_slope_table3 yet */ - sanei_genesys_generate_slope_table (slope_table1, motor->steps1, - motor->steps1 + 1, motor->vend1, - motor->vstart1, motor->vend1, - motor->steps1, motor->g1, &used1, - &vfinal); - sanei_genesys_generate_slope_table (slope_table2, motor->steps2, - motor->steps2 + 1, motor->vend2, - motor->vstart2, motor->vend2, - motor->steps2, motor->g2, &used2, - &vfinal); - - /* R01 */ - /* now setup other registers for final scan (ie with shading enabled) */ - /* watch dog + shading + scan enable */ - regs->find_reg(0x01).value |= REG01_DOGENB | REG01_DVDSET | REG01_SCAN; - if (dev->model->is_cis == SANE_TRUE) - regs->find_reg(0x01).value |= REG01_CISSET; - else - regs->find_reg(0x01).value &= ~REG01_CISSET; - - /* if device has no calibration, don't enable shading correction */ - if (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION) - { - regs->find_reg(0x01).value &= ~REG01_DVDSET; - } - - regs->find_reg(0x01).value &= ~REG01_FASTMOD; - if (motor->fastmod) - regs->find_reg(0x01).value |= REG01_FASTMOD; - - /* R02 */ - /* allow moving when buffer full by default */ - if (dev->model->is_sheetfed == SANE_FALSE) - dev->reg.find_reg(0x02).value &= ~REG02_ACDCDIS; - else - dev->reg.find_reg(0x02).value |= REG02_ACDCDIS; - - /* setup motor power and direction */ - sanei_genesys_set_motor_power(*regs, true); - regs->find_reg(0x02).value &= ~REG02_MTRREV; - - /* fastfed enabled (2 motor slope tables) */ - if (motor->fastfed) - regs->find_reg(0x02).value |= REG02_FASTFED; - else - regs->find_reg(0x02).value &= ~REG02_FASTFED; - - /* step type */ - regs->find_reg(0x02).value &= ~REG02_STEPSEL; - switch (motor->steptype) - { - case FULL_STEP: - break; - case HALF_STEP: - regs->find_reg(0x02).value |= 1; - break; - case QUATER_STEP: - regs->find_reg(0x02).value |= 2; - break; - default: - regs->find_reg(0x02).value |= 3; - break; - } - - /* if sheetfed, no AGOHOME */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - regs->find_reg(0x02).value &= ~REG02_AGOHOME; - } - else - { - regs->find_reg(0x02).value |= REG02_AGOHOME; - } - - /* R03 */ - regs->find_reg(0x03).value &= ~REG03_AVEENB; - /* regs->find_reg(0x03).value |= REG03_AVEENB; */ - regs->find_reg(0x03).value &= ~REG03_LAMPDOG; - - /* select XPA */ - regs->find_reg(0x03).value &= ~REG03_XPASEL; - if (params.flags & SCAN_FLAG_USE_XPA) { - regs->find_reg(0x03).value |= REG03_XPASEL; - } - regs->state.is_xpa_on = params.flags & SCAN_FLAG_USE_XPA; - - /* R04 */ - /* monochrome / color scan */ - switch (params.depth) - { - case 1: - regs->find_reg(0x04).value &= ~REG04_BITSET; - regs->find_reg(0x04).value |= REG04_LINEART; - break; - case 8: - regs->find_reg(0x04).value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - regs->find_reg(0x04).value &= ~REG04_LINEART; - regs->find_reg(0x04).value |= REG04_BITSET; - break; - } - - /* R05 */ - regs->find_reg(0x05).value &= ~REG05_DPIHW; - switch (sensor.optical_res) - { - case 600: - regs->find_reg(0x05).value |= REG05_DPIHW_600; - break; - case 1200: - regs->find_reg(0x05).value |= REG05_DPIHW_1200; - break; - case 2400: - regs->find_reg(0x05).value |= REG05_DPIHW_2400; - break; - default: - regs->find_reg(0x05).value |= REG05_DPIHW; - } - - /* gamma enable for scans */ - if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) - regs->find_reg(0x05).value |= REG05_GMM14BIT; - - regs->find_reg(0x05).value &= ~REG05_GMMENB; - - /* true CIS gray if needed */ - if (dev->model->is_cis == SANE_TRUE && params.channels == 1 - && dev->settings.true_gray) - { - regs->find_reg(0x05).value |= REG05_LEDADD; - } - else - { - regs->find_reg(0x05).value &= ~REG05_LEDADD; - } - - /* cktoggle, ckdelay and cksel at once, cktdelay=2 => half_ccd for md5345 */ - regs->find_reg(0x18).value = sensor_mst->r18; - - /* manual CCD/2 clock programming => half_ccd for hp2300 */ - regs->find_reg(0x1d).value = sensor_mst->r1d; - - /* HP2400 1200dpi mode tuning */ - - if (dev->model->ccd_type == CCD_HP2400) - { - /* reset count of dummy lines to zero */ - regs->find_reg(0x1e).value &= ~REG1E_LINESEL; - if (params.xres >= 1200) - { - /* there must be one dummy line */ - regs->find_reg(0x1e).value |= 1 & REG1E_LINESEL; - - /* GPO12 need to be set to zero */ - regs->find_reg(0x66).value &= ~0x20; - } - else - { - /* set GPO12 back to one */ - regs->find_reg(0x66).value |= 0x20; - } - } - - /* motor steps used */ - regs->find_reg(0x21).value = motor->steps1; - regs->find_reg(0x22).value = motor->fwdbwd; - regs->find_reg(0x23).value = motor->fwdbwd; - regs->find_reg(0x24).value = motor->steps1; - - /* scanned area height must be enlarged by max color shift needed */ - max_shift=sanei_genesys_compute_max_shift(dev,params.channels, params.yres, 0); - - /* we adjust linecnt according to real motor dpi */ - linecnt = (linecnt * motor->ydpi) / params.yres + max_shift; - - /* at QUATER_STEP lines are 'staggered' and need correction */ - stagger = 0; - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - { - /* for HP3670, stagger happens only at >=1200 dpi */ - if ((dev->model->motor_type != MOTOR_HP3670 && dev->model->motor_type != MOTOR_HP2400) - || params.yres >= (unsigned) sensor.optical_res) - { - stagger = (4 * params.yres) / dev->motor.base_ydpi; - } - } - linecnt += stagger; - - DBG(DBG_info, "%s : max_shift=%d, stagger=%d lines\n", __func__, max_shift, stagger); - - /* CIS scanners read one line per color channel - * since gray mode use 'add' we also read 3 channels even not in - * color mode */ - if (dev->model->is_cis == SANE_TRUE) - { - sanei_genesys_set_triple(regs, REG_LINCNT, linecnt * 3); - linecnt *= params.channels; - } - else - { - sanei_genesys_set_triple(regs, REG_LINCNT, linecnt); - } - - /* scanner's x coordinates are expressed in physical DPI but they must be divided by cksel */ - sx = startx / sensor_mst->cksel; - ex = endx / sensor_mst->cksel; - if (half_ccd == SANE_TRUE) - { - sx /= 2; - ex /= 2; - } - sanei_genesys_set_double(regs, REG_STRPIXEL, sx); - sanei_genesys_set_double(regs, REG_ENDPIXEL, ex); - DBG(DBG_info, "%s: startx=%d, endx=%d, half_ccd=%d\n", __func__, sx, ex, half_ccd); - - /* words_per_line must be computed according to the scan's resolution */ - /* in fact, words_per_line _gives_ the actual scan resolution */ - words_per_line = (((endx - startx) * sensor_mst->xdpi) / sensor.optical_res); - bpp=params.depth/8; - if (params.depth == 1) - { - words_per_line = (words_per_line+7)/8 ; - bpp=1; - } - else - { - words_per_line *= bpp; - } - dev->bpl = words_per_line; - words_per_line *= params.channels; - dev->wpl = words_per_line; - - DBG(DBG_info, "%s: wpl=%d\n", __func__, words_per_line); - sanei_genesys_set_triple(regs, REG_MAXWD, words_per_line); - - sanei_genesys_set_double(regs, REG_DPISET, sensor_mst->dpiset); - sanei_genesys_set_double(regs, REG_LPERIOD, sensor_mst->exposure); - - /* move distance must be adjusted to take into account the extra lines - * read to reorder data */ - feedl = move; - if (stagger + max_shift > 0 && feedl != 0) - { - if (feedl > - ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi) - feedl = - feedl - - ((max_shift + stagger) * dev->motor.optical_ydpi) / motor->ydpi; - } - - /* we assume all scans are done with 2 tables */ - /* - feedl = feed_steps - fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type); */ - /* but head has moved due to shading calibration => dev->scanhead_position_in_steps */ - if (feedl > 0) - { - /* take into account the distance moved during calibration */ - /* feedl -= dev->scanhead_position_in_steps; */ - DBG(DBG_info, "%s: initial move=%d\n", __func__, feedl); - DBG(DBG_info, "%s: scanhead_position_in_steps=%d\n", __func__, - dev->scanhead_position_in_steps); - - /* TODO clean up this when I'll fully understand. - * for now, special casing each motor */ - switch (dev->model->motor_type) - { - case MOTOR_5345: - switch (motor->ydpi) - { - case 200: - feedl -= 70; - break; - case 300: - feedl -= 70; - break; - case 400: - feedl += 130; - break; - case 600: - feedl += 160; - break; - case 1200: - feedl += 160; - break; - case 2400: - feedl += 180; - break; - default: - break; - } - break; - case MOTOR_HP2300: - switch (motor->ydpi) - { - case 75: - feedl -= 180; - break; - case 150: - feedl += 0; - break; - case 300: - feedl += 30; - break; - case 600: - feedl += 35; - break; - case 1200: - feedl += 45; - break; - default: - break; - } - break; - case MOTOR_HP2400: - switch (motor->ydpi) - { - case 150: - feedl += 150; - break; - case 300: - feedl += 220; - break; - case 600: - feedl += 260; - break; - case 1200: - feedl += 280; /* 300 */ - break; - case 50: - feedl += 0; - break; - case 100: - feedl += 100; - break; - default: - break; - } - break; - - /* theorical value */ - default: - if (motor->fastfed) - { - feedl = - feedl - 2 * motor->steps2 - - (motor->steps1 >> motor->steptype); - } - else - { - feedl = feedl - (motor->steps1 >> motor->steptype); - } - break; - } - /* security */ - if (feedl < 0) - feedl = 0; - } - - DBG(DBG_info, "%s: final move=%d\n", __func__, feedl); - sanei_genesys_set_triple(regs, REG_FEEDL, feedl); - - regs->find_reg(0x65).value = motor->mtrpwm; - - sanei_genesys_calculate_zmode2 (regs->find_reg(0x02).value & REG02_FASTFED, - sensor_mst->exposure, - slope_table1, - motor->steps1, - move, motor->fwdbwd, &z1, &z2); - - /* no z1/z2 for sheetfed scanners */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - z1 = 0; - z2 = 0; - } - sanei_genesys_set_double(regs, REG_Z1MOD, z1); - sanei_genesys_set_double(regs, REG_Z2MOD, z2); - regs->find_reg(0x6b).value = motor->steps2; - regs->find_reg(0x6c).value = - (regs->find_reg(0x6c).value & REG6C_TGTIME) | ((z1 >> 13) & 0x38) | ((z2 >> 16) - & 0x07); - - RIE (write_control (dev, sensor, xresolution)); - - /* setup analog frontend */ - RIE (gl646_set_fe(dev, sensor, AFE_SET, xresolution)); - - /* now we're done with registers setup values used by data transfer */ - /* we setup values needed for the data transfer */ - - /* we must use a round number of words_per_line */ - requested_buffer_size = 8 * words_per_line; - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * params.pixels * params.channels * params.depth) / 8; - - dev->read_buffer.clear(); - dev->read_buffer.alloc(read_buffer_size); - - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(read_buffer_size); - - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(requested_buffer_size); - - dev->out_buffer.clear(); - dev->out_buffer.alloc(8 * params.pixels * params.channels * bpp); - - /* scan bytes to read */ - dev->read_bytes_left = words_per_line * linecnt; - - DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - dev->current_setup.params = params; - dev->current_setup.pixels = - ((endx - startx) * sensor_mst->xdpi) / sensor.optical_res; - dev->current_setup.lines = linecnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = sensor_mst->exposure; - dev->current_setup.xres = sensor_mst->xdpi; - dev->current_setup.yres = motor->ydpi; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - /* total_bytes_to_read is the number of byte to send to frontend - * total_bytes_read is the number of bytes sent to frontend - * read_bytes_left is the number of bytes to read from the scanner - */ - dev->total_bytes_read = 0; - if (params.depth == 1) { - dev->total_bytes_to_read = ((params.pixels * params.lines) / 8 + - (((params.pixels * params.lines) % 8) ? 1 : 0)) * params.channels; - } else { - dev->total_bytes_to_read = params.pixels * params.lines * params.channels * bpp; - } - - /* select color filter based on settings */ - regs->find_reg(0x04).value &= ~REG04_FILTER; - if (params.channels == 1) { - switch (params.color_filter) { - case ColorFilter::RED: - regs->find_reg(0x04).value |= 0x04; - break; - case ColorFilter::GREEN: - regs->find_reg(0x04).value |= 0x08; - break; - case ColorFilter::BLUE: - regs->find_reg(0x04).value |= 0x0c; - break; - default: - break; - } - } - - DBG(DBG_proc, "%s: end\n", __func__); - return SANE_STATUS_GOOD; -} - - -/** copy sensor specific settings */ -/* *dev : device infos - *regs : regiters to be set - extended : do extended set up - half_ccd: set up for half ccd resolution - all registers 08-0B, 10-1D, 52-5E are set up. They shouldn't - appear anywhere else but in register init -*/ -static void -gl646_setup_sensor (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * regs) -{ - (void) dev; - DBG(DBG_proc, "%s: start\n", __func__); - - for (const auto& reg_setting : sensor.custom_regs) { - regs->set8(reg_setting.address, reg_setting.value); - } - // FIXME: all other drivers don't set exposure here - sanei_genesys_set_exposure(*regs, sensor.exposure); - - DBG(DBG_proc, "%s: end\n", __func__); -} - -/** Test if the ASIC works - */ -static SANE_Status -gl646_asic_test (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - size_t size, verify_size; - unsigned int i; - - DBG(DBG_proc, "%s: start\n", __func__); - - /* set and read exposure time, compare if it's the same */ - status = sanei_genesys_write_register (dev, 0x38, 0xde); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_write_register (dev, 0x39, 0xad); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_read_register (dev, 0x4e, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (val != 0xde) /* value of register 0x38 */ - { - DBG(DBG_error, "%s: register contains invalid value\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - status = sanei_genesys_read_register (dev, 0x4f, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (val != 0xad) /* value of register 0x39 */ - { - DBG(DBG_error, "%s: register contains invalid value\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - /* ram test: */ - size = 0x40000; - verify_size = size + 0x80; - /* todo: looks like the read size must be a multiple of 128? - otherwise the read doesn't succeed the second time after the scanner has - been plugged in. Very strange. */ - - std::vector data(size); - std::vector verify_data(verify_size); - - for (i = 0; i < (size - 1); i += 2) - { - data[i] = i / 512; - data[i + 1] = (i / 2) % 256; - } - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_bulk_write_data(dev, 0x3c, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = - gl646_bulk_read_data (dev, 0x45, verify_data.data(), verify_size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* i + 2 is needed as the changed address goes into effect only after one - data word is sent. */ - for (i = 0; i < size; i++) - { - if (verify_data[i + 2] != data[i]) - { - DBG(DBG_error, "%s: data verification error\n", __func__); - return SANE_STATUS_IO_ERROR; - } - } - - DBG(DBG_info, "%s: end\n", __func__); - - return SANE_STATUS_GOOD; -} - -/** - * Set all registers to default values after init - * @param dev scannerr's device to set - */ -static void -gl646_init_regs (Genesys_Device * dev) -{ - int addr; - - DBG(DBG_proc, "%s\n", __func__); - - dev->reg.clear(); - - for (addr = 1; addr <= 0x0b; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x10; addr <= 0x29; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x2c; addr <= 0x39; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x3d; addr <= 0x3f; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x52; addr <= 0x5e; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x60; addr <= 0x6d; addr++) - dev->reg.init_reg(addr, 0); - - dev->reg.find_reg(0x01).value = 0x20 /*0x22 */ ; /* enable shading, CCD, color, 1M */ - dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ - if (dev->model->motor_type == MOTOR_5345) - dev->reg.find_reg(0x02).value |= 0x01; /* half-step */ - switch (dev->model->motor_type) - { - case MOTOR_5345: - dev->reg.find_reg(0x02).value |= 0x01; /* half-step */ - break; - case MOTOR_XP200: - /* for this sheetfed scanner, no AGOHOME, nor backtracking */ - dev->reg.find_reg(0x02).value = 0x50; - break; - default: - break; - } - dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */ - dev->reg.find_reg(0x04).value = 0x13 /*0x03 */ ; /* 8 bits data, 16 bits A/D, color, Wolfson fe *//* todo: according to spec, 0x0 is reserved? */ - switch (dev->model->dac_type) - { - case DAC_AD_XP200: - dev->reg.find_reg(0x04).value = 0x12; - break; - default: - /* Wolfson frontend */ - dev->reg.find_reg(0x04).value = 0x13; - break; - } - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - dev->reg.find_reg(0x05).value = 0x00; /* 12 bits gamma, disable gamma, 24 clocks/pixel */ - switch (sensor.optical_res) - { - case 600: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; - break; - default: - dev->reg.find_reg(0x05).value |= REG05_DPIHW; - break; - } - if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) - dev->reg.find_reg(0x05).value |= REG05_GMM14BIT; - if (dev->model->dac_type == DAC_AD_XP200) - dev->reg.find_reg(0x05).value |= 0x01; /* 12 clocks/pixel */ - - if (dev->model->ccd_type == CCD_HP2300) - dev->reg.find_reg(0x06).value = 0x00; /* PWRBIT off, shading gain=4, normal AFE image capture */ - else - dev->reg.find_reg(0x06).value = 0x18; /* PWRBIT on, shading gain=8, normal AFE image capture */ - - - gl646_setup_sensor(dev, sensor, &dev->reg); - - dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */ - - switch (dev->model->ccd_type) - { - case CCD_HP2300: - dev->reg.find_reg(0x1e).value = 0xf0; - dev->reg.find_reg(0x1f).value = 0x10; - dev->reg.find_reg(0x20).value = 0x20; - break; - case CCD_HP2400: - dev->reg.find_reg(0x1e).value = 0x80; - dev->reg.find_reg(0x1f).value = 0x10; - dev->reg.find_reg(0x20).value = 0x20; - break; - case CCD_HP3670: - dev->reg.find_reg(0x19).value = 0x2a; - dev->reg.find_reg(0x1e).value = 0x80; - dev->reg.find_reg(0x1f).value = 0x10; - dev->reg.find_reg(0x20).value = 0x20; - break; - case CIS_XP200: - dev->reg.find_reg(0x1e).value = 0x10; - dev->reg.find_reg(0x1f).value = 0x01; - dev->reg.find_reg(0x20).value = 0x50; - break; - default: - dev->reg.find_reg(0x1f).value = 0x01; - dev->reg.find_reg(0x20).value = 0x50; - break; - } - - dev->reg.find_reg(0x21).value = 0x08 /*0x20 */ ; /* table one steps number for forward slope curve of the acc/dec */ - dev->reg.find_reg(0x22).value = 0x10 /*0x08 */ ; /* steps number of the forward steps for start/stop */ - dev->reg.find_reg(0x23).value = 0x10 /*0x08 */ ; /* steps number of the backward steps for start/stop */ - dev->reg.find_reg(0x24).value = 0x08 /*0x20 */ ; /* table one steps number backward slope curve of the acc/dec */ - dev->reg.find_reg(0x25).value = 0x00; /* scan line numbers (7000) */ - dev->reg.find_reg(0x26).value = 0x00 /*0x1b */ ; - dev->reg.find_reg(0x27).value = 0xd4 /*0x58 */ ; - dev->reg.find_reg(0x28).value = 0x01; /* PWM duty for lamp control */ - dev->reg.find_reg(0x29).value = 0xff; - - dev->reg.find_reg(0x2c).value = 0x02; /* set resolution (600 DPI) */ - dev->reg.find_reg(0x2d).value = 0x58; - dev->reg.find_reg(0x2e).value = 0x78; /* set black&white threshold high level */ - dev->reg.find_reg(0x2f).value = 0x7f; /* set black&white threshold low level */ - - dev->reg.find_reg(0x30).value = 0x00; /* begin pixel position (16) */ - dev->reg.find_reg(0x31).value = sensor.dummy_pixel /*0x10 */ ; /* TGW + 2*TG_SHLD + x */ - dev->reg.find_reg(0x32).value = 0x2a /*0x15 */ ; /* end pixel position (5390) */ - dev->reg.find_reg(0x33).value = 0xf8 /*0x0e */ ; /* TGW + 2*TG_SHLD + y */ - dev->reg.find_reg(0x34).value = sensor.dummy_pixel; - dev->reg.find_reg(0x35).value = 0x01 /*0x00 */ ; /* set maximum word size per line, for buffer full control (10800) */ - dev->reg.find_reg(0x36).value = 0x00 /*0x2a */ ; - dev->reg.find_reg(0x37).value = 0x00 /*0x30 */ ; - dev->reg.find_reg(0x38).value = 0x2a; // line period (exposure time = 11000 pixels) */ - dev->reg.find_reg(0x39).value = 0xf8; - dev->reg.find_reg(0x3d).value = 0x00; /* set feed steps number of motor move */ - dev->reg.find_reg(0x3e).value = 0x00; - dev->reg.find_reg(0x3f).value = 0x01 /*0x00 */ ; - - dev->reg.find_reg(0x60).value = 0x00; /* Z1MOD, 60h:61h:(6D b5:b3), remainder for start/stop */ - dev->reg.find_reg(0x61).value = 0x00; /* (21h+22h)/LPeriod */ - dev->reg.find_reg(0x62).value = 0x00; /* Z2MODE, 62h:63h:(6D b2:b0), remainder for start scan */ - dev->reg.find_reg(0x63).value = 0x00; /* (3Dh+3Eh+3Fh)/LPeriod for one-table mode,(21h+1Fh)/LPeriod */ - dev->reg.find_reg(0x64).value = 0x00; /* motor PWM frequency */ - dev->reg.find_reg(0x65).value = 0x00; /* PWM duty cycle for table one motor phase (63 = max) */ - if (dev->model->motor_type == MOTOR_5345) - dev->reg.find_reg(0x65).value = 0x02; /* PWM duty cycle for table one motor phase (63 = max) */ - dev->reg.find_reg(0x66).value = dev->gpo.value[0]; - dev->reg.find_reg(0x67).value = dev->gpo.value[1]; - dev->reg.find_reg(0x68).value = dev->gpo.enable[0]; - dev->reg.find_reg(0x69).value = dev->gpo.enable[1]; - - switch (dev->model->motor_type) - { - case MOTOR_HP2300: - case MOTOR_HP2400: - dev->reg.find_reg(0x6a).value = 0x7f; /* table two steps number for acc/dec */ - dev->reg.find_reg(0x6b).value = 0x78; /* table two steps number for acc/dec */ - dev->reg.find_reg(0x6d).value = 0x7f; - break; - case MOTOR_5345: - dev->reg.find_reg(0x6a).value = 0x42; /* table two fast moving step type, PWM duty for table two */ - dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */ - dev->reg.find_reg(0x6d).value = 0x41; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - case MOTOR_XP200: - dev->reg.find_reg(0x6a).value = 0x7f; /* table two fast moving step type, PWM duty for table two */ - dev->reg.find_reg(0x6b).value = 0x08; /* table two steps number for acc/dec */ - dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - case MOTOR_HP3670: - dev->reg.find_reg(0x6a).value = 0x41; /* table two steps number for acc/dec */ - dev->reg.find_reg(0x6b).value = 0xc8; /* table two steps number for acc/dec */ - dev->reg.find_reg(0x6d).value = 0x7f; - break; - default: - dev->reg.find_reg(0x6a).value = 0x40; /* table two fast moving step type, PWM duty for table two */ - dev->reg.find_reg(0x6b).value = 0xff; /* table two steps number for acc/dec */ - dev->reg.find_reg(0x6d).value = 0x01; /* select deceleration steps whenever go home (0), accel/decel stop time (31 * LPeriod) */ - break; - } - dev->reg.find_reg(0x6c).value = 0x00; /* peroid times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE (one period time) */ -} - - -/* Send slope table for motor movement - slope_table in machine byte order -*/ -static SANE_Status -gl646_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - int dpihw; - int start_address; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (table_nr = %d, steps = %d)=%d .. %d\n", __func__, table_nr, steps, - slope_table[0], slope_table[steps - 1]); - - dpihw = dev->reg.find_reg(0x05).value >> 6; - - if (dpihw == 0) /* 600 dpi */ - start_address = 0x08000; - else if (dpihw == 1) /* 1200 dpi */ - start_address = 0x10000; - else if (dpihw == 2) /* 2400 dpi */ - start_address = 0x1f800; - else /* reserved */ - return SANE_STATUS_INVAL; - - std::vector table(steps * 2); - for (int i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - status = - sanei_genesys_set_buffer_address (dev, start_address + table_nr * 0x100); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_bulk_write_data(dev, 0x3c, table.data(), steps * 2); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send slope table: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: end\n", __func__); - return status; -} - -/* Set values of Analog Device type frontend */ -static SANE_Status -gl646_set_ad_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - - DBG(DBG_proc, "%s(): start\n", __func__); - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - - dev->frontend = dev->frontend_initial; - - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write reg1: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - if (set == AFE_SET) - { - for (i = 0; i < 3; i++) - { - status = sanei_genesys_fe_write_data(dev, 0x02 + i, dev->frontend.get_gain(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write gain %d: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - for (i = 0; i < 3; i++) - { - status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.get_offset(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write offset %d: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - } - /* - if (set == AFE_POWER_SAVE) - { - status = - sanei_genesys_fe_write_data (dev, 0x00, dev->frontend.reg[0] | 0x04); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status)); - return status; - } - } */ - DBG(DBG_proc, "%s(): end\n", __func__); - - return status; -} - -/** set up analog frontend - * set up analog frontend - * @param dev device to set up - * @param set action from AFE_SET, AFE_INIT and AFE_POWERSAVE - * @param dpi resolution of the scan since it affects settings - * @return SANE_STATUS_GOOD if evrithing OK - */ -static SANE_Status -gl646_wm_hp3670(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set, int dpi) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - - DBGSTART; - switch (set) - { - case AFE_INIT: - status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: reset failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_sleep_ms(200); - RIE (sanei_genesys_write_register (dev, 0x50, 0x00)); - dev->frontend = dev->frontend_initial; - status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.regs.get_value(0x02)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg2 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - gl646_gpio_output_enable(dev->usb_dev, 0x07); - break; - case AFE_POWER_SAVE: - status = sanei_genesys_fe_write_data (dev, 0x01, 0x06); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data (dev, 0x06, 0x0f); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg6 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - return status; - break; - default: /* AFE_SET */ - /* mode setup */ - i = dev->frontend.regs.get_value(0x03); - if (dpi > sensor.optical_res / 2) - { - /* fe_reg_0x03 must be 0x12 for 1200 dpi in DAC_WOLFSON_HP3670. - * DAC_WOLFSON_HP2400 in 1200 dpi mode works well with - * fe_reg_0x03 set to 0x32 or 0x12 but not to 0x02 */ - i = 0x12; - } - status = sanei_genesys_fe_write_data (dev, 0x03, i); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg3 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - /* offset and sign (or msb/lsb ?) */ - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data(dev, 0x20 + i, dev->frontend.get_offset(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing offset%d failed: %s\n", __func__, i, - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x24 + i, - dev->frontend.regs.get_value(0x24 + i)); /* MSB/LSB ? */ - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing sign%d failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - - /* gain */ - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing gain%d failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - } - - DBGCOMPLETED; - return status; -} - -/** Set values of analog frontend - * @param dev device to set - * @param set action to execute - * @param dpi dpi to setup the AFE - * @return error or SANE_STATUS_GOOD */ -static SANE_Status -gl646_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set, int dpi) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - uint8_t val; - - DBG(DBG_proc, "%s (%s,%d)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?", dpi); - - /* Analog Device type frontend */ - if ((dev->reg.find_reg(0x04).value & REG04_FESET) == 0x02) - return gl646_set_ad_fe (dev, set); - - /* Wolfson type frontend */ - if ((dev->reg.find_reg(0x04).value & REG04_FESET) != 0x03) - { - DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, - dev->reg.find_reg(0x04).value & REG04_FESET); - return SANE_STATUS_UNSUPPORTED; - } - - /* per frontend function to keep code clean */ - switch (dev->model->dac_type) - { - case DAC_WOLFSON_HP3670: - case DAC_WOLFSON_HP2400: - return gl646_wm_hp3670(dev, sensor, set, dpi); - break; - default: - DBG(DBG_proc, "%s(): using old method\n", __func__); - break; - } - - /* initialize analog frontend */ - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - dev->frontend = dev->frontend_initial; - - /* reset only done on init */ - status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: init fe failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* enable GPIO for some models */ - if (dev->model->ccd_type == CCD_HP2300) - { - val = 0x07; - gl646_gpio_output_enable(dev->usb_dev, val); - } - return status; - } - - /* set fontend to power saving mode */ - if (set == AFE_POWER_SAVE) - { - status = sanei_genesys_fe_write_data (dev, 0x01, 0x02); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing data failed: %s\n", __func__, sane_strstatus(status)); - } - return status; - } - - /* here starts AFE_SET */ - /* TODO : base this test on cfg reg3 or a CCD family flag to be created */ - /* if (dev->model->ccd_type != CCD_HP2300 - && dev->model->ccd_type != CCD_HP3670 - && dev->model->ccd_type != CCD_HP2400) */ - { - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg0 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.regs.get_value(0x02)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg2 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - /* start with reg3 */ - status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x03)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg3 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - switch (dev->model->ccd_type) - { - default: - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data(dev, 0x24 + i, - dev->frontend.regs.get_value(0x24 + i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing gain[%d] failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_fe_write_data(dev, 0x20 + i, dev->frontend.get_offset(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing offset[%d] failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - break; - /* just can't have it to work .... - case CCD_HP2300: - case CCD_HP2400: - case CCD_HP3670: - - status = - sanei_genesys_fe_write_data(dev, 0x23, dev->frontend.get_offset(1)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing offset[1] failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x28, dev->frontend.get_gain(1)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing gain[1] failed: %s\n", __func__, sane_strstatus (status)); - return status; - } - break; */ - } - - /* end with reg1 */ - status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - - DBG(DBG_proc, "%s: end\n", __func__); - - return SANE_STATUS_GOOD; -} - -/** Set values of analog frontend - * this this the public interface, the gl646 as to use one more - * parameter to work effectively, hence the redirection - * @param dev device to set - * @param set action to execute - * @return error or SANE_STATUS_GOOD */ -static SANE_Status -gl646_public_set_fe (Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) -{ - return gl646_set_fe(dev, sensor, set, dev->settings.yres); -} - -/** - * enters or leaves power saving mode - * limited to AFE for now. - * @param dev scanner's device - * @param enable SANE_TRUE to enable power saving, SANE_FALSE to leave it - * @return allways SANE_STATUS_GOOD - */ -static -SANE_Status -gl646_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - - DBGSTART; - DBG(DBG_info, "%s: enable = %d\n", __func__, enable); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - if (enable) - { - /* gl646_set_fe(dev, sensor, AFE_POWER_SAVE); */ - } - else - { - gl646_set_fe(dev, sensor, AFE_INIT, 0); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl646_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); - int rate, exposure_time, tgtime, time; - - DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); - - local_reg.init_reg(0x01, dev->reg.get8(0x01)); // disable fastmode - local_reg.init_reg(0x03, dev->reg.get8(0x03)); // Lamp power control - local_reg.init_reg(0x05, dev->reg.get8(0x05) & ~REG05_BASESEL); // 24 clocks/pixel - local_reg.init_reg(0x38, 0x00); // line period low - local_reg.init_reg(0x39, 0x00); //line period high - local_reg.init_reg(0x6c, 0x00); // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE - - if (!delay) - local_reg.find_reg(0x03).value &= 0xf0; /* disable lampdog and set lamptime = 0 */ - else if (delay < 20) - local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ - else - local_reg.find_reg(0x03).value = (local_reg.get8(0x03) & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ - - time = delay * 1000 * 60; /* -> msec */ - exposure_time = - (uint32_t) (time * 32000.0 / - (24.0 * 64.0 * (local_reg.get8(0x03) & REG03_LAMPTIM) * - 1024.0) + 0.5); - /* 32000 = system clock, 24 = clocks per pixel */ - rate = (exposure_time + 65536) / 65536; - if (rate > 4) - { - rate = 8; - tgtime = 3; - } - else if (rate > 2) - { - rate = 4; - tgtime = 2; - } - else if (rate > 1) - { - rate = 2; - tgtime = 1; - } - else - { - rate = 1; - tgtime = 0; - } - - local_reg.find_reg(0x6c).value |= tgtime << 6; - exposure_time /= rate; - - if (exposure_time > 65535) - exposure_time = 65535; - - local_reg.find_reg(0x38).value = exposure_time / 256; - local_reg.find_reg(0x39).value = exposure_time & 255; - - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) { - DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: end\n", __func__); - return status; -} - - -/** - * loads document into scanner - * currently only used by XP200 - * bit2 (0x04) of gpio is paper event (document in/out) on XP200 - * HOMESNR is set if no document in front of sensor, the sequence of events is - * paper event -> document is in the sheet feeder - * HOMESNR becomes 0 -> document reach sensor - * HOMESNR becomes 1 ->document left sensor - * paper event -> document is out - */ -static SANE_Status -gl646_load_document (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - // FIXME: sequential not really needed in this case - Genesys_Register_Set regs(Genesys_Register_Set::SEQUENTIAL); - unsigned int used, vfinal, count; - uint16_t slope_table[255]; - uint8_t val; - - DBG(DBG_proc, "%s: start\n", __func__); - - /* no need to load document is flatbed scanner */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - DBG(DBG_proc, "%s: nothing to load\n", __func__); - DBG(DBG_proc, "%s: end\n", __func__); - return SANE_STATUS_GOOD; - } - - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* HOMSNR is set if a document is inserted */ - if ((val & REG41_HOMESNR)) - { - /* if no document, waits for a paper event to start loading */ - /* with a 60 seconde minutes timeout */ - count = 0; - do - { - gl646_gpio_read(dev->usb_dev, &val); - - DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, val); - if ((val & 0x04) != 0x04) - { - DBG(DBG_warn, "%s: no paper detected\n", __func__); - } - sanei_genesys_sleep_ms(200); - count++; - } - while (((val & 0x04) != 0x04) && (count < 300)); /* 1 min time out */ - if (count == 300) - { - DBG(DBG_error, "%s: timeout waiting for document\n", __func__); - return SANE_STATUS_NO_DOCS; - } - } - - /* set up to fast move before scan then move until document is detected */ - regs.init_reg(0x01, 0x90); - - /* AGOME, 2 slopes motor moving */ - regs.init_reg(0x02, 0x79); - - /* motor feeding steps to 0 */ - regs.init_reg(0x3d, 0); - regs.init_reg(0x3e, 0); - regs.init_reg(0x3f, 0); - - /* 50 fast moving steps */ - regs.init_reg(0x6b, 50); - - /* set GPO */ - regs.init_reg(0x66, 0x30); - - /* stesp NO */ - regs.init_reg(0x21, 4); - regs.init_reg(0x22, 1); - regs.init_reg(0x23, 1); - regs.init_reg(0x24, 4); - - /* generate slope table 2 */ - sanei_genesys_generate_slope_table (slope_table, - 50, - 51, - 2400, - 6000, 2400, 50, 0.25, &used, &vfinal); -/* document loading: - * send regs - * start motor - * wait e1 status to become e0 - */ - status = gl646_send_slope_table (dev, 1, slope_table, 50); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl646_start_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - - count = 0; - do - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_sleep_ms(200); - count++; - } - while ((val & REG41_MOTMFLG) && (count < 300)); - if (count == 300) - { - DBG(DBG_error, "%s: can't load document\n", __func__); - return SANE_STATUS_JAMMED; - } - - /* when loading OK, document is here */ - dev->document = SANE_TRUE; - - /* set up to idle */ - regs.set8(0x02, 0x71); - regs.set8(0x3f, 1); - regs.set8(0x6b, 8); - status = sanei_genesys_bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write idle registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: end\n", __func__); - - return status; -} - -/** - * detects end of document and adjust current scan - * to take it into account - * used by sheetfed scanners - */ -static SANE_Status -gl646_detect_document_end (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val, gpio; - unsigned int bytes_left, lines; - - DBG(DBG_proc, "%s: start\n", __func__); - - /* test for document presence */ - RIE (sanei_genesys_get_status (dev, &val)); - if (DBG_LEVEL > DBG_info) - { - print_status (val); - } - gl646_gpio_read(dev->usb_dev, &gpio); - DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); - - /* detect document event. There one event when the document go in, - * then another when it leaves */ - if ((dev->document == SANE_TRUE) && (gpio & 0x04) - && (dev->total_bytes_read > 0)) - { - DBG(DBG_info, "%s: no more document\n", __func__); - dev->document = SANE_FALSE; - - /* adjust number of bytes to read: - * total_bytes_to_read is the number of byte to send to frontend - * total_bytes_read is the number of bytes sent to frontend - * read_bytes_left is the number of bytes to read from the scanner - */ - DBG(DBG_io, "%s: total_bytes_to_read=%lu\n", __func__, (u_long) dev->total_bytes_to_read); - DBG(DBG_io, "%s: total_bytes_read =%lu\n", __func__, (u_long) dev->total_bytes_read); - DBG(DBG_io, "%s: read_bytes_left =%lu\n", __func__, (u_long) dev->read_bytes_left); - - /* amount of data available from scanner is what to scan */ - status = sanei_genesys_read_valid_words (dev, &bytes_left); - - /* we add the number of lines needed to read the last part of the document in */ - lines = - (SANE_UNFIX (dev->model->y_offset) * dev->current_setup.yres) / - MM_PER_INCH; - DBG(DBG_io, "%s: adding %d line to flush\n", __func__, lines); - bytes_left += lines * dev->wpl; - if (dev->current_setup.depth > 8) - { - bytes_left = 2 * bytes_left; - } - if (dev->current_setup.channels > 1) - { - bytes_left = 3 * bytes_left; - } - if (bytes_left < dev->read_bytes_left) - { - dev->total_bytes_to_read = dev->total_bytes_read + bytes_left; - dev->read_bytes_left = bytes_left; - } - DBG(DBG_io, "%s: total_bytes_to_read=%lu\n", __func__, (u_long) dev->total_bytes_to_read); - DBG(DBG_io, "%s: total_bytes_read =%lu\n", __func__, (u_long) dev->total_bytes_read); - DBG(DBG_io, "%s: read_bytes_left =%lu\n", __func__, (u_long) dev->read_bytes_left); - } - DBG(DBG_proc, "%s: end\n", __func__); - - return status; -} - -/** - * eject document from the feeder - * currently only used by XP200 - * TODO we currently rely on AGOHOME not being set for sheetfed scanners, - * maybe check this flag in eject to let the document being eject automaticaly - */ -static SANE_Status -gl646_eject_document (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - // FIXME: SEQUENTIAL not really needed in this case - Genesys_Register_Set regs((Genesys_Register_Set::SEQUENTIAL)); - unsigned int used, vfinal, count; - uint16_t slope_table[255]; - uint8_t gpio, state; - - DBG(DBG_proc, "%s: start\n", __func__); - - /* at the end there will be noe more document */ - dev->document = SANE_FALSE; - - // first check for document event - gl646_gpio_read(dev->usb_dev, &gpio); - - DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); - - /* test status : paper event + HOMESNR -> no more doc ? */ - status = sanei_genesys_get_status (dev, &state); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); - return status; - } - DBG(DBG_info, "%s: state=0x%02x\n", __func__, state); - if (DBG_LEVEL > DBG_info) - { - print_status (state); - } - - /* HOMSNR=0 if no document inserted */ - if ((state & REG41_HOMESNR) != 0) - { - dev->document = SANE_FALSE; - DBG(DBG_info, "%s: no more document to eject\n", __func__); - DBG(DBG_proc, "%s: end\n", __func__); - return status; - } - - /* there is a document inserted, eject it */ - status = sanei_genesys_write_register (dev, 0x01, 0xb0); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* wait for motor to stop */ - do - { - sanei_genesys_sleep_ms(200); - status = sanei_genesys_get_status (dev, &state); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - while (state & REG41_MOTMFLG); - - /* set up to fast move before scan then move until document is detected */ - regs.init_reg(0x01, 0xb0); - - /* AGOME, 2 slopes motor moving , eject 'backward' */ - regs.init_reg(0x02, 0x5d); - - /* motor feeding steps to 119880 */ - regs.init_reg(0x3d, 1); - regs.init_reg(0x3e, 0xd4); - regs.init_reg(0x3f, 0x48); - - /* 60 fast moving steps */ - regs.init_reg(0x6b, 60); - - /* set GPO */ - regs.init_reg(0x66, 0x30); - - /* stesp NO */ - regs.init_reg(0x21, 4); - regs.init_reg(0x22, 1); - regs.init_reg(0x23, 1); - regs.init_reg(0x24, 4); - - /* generate slope table 2 */ - sanei_genesys_generate_slope_table (slope_table, - 60, - 61, - 1600, - 10000, 1600, 60, 0.25, &used, &vfinal); -/* document eject: - * send regs - * start motor - * wait c1 status to become c8 : HOMESNR and ~MOTFLAG - */ - status = gl646_send_slope_table (dev, 1, slope_table, 60); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl646_start_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus (status)); - return SANE_STATUS_IO_ERROR; - } - - /* loop until paper sensor tells paper is out, and till motor is running */ - /* use a 30 timeout */ - count = 0; - do - { - status = sanei_genesys_get_status (dev, &state); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read status: %s\n", __func__, sane_strstatus(status)); - return status; - } - print_status (state); - sanei_genesys_sleep_ms(200); - count++; - } - while (((state & REG41_HOMESNR) == 0) && (count < 150)); - - // read GPIO on exit - gl646_gpio_read(dev->usb_dev, &gpio); - - DBG(DBG_info, "%s: GPIO=0x%02x\n", __func__, gpio); - - DBG(DBG_proc, "%s: end\n", __func__); - return status; -} - -/* Send the low-level scan command */ -static SANE_Status -gl646_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - (void) sensor; - SANE_Status status = SANE_STATUS_GOOD; - // FIXME: SEQUENTIAL not really needed in this case - Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); - - DBG(DBG_proc, "%s\n", __func__); - - local_reg.init_reg(0x03, sanei_genesys_read_reg_from_set(reg, 0x03)); - local_reg.init_reg(0x01, sanei_genesys_read_reg_from_set(reg, 0x01) | REG01_SCAN); /* set scan bit */ - - if (start_motor) { - local_reg.init_reg(0x0f, 0x01); - } else { - local_reg.init_reg(0x0f, 0x00); // do not start motor yet - } - - status = sanei_genesys_bulk_write_register(dev, local_reg); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: end\n", __func__); - - return status; -} - - -/* Send the stop scan command */ -static SANE_Status -end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop, SANE_Bool eject) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i = 0; - uint8_t val, scanfsh = 0; - - DBG(DBG_proc, "%s (check_stop = %d, eject = %d)\n", __func__, check_stop, eject); - - /* we need to compute scanfsh before cancelling scan */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io2) - { - print_status (val); - } - } - - /* ends scan */ - val = sanei_genesys_read_reg_from_set (reg, 0x01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set (reg, 0x01, val); - status = sanei_genesys_write_register (dev, 0x01, val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* for sheetfed scanners, we may have to eject document */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - if (eject == SANE_TRUE && dev->document == SANE_TRUE) - { - status = gl646_eject_document (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to eject document\n", __func__); - return status; - } - } - if (check_stop) - { - for (i = 0; i < 30; i++) /* do not wait longer than wait 3 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read register: %s\n", __func__, - sane_strstatus(status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io2) - { - print_status (val); - } - - if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh) - { - DBG(DBG_proc, "%s: scanfeed finished\n", __func__); - break; /* leave for loop */ - } - - sanei_genesys_sleep_ms(100); - } - } - } - else /* flat bed scanners */ - { - if (check_stop) - { - for (i = 0; i < 300; i++) /* do not wait longer than wait 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read register: %s\n", __func__, - sane_strstatus(status)); - return status; - } - if (val & REG41_SCANFSH) - scanfsh = 1; - if (DBG_LEVEL > DBG_io) - { - print_status (val); - } - - if (!(val & REG41_MOTMFLG) && (val & REG41_FEEDFSH) && scanfsh) - { - DBG(DBG_proc, "%s: scanfeed finished\n", __func__); - break; /* leave while loop */ - } - - if ((!(val & REG41_MOTMFLG)) && (val & REG41_HOMESNR)) - { - DBG(DBG_proc, "%s: head at home\n", __func__); - break; /* leave while loop */ - } - - sanei_genesys_sleep_ms(100); - } - } - } - - DBG(DBG_proc, "%s: end (i=%u)\n", __func__, i); - - return status; -} - -/* Send the stop scan command */ -static SANE_Status -gl646_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - return end_scan (dev, reg, check_stop, SANE_FALSE); -} - -/** - * parks head - * @param dev scanner's device - * @param wait_until_home true if the function waits until head parked - */ -static -SANE_Status -gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - uint8_t val; - int i; - int loop = 0; - - DBG(DBG_proc, "%s: start , wait_until_home = %d\n", __func__, wait_until_home); - - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL > DBG_io) - { - print_status (val); - } - - dev->scanhead_position_in_steps = 0; - - if (val & REG41_HOMESNR) /* is sensor at home? */ - { - DBG(DBG_info, "%s: end since already at home\n", __func__); - return SANE_STATUS_GOOD; - } - - /* stop motor if needed */ - if (val & REG41_MOTMFLG) - { - status = gl646_stop_motor (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - sanei_genesys_sleep_ms(200); - } - - /* when scanhead is moving then wait until scanhead stops or timeout */ - DBG(DBG_info, "%s: ensuring that motor is off\n", __func__); - val = REG41_MOTMFLG; - for (i = 400; i > 0 && (val & REG41_MOTMFLG); i--) /* do not wait longer than 40 seconds, count down to get i = 0 when busy */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to read home sensor & motor status: %s\n", __func__, - sane_strstatus(status)); - return status; - } - if (((val & (REG41_MOTMFLG | REG41_HOMESNR)) == REG41_HOMESNR)) /* at home and motor is off */ - { - DBG(DBG_info, "%s: already at home and not moving\n", __func__); - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - } - - if (!i) /* the loop counted down to 0, scanner still is busy */ - { - DBG(DBG_error, "%s: motor is still on: device busy\n", __func__); - return SANE_STATUS_DEVICE_BUSY; - } - - /* setup for a backward scan of 65535 steps, with no actual data reading */ - settings.scan_method = ScanMethod::FLATBED; - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - settings.xres = get_lowest_resolution(dev->model->ccd_type, 1); - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = 600; - settings.lines = 1; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres); - - status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_TRUE, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* backward , no actual data scanned TODO more setup flags to avoid this register manipulations ? */ - dev->reg.find_reg(0x02).value |= REG02_MTRREV; - dev->reg.find_reg(0x01).value &= ~REG01_SCAN; - sanei_genesys_set_triple(&dev->reg, REG_FEEDL, 65535); - - /* sets frontend */ - status = gl646_set_fe(dev, sensor, AFE_SET, settings.xres); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* write scan registers */ - try { - status = sanei_genesys_bulk_write_register(dev, dev->reg); - } catch (...) { - DBG(DBG_error, "%s: failed to bulk write registers\n", __func__); - } - if (status != SANE_STATUS_GOOD) - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - - /* registers are restored to an iddl state, give up if no head to park */ - if (dev->model->is_sheetfed == SANE_TRUE) - { - DBG(DBG_proc, "%s: end \n", __func__); - return SANE_STATUS_GOOD; - } - - /* starts scan */ - status = gl646_begin_scan(dev, sensor, &dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: \n", __func__); - return status; - } - - /* loop until head parked */ - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to read home sensor: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - if (val & 0x08) /* home sensor */ - { - DBG(DBG_info, "%s: reached home position\n", __func__); - DBG(DBG_proc, "%s: end\n", __func__); - sanei_genesys_sleep_ms(500); - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl646_stop_motor (dev); - end_scan(dev, &dev->reg, SANE_TRUE, SANE_FALSE); - DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - - DBG(DBG_info, "%s: scanhead is still moving\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * Automatically set top-left edge of the scan area by scanning an - * area at 300 dpi from very top of scanner - * @param dev device stucture describing the scanner - * @return SANE_STATUS_GOOD in cas of success, else failure code - */ -static SANE_Status -gl646_search_start_position (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - unsigned int resolution, x, y; - - DBG(DBG_proc, "%s: start\n", __func__); - - /* we scan at 300 dpi */ - resolution = get_closest_resolution(dev->model->ccd_type, 300, 1); - - // FIXME: the current approach of doing search only for one resolution does not work on scanners - // whith employ different sensors with potentially different settings. - auto& sensor = sanei_genesys_find_sensor_for_write(dev, resolution); - - /* fill settings for a gray level scan */ - settings.scan_method = ScanMethod::FLATBED; - settings.scan_mode = ScanColorMode::GRAY; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = 600; - settings.lines = dev->model->search_lines; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan the desired area */ - std::vector data; - status = simple_scan(dev, sensor, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, data); - - /* process data if scan is OK */ - if (status != SANE_STATUS_GOOD) { - DBG(DBG_error, "%s: simple_scan failed\n", __func__); - DBGCOMPLETED; - return status; - } - - - /* handle stagger case : reorder gray data and thus loose some lines */ - if (dev->current_setup.stagger > 0) - { - DBG(DBG_proc, "%s: 'un-staggering'\n", __func__); - for (y = 0; y < settings.lines - dev->current_setup.stagger; y++) - { - /* one point out of 2 is 'unaligned' */ - for (x = 0; x < settings.pixels; x += 2) - { - data[y * settings.pixels + x] = - data[(y + dev->current_setup.stagger) * settings.pixels + - x]; - } - } - /* correct line number */ - settings.lines -= dev->current_setup.stagger; - } - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_pnm_file("gl646_search_position.pnm", data.data(), settings.depth, 1, - settings.pixels, settings.lines); - } - - /* now search reference points on the data */ - status = - sanei_genesys_search_reference_point (dev, sensor, data.data(), - sensor.CCD_start_xoffset, - resolution, settings.pixels, - settings.lines); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, - sane_strstatus(status)); - } - - DBGCOMPLETED; - return status; -} - -/** - * internally overriden during effective calibration - * sets up register for coarse gain calibration - */ -static SANE_Status -gl646_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - (void) sensor; - (void) regs; - - DBG(DBG_proc, "%s\n", __func__); - DBG(DBG_proc, "%s: end\n", __func__); - - /* to make compilers happy ... */ - if (!dev) - { - return SANE_STATUS_INVAL; - } - - return SANE_STATUS_GOOD; -} - - -/** - * init registers for shading calibration - * we assume that scanner's head is on an area suiting shading calibration. - * We scan a full scan width area by the shading line number for the device - * at either at full sensor's resolution or half depending upon half_ccd - * @param dev scanner's device - * @return SANE_STATUS_GOOD if success, else error code - */ -static SANE_Status -gl646_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - (void) regs; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - /* 1: no half_ccd, 2: use half number of pixels */ - int half_ccd = 1; - int cksel = 1; - - DBG(DBG_proc, "%s: start\n", __func__); - - /* fill settings for scan : always a color scan */ - int channels = 3; - - if (sensor.ccd_size_divisor > 1) - { - // when shading all (full width) line, we must adapt to half_ccd case - if (is_half_ccd(dev->model->ccd_type, dev->settings.xres, channels) == SANE_TRUE) - { - half_ccd = 2; - } - } - - settings.scan_method = dev->settings.scan_method; - settings.scan_mode = dev->settings.scan_mode; - if (dev->model->is_cis == SANE_FALSE) - { - // FIXME: always a color scan, but why don't we set scan_mode to COLOR_SINGLE_PASS always? - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - } - settings.xres = sensor.optical_res / half_ccd; - cksel = get_cksel(dev->model->ccd_type, dev->settings.xres, channels); - settings.xres = settings.xres / cksel; - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (sensor.sensor_pixels * settings.xres) / sensor.optical_res; - dev->calib_lines = dev->model->shading_lines; - settings.lines = dev->calib_lines * (3 - half_ccd); - settings.depth = 16; - settings.color_filter = dev->settings.color_filter; - - settings.disable_interpolation = dev->settings.disable_interpolation; - settings.threshold = dev->settings.threshold; - settings.dynamic_lineart = SANE_FALSE; - - /* keep account of the movement for final scan move */ - dev->scanhead_position_in_steps += settings.lines; - - /* we don't want top offset, but we need right margin to be the same - * than the one for the final scan */ - status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE); - - /* used when sending shading calibration data */ - dev->calib_pixels = settings.pixels; - dev->calib_channels = dev->current_setup.channels; - if (dev->model->is_cis == SANE_FALSE) - { - dev->calib_channels = 3; - } - - /* no shading */ - dev->reg.find_reg(0x01).value &= ~REG01_DVDSET; - dev->reg.find_reg(0x02).value |= REG02_ACDCDIS; /* ease backtracking */ - dev->reg.find_reg(0x02).value &= ~(REG02_FASTFED | REG02_AGOHOME); - dev->reg.find_reg(0x05).value &= ~REG05_GMMENB; - sanei_genesys_set_motor_power(dev->reg, false); - - /* TODO another flag to setup regs ? */ - /* enforce needed LINCNT, getting rid of extra lines for color reordering */ - if (dev->model->is_cis == SANE_FALSE) - { - sanei_genesys_set_triple(&dev->reg, REG_LINCNT, dev->calib_lines); - } - else - { - sanei_genesys_set_triple(&dev->reg, REG_LINCNT, dev->calib_lines * 3); - } - - /* copy reg to calib_reg */ - dev->calib_reg = dev->reg; - - /* this is an hack to make calibration cache working .... */ - /* if we don't do this, cache will be identified at the shading calibration - * dpi which is different from calibration one */ - dev->current_setup.xres = dev->settings.xres; - DBG(DBG_info, "%s:\n\tdev->settings.xres=%d\n\tdev->settings.yres=%d\n", __func__, - dev->settings.xres, dev->settings.yres); - - DBG(DBG_proc, "%s: end\n", __func__); - return status; -} - -static bool gl646_needs_home_before_init_regs_for_scan(Genesys_Device* dev) -{ - return (dev->scanhead_position_in_steps > 0 && - dev->settings.scan_method == ScanMethod::FLATBED); -} - -/** - * set up registers for the actual scan. The scan's parameters are given - * through the device settings. It allocates the scan buffers. - */ -static SANE_Status -gl646_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - RIE(setup_for_scan(dev, sensor, &dev->reg, dev->settings, SANE_FALSE, SANE_TRUE, SANE_TRUE)); - - /* gamma is only enabled at final scan time */ - if (dev->settings.depth < 16) - dev->reg.find_reg(0x05).value |= REG05_GMMENB; - - DBGCOMPLETED; - return status; -} - -/** - * set up registers for the actual scan. The scan's parameters are given - * through the device settings. It allocates the scan buffers. - * @param dev scanner's device - * @param regs registers to set up - * @param settings settings of scan - * @param split SANE_TRUE if move to scan area is split from scan, SANE_FALSE is - * scan first moves to area - * @param xcorrection take x geometry correction into account (fixed and detected offsets) - * @param ycorrection take y geometry correction into account - */ -static SANE_Status -setup_for_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set *regs, - Genesys_Settings settings, - SANE_Bool split, - SANE_Bool xcorrection, - SANE_Bool ycorrection) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Int depth; - int channels; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - if (settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - channels = 3; - } - else - { - channels = 1; - } - - depth=settings.depth; - if (settings.scan_mode == ScanColorMode::LINEART) - { - if (settings.dynamic_lineart == SANE_TRUE) - { - depth = 8; - } - else - { - /* XXX STEF XXX : why does the common layer never send depth=1 ? */ - depth = 1; - } - } - - // compute distance to move - float move = 0; - // XXX STEF XXX MD5345 -> optical_ydpi, other base_ydpi => half/full step ? */ - if (split == SANE_FALSE) { - if (dev->model->is_sheetfed == SANE_FALSE) { - if (ycorrection == SANE_TRUE) { - move = SANE_UNFIX(dev->model->y_offset); - } - - // add tl_y to base movement - } - move += settings.tl_y; - - if (move < 0) { - DBG(DBG_error, "%s: overriding negative move value %f\n", __func__, move); - move = 0; - } - } - move = (move * dev->motor.optical_ydpi) / MM_PER_INCH; - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - float start = settings.tl_x; - if (xcorrection) { - if (settings.scan_method == ScanMethod::FLATBED) { - start += SANE_UNFIX(dev->model->x_offset); - } else { - start += SANE_UNFIX(dev->model->x_offset_ta); - } - } - start = (start * sensor.optical_res) / MM_PER_INCH; - - SetupParams params; - params.xres = settings.xres; - params.yres = settings.yres; - params.startx = start; - params.starty = move; - params.pixels = settings.pixels; - params.lines = settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = settings.scan_mode; - params.color_filter = settings.color_filter; - params.flags = 0; - if (settings.scan_method == ScanMethod::TRANSPARENCY) { - params.flags |= SCAN_FLAG_USE_XPA; - } - - uint16_t slope_table0[256] = {}; - uint16_t slope_table1[256] = {}; - - /* set up correct values for scan (gamma and shading enabled) */ - status = gl646_setup_registers(dev, sensor, regs, params, slope_table0, slope_table1, - xcorrection); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed setup registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* send computed slope tables */ - status = - gl646_send_slope_table (dev, 0, slope_table0, - sanei_genesys_read_reg_from_set (regs, 0x21)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send slope table 0: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = - gl646_send_slope_table (dev, 1, slope_table1, - sanei_genesys_read_reg_from_set (regs, 0x6b)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send slope table 1: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return status; -} - -/** - * this function sen gamm table to ASIC - */ -static SANE_Status -gl646_send_gamma_table (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int size; - int address; - SANE_Status status = SANE_STATUS_GOOD; - int bits; - - DBGSTART; - - /* gamma table size */ - if (dev->model->flags & GENESYS_FLAG_14BIT_GAMMA) - { - size = 16384; - bits = 14; - } - else - { - size = 4096; - bits = 12; - } - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - std::vector gamma(size * 2 * 3); - - RIE(sanei_genesys_generate_gamma_buffer(dev, sensor, bits, size-1, size, gamma.data())); - - /* table address */ - switch (dev->reg.find_reg(0x05).value >> 6) - { - case 0: /* 600 dpi */ - address = 0x09000; - break; - case 1: /* 1200 dpi */ - address = 0x11000; - break; - case 2: /* 2400 dpi */ - address = 0x20000; - break; - default: - return SANE_STATUS_INVAL; - } - - /* send address */ - status = sanei_genesys_set_buffer_address (dev, address); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* send data */ - status = sanei_genesys_bulk_write_data(dev, 0x3c, gamma.data(), size * 2 * 3); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send gamma table: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief this function does the led calibration. - * this function does the led calibration by scanning one line of the calibration - * area below scanner's top on white strip. The scope of this function is - * currently limited to the XP200 - */ -static SANE_Status -gl646_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs) -{ - (void) regs; - int total_size; - unsigned int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - unsigned int channels; - int avg[3], avga, avge; - int turn; - uint16_t expr, expg, expb; - Genesys_Settings settings; - SANE_Int resolution; - - SANE_Bool acceptable = SANE_FALSE; - - DBG(DBG_proc, "%s\n", __func__); - if (!dev->model->is_cis) - { - DBG(DBG_proc, "%s: not a cis scanner, nothing to do...\n", __func__); - return SANE_STATUS_GOOD; - } - - /* get led calibration resolution */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - channels = 3; - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - } - else - { - channels = 1; - settings.scan_mode = ScanColorMode::GRAY; - } - resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels); - - /* offset calibration is always done in color mode */ - settings.scan_method = ScanMethod::FLATBED; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (sensor.sensor_pixels * resolution) / sensor.optical_res; - settings.lines = 1; - settings.depth = 16; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* colors * bytes_per_color * scan lines */ - total_size = settings.pixels * channels * 2 * 1; - - std::vector line(total_size); - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - - Sensor_Master uint8_t regs_0x10_0x15[6]; - */ - expr = sensor.exposure.red; - expg = sensor.exposure.green; - expb = sensor.exposure.blue; - - turn = 0; - - do - { - sensor.exposure.red = expr; - sensor.exposure.green = expg; - sensor.exposure.blue = expb; - - DBG(DBG_info, "%s: starting first line reading\n", __func__); - - status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl646_led_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, settings.pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < settings.pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * settings.pixels + 1] * 256 + - line[i * 2 + j * 2 * settings.pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= settings.pixels; - } - - DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - acceptable = SANE_TRUE; - - if (!acceptable) - { - avga = (avg[0] + avg[1] + avg[2]) / 3; - expr = (expr * avga) / avg[0]; - expg = (expg * avga) / avg[1]; - expb = (expb * avga) / avg[2]; - - /* keep exposure time in a working window */ - avge = (expr + expg + expb) / 3; - if (avge > 0x2000) - { - expr = (expr * 0x2000) / avge; - expg = (expg * 0x2000) / avge; - expb = (expb * 0x2000) / avge; - } - if (avge < 0x400) - { - expr = (expr * 0x400) / avge; - expg = (expg * 0x400) / avge; - expb = (expb * 0x400) / avge; - } - } - - turn++; - - } - while (!acceptable && turn < 100); - - DBG(DBG_info,"%s: acceptable exposure: 0x%04x,0x%04x,0x%04x\n", __func__, expr, expg, expb); - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black) -{ - unsigned int i, j, k, average, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average value on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG(DBG_info, "%s: average = %d\n", __func__, average); - return average; -} - - -/** @brief calibration for AD frontend devices - * we do simple scan until all black_pixels are higher than 0, - * raising offset at each turn. - */ -static SANE_Status -ad_fe_offset_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - SANE_Status status = SANE_STATUS_GOOD; - unsigned int channels; - int pass = 0; - SANE_Int resolution; - Genesys_Settings settings; - unsigned int x, y, adr, min; - unsigned int bottom, black_pixels; - - DBG(DBG_proc, "%s: start\n", __func__); - channels = 3; - resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels); - black_pixels = - (sensor.black_pixels * resolution) / sensor.optical_res; - DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); - - settings.scan_method = ScanMethod::FLATBED; - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (sensor.sensor_pixels * resolution) / sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan first line of data with no gain */ - dev->frontend.set_gain(0, 0); - dev->frontend.set_gain(1, 0); - dev->frontend.set_gain(2, 0); - - std::vector line; - - /* scan with no move */ - bottom = 1; - do - { - pass++; - dev->frontend.set_offset(0, bottom); - dev->frontend.set_offset(1, bottom); - dev->frontend.set_offset(2, bottom); - status = - simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to scan first line\n", __func__); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - char title[30]; - snprintf(title, 30, "gl646_offset%03d.pnm", (int)bottom); - sanei_genesys_write_pnm_file (title, line.data(), 8, channels, - settings.pixels, settings.lines); - } - - min = 0; - for (y = 0; y < settings.lines; y++) - { - for (x = 0; x < black_pixels; x++) - { - adr = (x + y * settings.pixels) * channels; - if (line[adr] > min) - min = line[adr]; - if (line[adr + 1] > min) - min = line[adr + 1]; - if (line[adr + 2] > min) - min = line[adr + 2]; - } - } - - DBG(DBG_io2, "%s: pass=%d, min=%d\n", __func__, pass, min); - bottom++; - } - while (pass < 128 && min == 0); - if (pass == 128) - { - DBG(DBG_error, "%s: failed to find correct offset\n", __func__); - return SANE_STATUS_INVAL; - } - - DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - DBG(DBG_proc, "%s: end\n", __func__); - return status; -} - -#define DARK_TARGET 8 -/** - * This function does the offset calibration by scanning one line of the calibration - * area below scanner's top. There is a black margin and the remaining is white. - * genesys_search_start() must have been called so that the offsets and margins - * are already known. - * @param dev scanner's device - * @return SANE_STATUS_GOOD if success, else error code is failure -*/ -static SANE_Status -gl646_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - (void) regs; - SANE_Status status = SANE_STATUS_GOOD; - unsigned int channels; - int pass = 0, avg; - SANE_Int resolution; - Genesys_Settings settings; - int topavg, bottomavg; - int top, bottom, black_pixels; - - /* Analog Device fronted have a different calibration */ - if (dev->model->dac_type == DAC_AD_XP200) - { - return ad_fe_offset_calibration (dev, sensor); - } - - DBG(DBG_proc, "%s: start\n", __func__); - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - channels = 3; - if (dev->settings.xres > sensor.optical_res) { - resolution = get_closest_resolution(dev->model->ccd_type, sensor.optical_res, channels); - } else { - resolution = get_closest_resolution(dev->model->ccd_type, dev->settings.xres, channels); - } - black_pixels = - (sensor.black_pixels * resolution) / sensor.optical_res; - DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); - - settings.scan_method = ScanMethod::FLATBED; - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (sensor.sensor_pixels * resolution) / sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* scan first line of data with no gain, but with offset from - * last calibration */ - dev->frontend.set_gain(0, 0); - dev->frontend.set_gain(1, 0); - dev->frontend.set_gain(2, 0); - - /* scan with no move */ - bottom = 90; - dev->frontend.set_offset(0, bottom); - dev->frontend.set_offset(1, bottom); - dev->frontend.set_offset(2, bottom); - - std::vector first_line, second_line; - - status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, first_line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to scan first line\n", __func__); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - char title[30]; - snprintf(title, 30, "gl646_offset%03d.pnm", bottom); - sanei_genesys_write_pnm_file(title, first_line.data(), 8, channels, - settings.pixels, settings.lines); - } - bottomavg = dark_average(first_line.data(), settings.pixels, settings.lines, channels, - black_pixels); - DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); - - /* now top value */ - top = 231; - dev->frontend.set_offset(0, top); - dev->frontend.set_offset(1, top); - dev->frontend.set_offset(2, top); - status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to scan first line\n", __func__); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - char title[30]; - snprintf(title, 30, "gl646_offset%03d.pnm", top); - sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels, - settings.pixels, settings.lines); - } - topavg = dark_average(second_line.data(), settings.pixels, settings.lines, channels, - black_pixels); - DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.set_offset(0, (top + bottom) / 2); - dev->frontend.set_offset(1, (top + bottom) / 2); - dev->frontend.set_offset(2, (top + bottom) / 2); - - /* scan with no move */ - status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to scan first line\n", __func__); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - char title[30]; - snprintf(title, 30, "gl646_offset%03d.pnm", dev->frontend.get_offset(1)); - sanei_genesys_write_pnm_file (title, second_line.data(), 8, channels, - settings.pixels, settings.lines); - } - - avg = - dark_average (second_line.data(), settings.pixels, settings.lines, channels, - black_pixels); - DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.get_offset(1); - } - else - { - bottomavg = avg; - bottom = dev->frontend.get_offset(1); - } - } - - /* in case of debug do a final scan to get result */ - if (DBG_LEVEL >= DBG_data) - { - status = simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, second_line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to scan final line\n", __func__); - return status; - } - sanei_genesys_write_pnm_file("gl646_offset-final.pnm", second_line.data(), 8, channels, - settings.pixels, settings.lines); - } - - DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - DBG(DBG_proc, "%s: end\n", __func__); - return status; -} - -/** @brief gain calibration for Analog Device frontends - * Alternative coarse gain calibration - */ -static SANE_Status -ad_fe_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, int dpi) -{ - (void) regs; - unsigned int i, channels, val; - unsigned int size, count, resolution, pass; - SANE_Status status = SANE_STATUS_GOOD; - float average; - Genesys_Settings settings; - char title[32]; - - DBGSTART; - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - channels = 3; - resolution = get_closest_resolution(dev->model->ccd_type, dpi, channels); - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - - settings.scan_method = ScanMethod::FLATBED; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (sensor.sensor_pixels * resolution) / sensor.optical_res; - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - size = channels * settings.pixels * settings.lines; - - /* start gain value */ - dev->frontend.set_gain(0, 1); - dev->frontend.set_gain(1, 1); - dev->frontend.set_gain(2, 1); - - average = 0; - pass = 0; - - std::vector line; - - /* loop until each channel raises to acceptable level */ - while ((average < sensor.gain_white_ref) && (pass < 30)) - { - /* scan with no move */ - status = - simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to scan first line\n", __func__); - return status; - } - - /* log scanning data */ - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "gl646_alternative_gain%02d.pnm", (int)pass); - sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels, - settings.lines); - } - pass++; - - /* computes white average */ - average = 0; - count = 0; - for (i = 0; i < size; i++) - { - val = line[i]; - average += val; - count++; - } - average = average / count; - - uint8_t gain0 = dev->frontend.get_gain(0); - // adjusts gain for the channel - if (average < sensor.gain_white_ref) { - gain0 += 1; - } - - dev->frontend.set_gain(0, gain0); - dev->frontend.set_gain(1, gain0); - dev->frontend.set_gain(2, gain0); - - DBG(DBG_proc, "%s: average = %.2f, gain = %d\n", __func__, average, gain0); - } - - DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, - dev->frontend.get_gain(0), - dev->frontend.get_gain(1), - dev->frontend.get_gain(2)); - DBGCOMPLETED; - return status; -} - -/** - * Alternative coarse gain calibration - * this on uses the settings from offset_calibration. First scan moves so - * we can go to calibration area for XPA. - * @param dev device for scan - * @param dpi resolutnio to calibrate at - */ -static SANE_Status -gl646_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, int dpi) -{ - unsigned int i, j, k, channels, val, maximum, idx; - unsigned int count, resolution, pass; - SANE_Status status = SANE_STATUS_GOOD; - float average[3]; - Genesys_Settings settings; - char title[32]; - - if (dev->model->ccd_type == CIS_XP200) - { - return ad_fe_coarse_gain_calibration (dev, sensor, regs, sensor.optical_res); - } - DBGSTART; - - /* setup for a RGB scan, one full sensor's width line */ - /* resolution is the one from the final scan */ - channels = 3; - - /* we are searching a sensor resolution */ - if (dpi > sensor.optical_res) { - resolution = sensor.optical_res; - } else { - resolution = get_closest_resolution(dev->model->ccd_type, dev->settings.xres, channels); - } - - settings.scan_method = dev->settings.scan_method; - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_y = 0; - if (settings.scan_method == ScanMethod::FLATBED) - { - settings.tl_x = 0; - settings.pixels = (sensor.sensor_pixels * resolution) / sensor.optical_res; - } - else - { - settings.tl_x = SANE_UNFIX (dev->model->x_offset_ta); - settings.pixels = (SANE_UNFIX (dev->model->x_size_ta) * resolution) / MM_PER_INCH; - } - settings.lines = CALIBRATION_LINES; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* start gain value */ - dev->frontend.set_gain(0, 1); - dev->frontend.set_gain(1, 1); - dev->frontend.set_gain(2, 1); - - if (channels > 1) - { - average[0] = 0; - average[1] = 0; - average[2] = 0; - idx = 0; - } - else - { - average[0] = 255; - average[1] = 255; - average[2] = 255; - switch (dev->settings.color_filter) { - case ColorFilter::RED: idx = 0; break; - case ColorFilter::GREEN: idx = 1; break; - case ColorFilter::BLUE: idx = 2; break; - default: idx = 0; break; // should not happen - } - average[idx] = 0; - } - pass = 0; - - std::vector line; - - /* loop until each channel raises to acceptable level */ - while (((average[0] < sensor.gain_white_ref) - || (average[1] < sensor.gain_white_ref) - || (average[2] < sensor.gain_white_ref)) && (pass < 30)) - { - /* scan with no move */ - status = - simple_scan(dev, sensor, settings, SANE_FALSE, SANE_TRUE, SANE_FALSE, line); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to scan first line\n", __func__); - return status; - } - - /* log scanning data */ - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "gl646_gain%02d.pnm", (int)pass); - sanei_genesys_write_pnm_file(title, line.data(), 8, channels, settings.pixels, - settings.lines); - } - pass++; - - /* average high level for each channel and compute gain - to reach the target code - we only use the central half of the CCD data */ - for (k = idx; k < idx + channels; k++) - { - /* we find the maximum white value, so we can deduce a threshold - to average white values */ - maximum = 0; - for (i = 0; i < settings.lines; i++) - { - for (j = 0; j < settings.pixels; j++) - { - val = line[i * channels * settings.pixels + j + k]; - if (val > maximum) - maximum = val; - } - } - - /* threshold */ - maximum *= 0.9; - - /* computes white average */ - average[k] = 0; - count = 0; - for (i = 0; i < settings.lines; i++) - { - for (j = 0; j < settings.pixels; j++) - { - /* averaging only white points allow us not to care about dark margins */ - val = line[i * channels * settings.pixels + j + k]; - if (val > maximum) - { - average[k] += val; - count++; - } - } - } - average[k] = average[k] / count; - - /* adjusts gain for the channel */ - if (average[k] < sensor.gain_white_ref) - dev->frontend.set_gain(k, dev->frontend.get_gain(k) + 1); - - DBG(DBG_proc, "%s: channel %d, average = %.2f, gain = %d\n", __func__, k, average[k], - dev->frontend.get_gain(k)); - } - } - - if (channels < 3) { - dev->frontend.set_gain(1, dev->frontend.get_gain(0)); - dev->frontend.set_gain(2, dev->frontend.get_gain(0)); - } - - DBG(DBG_info, "%s: gains=(%d,%d,%d)\n", __func__, - dev->frontend.get_gain(0), - dev->frontend.get_gain(1), - dev->frontend.get_gain(2)); - DBGCOMPLETED; - return status; -} - -/** - * sets up the scanner's register for warming up. We scan 2 lines without moving. - * - */ -static SANE_Status -gl646_init_regs_for_warmup (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * local_reg, - int *channels, int *total_size) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - int resolution, lines; - - DBG(DBG_proc, "%s: start\n", __func__); - - dev->frontend = dev->frontend_initial; - - resolution = get_closest_resolution(dev->model->ccd_type, 300, 1); - - /* set up for a half width 2 lines gray scan without moving */ - settings.scan_method = ScanMethod::FLATBED; - settings.scan_mode = ScanColorMode::GRAY; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = - (sensor.sensor_pixels * resolution) / sensor.optical_res; - settings.lines = 2; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* setup for scan */ - status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_TRUE, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: setup_for_scan failed (%s)\n", __func__, sane_strstatus(status)); - return status; - } - - /* we are not going to move, so clear these bits */ - dev->reg.find_reg(0x02).value &= ~(REG02_FASTFED | REG02_AGOHOME); - - /* don't enable any correction for this scan */ - dev->reg.find_reg(0x01).value &= ~REG01_DVDSET; - - /* copy to local_reg */ - *local_reg = dev->reg; - - /* turn off motor during this scan */ - sanei_genesys_set_motor_power(*local_reg, false); - - /* returned value to higher level warmup function */ - *channels = 1; - uint32_t value = 0; - sanei_genesys_get_triple(local_reg, REG_LINCNT, &value); - lines = value + 1; - *total_size = lines * settings.pixels; - - /* now registers are ok, write them to scanner */ - RIE (gl646_set_fe(dev, sensor, AFE_SET, settings.xres)); - RIE(sanei_genesys_bulk_write_register(dev, *local_reg)); - - DBGCOMPLETED; - return status; -} - - -/* - * this function moves head without scanning, forward, then backward - * so that the head goes to park position. - * as a by-product, also check for lock - */ -static SANE_Status -gl646_repark_head (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - unsigned int expected, steps; - - DBG(DBG_proc, "%s: start\n", __func__); - - settings.scan_method = ScanMethod::FLATBED; - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - settings.xres = get_closest_resolution(dev->model->ccd_type, 75, 1); - settings.yres = settings.xres; - settings.tl_x = 0; - settings.tl_y = 5; - settings.pixels = 600; - settings.lines = 4; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - const auto& sensor = sanei_genesys_find_sensor(dev, settings.xres); - - status = setup_for_scan(dev, sensor, &dev->reg, settings, SANE_FALSE, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* TODO seems wrong ... no effective scan */ - dev->reg.find_reg(0x01).value &= ~REG01_SCAN; - - status = sanei_genesys_bulk_write_register(dev, dev->reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* start scan */ - status = gl646_begin_scan(dev, sensor, &dev->reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: \n", __func__); - return status; - } - - uint32_t value32 = 0; - sanei_genesys_get_triple(&dev->reg, REG_FEEDL, &value32); - expected = value32; - do - { - sanei_genesys_sleep_ms(100); - status = sanei_genesys_read_feed_steps (dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read feed steps: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - while (steps < expected); - - /* toggle motor flag, put an huge step number and redo move backward */ - status = gl646_slow_back_home (dev, 1); - DBG(DBG_proc, "%s: end\n", __func__); - return status; -} - -/* * - * initialize ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - * @param dev device description of the scanner to initailize - * @return SANE_STATUS_GOOD if success, error code if failure - */ -static SANE_Status -gl646_init (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - struct timeval tv; - uint8_t cold = 0, val = 0; - uint32_t addr = 0xdead; - size_t len; - - DBG_INIT (); - DBG(DBG_proc, "%s: start\n", __func__); - - /* to detect real power up condition, we write to REG41 - * with pwrbit set, then read it back. When scanner is cold (just replugged) - * PWRBIT will be set in the returned value - */ - RIE (sanei_genesys_get_status (dev, &cold)); - DBG(DBG_info, "%s: status=0x%02x\n", __func__, cold); - cold = !(cold & REG41_PWRBIT); - if (cold) - { - DBG(DBG_info, "%s: device is cold\n", __func__); - } - else - { - DBG(DBG_info, "%s: device is hot\n", __func__); - } - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - /* if scanning session hasn't been initialized, set it up */ - if (!dev->already_initialized) - { - dev->dark_average_data.clear(); - dev->white_average_data.clear(); - - dev->settings.color_filter = ColorFilter::GREEN; - gettimeofday (&tv, NULL); - dev->init_date = tv.tv_sec; - - /* Set default values for registers */ - gl646_init_regs (dev); - - /* Init shading data */ - RIE (sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels)); - - /* initial calibration reg values */ - dev->calib_reg = dev->reg; - } - - /* execute physical unit init only if cold */ - if (cold) - { - DBG(DBG_info, "%s: device is cold\n", __func__); - - val = 0x04; - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_INIT, INDEX, 1, &val); - - /* ASIC reset */ - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - sanei_genesys_sleep_ms(100); - - /* Write initial registers */ - RIE(sanei_genesys_bulk_write_register(dev, dev->reg)); - - /* Test ASIC and RAM */ - if (!(dev->model->flags & GENESYS_FLAG_LAZY_INIT)) - { - RIE (gl646_asic_test (dev)); - } - - /* send gamma tables if needed */ - status = gl646_send_gamma_table(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send generic gamma tables: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* Set powersaving (default = 15 minutes) */ - RIE (gl646_set_powersaving (dev, 15)); - } /* end if cold */ - - /* Set analog frontend */ - RIE (gl646_set_fe(dev, sensor, AFE_INIT, 0)); - - /* GPO enabling for XP200 */ - if (dev->model->ccd_type == CIS_XP200) - { - sanei_genesys_write_register (dev, 0x68, dev->gpo.enable[0]); - sanei_genesys_write_register (dev, 0x69, dev->gpo.enable[1]); - - // enable GPIO - gl646_gpio_output_enable(dev->usb_dev, 6); - - // writes 0 to GPIO - gl646_gpio_write(dev->usb_dev, 0); - - // clear GPIO enable - gl646_gpio_output_enable(dev->usb_dev, 0); - - sanei_genesys_write_register (dev, 0x66, 0x10); - sanei_genesys_write_register (dev, 0x66, 0x00); - sanei_genesys_write_register (dev, 0x66, 0x10); - } - - /* MD6471/G2410 and XP200 read/write data from an undocumented memory area which - * is after the second slope table */ - if (dev->model->gpo_type != GPO_HP3670 - && dev->model->gpo_type != GPO_HP2400) - { - switch (sensor.optical_res) - { - case 600: - addr = 0x08200; - break; - case 1200: - addr = 0x10200; - break; - case 2400: - addr = 0x1fa00; - break; - } - status = sanei_genesys_set_buffer_address (dev, addr); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up control address\n", __func__); - return SANE_STATUS_INVAL; - } - sanei_usb_set_timeout (2 * 1000); - len = 6; - status = gl646_bulk_read_data (dev, 0x45, dev->control, len); - /* for some reason, read fails here for MD6471, HP2300 and XP200 - * one time out of 2 scanimage launches - */ - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_warn, "%s: failed to read control\n", __func__); - status = gl646_bulk_read_data (dev, 0x45, dev->control, len); - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_warn, "%s: failed to read control\n", __func__); - return SANE_STATUS_INVAL; - } - else - { - DBG(DBG_info, "%s: control read=0x%02x 0x%02x 0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, - dev->control[0], dev->control[1], dev->control[2], dev->control[3], dev->control[4], - dev->control[5]); - } - sanei_usb_set_timeout (30 * 1000); - } - else - /* HP2400 and HP3670 case */ - { - dev->control[0] = 0x00; - dev->control[1] = 0x00; - dev->control[2] = 0x01; - dev->control[3] = 0x00; - dev->control[4] = 0x00; - dev->control[5] = 0x00; - } - - /* ensure head is correctly parked, and check lock */ - if (dev->model->is_sheetfed == SANE_FALSE) - { - if (dev->model->flags & GENESYS_FLAG_REPARK) - { - status = gl646_repark_head (dev); - if (status != SANE_STATUS_GOOD) - { - if (status == SANE_STATUS_INVAL) - { - DBG(DBG_error0, "Your scanner is locked. Please move the lock switch to the " - "unlocked position\n"); - return SANE_STATUS_JAMMED; - } - else - DBG(DBG_error, "%s: gl646_repark_head failed: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - else - { - RIE (gl646_slow_back_home (dev, SANE_TRUE)); - } - } - - /* here session and device are initialized */ - dev->already_initialized = SANE_TRUE; - - DBG(DBG_proc, "%s: end\n", __func__); - return SANE_STATUS_GOOD; -} - -static -SANE_Status -gl646_move_to_ta (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - if (simple_move (dev, SANE_UNFIX (dev->model->y_offset_calib_ta)) != - SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to move to calibration area\n", __func__); - return status; - } - DBGCOMPLETED; - return status; -} - - -/** - * Does a simple scan: ie no line reordering and avanced data buffering and - * shading correction. Memory for data is allocated in this function - * and must be freed by caller. - * @param dev device of the scanner - * @param settings parameters of the scan - * @param move SANE_TRUE if moving during scan - * @param forward SANE_TRUE if moving forward during scan - * @param shading SANE_TRUE to enable shading correction - * @param data pointer for the data - */ -static SANE_Status -simple_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Settings settings, SANE_Bool move, - SANE_Bool forward, SANE_Bool shading, std::vector& data) -{ - SANE_Status status = SANE_STATUS_INVAL; - unsigned int size, lines, x, y, bpp; - SANE_Bool empty, split; - int count; - uint8_t val; - - DBG(DBG_proc, "%s: starting\n", __func__); - DBG(DBG_io, "%s: move=%d, forward=%d, shading=%d\n", __func__, move, forward, shading); - - /* round up to multiple of 3 in case of CIS scanner */ - if (dev->model->is_cis == SANE_TRUE) - { - settings.lines = ((settings.lines + 2) / 3) * 3; - } - - /* setup for move then scan */ - if (move == SANE_TRUE && settings.tl_y > 0) - { - split = SANE_FALSE; - } - else - { - split = SANE_TRUE; - } - status = setup_for_scan(dev, sensor, &dev->reg, settings, split, SANE_FALSE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: setup_for_scan failed (%s)\n", __func__, sane_strstatus(status)); - return status; - } - - /* allocate memory fo scan : LINCNT may have been adjusted for CCD reordering */ - if (dev->model->is_cis == SANE_TRUE) - { - uint32_t value = 0; - sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &value); - lines = value / 3; - } - else - { - uint32_t value = 0; - sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &value); - lines = value + 1; - } - size = lines * settings.pixels; - if (settings.depth == 16) - bpp = 2; - else - bpp = 1; - size *= bpp; - if (settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - size *= 3; - data.clear(); - data.resize(size); - - DBG(DBG_io, "%s: allocated %d bytes of memory for %d lines\n", __func__, size, lines); - - /* put back real line number in settings */ - settings.lines = lines; - - /* initialize frontend */ - status = gl646_set_fe(dev, sensor, AFE_SET, settings.xres); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* no shading correction and not watch dog for simple scan */ - dev->reg.find_reg(0x01).value &= ~(REG01_DVDSET | REG01_DOGENB); - if (shading == SANE_TRUE) - { - dev->reg.find_reg(0x01).value |= REG01_DVDSET; - } - - /* enable gamma table for the scan */ - dev->reg.find_reg(0x05).value |= REG05_GMMENB; - - /* one table movement for simple scan */ - dev->reg.find_reg(0x02).value &= ~REG02_FASTFED; - - if (move == SANE_FALSE) - { - sanei_genesys_set_motor_power(dev->reg, false); - - /* no automatic go home if no movement */ - dev->reg.find_reg(0x02).value &= ~REG02_AGOHOME; - } - if (forward == SANE_FALSE) - { - dev->reg.find_reg(0x02).value |= REG02_MTRREV; - } - else - { - dev->reg.find_reg(0x02).value &= ~REG02_MTRREV; - } - - /* no automatic go home when using XPA */ - if (settings.scan_method == ScanMethod::TRANSPARENCY) - { - dev->reg.find_reg(0x02).value &= ~REG02_AGOHOME; - } - - /* write scan registers */ - status = sanei_genesys_bulk_write_register(dev, dev->reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* starts scan */ - status = gl646_begin_scan(dev, sensor, &dev->reg, move); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: \n", __func__); - return status; - } - - /* wait for buffers to be filled */ - count = 0; - do - { - sanei_genesys_sleep_ms(10); - RIE (sanei_genesys_get_status (dev, &val)); - if (DBG_LEVEL > DBG_info) - { - print_status (val); - } - RIE (sanei_genesys_test_buffer_empty (dev, &empty)); - count++; - } - while (empty && count < 1000); - if (count == 1000) - { - DBG(DBG_error, "%s: failed toread data\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* in case of CIS scanner, we must reorder data */ - if (dev->model->is_cis == SANE_TRUE - && settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - /* alloc one line sized working buffer */ - std::vector buffer(settings.pixels * 3 * bpp); - - /* reorder one line of data and put it back to buffer */ - if (bpp == 1) - { - for (y = 0; y < lines; y++) - { - /* reorder line */ - for (x = 0; x < settings.pixels; x++) - { - buffer[x * 3] = data[y * settings.pixels * 3 + x]; - buffer[x * 3 + 1] = data[y * settings.pixels * 3 + settings.pixels + x]; - buffer[x * 3 + 2] = data[y * settings.pixels * 3 + 2 * settings.pixels + x]; - } - /* copy line back */ - memcpy (data.data() + settings.pixels * 3 * y, buffer.data(), - settings.pixels * 3); - } - } - else - { - for (y = 0; y < lines; y++) - { - /* reorder line */ - for (x = 0; x < settings.pixels; x++) - { - buffer[x * 6] = data[y * settings.pixels * 6 + x * 2]; - buffer[x * 6 + 1] = data[y * settings.pixels * 6 + x * 2 + 1]; - buffer[x * 6 + 2] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2]; - buffer[x * 6 + 3] = data[y * settings.pixels * 6 + 2 * settings.pixels + x * 2 + 1]; - buffer[x * 6 + 4] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2]; - buffer[x * 6 + 5] = data[y * settings.pixels * 6 + 4 * settings.pixels + x * 2 + 1]; - } - /* copy line back */ - memcpy (data.data() + settings.pixels * 6 * y, buffer.data(), - settings.pixels * 6); - } - } - } - - /* end scan , waiting the motor to stop if needed (if moving), but without ejecting doc */ - status = end_scan(dev, &dev->reg, SANE_TRUE, SANE_FALSE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: end\n", __func__); - return status; -} - -/** - * Does a simple move of the given distance by doing a scan at lowest resolution - * shading correction. Memory for data is allocated in this function - * and must be freed by caller. - * @param dev device of the scanner - * @param distance distance to move in MM - */ -static SANE_Status -simple_move (Genesys_Device * dev, SANE_Int distance) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Settings settings; - - DBG(DBG_proc, "%s: %d mm\n", __func__, distance); - - int resolution = get_lowest_resolution(dev->model->ccd_type, 3); - - const auto& sensor = sanei_genesys_find_sensor(dev, resolution); - - /* TODO give a no AGOHOME flag */ - settings.scan_method = ScanMethod::TRANSPARENCY; - settings.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - settings.xres = resolution; - settings.yres = resolution; - settings.tl_y = 0; - settings.tl_x = 0; - settings.pixels = - (sensor.sensor_pixels * settings.xres) / sensor.optical_res; - settings.lines = (distance * settings.xres) / MM_PER_INCH; - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - std::vector data; - status = simple_scan(dev, sensor, settings, SANE_TRUE, SANE_TRUE, SANE_FALSE, data); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: simple_scan failed\n", __func__); - } - - DBGCOMPLETED - return status; -} - -/** - * update the status of the required sensor in the scanner session - * the button fileds are used to make events 'sticky' - */ -static SANE_Status -gl646_update_hardware_sensors (Genesys_Scanner * session) -{ - Genesys_Device *dev = session->dev; - uint8_t value; - - // do what is needed to get a new set of events, but try to not loose any of them. - gl646_gpio_read(dev->usb_dev, &value); - DBG(DBG_io, "%s: GPIO=0x%02x\n", __func__, value); - - // scan button - if (dev->model->buttons & GENESYS_HAS_SCAN_SW) { - switch (dev->model->gpo_type) { - case GPO_XP200: - session->buttons[BUTTON_SCAN_SW].write((value & 0x02) != 0); - break; - case GPO_5345: - session->buttons[BUTTON_SCAN_SW].write(value == 0x16); - break; - case GPO_HP2300: - session->buttons[BUTTON_SCAN_SW].write(value == 0x6c); - break; - case GPO_HP3670: - case GPO_HP2400: - session->buttons[BUTTON_SCAN_SW].write((value & 0x20) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - // email button - if (dev->model->buttons & GENESYS_HAS_EMAIL_SW) { - switch (dev->model->gpo_type) { - case GPO_5345: - session->buttons[BUTTON_EMAIL_SW].write(value == 0x12); - break; - case GPO_HP3670: - case GPO_HP2400: - session->buttons[BUTTON_EMAIL_SW].write((value & 0x08) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - // copy button - if (dev->model->buttons & GENESYS_HAS_COPY_SW) { - switch (dev->model->gpo_type) { - case GPO_5345: - session->buttons[BUTTON_COPY_SW].write(value == 0x11); - break; - case GPO_HP2300: - session->buttons[BUTTON_COPY_SW].write(value == 0x5c); - break; - case GPO_HP3670: - case GPO_HP2400: - session->buttons[BUTTON_COPY_SW].write((value & 0x10) == 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - // power button - if (dev->model->buttons & GENESYS_HAS_POWER_SW) { - switch (dev->model->gpo_type) { - case GPO_5345: - session->buttons[BUTTON_POWER_SW].write(value == 0x14); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - // ocr button - if (dev->model->buttons & GENESYS_HAS_OCR_SW) { - switch (dev->model->gpo_type) { - case GPO_5345: - session->buttons[BUTTON_OCR_SW].write(value == 0x13); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - // document detection - if (dev->model->buttons & GENESYS_HAS_PAGE_LOADED_SW) { - switch (dev->model->gpo_type) { - case GPO_XP200: - session->buttons[BUTTON_PAGE_LOADED_SW].write((value & 0x04) != 0); - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - /* XPA detection */ - if (dev->model->flags & GENESYS_FLAG_XPA) - { - switch (dev->model->gpo_type) - { - case GPO_HP3670: - case GPO_HP2400: - /* test if XPA is plugged-in */ - if ((value & 0x40) == 0) - { - DBG(DBG_io, "%s: enabling XPA\n", __func__); - session->opt[OPT_SOURCE].cap &= ~SANE_CAP_INACTIVE; - } - else - { - DBG(DBG_io, "%s: disabling XPA\n", __func__); - session->opt[OPT_SOURCE].cap |= SANE_CAP_INACTIVE; - } - break; - default: - return SANE_STATUS_UNSUPPORTED; - } - } - - return SANE_STATUS_GOOD; -} - - -static SANE_Status -write_control (Genesys_Device * dev, const Genesys_Sensor& sensor, int resolution) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t control[4]; - uint32_t addr = 0xdead; - - /* 2300 does not write to 'control' */ - if (dev->model->motor_type == MOTOR_HP2300) - return SANE_STATUS_GOOD; - - /* MD6471/G2410/HP2300 and XP200 read/write data from an undocumented memory area which - * is after the second slope table */ - switch (sensor.optical_res) - { - case 600: - addr = 0x08200; - break; - case 1200: - addr = 0x10200; - break; - case 2400: - addr = 0x1fa00; - break; - default: - DBG(DBG_error, "%s: failed to compute control address\n", __func__); - return SANE_STATUS_INVAL; - } - - /* XP200 sets dpi, what other scanner put is unknown yet */ - switch (dev->model->motor_type) - { - case MOTOR_XP200: - /* we put scan's dpi, not motor one */ - control[0] = LOBYTE (resolution); - control[1] = HIBYTE (resolution); - control[2] = dev->control[4]; - control[3] = dev->control[5]; - break; - case MOTOR_HP3670: - case MOTOR_HP2400: - case MOTOR_5345: - default: - control[0] = dev->control[2]; - control[1] = dev->control[3]; - control[2] = dev->control[4]; - control[3] = dev->control[5]; - break; - } - - DBG(DBG_info, "%s: control write=0x%02x 0x%02x 0x%02x 0x%02x\n", __func__, control[0], control[1], - control[2], control[3]); - status = sanei_genesys_set_buffer_address (dev, addr); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up control address\n", __func__); - return SANE_STATUS_INVAL; - } - status = sanei_genesys_bulk_write_data(dev, 0x3c, control, 4); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up control\n", __func__); - return SANE_STATUS_INVAL; - } - return status; -} - -/** - * check if a stored calibration is compatible with requested scan. - * @return true if compatible, false if not. - * Whenever an error is met, it is returned. - * @param dev scanner device - * @param cache cache entry to test - * @param for_overwrite reserved for future use ... - */ -static bool -gl646_is_compatible_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Calibration_Cache * cache, - int for_overwrite) -{ - (void) sensor; -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - int compatible = 1; - - DBG(DBG_proc, "%s: start (for_overwrite=%d)\n", __func__, for_overwrite); - - if (cache == NULL) - return false; - - /* build minimal current_setup for calibration cache use only, it will be better - * computed when during setup for scan - */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - { - dev->current_setup.channels = 3; - } - else - { - dev->current_setup.channels = 1; - } - dev->current_setup.xres = dev->settings.xres; - - DBG(DBG_io, "%s: requested=(%d,%f), tested=(%d,%f)\n", __func__, dev->current_setup.channels, - dev->current_setup.xres, cache->used_setup.channels, cache->used_setup.xres); - - /* a calibration cache is compatible if color mode and x dpi match the user - * requested scan. In the case of CIS scanners, dpi isn't a criteria */ - if (dev->model->is_cis == SANE_FALSE) - { - compatible = - ((dev->current_setup.channels == cache->used_setup.channels) - && (((int) dev->current_setup.xres) == - ((int) cache->used_setup.xres))); - } - else - { - compatible = - (dev->current_setup.channels == cache->used_setup.channels); - } - if (dev->current_setup.params.scan_method != cache->used_setup.params.scan_method) - { - DBG(DBG_io, "%s: current method=%d, used=%d\n", __func__, - static_cast(dev->current_setup.params.scan_method), - static_cast(cache->used_setup.params.scan_method)); - compatible = 0; - } - if (!compatible) - { - DBG(DBG_proc, "%s: completed, non compatible cache\n", __func__); - return false; - } - - /* a cache entry expires after 30 minutes for non sheetfed scanners */ - /* this is not taken into account when overwriting cache entries */ -#ifdef HAVE_SYS_TIME_H - if(for_overwrite == SANE_FALSE) - { - gettimeofday (&time, NULL); - if ((time.tv_sec - cache->last_calibration > 30 * 60) - && (dev->model->is_sheetfed == SANE_FALSE)) - { - DBG(DBG_proc, "%s: expired entry, non compatible cache\n", __func__); - return false; - } - } -#endif - - DBG(DBG_proc, "%s: completed, cache compatible\n", __func__); - return true; -} - -/** - * search for a full width black or white strip. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl646_search_strip(Genesys_Device * dev, const Genesys_Sensor& sensor, SANE_Bool forward, SANE_Bool black) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool half_ccd = SANE_FALSE; - Genesys_Settings settings; - int res = get_closest_resolution(dev->model->ccd_type, 75, 1); - unsigned int pass, count, found, x, y; - char title[80]; - - DBG(DBG_proc, "%s: start\n", __func__); - /* adapt to half_ccd case */ - if (sensor.ccd_size_divisor > 1) - { - /* walk the master mode list to find if half_ccd */ - // FIXME: possibly wrong channel count for is_half_ccd - if (is_half_ccd (dev->model->ccd_type, res, 3) == SANE_TRUE) - { - half_ccd = SANE_TRUE; - } - } - - /* we set up for a lowest available resolution color grey scan, full width */ - settings.scan_method = ScanMethod::FLATBED; - settings.scan_mode = ScanColorMode::GRAY; - settings.xres = res; - settings.yres = res; - settings.tl_x = 0; - settings.tl_y = 0; - settings.pixels = (SANE_UNFIX (dev->model->x_size) * res) / MM_PER_INCH; - if (half_ccd == SANE_TRUE) - { - settings.pixels /= 2; - } - - /* 15 mm at at time */ - settings.lines = (15 * settings.yres) / MM_PER_INCH; /* may become a parameter from genesys_devices.c */ - settings.depth = 8; - settings.color_filter = ColorFilter::RED; - - settings.disable_interpolation = 0; - settings.threshold = 0; - settings.dynamic_lineart = SANE_FALSE; - - /* signals if a strip of the given color has been found */ - found = 0; - - /* detection pass done */ - pass = 0; - - std::vector data; - - /* loop until strip is found or maximum pass number done */ - while (pass < 20 && !found) - { - /* scan a full width strip */ - status = - simple_scan(dev, sensor, settings, SANE_TRUE, forward, SANE_FALSE, data); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: simple_scan failed\n", __func__); - return status; - } - if (DBG_LEVEL >= DBG_data) - { - sprintf (title, "gl646_search_strip_%s%02d.pnm", forward ? "fwd" : "bwd", - (int)pass); - sanei_genesys_write_pnm_file (title, data.data(), settings.depth, 1, - settings.pixels, settings.lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < settings.lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < settings.pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * settings.pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * settings.pixels + x] < 60) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / settings.pixels < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, - pass, y); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < settings.lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < settings.pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * settings.pixels + x] > 60) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * settings.pixels + x] < 60) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (settings.pixels * settings.lines) < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d\n", __func__, settings.pixels, count); - } - } - pass++; - } - if (found) - { - status = SANE_STATUS_GOOD; - DBG(DBG_info, "%s: strip found\n", __func__); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG(DBG_info, "%s: strip not found\n", __func__); - } - return status; -} - -/** the gl646 command set */ -static Genesys_Command_Set gl646_cmd_set = { - "gl646-generic", /* the name of this set */ - - gl646_needs_home_before_init_regs_for_scan, - - gl646_init, - gl646_init_regs_for_warmup, - gl646_init_regs_for_coarse_calibration, - gl646_init_regs_for_shading, - gl646_init_regs_for_scan, - - gl646_get_filter_bit, - gl646_get_lineart_bit, - gl646_get_bitset_bit, - gl646_get_gain4_bit, - gl646_get_fast_feed_bit, - gl646_test_buffer_empty_bit, - gl646_test_motor_flag_bit, - - gl646_public_set_fe, - gl646_set_powersaving, - gl646_save_power, - - gl646_begin_scan, - gl646_end_scan, - - gl646_send_gamma_table, - - gl646_search_start_position, - - gl646_offset_calibration, - gl646_coarse_gain_calibration, - gl646_led_calibration, - - NULL, - gl646_slow_back_home, - NULL, - - sanei_genesys_bulk_write_register, - sanei_genesys_bulk_write_data, - gl646_bulk_read_data, - - gl646_update_hardware_sensors, - - /* sheetfed related functions */ - gl646_load_document, - gl646_detect_document_end, - gl646_eject_document, - gl646_search_strip, - - gl646_is_compatible_calibration, - gl646_move_to_ta, - NULL, - NULL, - NULL -}; - -SANE_Status -sanei_gl646_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl646_cmd_set; - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_gl646.h b/backend/genesys_gl646.h deleted file mode 100644 index 766176a..0000000 --- a/backend/genesys_gl646.h +++ /dev/null @@ -1,594 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003-2004 Henning Meier-Geinitz - Copyright (C) 2004-2005 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz - Copyright (C) 2005-2009 Pierre Willenbrock - - 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 "genesys.h" - -/* - * Genesys Logic GL646 based scanners - */ -/* Individual bits */ -#define REG01_CISSET 0x80 -#define REG01_DOGENB 0x40 -#define REG01_DVDSET 0x20 -#define REG01_FASTMOD 0x10 -#define REG01_COMPENB 0x08 -#define REG01_DRAMSEL 0x04 -#define REG01_SHDAREA 0x02 -#define REG01_SCAN 0x01 - -#define REG02_NOTHOME 0x80 -#define REG02_ACDCDIS 0x40 -#define REG02_AGOHOME 0x20 -#define REG02_MTRPWR 0x10 -#define REG02_FASTFED 0x08 -#define REG02_MTRREV 0x04 -#define REG02_STEPSEL 0x03 - -#define REG02_FULLSTEP 0x00 -#define REG02_HALFSTEP 0x01 -#define REG02_QUATERSTEP 0x02 - -#define REG03_TG3 0x80 -#define REG03_AVEENB 0x40 -#define REG03_XPASEL 0x20 -#define REG03_LAMPPWR 0x10 -#define REG03_LAMPDOG 0x08 -#define REG03_LAMPTIM 0x07 - -#define REG04_LINEART 0x80 -#define REG04_BITSET 0x40 -#define REG04_ADTYPE 0x30 -#define REG04_FILTER 0x0c -#define REG04_FESET 0x03 - -#define REG05_DPIHW 0xc0 -#define REG05_DPIHW_600 0x00 -#define REG05_DPIHW_1200 0x40 -#define REG05_DPIHW_2400 0x80 -#define REG05_DPIHW_4800 0xc0 -#define REG05_GMMTYPE 0x30 -#define REG05_GMM14BIT 0x10 -#define REG05_GMMENB 0x08 -#define REG05_LEDADD 0x04 -#define REG05_BASESEL 0x03 - -#define REG06_PWRBIT 0x10 -#define REG06_GAIN4 0x08 -#define REG06_OPTEST 0x07 - -#define REG07_DMASEL 0x02 -#define REG07_DMARDWR 0x01 - -#define REG16_CTRLHI 0x80 -#define REG16_SELINV 0x40 -#define REG16_TGINV 0x20 -#define REG16_CK1INV 0x10 -#define REG16_CK2INV 0x08 -#define REG16_CTRLINV 0x04 -#define REG16_CKDIS 0x02 -#define REG16_CTRLDIS 0x01 - -#define REG17_TGMODE 0xc0 -#define REG17_TGMODE_NO_DUMMY 0x00 -#define REG17_TGMODE_REF 0x40 -#define REG17_TGMODE_XPA 0x80 -#define REG17_TGW 0x3f - -#define REG18_CNSET 0x80 -#define REG18_DCKSEL 0x60 -#define REG18_CKTOGGLE 0x10 -#define REG18_CKDELAY 0x0c -#define REG18_CKSEL 0x03 - -#define REG1D_CKMANUAL 0x80 - -#define REG1E_WDTIME 0xf0 -#define REG1E_LINESEL 0x0f - -#define REG41_PWRBIT 0x80 -#define REG41_BUFEMPTY 0x40 -#define REG41_FEEDFSH 0x20 -#define REG41_SCANFSH 0x10 -#define REG41_HOMESNR 0x08 -#define REG41_LAMPSTS 0x04 -#define REG41_FEBUSY 0x02 -#define REG41_MOTMFLG 0x01 - -#define REG66_LOW_CURRENT 0x10 - -#define REG6A_FSTPSEL 0xc0 -#define REG6A_FASTPWM 0x3f - -#define REG6C_TGTIME 0xc0 -#define REG6C_Z1MOD 0x38 -#define REG6C_Z2MOD 0x07 - -#define REG_SCANFED 0x1f -#define REG_BUFSEL 0x20 -#define REG_LINCNT 0x25 -#define REG_DPISET 0x2c -#define REG_STRPIXEL 0x30 -#define REG_ENDPIXEL 0x32 -#define REG_DUMMY 0x34 -#define REG_MAXWD 0x35 -#define REG_LPERIOD 0x38 -#define REG_FEEDL 0x3d -#define REG_VALIDWORD 0x42 -#define REG_FEDCNT 0x48 -#define REG_SCANCNT 0x4b -#define REG_Z1MOD 0x60 -#define REG_Z2MOD 0x62 - - -#include "genesys.h" - -static SANE_Status gl646_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t set, int dpi); - -static SANE_Status gl646_public_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t set); - -static -SANE_Status -gl646_save_power (Genesys_Device * dev, SANE_Bool enable); - -static -SANE_Status -gl646_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); - -static -SANE_Status -gl646_move_to_ta (Genesys_Device * dev); - -/** - * sets up the scanner for a scan, registers, gamma tables, shading tables - * and slope tables, based on the parameter struct. - * @param dev device to set up - * @param regs registers to set up - * @param settings settings of the scan - * @param split true if move before scan has to be done - * @param xcorrection true if scanner's X geometry must be taken into account to - * compute X, ie add left margins - * @param ycorrection true if scanner's Y geometry must be taken into account to - * compute Y, ie add top margins - */ -static SANE_Status -setup_for_scan (Genesys_Device *device, - const Genesys_Sensor& sensor, - Genesys_Register_Set *regs, - Genesys_Settings settings, - SANE_Bool split, - SANE_Bool xcorrection, - SANE_Bool ycorrection); - -/** - * sets up the registers for a scan corresponding to the settings. - * Builds motor slope tables. Computes buffer sizes and data amount to - * transfer. It also sets up analog frontend. - * */ -static SANE_Status -gl646_setup_registers (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, SetupParams& params, - uint16_t * slope_table1, - uint16_t * slope_table2, - bool xcorrection); - -/** - * Does a simple move of the given distance by doing a scan at lowest resolution - * shading correction. Memory for data is allocated in this function - * and must be freed by caller. - * @param dev device of the scanner - * @param distance distance to move in MM - */ -static SANE_Status -simple_move (Genesys_Device * dev, SANE_Int distance); - -/** - * Does a simple scan of the area given by the settings. Scanned data - * it put in an allocated area which must be freed by the caller. - * and slope tables, based on the parameter struct. There is no shading - * correction while gamma correction is active. - * @param dev device to set up - * @param settings settings of the scan - * @param move flag to enable scanhead to move - * @param forward flag to tell movement direction - * @param shading flag to tell if shading correction should be done - * @param data pointer that will point to the scanned data - */ -static SANE_Status -simple_scan(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Settings settings, SANE_Bool move, SANE_Bool forward, - SANE_Bool shading, std::vector& data); - -/** - * Send the stop scan command - * */ -static SANE_Status -end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop, SANE_Bool eject); -/** - * writes control data to an area behind the last motor table. - */ -static SANE_Status write_control (Genesys_Device * dev, const Genesys_Sensor& sensor, - int resolution); - - -/** - * initialize scanner's registers at SANE init time - */ -static void gl646_init_regs (Genesys_Device * dev); - -static SANE_Status gl646_load_document (Genesys_Device * dev); - -static SANE_Status -gl646_detect_document_end (Genesys_Device * dev); - -#define FULL_STEP 0 -#define HALF_STEP 1 -#define QUATER_STEP 2 - -#define CALIBRATION_LINES 10 - -/** - * master motor settings table entry - */ -typedef struct -{ - /* key */ - SANE_Int motor; - SANE_Int dpi; - unsigned channels; - - /* settings */ - SANE_Int ydpi; /* real motor dpi, may be different from the resolution */ - SANE_Int steptype; /* 0=full, 1=half, 2=quarter */ - SANE_Bool fastmod; /* fast scanning 0/1 */ - SANE_Bool fastfed; /* fast fed slope tables */ - SANE_Int mtrpwm; - SANE_Int steps1; /* table 1 informations */ - SANE_Int vstart1; - SANE_Int vend1; - SANE_Int steps2; /* table 2 informations */ - SANE_Int vstart2; - SANE_Int vend2; - float g1; - float g2; - SANE_Int fwdbwd; /* forward/backward steps */ -} Motor_Master; - -/** - * master sensor settings table entry - */ -typedef struct -{ - /* key */ - SANE_Int sensor; /**< sensor identifier */ - SANE_Int dpi; /**< required dpi */ - unsigned channels; // 3 channels if color scan, 1 channel for gray scan - - /* settings */ - SANE_Int xdpi; /**< real sensor dpi, may be different from the required resolution */ - SANE_Int exposure; /**< exposure time */ - SANE_Int dpiset; /**< set sensor dpi */ - SANE_Int cksel; /**< dpiset 'divisor', part of reg 18h */ - SANE_Int dummy; /**< dummy exposure time */ - /* uint8_t regs_0x10_0x15[6];*/ - uint8_t *regs_0x10_0x15; /**< per color exposure time for CIS scanners */ - SANE_Bool half_ccd; /**> true if manual CCD/2 clock programming or real dpi is half dpiset */ - uint8_t r18; /**> content of register 18h */ - uint8_t r1d; /**> content of register 1dh */ -} Sensor_Master; - -/** - * settings for a given resolution and DPISET - * TODO clean up this when all scanners will have been added - */ -typedef struct -{ - /* key */ - SANE_Int sensor; - SANE_Int cksel; - - /* values */ - uint8_t regs_0x08_0x0b[4]; /**< settings for normal CCD clock */ - uint8_t manual_0x08_0x0b[4]; /**< settings for CCD/2 clock */ - uint8_t regs_0x16_0x1d[8]; - uint8_t regs_0x52_0x5e[13]; - uint8_t manual_0x52_0x58[7]; -} Sensor_Settings; - -static uint8_t xp200_color[6]={0x16, 0x44, 0x0c, 0x80, 0x09, 0x2e}; -static uint8_t xp200_gray[6]={0x05, 0x0a, 0x0f, 0xa0, 0x10, 0x10}; - -/** - * master sensor settings, for a given sensor and dpi, - * it gives exposure and CCD time - */ -static Sensor_Master sensor_master[] = { - /* HP3670 master settings */ - {CCD_HP3670, 75, 3, 75, 4879, 300, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 100, 3, 100, 4487, 400, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 150, 3, 150, 4879, 600, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 300, 3, 300, 4503, 1200, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 600, 3, 600, 10251, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x43}, - {CCD_HP3670,1200, 3, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, - {CCD_HP3670,2400, 3, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, - {CCD_HP3670, 75, 1, 75, 4879, 300, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 100, 1, 100, 4487, 400, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 150, 1, 150, 4879, 600, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 300, 1, 300, 4503, 1200, 4, 42, NULL, SANE_FALSE, 0x33, 0x43}, - {CCD_HP3670, 600, 1, 600, 10251, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x43}, - {CCD_HP3670,1200, 1, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, - {CCD_HP3670,2400, 1, 1200, 12750, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x43}, - - /* HP 2400 master settings */ - {CCD_HP2400, 50, 3, 50, 7211, 200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 100, 3, 100, 7211, 400, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 150, 3, 150, 7211, 600, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 300, 3, 300, 8751, 1200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 600, 3, 600, 18760, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x02}, - {CCD_HP2400,1200, 3, 1200, 21749, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x42}, - {CCD_HP2400, 50, 1, 50, 7211, 200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 100, 1, 100, 7211, 400, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 150, 1, 150, 7211, 600, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 300, 1, 300, 8751, 1200, 4, 42, NULL, SANE_FALSE, 0x3f, 0x02}, - {CCD_HP2400, 600, 1, 600, 18760, 1200, 2, 42, NULL, SANE_FALSE, 0x31, 0x02}, - {CCD_HP2400,1200, 1, 1200, 21749, 1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x42}, - - /* XP 200 master settings */ - {CIS_XP200 , 75, 3, 75, 5700, 75, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 100, 3, 100, 5700, 100, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 200, 3, 200, 5700, 200, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 300, 3, 300, 9000, 300, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 600, 3, 600, 16000, 600, 1, 42, xp200_color, SANE_FALSE, 0x00, 0x11}, - - {CIS_XP200 , 75, 1, 75, 16000, 75, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 100, 1, 100, 7800, 100, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 200, 1, 200, 11000, 200, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 300, 1, 300, 13000, 300, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - {CIS_XP200 , 600, 1, 600, 24000, 600, 1, 42, xp200_gray, SANE_FALSE, 0x00, 0x11}, - - /* HP 2300 master settings */ - {CCD_HP2300, 75, 3, 75, 4480, 150, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 150, 3, 150, 4350, 300, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 300, 3, 300, 4350, 600, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 600, 3, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - {CCD_HP2300,1200, 3, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - {CCD_HP2300, 75, 1, 75, 4480, 150, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 150, 1, 150, 4350, 300, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 300, 1, 300, 4350, 600, 1, 42, NULL, SANE_TRUE , 0x20, 0x85}, - {CCD_HP2300, 600, 1, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - {CCD_HP2300,1200, 1, 600, 8700, 600, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - /* non half ccd 300 dpi settings - {CCD_HP2300, 300, 3, 300, 8700, 300, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - {CCD_HP2300, 300, 1, 300, 8700, 300, 1, 42, NULL, SANE_FALSE, 0x20, 0x05}, - */ - - /* MD5345/6471 master settings */ - {CCD_5345 , 50, 3, 50, 12000, 100, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 75, 3, 75, 11000, 150, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 100, 3, 100, 11000, 200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 150, 3, 150, 11000, 300, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 200, 3, 200, 11000, 400, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 300, 3, 300, 11000, 600, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 400, 3, 400, 11000, 800, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 600, 3, 600, 11000,1200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 ,1200, 3, 1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, - {CCD_5345 ,2400, 3, 1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, - {CCD_5345 , 50, 1, 50, 12000, 100, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 75, 1, 75, 11000, 150, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 100, 1, 100, 11000, 200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 150, 1, 150, 11000, 300, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 200, 1, 200, 11000, 400, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 300, 1, 300, 11000, 600, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 400, 1, 400, 11000, 800, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 , 600, 1, 600, 11000,1200, 1, 42, NULL, SANE_TRUE , 0x28, 0x03}, - {CCD_5345 ,1200, 1, 1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, - {CCD_5345 ,2400, 1, 1200, 11000,1200, 1, 42, NULL, SANE_FALSE, 0x30, 0x03}, - -}; - -/** - * master motor settings, for a given motor and dpi, - * it gives steps and speed informations - */ -static Motor_Master motor_master[] = { - /* HP3670 motor settings */ - {MOTOR_HP3670, 75, 3, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 1, 200, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 100, 3, 100, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 143, 2905, 187, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 150, 3, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 73, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 300, 3, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 11, 1055, 563, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 600, 3, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 10687, 5126, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670,1200, 3,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 6375, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670,2400, 3,2400, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 12750, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 75, 1, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 1, 200, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 100, 1, 100, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 143, 2905, 187, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 150, 1, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 73, 3429, 305, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 300, 1, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 1, 11, 1055, 563, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670, 600, 1, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 10687, 5126, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670,1200, 1,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 6375, 192, 3399, 337, 0.3, 0.4, 192}, - {MOTOR_HP3670,2400, 3,2400, HALF_STEP, SANE_FALSE, SANE_TRUE , 0, 3, 15937, 12750, 192, 3399, 337, 0.3, 0.4, 192}, - - /* HP2400/G2410 motor settings base motor dpi = 600 */ - {MOTOR_HP2400, 50, 3, 50, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 100, 3, 100, HALF_STEP, SANE_FALSE, SANE_TRUE, 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 150, 3, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 15902, 902, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 300, 3, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 32, 16703, 2188, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 600, 3, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 18761, 18761, 192, 4905, 627, 0.30, 0.4, 192}, - {MOTOR_HP2400,1200, 3,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 43501, 43501, 192, 4905, 627, 0.30, 0.4, 192}, - {MOTOR_HP2400, 50, 1, 50, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 100, 1, 100, HALF_STEP, SANE_FALSE, SANE_TRUE, 63, 120, 8736, 601, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 150, 1, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 15902, 902, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 300, 1, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 32, 16703, 2188, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400, 600, 1, 600, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 18761, 18761, 192, 4905, 337, 0.30, 0.4, 192}, - {MOTOR_HP2400,1200, 1,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 43501, 43501, 192, 4905, 337, 0.30, 0.4, 192}, - - /* XP 200 motor settings */ - {MOTOR_XP200, 75, 3, 75, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2136, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 100, 3, 100, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2850, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 200, 3, 200, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6999, 5700, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 250, 3, 250, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6999, 6999, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 300, 3, 300, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 13500, 13500, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 600, 3, 600, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 31998, 31998, 2, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 75, 1, 75, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 2000, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 100, 1, 100, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6000, 1300, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 200, 1, 200, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 6000, 3666, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 300, 1, 300, HALF_STEP, SANE_TRUE , SANE_FALSE, 0, 4, 6500, 6500, 8, 12000, 1200, 0.3, 0.5, 1}, - {MOTOR_XP200, 600, 1, 600, HALF_STEP, SANE_TRUE , SANE_TRUE, 0, 4, 24000, 24000, 2, 12000, 1200, 0.3, 0.5, 1}, - - /* HP scanjet 2300c */ - {MOTOR_HP2300, 75, 3, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8139, 560, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 150, 3, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 7903, 543, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 300, 3, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 2175, 1087, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 600, 3, 600, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 8700, 4350, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300,1200, 3,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 17400, 8700, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 75, 1, 75, FULL_STEP, SANE_FALSE, SANE_TRUE , 63, 120, 8139, 560, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 150, 1, 150, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 67, 7903, 543, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 300, 1, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 2175, 1087, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 600, 1, 600, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 8700, 4350, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300,1200, 1,1200, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 3, 17400, 8700, 120, 4905, 337, 0.3, 0.4, 16}, - /* non half ccd settings for 300 dpi - {MOTOR_HP2300, 300, 3, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 44, 5386, 2175, 120, 4905, 337, 0.3, 0.4, 16}, - {MOTOR_HP2300, 300, 1, 300, HALF_STEP, SANE_FALSE, SANE_TRUE , 63, 44, 5386, 2175, 120, 4905, 337, 0.3, 0.4, 16}, - */ - - /* MD5345/6471 motor settings */ - /* vfinal=(exposure/(1200/dpi))/step_type */ - {MOTOR_5345, 50, 3, 50, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 250, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 75, 3, 75, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 343, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 100, 3, 100, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 458, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 150, 3, 150, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 687, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 200, 3, 200, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 916, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 300, 3, 300, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 1375, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 400, 3, 400, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2000, 1833, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 500, 3, 500, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2291, 2291, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 600, 3, 600, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 1200, 3,1200, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 146}, - {MOTOR_5345, 2400, 3,2400, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 5500, 5500, 255, 2000, 300, 0.3, 0.4, 146}, - {MOTOR_5345, 50, 1, 50, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 250, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 75, 1, 75, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 343, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 100, 1, 100, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 458, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 150, 1, 150, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 687, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 200, 1, 200, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 916, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 300, 1, 300, HALF_STEP , SANE_FALSE, SANE_TRUE , 2, 255, 2500, 1375, 255, 2000, 300, 0.3, 0.4, 64}, - {MOTOR_5345, 400, 1, 400, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2000, 1833, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 500, 1, 500, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2291, 2291, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 600, 1, 600, HALF_STEP , SANE_FALSE, SANE_TRUE , 0, 32, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 32}, - {MOTOR_5345, 1200, 1,1200, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 2750, 2750, 255, 2000, 300, 0.3, 0.4, 146}, - {MOTOR_5345, 2400, 1,2400, QUATER_STEP, SANE_FALSE, SANE_TRUE , 0, 16, 5500, 5500, 255, 2000, 300, 0.3, 0.4, 146}, /* 5500 guessed */ -}; - -/** - * sensor settings for a given sensor and timing method - */ -static Sensor_Settings sensor_settings[] = { - /* HP 3670 */ - {CCD_HP3670, 1, - {0x0d, 0x0f, 0x11, 0x13}, - {0x00, 0x00, 0x00, 0x00}, - {0x2b, 0x07, 0x30, 0x2a, 0x00, 0x00, 0xc0, 0x43}, - {0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17, 0x23, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00, }, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - }, - {CCD_HP3670, 2, - {0x00, 0x05, 0x06, 0x08}, - {0x00, 0x00, 0x00, 0x00}, - {0x33, 0x07, 0x31, 0x2a, 0x02, 0x0e, 0xc0, 0x43}, - {0x0b, 0x0f, 0x13, 0x17, 0x03, 0x07, 0x63, 0x00, 0xc1, 0x02, 0x0e, 0x00, 0x00, }, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - }, - {CCD_HP3670, 4, - {0x00, 0x0a, 0x0b, 0x0d}, - {0x00, 0x00, 0x00, 0x00}, - {0x33, 0x07, 0x33, 0x2a, 0x02, 0x13, 0xc0, 0x43}, - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83, 0x15, 0xc1, 0x05, 0x0a, 0x0f, 0x00, }, - {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} - }, - /* HP 2400 */ - {CCD_HP2400, 4, - {0x14, 0x15, 0x00, 0x00}, - {0x00, 0x00, 0x00, 0x00}, - {0xbf, 0x08, 0x3f, 0x2a, 0x00, 0x00, 0x00, 0x02}, - {11, 15, 19, 23, 3, 7, 0x63, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00}, - {11, 15, 19, 23, 3, 7, 0x63} - }, - {CCD_HP2400, 2, - {14, 15, 0, 0}, - {14, 15, 0, 0}, - {0xbf, 0x08, 0x31, 0x2a, 0, 0, 0, 0x02}, - {3, 7, 11, 15, 19, 23, 0x23, 0, 0xc1, 0, 0, 0, 0}, - {3, 7, 11, 15, 19, 23, 0x23} - }, - {CCD_HP2400, 1, - {0x02, 0x04, 0x00, 0x00}, - {0x02, 0x04, 0x00, 0x00}, - {0xbf, 0x08, 0x30, 0x2a, 0x00, 0x00, 0xc0, 0x42}, - {0x0b, 0x0f, 0x13, 0x17, 0x03, 0x07, 0x63, 0x00, 0xc1, 0x00, 0x0e, 0x00, 0x00}, - {0x0b, 0x0f, 0x13, 0x17, 0x03, 0x07, 0x63} - }, - {CIS_XP200, 1, - {6, 7, 10, 4}, - {6, 7, 10, 4}, - {0x24, 0x04, 0x00, 0x2a, 0x0a, 0x0a, 0, 0x11}, - {8, 2, 0, 0, 0, 0, 0x1a, 0x51, 0, 0, 0, 0, 0}, - {8, 2, 0, 0, 0, 0, 0x1a} - }, - {CCD_HP2300, 1, - {0x01, 0x03, 0x04, 0x06}, - {0x16, 0x00, 0x01, 0x03}, - {0xb7, 0x0a, 0x20, 0x2a, 0x6a, 0x8a, 0x00, 0x05}, - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83, 0x00, 0xc1, 0x06, 0x0b, 0x10, 0x16}, - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83} - }, - {CCD_5345, 1, - {0x0d, 0x0f, 0x11, 0x13}, - {0x00, 0x05, 0x06, 0x08}, /* manual clock 1/2 settings or half ccd */ - {0x0b, 0x0a, 0x30, 0x2a, 0x00, 0x00, 0x00, 0x03, }, - {0x03, 0x07, 0x0b, 0x0f, 0x13, 0x17, 0x23, 0x00, 0xc1, 0x00, 0x00, 0x00, 0x00}, - {0x0f, 0x13, 0x17, 0x03, 0x07, 0x0b, 0x83} /* half ccd settings */ - }, -}; diff --git a/backend/genesys_gl841.cc b/backend/genesys_gl841.cc deleted file mode 100644 index 9e8fc15..0000000 --- a/backend/genesys_gl841.cc +++ /dev/null @@ -1,5624 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003 Oliver Rauch - Copyright (C) 2003, 2004 Henning Meier-Geinitz - Copyright (C) 2004 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz - Copyright (C) 2005 Philipp Schmid - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2006 Laurent Charpentier - Copyright (C) 2010 Chris Berry and Michael Rickmann - for Plustek Opticbook 3600 support - - - 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. -*/ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_gl841.h" - -#include - -/**************************************************************************** - Low level function - ****************************************************************************/ - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - -/* Set address for writing data */ -static SANE_Status -gl841_set_buffer_address_gamma (Genesys_Device * dev, uint32_t addr) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xfffffff0); - - addr = addr >> 4; - - status = sanei_genesys_write_register (dev, 0x5c, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while writing low byte: %s\n", __func__, sane_strstatus(status)); - return status; - } - - addr = addr >> 8; - status = sanei_genesys_write_register (dev, 0x5b, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while writing high byte: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_io, "%s: completed\n", __func__); - - return status; -} - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl841_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_get_filter_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_get_lineart_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_get_bitset_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_get_gain4_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl841_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** copy sensor specific settings */ -/* *dev : device infos - *regs : registers to be set - extended : do extended set up - half_ccd: set up for half ccd resolution - all registers 08-0B, 10-1D, 52-59 are set up. They shouldn't - appear anywhere else but in register_ini - -Responsible for signals to CCD/CIS: - CCD_CK1X (CK1INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1MTGL(0x1C),CK1LOW(0x1D),CK1MAP(0x74,0x75,0x76),CK1NEG(0x7D)) - CCD_CK2X (CK2INV(0x16),CKDIS(0x16),CKTOGGLE(0x18),CKDELAY(0x18),MANUAL1(0x1A),CK1LOW(0x1D),CK1NEG(0x7D)) - CCD_CK3X (MANUAL3(0x1A),CK3INV(0x1A),CK3MTGL(0x1C),CK3LOW(0x1D),CK3MAP(0x77,0x78,0x79),CK3NEG(0x7D)) - CCD_CK4X (MANUAL3(0x1A),CK4INV(0x1A),CK4MTGL(0x1C),CK4LOW(0x1D),CK4MAP(0x7A,0x7B,0x7C),CK4NEG(0x7D)) - CCD_CPX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),CPH(0x72),CPL(0x73),CPNEG(0x7D)) - CCD_RSX (CTRLHI(0x16),CTRLINV(0x16),CTRLDIS(0x16),RSH(0x70),RSL(0x71),RSNEG(0x7D)) - CCD_TGX (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPR(0x10,0x11),TGSHLD(0x1D)) - CCD_TGG (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPG(0x12,0x13),TGSHLD(0x1D)) - CCD_TGB (TGINV(0x16),TGMODE(0x17),TGW(0x17),EXPB(0x14,0x15),TGSHLD(0x1D)) - LAMP_SW (EXPR(0x10,0x11),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) - XPA_SW (EXPG(0x12,0x13),XPA_SEL(0x03),LAMP_PWR(0x03),LAMPTIM(0x03),MTLLAMP(0x04),LAMPPWM(0x29)) - LAMP_B (EXPB(0x14,0x15),LAMP_PWR(0x03)) - -other registers: - CISSET(0x01),CNSET(0x18),DCKSEL(0x18),SCANMOD(0x18),EXPDMY(0x19),LINECLP(0x1A),CKAREA(0x1C),TGTIME(0x1C),LINESEL(0x1E),DUMMY(0x34) - -Responsible for signals to AFE: - VSMP (VSMP(0x58),VSMPW(0x58)) - BSMP (BSMP(0x59),BSMPW(0x59)) - -other register settings depending on this: - RHI(0x52),RLOW(0x53),GHI(0x54),GLOW(0x55),BHI(0x56),BLOW(0x57), - -*/ -static void sanei_gl841_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, - SANE_Bool extended, SANE_Bool half_ccd) -{ - DBG(DBG_proc, "%s\n", __func__); - - // that one is tricky at least - for (uint16_t addr = 0x08; addr <= 0x0b; ++addr) { - regs->set8(0x70 + addr - 0x08, sensor.custom_regs.get_value(addr)); - } - - // ignore registers in range [0x10..0x16) - for (uint16_t addr = 0x16; addr < 0x1e; ++addr) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - // ignore registers in range [0x5b..0x5e] - for (uint16_t addr = 0x52; addr < 0x52 + 9; ++addr) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - /* don't go any further if no extended setup */ - if (!extended) - return; - - /* todo : add more CCD types if needed */ - /* we might want to expand the Sensor struct to have these - 2 kind of settings */ - if (dev->model->ccd_type == CCD_5345) - { - if (half_ccd) - { - GenesysRegister* r; - /* settings for CCD used at half is max resolution */ - r = sanei_genesys_get_address (regs, 0x70); - r->value = 0x00; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 0x05; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 0x06; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 0x08; - r = sanei_genesys_get_address (regs, 0x18); - r->value = 0x28; - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ - } - else - { - GenesysRegister* r; - /* swap latch times */ - r = sanei_genesys_get_address (regs, 0x18); - r->value = 0x30; - regs->set8(0x52, sensor.custom_regs.get_value(0x55)); - regs->set8(0x53, sensor.custom_regs.get_value(0x56)); - regs->set8(0x54, sensor.custom_regs.get_value(0x57)); - regs->set8(0x55, sensor.custom_regs.get_value(0x52)); - regs->set8(0x56, sensor.custom_regs.get_value(0x53)); - regs->set8(0x57, sensor.custom_regs.get_value(0x54)); - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x20 | (r->value & 0x03); /* VSMP=4 */ - } - return; - } - - if (dev->model->ccd_type == CCD_HP2300) - { - /* settings for CCD used at half is max resolution */ - GenesysRegister* r; - if (half_ccd) - { - r = sanei_genesys_get_address (regs, 0x70); - r->value = 0x16; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 0x00; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 0x01; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 0x03; - /* manual clock programming */ - r = sanei_genesys_get_address (regs, 0x1d); - r->value |= 0x80; - } - else - { - r = sanei_genesys_get_address (regs, 0x70); - r->value = 1; - r = sanei_genesys_get_address (regs, 0x71); - r->value = 3; - r = sanei_genesys_get_address (regs, 0x72); - r->value = 4; - r = sanei_genesys_get_address (regs, 0x73); - r->value = 6; - } - r = sanei_genesys_get_address (regs, 0x58); - r->value = 0x80 | (r->value & 0x03); /* VSMP=16 */ - return; - } -} - -/** Test if the ASIC works - */ -/*TODO: make this functional*/ -static SANE_Status -sanei_gl841_asic_test (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - size_t size, verify_size; - unsigned int i; - - DBG(DBG_proc, "%s\n", __func__); - - return SANE_STATUS_INVAL; - - /* set and read exposure time, compare if it's the same */ - status = sanei_genesys_write_register (dev, 0x38, 0xde); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_write_register (dev, 0x39, 0xad); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_read_register (dev, 0x38, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (val != 0xde) /* value of register 0x38 */ - { - DBG(DBG_error, "%s: register contains invalid value\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - status = sanei_genesys_read_register (dev, 0x39, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read register: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (val != 0xad) /* value of register 0x39 */ - { - DBG(DBG_error, "%s: register contains invalid value\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - /* ram test: */ - size = 0x40000; - verify_size = size + 0x80; - /* todo: looks like the read size must be a multiple of 128? - otherwise the read doesn't succeed the second time after the scanner has - been plugged in. Very strange. */ - - std::vector data(size); - std::vector verify_data(verify_size); - - for (i = 0; i < (size - 1); i += 2) - { - data[i] = i / 512; - data[i + 1] = (i / 2) % 256; - } - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - -/* status = sanei_genesys_bulk_write_data(dev, 0x3c, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write data: %s\n", __func__, sane_strstatus(status)); - free (data); - free (verify_data); - return status; - }*/ - - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_bulk_read_data(dev, 0x45, verify_data.data(), verify_size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* todo: why i + 2 ? */ - for (i = 0; i < size; i++) - { - if (verify_data[i] != data[i]) - { - DBG(DBG_error, "%s: data verification error\n", __func__); - DBG(DBG_info, "0x%.8x: got %.2x %.2x %.2x %.2x, expected %.2x %.2x %.2x %.2x\n", - i, - verify_data[i], - verify_data[i+1], - verify_data[i+2], - verify_data[i+3], - data[i], - data[i+1], - data[i+2], - data[i+3]); - return SANE_STATUS_IO_ERROR; - } - } - - DBG(DBG_info, "%s: completed\n", __func__); - - return SANE_STATUS_GOOD; -} - -/* - * Set all registers LiDE 80 to default values - * (function called only once at the beginning) - * we are doing a special case to ease development - */ -static void -gl841_init_lide80 (Genesys_Device * dev) -{ - uint8_t val; - - INITREG (0x01, 0x82); /* 0x02 = SHDAREA and no CISSET ! */ - INITREG (0x02, 0x10); - INITREG (0x03, 0x50); - INITREG (0x04, 0x02); - INITREG (0x05, 0x4c); /* 1200 DPI */ - INITREG (0x06, 0x38); /* 0x38 scanmod=1, pwrbit, GAIN4 */ - INITREG (0x07, 0x00); - INITREG (0x08, 0x00); - INITREG (0x09, 0x11); - INITREG (0x0a, 0x00); - - INITREG (0x10, 0x40); - INITREG (0x11, 0x00); - INITREG (0x12, 0x40); - INITREG (0x13, 0x00); - INITREG (0x14, 0x40); - INITREG (0x15, 0x00); - INITREG (0x16, 0x00); - INITREG (0x17, 0x01); - INITREG (0x18, 0x00); - INITREG (0x19, 0x06); - INITREG (0x1a, 0x00); - INITREG (0x1b, 0x00); - INITREG (0x1c, 0x00); - INITREG (0x1d, 0x04); - INITREG (0x1e, 0x10); - INITREG (0x1f, 0x04); - INITREG (0x20, 0x02); - INITREG (0x21, 0x10); - INITREG (0x22, 0x20); - INITREG (0x23, 0x20); - INITREG (0x24, 0x10); - INITREG (0x25, 0x00); - INITREG (0x26, 0x00); - INITREG (0x27, 0x00); - - INITREG (0x29, 0xff); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - INITREG (0x2c, sensor.optical_res>>8); - INITREG (0x2d, sensor.optical_res & 0xff); - INITREG (0x2e, 0x80); - INITREG (0x2f, 0x80); - INITREG (0x30, 0x00); - INITREG (0x31, 0x10); - INITREG (0x32, 0x15); - INITREG (0x33, 0x0e); - INITREG (0x34, 0x40); - INITREG (0x35, 0x00); - INITREG (0x36, 0x2a); - INITREG (0x37, 0x30); - INITREG (0x38, 0x2a); - INITREG (0x39, 0xf8); - - INITREG (0x3d, 0x00); - INITREG (0x3e, 0x00); - INITREG (0x3f, 0x00); - - INITREG (0x52, 0x03); - INITREG (0x53, 0x07); - INITREG (0x54, 0x00); - INITREG (0x55, 0x00); - INITREG (0x56, 0x00); - INITREG (0x57, 0x00); - INITREG (0x58, 0x29); - INITREG (0x59, 0x69); - INITREG (0x5a, 0x55); - - INITREG (0x5d, 0x20); - INITREG (0x5e, 0x41); - INITREG (0x5f, 0x40); - INITREG (0x60, 0x00); - INITREG (0x61, 0x00); - INITREG (0x62, 0x00); - INITREG (0x63, 0x00); - INITREG (0x64, 0x00); - INITREG (0x65, 0x00); - INITREG (0x66, 0x00); - INITREG (0x67, 0x40); - INITREG (0x68, 0x40); - INITREG (0x69, 0x20); - INITREG (0x6a, 0x20); - INITREG (0x6c, dev->gpo.value[0]); - INITREG (0x6d, dev->gpo.value[1]); - INITREG (0x6e, dev->gpo.enable[0]); - INITREG (0x6f, dev->gpo.enable[1]); - INITREG (0x70, 0x00); - INITREG (0x71, 0x05); - INITREG (0x72, 0x07); - INITREG (0x73, 0x09); - INITREG (0x74, 0x00); - INITREG (0x75, 0x01); - INITREG (0x76, 0xff); - INITREG (0x77, 0x00); - INITREG (0x78, 0x0f); - INITREG (0x79, 0xf0); - INITREG (0x7a, 0xf0); - INITREG (0x7b, 0x00); - INITREG (0x7c, 0x1e); - INITREG (0x7d, 0x11); - INITREG (0x7e, 0x00); - INITREG (0x7f, 0x50); - INITREG (0x80, 0x00); - INITREG (0x81, 0x00); - INITREG (0x82, 0x0f); - INITREG (0x83, 0x00); - INITREG (0x84, 0x0e); - INITREG (0x85, 0x00); - INITREG (0x86, 0x0d); - INITREG (0x87, 0x02); - INITREG (0x88, 0x00); - INITREG (0x89, 0x00); - - /* specific scanner settings, clock and gpio first */ - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x0c); - sanei_genesys_write_register (dev, 0x06, 0x10); - sanei_genesys_write_register (dev, REG6E, 0x6d); - sanei_genesys_write_register (dev, REG6F, 0x80); - sanei_genesys_write_register (dev, REG6B, 0x0e); - sanei_genesys_read_register (dev, REG6C, &val); - sanei_genesys_write_register (dev, REG6C, 0x00); - sanei_genesys_read_register (dev, REG6D, &val); - sanei_genesys_write_register (dev, REG6D, 0x8f); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x0e); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x0e); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x0a); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x02); - sanei_genesys_read_register (dev, REG6B, &val); - sanei_genesys_write_register (dev, REG6B, 0x06); - - sanei_genesys_write_0x8c (dev, 0x10, 0x94); - sanei_genesys_write_register (dev, 0x09, 0x10); - - /* set up GPIO : no address, so no bulk write, doesn't written directly either ? */ - /* - dev->reg.find_reg(0x6c).value = dev->gpo.value[0]; - dev->reg.find_reg(0x6d).value = dev->gpo.value[1]; - dev->reg.find_reg(0x6e).value = dev->gpo.enable[0]; - dev->reg.find_reg(0x6f).value = dev->gpo.enable[1]; */ - - // FIXME: the following code originally changed 0x6b, but due to bug the 0x6c register was - // effectively changed. The current behavior matches the old code, but should probably be fixed. - dev->reg.find_reg(0x6c).value |= REG6B_GPO18; - dev->reg.find_reg(0x6c).value &= ~REG6B_GPO17; - - sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 0); -} - -/* - * Set all registers to default values - * (function called only once at the beginning) - */ -static void -gl841_init_registers (Genesys_Device * dev) -{ - int addr; - - DBG(DBG_proc, "%s\n", __func__); - - dev->reg.clear(); - if (dev->model->model_id == MODEL_CANON_LIDE_80) - { - gl841_init_lide80(dev); - return ; - } - - for (addr = 1; addr <= 0x0a; addr++) { - dev->reg.init_reg(addr, 0); - } - for (addr = 0x10; addr <= 0x27; addr++) { - dev->reg.init_reg(addr, 0); - } - dev->reg.init_reg(0x29, 0); - for (addr = 0x2c; addr <= 0x39; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x3d; addr <= 0x3f; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x52; addr <= 0x5a; addr++) - dev->reg.init_reg(addr, 0); - for (addr = 0x5d; addr <= 0x87; addr++) - dev->reg.init_reg(addr, 0); - - - dev->reg.find_reg(0x01).value = 0x20; /* (enable shading), CCD, color, 1M */ - if (dev->model->is_cis == SANE_TRUE) { - dev->reg.find_reg(0x01).value |= REG01_CISSET; - } else { - dev->reg.find_reg(0x01).value &= ~REG01_CISSET; - } - - dev->reg.find_reg(0x02).value = 0x30 /*0x38 */ ; /* auto home, one-table-move, full step */ - dev->reg.find_reg(0x02).value |= REG02_AGOHOME; - sanei_genesys_set_motor_power(dev->reg, true); - dev->reg.find_reg(0x02).value |= REG02_FASTFED; - - dev->reg.find_reg(0x03).value = 0x1f /*0x17 */ ; /* lamp on */ - dev->reg.find_reg(0x03).value |= REG03_AVEENB; - - if (dev->model->ccd_type == CCD_PLUSTEK_3600) /* AD front end */ - { - dev->reg.find_reg(0x04).value = (2 << REG04S_AFEMOD) | 0x02; - } - else /* Wolfson front end */ - { - dev->reg.find_reg(0x04).value |= 1 << REG04S_AFEMOD; - } - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - dev->reg.find_reg(0x05).value = 0x00; /* disable gamma, 24 clocks/pixel */ - if (sensor.sensor_pixels < 0x1500) - dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; - else if (sensor.sensor_pixels < 0x2a80) - dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; - else if (sensor.sensor_pixels < 0x5400) - dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; - else - { - dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; - DBG(DBG_warn, "%s: Cannot handle sensor pixel count %d\n", __func__, - sensor.sensor_pixels); - } - - - dev->reg.find_reg(0x06).value |= REG06_PWRBIT; - dev->reg.find_reg(0x06).value |= REG06_GAIN4; - - /* XP300 CCD needs different clock and clock/pixels values */ - if (dev->model->ccd_type != CCD_XP300 && dev->model->ccd_type != CCD_DP685 - && dev->model->ccd_type != CCD_PLUSTEK_3600) - { - dev->reg.find_reg(0x06).value |= 0 << REG06S_SCANMOD; - dev->reg.find_reg(0x09).value |= 1 << REG09S_CLKSET; - } - else - { - dev->reg.find_reg(0x06).value |= 0x05 << REG06S_SCANMOD; /* 15 clocks/pixel */ - dev->reg.find_reg(0x09).value = 0; /* 24 MHz CLKSET */ - } - - dev->reg.find_reg(0x1e).value = 0xf0; /* watch-dog time */ - - dev->reg.find_reg(0x17).value |= 1 << REG17S_TGW; - - dev->reg.find_reg(0x19).value = 0x50; - - dev->reg.find_reg(0x1d).value |= 1 << REG1DS_TGSHLD; - - dev->reg.find_reg(0x1e).value |= 1 << REG1ES_WDTIME; - -/*SCANFED*/ - dev->reg.find_reg(0x1f).value = 0x01; - -/*BUFSEL*/ - dev->reg.find_reg(0x20).value = 0x20; - -/*LAMPPWM*/ - dev->reg.find_reg(0x29).value = 0xff; - -/*BWHI*/ - dev->reg.find_reg(0x2e).value = 0x80; - -/*BWLOW*/ - dev->reg.find_reg(0x2f).value = 0x80; - -/*LPERIOD*/ - dev->reg.find_reg(0x38).value = 0x4f; - dev->reg.find_reg(0x39).value = 0xc1; - -/*VSMPW*/ - dev->reg.find_reg(0x58).value |= 3 << REG58S_VSMPW; - -/*BSMPW*/ - dev->reg.find_reg(0x59).value |= 3 << REG59S_BSMPW; - -/*RLCSEL*/ - dev->reg.find_reg(0x5a).value |= REG5A_RLCSEL; - -/*STOPTIM*/ - dev->reg.find_reg(0x5e).value |= 0x2 << REG5ES_STOPTIM; - - sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 0, 0); - - /* set up GPIO */ - dev->reg.find_reg(0x6c).value = dev->gpo.value[0]; - dev->reg.find_reg(0x6d).value = dev->gpo.value[1]; - dev->reg.find_reg(0x6e).value = dev->gpo.enable[0]; - dev->reg.find_reg(0x6f).value = dev->gpo.enable[1]; - - /* TODO there is a switch calling to be written here */ - if (dev->model->gpo_type == GPO_CANONLIDE35) - { - dev->reg.find_reg(0x6b).value |= REG6B_GPO18; - dev->reg.find_reg(0x6b).value &= ~REG6B_GPO17; - } - - if (dev->model->gpo_type == GPO_XP300) - { - dev->reg.find_reg(0x6b).value |= REG6B_GPO17; - } - - if (dev->model->gpo_type == GPO_DP685) - { - /* REG6B_GPO18 lights on green led */ - dev->reg.find_reg(0x6b).value |= REG6B_GPO17|REG6B_GPO18; - } - - DBG(DBG_proc, "%s complete\n", __func__); -} - -/* Send slope table for motor movement - slope_table in machine byte order - */ -static SANE_Status -gl841_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - int dpihw; - int start_address; - SANE_Status status = SANE_STATUS_GOOD; - char msg[4000]; -/*#ifdef WORDS_BIGENDIAN*/ - int i; -/*#endif*/ - - DBG(DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, table_nr, steps); - - dpihw = dev->reg.find_reg(0x05).value >> 6; - - if (dpihw == 0) /* 600 dpi */ - start_address = 0x08000; - else if (dpihw == 1) /* 1200 dpi */ - start_address = 0x10000; - else if (dpihw == 2) /* 2400 dpi */ - start_address = 0x20000; - else /* reserved */ - return SANE_STATUS_INVAL; - - std::vector table(steps * 2); - for(i = 0; i < steps; i++) { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), ",%d", slope_table[i]); - } - DBG(DBG_io, "%s: %s\n", __func__, msg); - } - - status = - sanei_genesys_set_buffer_address (dev, start_address + table_nr * 0x200); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_bulk_write_data(dev, 0x3c, table.data(), steps * 2); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send slope table: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: completed\n", __func__); - return status; -} - -static SANE_Status -gl841_set_lide80_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - - dev->frontend = dev->frontend_initial; - - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg 0x03 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x06, dev->frontend.regs.get_value(0x02)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg 0x06 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - if (set == AFE_SET) - { - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x06, dev->frontend.regs.get_value(0x20)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing offset failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x28)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing gain failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - return status; - DBGCOMPLETED; -} - -/* Set values of Analog Device type frontend */ -static SANE_Status -gl841_set_ad_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - - /* special case for LiDE 80 analog frontend */ - if(dev->model->dac_type==DAC_CANONLIDE80) - { - return gl841_set_lide80_fe(dev, set); - } - - DBG(DBG_proc, "%s(): start\n", __func__); - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - - dev->frontend = dev->frontend_initial; - - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg 0x01 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - for (i = 0; i < 6; i++) - { - status = - sanei_genesys_fe_write_data (dev, 0x02 + i, 0x00); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, 0x02 + i, - sane_strstatus(status)); - return status; - } - } - } - if (set == AFE_SET) - { - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg 0x00 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg 0x01 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* Write fe 0x02 (red gain)*/ - status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.get_gain(0)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing fe 0x02 (gain r) fail: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* Write fe 0x03 (green gain)*/ - status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.get_gain(1)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing fe 0x03 (gain g) fail: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* Write fe 0x04 (blue gain)*/ - status = sanei_genesys_fe_write_data(dev, 0x04, dev->frontend.get_gain(2)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing fe 0x04 (gain b) fail: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* Write fe 0x05 (red offset)*/ - status = - sanei_genesys_fe_write_data(dev, 0x05, dev->frontend.get_offset(0)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: write fe 0x05 (offset r) fail: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* Write fe 0x06 (green offset)*/ - status = - sanei_genesys_fe_write_data(dev, 0x06, dev->frontend.get_offset(1)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: write fe 0x06 (offset g) fail: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* Write fe 0x07 (blue offset)*/ - status = - sanei_genesys_fe_write_data(dev, 0x07, dev->frontend.get_offset(2)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: write fe 0x07 (offset b) fail: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - DBG(DBG_proc, "%s(): end\n", __func__); - - return status; -} - -/* Set values of analog frontend */ -static SANE_Status -gl841_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) -{ - (void) sensor; - SANE_Status status = SANE_STATUS_GOOD; - int i; - - DBG(DBG_proc, "%s (%s)\n", __func__, - set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?"); - - /* Analog Device type frontend */ - if ((dev->reg.find_reg(0x04).value & REG04_FESET) == 0x02) - { - return gl841_set_ad_fe (dev, set); - } - - if ((dev->reg.find_reg(0x04).value & REG04_FESET) != 0x00) - { - DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, - dev->reg.find_reg(0x04).value & REG04_FESET); - return SANE_STATUS_UNSUPPORTED; - } - - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - dev->frontend = dev->frontend_initial; - - /* reset only done on init */ - status = sanei_genesys_fe_write_data (dev, 0x04, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: reset fe failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); - } - - - if (set == AFE_POWER_SAVE) - { - status = sanei_genesys_fe_write_data (dev, 0x01, 0x02); - if (status != SANE_STATUS_GOOD) { - DBG(DBG_error, "%s: writing data failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - return status; - } - - /* todo : base this test on cfg reg3 or a CCD family flag to be created */ - /*if (dev->model->ccd_type!=CCD_HP2300 && dev->model->ccd_type!=CCD_HP2400) */ - { - - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg0 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x02, dev->frontend.regs.get_value(0x02)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg2 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg1 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_fe_write_data(dev, 0x03, dev->frontend.regs.get_value(0x03)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg3 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x06, dev->frontend.reg2[0]); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg6 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x08, dev->frontend.reg2[1]); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg8 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_fe_write_data (dev, 0x09, dev->frontend.reg2[2]); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg9 failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - for (i = 0; i < 3; i++) - { - status = - sanei_genesys_fe_write_data(dev, 0x24 + i, dev->frontend.regs.get_value(0x24 + i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing gain[%d] failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - - status = - sanei_genesys_fe_write_data(dev, 0x20 + i, - dev->frontend.get_offset(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing offset[%d] failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - - - DBG(DBG_proc, "%s: completed\n", __func__); - - return SANE_STATUS_GOOD; -} - -#define MOTOR_ACTION_FEED 1 -#define MOTOR_ACTION_GO_HOME 2 -#define MOTOR_ACTION_HOME_FREE 3 - -/** @brief turn off motor - * - */ -static SANE_Status -gl841_init_motor_regs_off(Genesys_Register_Set * reg, - unsigned int scan_lines) -{ - unsigned int feedl; - GenesysRegister* r; - - DBG(DBG_proc, "%s : scan_lines=%d\n", __func__, scan_lines); - - feedl = 2; - - r = sanei_genesys_get_address (reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address (reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address (reg, 0x25); - r->value = (scan_lines >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x26); - r->value = (scan_lines >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x27); - r->value = scan_lines & 0xff; - - r = sanei_genesys_get_address (reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - - r->value &= ~0x10; - - r->value &= ~0x06; - - r->value &= ~0x08; - - r->value &= ~0x20; - - r->value &= ~0x40; - - r = sanei_genesys_get_address (reg, 0x67); - r->value = 0x3f; - - r = sanei_genesys_get_address (reg, 0x68); - r->value = 0x3f; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = 0; - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x69); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x6a); - r->value = 0; - - r = sanei_genesys_get_address (reg, 0x5f); - r->value = 0; - - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief write motor table frequency - * Write motor frequency data table. - * @param dev device to set up motor - * @param ydpi motor target resolution - * @return SANE_STATUS_GOOD on success - */ -static SANE_Status gl841_write_freq(Genesys_Device *dev, unsigned int ydpi) -{ -SANE_Status status = SANE_STATUS_GOOD; -/**< fast table */ -uint8_t tdefault[] = {0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0x36,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xb6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0xf6,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76,0x18,0x76}; -uint8_t t1200[] = {0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc7,0x31,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc0,0x11,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0xc7,0xb1,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0x07,0xe0,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc7,0xf1,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc0,0x51,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0xc7,0x71,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20,0x07,0x20}; -uint8_t t300[] = {0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x08,0x32,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x00,0x13,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x08,0xb2,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x0c,0xa0,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x08,0xf2,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x00,0xd3,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x08,0x72,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60,0x0c,0x60}; -uint8_t t150[] = {0x0c,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0xcf,0x33,0x40,0x14,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x80,0x15,0x0c,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0xcf,0xb3,0x11,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x16,0xa0,0x0c,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0xcf,0xf3,0x40,0xd4,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x80,0xd5,0x0c,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0xcf,0x73,0x11,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60,0x16,0x60}; - -uint8_t *table; - - DBGSTART; - if(dev->model->motor_type == MOTOR_CANONLIDE80) - { - switch(ydpi) - { - case 3600: - case 1200: - table=t1200; - break; - case 900: - case 300: - table=t300; - break; - case 450: - case 150: - table=t150; - break; - default: - table=tdefault; - } - RIE(sanei_genesys_write_register(dev, 0x66, 0x00)); - RIE(sanei_genesys_write_register(dev, 0x5b, 0x0c)); - RIE(sanei_genesys_write_register(dev, 0x5c, 0x00)); - RIE(sanei_genesys_bulk_write_data(dev, 0x28, table, 128)); - RIE(sanei_genesys_write_register(dev, 0x5b, 0x00)); - RIE(sanei_genesys_write_register(dev, 0x5c, 0x00)); - } - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl841_init_motor_regs(Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int feed_steps,/*1/base_ydpi*/ -/*maybe float for half/quarter step resolution?*/ - unsigned int action, - unsigned int flags) -{ - SANE_Status status = SANE_STATUS_GOOD; - unsigned int fast_exposure; - int scan_power_mode; - int use_fast_fed = 0; - uint16_t fast_slope_table[256]; - unsigned int fast_slope_steps = 0; - unsigned int feedl; - GenesysRegister* r; -/*number of scan lines to add in a scan_lines line*/ - - DBG(DBG_proc, "%s : feed_steps=%d, action=%d, flags=%x\n", __func__, feed_steps, action, flags); - - memset(fast_slope_table,0xff,512); - - gl841_send_slope_table (dev, 0, fast_slope_table, 256); - gl841_send_slope_table (dev, 1, fast_slope_table, 256); - gl841_send_slope_table (dev, 2, fast_slope_table, 256); - gl841_send_slope_table (dev, 3, fast_slope_table, 256); - gl841_send_slope_table (dev, 4, fast_slope_table, 256); - - gl841_write_freq(dev, dev->motor.base_ydpi / 4); - - fast_slope_steps = 256; - if (action == MOTOR_ACTION_FEED || action == MOTOR_ACTION_GO_HOME) - { - /* FEED and GO_HOME can use fastest slopes available */ - fast_exposure = gl841_exposure_time(dev, sensor, - dev->motor.base_ydpi / 4, - 0, - 0, - 0, - &scan_power_mode); - DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); - } - - if (action == MOTOR_ACTION_HOME_FREE) { -/* HOME_FREE must be able to stop in one step, so do not try to get faster */ - fast_exposure = dev->motor.slopes[0][0].maximum_start_speed; - } - - sanei_genesys_create_slope_table3 ( - dev, - fast_slope_table, - 256, - fast_slope_steps, - 0, - fast_exposure, - dev->motor.base_ydpi / 4, - &fast_slope_steps, - &fast_exposure, 0); - - feedl = feed_steps - fast_slope_steps*2; - use_fast_fed = 1; - -/* all needed slopes available. we did even decide which mode to use. - what next? - - transfer slopes -SCAN: -flags \ use_fast_fed ! 0 1 -------------------------\-------------------- - 0 ! 0,1,2 0,1,2,3 -MOTOR_FLAG_AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 -OFF: none -FEED: 3 -GO_HOME: 3 -HOME_FREE: 3 - - setup registers - * slope specific registers (already done) - * DECSEL for HOME_FREE/GO_HOME/SCAN - * FEEDL - * MTRREV - * MTRPWR - * FASTFED - * STEPSEL - * MTRPWM - * FSTPSEL - * FASTPWM - * HOMENEG - * BWDSTEP - * FWDSTEP - * Z1 - * Z2 - */ - - r = sanei_genesys_get_address(reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address(reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address(reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address(reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address(reg, 0x25); - r->value = 0; - r = sanei_genesys_get_address(reg, 0x26); - r->value = 0; - r = sanei_genesys_get_address(reg, 0x27); - r->value = 0; - - r = sanei_genesys_get_address(reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - - r->value |= 0x10; - - if (action == MOTOR_ACTION_GO_HOME) - r->value |= 0x06; - else - r->value &= ~0x06; - - if (use_fast_fed) - r->value |= 0x08; - else - r->value &= ~0x08; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= 0x20; - else - r->value &= ~0x20; - - r->value &= ~0x40; - - status = gl841_send_slope_table (dev, 3, fast_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - - r = sanei_genesys_get_address(reg, 0x67); - r->value = 0x3f; - - r = sanei_genesys_get_address(reg, 0x68); - r->value = 0x3f; - - r = sanei_genesys_get_address(reg, REG_STEPNO); - r->value = 0; - - r = sanei_genesys_get_address(reg, REG_FASTNO); - r->value = 0; - - r = sanei_genesys_get_address(reg, 0x69); - r->value = 0; - - r = sanei_genesys_get_address(reg, 0x6a); - r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); - - r = sanei_genesys_get_address(reg, 0x5f); - r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); - - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_init_motor_regs_scan(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time,/*pixel*/ - float scan_yres,/*dpi, motor resolution*/ - int scan_step_type,/*0: full, 1: half, 2: quarter*/ - unsigned int scan_lines,/*lines, scan resolution*/ - unsigned int scan_dummy, -/*number of scan lines to add in a scan_lines line*/ - unsigned int feed_steps,/*1/base_ydpi*/ -/*maybe float for half/quarter step resolution?*/ - int scan_power_mode, - unsigned int flags) -{ - SANE_Status status = SANE_STATUS_GOOD; - unsigned int fast_exposure; - int use_fast_fed = 0; - int dummy_power_mode; - unsigned int fast_time; - unsigned int slow_time; - uint16_t slow_slope_table[256]; - uint16_t fast_slope_table[256]; - uint16_t back_slope_table[256]; - unsigned int slow_slope_time; - unsigned int fast_slope_time; - unsigned int slow_slope_steps = 0; - unsigned int fast_slope_steps = 0; - unsigned int back_slope_steps = 0; - unsigned int feedl; - GenesysRegister* r; - unsigned int min_restep = 0x20; - uint32_t z1, z2; - - DBG(DBG_proc, "%s : scan_exposure_time=%d, scan_yres=%g, scan_step_type=%d, scan_lines=%d," - " scan_dummy=%d, feed_steps=%d, scan_power_mode=%d, flags=%x\n", __func__, - scan_exposure_time, - scan_yres, - scan_step_type, - scan_lines, - scan_dummy, - feed_steps, - scan_power_mode, - flags); - - fast_exposure = gl841_exposure_time(dev, sensor, - dev->motor.base_ydpi / 4, - 0, - 0, - 0, - &dummy_power_mode); - - DBG(DBG_info, "%s : fast_exposure=%d pixels\n", __func__, fast_exposure); - - memset(slow_slope_table,0xff,512); - - gl841_send_slope_table (dev, 0, slow_slope_table, 256); - gl841_send_slope_table (dev, 1, slow_slope_table, 256); - gl841_send_slope_table (dev, 2, slow_slope_table, 256); - gl841_send_slope_table (dev, 3, slow_slope_table, 256); - gl841_send_slope_table (dev, 4, slow_slope_table, 256); - - /* motor frequency table */ - gl841_write_freq(dev, scan_yres); - -/* - we calculate both tables for SCAN. the fast slope step count depends on - how many steps we need for slow acceleration and how much steps we are - allowed to use. - */ - slow_slope_time = sanei_genesys_create_slope_table3 ( - dev, - slow_slope_table, 256, - 256, - scan_step_type, - scan_exposure_time, - scan_yres, - &slow_slope_steps, - NULL, - scan_power_mode); - - sanei_genesys_create_slope_table3 ( - dev, - back_slope_table, 256, - 256, - scan_step_type, - 0, - scan_yres, - &back_slope_steps, - NULL, - scan_power_mode); - - if (feed_steps < (slow_slope_steps >> scan_step_type)) { - /*TODO: what should we do here?? go back to exposure calculation?*/ - feed_steps = slow_slope_steps >> scan_step_type; - } - - if (feed_steps > fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type)) - fast_slope_steps = 256; - else -/* we need to shorten fast_slope_steps here. */ - fast_slope_steps = (feed_steps - - (slow_slope_steps >> scan_step_type))/2; - - DBG(DBG_info, "%s: Maximum allowed slope steps for fast slope: %d\n", __func__, - fast_slope_steps); - - fast_slope_time = sanei_genesys_create_slope_table3 ( - dev, - fast_slope_table, 256, - fast_slope_steps, - 0, - fast_exposure, - dev->motor.base_ydpi / 4, - &fast_slope_steps, - &fast_exposure, - scan_power_mode); - - /* fast fed special cases handling */ - if (dev->model->gpo_type == GPO_XP300 - || dev->model->gpo_type == GPO_DP685) - { - /* quirk: looks like at least this scanner is unable to use - 2-feed mode */ - use_fast_fed = 0; - } - else if (feed_steps < fast_slope_steps*2 + (slow_slope_steps >> scan_step_type)) { - use_fast_fed = 0; - DBG(DBG_info, "%s: feed too short, slow move forced.\n", __func__); - } else { -/* for deciding whether we should use fast mode we need to check how long we - need for (fast)accelerating, moving, decelerating, (TODO: stopping?) - (slow)accelerating again versus (slow)accelerating and moving. we need - fast and slow tables here. -*/ -/*NOTE: scan_exposure_time is per scan_yres*/ -/*NOTE: fast_exposure is per base_ydpi/4*/ -/*we use full steps as base unit here*/ - fast_time = - fast_exposure / 4 * - (feed_steps - fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type)) - + fast_slope_time*2 + slow_slope_time; - slow_time = - (scan_exposure_time * scan_yres) / dev->motor.base_ydpi * - (feed_steps - (slow_slope_steps >> scan_step_type)) - + slow_slope_time; - - DBG(DBG_info, "%s: Time for slow move: %d\n", __func__, slow_time); - DBG(DBG_info, "%s: Time for fast move: %d\n", __func__, fast_time); - - use_fast_fed = fast_time < slow_time; - } - - if (use_fast_fed) - feedl = feed_steps - fast_slope_steps*2 - - (slow_slope_steps >> scan_step_type); - else - if ((feed_steps << scan_step_type) < slow_slope_steps) - feedl = 0; - else - feedl = (feed_steps << scan_step_type) - slow_slope_steps; - DBG(DBG_info, "%s: Decided to use %s mode\n", __func__, use_fast_fed?"fast feed":"slow feed"); - -/* all needed slopes available. we did even decide which mode to use. - what next? - - transfer slopes -SCAN: -flags \ use_fast_fed ! 0 1 -------------------------\-------------------- - 0 ! 0,1,2 0,1,2,3 -MOTOR_FLAG_AUTO_GO_HOME ! 0,1,2,4 0,1,2,3,4 -OFF: none -FEED: 3 -GO_HOME: 3 -HOME_FREE: 3 - - setup registers - * slope specific registers (already done) - * DECSEL for HOME_FREE/GO_HOME/SCAN - * FEEDL - * MTRREV - * MTRPWR - * FASTFED - * STEPSEL - * MTRPWM - * FSTPSEL - * FASTPWM - * HOMENEG - * BWDSTEP - * FWDSTEP - * Z1 - * Z2 - */ - - r = sanei_genesys_get_address (reg, 0x3d); - r->value = (feedl >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x3e); - r->value = (feedl >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x3f); - r->value = feedl & 0xff; - r = sanei_genesys_get_address (reg, 0x5e); - r->value &= ~0xe0; - - r = sanei_genesys_get_address (reg, 0x25); - r->value = (scan_lines >> 16) & 0xf; - r = sanei_genesys_get_address (reg, 0x26); - r->value = (scan_lines >> 8) & 0xff; - r = sanei_genesys_get_address (reg, 0x27); - r->value = scan_lines & 0xff; - - r = sanei_genesys_get_address (reg, 0x02); - r->value &= ~0x01; /*LONGCURV OFF*/ - r->value &= ~0x80; /*NOT_HOME OFF*/ - r->value |= 0x10; - - r->value &= ~0x06; - - if (use_fast_fed) - r->value |= 0x08; - else - r->value &= ~0x08; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= 0x20; - else - r->value &= ~0x20; - - if (flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - r->value |= 0x40; - else - r->value &= ~0x40; - - status = gl841_send_slope_table (dev, 0, slow_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - - status = gl841_send_slope_table (dev, 1, back_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - - status = gl841_send_slope_table (dev, 2, slow_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - - if (use_fast_fed) { - status = gl841_send_slope_table (dev, 3, fast_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - } - - if (flags & MOTOR_FLAG_AUTO_GO_HOME){ - status = gl841_send_slope_table (dev, 4, fast_slope_table, 256); - - if (status != SANE_STATUS_GOOD) - return status; - } - - -/* now reg 0x21 and 0x24 are available, we can calculate reg 0x22 and 0x23, - reg 0x60-0x62 and reg 0x63-0x65 - rule: - 2*STEPNO+FWDSTEP=2*FASTNO+BWDSTEP -*/ -/* steps of table 0*/ - if (min_restep < slow_slope_steps*2+2) - min_restep = slow_slope_steps*2+2; -/* steps of table 1*/ - if (min_restep < back_slope_steps*2+2) - min_restep = back_slope_steps*2+2; -/* steps of table 0*/ - r = sanei_genesys_get_address (reg, REG_FWDSTEP); - r->value = min_restep - slow_slope_steps*2; -/* steps of table 1*/ - r = sanei_genesys_get_address (reg, REG_BWDSTEP); - r->value = min_restep - back_slope_steps*2; - -/* - for z1/z2: - in dokumentation mentioned variables a-d: - a = time needed for acceleration, table 1 - b = time needed for reg 0x1f... wouldn't that be reg0x1f*exposure_time? - c = time needed for acceleration, table 1 - d = time needed for reg 0x22... wouldn't that be reg0x22*exposure_time? - z1 = (c+d-1) % exposure_time - z2 = (a+b-1) % exposure_time -*/ -/* i don't see any effect of this. i can only guess that this will enhance - sub-pixel accuracy - z1 = (slope_0_time-1) % exposure_time; - z2 = (slope_0_time-1) % exposure_time; -*/ - z1 = z2 = 0; - - DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); - DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); - r = sanei_genesys_get_address (reg, 0x60); - r->value = ((z1 >> 16) & 0xff); - r = sanei_genesys_get_address (reg, 0x61); - r->value = ((z1 >> 8) & 0xff); - r = sanei_genesys_get_address (reg, 0x62); - r->value = (z1 & 0xff); - r = sanei_genesys_get_address (reg, 0x63); - r->value = ((z2 >> 16) & 0xff); - r = sanei_genesys_get_address (reg, 0x64); - r->value = ((z2 >> 8) & 0xff); - r = sanei_genesys_get_address (reg, 0x65); - r->value = (z2 & 0xff); - - r = sanei_genesys_get_address (reg, REG1E); - r->value &= REG1E_WDTIME; - r->value |= scan_dummy; - - r = sanei_genesys_get_address (reg, 0x67); - r->value = 0x3f | (scan_step_type << 6); - - r = sanei_genesys_get_address (reg, 0x68); - r->value = 0x3f; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = (slow_slope_steps >> 1) + (slow_slope_steps & 1); - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = (back_slope_steps >> 1) + (back_slope_steps & 1); - - r = sanei_genesys_get_address (reg, 0x69); - r->value = (slow_slope_steps >> 1) + (slow_slope_steps & 1); - - r = sanei_genesys_get_address (reg, 0x6a); - r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); - - r = sanei_genesys_get_address (reg, 0x5f); - r->value = (fast_slope_steps >> 1) + (fast_slope_steps & 1); - - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static int -gl841_get_dpihw(Genesys_Device * dev) -{ - GenesysRegister* r; - r = sanei_genesys_get_address(&dev->reg, 0x05); - if ((r->value & REG05_DPIHW) == REG05_DPIHW_600) - return 600; - if ((r->value & REG05_DPIHW) == REG05_DPIHW_1200) - return 1200; - if ((r->value & REG05_DPIHW) == REG05_DPIHW_2400) - return 2400; - return 0; -} - -static SANE_Status -gl841_init_optical_regs_off(Genesys_Register_Set * reg) -{ - GenesysRegister* r; - - DBGSTART; - - r = sanei_genesys_get_address(reg, 0x01); - r->value &= ~REG01_SCAN; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_init_optical_regs_scan(Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int exposure_time, - unsigned int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, - ColorFilter color_filter, - int flags - ) -{ - unsigned int words_per_line; - unsigned int end; - unsigned int dpiset; - GenesysRegister* r; - SANE_Status status = SANE_STATUS_GOOD; - uint16_t expavg, expr, expb, expg; - - DBG(DBG_proc, "%s : exposure_time=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", __func__, - exposure_time, - used_res, - start, - pixels, - channels, - depth, - half_ccd, - flags); - - end = start + pixels; - - status = gl841_set_fe(dev, sensor, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* adjust used_res for chosen dpihw */ - used_res = used_res * gl841_get_dpihw(dev) / sensor.optical_res; - -/* - with half_ccd the optical resolution of the ccd is halved. We don't apply this - to dpihw, so we need to double dpiset. - - For the scanner only the ratio of dpiset and dpihw is of relevance to scale - down properly. -*/ - if (half_ccd) - dpiset = used_res * 2; - else - dpiset = used_res; - - /* gpio part.*/ - if (dev->model->gpo_type == GPO_CANONLIDE35) - { - r = sanei_genesys_get_address (reg, REG6C); - if (half_ccd) - r->value &= ~0x80; - else - r->value |= 0x80; - } - if (dev->model->gpo_type == GPO_CANONLIDE80) - { - r = sanei_genesys_get_address (reg, REG6C); - if (half_ccd) - { - r->value &= ~0x40; - r->value |= 0x20; - } - else - { - r->value &= ~0x20; - r->value |= 0x40; - } - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, 0x01); - r->value |= REG01_SCAN; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - r->value &= ~REG01_DVDSET; - else - r->value |= REG01_DVDSET; - - /* average looks better than deletion, and we are already set up to - use one of the average enabled resolutions - */ - r = sanei_genesys_get_address (reg, 0x03); - r->value |= REG03_AVEENB; - sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); - - /* BW threshold */ - r = sanei_genesys_get_address (reg, 0x2e); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, 0x2f); - r->value = dev->settings.threshold; - - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, 0x04); - switch (depth) { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - /* AFEMOD should depend on FESET, and we should set these - * bits separately */ - r->value &= ~(REG04_FILTER | REG04_AFEMOD); - if (flags & OPTICAL_FLAG_ENABLE_LEDADD) - { - r->value |= 0x10; /* no filter */ - } - else if (channels == 1) - { - switch (color_filter) - { - case ColorFilter::RED: - r->value |= 0x14; - break; - case ColorFilter::GREEN: - r->value |= 0x18; - break; - case ColorFilter::BLUE: - r->value |= 0x1c; - break; - default: - r->value |= 0x10; - break; - } - } - else - { - if (dev->model->ccd_type == CCD_PLUSTEK_3600) - { - r->value |= 0x22; /* slow color pixel by pixel */ - } - else - { - r->value |= 0x10; /* color pixel by pixel */ - } - } - - /* CIS scanners can do true gray by setting LEDADD */ - r = sanei_genesys_get_address (reg, 0x87); - r->value &= ~REG87_LEDADD; - if (flags & OPTICAL_FLAG_ENABLE_LEDADD) - { - r->value |= REG87_LEDADD; - sanei_genesys_get_double (reg, REG_EXPR, &expr); - sanei_genesys_get_double (reg, REG_EXPG, &expg); - sanei_genesys_get_double (reg, REG_EXPB, &expb); - - /* use minimal exposure for best image quality */ - expavg = expg; - if (expr < expg) - expavg = expr; - if (expb < expavg) - expavg = expb; - - sanei_genesys_set_double(&dev->reg, REG_EXPR, expavg); - sanei_genesys_set_double(&dev->reg, REG_EXPG, expavg); - sanei_genesys_set_double(&dev->reg, REG_EXPB, expavg); - } - - /* enable gamma tables */ - r = sanei_genesys_get_address (reg, 0x05); - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - /* sensor parameters */ - sanei_gl841_setup_sensor(dev, sensor, &dev->reg, 1, half_ccd); - - r = sanei_genesys_get_address (reg, 0x29); - r->value = 255; /*<<<"magic" number, only suitable for cis*/ - - sanei_genesys_set_double(reg, REG_DPISET, dpiset); - sanei_genesys_set_double(reg, REG_STRPIXEL, start); - sanei_genesys_set_double(reg, REG_ENDPIXEL, end); - DBG(DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d\n", __func__, start, end); - - /* words(16bit) before gamma, conversion to 8 bit or lineart*/ - words_per_line = (pixels * dpiset) / gl841_get_dpihw(dev); - - words_per_line *= channels; - - if (depth == 1) - words_per_line = (words_per_line >> 3) + ((words_per_line & 7)?1:0); - else - words_per_line *= depth / 8; - - dev->wpl = words_per_line; - dev->bpl = words_per_line; - - r = sanei_genesys_get_address (reg, 0x35); - r->value = LOBYTE (HIWORD (words_per_line)); - r = sanei_genesys_get_address (reg, 0x36); - r->value = HIBYTE (LOWORD (words_per_line)); - r = sanei_genesys_get_address (reg, 0x37); - r->value = LOBYTE (LOWORD (words_per_line)); - - sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); - - r = sanei_genesys_get_address (reg, 0x34); - r->value = sensor.dummy_pixel; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static int -gl841_get_led_exposure(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int d,r,g,b,m; - if (!dev->model->is_cis) - return 0; - d = dev->reg.find_reg(0x19).value; - - r = sensor.exposure.red; - g = sensor.exposure.green; - b = sensor.exposure.blue; - - m = r; - if (m < g) - m = g; - if (m < b) - m = b; - - return m + d; -} - -/** @brief compute exposure time - * Compute exposure time for the device and the given scan resolution, - * also compute scan_power_mode - */ -static int -gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, - float slope_dpi, - int scan_step_type, - int start, - int used_pixels, - int *scan_power_mode) -{ -int exposure_time = 0; -int exposure_time2 = 0; -int led_exposure; - - *scan_power_mode=0; - led_exposure=gl841_get_led_exposure(dev, sensor); - exposure_time = sanei_genesys_exposure_time2( - dev, - slope_dpi, - scan_step_type, - start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ - led_exposure, - *scan_power_mode); - - while(*scan_power_mode + 1 < dev->motor.power_mode_count) { - exposure_time2 = sanei_genesys_exposure_time2( - dev, - slope_dpi, - scan_step_type, - start+used_pixels,/*+tgtime? currently done in sanei_genesys_exposure_time2 with tgtime = 32 pixel*/ - led_exposure, - *scan_power_mode + 1); - if (exposure_time < exposure_time2) - break; - exposure_time = exposure_time2; - (*scan_power_mode)++; - } - - return exposure_time; -} - -/**@brief compute scan_step_type - * Try to do at least 4 steps per line. if that is impossible we will have to - * live with that. - * @param dev device - * @param yres motor resolution - */ -static int -gl841_scan_step_type(Genesys_Device *dev, int yres) -{ -int scan_step_type=0; - - /* TODO : check if there is a bug around the use of max_step_type */ - /* should be <=1, need to chek all devices entry in genesys_devices */ - if (yres*4 < dev->motor.base_ydpi || dev->motor.max_step_type <= 0) - { - scan_step_type = 0; - } - else if (yres*4 < dev->motor.base_ydpi*2 || dev->motor.max_step_type <= 1) - { - scan_step_type = 1; - } - else - { - scan_step_type = 2; - } - - /* this motor behaves differently */ - if (dev->model->motor_type==MOTOR_CANONLIDE80) - { - /* driven by 'frequency' tables ? */ - scan_step_type = 0; - } - - return scan_step_type; -} - -/* set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -static -SANE_Status -gl841_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SetupParams& params) -{ - params.assert_valid(); - - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; - int exposure_time; - int scan_power_mode; - int i; - int stagger; - int avg; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - SANE_Status status = SANE_STATUS_GOOD; - unsigned int oflags; /**> optical flags */ - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - -/* -results: - -for scanner: -half_ccd -start -end -dpiset -exposure_time -dummy -z1 -z2 - -for ordered_read: - dev->words_per_line - dev->read_factor - dev->requested_buffer_size - dev->read_buffer_size - dev->read_pos - dev->read_bytes_in_buffer - dev->read_bytes_left - dev->max_shift - dev->stagger - -independent of our calculated values: - dev->total_bytes_read - dev->bytes_to_read - */ - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) { - half_ccd = SANE_TRUE; - } else { - half_ccd = SANE_FALSE; - } - -/* optical_res */ - - optical_res = sensor.optical_res; - if (half_ccd) - optical_res /= 2; - -/* stagger */ - - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG(DBG_info, "%s : stagger=%d lines\n", __func__, stagger); - -/* used_res */ - i = optical_res / params.xres; - -/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ - - if (i < 2 || (params.flags & SCAN_FLAG_USE_OPTICAL_RES)) /* optical_res >= xres > optical_res/2 */ - used_res = optical_res; - else if (i < 3) /* optical_res/2 >= xres > optical_res/3 */ - used_res = optical_res/2; - else if (i < 4) /* optical_res/3 >= xres > optical_res/4 */ - used_res = optical_res/3; - else if (i < 5) /* optical_res/4 >= xres > optical_res/5 */ - used_res = optical_res/4; - else if (i < 6) /* optical_res/5 >= xres > optical_res/6 */ - used_res = optical_res/5; - else if (i < 8) /* optical_res/6 >= xres > optical_res/8 */ - used_res = optical_res/6; - else if (i < 10) /* optical_res/8 >= xres > optical_res/10 */ - used_res = optical_res/8; - else if (i < 12) /* optical_res/10 >= xres > optical_res/12 */ - used_res = optical_res/10; - else if (i < 15) /* optical_res/12 >= xres > optical_res/15 */ - used_res = optical_res/12; - else - used_res = optical_res/15; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - /* add x coordinates */ - start = ((sensor.CCD_start_xoffset + params.startx) * used_res) / sensor.optical_res; - - /* needs to be aligned for used_res */ - start = (start * optical_res) / used_res; - - start += sensor.dummy_pixel + 1; - - if (stagger > 0) - start |= 1; - - /* in case of SHDAREA, we need to align start - * on pixel average factor, startx is different of - * 0 only when calling for function to setup for - * scan, where shading data needs to be align */ - if((dev->reg.find_reg(0x01).value & REG01_SHDAREA) != 0) - { - avg=optical_res/used_res; - start=(start/avg)*avg; - } - - /* compute correct pixels number */ - /* pixels */ - used_pixels = (params.pixels * optical_res) / params.xres; - - /* round up pixels number if needed */ - if (used_pixels * params.xres < params.pixels * optical_res) - used_pixels++; - -/* dummy */ - /* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1 - dummy line. Maybe the dummy line adds correctness since the motor runs - slower (higher dpi) - */ -/* for cis this creates better aligned color lines: -dummy \ scanned lines - 0: R G B R ... - 1: R G B - R ... - 2: R G B - - R ... - 3: R G B - - - R ... - 4: R G B - - - - R ... - 5: R G B - - - - - R ... - 6: R G B - - - - - - R ... - 7: R G B - - - - - - - R ... - 8: R G B - - - - - - - - R ... - 9: R G B - - - - - - - - - R ... - 10: R G B - - - - - - - - - - R ... - 11: R G B - - - - - - - - - - - R ... - 12: R G B - - - - - - - - - - - - R ... - 13: R G B - - - - - - - - - - - - - R ... - 14: R G B - - - - - - - - - - - - - - R ... - 15: R G B - - - - - - - - - - - - - - - R ... - -- pierre - */ - dummy = 0; - -/* slope_dpi */ -/* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = params.yres* params.channels; - else - slope_dpi = params.yres; - - slope_dpi = slope_dpi * (1 + dummy); - - scan_step_type = gl841_scan_step_type(dev, params.yres); - exposure_time = gl841_exposure_time(dev, sensor, - slope_dpi, - scan_step_type, - start, - used_pixels, - &scan_power_mode); - DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if(params.flags & SCAN_FLAG_DYNAMIC_LINEART) - { - params.depth=8; - } - - oflags=0; - if (params.flags & SCAN_FLAG_DISABLE_SHADING) - { - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - } - if ((params.flags & SCAN_FLAG_DISABLE_GAMMA) || (params.depth==16)) - { - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - } - if (params.flags & SCAN_FLAG_DISABLE_LAMP) - { - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - } - if (params.flags & SCAN_FLAG_ENABLE_LEDADD) - { - oflags |= OPTICAL_FLAG_ENABLE_LEDADD; - } - - status = gl841_init_optical_regs_scan(dev, sensor, - reg, - exposure_time, - used_res, - start, - used_pixels, - params.channels, - params.depth, - half_ccd, - params.color_filter, - oflags); - if (status != SANE_STATUS_GOOD) - { - return status; - } - -/*** motor parameters ***/ - - /* scanned area must be enlarged by max color shift needed */ - max_shift=sanei_genesys_compute_max_shift(dev, params.channels,params.yres,params.flags); - - /* lincnt */ - lincnt = params.lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = params.starty; - DBG(DBG_info, "%s: move=%d steps\n", __func__, move); - - /* subtract current head position */ - move -= dev->scanhead_position_in_steps; - DBG(DBG_info, "%s: move=%d steps\n", __func__, move); - - if (move < 0) - move = 0; - - /* round it */ -/* the move is not affected by dummy -- pierre */ -/* move = ((move + dummy) / (dummy + 1)) * (dummy + 1); - DBG(DBG_info, "%s: move=%d steps\n", __func__, move);*/ - - if (params.flags & SCAN_FLAG_SINGLE_LINE) - status = gl841_init_motor_regs_off(reg, dev->model->is_cis?lincnt* params.channels:lincnt); - else - status = gl841_init_motor_regs_scan(dev, sensor, - reg, - exposure_time, - slope_dpi, - scan_step_type, - dev->model->is_cis?lincnt* params.channels:lincnt, - dummy, - move, - scan_power_mode, - (params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE)? - MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE:0 - ); - - if (status != SANE_STATUS_GOOD) - return status; - - - /*** prepares data reordering ***/ - -/* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * params.channels * params.depth) / 8; - - requested_buffer_size = 8 * bytes_per_line; - /* we must use a round number of bytes_per_line */ - if (requested_buffer_size > sanei_genesys_get_bulk_max_size(dev)) - requested_buffer_size = - (sanei_genesys_get_bulk_max_size(dev) / bytes_per_line) * bytes_per_line; - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * params.channels * params.depth) / 8; - - dev->read_buffer.clear(); - dev->read_buffer.alloc(read_buffer_size); - - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(read_buffer_size); - - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(requested_buffer_size); - - dev->out_buffer.clear(); - dev->out_buffer.alloc((8 * dev->settings.pixels * params.channels * params.depth) / 8); - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res)/optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - -/* TODO: should this be done elsewhere? */ - /* scan bytes to send to the frontend */ - /* theory : - target_size = - (dev->settings.pixels * dev->settings.lines * channels * depth) / 8; - but it suffers from integer overflow so we do the following: - - 1 bit color images store color data byte-wise, eg byte 0 contains - 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains - 8 bits of blue. - This does not fix the overflow, though. - 644mp*16 = 10gp, leading to an overflow - -- pierre - */ - - dev->total_bytes_read = 0; - if (params.depth == 1) - dev->total_bytes_to_read = - ((dev->settings.pixels * dev->settings.lines) / 8 + - (((dev->settings.pixels * dev->settings.lines)%8)?1:0) - ) * params.channels; - else - dev->total_bytes_to_read = - dev->settings.pixels * dev->settings.lines * params.channels * (params.depth / 8); - - DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); -/* END TODO */ - - DBG(DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} - -static void gl841_calculate_current_setup(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int depth; - int start; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure_time; - int scan_power_mode; - int i; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int max_shift; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - -/* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - -/* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - -/* start */ - start = SANE_UNFIX (dev->model->x_offset); - - start += dev->settings.tl_x; - - start = (start * sensor.optical_res) / MM_PER_INCH; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; - params.starty = 0; // not used - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = 0; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) { - half_ccd = SANE_TRUE; - } else { - half_ccd = SANE_FALSE; - } - -/* optical_res */ - - optical_res = sensor.optical_res; - if (half_ccd) - optical_res /= 2; - -/* stagger */ - - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG(DBG_info, "%s: stagger=%d lines\n", __func__, stagger); - -/* used_res */ - i = optical_res / params.xres; - -/* gl841 supports 1/1 1/2 1/3 1/4 1/5 1/6 1/8 1/10 1/12 1/15 averaging */ - - if (i < 2) /* optical_res >= xres > optical_res/2 */ - used_res = optical_res; - else if (i < 3) /* optical_res/2 >= xres > optical_res/3 */ - used_res = optical_res/2; - else if (i < 4) /* optical_res/3 >= xres > optical_res/4 */ - used_res = optical_res/3; - else if (i < 5) /* optical_res/4 >= xres > optical_res/5 */ - used_res = optical_res/4; - else if (i < 6) /* optical_res/5 >= xres > optical_res/6 */ - used_res = optical_res/5; - else if (i < 8) /* optical_res/6 >= xres > optical_res/8 */ - used_res = optical_res/6; - else if (i < 10) /* optical_res/8 >= xres > optical_res/10 */ - used_res = optical_res/8; - else if (i < 12) /* optical_res/10 >= xres > optical_res/12 */ - used_res = optical_res/10; - else if (i < 15) /* optical_res/12 >= xres > optical_res/15 */ - used_res = optical_res/12; - else - used_res = optical_res/15; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - start = ((sensor.CCD_start_xoffset + params.startx) * used_res) / sensor.optical_res; - -/* needs to be aligned for used_res */ - start = (start * optical_res) / used_res; - - start += sensor.dummy_pixel + 1; - - if (stagger > 0) { - start |= 1; - } - - used_pixels = (params.pixels * optical_res) / params.xres; - - // round up pixels number if needed - if (used_pixels * params.xres < params.pixels * optical_res) { - used_pixels++; - } - - /* dummy lines: may not be usefull, for instance 250 dpi works with 0 or 1 - dummy line. Maybe the dummy line adds correctness since the motor runs - slower (higher dpi) - */ -/* for cis this creates better aligned color lines: -dummy \ scanned lines - 0: R G B R ... - 1: R G B - R ... - 2: R G B - - R ... - 3: R G B - - - R ... - 4: R G B - - - - R ... - 5: R G B - - - - - R ... - 6: R G B - - - - - - R ... - 7: R G B - - - - - - - R ... - 8: R G B - - - - - - - - R ... - 9: R G B - - - - - - - - - R ... - 10: R G B - - - - - - - - - - R ... - 11: R G B - - - - - - - - - - - R ... - 12: R G B - - - - - - - - - - - - R ... - 13: R G B - - - - - - - - - - - - - R ... - 14: R G B - - - - - - - - - - - - - - R ... - 15: R G B - - - - - - - - - - - - - - - R ... - -- pierre - */ - dummy = 0; - -/* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) { - slope_dpi = params.yres * params.channels; - } else { - slope_dpi = params.yres; - } - - slope_dpi = slope_dpi * (1 + dummy); - - scan_step_type = gl841_scan_step_type(dev, params.yres); - exposure_time = gl841_exposure_time(dev, sensor, - slope_dpi, - scan_step_type, - start, - used_pixels, - &scan_power_mode); - DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /* scanned area must be enlarged by max color shift needed */ - max_shift = sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); - - lincnt = params.lines + max_shift + stagger; - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res)/optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBGCOMPLETED; -} - -/*for fast power saving methods only, like disabling certain amplifiers*/ -static SANE_Status gl841_save_power(Genesys_Device * dev, SANE_Bool enable) -{ - uint8_t val; - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); - - if (enable) - { - if (dev->model->gpo_type == GPO_CANONLIDE35) - { -/* expect GPIO17 to be enabled, and GPIO9 to be disabled, - while GPIO8 is disabled*/ -/* final state: GPIO8 disabled, GPIO9 enabled, GPIO17 disabled, - GPIO18 disabled*/ - - sanei_genesys_read_register(dev, REG6D, &val); - sanei_genesys_write_register(dev, REG6D, val | 0x80); - - sanei_genesys_sleep_ms(1); - - /*enable GPIO9*/ - sanei_genesys_read_register(dev, REG6C, &val); - sanei_genesys_write_register(dev, REG6C, val | 0x01); - - /*disable GPO17*/ - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO17); - - /*disable GPO18*/ - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO18); - - sanei_genesys_sleep_ms(1); - - sanei_genesys_read_register(dev, REG6D, &val); - sanei_genesys_write_register(dev, REG6D, val & ~0x80); - - } - if (dev->model->gpo_type == GPO_DP685) - { - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val & ~REG6B_GPO17); - dev->reg.find_reg(0x6b).value &= ~REG6B_GPO17; - dev->calib_reg.find_reg(0x6b).value &= ~REG6B_GPO17; - } - - gl841_set_fe(dev, sensor, AFE_POWER_SAVE); - - } - else - { - if (dev->model->gpo_type == GPO_CANONLIDE35) - { -/* expect GPIO17 to be enabled, and GPIO9 to be disabled, - while GPIO8 is disabled*/ -/* final state: GPIO8 enabled, GPIO9 disabled, GPIO17 enabled, - GPIO18 enabled*/ - - sanei_genesys_read_register(dev, REG6D, &val); - sanei_genesys_write_register(dev, REG6D, val | 0x80); - - sanei_genesys_sleep_ms(10); - - /*disable GPIO9*/ - sanei_genesys_read_register(dev, REG6C, &val); - sanei_genesys_write_register(dev, REG6C, val & ~0x01); - - /*enable GPIO10*/ - sanei_genesys_read_register(dev, REG6C, &val); - sanei_genesys_write_register(dev, REG6C, val | 0x02); - - /*enable GPO17*/ - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO17); - dev->reg.find_reg(0x6b).value |= REG6B_GPO17; - dev->calib_reg.find_reg(0x6b).value |= REG6B_GPO17; - - /*enable GPO18*/ - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO18); - dev->reg.find_reg(0x6b).value |= REG6B_GPO18; - dev->calib_reg.find_reg(0x6b).value |= REG6B_GPO18; - - } - if (dev->model->gpo_type == GPO_DP665 - || dev->model->gpo_type == GPO_DP685) - { - sanei_genesys_read_register(dev, REG6B, &val); - sanei_genesys_write_register(dev, REG6B, val | REG6B_GPO17); - dev->reg.find_reg(0x6b).value |= REG6B_GPO17; - dev->calib_reg.find_reg(0x6b).value |= REG6B_GPO17; - } - - } - - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_set_powersaving (Genesys_Device * dev, - int delay /* in minutes */ ) -{ - SANE_Status status = SANE_STATUS_GOOD; - // FIXME: SEQUENTIAL not really needed in this case - Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); - int rate, exposure_time, tgtime, time; - - DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); - - local_reg.init_reg(0x01, dev->reg.get8(0x01)); /* disable fastmode */ - local_reg.init_reg(0x03, dev->reg.get8(0x03)); /* Lamp power control */ - local_reg.init_reg(0x05, dev->reg.get8(0x05)); /*& ~REG05_BASESEL*/; /* 24 clocks/pixel */ - local_reg.init_reg(0x18, 0x00); // Set CCD type - local_reg.init_reg(0x38, 0x00); - local_reg.init_reg(0x39, 0x00); - - // period times for LPeriod, expR,expG,expB, Z1MODE, Z2MODE - local_reg.init_reg(0x1c, dev->reg.get8(0x05) & ~REG1C_TGTIME); - - if (!delay) { - local_reg.find_reg(0x03).value = local_reg.find_reg(0x03).value & 0xf0; /* disable lampdog and set lamptime = 0 */ - } else if (delay < 20) { - local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x09; /* enable lampdog and set lamptime = 1 */ - } else { - local_reg.find_reg(0x03).value = (local_reg.find_reg(0x03).value & 0xf0) | 0x0f; /* enable lampdog and set lamptime = 7 */ - } - - time = delay * 1000 * 60; /* -> msec */ - exposure_time = - (uint32_t) (time * 32000.0 / - (24.0 * 64.0 * (local_reg.find_reg(0x03).value & REG03_LAMPTIM) * - 1024.0) + 0.5); - /* 32000 = system clock, 24 = clocks per pixel */ - rate = (exposure_time + 65536) / 65536; - if (rate > 4) - { - rate = 8; - tgtime = 3; - } - else if (rate > 2) - { - rate = 4; - tgtime = 2; - } - else if (rate > 1) - { - rate = 2; - tgtime = 1; - } - else - { - rate = 1; - tgtime = 0; - } - - local_reg.find_reg(0x1c).value |= tgtime; - exposure_time /= rate; - - if (exposure_time > 65535) - exposure_time = 65535; - - local_reg.set8(0x38, exposure_time >> 8); - local_reg.set8(0x39, exposure_time & 255); /* lowbyte */ - - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - - DBG(DBG_proc, "%s: completed\n", __func__); - return status; -} - -static SANE_Status -gl841_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -static SANE_Status -gl841_stop_action (Genesys_Device * dev) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val40, val; - unsigned int loop; - - DBG(DBG_proc, "%s\n", __func__); - - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - status = sanei_genesys_read_register(dev, 0x40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBG(DBG_info, "%s: already stopped\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - local_reg = dev->reg; - - gl841_init_optical_regs_off(&local_reg); - - gl841_init_motor_regs_off(&local_reg,0); - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* looks like writing the right registers to zero is enough to get the chip - out of scan mode into command mode, actually triggering(writing to - register 0x0f) seems to be unnecessary */ - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_read_register(dev, 0x40, &val40); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - sanei_genesys_sleep_ms(100); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - -static SANE_Status -gl841_get_paper_sensor(Genesys_Device * dev, SANE_Bool * paper_loaded) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - status = sanei_genesys_read_register(dev, REG6D, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read gpio: %s\n", __func__, sane_strstatus(status)); - return status; - } - *paper_loaded = (val & 0x1) == 0; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_eject_document (Genesys_Device * dev) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - SANE_Bool paper_loaded; - unsigned int init_steps; - float feed_mm; - int loop; - - DBG(DBG_proc, "%s\n", __func__); - - if (dev->model->is_sheetfed == SANE_FALSE) - { - DBG(DBG_proc, "%s: there is no \"eject sheet\"-concept for non sheet fed\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; - } - - - local_reg.clear(); - val = 0; - - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read status register: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - - local_reg = dev->reg; - - gl841_init_optical_regs_off(&local_reg); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - gl841_init_motor_regs(dev, sensor, &local_reg, - 65536,MOTOR_ACTION_FEED,0); - - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - try { - status = gl841_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl841_stop_action(dev); - } catch (...) {} - try { - // restore original registers - sanei_genesys_bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl841_stop_action (dev); - /* send original registers */ - sanei_genesys_bulk_write_register(dev, dev->reg); - return status; - } - - RIE(gl841_get_paper_sensor(dev, &paper_loaded)); - if (paper_loaded) - { - DBG(DBG_info, "%s: paper still loaded\n", __func__); - /* force document TRUE, because it is definitely present */ - dev->document = SANE_TRUE; - dev->scanhead_position_in_steps = 0; - - loop = 300; - while (loop > 0) /* do not wait longer then 30 seconds */ - { - - RIE(gl841_get_paper_sensor(dev, &paper_loaded)); - - if (!paper_loaded) - { - DBG(DBG_info, "%s: reached home position\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - break; - } - sanei_genesys_sleep_ms(100); - --loop; - } - - if (loop == 0) - { - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl841_stop_action (dev); - DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); - return SANE_STATUS_IO_ERROR; - } - } - - feed_mm = SANE_UNFIX(dev->model->eject_feed); - if (dev->document) - { - feed_mm += SANE_UNFIX(dev->model->post_scan); - } - - status = sanei_genesys_read_feed_steps(dev, &init_steps); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read feed steps: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* now feed for extra steps */ - loop = 0; - while (loop < 300) /* do not wait longer then 30 seconds */ - { - unsigned int steps; - - status = sanei_genesys_read_feed_steps(dev, &steps); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read feed steps: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_info, "%s: init_steps: %d, steps: %d\n", __func__, init_steps, steps); - - if (steps > init_steps + (feed_mm * dev->motor.base_ydpi) / MM_PER_INCH) - { - break; - } - - sanei_genesys_sleep_ms(100); - ++loop; - } - - status = gl841_stop_action(dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status)); - return status; - } - - dev->document = SANE_FALSE; - - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl841_load_document (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool paper_loaded; - int loop = 300; - DBG(DBG_proc, "%s\n", __func__); - while (loop > 0) /* do not wait longer then 30 seconds */ - { - - RIE(gl841_get_paper_sensor(dev, &paper_loaded)); - - if (paper_loaded) - { - DBG(DBG_info, "%s: document inserted\n", __func__); - - /* when loading OK, document is here */ - dev->document = SANE_TRUE; - - // give user some time to place document correctly - sanei_genesys_sleep_ms(1000); - break; - } - sanei_genesys_sleep_ms(100); - --loop; - } - - if (loop == 0) - { - /* when we come here then the user needed to much time for this */ - DBG(DBG_error, "%s: timeout while waiting for document\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - -/** - * detects end of document and adjust current scan - * to take it into account - * used by sheetfed scanners - */ -static SANE_Status -gl841_detect_document_end (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool paper_loaded; - unsigned int scancnt = 0, lincnt, postcnt; - uint8_t val; - size_t total_bytes_to_read; - - DBG(DBG_proc, "%s: begin\n", __func__); - - RIE (gl841_get_paper_sensor (dev, &paper_loaded)); - - /* sheetfed scanner uses home sensor as paper present */ - if ((dev->document == SANE_TRUE) && !paper_loaded) - { - DBG(DBG_info, "%s: no more document\n", __func__); - dev->document = SANE_FALSE; - - /* we can't rely on total_bytes_to_read since the frontend - * might have been slow to read data, so we re-evaluate the - * amount of data to scan form the hardware settings - */ - try { - status = sanei_genesys_read_scancnt(dev, &scancnt); - } catch (...) { - dev->total_bytes_to_read = dev->total_bytes_read; - dev->read_bytes_left = 0; - throw; - } - - if(status!=SANE_STATUS_GOOD) - { - dev->total_bytes_to_read = dev->total_bytes_read; - dev->read_bytes_left = 0; - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; - } - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS && dev->model->is_cis) - { - scancnt/=3; - } - DBG(DBG_io, "%s: scancnt=%u lines\n", __func__, scancnt); - - RIE(sanei_genesys_read_register(dev, 0x25, &val)); - lincnt=65536*val; - RIE(sanei_genesys_read_register(dev, 0x26, &val)); - lincnt+=256*val; - RIE(sanei_genesys_read_register(dev, 0x27, &val)); - lincnt+=val; - DBG(DBG_io, "%s: lincnt=%u lines\n", __func__, lincnt); - postcnt=(SANE_UNFIX(dev->model->post_scan)/MM_PER_INCH)*dev->settings.yres; - DBG(DBG_io, "%s: postcnt=%u lines\n", __func__, postcnt); - - /* the current scancnt is also the final one, so we use it to - * compute total bytes to read. We also add the line count to eject document */ - total_bytes_to_read=(scancnt+postcnt)*dev->wpl; - - DBG(DBG_io, "%s: old total_bytes_to_read=%u\n", __func__, - (unsigned int)dev->total_bytes_to_read); - DBG(DBG_io, "%s: new total_bytes_to_read=%u\n", __func__, (unsigned int)total_bytes_to_read); - - /* assign new end value */ - if(dev->total_bytes_to_read>total_bytes_to_read) - { - DBG(DBG_io, "%s: scan shorten\n", __func__); - dev->total_bytes_to_read=total_bytes_to_read; - } - } - - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - -/* Send the low-level scan command */ -/* todo : is this that useful ? */ -static SANE_Status -gl841_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - (void) sensor; - SANE_Status status = SANE_STATUS_GOOD; - // FIXME: SEQUENTIAL not really needed in this case - Genesys_Register_Set local_reg(Genesys_Register_Set::SEQUENTIAL); - uint8_t val; - - DBG(DBG_proc, "%s\n", __func__); - - if (dev->model->gpo_type == GPO_CANONLIDE80) - { - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - val = REG6B_GPO18; - RIE (sanei_genesys_write_register (dev, REG6B, val)); - } - - if (dev->model->ccd_type != CCD_PLUSTEK_3600) { - local_reg.init_reg(0x03, sanei_genesys_read_reg_from_set(reg, 0x03) | REG03_LAMPPWR); - } else { - // TODO PLUSTEK_3600: why ?? - local_reg.init_reg(0x03, sanei_genesys_read_reg_from_set(reg, 0x03)); - } - - local_reg.init_reg(0x01, sanei_genesys_read_reg_from_set(reg, 0x01) | REG01_SCAN); /* set scan bit */ - local_reg.init_reg(0x0d, 0x01); - - if (start_motor) { - local_reg.init_reg(0x0f, 0x01); - } else { - // do not start motor yet - local_reg.init_reg(0x0f, 0x00); - } - - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: completed\n", __func__); - - return status; -} - - -/* Send the stop scan command */ -static SANE_Status -gl841_end_scan (Genesys_Device * dev, Genesys_Register_Set __sane_unused__ * reg, - SANE_Bool check_stop) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - DBG(DBG_proc, "%s: completed\n", __func__); - - return status; -} - -/* Moves the slider to steps */ -static SANE_Status -gl841_feed (Genesys_Device * dev, int steps) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - int loop; - - DBG(DBG_proc, "%s (steps = %d)\n", __func__, steps); - - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop action: %s\n", __func__, sane_strstatus(status)); - return status; - } - - // FIXME: we should pick sensor according to the resolution scanner is currently operating on - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - local_reg = dev->reg; - - gl841_init_optical_regs_off(&local_reg); - - gl841_init_motor_regs(dev, sensor, &local_reg, steps,MOTOR_ACTION_FEED,0); - - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - try { - status = gl841_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl841_stop_action (dev); - } catch (...) {} - try { - // send original registers - sanei_genesys_bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl841_stop_action (dev); - /* send original registers */ - sanei_genesys_bulk_write_register(dev, dev->reg); - return status; - } - - loop = 0; - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (!(val & REG41_MOTORENB)) /* motor enabled */ - { - DBG(DBG_proc, "%s: finished\n", __func__); - dev->scanhead_position_in_steps += steps; - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl841_stop_action (dev); - - DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); - return SANE_STATUS_IO_ERROR; -} - -/* Moves the slider to the home (top) position slowly */ -static SANE_Status -gl841_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - uint8_t val; - int loop = 0; - - DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); - - if (dev->model->is_sheetfed == SANE_TRUE) - { - DBG(DBG_proc, "%s: there is no \"home\"-concept for sheet fed\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; - } - - /* reset gpio pin */ - if (dev->model->gpo_type == GPO_CANONLIDE35) - { - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val = dev->gpo.value[0]; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - } - if (dev->model->gpo_type == GPO_CANONLIDE80) - { - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - val = REG6B_GPO18 | REG6B_GPO17; - RIE (sanei_genesys_write_register (dev, REG6B, val)); - } - gl841_save_power(dev, SANE_FALSE); - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - sanei_genesys_sleep_ms(100); - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - dev->scanhead_position_in_steps = 0; - - if (val & REG41_HOMESNR) /* is sensor at home? */ - { - DBG(DBG_info, "%s: already at home, completed\n", __func__); - dev->scanhead_position_in_steps = 0; - return SANE_STATUS_GOOD; - } - - /* end previous scan if any */ - r = sanei_genesys_get_address(&dev->reg, REG01); - r->value &= ~REG01_SCAN; - status = sanei_genesys_write_register (dev, REG01, r->value); - - /* if motor is on, stop current action */ - if (val & REG41_MOTORENB) - { - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop motor: %s\n", __func__, sane_strstatus(status)); - return SANE_STATUS_IO_ERROR; - } - } - - local_reg = dev->reg; - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - gl841_init_motor_regs(dev, sensor, &local_reg, 65536,MOTOR_ACTION_GO_HOME,0); - - /* set up for reverse and no scan */ - r = sanei_genesys_get_address(&local_reg, REG02); - r->value |= REG02_MTRREV; - r = sanei_genesys_get_address(&local_reg, REG01); - r->value &= ~REG01_SCAN; - - RIE (sanei_genesys_bulk_write_register(dev, local_reg)); - - try { - status = gl841_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl841_stop_action(dev); - } catch (...) {} - try { - sanei_genesys_bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl841_stop_action (dev); - /* send original registers */ - sanei_genesys_bulk_write_register(dev, dev->reg); - return status; - } - - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - if (val & REG41_HOMESNR) /* home sensor */ - { - DBG(DBG_info, "%s: reached home position\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl841_stop_action (dev); - DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - DBG(DBG_info, "%s: scanhead is still moving\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl841_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg; - int steps; - - int pixels = 600; - int dpi = 300; - - DBGSTART; - - local_reg = dev->reg; - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - // FIXME: the current approach of doing search only for one resolution does not work on scanners - // whith employ different sensors with potentially different settings. - auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); - - SetupParams params; - params.xres = dpi; - params.yres = dpi; - params.startx = 0; - params.starty = 0; /*we should give a small offset here~60 steps*/ - params.pixels = 600; - params.lines = dev->model->search_lines; - params.depth = 8; - params.channels = 1; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::GREEN; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; - - status = gl841_init_scan_regs(dev, sensor, &local_reg, params); - - if(status!=SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to init scan registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* send to scanner */ - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - size = pixels * dev->model->search_lines; - - std::vector data(size); - - status = gl841_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl841_search_position.pnm", data.data(), 8, 1, pixels, - dev->model->search_lines); - - status = gl841_end_scan(dev, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* update regs to copy ASIC internal state */ - dev->reg = local_reg; - -/*TODO: find out where sanei_genesys_search_reference_point - stores information, and use that correctly*/ - status = - sanei_genesys_search_reference_point (dev, sensor, data.data(), 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl841_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t channels; - uint8_t cksel; - - DBGSTART; - - cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else { - channels = 1; - } - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = 0; - params.starty = 0; - params.pixels = sensor.optical_res / cksel; /* XXX STEF XXX !!! */ - params.lines = 20; - params.depth = 16; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl841_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, - sensor.optical_res / cksel, dev->settings.xres); - - status = sanei_genesys_bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - -/* if (DBG_LEVEL >= DBG_info) - sanei_gl841_print_registers (regs);*/ - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -static SANE_Status -gl841_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Int ydpi; - float starty=0; - - DBGSTART; - DBG(DBG_proc, "%s: lines = %d\n", __func__, (int)(dev->calib_lines)); - - /* initial calibration reg values */ - regs = dev->reg; - - ydpi = dev->motor.base_ydpi; - if (dev->model->motor_type == MOTOR_PLUSTEK_3600) /* TODO PLUSTEK_3600: 1200dpi not yet working, produces dark bar */ - { - ydpi = 600; - } - if (dev->model->motor_type == MOTOR_CANONLIDE80) - { - ydpi = gl841_get_dpihw(dev); - /* get over extra dark area for this model. - It looks like different devices have dark areas of different width - due to manufacturing variability. The initial value of starty was 140, - but it moves the sensor almost past the dark area completely in places - on certain devices. - - On a particular device the black area starts at roughly position - 160 to 230 depending on location (the dark area is not completely - parallel to the frame). - */ - starty = 70; - } - - dev->calib_channels = 3; - dev->calib_lines = dev->model->shading_lines; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = ydpi; - params.startx = 0; - params.starty = starty; - params.pixels = (sensor.sensor_pixels * dev->settings.xres) / sensor.optical_res; - params.lines = dev->calib_lines; - params.depth = 16; - params.channels = dev->calib_channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_USE_OPTICAL_RES | - /*SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE |*/ - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl841_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - dev->calib_pixels = dev->current_setup.pixels; - dev->scanhead_position_in_steps += dev->calib_lines + starty; - - status = sanei_genesys_bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* set up registers for the actual scan - */ -static SANE_Status -gl841_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - -/* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - -/* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - - /* steps to move to reach scanning area: - - first we move to physical start of scanning - either by a fixed steps amount from the black strip - or by a fixed amount from parking position, - minus the steps done during shading calibration - - then we move by the needed offset whitin physical - scanning area - - assumption: steps are expressed at maximum motor resolution - - we need: - SANE_Fixed y_offset; - SANE_Fixed y_size; - SANE_Fixed y_offset_calib; - mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ - - /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is - relative from origin, else, it is from parking position */ - - move_dpi = dev->motor.base_ydpi; - - move = 0; - if (dev->model->flags & GENESYS_FLAG_SEARCH_START) - { - move += SANE_UNFIX (dev->model->y_offset_calib); - } - - DBG(DBG_info, "%s move=%f steps\n", __func__, move); - - move += SANE_UNFIX (dev->model->y_offset); - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - move += dev->settings.tl_y; - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - move = (move * move_dpi) / MM_PER_INCH; - -/* start */ - start = SANE_UNFIX (dev->model->x_offset); - - start += dev->settings.tl_x; - - start = (start * sensor.optical_res) / MM_PER_INCH; - - flags=0; - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - flags = 0; - - /* true gray (led add for cis scanners) */ - if(dev->model->is_cis && dev->settings.true_gray - && dev->settings.scan_mode != ScanColorMode::COLOR_SINGLE_PASS - && dev->model->ccd_type != CIS_CANONLIDE80) - { - // on Lide 80 the LEDADD bit results in only red LED array being lit - DBG(DBG_io, "%s: activating LEDADD\n", __func__); - flags |= SCAN_FLAG_ENABLE_LEDADD; - } - - /* enable emulated lineart from gray data */ - if(dev->settings.scan_mode == ScanColorMode::LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; - params.starty = move; - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = flags; - - status = gl841_init_scan_regs(dev, sensor, &dev->reg, params); - - if (status != SANE_STATUS_GOOD) - return status; - - - DBG(DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} - -/* - * this function sends generic gamma table (ie linear ones) - * or the Sensor specific one if provided - */ -static SANE_Status -gl841_send_gamma_table(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int size; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - size = 256; - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - std::vector gamma(size * 2 * 3); - - RIE(sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data())); - - /* send address */ - status = gl841_set_buffer_address_gamma (dev, 0x00000); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* send data */ - status = sanei_genesys_bulk_write_data(dev, 0x28, gamma.data(), size * 2 * 3); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send gamma table: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* this function does the led calibration by scanning one line of the calibration - area below scanner's top on white strip. - --needs working coarse/gain -*/ -static SANE_Status -gl841_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs) -{ - int num_pixels; - int total_size; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels; - int avg[3], avga, avge; - int turn; - uint16_t exp[3], target; - int move; - - SANE_Bool acceptable = SANE_FALSE; - - /* these 2 boundaries should be per sensor */ - uint16_t min_exposure=500; - uint16_t max_exposure; - - DBGSTART; - - /* feed to white strip if needed */ - if (dev->model->y_offset_calib>0) - { - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * (dev->motor.base_ydpi)) / MM_PER_INCH; - DBG(DBG_io, "%s: move=%d lines\n", __func__, move); - status = gl841_feed(dev, move); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to feed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - /* offset calibration is always done in color mode */ - channels = 3; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = 0; - params.starty = 0; - params.pixels = (sensor.sensor_pixels*dev->settings.xres) / sensor.optical_res; - params.lines = 1; - params.depth = 16; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES; - - status = gl841_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - RIE(sanei_genesys_bulk_write_register(dev, regs)); - - num_pixels = dev->current_setup.pixels; - - total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ - - std::vector line(total_size); - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - */ - - exp[0] = sensor.exposure.red; - exp[1] = sensor.exposure.green; - exp[2] = sensor.exposure.blue; - - turn = 0; - /* max exposure is set to ~2 time initial average - * exposure, or 2 time last calibration exposure */ - max_exposure=((exp[0]+exp[1]+exp[2])/3)*2; - target=sensor.gain_white_ref*256; - - do { - sensor.exposure.red = exp[0]; - sensor.exposure.green = exp[1]; - sensor.exposure.blue = exp[2]; - - sanei_genesys_set_exposure(regs, sensor.exposure); - RIE(sanei_genesys_write_register(dev, 0x10, (sensor.exposure.red >> 8) & 0xff)); - RIE(sanei_genesys_write_register(dev, 0x11, sensor.exposure.red & 0xff)); - RIE(sanei_genesys_write_register(dev, 0x12, (sensor.exposure.green >> 8) & 0xff)); - RIE(sanei_genesys_write_register(dev, 0x13, sensor.exposure.green & 0xff)); - RIE(sanei_genesys_write_register(dev, 0x14, (sensor.exposure.blue >> 8) & 0xff)); - RIE(sanei_genesys_write_register(dev, 0x15, sensor.exposure.blue & 0xff)); - - RIE(sanei_genesys_bulk_write_register(dev, regs)); - - DBG(DBG_info, "%s: starting line reading\n", __func__); - RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) { - char fn[30]; - snprintf(fn, 30, "gl841_led_%d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), 16, channels, num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG(DBG_info,"%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - acceptable = SANE_TRUE; - - /* exposure is acceptable if each color is in the %5 range - * of other color channels */ - if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || - avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || - avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) - { - acceptable = SANE_FALSE; - } - - /* led exposure is not acceptable if white level is too low - * ~80 hardcoded value for white level */ - if(avg[0]<20000 || avg[1]<20000 || avg[2]<20000) - { - acceptable = SANE_FALSE; - } - - /* for scanners using target value */ - if(target>0) - { - acceptable = SANE_TRUE; - for(i=0;i<3;i++) - { - /* we accept +- 2% delta from target */ - if(abs(avg[i]-target)>target/50) - { - exp[i]=(exp[i]*target)/avg[i]; - acceptable = SANE_FALSE; - } - } - } - else - { - if (!acceptable) - { - avga = (avg[0]+avg[1]+avg[2])/3; - exp[0] = (exp[0] * avga) / avg[0]; - exp[1] = (exp[1] * avga) / avg[1]; - exp[2] = (exp[2] * avga) / avg[2]; - /* - keep the resulting exposures below this value. - too long exposure drives the ccd into saturation. - we may fix this by relying on the fact that - we get a striped scan without shading, by means of - statistical calculation - */ - avge = (exp[0] + exp[1] + exp[2]) / 3; - - if (avge > max_exposure) { - exp[0] = (exp[0] * max_exposure) / avge; - exp[1] = (exp[1] * max_exposure) / avge; - exp[2] = (exp[2] * max_exposure) / avge; - } - if (avge < min_exposure) { - exp[0] = (exp[0] * min_exposure) / avge; - exp[1] = (exp[1] * min_exposure) / avge; - exp[2] = (exp[2] * min_exposure) / avge; - } - - } - } - - RIE (gl841_stop_action (dev)); - - turn++; - - } while (!acceptable && turn < 100); - - DBG(DBG_info,"%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); - - gl841_slow_back_home(dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - -/** @brief calibration for AD frontend devices - * offset calibration assumes that the scanning head is on a black area - * For LiDE80 analog frontend - * 0x0003 : is gain and belongs to [0..63] - * 0x0006 : is offset - * We scan a line with no gain until average offset reaches the target - */ -static SANE_Status -ad_fe_offset_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - int num_pixels; - int total_size; - int i; - int average; - int turn; - int top; - int bottom; - int target; - - DBGSTART; - - /* don't impact 3600 behavior since we can't test it */ - if (dev->model->ccd_type == CCD_PLUSTEK_3600) - { - DBGCOMPLETED; - return status; - } - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = 0; - params.starty = 0; - params.pixels = (sensor.sensor_pixels*dev->settings.xres) / sensor.optical_res; - params.lines = 1; - params.depth = 8; - params.channels = 3; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES; - - status = gl841_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - num_pixels = dev->current_setup.pixels; - total_size = num_pixels * 3 * 2 * 1; - - std::vector line(total_size); - - dev->frontend.set_gain(0, 0); - dev->frontend.set_gain(1, 0); - dev->frontend.set_gain(2, 0); - - /* loop on scan until target offset is reached */ - turn=0; - target=24; - bottom=0; - top=255; - do { - /* set up offset mid range */ - dev->frontend.set_offset(0, (top + bottom) / 2); - dev->frontend.set_offset(1, (top + bottom) / 2); - dev->frontend.set_offset(2, (top + bottom) / 2); - - /* scan line */ - DBG(DBG_info, "%s: starting line reading\n", __func__); - sanei_genesys_bulk_write_register(dev, regs); - gl841_set_fe(dev, sensor, AFE_SET); - gl841_begin_scan(dev, sensor, ®s, SANE_TRUE); - sanei_genesys_read_data_from_scanner(dev, line.data(), total_size); - gl841_stop_action (dev); - if (DBG_LEVEL >= DBG_data) { - char fn[30]; - snprintf(fn, 30, "gl841_offset_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), 8, 3, num_pixels, 1); - } - - /* search for minimal value */ - average=0; - for(i=0;itarget) - { - top=(top+bottom)/2; - } - else - { - bottom=(top+bottom)/2; - } - turn++; - } while ((top-bottom)>1 && turn < 100); - - // FIXME: don't overwrite the calibrated values - dev->frontend.set_offset(0, 0); - dev->frontend.set_offset(1, 0); - dev->frontend.set_offset(2, 0); - DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - DBGCOMPLETED; - return status; -} - -/* this function does the offset calibration by scanning one line of the calibration - area below scanner's top. There is a black margin and the remaining is white. - sanei_genesys_search_start() must have been called so that the offsets and margins - are allready known. - -this function expects the slider to be where? -*/ -static SANE_Status -gl841_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - int num_pixels; - int total_size; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels; - int off[3],offh[3],offl[3],off1[3],off2[3]; - int min1[3],min2[3]; - int cmin[3],cmax[3]; - int turn; - SANE_Bool acceptable = SANE_FALSE; - int mintgt = 0x400; - - DBG(DBG_proc, "%s\n", __func__); - - /* Analog Device fronted have a different calibration */ - if ((dev->reg.find_reg(0x04).value & REG04_FESET) == 0x02) - { - return ad_fe_offset_calibration(dev, sensor, regs); - } - - /* offset calibration is always done in color mode */ - channels = 3; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = 0; - params.starty = 0; - params.pixels = (sensor.sensor_pixels*dev->settings.xres) / sensor.optical_res; - params.lines = 1; - params.depth = 16; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES | - SCAN_FLAG_DISABLE_LAMP; - - status = gl841_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - num_pixels = dev->current_setup.pixels; - - total_size = num_pixels * channels * 2 * 1; /* colors * bytes_per_color * scan lines */ - - std::vector first_line(total_size); - std::vector second_line(total_size); - - /* scan first line of data with no offset nor gain */ -/*WM8199: gain=0.73; offset=-260mV*/ -/*okay. the sensor black level is now at -260mV. we only get 0 from AFE...*/ -/* we should probably do real calibration here: - * -detect acceptable offset with binary search - * -calculate offset from this last version - * - * acceptable offset means - * - few completely black pixels(<10%?) - * - few completely white pixels(<10%?) - * - * final offset should map the minimum not completely black - * pixel to 0(16 bits) - * - * this does account for dummy pixels at the end of ccd - * this assumes slider is at black strip(which is not quite as black as "no - * signal"). - * - */ - dev->frontend.set_gain(0, 0); - dev->frontend.set_gain(1, 0); - dev->frontend.set_gain(2, 0); - offh[0] = 0xff; - offh[1] = 0xff; - offh[2] = 0xff; - offl[0] = 0x00; - offl[1] = 0x00; - offl[2] = 0x00; - turn = 0; - - do { - - RIE(sanei_genesys_bulk_write_register(dev, regs)); - - for (j=0; j < channels; j++) { - off[j] = (offh[j]+offl[j])/2; - dev->frontend.set_offset(j, off[j]); - } - - status = gl841_set_fe(dev, sensor, AFE_SET); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup frontend: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_info, "%s: starting first line reading\n", __func__); - RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); - - RIE(sanei_genesys_read_data_from_scanner (dev, first_line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) { - char fn[30]; - snprintf(fn, 30, "gl841_offset1_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, first_line.data(), 16, channels, num_pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - cmin[j] = 0; - cmax[j] = 0; - - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - first_line[i * 2 + j * 2 * num_pixels]; - else - val = - first_line[i * 2 * channels + 2 * j + 1] * 256 + - first_line[i * 2 * channels + 2 * j]; - if (val < 10) - cmin[j]++; - if (val > 65525) - cmax[j]++; - } - - /* TODO the DP685 has a black strip in the middle of the sensor - * should be handled in a more elegant way , could be a bug */ - if (dev->model->ccd_type == CCD_DP685) - cmin[j] -= 20; - - if (cmin[j] > num_pixels/100) { - acceptable = SANE_FALSE; - if (dev->model->is_cis) - offl[0] = off[0]; - else - offl[j] = off[j]; - } - if (cmax[j] > num_pixels/100) { - acceptable = SANE_FALSE; - if (dev->model->is_cis) - offh[0] = off[0]; - else - offh[j] = off[j]; - } - } - - DBG(DBG_info,"%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0], - cmin[1], cmax[1], cmin[2], cmax[2]); - - if (dev->model->is_cis) { - offh[2] = offh[1] = offh[0]; - offl[2] = offl[1] = offl[0]; - } - - RIE(gl841_stop_action(dev)); - - turn++; - } while (!acceptable && turn < 100); - - DBG(DBG_info,"%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); - - - for (j = 0; j < channels; j++) - { - off1[j] = off[j]; - - min1[j] = 65536; - - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - first_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - first_line[i * 2 + j * 2 * num_pixels]; - else - val = - first_line[i * 2 * channels + 2 * j + 1] * 256 + - first_line[i * 2 * channels + 2 * j]; - if (min1[j] > val && val >= 10) - min1[j] = val; - } - } - - - offl[0] = off[0]; - offl[1] = off[0]; - offl[2] = off[0]; - turn = 0; - - do { - - for (j=0; j < channels; j++) { - off[j] = (offh[j]+offl[j])/2; - dev->frontend.set_offset(j, off[j]); - } - - status = gl841_set_fe(dev, sensor, AFE_SET); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup frontend: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(sanei_genesys_bulk_write_register(dev, regs)); - RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) { - char fn[30]; - snprintf(fn, 30, "gl841_offset2_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, second_line.data(), 16, channels, num_pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - cmin[j] = 0; - cmax[j] = 0; - - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - second_line[i * 2 + j * 2 * num_pixels]; - else - val = - second_line[i * 2 * channels + 2 * j + 1] * 256 + - second_line[i * 2 * channels + 2 * j]; - if (val < 10) - cmin[j]++; - if (val > 65525) - cmax[j]++; - } - - if (cmin[j] > num_pixels/100) { - acceptable = SANE_FALSE; - if (dev->model->is_cis) - offl[0] = off[0]; - else - offl[j] = off[j]; - } - if (cmax[j] > num_pixels/100) { - acceptable = SANE_FALSE; - if (dev->model->is_cis) - offh[0] = off[0]; - else - offh[j] = off[j]; - } - } - - DBG(DBG_info, "%s: black/white pixels: %d/%d,%d/%d,%d/%d\n", __func__, cmin[0], cmax[0], - cmin[1], cmax[1], cmin[2], cmax[2]); - - if (dev->model->is_cis) { - offh[2] = offh[1] = offh[0]; - offl[2] = offl[1] = offl[0]; - } - - RIE(gl841_stop_action (dev)); - - turn++; - - } while (!acceptable && turn < 100); - - DBG(DBG_info, "%s: acceptable offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); - - - for (j = 0; j < channels; j++) - { - off2[j] = off[j]; - - min2[j] = 65536; - - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - second_line[i * 2 + j * 2 * num_pixels + 1] * 256 + - second_line[i * 2 + j * 2 * num_pixels]; - else - val = - second_line[i * 2 * channels + 2 * j + 1] * 256 + - second_line[i * 2 * channels + 2 * j]; - if (min2[j] > val && val != 0) - min2[j] = val; - } - } - - DBG(DBG_info, "%s: first set: %d/%d,%d/%d,%d/%d\n", __func__, off1[0], min1[0], off1[1], min1[1], - off1[2], min1[2]); - - DBG(DBG_info, "%s: second set: %d/%d,%d/%d,%d/%d\n", __func__, off2[0], min2[0], off2[1], min2[1], - off2[2], min2[2]); - -/* - calculate offset for each channel - based on minimal pixel value min1 at offset off1 and minimal pixel value min2 - at offset off2 - - to get min at off, values are linearly interpolated: - min=real+off*fact - min1=real+off1*fact - min2=real+off2*fact - - fact=(min1-min2)/(off1-off2) - real=min1-off1*(min1-min2)/(off1-off2) - - off=(min-min1+off1*(min1-min2)/(off1-off2))/((min1-min2)/(off1-off2)) - - off=(min*(off1-off2)+min1*off2-off1*min2)/(min1-min2) - - */ - for (j = 0; j < channels; j++) - { - if (min2[j]-min1[j] == 0) { -/*TODO: try to avoid this*/ - DBG(DBG_warn, "%s: difference too small\n", __func__); - if (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j] >= 0) - off[j] = 0x0000; - else - off[j] = 0xffff; - } else - off[j] = (mintgt * (off1[j] - off2[j]) + min1[j] * off2[j] - min2[j] * off1[j])/(min1[j]-min2[j]); - if (off[j] > 255) - off[j] = 255; - if (off[j] < 0) - off[j] = 0; - dev->frontend.set_offset(j, off[j]); - } - - DBG(DBG_info, "%s: final offsets: %d,%d,%d\n", __func__, off[0], off[1], off[2]); - - if (dev->model->is_cis) { - if (off[0] < off[1]) - off[0] = off[1]; - if (off[0] < off[2]) - off[0] = off[2]; - dev->frontend.set_offset(0, off[0]); - dev->frontend.set_offset(1, off[0]); - dev->frontend.set_offset(2, off[0]); - } - - if (channels == 1) - { - dev->frontend.set_offset(1, dev->frontend.get_offset(0)); - dev->frontend.set_offset(2, dev->frontend.get_offset(0)); - } - - DBG(DBG_proc, "%s: completed\n", __func__); - return status; -} - - -/* alternative coarse gain calibration - this on uses the settings from offset_calibration and - uses only one scanline - */ -/* - with offset and coarse calibration we only want to get our input range into - a reasonable shape. the fine calibration of the upper and lower bounds will - be done with shading. - */ -static SANE_Status -gl841_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, int dpi) -{ - int num_pixels; - int total_size; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3]; - int val; - int lines=1; - int move; - - DBG(DBG_proc, "%s: dpi=%d\n", __func__, dpi); - - /* feed to white strip if needed */ - if (dev->model->y_offset_calib>0) - { - move = SANE_UNFIX (dev->model->y_offset_calib); - move = (move * (dev->motor.base_ydpi)) / MM_PER_INCH; - DBG(DBG_io, "%s: move=%d lines\n", __func__, move); - status = gl841_feed(dev, move); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to feed: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - /* coarse gain calibration is allways done in color mode */ - channels = 3; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = 0; - params.starty = 0; - params.pixels = (sensor.sensor_pixels*dev->settings.xres) / sensor.optical_res; - params.lines = lines; - params.depth = 16; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES; - - status = gl841_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - RIE(sanei_genesys_bulk_write_register(dev, regs)); - - num_pixels = dev->current_setup.pixels; - - total_size = num_pixels * channels * 2 * lines; /* colors * bytes_per_color * scan lines */ - - std::vector line(total_size); - - RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl841_gain.pnm", line.data(), 16, channels, num_pixels, lines); - - /* average high level for each channel and compute gain - to reach the target code - we only use the central half of the CCD data */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - - if (val > max[j]) - max[j] = val; - } - - gain[j] = 65535.0/max[j]; - - uint8_t out_gain = 0; - - if (dev->model->dac_type == DAC_CANONLIDE35 || - dev->model->dac_type == DAC_WOLFSON_XP300 || - dev->model->dac_type == DAC_WOLFSON_DSM600) - { - gain[j] *= 0.69;/*seems we don't get the real maximum. empirically derived*/ - if (283 - 208/gain[j] > 255) - out_gain = 255; - else if (283 - 208/gain[j] < 0) - out_gain = 0; - else - out_gain = 283 - 208/gain[j]; - } - else if (dev->model->dac_type == DAC_CANONLIDE80) - { - out_gain = gain[j]*12; - } - dev->frontend.set_gain(j, out_gain); - - DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], - out_gain); - } - - for (j = 0; j < channels; j++) - { - if(gain[j] > 10) - { - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**** ****\n"); - DBG (DBG_error0, "**** Extremely low Brightness detected. ****\n"); - DBG (DBG_error0, "**** Check the scanning head is ****\n"); - DBG (DBG_error0, "**** unlocked and moving. ****\n"); - DBG (DBG_error0, "**** ****\n"); - DBG (DBG_error0, "**********************************************\n"); - DBG (DBG_error0, "**********************************************\n"); - return SANE_STATUS_JAMMED; - } - - } - - if (dev->model->is_cis) { - uint8_t gain0 = dev->frontend.get_gain(0); - if (gain0 > dev->frontend.get_gain(1)) { - gain0 = dev->frontend.get_gain(1); - } - if (gain0 > dev->frontend.get_gain(2)) { - gain0 = dev->frontend.get_gain(2); - } - dev->frontend.set_gain(0, gain0); - dev->frontend.set_gain(1, gain0); - dev->frontend.set_gain(2, gain0); - } - - if (channels == 1) { - dev->frontend.set_gain(0, dev->frontend.get_gain(1)); - dev->frontend.set_gain(2, dev->frontend.get_gain(1)); - } - - DBG(DBG_info, "%s: gain=(%d,%d,%d)\n", __func__, - dev->frontend.get_gain(0), - dev->frontend.get_gain(1), - dev->frontend.get_gain(2)); - - RIE (gl841_stop_action (dev)); - - gl841_slow_back_home(dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - -/* - * wait for lamp warmup by scanning the same line until difference - * between 2 scans is below a threshold - */ -static SANE_Status -gl841_init_regs_for_warmup (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * local_reg, - int *channels, int *total_size) -{ - int num_pixels = (int) (4 * 300); - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s\n", __func__); - - *local_reg = dev->reg; - -/* okay.. these should be defaults stored somewhere */ - dev->frontend.set_gain(0, 0); - dev->frontend.set_gain(1, 0); - dev->frontend.set_gain(2, 0); - dev->frontend.set_offset(0, 0x80); - dev->frontend.set_offset(1, 0x80); - dev->frontend.set_offset(2, 0x80); - - SetupParams params; - params.xres = sensor.optical_res; - params.yres = dev->settings.yres; - params.startx = sensor.dummy_pixel; - params.starty = 0; - params.pixels = num_pixels; - params.lines = 1; - params.depth = 16; - params.channels = *channels; - params.scan_method = dev->settings.scan_method; - if (*channels == 3) { - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - } else { - params.scan_mode = ScanColorMode::GRAY; - } - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES; - - status = gl841_init_scan_regs(dev, sensor, local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - num_pixels = dev->current_setup.pixels; - - *total_size = num_pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */ - - RIE(sanei_genesys_bulk_write_register(dev, *local_reg)); - - return status; -} - - -/* - * this function moves head without scanning, forward, then backward - * so that the head goes to park position. - * as a by-product, also check for lock - */ -static SANE_Status -sanei_gl841_repark_head (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s\n", __func__); - - status = gl841_feed(dev,232); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to feed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* toggle motor flag, put an huge step number and redo move backward */ - status = gl841_slow_back_home (dev, SANE_TRUE); - DBG(DBG_proc, "%s: completed\n", __func__); - return status; -} - -static bool -gl841_is_compatible_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Calibration_Cache *cache, - int for_overwrite) -{ -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - - DBGSTART; - - /* calibration cache not working yet for this model */ - if (dev->model->ccd_type == CCD_PLUSTEK_3600) - { - return false; - } - - gl841_calculate_current_setup (dev, sensor); - - DBG(DBG_proc, "%s: checking\n", __func__); - - if (dev->current_setup.ccd_size_divisor != cache->used_setup.ccd_size_divisor) - return false; - - /* a cache entry expires after 30 minutes for non sheetfed scanners */ - /* this is not taken into account when overwriting cache entries */ -#ifdef HAVE_SYS_TIME_H - if(for_overwrite == SANE_FALSE) - { - gettimeofday (&time, NULL); - if ((time.tv_sec - cache->last_calibration > 30 * 60) - && (dev->model->is_sheetfed == SANE_FALSE)) - { - DBG(DBG_proc, "%s: expired entry, non compatible cache\n", __func__); - return false; - } - } -#endif - - DBGCOMPLETED; - return true; -} - -/* - * initialize ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -static SANE_Status -gl841_init (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - size_t size; - - DBG_INIT (); - DBGSTART; - - dev->scanhead_position_in_steps = 0; - - /* Check if the device has already been initialized and powered up */ - if (dev->already_initialized) - { - RIE (sanei_genesys_get_status (dev, &val)); - if (val & REG41_PWRBIT) - { - DBG(DBG_info, "%s: already initialized\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - } - - dev->dark_average_data.clear(); - dev->white_average_data.clear(); - - dev->settings.color_filter = ColorFilter::RED; - - /* ASIC reset */ - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - - /* Set default values for registers */ - gl841_init_registers (dev); - - /* Write initial registers */ - RIE(sanei_genesys_bulk_write_register(dev, dev->reg)); - - /* Test ASIC and RAM */ - if (!(dev->model->flags & GENESYS_FLAG_LAZY_INIT)) - { - RIE (sanei_gl841_asic_test (dev)); - } - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - /* Set analog frontend */ - RIE (gl841_set_fe(dev, sensor, AFE_INIT)); - - /* Move home */ - RIE (gl841_slow_back_home (dev, SANE_TRUE)); - - /* Init shading data */ - RIE (sanei_genesys_init_shading_data(dev, sensor, sensor.sensor_pixels)); - - /* ensure head is correctly parked, and check lock */ - if (dev->model->flags & GENESYS_FLAG_REPARK) - { - status = sanei_gl841_repark_head (dev); - if (status != SANE_STATUS_GOOD) - { - if (status == SANE_STATUS_INVAL) - DBG(DBG_error0, "Your scanner is locked. Please move the lock switch to the unlocked " - "position\n"); - else - DBG(DBG_error, "%s: sanei_gl841_repark_head failed: %s\n", __func__, - sane_strstatus(status)); - return status; - } - } - - /* send gamma tables */ - status = gl841_send_gamma_table(dev, sensor); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send initial gamma tables: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* initial calibration reg values */ - Genesys_Register_Set& regs = dev->calib_reg; - regs = dev->reg; - - SetupParams params; - params.xres = 300; - params.yres = 300; - params.startx = 0; - params.starty = 0; - params.pixels = (16 * 300) / sensor.optical_res; - params.lines = 1; - params.depth = 16; - params.channels = 3; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = ColorFilter::RED; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_USE_OPTICAL_RES; - - status = gl841_init_scan_regs(dev, sensor, ®s, params); - - RIE(sanei_genesys_bulk_write_register(dev, regs)); - - size = dev->current_setup.pixels * 3 * 2 * 1; /* colors * bytes_per_color * scan lines */ - - std::vector line(size); - - DBG(DBG_info, "%s: starting dummy data reading\n", __func__); - RIE(gl841_begin_scan(dev, sensor, ®s, SANE_TRUE)); - - sanei_usb_set_timeout(1000);/* 1 second*/ - -/*ignore errors. next read will succeed*/ - sanei_genesys_read_data_from_scanner(dev, line.data(), size); - - sanei_usb_set_timeout(30 * 1000);/* 30 seconds*/ - - RIE (gl841_end_scan(dev, ®s, SANE_TRUE)); - - regs = dev->reg; - - /* Set powersaving (default = 15 minutes) */ - RIE (gl841_set_powersaving (dev, 15)); - dev->already_initialized = SANE_TRUE; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl841_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not lose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - if (s->dev->model->gpo_type == GPO_CANONLIDE35 - || s->dev->model->gpo_type == GPO_CANONLIDE80) - { - RIE(sanei_genesys_read_register(s->dev, REG6D, &val)); - s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); - s->buttons[BUTTON_FILE_SW].write((val & 0x02) == 0); - s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); - s->buttons[BUTTON_COPY_SW].write((val & 0x08) == 0); - } - - if (s->dev->model->gpo_type == GPO_XP300 || - s->dev->model->gpo_type == GPO_DP665 || - s->dev->model->gpo_type == GPO_DP685) - { - RIE(sanei_genesys_read_register(s->dev, REG6D, &val)); - - s->buttons[BUTTON_PAGE_LOADED_SW].write((val & 0x01) == 0); - s->buttons[BUTTON_SCAN_SW].write((val & 0x02) == 0); - } - - return status; -} - -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl841_search_strip(Genesys_Device * dev, const Genesys_Sensor& sensor, - SANE_Bool forward, SANE_Bool black) -{ - unsigned int pixels, lines, channels; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg; - size_t size; - int steps, depth, dpi; - unsigned int pass, count, found, x, y, length; - char title[80]; - GenesysRegister *r; - uint8_t white_level=90; /**< default white level to detect white dots */ - uint8_t black_level=60; /**< default black level to detect black dots */ - - DBG(DBG_proc, "%s %s %s\n", __func__, black ? "black" : "white", forward ? "forward" : "reverse"); - - /* use maximum gain when doing forward white strip detection - * since we don't have calibrated the sensor yet */ - if(!black && forward) - { - dev->frontend.set_gain(0, 0xff); - dev->frontend.set_gain(1, 0xff); - dev->frontend.set_gain(2, 0xff); - } - - gl841_set_fe(dev, sensor, AFE_SET); - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* set up for a gray scan at lowest dpi */ - dpi = 9600; - for (x = 0; x < MAX_RESOLUTIONS; x++) - { - if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) - dpi = dev->model->xdpi_values[x]; - } - channels = 1; - - /* shading calibation is done with dev->motor.base_ydpi */ - /* lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; */ - lines = (10*dpi)/MM_PER_INCH; - - depth = 8; - pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; - size = pixels * channels * lines * (depth / 8); - std::vector data(size); - - /* 20 cm max length for calibration sheet */ - length = ((200 * dpi) / MM_PER_INCH)/lines; - - dev->scanhead_position_in_steps = 0; - - local_reg = dev->reg; - - SetupParams params; - params.xres = dpi; - params.yres = dpi; - params.startx = 0; - params.starty = 0; - params.pixels = pixels; - params.lines = lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::RED; - params.flags = SCAN_FLAG_DISABLE_SHADING | SCAN_FLAG_DISABLE_GAMMA; - - status = gl841_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* set up for reverse or forward */ - r = sanei_genesys_get_address(&local_reg, 0x02); - if (forward) - r->value &= ~4; - else - r->value |= 4; - - - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl841_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl841_stop_action failed\n", __func__); - return status; - } - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", black ? "black" : "white", - forward ? "fwd" : "bwd", pass); - sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < length && !found) - { - status = sanei_genesys_bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* now start scan */ - status = gl841_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error,"%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner (dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "g%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl841_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl841_stop_action failed\n", __func__); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf(title, "gl841_search_strip_%s_%s%02u.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", pass); - sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > white_level) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < black_level) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, - pass, y); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > white_level) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < black_level) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - pass++; - } - - if (found) - { - status = SANE_STATUS_GOOD; - DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG(DBG_info, "%s: %s strip not found\n", __func__, black ? "black" : "white"); - } - - DBG(DBG_proc, "%s: completed\n", __func__); - return status; -} - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -static -SANE_Status -gl841_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t length, x, factor, pixels, i; - uint32_t lines, channels; - uint16_t dpiset, dpihw, strpixel ,endpixel, beginpixel; - uint8_t *ptr,*src; - - DBGSTART; - DBG(DBG_io2, "%s: writing %d bytes of shading data\n", __func__, size); - - /* old method if no SHDAREA */ - if((dev->reg.find_reg(0x01).value & REG01_SHDAREA) == 0) - { - /* start address */ - status = sanei_genesys_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* shading data whole line */ - status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send shading table: %s\n", __func__, - sane_strstatus(status)); - return status; - } - DBGCOMPLETED; - return status; - } - - /* data is whole line, we extract only the part for the scanned area */ - length = (uint32_t) (size / 3); - sanei_genesys_get_double(&dev->reg,REG_STRPIXEL,&strpixel); - sanei_genesys_get_double(&dev->reg,REG_ENDPIXEL,&endpixel); - DBG(DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d\n", __func__, strpixel, endpixel, - endpixel-strpixel); - - /* compute deletion/average factor */ - sanei_genesys_get_double(&dev->reg,REG_DPISET,&dpiset); - dpihw = gl841_get_dpihw(dev); - unsigned ccd_size_divisor = dev->current_setup.ccd_size_divisor; - factor=dpihw/dpiset; - DBG(DBG_io2, "%s: dpihw=%d, dpiset=%d, ccd_size_divisor=%d, factor=%d\n", __func__, dpihw, dpiset, - ccd_size_divisor, factor); - - /* binary data logging */ - if(DBG_LEVEL>=DBG_data) - { - dev->binary=fopen("binary.pnm","wb"); - sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &lines); - channels=dev->current_setup.channels; - if(dev->binary!=NULL) - { - fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); - } - } - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; /* 2 words of 2 bytes */ - endpixel*=2*2; - pixels=endpixel-strpixel; - - /* shading pixel begin is start pixel minus start pixel during shading - * calibration. Currently only cases handled are full and half ccd resolution. - */ - beginpixel = sensor.CCD_start_xoffset / ccd_size_divisor; - beginpixel += sensor.dummy_pixel + 1; - DBG(DBG_io2, "%s: ORIGIN PIXEL=%d\n", __func__, beginpixel); - beginpixel = (strpixel-beginpixel*2*2)/factor; - DBG(DBG_io2, "%s: BEGIN PIXEL=%d\n", __func__, beginpixel/4); - - DBG(DBG_io2, "%s: using chunks of %d bytes (%d shading data pixels)\n", __func__, length, - length/4); - std::vector buffer(pixels, 0); - - /* write actual shading data contigously - * channel by channel, starting at addr 0x0000 - * */ - for(i=0;i<3;i++) - { - /* copy data to work buffer and process it */ - /* coefficent destination */ - ptr=buffer.data(); - - /* iterate on both sensor segment, data has been averaged, - * so is in the right order and we only have to copy it */ - for(x=0;xmodel->cmd_set->bulk_write_data(dev, 0x3c, buffer.data(), pixels)); - } - - DBGCOMPLETED; - - return status; -} - - -/** the gl841 command set */ -static Genesys_Command_Set gl841_cmd_set = { - "gl841-generic", /* the name of this set */ - - [](Genesys_Device* dev) -> bool { (void) dev; return true; }, - - gl841_init, - gl841_init_regs_for_warmup, - gl841_init_regs_for_coarse_calibration, - gl841_init_regs_for_shading, - gl841_init_regs_for_scan, - - gl841_get_filter_bit, - gl841_get_lineart_bit, - gl841_get_bitset_bit, - gl841_get_gain4_bit, - gl841_get_fast_feed_bit, - gl841_test_buffer_empty_bit, - gl841_test_motor_flag_bit, - - gl841_set_fe, - gl841_set_powersaving, - gl841_save_power, - - gl841_begin_scan, - gl841_end_scan, - - gl841_send_gamma_table, - - gl841_search_start_position, - - gl841_offset_calibration, - gl841_coarse_gain_calibration, - gl841_led_calibration, - - NULL, - gl841_slow_back_home, - NULL, - - sanei_genesys_bulk_write_register, - sanei_genesys_bulk_write_data, - sanei_genesys_bulk_read_data, - - gl841_update_hardware_sensors, - - gl841_load_document, - gl841_detect_document_end, - gl841_eject_document, - gl841_search_strip, - - gl841_is_compatible_calibration, - NULL, - gl841_send_shading_data, - gl841_calculate_current_setup, - NULL -}; - -SANE_Status -sanei_gl841_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl841_cmd_set; - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_gl841.h b/backend/genesys_gl841.h deleted file mode 100644 index 3dbfc80..0000000 --- a/backend/genesys_gl841.h +++ /dev/null @@ -1,265 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2011-2013 Stéphane Voltz - - 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 "genesys.h" - -/* Individual bits */ -#define REG01 0x01 -#define REG01_CISSET 0x80 -#define REG01_DOGENB 0x40 -#define REG01_DVDSET 0x20 -#define REG01_M16DRAM 0x08 -#define REG01_DRAMSEL 0x04 -#define REG01_SHDAREA 0x02 -#define REG01_SCAN 0x01 - -#define REG02 0x02 -#define REG02_NOTHOME 0x80 -#define REG02_ACDCDIS 0x40 -#define REG02_AGOHOME 0x20 -#define REG02_MTRPWR 0x10 -#define REG02_FASTFED 0x08 -#define REG02_MTRREV 0x04 -#define REG02_HOMENEG 0x02 -#define REG02_LONGCURV 0x01 - -#define REG03_LAMPDOG 0x80 -#define REG03_AVEENB 0x40 -#define REG03_XPASEL 0x20 -#define REG03_LAMPPWR 0x10 -#define REG03_LAMPTIM 0x0f - -#define REG04_LINEART 0x80 -#define REG04_BITSET 0x40 -#define REG04_AFEMOD 0x30 -#define REG04_FILTER 0x0c -#define REG04_FESET 0x03 - -#define REG04S_AFEMOD 4 - -#define REG05_DPIHW 0xc0 -#define REG05_DPIHW_600 0x00 -#define REG05_DPIHW_1200 0x40 -#define REG05_DPIHW_2400 0x80 -#define REG05_MTLLAMP 0x30 -#define REG05_GMMENB 0x08 -#define REG05_MTLBASE 0x03 - -#define REG06_SCANMOD 0xe0 -#define REG06S_SCANMOD 5 -#define REG06_PWRBIT 0x10 -#define REG06_GAIN4 0x08 -#define REG06_OPTEST 0x07 - -#define REG07_SRAMSEL 0x08 -#define REG07_FASTDMA 0x04 -#define REG07_DMASEL 0x02 -#define REG07_DMARDWR 0x01 - -#define REG08_DECFLAG 0x40 -#define REG08_GMMFFR 0x20 -#define REG08_GMMFFG 0x10 -#define REG08_GMMFFB 0x08 -#define REG08_GMMZR 0x04 -#define REG08_GMMZG 0x02 -#define REG08_GMMZB 0x01 - -#define REG09_MCNTSET 0xc0 -#define REG09_CLKSET 0x30 -#define REG09_BACKSCAN 0x08 -#define REG09_ENHANCE 0x04 -#define REG09_SHORTTG 0x02 -#define REG09_NWAIT 0x01 - -#define REG09S_MCNTSET 6 -#define REG09S_CLKSET 4 - - -#define REG0A_SRAMBUF 0x01 - -#define REG0D 0x0d -#define REG0D_CLRLNCNT 0x01 - -#define REG16_CTRLHI 0x80 -#define REG16_TOSHIBA 0x40 -#define REG16_TGINV 0x20 -#define REG16_CK1INV 0x10 -#define REG16_CK2INV 0x08 -#define REG16_CTRLINV 0x04 -#define REG16_CKDIS 0x02 -#define REG16_CTRLDIS 0x01 - -#define REG17_TGMODE 0xc0 -#define REG17_TGMODE_NO_DUMMY 0x00 -#define REG17_TGMODE_REF 0x40 -#define REG17_TGMODE_XPA 0x80 -#define REG17_TGW 0x3f -#define REG17S_TGW 0 - -#define REG18_CNSET 0x80 -#define REG18_DCKSEL 0x60 -#define REG18_CKTOGGLE 0x10 -#define REG18_CKDELAY 0x0c -#define REG18_CKSEL 0x03 - -#define REG1A_MANUAL3 0x02 -#define REG1A_MANUAL1 0x01 -#define REG1A_CK4INV 0x08 -#define REG1A_CK3INV 0x04 -#define REG1A_LINECLP 0x02 - -#define REG1C_TGTIME 0x07 - -#define REG1D_CK4LOW 0x80 -#define REG1D_CK3LOW 0x40 -#define REG1D_CK1LOW 0x20 -#define REG1D_TGSHLD 0x1f -#define REG1DS_TGSHLD 0 - - -#define REG1E 0x1e -#define REG1E_WDTIME 0xf0 -#define REG1ES_WDTIME 4 -#define REG1E_LINESEL 0x0f -#define REG1ES_LINESEL 0 - -#define REG_EXPR 0x10 -#define REG_EXPG 0x12 -#define REG_EXPB 0x14 -#define REG_STEPNO 0x21 -#define REG_FWDSTEP 0x22 -#define REG_BWDSTEP 0x23 -#define REG_FASTNO 0x24 -#define REG_LINCNT 0x25 -#define REG_DPISET 0x2c -#define REG_STRPIXEL 0x30 -#define REG_ENDPIXEL 0x32 -#define REG_LPERIOD 0x38 - -#define REG40_HISPDFLG 0x04 -#define REG40_MOTMFLG 0x02 -#define REG40_DATAENB 0x01 - -#define REG41_PWRBIT 0x80 -#define REG41_BUFEMPTY 0x40 -#define REG41_FEEDFSH 0x20 -#define REG41_SCANFSH 0x10 -#define REG41_HOMESNR 0x08 -#define REG41_LAMPSTS 0x04 -#define REG41_FEBUSY 0x02 -#define REG41_MOTORENB 0x01 - -#define REG58_VSMP 0xf8 -#define REG58S_VSMP 3 -#define REG58_VSMPW 0x07 -#define REG58S_VSMPW 0 - -#define REG59_BSMP 0xf8 -#define REG59S_BSMP 3 -#define REG59_BSMPW 0x07 -#define REG59S_BSMPW 0 - -#define REG5A_ADCLKINV 0x80 -#define REG5A_RLCSEL 0x40 -#define REG5A_CDSREF 0x30 -#define REG5AS_CDSREF 4 -#define REG5A_RLC 0x0f -#define REG5AS_RLC 0 - -#define REG5E_DECSEL 0xe0 -#define REG5ES_DECSEL 5 -#define REG5E_STOPTIM 0x1f -#define REG5ES_STOPTIM 0 - -#define REG60_ZIMOD 0x1f -#define REG61_Z1MOD 0xff -#define REG62_Z1MOD 0xff - -#define REG63_Z2MOD 0x1f -#define REG64_Z2MOD 0xff -#define REG65_Z2MOD 0xff - -#define REG67_STEPSEL 0xc0 -#define REG67_FULLSTEP 0x00 -#define REG67_HALFSTEP 0x40 -#define REG67_QUATERSTEP 0x80 -#define REG67_MTRPWM 0x3f - -#define REG68_FSTPSEL 0xc0 -#define REG68_FULLSTEP 0x00 -#define REG68_HALFSTEP 0x40 -#define REG68_QUATERSTEP 0x80 -#define REG68_FASTPWM 0x3f - -#define REG6B_MULTFILM 0x80 -#define REG6B_GPOM13 0x40 -#define REG6B_GPOM12 0x20 -#define REG6B_GPOM11 0x10 -#define REG6B_GPO18 0x02 -#define REG6B_GPO17 0x01 - -#define REG6B 0x6b - -#define REG6C 0x6c -#define REG6C_GPIOH 0xff -#define REG6C_GPIOL 0xff - -#define REG6D 0x6d -#define REG6E 0x6e -#define REG6F 0x6f - -#define REG87_LEDADD 0x04 - -#define INITREG(adr,val) {dev->reg.init_reg(adr, val); } - -/** - * prototypes declaration in case of unit testing - */ - -static -int gl841_exposure_time(Genesys_Device *dev, const Genesys_Sensor& sensor, - float slope_dpi, - int scan_step_type, - int start, - int used_pixels, - int *scan_power_mode); diff --git a/backend/genesys_gl843.cc b/backend/genesys_gl843.cc deleted file mode 100644 index a72dc5a..0000000 --- a/backend/genesys_gl843.cc +++ /dev/null @@ -1,4415 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2013 Stéphane Voltz - - - 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. -*/ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_gl843.h" - -#include -#include - -/**************************************************************************** - Low level function - ****************************************************************************/ - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - -/* Set address for writing data */ -static SANE_Status -gl843_set_buffer_address (Genesys_Device * dev, uint32_t addr) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xffff); - - status = sanei_genesys_write_register (dev, 0x5b, ((addr >> 8) & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while writing high byte: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = sanei_genesys_write_register (dev, 0x5c, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while writing low byte: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_io, "%s: completed\n", __func__); - - return status; -} - -/** - * writes a block of data to RAM - * @param dev USB device - * @param addr RAM address to write to - * @param size size of the chunk of data - * @param data pointer to the data to write - */ -static SANE_Status -write_data (Genesys_Device * dev, uint32_t addr, uint32_t size, - uint8_t * data) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - status = gl843_set_buffer_address (dev, addr); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while setting address for bulk write data: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* write actual data */ - status = sanei_genesys_bulk_write_data(dev, 0x28, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while writing bulk write data: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* set back address to 0 */ - status = gl843_set_buffer_address (dev, 0); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed setting to default RAM address: %s\n", __func__, - sane_strstatus(status)); - return status; - } - DBGCOMPLETED; - return status; -} - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl843_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_get_filter_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_get_lineart_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_get_bitset_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_get_gain4_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -/** - * compute the step multiplier used - */ -static int -gl843_get_step_multiplier (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - int value = 1; - - r = sanei_genesys_get_address (regs, REG9D); - if (r != NULL) - { - switch (r->value & 0x0c) - { - case 0x04: - value = 2; - break; - case 0x08: - value = 4; - break; - default: - value = 1; - } - } - DBG(DBG_io, "%s: step multiplier is %d\n", __func__, value); - return value; -} - -static SANE_Bool -gl843_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl843_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** copy sensor specific settings */ -static void -gl843_setup_sensor (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, int dpi,int flags) -{ - (void) dpi; - (void) flags; - - DBGSTART; - - for (const auto& custom_reg : sensor.custom_regs) { - regs->set8(custom_reg.address, custom_reg.value); - } - if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE)) { - regs->set8(0x7d, 0x90); - } - - DBGCOMPLETED; -} - - -/** @brief set all registers to default values . - * This function is called only once at the beginning and - * fills register startup values for registers reused across scans. - * Those that are rarely modified or not modified are written - * individually. - * @param dev device structure holding register set to initialize - */ -static void -gl843_init_registers (Genesys_Device * dev) -{ - // Within this function SENSOR_DEF marker documents that a register is part - // of the sensors definition and the actual value is set in - // gl843_setup_sensor(). - - DBGSTART; - - dev->reg.clear(); - - /* default to KV-SS080 */ - SETREG (0xa2, 0x0f); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0xa2, 0x1f); - } - SETREG (0x01, 0x00); - SETREG (0x02, 0x78); - SETREG (0x03, 0x1f); - SETREG (0x04, 0x10); - - // fine tune upon device description - SETREG (0x05, 0x80); - if (dev->model->model_id == MODEL_HP_SCANJET_G4010 || - dev->model->model_id == MODEL_HP_SCANJET_G4050 || - dev->model->model_id == MODEL_HP_SCANJET_4850C) - { - SETREG (0x05, 0x08); - } - - dev->reg.find_reg(0x05).value &= ~REG05_DPIHW; - switch (sanei_genesys_find_sensor_any(dev).optical_res) - { - case 600: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; - break; - case 4800: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_4800; - break; - } - - // TODO: on 8600F the windows driver turns off GAIN4 which is recommended - SETREG (0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ - SETREG (0x08, 0x00); - SETREG (0x09, 0x00); - SETREG (0x0a, 0x00); - - // This register controls clock and RAM settings and is further modified in - // gl843_boot - SETREG (0x0b, 0x6a); - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x0b, 0x89); - } - - // EXPR[0:15], EXPG[0:15], EXPB[0:15]: Exposure time settings. - SETREG(0x10, 0x00); // SENSOR_DEF - SETREG(0x11, 0x00); // SENSOR_DEF - SETREG(0x12, 0x00); // SENSOR_DEF - SETREG(0x13, 0x00); // SENSOR_DEF - SETREG(0x14, 0x00); // SENSOR_DEF - SETREG(0x15, 0x00); // SENSOR_DEF - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - dev->reg.set16(REG_EXPR, 0x9c40); - dev->reg.set16(REG_EXPG, 0x9c40); - dev->reg.set16(REG_EXPB, 0x9c40); - } - // CCD signal settings. - SETREG(0x16, 0x33); // SENSOR_DEF - SETREG(0x17, 0x1c); // SENSOR_DEF - SETREG(0x18, 0x10); // SENSOR_DEF - - // EXPDMY[0:7]: Exposure time of dummy lines. - SETREG(0x19, 0x2a); // SENSOR_DEF - - // Various CCD clock settings. - SETREG(0x1a, 0x04); // SENSOR_DEF - SETREG(0x1b, 0x00); // SENSOR_DEF - SETREG(0x1c, 0x20); // SENSOR_DEF - SETREG(0x1d, 0x04); // SENSOR_DEF - - SETREG (0x1e, 0x10); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x1e, 0x20); - } - - SETREG (0x1f, 0x01); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x1f, 0xff); - } - - SETREG (0x20, 0x10); - SETREG (0x21, 0x04); - SETREG (0x22, 0x01); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x22, 0xc8); - } - - SETREG (0x23, 0x01); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x23, 0xc8); - } - - SETREG (0x24, 0x04); - SETREG (0x25, 0x00); - SETREG (0x26, 0x00); - SETREG (0x27, 0x00); - SETREG (0x2c, 0x02); - SETREG (0x2d, 0x58); - // BWHI[0:7]: high level of black and white threshold - SETREG (0x2e, 0x80); - // BWLOW[0:7]: low level of black and white threshold - SETREG (0x2f, 0x80); - SETREG (0x30, 0x00); - SETREG (0x31, 0x14); - SETREG (0x32, 0x27); - SETREG (0x33, 0xec); - - // DUMMY: CCD dummy and optically black pixel count - SETREG (0x34, 0x24); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x34, 0x14); - } - - // MAXWD: If available buffer size is less than 2*MAXWD words, then - // "buffer full" state will be set. - SETREG (0x35, 0x00); - SETREG (0x36, 0xff); - SETREG (0x37, 0xff); - - // LPERIOD: Line period or exposure time for CCD or CIS. - SETREG(0x38, 0x55); // SENSOR_DEF - SETREG(0x39, 0xf0); // SENSOR_DEF - - // FEEDL[0:24]: The number of steps of motor movement. - SETREG(0x3d, 0x00); - SETREG (0x3e, 0x00); - SETREG (0x3f, 0x01); - - // Latch points for high and low bytes of R, G and B channels of AFE. If - // multiple clocks per pixel are consumed, then the setting defines during - // which clock the corresponding value will be read. - // RHI[0:4]: The latch point for high byte of R channel. - // RLOW[0:4]: The latch point for low byte of R channel. - // GHI[0:4]: The latch point for high byte of G channel. - // GLOW[0:4]: The latch point for low byte of G channel. - // BHI[0:4]: The latch point for high byte of B channel. - // BLOW[0:4]: The latch point for low byte of B channel. - SETREG(0x52, 0x01); // SENSOR_DEF - SETREG(0x53, 0x04); // SENSOR_DEF - SETREG(0x54, 0x07); // SENSOR_DEF - SETREG(0x55, 0x0a); // SENSOR_DEF - SETREG(0x56, 0x0d); // SENSOR_DEF - SETREG(0x57, 0x10); // SENSOR_DEF - - // VSMP[0:4]: The position of the image sampling pulse for AFE in cycles. - // VSMPW[0:2]: The length of the image sampling pulse for AFE in cycles. - SETREG(0x58, 0x1b); // SENSOR_DEF - - SETREG(0x59, 0x00); // SENSOR_DEF - SETREG(0x5a, 0x40); // SENSOR_DEF - - // 0x5b-0x5c: GMMADDR[0:15] address for gamma or motor tables download - // SENSOR_DEF - - // DECSEL[0:2]: The number of deceleratino steps after touching home sensor - // STOPTIM[0:4]: The stop duration between change of directions in - // backtracking - SETREG (0x5e, 0x23); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x5e, 0x1f); - } - - // FMOVDEC: The number of deceleration steps in table 5 for auto-go-home - SETREG (0x5f, 0x01); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x5f, 0xf0); - } - - // Z1MOD[0:20] - SETREG (0x60, 0x00); - SETREG (0x61, 0x00); - SETREG (0x62, 0x00); - - // Z2MOD[0:20] - SETREG (0x63, 0x00); - SETREG (0x64, 0x00); - SETREG (0x65, 0x00); - - // STEPSEL[0:1]. Motor movement step mode selection for tables 1-3 in - // scanning mode. - // MTRPWM[0:5]. Motor phase PWM duty cycle setting for tables 1-3 - SETREG (0x67, 0x7f); - // FSTPSEL[0:1]: Motor movement step mode selection for tables 4-5 in - // command mode. - // FASTPWM[5:0]: Motor phase PWM duty cycle setting for tables 4-5 - SETREG (0x68, 0x7f); - - // FSHDEC[0:7]: The number of deceleration steps after scanning is finished - // (table 3) - SETREG (0x69, 0x01); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x69, 64); - } - - // FMOVNO[0:7] The number of acceleration or deceleration steps for fast - // moving (table 4) - SETREG (0x6a, 0x04); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x69, 64); - } - - // GPIO-related register bits - SETREG (0x6b, 0x30); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x6b, 0x72); - } - - // 0x6c, 0x6d, 0x6e, 0x6f are set according to gpio tables. See - // gl843_init_gpio. - - // RSH[0:4]: The position of rising edge of CCD RS signal in cycles - // RSL[0:4]: The position of falling edge of CCD RS signal in cycles - // CPH[0:4]: The position of rising edge of CCD CP signal in cycles. - // CPL[0:4]: The position of falling edge of CCD CP signal in cycles - SETREG(0x70, 0x01); // SENSOR_DEF - SETREG(0x71, 0x03); // SENSOR_DEF - SETREG (0x72, 0x04); - SETREG (0x73, 0x05); - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x70, 0x00); - SETREG(0x71, 0x02); - SETREG(0x72, 0x02); - SETREG(0x73, 0x04); - } - - // CK1MAP[0:17], CK3MAP[0:17], CK4MAP[0:17]: CCD clock bit mapping setting. - SETREG(0x74, 0x00); // SENSOR_DEF - SETREG(0x75, 0x00); // SENSOR_DEF - SETREG(0x76, 0x3c); // SENSOR_DEF - SETREG(0x77, 0x00); // SENSOR_DEF - SETREG(0x78, 0x00); // SENSOR_DEF - SETREG(0x79, 0x9f); // SENSOR_DEF - SETREG(0x7a, 0x00); // SENSOR_DEF - SETREG(0x7b, 0x00); // SENSOR_DEF - SETREG(0x7c, 0x55); // SENSOR_DEF - - // various AFE settings - SETREG(0x7d, 0x00); - - // GPOLED[x]: LED vs GPIO settings - SETREG(0x7e, 0x00); - - // BSMPDLY, VSMPDLY - // LEDCNT[0:1]: Controls led blinking and its period - SETREG (0x7f, 0x00); - - // VRHOME, VRMOVE, VRBACK, VRSCAN: Vref settings of the motor driver IC for - // moving in various situations. - SETREG (0x80, 0x00); - - if (dev->model->model_id != MODEL_CANON_CANOSCAN_4400F) - { - // NOTE: Historical code. None of the following 6 registers are - // documented in the datasheet. Their default value is 0, so probably it's - // not a bad idea to leave this here. - SETREG (0x81, 0x00); - SETREG (0x82, 0x00); - SETREG (0x83, 0x00); - SETREG (0x84, 0x00); - SETREG (0x85, 0x00); - SETREG (0x86, 0x00); - } - - SETREG (0x87, 0x00); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x87, 0x02); - } - - // MTRPLS[0:7]: The width of the ADF motor trigger signal pulse. - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x94, 0xff); - } - - // 0x95-0x97: SCANLEN[0:19]: Controls when paper jam bit is set in sheetfed - // scanners. - - // ONDUR[0:15]: The duration of PWM ON phase for LAMP control - // OFFDUR[0:15]: The duration of PWM OFF phase for LAMP control - // both of the above are in system clocks - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x98, 0x00); - SETREG(0x99, 0x00); - SETREG(0x9a, 0x00); - SETREG(0x9b, 0x00); - } - - // RMADLY[0:1], MOTLAG, CMODE, STEPTIM, MULDMYLN, IFRS - SETREG(0x9d, 0x04); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0x9d, 0x08); // additionally sets the multiplier for slope tables - } - - - // SEL3INV, TGSTIME[0:2], TGWTIME[0:2] - SETREG (0x9e, 0x00); // SENSOR_DEF - - // RFHSET[0:4]: Refresh time of SDRAM in units of 2us - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0xa2, 0x1f); - } - - // 0xa6-0xa9: controls gpio, see gl843_gpio_init - - // GPOM9, MULSTOP[0-2], NODECEL, TB3TB1, TB5TB2, FIX16CLK. - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0xab, 0x00); - } - - // VRHOME[3:2], VRMOVE[3:2], VRBACK[3:2]: Vref setting of the motor driver IC - // for various situations. - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - SETREG(0xac, 0x00); - } - - if (dev->model->model_id != MODEL_CANON_CANOSCAN_8400F) - { - SETREG (0x0c, 0x00); - SETREG (0x94, 0xff); - SETREG (0xab, 0x50); - } - - if (dev->model->model_id != MODEL_CANON_CANOSCAN_4400F - && dev->model->model_id != MODEL_CANON_CANOSCAN_8400F) - { - SETREG (0xaa, 0x00); - } - - /* G4050 values */ - if (dev->model->model_id == MODEL_HP_SCANJET_G4010 || - dev->model->model_id == MODEL_HP_SCANJET_G4050 || - dev->model->model_id == MODEL_HP_SCANJET_4850C) - { - SETREG (0x03, 0x1d); - SETREG (0x06, 0xd0); /* SCANMOD=110, PWRBIT and no GAIN4 */ - SETREG (0x06, 0xd8); /* SCANMOD=110, PWRBIT and GAIN4 */ - SETREG (0x0a, 0x18); - SETREG (0x0b, 0x69); - - /* CIS exposure is used for XPA lamp movement */ - SETREG (0x10, 0x2c); - SETREG (0x11, 0x09); - SETREG (0x12, 0x22); - SETREG (0x13, 0xb8); - SETREG (0x14, 0x10); - SETREG (0x15, 0xf0); - - SETREG (0x6b, 0xf4); - - SETREG (0x70, 0x00); - SETREG (0x71, 0x02); - SETREG (0x72, 0x00); - SETREG (0x73, 0x00); - - SETREG (0x80, 0x50); - SETREG (0x9d, 0x08); - SETREG (0xab, 0x40); - - /* XXX STEF XXX TODO move to set for scan */ - SETREG (0x98, 0x03); - SETREG (0x99, 0x30); - SETREG (0x9a, 0x01); - SETREG (0x9b, 0x80); - SETREG (0xac, 0x00); - } - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_4400F) - { - SETREG (0x06, 0xf0); /* SCANMOD=111, PWRBIT and no GAIN4 */ - SETREG (0x0b, 0x69); /* 16M only */ - SETREG (0x1e, 0x20); - SETREG (0x22, 0xc8); - SETREG (0x23, 0xc8); - SETREG (0x5e, 0x3f); - SETREG (0x5f, 0xf0); - SETREG (0x6b, 0x72); - SETREG (0x72, 0x01); - SETREG (0x73, 0x03); - SETREG (0x80, 0x0c); - SETREG (0x87, 0x02); /* MCLOCK -> CK4MAP */ - SETREG (0x9d, 0x08); /* STEPTIM=2 */ - SETREG (0xa2, 0x1f); - SETREG (0xab, 0x00); - sanei_genesys_set_double(&dev->reg,REG_EXPR,0x9c40); - sanei_genesys_set_double(&dev->reg,REG_EXPG,0x9c40); - sanei_genesys_set_double(&dev->reg,REG_EXPB,0x9c40); - } - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8400F) - { - SETREG (0x03, 0x1c); - SETREG (0x06, 0xd0); /* SCANMOD=110, PWRBIT and no GAIN4 */ - SETREG (0x0a, 0x10); - SETREG (0x22, 0x50); - SETREG (0x23, 0x50); - SETREG (0x5e, 0x85); - SETREG (0x6b, 0xb1); - SETREG (0x1e, 0xa0); - SETREG (0x72, 0x03); - SETREG (0x73, 0x04); - SETREG (0x7d, 0x20); - SETREG (0x80, 0x28); - SETREG (0x87, 0x02); /* MCLOCK -> CK4MAP */ - SETREG (0x9d, 0x08); /* STEPTIM=2 */ - } - - dev->calib_reg = dev->reg; - - DBGCOMPLETED; -} - -/* Send slope table for motor movement - slope_table in machine byte order - */ -static SANE_Status -gl843_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - char msg[10000]; - - DBG(DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, table_nr, steps); - - std::vector table(steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), "%d", slope_table[i]); - } - DBG(DBG_io, "%s: %s\n", __func__, msg); - } - - - /* slope table addresses are fixed : 0x4000, 0x4800, 0x5000, 0x5800, 0x6000 */ - /* XXX STEF XXX USB 1.1 ? sanei_genesys_write_0x8c (dev, 0x0f, 0x14); */ - status = write_data (dev, 0x4000 + 0x800 * table_nr, steps * 2, table.data()); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: write data failed writing slope table %d (%s)\n", __func__, table_nr, - sane_strstatus(status)); - } - - DBGCOMPLETED; - return status; -} - - -/* Set values of analog frontend */ -static SANE_Status -gl843_set_fe (Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) -{ - (void) sensor; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - int i; - - DBG(DBG_proc, "%s (%s)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?"); - - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - dev->frontend = dev->frontend_initial; - } - - /* check analog frontend type */ - // FIXME: looks like we write to that register with initial data - RIE (sanei_genesys_read_register (dev, REG04, &val)); - if ((val & REG04_FESET) != 0x00) - { - /* for now there is no support for AD fe */ - DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, - dev->reg.find_reg(0x04).value & REG04_FESET); - return SANE_STATUS_UNSUPPORTED; - } - - DBG(DBG_proc, "%s(): frontend reset complete\n", __func__); - - for (i = 1; i <= 3; i++) - { - // FIXME: BUG: we should initialize dev->frontend before first use. Right now it's - // initialized during genesys_coarse_calibration() - if (dev->frontend.regs.empty()) { - status = sanei_genesys_fe_write_data(dev, i, 0x00); - } else { - status = sanei_genesys_fe_write_data(dev, i, dev->frontend.regs.get_value(0x00 + i)); - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing reg[%d] failed: %s\n", __func__, i, sane_strstatus(status)); - return status; - } - } - for (const auto& reg : sensor.custom_fe_regs) { - status = sanei_genesys_fe_write_data(dev, reg.address, reg.value); - if (status != SANE_STATUS_GOOD) { - DBG(DBG_error, "%s: writing reg[%d] failed: %s\n", __func__, i, sane_strstatus(status)); - return status; - } - } - - for (i = 0; i < 3; i++) - { - // FIXME: BUG: see above - if (dev->frontend.regs.empty()) { - status = sanei_genesys_fe_write_data(dev, 0x20 + i, 0x00); - } else { - status = sanei_genesys_fe_write_data(dev, 0x20 + i, dev->frontend.get_offset(i)); - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing offset[%d] failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - - if (dev->model->ccd_type == CCD_KVSS080) - { - for (i = 0; i < 3; i++) - { - // FIXME: BUG: see above - if (dev->frontend.regs.empty()) { - status = sanei_genesys_fe_write_data(dev, 0x24 + i, 0x00); - } else { - status = sanei_genesys_fe_write_data(dev, 0x24 + i, - dev->frontend.regs.get_value(0x24 + i)); - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing sign[%d] failed: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - } - - for (i = 0; i < 3; i++) - { - // FIXME: BUG: see above - if (dev->frontend.regs.empty()) { - status = sanei_genesys_fe_write_data(dev, 0x28 + i, 0x00); - } else { - status = sanei_genesys_fe_write_data(dev, 0x28 + i, dev->frontend.get_gain(i)); - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: writing gain[%d] failed: %s\n", __func__, i, sane_strstatus(status)); - return status; - } - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl843_init_motor_regs_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int exposure, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - int scan_power_mode, - unsigned int flags) -{ - SANE_Status status = SANE_STATUS_GOOD; - int use_fast_fed, coeff; - unsigned int lincnt; - uint16_t scan_table[1024]; - uint16_t fast_table[1024]; - int scan_steps,fast_steps, fast_step_type; - unsigned int feedl,factor,dist; - GenesysRegister *r; - uint32_t z1, z2; - - DBGSTART; - DBG(DBG_info, "%s : exposure=%d, scan_yres=%g, scan_step_type=%d, scan_lines=%d, scan_dummy=%d, " - "feed_steps=%d, scan_power_mode=%d, flags=%x\n", __func__, exposure, scan_yres, - scan_step_type, scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); - - /* get step multiplier */ - factor = gl843_get_step_multiplier (reg); - - use_fast_fed = 0; - - if((scan_yres>=300 && feed_steps>900) || (flags & MOTOR_FLAG_FEED)) - use_fast_fed=1; - - lincnt=scan_lines; - sanei_genesys_set_triple(reg,REG_LINCNT,lincnt); - DBG(DBG_io, "%s: lincnt=%d\n", __func__, lincnt); - - /* compute register 02 value */ - r = sanei_genesys_get_address (reg, REG02); - r->value = 0x00; - sanei_genesys_set_motor_power(*reg, true); - - if (use_fast_fed) - r->value |= REG02_FASTFED; - else - r->value &= ~REG02_FASTFED; - - /* in case of automatic go home, move until home sensor */ - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= REG02_AGOHOME | REG02_NOTHOME; - - /* disable backtracking */ - if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - ||(scan_yres>=2400) - ||(scan_yres>=sensor.optical_res)) - r->value |= REG02_ACDCDIS; - - /* scan and backtracking slope table */ - sanei_genesys_slope_table(scan_table, - &scan_steps, - scan_yres, - exposure, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - gl843_motors); - RIE(gl843_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); - RIE(gl843_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); - - /* STEPNO */ - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = scan_steps; - - /* FSHDEC */ - r = sanei_genesys_get_address (reg, REG_FSHDEC); - r->value = scan_steps; - - /* fast table */ - fast_step_type=0; - if(scan_step_type<=fast_step_type) - { - fast_step_type=scan_step_type; - } - sanei_genesys_slope_table(fast_table, - &fast_steps, - sanei_genesys_get_lowest_ydpi(dev), - exposure, - dev->motor.base_ydpi, - fast_step_type, - factor, - dev->model->motor_type, - gl843_motors); - RIE(gl843_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); - RIE(gl843_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); - RIE(gl843_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); - - /* FASTNO */ - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = fast_steps; - - /* FMOVNO */ - r = sanei_genesys_get_address (reg, REG_FMOVNO); - r->value = fast_steps; - - /* substract acceleration distance from feedl */ - feedl=feed_steps; - feedl<<=scan_step_type; - - dist = scan_steps; - if (use_fast_fed) - { - dist += fast_steps*2; - } - DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); - - /* get sure when don't insane value : XXX STEF XXX in this case we should - * fall back to single table move */ - if(dist600) - { - z1=0; - z2=0; - } - - sanei_genesys_set_triple(reg,REG_Z1MOD,z1); - DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); - - sanei_genesys_set_triple(reg,REG_Z2MOD,z2); - DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); - - r = sanei_genesys_get_address (reg, REG1E); - r->value &= 0xf0; /* 0 dummy lines */ - r->value |= scan_dummy; /* dummy lines */ - - r = sanei_genesys_get_address (reg, REG67); - r->value = 0x3f | (scan_step_type << REG67S_STEPSEL); - - r = sanei_genesys_get_address (reg, REG68); - r->value = 0x3f | (scan_step_type << REG68S_FSTPSEL); - - /* steps for STOP table */ - r = sanei_genesys_get_address (reg, REG_FMOVDEC); - r->value = fast_steps; - - /* Vref XXX STEF XXX : optical divider or step type ? */ - r = sanei_genesys_get_address (reg, 0x80); - if (!(dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE)) - { - r->value = 0x50; - coeff=sensor.optical_res/sanei_genesys_compute_dpihw(dev, sensor, scan_yres); - if (dev->model->motor_type == MOTOR_KVSS080) - { - if(coeff>=1) - { - r->value |= 0x05; - } - } - else { - switch(coeff) - { - case 4: - r->value |= 0x0a; - break; - case 2: - r->value |= 0x0f; - break; - case 1: - r->value |= 0x0f; - break; - } - } - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** @brief setup optical related registers - * start and pixels are expressed in optical sensor resolution coordinate - * space. - * @param dev device to use - * @param reg registers to set up - * @param exposure exposure time to use - * @param used_res scanning resolution used, may differ from - * scan's one - * @param start logical start pixel coordinate - * @param pixels logical number of pixels to use - * @param channels number of color channles used (1 or 3) - * @param depth bit depth of the scan (1, 8 or 16 bits) - * @param ccd_size_divisor SANE_TRUE specifies how much x coordinates must be shrunk - * @param color_filter to choose the color channel used in gray scans - * @param flags to drive specific settings such no calibration, XPA use ... - * @return SANE_STATUS_GOOD if OK - */ -static SANE_Status -gl843_init_optical_regs_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int exposure, - int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - unsigned ccd_size_divisor, - ColorFilter color_filter, - int flags) -{ - unsigned int words_per_line; - unsigned int startx, endx, used_pixels; - unsigned int dpiset, dpihw, factor; - unsigned int bytes; - unsigned int tgtime; /**> exposure time multiplier */ - unsigned int cksel; /**> clock per system pixel time in capturing image */ - GenesysRegister *r; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s : exposure=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "ccd_size_divisor=%d, flags=%x\n", __func__, exposure, used_res, start, pixels, channels, - depth, ccd_size_divisor, flags); - - /* tgtime */ - tgtime = exposure / 65536 + 1; - DBG(DBG_io2, "%s: tgtime=%d\n", __func__, tgtime); - - /* to manage high resolution device while keeping good - * low resolution scanning speed, we make hardware dpi vary */ - dpihw=sanei_genesys_compute_dpihw(dev, sensor, used_res); - factor=sensor.optical_res/dpihw; - DBG(DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); - - /* sensor parameters */ - gl843_setup_sensor (dev, sensor, reg, dpihw, flags); - - /* resolution is divided according to CKSEL which is known once sensor is set up */ - r = sanei_genesys_get_address (reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - DBG(DBG_io2, "%s: cksel=%d\n", __func__, cksel); - dpiset = used_res * cksel; - - /* start and end coordinate in optical dpi coordinates */ - startx = (start + sensor.dummy_pixel)/cksel; - - used_pixels=pixels/cksel; - endx = startx + used_pixels; - - /* pixel coordinate factor correction when used dpihw is not maximal one */ - startx/=factor; - endx/=factor; - used_pixels=endx-startx; - - /* in case of stagger we have to start at an odd coordinate */ - if ((flags & OPTICAL_FLAG_STAGGER) - &&((startx & 1)==0)) - { - startx++; - endx++; - } - - status = gl843_set_fe(dev, sensor, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, REG01); - r->value &= ~REG01_SCAN; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - r->value &= ~REG01_DVDSET; - } - else - { - r->value |= REG01_DVDSET; - } - if(dpihw>600) - { - r->value |= REG01_SHDAREA; - } - else - { - r->value &= ~REG01_SHDAREA; - } - - r = sanei_genesys_get_address (reg, REG03); - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - r->value |= REG03_AVEENB; - else { - r->value &= ~REG03_AVEENB; - } - - // FIXME: we probably don't need to set exposure to registers at this point. It was this way - // before a refactor. - sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); - - /* select XPA */ - r->value &= ~REG03_XPASEL; - if (flags & OPTICAL_FLAG_USE_XPA) - { - r->value |= REG03_XPASEL; - } - reg->state.is_xpa_on = flags & OPTICAL_FLAG_USE_XPA; - - /* BW threshold */ - r = sanei_genesys_get_address (reg, REG2E); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, REG2F); - r->value = dev->settings.threshold; - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, REG04); - switch (depth) - { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - r->value &= ~(REG04_FILTER | REG04_AFEMOD); - if (channels == 1) - { - switch (color_filter) - { - case ColorFilter::RED: - r->value |= 0x14; - break; - case ColorFilter::BLUE: - r->value |= 0x1c; - break; - case ColorFilter::GREEN: - r->value |= 0x18; - break; - default: - break; // should not happen - } - } - else - r->value |= 0x10; /* mono */ - - /* register 05 */ - r = sanei_genesys_get_address (reg, REG05); - - /* set up dpihw */ - r->value &= ~REG05_DPIHW; - switch(dpihw) - { - case 600: - r->value |= REG05_DPIHW_600; - break; - case 1200: - r->value |= REG05_DPIHW_1200; - break; - case 2400: - r->value |= REG05_DPIHW_2400; - break; - case 4800: - r->value |= REG05_DPIHW_4800; - break; - } - - /* enable gamma tables */ - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - sanei_genesys_set_double(reg, REG_DPISET, dpiset * ccd_size_divisor); - DBG(DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset * ccd_size_divisor); - - sanei_genesys_set_double(reg, REG_STRPIXEL, startx); - sanei_genesys_set_double(reg, REG_ENDPIXEL, endx); - - /* words(16bit) before gamma, conversion to 8 bit or lineart */ - words_per_line = (used_pixels * dpiset) / dpihw; - bytes = depth / 8; - if (depth == 1) - { - words_per_line = (words_per_line >> 3) + ((words_per_line & 7) ? 1 : 0); - } - else - { - words_per_line *= bytes; - } - - dev->wpl = words_per_line; - dev->bpl = words_per_line; - - DBG(DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); - DBG(DBG_io2, "%s: pixels =%d\n", __func__, pixels); - DBG(DBG_io2, "%s: depth =%d\n", __func__, depth); - DBG(DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long) dev->bpl); - DBG(DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); - DBG(DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); - - words_per_line *= channels; - - /* MAXWD is expressed in 2 words unit */ - /* nousedspace = (mem_bank_range * 1024 / 256 -1 ) * 4; */ - sanei_genesys_set_triple(reg,REG_MAXWD,(words_per_line)>>1); - DBG(DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); - - sanei_genesys_set_double(reg,REG_LPERIOD,exposure/tgtime); - DBG(DBG_io2, "%s: exposure used=%d\n", __func__, exposure/tgtime); - - r = sanei_genesys_get_address (reg, REG_DUMMY); - r->value = sensor.dummy_pixel; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -struct ScanSession { - SetupParams params; - - // whether the session setup has been computed via gl843_compute_session() - bool computed = false; - - // whether CCD operates as half-resolution or full resolution at a specific resolution - unsigned ccd_size_divisor = 1; - - // the optical resolution of the scanner. - unsigned optical_resolution = 0; - - // the number of pixels at the optical resolution. - unsigned optical_pixels = 0; - - // the number of bytes in the output of a single line directly from scanner - unsigned optical_line_bytes = 0; - - // the resolution of the output data. - unsigned output_resolution = 0; - - // the number of pixels in output data - unsigned output_pixels = 0; - - // the number of bytes in the output of a single line - unsigned output_line_bytes = 0; - - // the number of lines in the output of the scanner. This must be larger than the user - // requested number due to line staggering and color channel shifting. - unsigned output_line_count = 0; - - // the number of staggered lines (i.e. lines that overlap during scanning due to line being - // thinner than the CCD element) - unsigned num_staggered_lines = 0; - - // the number of lines that color channels shift due to different physical positions of - // different color channels - unsigned max_color_shift_lines = 0; - - void assert_computed() const - { - if (!computed) { - throw std::runtime_error("ScanSession is not computed"); - } - } -}; - -static unsigned align_int_up(unsigned num, unsigned alignment) -{ - unsigned mask = alignment - 1; - if (num & mask) - num = (num & ~mask) + alignment; - return num; -} - -// computes physical parameters for specific scan setup -static void gl843_compute_session(Genesys_Device* dev, ScanSession& s, - const Genesys_Sensor& sensor) -{ - s.params.assert_valid(); - s.ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(s.params.xres); - - s.optical_resolution = sensor.optical_res / s.ccd_size_divisor; - - if (s.params.flags & SCAN_FLAG_USE_OPTICAL_RES) { - s.output_resolution = s.optical_resolution; - } else { - // resolution is choosen from a fixed list and can be used directly - // unless we have ydpi higher than sensor's maximum one - if (s.params.xres > s.optical_resolution) - s.output_resolution = s.optical_resolution; - else - s.output_resolution = s.params.xres; - } - - // compute rounded up number of optical pixels - s.optical_pixels = (s.params.pixels * s.optical_resolution) / s.params.xres; - if (s.optical_pixels * s.params.xres < s.params.pixels * s.optical_resolution) - s.optical_pixels++; - - // ensure the number of optical pixels is divisible by 2. - // In quarter-CCD mode optical_pixels is 4x larger than the actual physical number - s.optical_pixels = align_int_up(s.optical_pixels, 2 * s.ccd_size_divisor); - - s.output_pixels = - (s.optical_pixels * s.output_resolution) / s.optical_resolution; - - // Note: staggering is not applied for calibration. Staggering starts at 2400 dpi - s.num_staggered_lines = 0; - if ((s.params.yres > 1200) && - ((s.params.flags & SCAN_FLAG_IGNORE_LINE_DISTANCE) == 0) && - (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - { - s.num_staggered_lines = (4 * s.params.yres) / dev->motor.base_ydpi; - } - - s.max_color_shift_lines = sanei_genesys_compute_max_shift(dev, s.params.channels, - s.params.yres, s.params.flags); - - s.output_line_count = s.params.lines + s.max_color_shift_lines + s.num_staggered_lines; - - s.optical_line_bytes = (s.optical_pixels * s.params.channels * s.params.depth) / 8; - s.output_line_bytes = (s.output_pixels * s.params.channels * s.params.depth) / 8; - s.computed = true; -} - -/* set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -static SANE_Status gl843_init_scan_regs(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set* reg, - ScanSession& session) -{ - session.assert_computed(); - - int start; - int move; - unsigned int oflags, mflags; /**> optical and motor flags */ - int exposure; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int scan_power_mode = 0; - size_t requested_buffer_size, read_buffer_size; - - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, session.params); - - DBG(DBG_info, "%s : stagger=%d lines\n", __func__, session.num_staggered_lines); - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - oflags = 0; - if (session.params.flags & SCAN_FLAG_DISABLE_SHADING) - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - if (session.params.flags & SCAN_FLAG_DISABLE_GAMMA) - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - if (session.params.flags & SCAN_FLAG_DISABLE_LAMP) - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - if (session.params.flags & SCAN_FLAG_CALIBRATION) - oflags |= OPTICAL_FLAG_DISABLE_DOUBLE; - if (session.num_staggered_lines) - oflags |= OPTICAL_FLAG_STAGGER; - if (session.params.flags & SCAN_FLAG_USE_XPA) - oflags |= OPTICAL_FLAG_USE_XPA; - - - /* compute scan parameters values */ - /* pixels are allways given at full optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - start = session.params.startx; - - dummy = 0; - /* dummy = 1; XXX STEF XXX */ - - /* slope_dpi */ - /* cis color scan is effectively a gray scan with 3 gray lines per color line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = session.params.yres * session.params.channels; - else - slope_dpi = session.params.yres; - slope_dpi = slope_dpi * (1 + dummy); - - /* scan_step_type */ - exposure = sensor.exposure_lperiod; - if (exposure < 0) { - throw std::runtime_error("Exposure not defined in sensor definition"); - } - scan_step_type = sanei_genesys_compute_step_type(gl843_motors, dev->model->motor_type, exposure); - - DBG(DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); - DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); - - /*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if (session.params.flags & SCAN_FLAG_DYNAMIC_LINEART) { - session.params.depth = 8; - } - - /* no 16 bit gamma for this ASIC */ - if (session.params.depth == 16) - { - session.params.flags |= SCAN_FLAG_DISABLE_GAMMA; - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - } - - /* now _LOGICAL_ optical values used are known, setup registers */ - status = gl843_init_optical_regs_scan (dev, sensor, - reg, - exposure, - session.output_resolution, - start, - session.optical_pixels, - session.params.channels, - session.params.depth, - session.ccd_size_divisor, - session.params.color_filter, - oflags); - if (status != SANE_STATUS_GOOD) - return status; - - /*** motor parameters ***/ - - /* it seems base_dpi of the G4050 motor is changed above 600 dpi*/ - if (dev->model->motor_type == MOTOR_G4050 && session.params.yres>600) - { - dev->ld_shift_r = (dev->model->ld_shift_r*3800)/dev->motor.base_ydpi; - dev->ld_shift_g = (dev->model->ld_shift_g*3800)/dev->motor.base_ydpi; - dev->ld_shift_b = (dev->model->ld_shift_b*3800)/dev->motor.base_ydpi; - } - else - { - dev->ld_shift_r = dev->model->ld_shift_r; - dev->ld_shift_g = dev->model->ld_shift_g; - dev->ld_shift_b = dev->model->ld_shift_b; - } - - /* add tl_y to base movement */ - move = session.params.starty; - DBG(DBG_info, "%s: move=%d steps\n", __func__, move); - - - mflags=0; - if(session.params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) - mflags|=MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; - if(session.params.flags & SCAN_FLAG_FEEDING) - mflags|=MOTOR_FLAG_FEED; - if (session.params.flags & SCAN_FLAG_USE_XPA) - mflags |= MOTOR_FLAG_USE_XPA; - - status = gl843_init_motor_regs_scan (dev, sensor, - reg, - exposure, - slope_dpi, - scan_step_type, - dev->model->is_cis ? session.output_line_count * session.params.channels - : session.output_line_count, - dummy, - move, - scan_power_mode, - mflags); - if (status != SANE_STATUS_GOOD) - return status; - - /* since we don't have sheetfed scanners to handle, - * use huge read buffer */ - /* TODO find the best size according to settings */ - requested_buffer_size = 16 * session.output_line_bytes; - - read_buffer_size = - 2 * requested_buffer_size + - (session.max_color_shift_lines + session.num_staggered_lines) * session.optical_line_bytes; - - dev->read_buffer.clear(); - dev->read_buffer.alloc(read_buffer_size); - - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(read_buffer_size); - - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(requested_buffer_size); - - dev->out_buffer.clear(); - dev->out_buffer.alloc((8 * session.params.pixels * session.params.channels * - session.params.depth) / 8); - - dev->read_bytes_left = session.output_line_bytes * session.output_line_count; - - DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - dev->current_setup.params = session.params; - dev->current_setup.pixels = session.output_pixels; - DBG(DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); - dev->current_setup.lines = session.output_line_count; - dev->current_setup.depth = session.params.depth; - dev->current_setup.channels = session.params.channels; - dev->current_setup.exposure_time = exposure; - dev->current_setup.xres = session.output_resolution; - dev->current_setup.yres = session.params.yres; - dev->current_setup.ccd_size_divisor = session.ccd_size_divisor; - dev->current_setup.stagger = session.num_staggered_lines; - dev->current_setup.max_shift = session.max_color_shift_lines + session.num_staggered_lines; - - dev->total_bytes_read = 0; - if (session.params.depth == 1) { - dev->total_bytes_to_read = ((session.params.pixels * session.params.lines) / 8 + - (((session.params.pixels * session.params.lines) % 8) ? 1 : 0)) * - session.params.channels; - } else { - dev->total_bytes_to_read = session.params.pixels * session.params.lines * - session.params.channels * (session.params.depth / 8); - } - - DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); - - DBG(DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} - -static void -gl843_calculate_current_setup(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int depth; - int start; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure; - int stagger; - - int max_shift; - - int optical_res; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - unsigned ccd_size_divisor = sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); - - /* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - /* start */ - if(dev->settings.scan_method==ScanMethod::TRANSPARENCY) - start = SANE_UNFIX (dev->model->x_offset_ta); - else - start = SANE_UNFIX (dev->model->x_offset); - - start /= ccd_size_divisor; - - start += dev->settings.tl_x; - start = (start * sensor.optical_res) / MM_PER_INCH; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; // not used - params.starty = 0; // not used - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = 0; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - - /* optical_res */ - optical_res = sensor.optical_res / ccd_size_divisor; - - /* stagger */ - if (ccd_size_divisor == 1 && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG(DBG_info, "%s: stagger=%d lines\n", __func__, stagger); - - if (params.xres <= (unsigned) optical_res) { - used_res = params.xres; - } else { - used_res = optical_res; - } - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - - /* compute correct pixels number */ - used_pixels = (params.pixels * optical_res) / params.xres; - DBG(DBG_info, "%s: used_pixels=%d\n", __func__, used_pixels); - - /* exposure */ - exposure = sensor.exposure_lperiod; - if (exposure < 0) { - throw std::runtime_error("Exposure not defined in sensor definition"); - } - DBG(DBG_info, "%s : exposure=%d pixels\n", __func__, exposure); - - /* it seems base_dpi of the G4050 motor is changed above 600 dpi*/ - if (dev->model->motor_type == MOTOR_G4050 && params.yres>600) - { - dev->ld_shift_r = (dev->model->ld_shift_r*3800)/dev->motor.base_ydpi; - dev->ld_shift_g = (dev->model->ld_shift_g*3800)/dev->motor.base_ydpi; - dev->ld_shift_b = (dev->model->ld_shift_b*3800)/dev->motor.base_ydpi; - } - else - { - dev->ld_shift_r = dev->model->ld_shift_r; - dev->ld_shift_g = dev->model->ld_shift_g; - dev->ld_shift_b = dev->model->ld_shift_b; - } - - /* scanned area must be enlarged by max color shift needed */ - max_shift = sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); - - /* lincnt */ - lincnt = params.lines + max_shift + stagger; - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - DBG(DBG_info, "%s: current_setup.pixels=%d\n", __func__, dev->current_setup.pixels); - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = ccd_size_divisor; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBG(DBG_proc, "%s: completed\n", __func__); -} - -/** - * for fast power saving methods only, like disabling certain amplifiers - * @param dev device to use - * @param enable true to set inot powersaving - * */ -static SANE_Status -gl843_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - uint8_t val; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); - if (dev == NULL) - return SANE_STATUS_INVAL; - - /* switch KV-SS080 lamp off */ - if (dev->model->gpo_type == GPO_KVSS080) - { - RIE(sanei_genesys_read_register (dev, REG6C, &val)); - if(enable) - val &= 0xef; - else - val |= 0x10; - RIE(sanei_genesys_write_register(dev,REG6C,val)); - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl843_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl843_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -static SANE_Status -gl843_stop_action_no_move(Genesys_Device* dev, Genesys_Register_Set* reg) -{ - uint8_t val = sanei_genesys_read_reg_from_set(reg, REG01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set(reg, REG01, val); - SANE_Status ret = sanei_genesys_write_register(dev, REG01, val); - sanei_genesys_sleep_ms(100); - return ret; -} - -static SANE_Status -gl843_stop_action (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val40, val; - unsigned int loop; - - DBG(DBG_proc, "%s\n", __func__); - - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - val40 = 0; - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - DBG(DBG_proc, "%s: completed\n", __func__); - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBG(DBG_info, "%s: already stopped\n", __func__); - DBG(DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; - } - - /* ends scan 646 */ - val = dev->reg.get8(REG01); - val &= ~REG01_SCAN; - dev->reg.set8(REG01, val); - status = sanei_genesys_write_register (dev, REG01, val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_sleep_ms(100); - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - val40 = 0; - status = sanei_genesys_read_register (dev, 0x40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) - && !(val & REG41_MOTORENB)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - sanei_genesys_sleep_ms(100); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - -static SANE_Status -gl843_get_paper_sensor (Genesys_Device * dev, SANE_Bool * paper_loaded) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - status = sanei_genesys_read_register (dev, REG6D, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read gpio: %s\n", __func__, sane_strstatus(status)); - return status; - } - *paper_loaded = (val & 0x1) == 0; - return SANE_STATUS_GOOD; - - return SANE_STATUS_INVAL; -} - -static SANE_Status -gl843_eject_document (Genesys_Device * dev) -{ - DBG(DBG_proc, "%s: not implemented \n", __func__); - if (dev == NULL) - return SANE_STATUS_INVAL; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -gl843_load_document (Genesys_Device * dev) -{ - DBG(DBG_proc, "%s: not implemented \n", __func__); - if (dev == NULL) - return SANE_STATUS_INVAL; - return SANE_STATUS_GOOD; -} - -/** - * detects end of document and adjust current scan - * to take it into account - * used by sheetfed scanners - */ -static SANE_Status -gl843_detect_document_end (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - SANE_Bool paper_loaded; - unsigned int scancnt = 0; - int flines, channels, depth, bytes_remain, sublines, - bytes_to_flush, lines, sub_bytes, tmp, read_bytes_left; - DBG(DBG_proc, "%s: begin\n", __func__); - - RIE (gl843_get_paper_sensor (dev, &paper_loaded)); - - /* sheetfed scanner uses home sensor as paper present */ - if ((dev->document == SANE_TRUE) && !paper_loaded) - { - DBG(DBG_info, "%s: no more document\n", __func__); - dev->document = SANE_FALSE; - - channels = dev->current_setup.channels; - depth = dev->current_setup.depth; - read_bytes_left = (int) dev->read_bytes_left; - DBG(DBG_io, "%s: read_bytes_left=%d\n", __func__, read_bytes_left); - - /* get lines read */ - try { - status = sanei_genesys_read_scancnt(dev, &scancnt); - } catch (...) { - flines = 0; - } - if (status != SANE_STATUS_GOOD) - { - flines = 0; - } - else - { - /* compute number of line read */ - tmp = (int) dev->total_bytes_read; - if (depth == 1 || dev->settings.scan_mode == ScanColorMode::LINEART) - flines = tmp * 8 / dev->settings.pixels / channels; - else - flines = tmp / (depth / 8) / dev->settings.pixels / channels; - - /* number of scanned lines, but no read yet */ - flines = scancnt - flines; - - DBG(DBG_io, "%s: %d scanned but not read lines\n", __func__, flines); - } - - /* adjust number of bytes to read - * we need to read the final bytes which are word per line * number of last lines - * to have doc leaving feeder */ - lines = - (SANE_UNFIX (dev->model->post_scan) * dev->current_setup.yres) / - MM_PER_INCH + flines; - DBG(DBG_io, "%s: adding %d line to flush\n", __func__, lines); - - /* number of bytes to read from scanner to get document out of it after - * end of document dectected by hardware sensor */ - bytes_to_flush = lines * dev->wpl; - - /* if we are already close to end of scan, flushing isn't needed */ - if (bytes_to_flush < read_bytes_left) - { - /* we take all these step to work around an overflow on some plateforms */ - tmp = (int) dev->total_bytes_read; - DBG (DBG_io, "%s: tmp=%d\n", __func__, tmp); - bytes_remain = (int) dev->total_bytes_to_read; - DBG(DBG_io, "%s: bytes_remain=%d\n", __func__, bytes_remain); - bytes_remain = bytes_remain - tmp; - DBG(DBG_io, "%s: bytes_remain=%d\n", __func__, bytes_remain); - - /* remaining lines to read by frontend for the current scan */ - if (depth == 1 || dev->settings.scan_mode == ScanColorMode::LINEART) - { - flines = bytes_remain * 8 / dev->settings.pixels / channels; - } - else - flines = bytes_remain / (depth / 8) - / dev->settings.pixels / channels; - DBG(DBG_io, "%s: flines=%d\n", __func__, flines); - - if (flines > lines) - { - /* change the value controlling communication with the frontend : - * total bytes to read is current value plus the number of remaining lines - * multiplied by bytes per line */ - sublines = flines - lines; - - if (depth == 1 || dev->settings.scan_mode == ScanColorMode::LINEART) - sub_bytes = - ((dev->settings.pixels * sublines) / 8 + - (((dev->settings.pixels * sublines) % 8) ? 1 : 0)) * - channels; - else - sub_bytes = - dev->settings.pixels * sublines * channels * (depth / 8); - - dev->total_bytes_to_read -= sub_bytes; - - /* then adjust the physical bytes to read */ - if (read_bytes_left > sub_bytes) - { - dev->read_bytes_left -= sub_bytes; - } - else - { - dev->total_bytes_to_read = dev->total_bytes_read; - dev->read_bytes_left = 0; - } - - DBG(DBG_io, "%s: sublines=%d\n", __func__, sublines); - DBG(DBG_io, "%s: subbytes=%d\n", __func__, sub_bytes); - DBG(DBG_io, "%s: total_bytes_to_read=%lu\n", __func__, - (unsigned long) dev->total_bytes_to_read); - DBG(DBG_io, "%s: read_bytes_left=%d\n", __func__, read_bytes_left); - } - } - else - { - DBG(DBG_io, "%s: no flushing needed\n", __func__); - } - } - - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - -// enables or disables XPA slider motor -static SANE_Status gl843_set_xpa_motor_power(Genesys_Device *dev, bool set) -{ - uint8_t val; - SANE_Status status=SANE_STATUS_GOOD; - - DBGSTART; - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) { - - if (set) { - RIE(sanei_genesys_read_register(dev, REG6C, &val)); - val &= ~REG6C_GPIO14; - if (dev->current_setup.xres >= 2400) { - val |= REG6C_GPIO10; - } - RIE(sanei_genesys_write_register(dev, REG6C, val)); - - RIE(sanei_genesys_read_register(dev, REGA6, &val)); - val |= REGA6_GPIO17; - RIE(sanei_genesys_write_register(dev, REGA6,val)); - } else { - RIE(sanei_genesys_read_register(dev, REG6C, &val)); - val |= REG6C_GPIO14; - val &= ~REG6C_GPIO10; - RIE(sanei_genesys_write_register(dev, REG6C, val)); - - RIE(sanei_genesys_read_register(dev, REGA6, &val)); - val &= ~REGA6_GPIO17; - RIE(sanei_genesys_write_register(dev, REGA6,val)); - } - DBGCOMPLETED; - return status; - } - - if (dev->model->model_id == MODEL_HP_SCANJET_G4050) { - - if (set) { - /* set MULTFILM et GPOADF */ - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - val |=REG6B_MULTFILM|REG6B_GPOADF; - RIE (sanei_genesys_write_register (dev, REG6B, val)); - - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val &= ~REG6C_GPIO15; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - - /* Motor power ? No move at all without this one */ - RIE (sanei_genesys_read_register (dev, REGA6, &val)); - val |= REGA6_GPIO20; - RIE (sanei_genesys_write_register(dev,REGA6,val)); - - RIE (sanei_genesys_read_register (dev, REGA8, &val)); - val &= ~REGA8_GPO27; - RIE (sanei_genesys_write_register (dev, REGA8, val)); - - RIE (sanei_genesys_read_register (dev, REGA9, &val)); - val |= REGA9_GPO32|REGA9_GPO31; - RIE (sanei_genesys_write_register (dev, REGA9, val)); - } else { - /* unset GPOADF */ - RIE (sanei_genesys_read_register (dev, REG6B, &val)); - val &= ~REG6B_GPOADF; - RIE (sanei_genesys_write_register (dev, REG6B, val)); - - RIE (sanei_genesys_read_register (dev, REGA8, &val)); - val |= REGA8_GPO27; - RIE (sanei_genesys_write_register (dev, REGA8, val)); - - RIE (sanei_genesys_read_register (dev, REGA9, &val)); - val &= ~REGA9_GPO31; - RIE (sanei_genesys_write_register (dev, REGA9, val)); - } - DBGCOMPLETED; - return status; - } - - DBGCOMPLETED; - return status; -} - - -/** @brief light XPA lamp - * toggle gpios to switch off regular lamp and light on the - * XPA light - * @param dev device to set up - */ -static SANE_Status gl843_set_xpa_lamp_power(Genesys_Device *dev, bool set) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val = 0; - DBGSTART; - - if (set) { - RIE(sanei_genesys_read_register(dev, REGA6, &val)); - - // cut regular lamp power - val &= ~(REGA6_GPIO24 | REGA6_GPIO23); - - // set XPA lamp power - val |= REGA6_GPIO22 | REGA6_GPIO21 | REGA6_GPIO19; - - RIE(sanei_genesys_write_register(dev, REGA6, val)); - - RIE(sanei_genesys_read_register(dev, REGA7, &val)); - val|=REGA7_GPOE24; /* lamp 1 off GPOE 24 */ - val|=REGA7_GPOE23; /* lamp 2 off GPOE 23 */ - val|=REGA7_GPOE22; /* full XPA lamp power */ - RIE(sanei_genesys_write_register(dev, REGA7, val)); - } else { - RIE(sanei_genesys_read_register(dev, REGA6, &val)); - - // switch on regular lamp - val |= REGA6_GPIO23; - - // no XPA lamp power (2 bits for level: __11 ____) - val &= ~(REGA6_GPIO22 | REGA6_GPIO21); - - RIE(sanei_genesys_write_register(dev, REGA6, val)); - } - - DBGCOMPLETED; - return status; -} - -/* Send the low-level scan command */ -static SANE_Status -gl843_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - uint16_t dpiset, dpihw; - - DBGSTART; - - /* get back the target dpihw */ - sanei_genesys_get_double (reg, REG_DPISET, &dpiset); - dpihw = sanei_genesys_compute_dpihw(dev, sensor, dpiset); - - /* set up GPIO for scan */ - switch(dev->model->gpo_type) - { - /* KV case */ - case GPO_KVSS080: - RIE (sanei_genesys_write_register (dev, REGA9, 0x00)); - RIE (sanei_genesys_write_register (dev, REGA6, 0xf6)); - /* blinking led */ - RIE (sanei_genesys_write_register (dev, 0x7e, 0x04)); - break; - case GPO_G4050: - RIE (sanei_genesys_write_register (dev, REGA7, 0xfe)); - RIE (sanei_genesys_write_register (dev, REGA8, 0x3e)); - RIE (sanei_genesys_write_register (dev, REGA9, 0x06)); - switch (dpihw) - { - case 1200: - case 2400: - case 4800: - RIE (sanei_genesys_write_register (dev, REG6C, 0x60)); - RIE (sanei_genesys_write_register (dev, REGA6, 0x46)); - break; - default: /* 600 dpi case */ - RIE (sanei_genesys_write_register (dev, REG6C, 0x20)); - RIE (sanei_genesys_write_register (dev, REGA6, 0x44)); - } - - if (reg->state.is_xpa_on && reg->state.is_lamp_on) { - RIE(gl843_set_xpa_lamp_power(dev, true)); - } - - if (reg->state.is_xpa_on) { - dev->needs_home_ta = SANE_TRUE; - RIE(gl843_set_xpa_motor_power(dev, true)); - } - - /* blinking led */ - RIE (sanei_genesys_write_register (dev, REG7E, 0x01)); - break; - case GPO_CS8600F: - if (reg->state.is_xpa_on) { - dev->needs_home_ta = SANE_TRUE; - RIE(gl843_set_xpa_motor_power(dev, true)); - } - break; - case GPO_CS4400F: - case GPO_CS8400F: - default: - break; - } - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register - (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* enable scan and motor */ - RIE (sanei_genesys_read_register (dev, REG01, &val)); - val |= REG01_SCAN; - RIE (sanei_genesys_write_register (dev, REG01, val)); - - if (start_motor) - { - RIE (sanei_genesys_write_register (dev, REG0F, 1)); - } - else - { - RIE (sanei_genesys_write_register (dev, REG0F, 0)); - } - - DBGCOMPLETED; - return status; -} - - -/* Send the stop scan command */ -static SANE_Status -gl843_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); - if (reg == NULL) - return SANE_STATUS_INVAL; - - /* post scan gpio */ - RIE(sanei_genesys_write_register(dev,0x7e,0x00)); - - // turn off XPA lamp if needed - // BUG: the if condition below probably shouldn't be enabled when XPA is off - if (reg->state.is_xpa_on || reg->state.is_lamp_on) { - gl843_set_xpa_lamp_power(dev, false); - } - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl843_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -/** @brief park XPA lamp - * park the XPA lamp if needed - */ -static SANE_Status gl843_park_xpa_lamp (Genesys_Device * dev) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - uint8_t val; - int loop = 0; - - DBGSTART; - - /* copy scan settings */ - local_reg = dev->reg; - - /* set a huge feedl and reverse direction */ - sanei_genesys_set_triple(&local_reg,REG_FEEDL,0xbdcd); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse and no scan */ - r = sanei_genesys_get_address (&local_reg, REG02); - r->value |= REG02_MTRREV; - r = sanei_genesys_get_address (&local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* write to scanner and start action */ - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - RIE(gl843_set_xpa_motor_power(dev, true)); - try { - status = gl843_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl843_stop_action(dev); - } catch (...) {} - try { - // restore original registers - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl843_stop_action (dev); - /* restore original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - while (loop < 600) /* do not wait longer then 60 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io2) - { - sanei_genesys_print_status (val); - } - - if (val & REG41_HOMESNR) /* home sensor */ - { - DBG(DBG_info, "%s: reached home position\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - - gl843_set_xpa_motor_power(dev, false); - dev->needs_home_ta = SANE_FALSE; - - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - ++loop; - } - - /* we are not parked here.... should we fail ? */ - DBG(DBG_info, "%s: XPA lamp is not parked\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief Moves the slider to the home (top) position slowly - * */ -static SANE_Status -gl843_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - uint8_t val; - float resolution; - int loop = 0; - - DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); - - if (dev->needs_home_ta) { - RIE(gl843_park_xpa_lamp(dev)); - } - - /* regular slow back home */ - dev->scanhead_position_in_steps = 0; - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_sleep_ms(100); - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - if (val & HOMESNR) /* is sensor at home? */ - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - local_reg = dev->reg; - resolution=sanei_genesys_get_lowest_ydpi(dev); - - const auto& sensor = sanei_genesys_find_sensor(dev, resolution); - - ScanSession session; - session.params.xres = resolution; - session.params.yres = resolution; - session.params.startx = 100; - session.params.starty = 40000; - session.params.pixels = 100; - session.params.lines = 100; - session.params.depth = 8; - session.params.channels = 1; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::LINEART; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - gl843_compute_session(dev, session, sensor); - - status = gl843_init_scan_regs(dev, sensor, &local_reg, session); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse and no scan */ - r = sanei_genesys_get_address(&local_reg, REG02); - r->value |= REG02_MTRREV; - r = sanei_genesys_get_address(&local_reg, REG01); - r->value &= ~REG01_SCAN; - - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - - try { - status = gl843_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl843_stop_action(dev); - } catch (...) {} - try { - // restore original registers - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl843_stop_action (dev); - /* restore original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - if (wait_until_home) - { - - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io2) - { - sanei_genesys_print_status (val); - } - - if (val & REG41_HOMESNR) /* home sensor */ - { - DBG(DBG_info, "%s: reached home position\n", __func__); - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl843_stop_action (dev); - DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - DBG(DBG_info, "%s: scanhead is still moving\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl843_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg; - int steps; - - int pixels = 600; - int dpi = 300; - - DBG(DBG_proc, "%s\n", __func__); - - local_reg = dev->reg; - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - // FIXME: the current approach of doing search only for one resolution does not work on scanners - // whith employ different sensors with potentially different settings. - auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); - - ScanSession session; - session.params.xres = dpi; - session.params.yres = dpi; - session.params.startx = 0; - session.params.starty = 0; // we should give a small offset here - ~60 steps - session.params.pixels = 600; - session.params.lines = dev->model->search_lines; - session.params.depth = 8; - session.params.channels = 1; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::GRAY; - session.params.color_filter = ColorFilter::GREEN; - session.params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; - gl843_compute_session(dev, session, sensor); - - status = gl843_init_scan_regs(dev, sensor, &local_reg, session); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk setup registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* send to scanner */ - status = dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - size = dev->read_bytes_left; - - std::vector data(size); - - status = gl843_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - RIE(gl843_stop_action_no_move(dev, &local_reg)); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl843_search_position.pnm", data.data(), 8, 1, pixels, - dev->model->search_lines); - - status = gl843_end_scan(dev, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* update regs to copy ASIC internal state */ - dev->reg = local_reg; - - status = - sanei_genesys_search_reference_point (dev, sensor, data.data(), 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl843_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t channels; - uint8_t cksel; - - DBGSTART; - cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - int flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) { - flags |= SCAN_FLAG_USE_XPA; - } - - ScanSession session; - session.params.xres = dev->settings.xres; - session.params.yres = dev->settings.yres; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = sensor.optical_res / cksel; // XXX STEF XXX dpi instead of pixels! - session.params.lines = 20; - session.params.depth = 16; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = dev->settings.scan_mode; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = flags; - gl843_compute_session(dev, session, sensor); - - status = gl843_init_scan_regs(dev, sensor, ®s, session); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_set_motor_power(regs, false); - - DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, - sensor.optical_res / cksel, dev->settings.xres); - - status = dev->model->cmd_set->bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move - * */ -static SANE_Status -gl843_feed (Genesys_Device * dev, unsigned int steps) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - float resolution; - uint8_t val; - - DBGSTART; - - /* prepare local registers */ - local_reg = dev->reg; - - resolution=sanei_genesys_get_lowest_ydpi(dev); - - const auto& sensor = sanei_genesys_find_sensor(dev, resolution); - - ScanSession session; - session.params.xres = resolution; - session.params.yres = resolution; - session.params.startx = 0; - session.params.starty = steps; - session.params.pixels = 100; - session.params.lines = 3; - session.params.depth = 8; - session.params.channels = 3; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = ColorFilter::RED; - session.params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_FEEDING | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - gl843_compute_session(dev, session, sensor); - - status = gl843_init_scan_regs(dev, sensor, &local_reg, session); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); - - /* set up for no scan */ - r = sanei_genesys_get_address(&local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* send registers */ - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - - try { - status = gl843_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl843_stop_action(dev); - } catch (...) {} - try { - // restore original registers - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl843_stop_action (dev); - - /* restore original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - /* wait until feed count reaches the required value, but do not - * exceed 30s */ - do - { - status = sanei_genesys_get_status (dev, &val); - } - while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); - - // looks like the scanner locks up if we scan immediately after feeding - sanei_genesys_sleep_ms(100); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status gl843_move_to_ta (Genesys_Device * dev); - -/* init registers for shading calibration */ -/* shading calibration is done at dpihw */ -static SANE_Status -gl843_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - int move, resolution, dpihw, factor; - uint16_t strpixel; - - DBGSTART; - - /* initial calibration reg values */ - regs = dev->reg; - - dev->calib_channels = 3; - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) - dev->calib_lines = dev->model->shading_ta_lines; - else - dev->calib_lines = dev->model->shading_lines; - dpihw = sanei_genesys_compute_dpihw_calibration(dev, sensor, dev->settings.xres); - factor=sensor.optical_res/dpihw; - resolution=dpihw; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, - dev->settings.scan_method); - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY && - dev->model->model_id == MODEL_CANON_CANOSCAN_8600F && - dev->settings.xres == 4800) - { - float offset = SANE_UNFIX(dev->model->x_offset_ta); - offset /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); - offset = (offset * calib_sensor.optical_res) / MM_PER_INCH; - - unsigned size = SANE_UNFIX(dev->model->x_size_ta); - size /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); - size = (size * calib_sensor.optical_res) / MM_PER_INCH; - - dev->calib_pixels_offset = offset; - dev->calib_pixels = size; - } - else - { - dev->calib_pixels_offset = 0; - dev->calib_pixels = calib_sensor.sensor_pixels / factor; - } - - dev->calib_resolution = resolution; - - int flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) - { - // note: move_to_ta() function has already been called and the sensor is at the - // transparency adapter - move = 0; // already at dev->model->y_offset_calib_ta implicitly - flags |= SCAN_FLAG_USE_XPA; - } - else - move = SANE_UNFIX(dev->model->y_offset_calib); - - move = (move * resolution) / MM_PER_INCH; - - ScanSession session; - session.params.xres = resolution; - session.params.yres = resolution; - session.params.startx = dev->calib_pixels_offset; - session.params.starty = move; - session.params.pixels = dev->calib_pixels; - session.params.lines = dev->calib_lines; - session.params.depth = 16; - session.params.channels = dev->calib_channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = dev->settings.scan_mode; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = flags; - gl843_compute_session(dev, session, calib_sensor); - - status = gl843_init_scan_regs(dev, calib_sensor, ®s, session); - - // the pixel number may be updated to conform to scanner constraints - dev->calib_pixels = dev->current_setup.pixels; - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - dev->calib_total_bytes_to_read = dev->read_bytes_left; - - dev->scanhead_position_in_steps += dev->calib_lines + move; - sanei_genesys_get_double(®s,REG_STRPIXEL,&strpixel); - DBG(DBG_info, "%s: STRPIXEL=%d\n", __func__, strpixel); - - status = dev->model->cmd_set->bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief set up registers for the actual scan - */ -static SANE_Status -gl843_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - /* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - move_dpi = dev->motor.base_ydpi; - - flags = 0; - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) - { - // note: move_to_ta() function has already been called and the sensor is at the - // transparency adapter - move = SANE_UNFIX(dev->model->y_offset_ta) - SANE_UNFIX(dev->model->y_offset_calib_ta); - flags |= SCAN_FLAG_USE_XPA; - } - else - move = SANE_UNFIX(dev->model->y_offset); - - move += dev->settings.tl_y; - move = (move * move_dpi) / MM_PER_INCH; - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - /* start */ - if(dev->settings.scan_method==ScanMethod::TRANSPARENCY) - start = SANE_UNFIX (dev->model->x_offset_ta); - else - start = SANE_UNFIX (dev->model->x_offset); - - start /= sensor.get_ccd_size_divisor_for_dpi(dev->settings.xres); - start += dev->settings.tl_x; - start = (start * sensor.optical_res) / MM_PER_INCH; - - /* enable emulated lineart from gray data */ - if(dev->settings.scan_mode == ScanColorMode::LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - ScanSession session; - session.params.xres = dev->settings.xres; - session.params.yres = dev->settings.yres; - session.params.startx = start; - session.params.starty = move; - session.params.pixels = dev->settings.pixels; - session.params.lines = dev->settings.lines; - session.params.depth = depth; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = dev->settings.scan_mode; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = flags; - gl843_compute_session(dev, session, sensor); - - status = gl843_init_scan_regs(dev, sensor, &dev->reg, session); - - if (status != SANE_STATUS_GOOD) - return status; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * This function sends gamma tables to ASIC - */ -static SANE_Status -gl843_send_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor) -{ - int size; - SANE_Status status = SANE_STATUS_GOOD; - int i; - - DBGSTART; - - size = 256; - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - std::vector gamma(size * 2 * 3); - - std::vector rgamma = get_gamma_table(dev, sensor, GENESYS_RED); - std::vector ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN); - std::vector bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE); - - // copy sensor specific's gamma tables - for (i = 0; i < size; i++) { - gamma[i * 2 + size * 0 + 0] = rgamma[i] & 0xff; - gamma[i * 2 + size * 0 + 1] = (rgamma[i] >> 8) & 0xff; - gamma[i * 2 + size * 2 + 0] = ggamma[i] & 0xff; - gamma[i * 2 + size * 2 + 1] = (ggamma[i] >> 8) & 0xff; - gamma[i * 2 + size * 4 + 0] = bgamma[i] & 0xff; - gamma[i * 2 + size * 4 + 1] = (bgamma[i] >> 8) & 0xff; - } - - /* send address */ - status = gl843_set_buffer_address (dev, 0x0000); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* send data */ - status = sanei_genesys_bulk_write_data(dev, 0x28, gamma.data(), size * 2 * 3); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send gamma table: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} - -/* this function does the led calibration by scanning one line of the calibration - area below scanner's top on white strip. - --needs working coarse/gain -*/ -static SANE_Status -gl843_led_calibration (Genesys_Device * dev, Genesys_Sensor& sensor, Genesys_Register_Set& regs) -{ - int num_pixels; - int total_size; - int used_res; - int i, j; - SANE_Status status = SANE_STATUS_GOOD; - int val; - int channels, depth; - int avg[3], avga, avge; - int turn; - uint16_t expr, expg, expb; - - SANE_Bool acceptable = SANE_FALSE; - - DBG(DBG_proc, "%s\n", __func__); - - /* offset calibration is always done in color mode */ - channels = 3; - depth = 16; - used_res = sensor.optical_res; - - auto& calib_sensor = sanei_genesys_find_sensor_for_write(dev, used_res, - dev->settings.scan_method); - num_pixels = - (calib_sensor.sensor_pixels * used_res) / calib_sensor.optical_res; - - /* initial calibration reg values */ - regs = dev->reg; - - ScanSession session; - session.params.xres = used_res; - session.params.yres = dev->motor.base_ydpi; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = num_pixels; - session.params.lines = 1; - session.params.depth = depth; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - gl843_compute_session(dev, session, calib_sensor); - - status = gl843_init_scan_regs(dev, calib_sensor, ®s, session); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - - total_size = dev->read_bytes_left; - - std::vector line(total_size); - -/* - we try to get equal bright leds here: - - loop: - average per color - adjust exposure times - */ - - expr = calib_sensor.exposure.red; - expg = calib_sensor.exposure.green; - expb = calib_sensor.exposure.blue; - - turn = 0; - - do - { - - calib_sensor.exposure.red = expr; - calib_sensor.exposure.green = expg; - calib_sensor.exposure.blue = expb; - - sanei_genesys_set_exposure(regs, calib_sensor.exposure); - - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - - DBG(DBG_info, "%s: starting first line reading\n", __func__); - RIE (gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); - RIE (sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); - RIE(gl843_stop_action_no_move(dev, ®s)); - - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl843_led_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), depth, channels, num_pixels, 1); - } - - acceptable = SANE_TRUE; - - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - acceptable = SANE_TRUE; - - if (avg[0] < avg[1] * 0.95 || avg[1] < avg[0] * 0.95 || - avg[0] < avg[2] * 0.95 || avg[2] < avg[0] * 0.95 || - avg[1] < avg[2] * 0.95 || avg[2] < avg[1] * 0.95) - acceptable = SANE_FALSE; - - if (!acceptable) - { - avga = (avg[0] + avg[1] + avg[2]) / 3; - expr = (expr * avga) / avg[0]; - expg = (expg * avga) / avg[1]; - expb = (expb * avga) / avg[2]; -/* - keep the resulting exposures below this value. - too long exposure drives the ccd into saturation. - we may fix this by relying on the fact that - we get a striped scan without shading, by means of - statistical calculation -*/ - avge = (expr + expg + expb) / 3; - - /* don't overflow max exposure */ - if (avge > 3000) - { - expr = (expr * 2000) / avge; - expg = (expg * 2000) / avge; - expb = (expb * 2000) / avge; - } - if (avge < 50) - { - expr = (expr * 50) / avge; - expg = (expg * 50) / avge; - expb = (expb * 50) / avge; - } - - } - - RIE (gl843_stop_action (dev)); - - turn++; - - } - while (!acceptable && turn < 100); - - DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, expr, expg, expb); - - sensor.exposure = calib_sensor.exposure; - - gl843_slow_back_home (dev, SANE_TRUE); - - DBG(DBG_proc, "%s: completed\n", __func__); - return status; -} - - - -/** - * average dark pixels of a 8 bits scan of a given channel - */ -static int -dark_average_channel (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black, int channel) -{ - unsigned int i, j, k, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average values on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - // FIXME: start with the second line because the black pixels often have noise on the first - // line; the cause is probably incorrectly cleaned up previous scan - for (i = 1; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j*channels + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); - } - DBG(DBG_info, "%s: average = %d\n", __func__, avg[channel]); - return avg[channel]; -} - -/** @brief calibrate AFE offset - * Iterate doing scans at target dpi until AFE offset if correct. One - * color line is scanned at a time. Scanning head doesn't move. - * @param dev device to calibrate - */ -static SANE_Status -gl843_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - unsigned int channels, bpp; - int pass, total_size, i, resolution, lines; - int topavg[3], bottomavg[3], avg[3]; - int top[3], bottom[3], black_pixels, pixels, factor, dpihw; - - DBGSTART; - - /* offset calibration is always done in color mode */ - channels = 3; - lines = 8; - bpp = 8; - - /* compute divider factor to compute final pixels number */ - dpihw = sanei_genesys_compute_dpihw_calibration(dev, sensor, dev->settings.xres); - factor = sensor.optical_res / dpihw; - resolution = dpihw; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, - dev->settings.scan_method); - - int target_pixels = calib_sensor.sensor_pixels / factor; - int start_pixel = 0; - black_pixels = calib_sensor.black_pixels / factor; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY && - dev->model->model_id == MODEL_CANON_CANOSCAN_8600F && - dev->settings.xres == 4800) - { - start_pixel = SANE_UNFIX(dev->model->x_offset_ta); - start_pixel /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); - start_pixel = (start_pixel * calib_sensor.optical_res) / MM_PER_INCH; - - target_pixels = SANE_UNFIX(dev->model->x_size_ta); - target_pixels /= calib_sensor.get_ccd_size_divisor_for_dpi(resolution); - target_pixels = (target_pixels * calib_sensor.optical_res) / MM_PER_INCH; - } - - int flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - if (dev->settings.scan_method == ScanMethod::TRANSPARENCY) - { - flags |= SCAN_FLAG_USE_XPA; - } - - ScanSession session; - session.params.xres = resolution; - session.params.yres = resolution; - session.params.startx = start_pixel; - session.params.starty = 0; - session.params.pixels = target_pixels; - session.params.lines = lines; - session.params.depth = bpp; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = ColorFilter::RED; - session.params.flags = flags; - gl843_compute_session(dev, session, calib_sensor); - pixels = session.output_pixels; - - DBG(DBG_io, "%s: dpihw =%d\n", __func__, dpihw); - DBG(DBG_io, "%s: factor =%d\n", __func__, factor); - DBG(DBG_io, "%s: resolution =%d\n", __func__, resolution); - DBG(DBG_io, "%s: pixels =%d\n", __func__, pixels); - DBG(DBG_io, "%s: black_pixels=%d\n", __func__, black_pixels); - status = gl843_init_scan_regs(dev, calib_sensor, ®s, session); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_set_motor_power(regs, false); - - /* allocate memory for scans */ - total_size = dev->read_bytes_left; - - std::vector first_line(total_size); - std::vector second_line(total_size); - - /* init gain and offset */ - for (i = 0; i < 3; i++) - { - bottom[i] = 10; - dev->frontend.set_offset(i, bottom[i]); - dev->frontend.set_gain(i, 0); - } - RIE(gl843_set_fe(dev, calib_sensor, AFE_SET)); - - /* scan with obttom AFE settings */ - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting first line reading\n", __func__); - RIE(gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); - RIE(gl843_stop_action_no_move(dev, ®s)); - - if (DBG_LEVEL >= DBG_data) - { - char fn[40]; - snprintf(fn, 40, "gl843_bottom_offset_%03d_%03d_%03d.pnm", - bottom[0], bottom[1], bottom[2]); - sanei_genesys_write_pnm_file(fn, first_line.data(), bpp, channels, pixels, lines); - } - - for (i = 0; i < 3; i++) - { - bottomavg[i] = dark_average_channel(first_line.data(), pixels, lines, channels, black_pixels, i); - DBG(DBG_io2, "%s: bottom avg %d=%d\n", __func__, i, bottomavg[i]); - } - - /* now top value */ - for (i = 0; i < 3; i++) - { - top[i] = 255; - dev->frontend.set_offset(i, top[i]); - } - RIE(gl843_set_fe(dev, calib_sensor, AFE_SET)); - - /* scan with top AFE values */ - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size)); - RIE(gl843_stop_action_no_move(dev, ®s)); - - for (i = 0; i < 3; i++) - { - topavg[i] = dark_average_channel(second_line.data(), pixels, lines, channels, black_pixels, i); - DBG(DBG_io2, "%s: top avg %d=%d\n", __func__, i, topavg[i]); - } - - pass = 0; - - std::vector debug_image; - size_t debug_image_lines = 0; - std::string debug_image_info; - - /* loop until acceptable level */ - while ((pass < 32) - && ((top[0] - bottom[0] > 1) - || (top[1] - bottom[1] > 1) || (top[2] - bottom[2] > 1))) - { - pass++; - - /* settings for new scan */ - for (i = 0; i < 3; i++) - { - if (top[i] - bottom[i] > 1) - { - dev->frontend.set_offset(i, (top[i] + bottom[i]) / 2); - } - } - RIE(gl843_set_fe(dev, calib_sensor, AFE_SET)); - - /* scan with no move */ - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, second_line.data(), total_size)); - RIE(gl843_stop_action_no_move(dev, ®s)); - - if (DBG_LEVEL >= DBG_data) - { - char title[100]; - snprintf(title, 100, "lines: %d pixels_per_line: %d offsets[0..2]: %d %d %d\n", - lines, pixels, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - debug_image_info += title; - std::copy(second_line.begin(), second_line.end(), std::back_inserter(debug_image)); - debug_image_lines += lines; - } - - for (i = 0; i < 3; i++) - { - avg[i] = dark_average_channel(second_line.data(), pixels, lines, channels, black_pixels, i); - DBG(DBG_info, "%s: avg[%d]=%d offset=%d\n", __func__, i, avg[i], - dev->frontend.get_offset(i)); - } - - /* compute new boundaries */ - for (i = 0; i < 3; i++) - { - if (topavg[i] >= avg[i]) - { - topavg[i] = avg[i]; - top[i] = dev->frontend.get_offset(i); - } - else - { - bottomavg[i] = avg[i]; - bottom[i] = dev->frontend.get_offset(i); - } - } - } - - if (DBG_LEVEL >= DBG_data) - { - sanei_genesys_write_file("gl843_offset_all_desc.txt", - (uint8_t*) debug_image_info.data(), debug_image_info.size()); - sanei_genesys_write_pnm_file("gl843_offset_all.pnm", - debug_image.data(), bpp, channels, pixels, debug_image_lines); - } - - DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* alternative coarse gain calibration - this on uses the settings from offset_calibration and - uses only one scanline - */ -/* - with offset and coarse calibration we only want to get our input range into - a reasonable shape. the fine calibration of the upper and lower bounds will - be done with shading. - */ -static SANE_Status -gl843_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, int dpi) -{ - int pixels, factor, dpihw; - int total_size; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float coeff; - int val, lines; - int resolution; - int bpp; - - DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); - dpihw=sanei_genesys_compute_dpihw_calibration(dev, sensor, dpi); - factor=sensor.optical_res/dpihw; - - /* coarse gain calibration is always done in color mode */ - channels = 3; - - /* follow CKSEL */ - if (dev->model->ccd_type == CCD_KVSS080) - { - if(dev->settings.xressettings.scan_method == ScanMethod::TRANSPARENCY) - { - flags |= SCAN_FLAG_USE_XPA; - } - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, - dev->settings.scan_method); - - ScanSession session; - session.params.xres = resolution; - session.params.yres = resolution; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = target_pixels; - session.params.lines = lines; - session.params.depth = bpp; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = flags; - gl843_compute_session(dev, session, calib_sensor); - pixels = session.output_pixels; - - try { - status = gl843_init_scan_regs(dev, calib_sensor, ®s, session); - } catch (...) { - try { - sanei_genesys_set_motor_power(regs, false); - } catch (...) {} - throw; - } - - sanei_genesys_set_motor_power(regs, false); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - - total_size = dev->read_bytes_left; - - std::vector line(total_size); - - RIE(gl843_set_fe(dev, calib_sensor, AFE_SET)); - RIE(gl843_begin_scan(dev, calib_sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, line.data(), total_size)); - RIE(gl843_stop_action_no_move(dev, ®s)); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl843_gain.pnm", line.data(), bpp, channels, pixels, lines); - - /* average value on each channel */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - // FIXME: start from the second line because the first line often has artifacts. Probably - // caused by unclean cleanup of previous scans - for (i = pixels/4 + pixels; i < (pixels*3/4) + pixels; i++) - { - if(bpp==16) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * pixels + 1] * 256 + - line[i * 2 + j * 2 * pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - } - else - { - if (dev->model->is_cis) - val = line[i + j * pixels]; - else - val = line[i * channels + j]; - } - - max[j] += val; - } - max[j] = max[j] / (pixels/2); - - /* the flow of data through the frontend ADC is as follows (see e.g. VM8192 datasheet) - input - -> apply offset (o = i + 260mV * (DAC[7:0]-127.5)/127.5) -> - -> apply gain (o = i * 208/(283-PGA[7:0]) - -> ADC - - Here we have some input data that was acquired with zero gain (PGA==0). - We want to compute gain such that the output would approach full ADC range (controlled by - gain_white_ref). - - We want to solve the following for {PGA}: - - {input} * 208 / (283 - 0) = {output} - {input} * 208 / (283 - {PGA}) = {target output} - - The solution is the following equation: - - {PGA} = 283 * (1 - {output} / {target output}) - */ - float gain = ((float) max[j] / (calib_sensor.gain_white_ref*coeff)); - int code = 283 * (1 - gain); - if (code > 255) - code = 255; - else if (code < 0) - code = 0; - dev->frontend.set_gain(j, code); - - DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain, - code); - } - - if (dev->model->is_cis) { - uint8_t gain0 = dev->frontend.get_gain(0); - if (gain0 > dev->frontend.get_gain(1)) { - gain0 = dev->frontend.get_gain(1); - } - if (gain0 > dev->frontend.get_gain(2)) { - gain0 = dev->frontend.get_gain(2); - } - dev->frontend.set_gain(0, gain0); - dev->frontend.set_gain(1, gain0); - dev->frontend.set_gain(2, gain0); - } - - if (channels == 1) { - dev->frontend.set_gain(0, dev->frontend.get_gain(1)); - dev->frontend.set_gain(2, dev->frontend.get_gain(1)); - } - - RIE (gl843_stop_action (dev)); - - status=gl843_slow_back_home (dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - -/* - * wait for lamp warmup by scanning the same line until difference - * between 2 scans is below a threshold - */ -static SANE_Status -gl843_init_regs_for_warmup (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - int *channels, int *total_size) -{ - int num_pixels; - SANE_Status status = SANE_STATUS_GOOD; - int dpihw; - int resolution; - int factor; - - DBGSTART; - if (dev == NULL || reg == NULL || channels == NULL || total_size == NULL) - return SANE_STATUS_INVAL; - - /* setup scan */ - *channels=3; - resolution=600; - dpihw=sanei_genesys_compute_dpihw_calibration(dev, sensor, resolution); - resolution=dpihw; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, resolution, - dev->settings.scan_method); - factor = calib_sensor.optical_res/dpihw; - num_pixels = calib_sensor.sensor_pixels/(factor*2); - *total_size = num_pixels * 3 * 1; - - *reg = dev->reg; - - ScanSession session; - session.params.xres = resolution; - session.params.yres = resolution; - session.params.startx = num_pixels/2; - session.params.starty = 0; - session.params.pixels = num_pixels; - session.params.lines = 1; - session.params.depth = 8; - session.params.channels = *channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - session.params.color_filter = dev->settings.color_filter; - session.params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - gl843_compute_session(dev, session, calib_sensor); - - status = gl843_init_scan_regs(dev, calib_sensor, reg, session); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - sanei_genesys_set_motor_power(*reg, false); - RIE(dev->model->cmd_set->bulk_write_register(dev, *reg)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * set up GPIO/GPOE for idle state -WRITE GPIO[17-21]= GPIO19 -WRITE GPOE[17-21]= GPOE21 GPOE20 GPOE19 GPOE18 -genesys_write_register(0xa8,0x3e) -GPIO(0xa8)=0x3e - */ -static SANE_Status -gl843_init_gpio (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx; - - DBGSTART; - - RIE (sanei_genesys_write_register (dev, REG6E, dev->gpo.enable[0])); - RIE (sanei_genesys_write_register (dev, REG6F, dev->gpo.enable[1])); - RIE (sanei_genesys_write_register (dev, REG6C, dev->gpo.value[0])); - RIE (sanei_genesys_write_register (dev, REG6D, dev->gpo.value[1])); - - idx=0; - while(dev->model->gpo_type != gpios[idx].gpo_type && gpios[idx].gpo_type!=0) - { - idx++; - } - if (gpios[idx].gpo_type!=0) - { - RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); - RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); - RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); - RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); - } - else - { - status=SANE_STATUS_INVAL; - } - - DBGCOMPLETED; - return status; -} - - -/* * - * initialize ASIC from power on condition - */ -static SANE_Status -gl843_boot (Genesys_Device * dev, SANE_Bool cold) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - DBGSTART; - - if(cold) - { - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - } - - if(dev->usb_mode == 1) - { - val = 0x14; - } - else - { - val = 0x11; - } - RIE (sanei_genesys_write_0x8c (dev, 0x0f, val)); - - /* test CHKVER */ - RIE (sanei_genesys_read_register (dev, REG40, &val)); - if (val & REG40_CHKVER) - { - RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); - } - - /* Set default values for registers */ - gl843_init_registers (dev); - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - // turns on vref control for maximum current of the motor driver - RIE(sanei_genesys_write_register (dev, REG6B, 0x72)); - } - else - { - RIE(sanei_genesys_write_register (dev, REG6B, 0x02)); - } - - /* Write initial registers */ - RIE (dev->model->cmd_set->bulk_write_register(dev, dev->reg)); - - // Enable DRAM by setting a rising edge on bit 3 of reg 0x0b - val = dev->reg.find_reg(0x0b).value & REG0B_DRAMSEL; - val = (val | REG0B_ENBDRAM); - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg.find_reg(0x0b).value = val; - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0xc8)); - } - else - { - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0xb4)); - } - - /* CLKSET */ - int clock_freq = REG0B_48MHZ; - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - clock_freq = REG0B_60MHZ; - - val = (dev->reg.find_reg(0x0b).value & ~REG0B_CLKSET) | clock_freq; - - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg.find_reg(0x0b).value = val; - - /* prevent further writings by bulk write register */ - dev->reg.remove_reg(0x0b); - - if (dev->model->model_id != MODEL_CANON_CANOSCAN_8600F) - { - // set up end access - // FIXME: this is overwritten in gl843_init_gpio - sanei_genesys_write_register(dev, REGA7, 0x04); - sanei_genesys_write_register(dev, REGA9, 0x00); - } - - /* set RAM read address */ - RIE (sanei_genesys_write_register (dev, REG29, 0x00)); - RIE (sanei_genesys_write_register (dev, REG2A, 0x00)); - RIE (sanei_genesys_write_register (dev, REG2B, 0x00)); - - /* setup gpio */ - RIE (gl843_init_gpio (dev)); - - gl843_feed (dev, 300); - sanei_genesys_sleep_ms(100); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* * - * initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -static SANE_Status -gl843_init (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG_INIT (); - DBGSTART; - - status=sanei_genesys_asic_init(dev, 0); - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl843_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not lose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); - - switch (s->dev->model->gpo_type) - { - case GPO_KVSS080: - s->buttons[BUTTON_SCAN_SW].write((val & 0x04) == 0); - break; - case GPO_G4050: - s->buttons[BUTTON_SCAN_SW].write((val & 0x01) == 0); - s->buttons[BUTTON_FILE_SW].write((val & 0x02) == 0); - s->buttons[BUTTON_EMAIL_SW].write((val & 0x04) == 0); - s->buttons[BUTTON_COPY_SW].write((val & 0x08) == 0); - break; - case GPO_CS4400F: - case GPO_CS8400F: - default: - break; - } - - return status; -} - -/** @brief move sensor to transparency adaptor - * Move sensor to the calibration of the transparency adapator (XPA). - * @param dev device to use - */ -static SANE_Status -gl843_move_to_ta (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - float resolution; - unsigned int feed; - - DBGSTART; - - resolution=sanei_genesys_get_lowest_ydpi(dev); - feed = 16*(SANE_UNFIX (dev->model->y_offset_calib_ta) * resolution) / MM_PER_INCH; - status = gl843_feed (dev, feed); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to move to XPA calibration area\n", __func__); - return status; - } - - DBGCOMPLETED; - return status; -} - - -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl843_search_strip (Genesys_Device * dev, const Genesys_Sensor& sensor, - SANE_Bool forward, SANE_Bool black) -{ - unsigned int pixels, lines, channels; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg; - size_t size; - int steps, depth, dpi; - unsigned int pass, count, found, x, y; - GenesysRegister *r; - - DBG(DBG_proc, "%s %s %s\n", __func__, black ? "black" : "white", forward ? "forward" : "reverse"); - - gl843_set_fe(dev, sensor, AFE_SET); - status = gl843_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* set up for a gray scan at lowest dpi */ - dpi = sanei_genesys_get_lowest_dpi(dev); - channels = 1; - - const auto& calib_sensor = sanei_genesys_find_sensor(dev, dpi, dev->settings.scan_method); - - /* 10 MM */ - /* lines = (10 * dpi) / MM_PER_INCH; */ - /* shading calibation is done with dev->motor.base_ydpi */ - lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; - depth = 8; - pixels = (calib_sensor.sensor_pixels * dpi) / calib_sensor.optical_res; - - dev->scanhead_position_in_steps = 0; - - local_reg = dev->reg; - - ScanSession session; - session.params.xres = dpi; - session.params.yres = dpi; - session.params.startx = 0; - session.params.starty = 0; - session.params.pixels = pixels; - session.params.lines = lines; - session.params.depth = depth; - session.params.channels = channels; - session.params.scan_method = dev->settings.scan_method; - session.params.scan_mode = ScanColorMode::GRAY; - session.params.color_filter = ColorFilter::RED; - session.params.flags = SCAN_FLAG_DISABLE_SHADING | SCAN_FLAG_DISABLE_SHADING; - gl843_compute_session(dev, session, calib_sensor); - - status = gl843_init_scan_regs(dev, calib_sensor, &local_reg, session); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - size = dev->read_bytes_left; - std::vector data(size); - - /* set up for reverse or forward */ - r = sanei_genesys_get_address(&local_reg, REG02); - if (forward) - r->value &= ~REG02_MTRREV; - else - r->value |= REG02_MTRREV; - - - status = dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl843_begin_scan(dev, calib_sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl843_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl843_stop_action failed\n", __func__); - return status; - } - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - char fn[40]; - snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file(fn, data.data(), depth, channels, pixels, lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < 20 && !found) - { - status = - dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* now start scan */ - status = gl843_begin_scan(dev, calib_sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl843_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl843_stop_action failed\n", __func__); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - char fn[40]; - snprintf(fn, 40, "gl843_search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file(fn, data.data(), depth, channels, pixels, lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, - pass, y); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - pass++; - } - if (found) - { - status = SANE_STATUS_GOOD; - DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG(DBG_info, "%s: %s strip not found\n", __func__, black ? "black" : "white"); - } - - DBG(DBG_proc, "%s: completed\n", __func__); - return status; -} - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -static SANE_Status -gl843_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t final_size, length, i; - uint8_t *buffer; - int count,offset; - unsigned int cksel; - GenesysRegister *r; - uint16_t dpiset, strpixel, endpixel, startx, factor; - - DBGSTART; - - offset=0; - length=size; - r = sanei_genesys_get_address(&dev->reg, REG01); - if(r->value & REG01_SHDAREA) - { - /* recompute STRPIXEL used shading calibration so we can - * compute offset within data for SHDAREA case */ - r = sanei_genesys_get_address(&dev->reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - sanei_genesys_get_double(&dev->reg,REG_DPISET,&strpixel); - sanei_genesys_get_double(&dev->reg,REG_DPISET,&dpiset); - factor=sensor.optical_res/sanei_genesys_compute_dpihw(dev, sensor, dpiset); - - /* start coordinate in optical dpi coordinates */ - startx = (sensor.dummy_pixel / cksel) / factor; - - /* current scan coordinates */ - sanei_genesys_get_double(&dev->reg,REG_STRPIXEL,&strpixel); - sanei_genesys_get_double(&dev->reg,REG_ENDPIXEL,&endpixel); - - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - int optical_res = sensor.optical_res / dev->current_setup.ccd_size_divisor; - int dpiset_real = dpiset / dev->current_setup.ccd_size_divisor; - int half_ccd_factor = optical_res / - sanei_genesys_compute_dpihw_calibration(dev, sensor, dpiset_real); - strpixel /= half_ccd_factor; - endpixel /= half_ccd_factor; - } - - /* 16 bit words, 2 words per color, 3 color channels */ - offset=(strpixel-startx)*2*2*3; - length=(endpixel-strpixel)*2*2*3; - DBG(DBG_info, "%s: STRPIXEL=%d, ENDPIXEL=%d, startx=%d\n", __func__, strpixel, endpixel, - startx); - } - - /* compute and allocate size for final data */ - final_size = ((length+251) / 252) * 256; - DBG(DBG_io, "%s: final shading size=%04x (length=%d)\n", __func__, final_size, length); - std::vector final_data(final_size, 0); - - /* copy regular shading data to the expected layout */ - buffer = final_data.data(); - count = 0; - - /* loop over calibration data */ - for (i = 0; i < length; i++) - { - buffer[count] = data[offset+i]; - count++; - if ((count % (256*2)) == (252*2)) - { - count += 4*2; - } - } - - /* send data */ - status = sanei_genesys_set_buffer_address (dev, 0); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set buffer address: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = dev->model->cmd_set->bulk_write_data (dev, 0x3c, final_data.data(), count); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to send shading table: %s\n", __func__, sane_strstatus(status)); - } - - DBGCOMPLETED; - return status; -} - - -/** the gl843 command set */ -static Genesys_Command_Set gl843_cmd_set = { - "gl843-generic", /* the name of this set */ - - [](Genesys_Device* dev) -> bool { (void) dev; return true; }, - - gl843_init, - gl843_init_regs_for_warmup, - gl843_init_regs_for_coarse_calibration, - gl843_init_regs_for_shading, - gl843_init_regs_for_scan, - - gl843_get_filter_bit, - gl843_get_lineart_bit, - gl843_get_bitset_bit, - gl843_get_gain4_bit, - gl843_get_fast_feed_bit, - gl843_test_buffer_empty_bit, - gl843_test_motor_flag_bit, - - gl843_set_fe, - gl843_set_powersaving, - gl843_save_power, - - gl843_begin_scan, - gl843_end_scan, - - gl843_send_gamma_table, - - gl843_search_start_position, - - gl843_offset_calibration, - gl843_coarse_gain_calibration, - gl843_led_calibration, - - NULL, - gl843_slow_back_home, - NULL, - - sanei_genesys_bulk_write_register, - sanei_genesys_bulk_write_data, - sanei_genesys_bulk_read_data, - - gl843_update_hardware_sensors, - - gl843_load_document, - gl843_detect_document_end, - gl843_eject_document, - gl843_search_strip, - - sanei_genesys_is_compatible_calibration, - gl843_move_to_ta, - gl843_send_shading_data, - gl843_calculate_current_setup, - gl843_boot -}; - -SANE_Status -sanei_gl843_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl843_cmd_set; - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_gl843.h b/backend/genesys_gl843.h deleted file mode 100644 index 7651cc9..0000000 --- a/backend/genesys_gl843.h +++ /dev/null @@ -1,472 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2013 Stéphane Voltz - - 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 "genesys.h" - -#define REG01 0x01 -#define REG01_CISSET 0x80 -#define REG01_DOGENB 0x40 -#define REG01_DVDSET 0x20 -#define REG01_STAGGER 0x10 -#define REG01_COMPENB 0x08 -#define REG01_TRUEGRAY 0x04 -#define REG01_SHDAREA 0x02 -#define REG01_SCAN 0x01 - -#define REG02 0x02 -#define REG02_NOTHOME 0x80 -#define REG02_ACDCDIS 0x40 -#define REG02_AGOHOME 0x20 -#define REG02_MTRPWR 0x10 -#define REG02_FASTFED 0x08 -#define REG02_MTRREV 0x04 -#define REG02_HOMENEG 0x02 -#define REG02_LONGCURV 0x01 - -#define REG03 0x03 -#define REG03_LAMPDOG 0x80 -#define REG03_AVEENB 0x40 -#define REG03_XPASEL 0x20 -#define REG03_LAMPPWR 0x10 -#define REG03_LAMPTIM 0x0f - -#define REG04 0x04 -#define REG04_LINEART 0x80 -#define REG04_BITSET 0x40 -#define REG04_AFEMOD 0x30 -#define REG04_FILTER 0x0c -#define REG04_FESET 0x03 - -#define REG04S_AFEMOD 4 - -#define REG05 0x05 -#define REG05_DPIHW 0xc0 -#define REG05_DPIHW_600 0x00 -#define REG05_DPIHW_1200 0x40 -#define REG05_DPIHW_2400 0x80 -#define REG05_DPIHW_4800 0xc0 -#define REG05_MTLLAMP 0x30 -#define REG05_GMMENB 0x08 -#define REG05_MTLBASE 0x03 - -#define REG06 0x06 -#define REG06_SCANMOD 0xe0 -#define REG06S_SCANMOD 5 -#define REG06_PWRBIT 0x10 -#define REG06_GAIN4 0x08 -#define REG06_OPTEST 0x07 - -#define REG07_LAMPSIM 0x80 - -#define REG08_DECFLAG 0x40 -#define REG08_GMMFFR 0x20 -#define REG08_GMMFFG 0x10 -#define REG08_GMMFFB 0x08 -#define REG08_GMMZR 0x04 -#define REG08_GMMZG 0x02 -#define REG08_GMMZB 0x01 - -#define REG09_MCNTSET 0xc0 -#define REG09_EVEN1ST 0x20 -#define REG09_BLINE1ST 0x10 -#define REG09_BACKSCAN 0x08 -#define REG09_ENHANCE 0x04 -#define REG09_SHORTTG 0x02 -#define REG09_NWAIT 0x01 - -#define REG09S_MCNTSET 6 -#define REG09S_CLKSET 4 - -#define REG0B 0x0b -#define REG0B_DRAMSEL 0x07 -#define REG0B_ENBDRAM 0x08 -#define REG0B_ENBDRAM 0x08 -#define REG0B_RFHDIS 0x10 -#define REG0B_CLKSET 0xe0 -#define REG0B_24MHZ 0x00 -#define REG0B_30MHZ 0x20 -#define REG0B_40MHZ 0x40 -#define REG0B_48MHZ 0x60 -#define REG0B_60MHZ 0x80 - -#define REG0D 0x0d -#define REG0D_JAMPCMD 0x80 -#define REG0D_DOCCMD 0x40 -#define REG0D_CCDCMD 0x20 -#define REG0D_FULLSTP 0x10 -#define REG0D_SEND 0x08 -#define REG0D_CLRMCNT 0x04 -#define REG0D_CLRDOCJM 0x02 -#define REG0D_CLRLNCNT 0x01 - -#define REG0F 0x0f - -#define REG_EXPR 0x10 -#define REG_EXPG 0x12 -#define REG_EXPB 0x14 - -#define REG16_CTRLHI 0x80 -#define REG16_TOSHIBA 0x40 -#define REG16_TGINV 0x20 -#define REG16_CK1INV 0x10 -#define REG16_CK2INV 0x08 -#define REG16_CTRLINV 0x04 -#define REG16_CKDIS 0x02 -#define REG16_CTRLDIS 0x01 - -#define REG17_TGMODE 0xc0 -#define REG17_TGMODE_NO_DUMMY 0x00 -#define REG17_TGMODE_REF 0x40 -#define REG17_TGMODE_XPA 0x80 -#define REG17_TGW 0x3f -#define REG17S_TGW 0 - -#define REG18 0x18 -#define REG18_CNSET 0x80 -#define REG18_DCKSEL 0x60 -#define REG18_CKTOGGLE 0x10 -#define REG18_CKDELAY 0x0c -#define REG18_CKSEL 0x03 - -#define REG_EXPDMY 0x19 - -#define REG1A_TGLSW2 0x80 -#define REG1A_TGLSW1 0x40 -#define REG1A_MANUAL3 0x02 -#define REG1A_MANUAL1 0x01 -#define REG1A_CK4INV 0x08 -#define REG1A_CK3INV 0x04 -#define REG1A_LINECLP 0x02 - -#define REG1C 0x1c -#define REG1C_TGTIME 0x07 - -#define REG1D_CK4LOW 0x80 -#define REG1D_CK3LOW 0x40 -#define REG1D_CK1LOW 0x20 -#define REG1D_TGSHLD 0x1f -#define REG1DS_TGSHLD 0 - - -#define REG1E 0x1e -#define REG1E_WDTIME 0xf0 -#define REG1ES_WDTIME 4 -#define REG1E_LINESEL 0x0f -#define REG1ES_LINESEL 0 - -#define REG21 0x21 -#define REG_STEPNO 0x21 -#define REG_FWDSTEP 0x22 -#define REG_BWDSTEP 0x23 -#define REG_FASTNO 0x24 -#define REG_LINCNT 0x25 - -#define REG29 0x29 -#define REG2A 0x2a -#define REG2B 0x2b -#define REG_DPISET 0x2c -#define REG2E 0x2e -#define REG2F 0x2f - -#define REG_STRPIXEL 0x30 -#define REG_ENDPIXEL 0x32 -#define REG_DUMMY 0x34 -#define REG_MAXWD 0x35 -#define REG_LPERIOD 0x38 -#define REG_FEEDL 0x3d - -#define REG40 0x40 -#define REG40_DOCSNR 0x80 -#define REG40_ADFSNR 0x40 -#define REG40_COVERSNR 0x20 -#define REG40_CHKVER 0x10 -#define REG40_DOCJAM 0x08 -#define REG40_HISPDFLG 0x04 -#define REG40_MOTMFLG 0x02 -#define REG40_DATAENB 0x01 - -#define REG41_PWRBIT 0x80 -#define REG41_BUFEMPTY 0x40 -#define REG41_FEEDFSH 0x20 -#define REG41_SCANFSH 0x10 -#define REG41_HOMESNR 0x08 -#define REG41_LAMPSTS 0x04 -#define REG41_FEBUSY 0x02 -#define REG41_MOTORENB 0x01 - -#define REG58_VSMP 0xf8 -#define REG58S_VSMP 3 -#define REG58_VSMPW 0x07 -#define REG58S_VSMPW 0 - -#define REG59_BSMP 0xf8 -#define REG59S_BSMP 3 -#define REG59_BSMPW 0x07 -#define REG59S_BSMPW 0 - -#define REG5A_ADCLKINV 0x80 -#define REG5A_RLCSEL 0x40 -#define REG5A_CDSREF 0x30 -#define REG5AS_CDSREF 4 -#define REG5A_RLC 0x0f -#define REG5AS_RLC 0 - -#define REG5E 0x5e -#define REG5E_DECSEL 0xe0 -#define REG5ES_DECSEL 5 -#define REG5E_STOPTIM 0x1f -#define REG5ES_STOPTIM 0 - -#define REG_FMOVDEC 0x5f - -#define REG60 0x60 -#define REG60_Z1MOD 0x1f -#define REG61 0x61 -#define REG61_Z1MOD 0xff -#define REG62 0x62 -#define REG62_Z1MOD 0xff - -#define REG63 0x63 -#define REG63_Z2MOD 0x1f -#define REG64 0x64 -#define REG64_Z2MOD 0xff -#define REG65 0x65 -#define REG65_Z2MOD 0xff - -#define REG67 0x67 - -#define REG68 0x68 - -#define REG67S_STEPSEL 6 -#define REG67_STEPSEL 0xc0 -#define REG67_FULLSTEP 0x00 -#define REG67_HALFSTEP 0x20 -#define REG67_EIGHTHSTEP 0x60 -#define REG67_16THSTEP 0x80 - -#define REG68S_FSTPSEL 6 -#define REG68_FSTPSEL 0xc0 -#define REG68_FULLSTEP 0x00 -#define REG68_HALFSTEP 0x20 -#define REG68_EIGHTHSTEP 0x60 -#define REG68_16THSTEP 0x80 - -#define REG_FSHDEC 0x69 -#define REG_FMOVNO 0x6a - -#define REG6B 0x6b -#define REG6B_MULTFILM 0x80 -#define REG6B_GPOM13 0x40 -#define REG6B_GPOM12 0x20 -#define REG6B_GPOM11 0x10 -#define REG6B_GPOCK4 0x08 -#define REG6B_GPOCP 0x04 -#define REG6B_GPOLEDB 0x02 -#define REG6B_GPOADF 0x01 - -#define REG6C 0x6c -#define REG6C_GPIO16 0x80 -#define REG6C_GPIO15 0x40 -#define REG6C_GPIO14 0x20 -#define REG6C_GPIO13 0x10 -#define REG6C_GPIO12 0x08 -#define REG6C_GPIO11 0x04 -#define REG6C_GPIO10 0x02 -#define REG6C_GPIO9 0x01 -#define REG6C_GPIOH 0xff -#define REG6C_GPIOL 0xff - -#define REG_Z1MOD 0x60 -#define REG_Z2MOD 0x63 - -#define REG6D 0x6d -#define REG6E 0x6e -#define REG6F 0x6f - -#define REG_CK1MAP 0x74 -#define REG_CK3MAP 0x77 -#define REG_CK4MAP 0x7a - -#define REG7E 0x7e - -#define REG9D 0x9d -#define REG9DS_STEPTIM 2 - -#define REG87_LEDADD 0x04 - -#define REGA6 0xa6 -#define REGA6_GPIO24 0x80 -#define REGA6_GPIO23 0x40 -#define REGA6_GPIO22 0x20 -#define REGA6_GPIO21 0x10 -#define REGA6_GPIO20 0x08 -#define REGA6_GPIO19 0x04 -#define REGA6_GPIO18 0x02 -#define REGA6_GPIO17 0x01 -#define REGA7 0xa7 -#define REGA7_GPOE24 0x80 -#define REGA7_GPOE23 0x40 -#define REGA7_GPOE22 0x20 -#define REGA7_GPOE21 0x10 -#define REGA7_GPOE20 0x08 -#define REGA7_GPOE19 0x04 -#define REGA7_GPOE18 0x02 -#define REGA7_GPOE17 0x01 -#define REGA8 0xa8 -#define REGA8_GPOE27 0x20 -#define REGA8_GPOE26 0x10 -#define REGA8_GPOE25 0x08 -#define REGA8_GPO27 0x04 -#define REGA8_GPO26 0x02 -#define REGA8_GPO25 0x01 -#define REGA9 0xa9 -#define REGA9_GPO33 0x20 -#define REGA9_GPO32 0x10 -#define REGA9_GPO31 0x08 -#define REGA9_GPO30 0x04 -#define REGA9_GPO29 0x02 -#define REGA9_GPO28 0x01 - -#define SCAN_TABLE 0 /* table 1 at 0x4000 */ -#define BACKTRACK_TABLE 1 /* table 2 at 0x4800 */ -#define STOP_TABLE 2 /* table 3 at 0x5000 */ -#define FAST_TABLE 3 /* table 4 at 0x5800 */ -#define HOME_TABLE 4 /* table 5 at 0x6000 */ - -#define SCAN_FLAG_SINGLE_LINE 0x001 -#define SCAN_FLAG_DISABLE_SHADING 0x002 -#define SCAN_FLAG_DISABLE_GAMMA 0x004 -#define SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE 0x008 -#define SCAN_FLAG_IGNORE_LINE_DISTANCE 0x010 -#define SCAN_FLAG_USE_OPTICAL_RES 0x020 -#define SCAN_FLAG_DISABLE_LAMP 0x040 -#define SCAN_FLAG_DYNAMIC_LINEART 0x080 - -#define SETREG(adr,val) { dev->reg.init_reg(adr, val); } - -typedef struct -{ - SANE_Int gpo_type; - uint8_t ra6; - uint8_t ra7; - uint8_t ra8; - uint8_t ra9; -} Gpio_layout; - -static Gpio_layout gpios[]={ - /* G4050 */ - { - GPO_G4050, 0x08, 0x1e, 0x3e, 0x06 - }, - /* KV-SS080 */ - { - GPO_KVSS080, 0x06, 0x0f, 0x00, 0x08 - }, - /* 4400F */ - { - GPO_CS4400F, 0x00, 0xff, 0x07, 0x00 - }, - /* 8400F */ - { - GPO_CS8400F, 0x00, 0x03, 0x00, 0x02 - }, - { - GPO_CS8600F, 0x00, 0xff, 0x00, 0x00, - }, - /* end marker */ - { - 0, 0, 0, 0, 0 - }, -}; - - -static uint32_t kvss080[]={44444, 34188, 32520, 29630, 26666, 24242, 22222, 19048, 16666, 15686, 14814, 14034, 12402, 11110, 8888, 7618, 6666, 5926, 5228, 4678, 4172, 3682, 3336, 3074, 2866, 2702, 2566, 2450, 2352, 2266, 2188, 2118, 2056, 2002, 1950, 1904, 1860, 1820, 1784, 1748, 1716, 1684, 1656, 1628, 1600, 1576, 1552, 1528, 1506, 1486, 1466, 1446, 1428, 1410, 1394, 1376, 1360, 1346, 1330, 1316, 1302, 1288, 1276, 1264, 1250, 1238, 1228, 1216, 1206, 1194, 1184, 1174, 1164, 1154, 1146, 1136, 1128, 1120, 1110, 1102, 1094, 1088, 1080, 1072, 1064, 1058, 1050, 1044, 1038, 1030, 1024, 1018, 1012, 1006, 1000, 994, 988, 984, 978, 972, 968, 962, 958, 952, 948, 942, 938, 934, 928, 924, 920, 916, 912, 908, 904, 900, 896, 892, 888, 884, 882, 878, 874, 870, 868, 864, 860, 858, 854, 850, 848, 844, 842, 838, 836, 832, 830, 826, 824, 822, 820, 816, 814, 812, 808, 806, 804, 802, 800, 796, 794, 792, 790, 788, 786, 784, 782, 778, 776, 774, 772, 770, 768, 766, 764, 762, 760, 758, 756, 754, 752, 750, 750, 748, 746, 744, 742, 740, 738, 736, 734, 734, 732, 730, 728, 726, 724, 724, 722, 720, 718, 716, 716, 714, 712, 710, 710, 708, 706, 704, 704, 702, 700, 698, 698, 696, 694, 694, 692, 690, 690, 688, 686, 686, 684, 682, 682, 680, 678, 678, 676, 674, 674, 672, 672, 670, 668, 668, 666, 666, 664, 662, 662, 660, 660, 658, 656, 656, 654, 654, 652, 652, 650, 650, 648, 646, 646, 644, 644, 642, 642, 640, 640, 638, 638, 636, 636, 636, 634, 634, 632, 632, 630, 630, 628, 628, 626, 626, 624, 624, 624, 622, 622, 620, 620, 618, 618, 618, 616, 616, 614, 614, 612, 612, 612, 610, 610, 608, 608, 608, 606, 606, 606, 604, 604, 602, 602, 602, 600, 600, 600, 598, 598, 596, 596, 596, 594, 594, 594, 592, 592, 592, 590, 590, 590, 588, 588, 588, 586, 586, 586, 584, 584, 584, 582, 582, 582, 590, 590, 590, 588, 588, 588, 586, 586, 586, 584, 584, 584, 582, 582, 582, 580, 580, 580, 578, 578, 578, 576, 576, 576, 576, 574, 574, 574, 572, 572, 572, 570, 570, 570, 568, 568, 568, 568, 566, 566, 566, 564, 564, 564, 562, 562, 562, 562, 560, 560, 560, 558, 558, 558, 558, 556, 556, 556, 554, 554, 554, 552, 552, 552, 552, 550, 550, 550, 548, 548, 548, 548, 546, 546, 546, 546, 544, 544, 544, 542, 542, 542, 542, 540, 540, 540, 538, 538, 538, 538, 536, 536, 536, 536, 534, 534, 534, 534, 532, 532, 532, 530, 530, 530, 530, 528, 528, 528, 528, 526, 526, 526, 526, 524, 524, 524, 524, 522, 522, 522, 522, 520, 520, 520, 520, 518, 518, 518, 516, 516, 516, 516, 514, 514, 514, 514, 514, 512, 512, 512, 512, 510, 510, 510, 510, 508, 508, 508, 508, 506, 506, 506, 506, 504, 504, 504, 504, 502, 502, 502, 502, 500, 500, 500, 500, 0}; -static uint32_t g4050_fast[]={7842,5898,4384,4258,4152,4052,3956,3864,3786,3714,3632,3564,3498,3444,3384,3324,3276,3228,3174,3128,3086,3044,3002,2968,2930,2892,2860,2824,2794,2760,2732,2704,2676,2650,2618,2594,2568,2548,2524,2500,2478,2454,2436,2414,2392,2376,2354,2338,2318,2302,2282,2266,2252,2232,2218,2202,2188,2174,2160,2142,2128,2116,2102,2088,2076,2062,2054,2040,2028,2020,2014,2008,2004,2002,2002,2002,1946,1882,1826,1770,1716,1662,1612,1568,1526,1488,1454,1422,1390,1362,1336,1310,1288,1264,1242,1222,1204,1184,1166,1150,1134,1118,1104,1090,1076,1064,1050,1038,1026,1016,1004,994,984,972,964,954,944,936,928,920,910,902,896,888,880,874,866,860,854,848,840,834,828,822,816,812,806,800,796,790,784,780,776,770,766,760,756,752,748,744,740,736,732,728,724,720,716,712,708,704,702,698,694,690,688,684,682,678,674,672,668,666,662,660,656,654,650,648,646,644,640,638,636,632,630,628,624,622,620,618,616,614,610,608,606,604,602,600,598,596,594,592,590,588,586,584,582,580,578,576,574,572,570,568,566,564,564,562,560,558,556,554,552,552,550,548,546,546,544,542,540,538,538,536,534,532,532,530,528,528,526,524,522,522,520,518,518,516,514,514,512,512,510,508,508,506,504,504,502,502,500,498,498,496,496,494,494,492,490,490,488,488,486,486,484,484,482,480,480,478,478,476,476,474,474,472,472,470,470,468,468,468,466,466,464,464,462,462,460,460,458,458,456,456,456,454,454,452,452,450,450,450,448,448,446,446,444,444,444,442,442,440,440,440,438,438,438,436,436,434,434,434,432,432,432,430,430,428,428,428,426,426,426,424,424,424,422,422,422,420,420,420,418,418,418,416,416,416,414,414,414,412,412,412,410,410,410,408,408,408,406,406,406,404,404,404,404,402,402,402,400,400,400,400,398,398,398,396,396,396,396,394,394,394,392,392,392,392,390,390,390,388,388,388,388,386,386,386,386,384,384,384,384,382,382,382,382,380,380,380,380,378,378,378,378,376,376,376,376,376,374,374,374,374,374,372,372,372,372,372,370,370,370,370,370,368,368,368,368,368,366,366,366,366,366,364,364,364,364,364,364,362,362,362,362,362,360,360,360,360,360,360,358,358,358,358,358,358,356,356,356,356,356,356,354,354,354,354,354,352,352,352,352,352,352,350,350,350,350,350,350,350,348,348,348,348,348,348,346,346,346,346,346,346,344,344,344,344,344,344,344,342,342,342,342,342,342,340,340,340,340,340,340,340,338,338,338,338,338,338,338,336,336,336,336,336,336,336,334,334,334,334,334,334,334,332,332,332,332,332,332,332,332,330,330,330,330,330,330,330,328,328,328,328,328,328,328,328,326,326,326,326,326,326,326,324,324,324,324,324,324,324,324,322,322,322,322,322,322,322,322,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320,320, 0}; -static uint32_t g4050_high[]={28032,28032,28032,28032,28032,28032,28032,28032, 27668,27024,26479,25975,25402,24926,24465,24087,23667,23248,22912,22576,22198,21877,21583,21289,20996,20758,20492,20226,20002,19751,19541,19303,19107,18911,18715,18534,18310,18142,17960,17820,17652,17485,17331,17163,17037,16883,16729,16617,16463,16352,16212,16100,15960,15848,15750,15610,15512,15400,15302,15204,15107,14981,14883,14799,14701,14603,14519,14421,14365,14267,14183,14127,14085,14043,14016,14002,14002,14002,13610,13162,12771,12379,12001,11624,11274,10966,10672,10407,10169,9945,9721,9525,9344,9162,9008,8840,8686,8546,8420,8280,8155,8043,7931,7819,7721,7623,7525,7441,7343,7259,7175,7105,7021,6952,6882,6798,6742,6672,6602,6546,6490,6434,6364,6308,6266,6210,6154,6112,6056,6014,5972,5930,5874,5833,5791,5749,5707,5679,5637,5595,5567,5525,5483,5455,5427,5385,5357,5315,5287,5259,5231,5203,5175,5147,5119,5091,5063,5035,5007,4979,4951,4923,4909,4881,4853,4825,4811,4783,4769,4741,4713,4699,4672,4658,4630,4616,4588,4574,4546,4532,4518,4504,4476,4462,4448,4420,4406,4392,4364,4350,4336,4322,4308,4294,4266,4252,4238,4224,4210,4196,4182,4168,4154,4140,4126,4112,4098,4084,4070,4056,4042,4028,4014,4000,3986,3972,3958,3944,3944,3930,3916,3902,3888,3874,3860,3860,3846,3832,3818,3818,3804,3790,3776,3762,3762,3748,3734,3720,3720,3706,3692,3692,3678,3664,3650,3650,3636,3622,3622,3608,3594,3594,3580,3580,3566,3552,3552,3538,3524,3524,3510,3510,3497,3483,3483,3469,3469,3455,3455,3441,3427,3427,3413,3413,3399,3399,3385,3385,3371,3357,3357,3343,3343,3329,3329,3315,3315,3301,3301,3287,3287,3273,3273,3273,3259,3259,3245,3245,3231,3231,3217,3217,3203,3203,3189,3189,3189,3175,3175,3161,3161,3147,3147,3147,3133,3133,3119,3119,3105,3105,3105,3091,3091,3077,3077,3077,3063,3063,3063,3049,3049,3035,3035,3035,3021,3021,3021,3007,3007,2993,2993,2993,2979,2979,2979,2965,2965,2965,2951,2951,2951,2937,2937,2937,2923,2923,2923,2909,2909,2909,2895,2895,2895,2881,2881,2881,2867,2867,2867,2853,2853,2853,2839,2839,2839,2825,2825,2825,2825,2811,2811,2811,2797,2797,2797,2797,2783,2783,2783,2769,2769,2769,2769,2755,2755,2755,2741,2741,2741,2741,2727,2727,2727,2713,2713,2713,2713,2699,2699,2699,2699,2685,2685,2685,2685,2671,2671,2671,2671,2657,2657,2657,2657,2643,2643,2643,2643,2629,2629,2629,2629,2629,2615,2615,2615,2615,2615,2601,2601,2601,2601,2601,2587,2587,2587,2587,2587,2573,2573,2573,2573,2573,2559,2559,2559,2559,2559,2545,2545,2545,2545,2545,2545,2531,2531,2531,2531,2531,2517,2517,2517,2517,2517,2517,2503,2503,2503,2503,2503,2503,2489,2489,2489,2489,2489,2489,2475,2475,2475,2475,2475,2461,2461,2461,2461,2461,2461,2447,2447,2447,2447,2447,2447,2447,2433,2433,2433,2433,2433,2433,2419,2419,2419,2419,2419,2419,2405,2405,2405,2405,2405,2405,2405,2391,2391,2391,2391,2391,2391,2377,2377,2377,2377,2377,2377,2377,2363,2363,2363,2363,2363,2363,2363,2349,2349,2349,2349,2349,2349,2349,2336,2336,2336,2336,2336,2336,2336,2322,2322,2322,2322,2322,2322,2322,2322,2308,2308,2308,2308,2308,2308,2308,2294,2294,2294,2294,2294,2294,2294,2294,2280,2280,2280,2280,2280,2280,2280,2266,2266,2266,2266,2266,2266,2266,2266,2252,2252,2252,2252,2252,2252,2252,2252,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238,2238, 0}; -static uint32_t g4050_max[]={42752,42752,42752,42752,42752,42752,42752,42752, 41824,31456,23381,22709,22144,21610,21098,20608,20192,19808,19370,19008,18656,18368,18048,17728,17472,17216,16928,16682,16458,16234,16010,15829,15626,15424,15253,15061,14901,14720,14570,14421,14272,14133,13962,13834,13696,13589,13461,13333,13216,13088,12992,12874,12757,12672,12554,12469,12362,12277,12170,12085,12010,11904,11829,11744,11669,11594,11520,11424,11349,11285,11210,11136,11072,10997,10954,10880,10816,10773,10741,10709,10688,10677,10677,10677,10378,10037,9738,9440,9152,8864,8597,8362,8138,7936,7754,7584,7413,7264,7125,6986,6869,6741,6624,6517,6421,6314,6218,6133,6048,5962,5888,5813,5738,5674,5600,5536,5472,5418,5354,5301,5248,5184,5141,5088,5034,4992,4949,4906,4853,4810,4778,4736,4693,4661,4618,4586,4554,4522,4480,4448,4416,4384,4352,4330,4298,4266,4245,4213,4181,4160,4138,4106,4085,4053,4032,4010,3989,3968,3946,3925,3904,3882,3861,3840,3818,3797,3776,3754,3744,3722,3701,3680,3669,3648,3637,3616,3594,3584,3562,3552,3530,3520,3498,3488,3466,3456,3445,3434,3413,3402,3392,3370,3360,3349,3328,3317,3306,3296,3285,3274,3253,3242,3232,3221,3210,3200,3189,3178,3168,3157,3146,3136,3125,3114,3104,3093,3082,3072,3061,3050,3040,3029,3018,3008,3008,2997,2986,2976,2965,2954,2944,2944,2933,2922,2912,2912,2901,2890,2880,2869,2869,2858,2848,2837,2837,2826,2816,2816,2805,2794,2784,2784,2773,2762,2762,2752,2741,2741,2730,2730,2720,2709,2709,2698,2688,2688,2677,2677,2666,2656,2656,2645,2645,2634,2634,2624,2613,2613,2602,2602,2592,2592,2581,2581,2570,2560,2560,2549,2549,2538,2538,2528,2528,2517,2517,2506,2506,2496,2496,2496,2485,2485,2474,2474,2464,2464,2453,2453,2442,2442,2432,2432,2432,2421,2421,2410,2410,2400,2400,2400,2389,2389,2378,2378,2368,2368,2368,2357,2357,2346,2346,2346,2336,2336,2336,2325,2325,2314,2314,2314,2304,2304,2304,2293,2293,2282,2282,2282,2272,2272,2272,2261,2261,2261,2250,2250,2250,2240,2240,2240,2229,2229,2229,2218,2218,2218,2208,2208,2208,2197,2197,2197,2186,2186,2186,2176,2176,2176,2165,2165,2165,2154,2154,2154,2154,2144,2144,2144,2133,2133,2133,2133,2122,2122,2122,2112,2112,2112,2112,2101,2101,2101,2090,2090,2090,2090,2080,2080,2080,2069,2069,2069,2069,2058,2058,2058,2058,2048,2048,2048,2048,2037,2037,2037,2037,2026,2026,2026,2026,2016,2016,2016,2016,2005,2005,2005,2005,2005,1994,1994,1994,1994,1994,1984,1984,1984,1984,1984,1973,1973,1973,1973,1973,1962,1962,1962,1962,1962,1952,1952,1952,1952,1952,1941,1941,1941,1941,1941,1941,1930,1930,1930,1930,1930,1920,1920,1920,1920,1920,1920,1909,1909,1909,1909,1909,1909,1898,1898,1898,1898,1898,1898,1888,1888,1888,1888,1888,1877,1877,1877,1877,1877,1877,1866,1866,1866,1866,1866,1866,1866,1856,1856,1856,1856,1856,1856,1845,1845,1845,1845,1845,1845,1834,1834,1834,1834,1834,1834,1834,1824,1824,1824,1824,1824,1824,1813,1813,1813,1813,1813,1813,1813,1802,1802,1802,1802,1802,1802,1802,1792,1792,1792,1792,1792,1792,1792,1781,1781,1781,1781,1781,1781,1781,1770,1770,1770,1770,1770,1770,1770,1770,1760,1760,1760,1760,1760,1760,1760,1749,1749,1749,1749,1749,1749,1749,1749,1738,1738,1738,1738,1738,1738,1738,1728,1728,1728,1728,1728,1728,1728,1728,1717,1717,1717,1717,1717,1717,1717,1717,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,1706,0}; -static uint32_t g4050_xpa[]={9422,5978,4736,4028,3560,3220,2914,2756,2588,2448,2328,2224,2132,2052,1978,1914,1854,1800,1752,1706,1664,1626,1588,1554,1522,1492,1464,1438,1412,1388,1366,1344,1324,1304,1284,1268,1250,1232,1218,1202,1188,1172,1160,1146,1134,1120,1110,1098,1086,1076,1066,1056,1046,1036,1026,1018,1008,1000,992,984,976,968,960,952,946,938,932,924,918,912,906,898,892,888,882,876,870,864,860,854,848,844,838,834,828,824,820,814,810,806,802,798,794,790,786,782,778,774,770,766,762,758,754,752,748,744,740,738,734,730,728,724,722,718,716,712,710,706,704,700,698,696,692,690,686,684,682,678,676,674,672,668,666,664,662,660,656,654,652,650,648,646,644,642,638,636,634,632,630,628,626,624,622,620,618,616,614,612,612,610,608,606,604,602,600,598,596,594,594,592,590,588,586,584,584,582,580,578,576,576,574,572,570,570,568,566,564,564,562,560,560,558,556,554,554,552,550,550,548,546,546,544,542,542,540,540,538,536,536,534,532,532,530,530,528,526,526,524,524,522,522,520,518,518,516,516,514,514,512,512,510,508,508,506,506,504,504,502,502,500,500,498,498,496,496,494,494,492,492,492,490,490,488,488,486,486,484,484,482,482,480,480,480,478,478,476,476,474,474,474,472,472,470,470,468,468,468,466,466,464,464,464,462,462,462,460,460,458,458,458,456,456,454,454,454,452,452,452,450,450,450,448,448,446,446,446,444,444,444,442,442,442,440,440,440,438,438,438,436,436,436,434,434,434,432,432,432,430,430,430,430,428,428,428,426,426,426,424,424,424,424,422,422,422,420,420,420,418,418,418,418,416,416,416,414,414,414,414,412,412,412,412,410,410,410,408,408,408,408,406,406,406,406,404,404,404,404,402,402,402,402,400,400,400,400,398,398,398,398,396,396,396,396,394,394,394,394,392,392,392,392,392,390,390,390,390,388,388,388,388,386,386,386,386,386,384,384,384,384,384,382,382,382,382,380,380,380,380,380,378,378,378,378,378,376,376,376,376,376,374,374,374,374,374,372,372,372,372,372,370,370,370,370,370,368,368,368,368,368,366,366,366,366,366,364,364,364,364,364,364,362,362,362,362,362,360,360,360,360,360,360,358,358,358,358,358,358,356,356,356,356,356,354,354,354,354,354,354,352,352,352,352,352,352,350,350,350,350,350,350,350,348,348,348,348,348,348,346,346,346,346,346,346,344,344,344,344,344,344,344,342,342,342,342,342,342,340,340,340,340,340,340,340,338,338,338,338,338,338,338,336,336,336,336,336,336,336,334,334,334,334,334,334,334,332,332,332,332,332,332,332,330,330,330,330,330,330,330,330,328,328,328,328,328,328,328,326,326,326,326,326,326,326,326,324,324,324,324,324,324,324,324,322,322,322,322,322,322,322,322,320,320,320,320,320,320,320,320,318,318,318,318,318,318,318,318,318,316,316,316,316,316,316,316,316,314,314,314,314,314,314,314,314,314,312,312,312,312,312,312,312,312,312,310,310,310,310,310,310,310,310,310,308,308,308,308,308,308,308,308,308,306,306,306,306,306,306,306,306,306,306,304,304,304,304,304,304,304,304,304,302,302,302,302,302,302,302,302,302,302,300,300,300,300,300,300,300,300,300,300,298,298,298,298,298,298,298,298,298,298,298,296,296,296,296,296,296,296,296,296,296,294,294,294,294,294,294,294,294,294,294,294,292,292,292,292,292,292,292,292,292,292,292,290,290,290,290,290,290,290,290,290,290,290,288,288,288,288,288,288,288,288,288,288,288,288,286,286,286,286,286,286,286,286,286,286,286,286,284,284,284,284,284,284,284,284,284,284,284,284,282,282,282,282,282,282,282,282,282,282,282,282,280,280,280,280,280,280,280,280,280,280,280,280,280,278,278,278,278,278,278,278,278,278,278,278,278,278,276,276,276,276,276,276,276,276,276,276,276,276,276,274,274,274,274,274,274,274,274,274,274,274,274,274,274,272,272,272,272,272,272,272,272,272,272,272,272,272,272,270,270,270,270,270,270,270,270,270,270,270,270,270,270,268,268,268,268,268,268,268,268,268,268,268,268,268,268,268,266,266,266,266,266,266,266,266,266,266,266,266,266,266,266,264,264,264,264,264,264,264,264,264,264,264,264,264,264,264,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,262,260,260,260,260,260,260,260,260,260,260,260,260,260,260,260,260,258,258,258,258,258,258,258,258,258,258,258,258,258,258,258,258,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,256,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,0}; -static uint32_t cs4400f_fast[]={49152, 49152, 31144, 23652, 19538, 16822, 14908, 13442, 12288, 11356, 10590, 9922, 9362, 8886, 8456, 8064, 7728, 7418, 7148, 6882, 6664, 6446, 6252, 6060, 5890, 5740, 5586, 5450, 5322, 5198, 5080, 4968, 4868, 4766, 4674, 4584, 4500, 4418, 4338, 4262, 4194, 4122, 4058, 3996, 3932, 3874, 3816, 3766, 3712, 3662, 3610, 3566, 3518, 3474, 3430, 3388, 3350, 3310, 3272, 3236, 3200, 3164, 3130, 3096, 3062, 3032, 3000, 2972, 2942, 2914, 2884, 2858, 2832, 2806, 2780, 2756, 2732, 2708, 2686, 2662, 2640, 2618, 2596, 2576, 2554, 2536, 2516, 2496, 2478, 2458, 2440, 2422, 2404, 2388, 2370, 2354, 2338, 2320, 2306, 2290, 2276, 2258, 2244, 2230, 2216, 2202, 2188, 2174, 2162, 2148, 2134, 2122, 2108, 2096, 2084, 2072, 2060, 2048, 2036, 2026, 2014, 2002, 1992, 1982, 1970, 1960, 1950, 1940, 1928, 1920, 1908, 1900, 1890, 1880, 1872, 1862, 1852, 1844, 1834, 1826, 1818, 1808, 1800, 1792, 1784, 1776, 1768, 1760, 1752, 1742, 1736, 1728, 1720, 1712, 1704, 1698, 1690, 1684, 1676, 1670, 1662, 1656, 1648, 1642, 1634, 1628, 1622, 1616, 1608, 1602, 1596, 1590, 1584, 1578, 1572, 1566, 1560, 1554, 1548, 1542, 1536, 1532, 1526, 1520, 1514, 1508, 1504, 1498, 1492, 1488, 1482, 1478, 1472, 1466, 1462, 1456, 1452, 1446, 1442, 1438, 1432, 1428, 1424, 1418, 1414, 1410, 1404, 1400, 1396, 1390, 1386, 1382, 1378, 1374, 1370, 1364, 1360, 1356, 1352, 1348, 1344, 1340, 1336, 1332, 1328, 1324, 1320, 1316, 1312, 1308, 1304, 1302, 1298, 1294, 1290, 1286, 1282, 1278, 1276, 1272, 1268, 1264, 1262, 1258, 1254, 1250, 1248, 1244, 1240, 1238, 1234, 1230, 1228, 1224, 1222, 1218, 1214, 1212, 1208, 1206, 1202, 1200, 1196, 1194, 1190, 1186, 1184, 1182, 1178, 1176, 1172, 1170, 1166, 1164, 1162, 1158, 1156, 1152, 1150, 1148, 1144, 1142, 1138, 1136, 1134, 1130, 1128, 1126, 1122, 1120, 1118, 1116, 1112, 1110, 1108, 1106, 1102, 1100, 1098, 1096, 1092, 1090, 1088, 1086, 1082, 1080, 1078, 1076, 1074, 1072, 1068, 1066, 1064, 1062, 1060, 1058, 1056, 1054, 1052, 1048, 1046, 1044, 1042, 1040, 1038, 1036, 1034, 1032, 1030, 1028, 1026, 1024, 1022, 1020, 1018, 1016, 1014, 1012, 1010, 1008, 1006, 1004, 1002, 1000, 998, 996, 994, 992, 990, 988, 986, 984, 982, 980, 978, 976, 974, 972, 972, 970, 968, 966, 964, 962, 960, 958, 956, 956, 954, 952, 950, 948, 946, 944, 944, 942, 940, 938, 936, 934, 934, 932, 930, 928, 926, 926, 924, 922, 920, 918, 918, 916, 914, 912, 912, 910, 908, 906, 904, 904, 902, 900, 898, 898, 896, 894, 892, 892, 890, 888, 888, 886, 884, 882, 882, 880, 878, 878, 876, 874, 874, 872, 870, 868, 868, 866, 864, 864, 862, 860, 860, 858, 856, 856, 854, 852, 852, 850, 848, 848, 846, 846, 844, 842, 842, 840, 838, 838, 836, 834, 834, 832, 832, 830, 828, 828, 826, 826, 824, 822, 822, 820, 820, 818, 816, 816, 814, 814, 812, 812, 810, 808, 808, 806, 806, 804, 802, 802, 800, 800, 798, 798, 796, 796, 794, 792, 792, 790, 790, 788, 788, 786, 786, 784, 784, 782, 782, 780, 780, 778, 778, 776, 774, 774, 772, 772, 770, 770, 768, 768, 766, 766, 764, 764, 762, 762, 760, 760, 758, 758, 758, 756, 756, 754, 754, 752, 752, 750, 750, 748, 748, 746, 746, 744, 744, 742, 742, 740, 740, 738, 738, 738, 736, 736, 734, 734, 732, 732, 730, 730, 730, 728, 728, 726, 726, 724, 724, 722, 722, 722, 720, 720, 718, 718, 718, 716, 716, 714, 714, 712, 712, 712, 710, 710, 708, 708, 708, 706, 706, 704, 704, 702, 702, 702, 700, 700, 698, 698, 698, 696, 696, 694, 694, 694, 692, 692, 692, 690, 690, 688, 688, 688, 686, 686, 684, 684, 684, 682, 682, 682, 680, 680, 680, 678, 678, 676, 676, 676, 674, 674, 674, 672, 672, 670, 670, 670, 668, 668, 668, 666, 666, 666, 664, 664, 664, 662, 662, 660, 660, 660, 658, 658, 658, 656, 656, 656, 654, 654, 654, 652, 652, 652, 650, 650, 650, 648, 648, 648, 646, 646, 646, 644, 644, 644, 642, 642, 642, 640, 640, 640, 640, 638, 638, 638, 636, 636, 636, 634, 634, 634, 632, 632, 632, 630, 630, 630, 630, 628, 628, 628, 626, 626, 626, 624, 624, 624, 624, 622, 622, 622, 620, 620, 620, 618, 618, 618, 618, 616, 616, 616, 614, 614, 614, 614, 612, 612, 612, 610, 610, 610, 610, 608, 608, 608, 606, 606, 606, 606, 604, 604, 604, 604, 602, 602, 602, 600, 600, 600, 600, 598, 598, 598, 598, 596, 596, 596, 594, 594, 594, 594, 592, 592, 592, 592, 590, 590, 590, 590, 588, 588, 588, 586, 586, 586, 586, 584, 584, 584, 584, 582, 582, 582, 582, 580, 580, 580, 580, 578, 578, 578, 578, 576, 576, 576, 576, 574, 574, 574, 574, 574, 572, 572, 572, 572, 570, 570, 570, 570, 568, 568, 568, 568, 566, 566, 566, 566, 564, 564, 564, 564, 564, 562, 562, 562, 562, 560, 560, 560, 560, 558, 558, 558, 558, 558, 556, 556, 556, 556, 554, 554, 554, 554, 554, 552, 552, 552, 552, 550, 550, 550, 550, 550, 548, 548, 548, 548, 546, 546, 546, 546, 546, 544, 544, 544, 544, 544, 542, 542, 542, 542, 540, 540, 540, 540, 540, 538, 538, 538, 538, 538, 536, 536, 536, 536, 536, 534, 534, 534, 534, 534, 532, 532, 532, 532, 532, 530, 530, 530, 530, 530, 528, 528, 528, 528, 528, 526, 526, 526, 526, 526, 524, 524, 524, 524, 524, 522, 522, 522, 522, 522, 520, 520, 520, 520, 520, 520, 518, 518, 518, 518, 518, 516, 516, 516, 516, 516, 514, 514, 514, 514, 514, 514, 512, 512, 512, 512, 512, 510, 510, 510, 510, 510, 510, 508, 508, 508, 508, 508, 506, 506, 506, 506, 506, 506, 504, 504, 504, 504, 504, 502, 502, 502, 502, 502, 502, 500, 500, 500, 500, 500, 500, 498, 498, 498, 498, 498, 498, 496, 496, 496, 496, 496, 496, 494, 494, 494, 494, 494, 494, 492, 492, 492, 492, 492, 492, 490, 490, 490, 490, 490, 490, 488, 488, 488, 488, 488, 488, 486, 486, 486, 486, 486, 486, 484, 484, 484, 484, 484, 484, 484, 0, 0, 0, 0, 0}; -static uint32_t cs8400f_fast[]={8743, 8205, 7017, 6201, 4938, 4016, 3371, 2966, 2682, 2469, 2296, 2159, 2041, 1942, 1857, 1782, 1716, 1656, 1602, 1554, 1510, 1470, 1432, 1398, 1366, 1336, 1309, 1282, 1258, 1235, 1213, 1193, 1173, 1154, 1137, 1120, 1104, 1089, 1074, 1060, 1047, 1034, 1022, 1010, 998, 987, 976, 966, 956, 946, 937, 928, 919, 911, 902, 894, 887, 879, 872, 864, 858, 851, 844, 838, 832, 825, 819, 814, 808, 802, 797, 792, 786, 781, 776, 771, 766, 762, 757, 753, 748, 744, 740, 736, 731, 728, 724, 720, 716, 712, 709, 705, 701, 698, 695, 691, 688, 685, 682, 679, 675, 672, 669, 666, 664, 661, 658, 655, 652, 650, 647, 644, 642, 639, 637, 634, 632, 629, 627, 625, 622, 620, 618, 616, 613, 611, 609, 607, 605, 603, 601, 599, 597, 595, 593, 591, 589, 587, 585, 583, 581, 580, 578, 576, 574, 573, 571, 569, 567, 566, 564, 563, 561, 559, 558, 556, 555, 553, 552, 550, 549, 547, 546, 544, 543, 542, 540, 539, 537, 536, 535, 533, 532, 531, 529, 528, 527, 526, 524, 523, 522, 521, 519, 518, 517, 516, 515, 514, 512, 511, 510, 509, 508, 507, 506, 505, 504, 502, 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, 491, 490, 489, 488, 488, 487, 486, 485, 484, 483, 482, 481, 480, 479, 478, 477, 477, 476, 475, 474, 473, 472, 472, 471, 470, 469, 468, 467, 467, 466, 465, 464, 464, 463, 462, 461, 460, 460, 459, 458, 457, 457, 456, 455, 454, 454, 453, 452, 452, 451, 450, 449, 449, 448, 448, 447, 446, 446, 445, 444, 444, 443, 442, 442, 441, 440, 440, 439, 438, 438, 437, 437, 436, 435, 435, 434, 434, 433, 432, 432, 431, 431, 430, 429, 429, 428, 428, 427, 427, 426, 425, 425, 424, 424, 423, 423, 422, 422, 421, 421, 420, 420, 419, 419, 418, 417, 417, 416, 416, 416, 415, 414, 414, 414, 413, 412, 412, 412, 411, 411, 410, 410, 409, 409, 408, 408, 407, 407, 406, 406, 406, 405, 405, 404, 404, 403, 403, 402, 402, 402, 401, 401, 400, 400, 399, 399, 398, 398, 398, 397, 397, 396, 396, 396, 395, 395, 394, 394, 394, 393, 393, 392, 392, 392, 391, 391, 391, 390, 390, 389, 389, 389, 388, 388, 387, 387, 387, 386, 386, 385, 385, 385, 384, 384, 384, 383, 383, 383, 382, 382, 382, 381, 381, 381, 380, 380, 380, 379, 379, 379, 378, 378, 378, 377, 377, 377, 376, 376, 376, 375, 375, 375, 374, 374, 374, 373, 373, 373, 372, 372, 372, 371, 371, 371, 370, 370, 370, 370, 369, 369, 369, 368, 368, 368, 368, 367, 367, 367, 367, 366, 366, 366, 365, 365, 365, 365, 364, 364, 364, 363, 363, 363, 363, 362, 362, 362, 362, 361, 361, 361, 360, 360, 360, 360, 359, 359, 359, 358, 358, 358, 358, 357, 357, 357, 356, 356, 356, 356, 355, 355, 355, 355, 354, 354, 354, 354, 354, 353, 353, 353, 353, 352, 352, 352, 352, 352, 351, 351, 351, 351, 350, 350, 350, 350, 350, 349, 349, 349, 349, 348, 348, 348, 348, 348, 347, 347, 347, 347, 346, 346, 346, 346, 346, 345, 345, 345, 345, 344, 344, 344, 344, 344, 343, 343, 343, 343, 342, 342, 342, 342, 342, 341, 341, 341, 341, 340, 340, 340, 340, 340, 339, 339, 339, 339, 338, 338, 338, 338, 338, 337, 337, 337, 337, 337, 337, 336, 336, 336, 336, 336, 336, 335, 335, 335, 335, 335, 335, 334, 334, 334, 334, 334, 334, 333, 333, 333, 333, 333, 333, 332, 332, 332, 332, 332, 332, 331, 331, 331, 331, 331, 331, 330, 330, 330, 330, 330, 330, 329, 329, 329, 329, 329, 329, 328, 328, 328, 328, 328, 328, 327, 327, 327, 327, 327, 327, 326, 326, 326, 326, 326, 326, 325, 325, 325, 325, 325, 325, 324, 324, 324, 324, 324, 324, 323, 323, 323, 323, 323, 323, 322, 322, 322, 322, 322, 322, 321, 321, 321, 321, 321, 321, 320, 320, 320, 320, 320, 320, 319, 319, 319, 319, 319, 319, 318, 318, 318, 318, 318, 318, 317, 317, 317, 317, 317, 317, 316, 316, 316, 316, 316, 316, 315, 315, 315, 315, 315, 315, 314, 314, 314, 314, 314, 314, 313, 313, 313, 313, 313, 313, 312, 312, 312, 312, 312, 312, 311, 311, 311, 311, 311, 311, 310, 310, 310, 310, 310, 310, 309, 309, 309, 309, 309, 309, 308, 308, 308, 308, 308, 308, 307, 307, 307, 307, 307, 307, 306, 306, 306, 306, 306, 306, 305, 305, 305, 305, 305, 305, 304, 304, 304, 304, 304, 304, 303, 303, 303, 303, 303, 303, 302, 302, 302, 302, 302, 302, 302, 301, 301, 301, 301, 301, 301, 301, 301, 301, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 300, 0, 0, 0, 0, 0 }; -static uint32_t motor_speeds_cs8600f[] = { - 54612, 54612, 34604, 26280, 21708, 18688, 16564, 14936, 13652, 12616, - 11768, 11024, 10400, 9872, 9392, 8960, 8584, 8240, 7940, 7648, - 7404, 7160, 6948, 6732, 6544, 6376, 6208, 6056, 5912, 5776, - 5644, 5520, 5408, 5292, 5192, 5092, 5000, 4908, 4820, 4736, - 4660, 4580, 4508, 4440, 4368, 4304, 4240, 4184, 4124, 4068, - 4012, 3960, 3908, 3860, 3808, 3764, 3720, 3676, 3636, 3592, - 3552, 3516, 3476, 3440, 3400, 3368, 3332, 3300, 3268, 3236, - 3204, 3176, 3148, 3116, 3088, 3060, 3036, 3008, 2984, 2956, - 2932, 2908, 2884, 2860, 2836, 2816, 2796, 2772, 2752, 2732, - 2708, 2692, 2672, 2652, 2632, 2616, 2596, 2576, 2560, 2544, - 2528, 2508, 2492, 2476, 2460, 2444, 2432, 2416, 2400, 2384, - 2372, 2356, 2344, 2328, 2316, 2304, 2288, 2276, 2260, 2252, - 2236, 2224, 2212, 2200, 2188, 2176, 2164, 2156, 2144, 2132, - 2120, 2108, 2100, 2088, 2080, 2068, 2056, 2048, 2036, 2028, - 2020, 2008, 2000, 1988, 1980, 1972, 1964, 1952, 1944, 1936, - 1928, 1920, 1912, 1900, 1892, 1884, 1876, 1868, 1860, 1856, - 1848, 1840, 1832, 1824, 1816, 1808, 1800, 1796, 1788, 1780, - 1772, 1764, 1760, 1752, 1744, 1740, 1732, 1724, 1720, 1712, - 1708, 1700, 1692, 1688, 1680, 1676, 1668, 1664, 1656, 1652, - 1644, 1640, 1636, 1628, 1624, 1616, 1612, 1608, 1600, 1596, - 1592, 1584, 1580, 1576, 1568, 1564, 1560, 1556, 1548, 1544, - 1540, 1536, 1528, 1524, 1520, 1516, 1512, 1508, 1500, 0 -}; - -/** - * database of motor profiles - */ - -static Motor_Profile gl843_motors[]={ - /* KV-SS080 */ - {MOTOR_KVSS080, 8000, 1, kvss080}, - /* G4010/G4050/CS4400F */ - {MOTOR_G4050, 8016, 1, g4050_fast}, - {MOTOR_G4050, 11640, 1, cs4400f_fast}, - {MOTOR_G4050, 15624, 1, g4050_xpa}, - {MOTOR_G4050, 42752, 2, g4050_max}, - {MOTOR_G4050, 56064, 1, g4050_high}, - /* CS8400F */ - {MOTOR_CS8400F, 7200, 0, cs8400f_fast}, - { MOTOR_CS8600F, 0x59d8, 2, motor_speeds_cs8600f }, // FIXME: if the exposure is lower then we'll select another motor - { 0, 0, 0, NULL }, -}; diff --git a/backend/genesys_gl846.cc b/backend/genesys_gl846.cc deleted file mode 100644 index c5294b8..0000000 --- a/backend/genesys_gl846.cc +++ /dev/null @@ -1,3393 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2012-2013 Stéphane Voltz - - - 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. -*/ - -/** @file - * - * This file handles GL846 and GL845 ASICs since they are really close to each other. - */ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_gl846.h" - -#include - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl846_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_get_filter_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_get_lineart_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_get_bitset_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_get_gain4_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl846_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** - * compute the step multiplier used - */ -static int -gl846_get_step_multiplier (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - int value = 1; - - r = sanei_genesys_get_address (regs, 0x9d); - if (r != NULL) - { - value = (r->value & 0x0f)>>1; - value = 1 << value; - } - DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); - return value; -} - -/** @brief sensor profile - * search for the database of motor profiles and get the best one. Each - * profile is at a specific dpihw. Use LiDE 110 table by default. - * @param sensor_type sensor id - * @param dpi hardware dpi for the scan - * @return a pointer to a Sensor_Profile struct - */ -static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi) -{ - unsigned int i; - int idx; - - i=0; - idx=-1; - while(i=dpi - && sensors[i].dpimodel->ccd_type, xres); - return sensor_profile->exposure; -} - - -/** @brief sensor specific settings -*/ -static void gl846_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, int dpi) -{ - GenesysRegister *r; - int dpihw; - uint16_t exp; - - DBGSTART; - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpi); - - for (uint16_t addr = 0x16; addr < 0x1e; addr++) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - for (uint16_t addr = 0x52; addr < 0x52 + 9; addr++) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - /* set EXPDUMMY and CKxMAP */ - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpi); - Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw); - - sanei_genesys_set_reg_from_set(regs,REG_EXPDMY,(uint8_t)((sensor_profile->expdummy) & 0xff)); - - /* if no calibration has been done, set default values for exposures */ - exp = sensor.exposure.red; - if(exp==0) - { - exp=sensor_profile->expr; - } - sanei_genesys_set_double(regs,REG_EXPR,exp); - - exp = sensor.exposure.green; - if(exp==0) - { - exp=sensor_profile->expg; - } - sanei_genesys_set_double(regs,REG_EXPG,exp); - - exp = sensor.exposure.blue; - if(exp==0) - { - exp=sensor_profile->expb; - } - sanei_genesys_set_double(regs,REG_EXPB,exp); - - sanei_genesys_set_triple(regs,REG_CK1MAP,sensor_profile->ck1map); - sanei_genesys_set_triple(regs,REG_CK3MAP,sensor_profile->ck3map); - sanei_genesys_set_triple(regs,REG_CK4MAP,sensor_profile->ck4map); - - /* order of the sub-segments */ - dev->order=sensor_profile->order; - - r = sanei_genesys_get_address (regs, 0x17); - r->value = sensor_profile->r17; - - DBGCOMPLETED; -} - - -/** @brief set all registers to default values . - * This function is called only once at the beginning and - * fills register startup values for registers reused across scans. - * Those that are rarely modified or not modified are written - * individually. - * @param dev device structure holding register set to initialize - */ -static void -gl846_init_registers (Genesys_Device * dev) -{ - DBGSTART; - - dev->reg.clear(); - - SETREG (0x01,0x60); - SETREG (0x02,0x38); - SETREG (0x03,0x03); - SETREG (0x04,0x22); - SETREG (0x05,0x60); - SETREG (0x06,0x10); - SETREG (0x08,0x60); - SETREG (0x09,0x00); - SETREG (0x0a,0x00); - SETREG (0x0b,0x8b); - SETREG (0x0c,0x00); - SETREG (0x0d,0x00); - SETREG (0x10,0x00); - SETREG (0x11,0x00); - SETREG (0x12,0x00); - SETREG (0x13,0x00); - SETREG (0x14,0x00); - SETREG (0x15,0x00); - SETREG (0x16,0xbb); - SETREG (0x17,0x13); - SETREG (0x18,0x10); - SETREG (0x19,0x2a); - SETREG (0x1a,0x34); - SETREG (0x1b,0x00); - SETREG (0x1c,0x20); - SETREG (0x1d,0x06); - SETREG (0x1e,0xf0); - SETREG (0x1f,0x01); - SETREG (0x20,0x03); - SETREG (0x21,0x10); - SETREG (0x22,0x60); - SETREG (0x23,0x60); - SETREG (0x24,0x60); - SETREG (0x25,0x00); - SETREG (0x26,0x00); - SETREG (0x27,0x00); - SETREG (0x2c,0x00); - SETREG (0x2d,0x00); - SETREG (0x2e,0x80); - SETREG (0x2f,0x80); - SETREG (0x30,0x00); - SETREG (0x31,0x00); - SETREG (0x32,0x00); - SETREG (0x33,0x00); - SETREG (0x34,0x1f); - SETREG (0x35,0x00); - SETREG (0x36,0x40); - SETREG (0x37,0x00); - SETREG (0x38,0x2a); - SETREG (0x39,0xf8); - SETREG (0x3d,0x00); - SETREG (0x3e,0x00); - SETREG (0x3f,0x01); - SETREG (0x52,0x02); - SETREG (0x53,0x04); - SETREG (0x54,0x06); - SETREG (0x55,0x08); - SETREG (0x56,0x0a); - SETREG (0x57,0x00); - SETREG (0x58,0x59); - SETREG (0x59,0x31); - SETREG (0x5a,0x40); - SETREG (0x5e,0x1f); - SETREG (0x5f,0x01); - SETREG (0x60,0x00); - SETREG (0x61,0x00); - SETREG (0x62,0x00); - SETREG (0x63,0x00); - SETREG (0x64,0x00); - SETREG (0x65,0x00); - SETREG (0x67,0x7f); - SETREG (0x68,0x7f); - SETREG (0x69,0x01); - SETREG (0x6a,0x01); - SETREG (0x70,0x01); - SETREG (0x71,0x00); - SETREG (0x72,0x02); - SETREG (0x73,0x01); - SETREG (0x74,0x00); - SETREG (0x75,0x00); - SETREG (0x76,0x00); - SETREG (0x77,0x00); - SETREG (0x78,0x00); - SETREG (0x79,0x3f); - SETREG (0x7a,0x00); - SETREG (0x7b,0x09); - SETREG (0x7c,0x99); - SETREG (0x7d,0x20); - SETREG (0x7f,0x05); - SETREG (0x80,0x4f); - SETREG (0x87,0x02); - SETREG (0x94,0xff); - SETREG (0x9d,0x04); - SETREG (0x9e,0x00); - SETREG (0xa1,0xe0); - SETREG (0xa2,0x1f); - SETREG (0xab,0xc0); - SETREG (0xbb,0x00); - SETREG (0xbc,0x0f); - SETREG (0xdb,0xff); - SETREG (0xfe,0x08); - SETREG (0xff,0x02); - SETREG (0x98,0x20); - SETREG (0x99,0x00); - SETREG (0x9a,0x90); - SETREG (0x9b,0x00); - SETREG (0xf8,0x05); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - /* fine tune upon device description */ - dev->reg.find_reg(0x05).value &= ~REG05_DPIHW; - switch (sensor.optical_res) - { - case 600: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; - break; - case 4800: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_4800; - break; - } - - /* initalize calibration reg */ - dev->calib_reg = dev->reg; - - DBGCOMPLETED; -} - -/**@brief send slope table for motor movement - * Send slope_table in machine byte order - * @param dev device to send slope table - * @param table_nr index of the slope table in ASIC memory - * Must be in the [0-4] range. - * @param slope_table pointer to 16 bit values array of the slope table - * @param steps number of elements in the slope table - */ -static SANE_Status -gl846_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - char msg[10000]; - - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, - table_nr, steps); - - /* sanity check */ - if(table_nr<0 || table_nr>4) - { - DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); - return SANE_STATUS_INVAL; - } - - std::vector table(steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), "%d", slope_table[i]); - } - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - /* slope table addresses are fixed */ - status = sanei_genesys_write_ahb(dev, 0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: write to AHB failed writing slope table %d (%s)\n", __func__, table_nr, - sane_strstatus(status)); - } - - DBGCOMPLETED; - return status; -} - -/** - * Set register values of Analog Device type frontend - * */ -static SANE_Status -gl846_set_adi_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - uint8_t val8; - - DBGSTART; - - /* wait for FE to be ready */ - status = sanei_genesys_get_status (dev, &val8); - while (val8 & REG41_FEBUSY) - { - sanei_genesys_sleep_ms(10); - status = sanei_genesys_get_status (dev, &val8); - }; - - if (set == AFE_INIT) - { - DBG (DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - dev->frontend = dev->frontend_initial; - } - - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg0: %s\n", __func__, - sane_strstatus (status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to write reg1: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - for (i = 0; i < 3; i++) - { - status = sanei_genesys_fe_write_data(dev, 0x02 + i, dev->frontend.get_gain(i)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write gain %d: %s\n", __func__, i, - sane_strstatus (status)); - return status; - } - } - for (i = 0; i < 3; i++) - { - status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.get_offset(i)); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to write offset %d: %s\n", __func__, i, - sane_strstatus (status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl846_homsnr_gpio(Genesys_Device *dev) -{ -uint8_t val; -SANE_Status status=SANE_STATUS_GOOD; - - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val |= 0x41; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - - return status; -} - -/* Set values of analog frontend */ -static SANE_Status -gl846_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) -{ - (void) sensor; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (%s)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : - set == AFE_POWER_SAVE ? "powersave" : "huh?"); - - /* route to specific analog frontend setup */ - switch (dev->reg.find_reg(0x04).value & REG04_FESET) - { - case 0x02: /* ADI FE */ - status = gl846_set_adi_fe(dev, set); - break; - default: - DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, - dev->reg.find_reg(0x04).value & REG04_FESET); - status = SANE_STATUS_UNSUPPORTED; - } - - DBGCOMPLETED; - return status; -} - - -/** @brief set up motor related register for scan - */ -static SANE_Status -gl846_init_motor_regs_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - int scan_power_mode, - unsigned int flags) -{ - SANE_Status status = SANE_STATUS_GOOD; - int use_fast_fed; - unsigned int fast_dpi; - uint16_t scan_table[SLOPE_TABLE_SIZE]; - uint16_t fast_table[SLOPE_TABLE_SIZE]; - int scan_steps, fast_steps, factor; - unsigned int feedl, dist; - GenesysRegister *r; - uint32_t z1, z2; - unsigned int min_restep = 0x20; - uint8_t val; - int fast_step_type; - unsigned int ccdlmt,tgtime; - - DBGSTART; - DBG(DBG_proc, "%s : scan_exposure_time=%d, scan_yres=%g, scan_step_type=%d, scan_lines=%d, " - "scan_dummy=%d, feed_steps=%d, scan_power_mode=%d, flags=%x\n", __func__, scan_exposure_time, - scan_yres, scan_step_type, scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); - - /* get step multiplier */ - factor = gl846_get_step_multiplier (reg); - - use_fast_fed=0; - /* no fast fed since feed works well */ - if(dev->settings.yres==4444 && feed_steps>100 - && ((flags & MOTOR_FLAG_FEED)==0)) - { - use_fast_fed=1; - } - DBG (DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); - - sanei_genesys_set_triple(reg, REG_LINCNT, scan_lines); - DBG (DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); - - /* compute register 02 value */ - r = sanei_genesys_get_address (reg, REG02); - r->value = 0x00; - sanei_genesys_set_motor_power(*reg, true); - - if (use_fast_fed) - r->value |= REG02_FASTFED; - else - r->value &= ~REG02_FASTFED; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= REG02_AGOHOME | REG02_NOTHOME; - - if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - ||(scan_yres>=sensor.optical_res)) - { - r->value |= REG02_ACDCDIS; - } - - /* scan and backtracking slope table */ - sanei_genesys_slope_table(scan_table, - &scan_steps, - scan_yres, - scan_exposure_time, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - gl846_motors); - RIE(gl846_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); - RIE(gl846_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); - - /* fast table */ - fast_dpi=sanei_genesys_get_lowest_ydpi(dev); - fast_step_type=scan_step_type; - if(scan_step_type>=2) - { - fast_step_type=2; - } - - sanei_genesys_slope_table(fast_table, - &fast_steps, - fast_dpi, - scan_exposure_time, - dev->motor.base_ydpi, - fast_step_type, - factor, - dev->model->motor_type, - gl846_motors); - - /* manual override of high start value */ - fast_table[0]=fast_table[1]; - - RIE(gl846_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); - RIE(gl846_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); - RIE(gl846_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); - - /* correct move distance by acceleration and deceleration amounts */ - feedl=feed_steps; - if (use_fast_fed) - { - feedl<<=fast_step_type; - dist=(scan_steps+2*fast_steps)*factor; - /* TODO read and decode REGAB */ - r = sanei_genesys_get_address (reg, 0x5e); - dist += (r->value & 31); - /* FEDCNT */ - r = sanei_genesys_get_address (reg, REG_FEDCNT); - dist += r->value; - } - else - { - feedl<<=scan_step_type; - dist=scan_steps*factor; - if (flags & MOTOR_FLAG_FEED) - dist *=2; - } - DBG (DBG_io2, "%s: scan steps=%d\n", __func__, scan_steps); - DBG (DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); - - /* check for overflow */ - if(distvalue & REG0C_CCDLMT)+1; - - r = sanei_genesys_get_address (reg, REG1C); - tgtime=1<<(r->value & REG1C_TGTIME); - - /* hi res motor speed GPIO */ - /* - RIE (sanei_genesys_read_register (dev, REG6C, &effective)); - */ - - /* if quarter step, bipolar Vref2 */ - /* XXX STEF XXX GPIO - if (scan_step_type > 1) - { - if (scan_step_type < 3) - { - val = effective & ~REG6C_GPIO13; - } - else - { - val = effective | REG6C_GPIO13; - } - } - else - { - val = effective; - } - RIE (sanei_genesys_write_register (dev, REG6C, val)); - */ - - /* effective scan */ - /* - RIE (sanei_genesys_read_register (dev, REG6C, &effective)); - val = effective | REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - */ - - if(dev->model->gpo_type==GPO_IMG101) - { - if(scan_yres==sanei_genesys_compute_dpihw(dev, sensor,scan_yres)) - { - val=1; - } - else - { - val=0; - } - RIE (sanei_genesys_write_register (dev, REG7E, val)); - } - - min_restep=scan_steps/2-1; - if (min_restep < 1) - min_restep = 1; - r = sanei_genesys_get_address (reg, REG_FWDSTEP); - r->value = min_restep; - r = sanei_genesys_get_address (reg, REG_BWDSTEP); - r->value = min_restep; - - sanei_genesys_calculate_zmode2(use_fast_fed, - scan_exposure_time*ccdlmt*tgtime, - scan_table, - scan_steps*factor, - feedl, - min_restep*factor, - &z1, - &z2); - - DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); - sanei_genesys_set_triple(reg, REG60, z1 | (scan_step_type << (16+REG60S_STEPSEL))); - - DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); - sanei_genesys_set_triple(reg, REG63, z2 | (scan_step_type << (16+REG63S_FSTPSEL))); - - r = sanei_genesys_get_address (reg, 0x1e); - r->value &= 0xf0; /* 0 dummy lines */ - r->value |= scan_dummy; /* dummy lines */ - - r = sanei_genesys_get_address (reg, REG67); - r->value = 0x7f; - - r = sanei_genesys_get_address (reg, REG68); - r->value = 0x7f; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FSHDEC); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FMOVNO); - r->value = fast_steps; - - r = sanei_genesys_get_address (reg, REG_FMOVDEC); - r->value = fast_steps; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** @brief set up registers related to sensor - * Set up the following registers - 0x01 - 0x03 - 0x10-0x015 R/G/B exposures - 0x19 EXPDMY - 0x2e BWHI - 0x2f BWLO - 0x04 - 0x87 - 0x05 - 0x2c,0x2d DPISET - 0x30,0x31 STRPIXEL - 0x32,0x33 ENDPIXEL - 0x35,0x36,0x37 MAXWD [25:2] (>>2) - 0x38,0x39 LPERIOD - 0x34 DUMMY - */ -static SANE_Status -gl846_init_optical_regs_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int exposure_time, - int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, ColorFilter color_filter, int flags) -{ - unsigned int words_per_line; - unsigned int startx, endx, used_pixels; - unsigned int dpiset, dpihw,segnb,cksel,factor; - unsigned int bytes; - GenesysRegister *r; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s : exposure_time=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", __func__, exposure_time, used_res, start, pixels, channels, depth, - half_ccd, flags); - - /* resolution is divided according to CKSEL */ - r = sanei_genesys_get_address (reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - DBG(DBG_io2, "%s: cksel=%d\n", __func__, cksel); - - /* to manage high resolution device while keeping good - * low resolution scanning speed, we make hardware dpi vary */ - dpihw=sanei_genesys_compute_dpihw(dev, sensor, used_res * cksel); - factor=sensor.optical_res/dpihw; - DBG(DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); - - /* sensor parameters */ - Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, dpihw); - gl846_setup_sensor(dev, sensor, reg, dpihw); - dpiset = used_res * cksel; - - /* start and end coordinate in optical dpi coordinates */ - startx = start/cksel+sensor.CCD_start_xoffset; - used_pixels=pixels/cksel; - - /* end of sensor window */ - endx = startx + used_pixels; - - /* sensors are built from 600 dpi segments for LiDE 100/200 - * and 1200 dpi for the 700F */ - if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR) - { - segnb=dpihw/600; - } - else - { - segnb=1; - } - - /* compute pixel coordinate in the given dpihw space, - * taking segments into account */ - startx/=factor*segnb; - endx/=factor*segnb; - dev->len=endx-startx; - dev->dist=0; - dev->skip=0; - - /* in cas of multi-segments sensor, we have to add the witdh - * of the sensor crossed by the scan area */ - if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR && segnb>1) - { - dev->dist = sensor_profile->segcnt; - } - - /* use a segcnt rounded to next even number */ - endx += ((dev->dist+1)&0xfffe)*(segnb-1); - used_pixels=endx-startx; - - status = gl846_set_fe(dev, sensor, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, REG01); - r->value &= ~REG01_SCAN; - r->value |= REG01_SHDAREA; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - r->value &= ~REG01_DVDSET; - } - else - { - r->value |= REG01_DVDSET; - } - - r = sanei_genesys_get_address (reg, REG03); - r->value &= ~REG03_AVEENB; - - sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); - - /* BW threshold */ - r = sanei_genesys_get_address (reg, 0x2e); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, 0x2f); - r->value = dev->settings.threshold; - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, REG04); - switch (depth) - { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - r->value &= ~(REG04_FILTER | REG04_AFEMOD); - if (channels == 1) - { - switch (color_filter) - { - case ColorFilter::RED: - r->value |= 0x24; - break; - case ColorFilter::BLUE: - r->value |= 0x2c; - break; - case ColorFilter::GREEN: - r->value |= 0x28; - break; - default: - break; // should not happen - } - } - else - r->value |= 0x20; /* mono */ - - /* register 05 */ - r = sanei_genesys_get_address (reg, REG05); - - /* set up dpihw */ - r->value &= ~REG05_DPIHW; - switch(dpihw) - { - case 600: - r->value |= REG05_DPIHW_600; - break; - case 1200: - r->value |= REG05_DPIHW_1200; - break; - case 2400: - r->value |= REG05_DPIHW_2400; - break; - case 4800: - r->value |= REG05_DPIHW_4800; - break; - } - - /* enable gamma tables */ - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - /* CIS scanners can do true gray by setting LEDADD */ - /* we set up LEDADD only when asked */ - if (dev->model->is_cis == SANE_TRUE) - { - r = sanei_genesys_get_address (reg, 0x87); - r->value &= ~REG87_LEDADD; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG87_LEDADD; - } - /* RGB weighting - r = sanei_genesys_get_address (reg, 0x01); - r->value &= ~REG01_TRUEGRAY; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG01_TRUEGRAY; - }*/ - } - - /* words(16bit) before gamma, conversion to 8 bit or lineart*/ - words_per_line = (used_pixels * dpiset) / dpihw; - bytes=depth/8; - if (depth == 1) - { - words_per_line = (words_per_line+7)/8 ; - dev->len = (dev->len >> 3) + ((dev->len & 7) ? 1 : 0); - dev->dist = (dev->dist >> 3) + ((dev->dist & 7) ? 1 : 0); - } - else - { - words_per_line *= bytes; - dev->dist *= bytes; - dev->len *= bytes; - } - - dev->bpl = words_per_line; - dev->cur=0; - dev->segnb=segnb; - dev->line_interp = 0; - - sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); - - sanei_genesys_set_double(reg,REG_STRPIXEL,startx); - sanei_genesys_set_double(reg,REG_ENDPIXEL,endx); - DBG (DBG_io2, "%s: startx=%d\n", __func__, startx); - DBG (DBG_io2, "%s: endx =%d\n", __func__, endx); - - DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->segnb =%lu\n", __func__, (unsigned long)dev->segnb); - - words_per_line *= channels; - dev->wpl = words_per_line; - - dev->oe_buffer.clear(); - dev->oe_buffer.alloc(dev->wpl); - - /* MAXWD is expressed in 4 words unit */ - sanei_genesys_set_triple(reg, REG_MAXWD, (words_per_line >> 2)); - DBG (DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); - - sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); - DBG (DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); - - r = sanei_genesys_get_address (reg, 0x34); - r->value = sensor.dummy_pixel; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -static SANE_Status -gl846_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SetupParams& params) -{ - params.assert_valid(); - - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; - unsigned int oflags; /**> optical flags */ - unsigned int mflags; /**> motor flags */ - int exposure_time; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int scan_power_mode = 0; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - - /* we may have 2 domains for ccd: xres below or above half ccd max dpi */ - if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) - { - half_ccd = SANE_TRUE; - } - else - { - half_ccd = SANE_FALSE; - } - - /* optical_res */ - optical_res = sensor.optical_res; - if (half_ccd) - optical_res /= 2; - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG(DBG_info, "%s : stagger=%d lines\n", __func__, stagger); - - /* used_res */ - if (params.flags & SCAN_FLAG_USE_OPTICAL_RES) - { - used_res = optical_res; - } - else - { - /* resolution is choosen from a list */ - used_res = params.xres; - } - - /* compute scan parameters values */ - /* pixels are allways given at full optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - /* add x coordinates */ - start = params.startx; - - if (stagger > 0) - start |= 1; - - /* compute correct pixels number */ - /* pixels */ - used_pixels = (params.pixels * optical_res) / params.xres; - - /* round up pixels number if needed */ - if (used_pixels * params.xres < params.pixels * optical_res) - used_pixels++; - - dummy = 3-params.channels; - -/* slope_dpi */ -/* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = params.yres * params.channels; - else - slope_dpi = params.yres; - - slope_dpi = slope_dpi * (1 + dummy); - - exposure_time = gl846_compute_exposure (dev, used_res); - scan_step_type = sanei_genesys_compute_step_type(gl846_motors, dev->model->motor_type, exposure_time); - - DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); - -/*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if (params.flags & SCAN_FLAG_DYNAMIC_LINEART) { - params.depth = 8; - } - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - oflags = 0; - if(params.flags & SCAN_FLAG_DISABLE_SHADING) - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - if(params.flags & SCAN_FLAG_DISABLE_GAMMA) - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - if(params.flags & SCAN_FLAG_DISABLE_LAMP) - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - - if (dev->model->is_cis && dev->settings.true_gray) - { - oflags |= OPTICAL_FLAG_ENABLE_LEDADD; - } - - status = gl846_init_optical_regs_scan (dev, sensor, - reg, - exposure_time, - used_res, - start, - used_pixels, - params.channels, - params.depth, - half_ccd, - params.color_filter, - oflags); - - if (status != SANE_STATUS_GOOD) - return status; - -/*** motor parameters ***/ - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,params.channels,params.yres,params.flags); - - /* lincnt */ - lincnt = params.lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = params.starty; - DBG(DBG_info, "%s: move=%d steps\n", __func__, move); - - mflags=0; - if(params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) - mflags |= MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; - if(params.flags & SCAN_FLAG_FEEDING) - mflags |= MOTOR_FLAG_FEED; - - status = gl846_init_motor_regs_scan (dev, sensor, - reg, - exposure_time, - slope_dpi, - scan_step_type, - dev->model->is_cis ? lincnt * - params.channels : lincnt, dummy, move, - scan_power_mode, - mflags); - - if (status != SANE_STATUS_GOOD) - return status; - - - /*** prepares data reordering ***/ - -/* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * params.channels * params.depth) / 8; - - requested_buffer_size = 8 * bytes_per_line; - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * params.channels * params.depth) / 8; - - dev->read_buffer.clear(); - dev->read_buffer.alloc(read_buffer_size); - - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(read_buffer_size); - - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(requested_buffer_size); - - dev->out_buffer.clear(); - dev->out_buffer.alloc((8 * params.pixels * params.channels * params.depth) / 8); - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - -/* TODO: should this be done elsewhere? */ - /* scan bytes to send to the frontend */ - /* theory : - target_size = - (params.pixels * params.lines * channels * depth) / 8; - but it suffers from integer overflow so we do the following: - - 1 bit color images store color data byte-wise, eg byte 0 contains - 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains - 8 bits of blue. - This does not fix the overflow, though. - 644mp*16 = 10gp, leading to an overflow - -- pierre - */ - - dev->total_bytes_read = 0; - if (params.depth == 1) - dev->total_bytes_to_read = - ((params.pixels * params.lines) / 8 + - (((params.pixels * params.lines) % 8) ? 1 : 0)) * - params.channels; - else - dev->total_bytes_to_read = - params.pixels * params.lines * params.channels * (params.depth / 8); - - DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); -/* END TODO */ - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static void -gl846_calculate_current_setup(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int depth; - int start; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure_time; - int stagger; - - int slope_dpi; - int dummy = 0; - int max_shift; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - /* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * sensor.optical_res) / MM_PER_INCH; - - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; // not used - params.starty = 0; // not used - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = 0; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) { - half_ccd = SANE_TRUE; - } else { - half_ccd = SANE_FALSE; - } - - /* optical_res */ - optical_res = sensor.optical_res; - - /* stagger */ - if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG(DBG_info, "%s: stagger=%d lines\n", __func__, stagger); - - /* resolution is choosen from a fixed list */ - used_res = params.xres; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - - /* compute correct pixels number */ - used_pixels = (params.pixels * optical_res) / used_res; - dummy = 3 - params.channels; - - /* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) { - slope_dpi = params.yres * params.channels; - } else { - slope_dpi = params.yres; - } - - slope_dpi = slope_dpi * (1 + dummy); - - exposure_time = gl846_compute_exposure (dev, used_res); - DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - max_shift = sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); - - /* lincnt */ - lincnt = params.lines + max_shift + stagger; - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBGCOMPLETED; -} - -/*for fast power saving methods only, like disabling certain amplifiers*/ -static SANE_Status -gl846_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl846_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl846_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -static SANE_Status -gl846_stop_action (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val40, val; - unsigned int loop; - - DBGSTART; - - /* post scan gpio : without that HOMSNR is unreliable */ - gl846_homsnr_gpio(dev); - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBG(DBG_info, "%s: already stopped\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* ends scan */ - val = dev->reg.get8(REG01); - val &= ~REG01_SCAN; - dev->reg.set8(REG01, val); - status = sanei_genesys_write_register (dev, REG01, val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_sleep_ms(100); - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) - && !(val & REG41_MOTORENB)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - sanei_genesys_sleep_ms(100); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - -/* Send the low-level scan command */ -static SANE_Status -gl846_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - (void) sensor; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - GenesysRegister *r; - - DBGSTART; - - /* XXX STEF XXX SCAN GPIO */ - /* - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - RIE (sanei_genesys_write_register (dev, REG6C, val)); - */ - - val = REG0D_CLRLNCNT; - RIE (sanei_genesys_write_register (dev, REG0D, val)); - val = REG0D_CLRMCNT; - RIE (sanei_genesys_write_register (dev, REG0D, val)); - - RIE (sanei_genesys_read_register (dev, REG01, &val)); - val |= REG01_SCAN; - RIE (sanei_genesys_write_register (dev, REG01, val)); - r = sanei_genesys_get_address (reg, REG01); - r->value = val; - - if (start_motor) - { - RIE (sanei_genesys_write_register (dev, REG0F, 1)); - } - else - { - RIE (sanei_genesys_write_register (dev, REG0F, 0)); - } - - DBGCOMPLETED; - - return status; -} - - -/* Send the stop scan command */ -static SANE_Status -gl846_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); - if (reg == NULL) - return SANE_STATUS_INVAL; - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl846_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -/* Moves the slider to the home (top) postion slowly */ -static SANE_Status -gl846_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - float resolution; - uint8_t val; - int loop = 0; - ScanColorMode scan_mode; - - DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); - - /* post scan gpio : without that HOMSNR is unreliable */ - gl846_homsnr_gpio(dev); - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - sanei_genesys_sleep_ms(100); - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - /* is sensor at home? */ - if (val & HOMESNR) - { - DBG(DBG_info, "%s: already at home, completed\n", __func__); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - local_reg = dev->reg; - - resolution=sanei_genesys_get_lowest_ydpi(dev); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - /* TODO add scan_mode to the API */ - scan_mode= dev->settings.scan_mode; - dev->settings.scan_mode = ScanColorMode::LINEART; - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 100; - params.starty = 30000; - params.pixels = 100; - params.lines = 100; - params.depth = 8; - params.channels = 1; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::RED; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl846_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - dev->settings.scan_mode=scan_mode; - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse */ - r = sanei_genesys_get_address(&local_reg, REG02); - r->value |= REG02_MTRREV; - - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - - try { - status = gl846_start_action(dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl846_stop_action(dev); - } catch (...) {} - try { - // restore original registers - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl846_stop_action (dev); - /* send original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - /* post scan gpio : without that HOMSNR is unreliable */ - gl846_homsnr_gpio(dev); - - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - if (val & HOMESNR) /* home sensor */ - { - DBG(DBG_info, "%s: reached home position\n", __func__); - gl846_stop_action (dev); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl846_stop_action (dev); - DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - DBG(DBG_info, "%s: scanhead is still moving\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl846_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg; - int steps; - - int pixels = 600; - int dpi = 300; - - DBG(DBG_proc, "%s\n", __func__); - - local_reg = dev->reg; - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - // FIXME: the current approach of doing search only for one resolution does not work on scanners - // whith employ different sensors with potentially different settings. - auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); - - SetupParams params; - params.xres = dpi; - params.yres = dpi; - params.startx = 0; - params.starty = 0; /*we should give a small offset here~60 steps */ - params.pixels = 600; - params.lines = dev->model->search_lines; - params.depth = 8; - params.channels = 1; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::GREEN; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl846_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* send to scanner */ - status = dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - size = pixels * dev->model->search_lines; - - std::vector data(size); - - status = gl846_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl846_search_position.pnm", data.data(), 8, 1, pixels, - dev->model->search_lines); - - status = gl846_end_scan (dev, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* update regs to copy ASIC internal state */ - dev->reg = local_reg; - -/*TODO: find out where sanei_genesys_search_reference_point - stores information, and use that correctly*/ - status = - sanei_genesys_search_reference_point (dev, sensor, data.data(), 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl846_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t channels; - uint8_t cksel; - - DBG(DBG_proc, "%s\n", __func__); - - - cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else { - channels = 1; - } - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = 0; - params.starty = 0; - params.pixels = sensor.optical_res / cksel; - params.lines = 20; - params.depth = 16; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl846_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, - sensor.optical_res / cksel, dev->settings.xres); - - status = dev->model->cmd_set->bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move in base_dpi line count - * */ -static SANE_Status -gl846_feed (Genesys_Device * dev, unsigned int steps) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - float resolution; - uint8_t val; - - DBGSTART; - DBG(DBG_io, "%s: steps=%d\n", __func__, steps); - - /* prepare local registers */ - local_reg = dev->reg; - - resolution=sanei_genesys_get_lowest_ydpi(dev); - const auto& sensor = sanei_genesys_find_sensor(dev, resolution); - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 0; - params.starty = steps; - params.pixels = 100; - params.lines = 3; - params.depth = 8; - params.channels = 3; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_FEEDING | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl846_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* set exposure to zero */ - sanei_genesys_set_triple(&local_reg,REG_EXPR,0); - sanei_genesys_set_triple(&local_reg,REG_EXPG,0); - sanei_genesys_set_triple(&local_reg,REG_EXPB,0); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); - - /* set up for no scan */ - r = sanei_genesys_get_address(&local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* send registers */ - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - - try { - status = gl846_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl846_stop_action(dev); - } catch (...) {} - try { - // restore original registers - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl846_stop_action (dev); - - /* restore original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - /* wait until feed count reaches the required value, but do not - * exceed 30s */ - do - { - status = sanei_genesys_get_status (dev, &val); - } - while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); - - /* then stop scanning */ - RIE(gl846_stop_action (dev)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -static SANE_Status -gl846_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - float move; - - DBGSTART; - dev->calib_channels = 3; - - /* initial calibration reg values */ - regs = dev->reg; - - dev->calib_resolution = sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); - dev->calib_total_bytes_to_read = 0; - dev->calib_lines = dev->model->shading_lines; - if(dev->calib_resolution==4800) - dev->calib_lines *= 2; - dev->calib_pixels = (sensor.sensor_pixels*dev->calib_resolution)/sensor.optical_res; - DBG(DBG_io, "%s: calib_lines = %d\n", __func__, (unsigned int)dev->calib_lines); - DBG(DBG_io, "%s: calib_pixels = %d\n", __func__, (unsigned int)dev->calib_pixels); - - /* this is aworkaround insufficent distance for slope - * motor acceleration TODO special motor slope for shading */ - move=1; - if(dev->calib_resolution<1200) - { - move=40; - } - - SetupParams params; - params.xres = dev->calib_resolution; - params.yres = dev->calib_resolution; - params.startx = 0; - params.starty = move; - params.pixels = dev->calib_pixels; - params.lines = dev->calib_lines; - params.depth = 16; - params.channels = dev->calib_channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl846_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = dev->model->cmd_set->bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* we use GENESYS_FLAG_SHADING_REPARK */ - dev->scanhead_position_in_steps = 0; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief set up registers for the actual scan - */ -static SANE_Status -gl846_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - /* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - - /* steps to move to reach scanning area: - - first we move to physical start of scanning - either by a fixed steps amount from the black strip - or by a fixed amount from parking position, - minus the steps done during shading calibration - - then we move by the needed offset whitin physical - scanning area - - assumption: steps are expressed at maximum motor resolution - - we need: - SANE_Fixed y_offset; - SANE_Fixed y_size; - SANE_Fixed y_offset_calib; - mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ - - /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is - relative from origin, else, it is from parking position */ - - move_dpi = dev->motor.base_ydpi; - - move = SANE_UNFIX (dev->model->y_offset); - move += dev->settings.tl_y; - move = (move * move_dpi) / MM_PER_INCH; - move -= dev->scanhead_position_in_steps; - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - /* fast move to scan area */ - /* we don't move fast the whole distance since it would involve - * computing acceleration/deceleration distance for scan - * resolution. So leave a remainder for it so scan makes the final - * move tuning */ - if(channels*dev->settings.yres>=600 && move>700) - { - status = gl846_feed (dev, move-500); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to move to scan area\n", __func__); - return status; - } - move=500; - } - - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * sensor.optical_res) / MM_PER_INCH; - - flags = 0; - - /* emulated lineart from gray data is required for now */ - if(dev->settings.scan_mode == ScanColorMode::LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - /* backtracking isn't handled well, so don't enable it */ - flags |= SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; - params.starty = move; - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = flags; - - status = gl846_init_scan_regs(dev, sensor, &dev->reg, params); - - if (status != SANE_STATUS_GOOD) - return status; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -static SANE_Status -gl846_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t addr, length, i, x, factor, pixels; - uint32_t dpiset, dpihw, strpixel, endpixel; - uint16_t tempo; - uint32_t lines, channels; - uint8_t val,*ptr,*src; - - DBGSTART; - DBG(DBG_io2, "%s: writing %d bytes of shading data\n", __func__, size); - - /* shading data is plit in 3 (up to 5 with IR) areas - write(0x10014000,0x00000dd8) - URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x.... - write(0x1003e000,0x00000dd8) - write(0x10068000,0x00000dd8) - */ - length = (uint32_t) (size / 3); - sanei_genesys_get_double(&dev->reg,REG_STRPIXEL,&tempo); - strpixel=tempo; - sanei_genesys_get_double(&dev->reg,REG_ENDPIXEL,&tempo); - endpixel=tempo; - - /* compute deletion factor */ - sanei_genesys_get_double(&dev->reg,REG_DPISET,&tempo); - dpiset=tempo; - DBG(DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n", __func__, strpixel, endpixel, - endpixel-strpixel, dpiset); - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpiset); - factor=dpihw/dpiset; - DBG(DBG_io2, "%s: factor=%d\n", __func__, factor); - - if(DBG_LEVEL>=DBG_data) - { - dev->binary=fopen("binary.pnm","wb"); - sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &lines); - channels=dev->current_setup.channels; - if(dev->binary!=NULL) - { - fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); - } - } - - pixels=endpixel-strpixel; - - /* since we're using SHDAREA, substract startx coordinate from shading */ - strpixel-=((sensor.CCD_start_xoffset*600)/sensor.optical_res); - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; - pixels*=2*2; - - std::vector buffer(pixels, 0); - - DBG(DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n", __func__, pixels, pixels); - - /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address - * is 8192*reg value */ - - /* write actual color channel data */ - for(i=0;i<3;i++) - { - /* build up actual shading data by copying the part from the full width one - * to the one corresponding to SHDAREA */ - ptr = buffer.data(); - - /* iterate on both sensor segment */ - for(x=0;xmodel->y_offset_calib); - move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; - if(move>20) - { - RIE(gl846_feed (dev, move)); - } - DBG(DBG_io, "%s: move=%f steps\n", __func__, move); - - /* offset calibration is always done in color mode */ - channels = 3; - depth=16; - used_res=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); - Sensor_Profile* sensor_profile = get_sensor_profile(dev->model->ccd_type, used_res); - num_pixels = (sensor.sensor_pixels*used_res)/sensor.optical_res; - - /* initial calibration reg values */ - regs = dev->reg; - - SetupParams params; - params.xres = used_res; - params.yres = used_res; - params.startx = 0; - params.starty = 0; - params.pixels = num_pixels; - params.lines = 1; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl846_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ - std::vector line(total_size); - - /* initial loop values and boundaries */ - exp[0]=sensor_profile->expr; - exp[1]=sensor_profile->expg; - exp[2]=sensor_profile->expb; - - bottom[0]=29000; - bottom[1]=29000; - bottom[2]=29000; - - top[0]=41000; - top[1]=51000; - top[2]=51000; - - turn = 0; - - /* no move during led calibration */ - sanei_genesys_set_motor_power(regs, false); - do - { - /* set up exposure */ - sanei_genesys_set_double(®s,REG_EXPR,exp[0]); - sanei_genesys_set_double(®s,REG_EXPG,exp[1]); - sanei_genesys_set_double(®s,REG_EXPB,exp[2]); - - /* write registers and scan data */ - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - - DBG(DBG_info, "%s: starting line reading\n", __func__); - RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); - - /* stop scanning */ - RIE(gl846_stop_action(dev)); - - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl846_led_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), depth, channels, num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - /* check if exposure gives average within the boundaries */ - acceptable = SANE_TRUE; - for(i=0;i<3;i++) - { - if(avg[i]top[i]) - { - exp[i]=(exp[i]*top[i])/avg[i]; - acceptable = SANE_FALSE; - } - } - - turn++; - } - while (!acceptable && turn < 100); - - DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); - - /* set these values as final ones for scan */ - sanei_genesys_set_double(&dev->reg,REG_EXPR,exp[0]); - sanei_genesys_set_double(&dev->reg,REG_EXPG,exp[1]); - sanei_genesys_set_double(&dev->reg,REG_EXPB,exp[2]); - - /* store in this struct since it is the one used by cache calibration */ - sensor.exposure.red = exp[0]; - sensor.exposure.green = exp[1]; - sensor.exposure.blue = exp[2]; - - /* go back home */ - if(move>20) - { - status=gl846_slow_back_home (dev, SANE_TRUE); - } - - DBGCOMPLETED; - return status; -} - -/** - * set up GPIO/GPOE for idle state - */ -static SANE_Status -gl846_init_gpio (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx=0; - - DBGSTART; - - /* search GPIO profile */ - while(gpios[idx].sensor_id!=0 && dev->model->gpo_type!=gpios[idx].sensor_id) - { - idx++; - } - if(gpios[idx].sensor_id==0) - { - DBG(DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __func__, - dev->model->ccd_type); - return SANE_STATUS_INVAL; - } - - RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); - RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); - - RIE (sanei_genesys_write_register (dev, REG6B, gpios[idx].r6b)); - RIE (sanei_genesys_write_register (dev, REG6C, gpios[idx].r6c)); - RIE (sanei_genesys_write_register (dev, REG6D, gpios[idx].r6d)); - RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); - RIE (sanei_genesys_write_register (dev, REG6F, gpios[idx].r6f)); - - RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); - RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); - - DBGCOMPLETED; - return status; -} - -/** - * set memory layout by filling values in dedicated registers - */ -static SANE_Status -gl846_init_memory_layout (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx = 0, i; - uint8_t val; - - DBGSTART - - /* point to per model memory layout */ - idx = 0; - while(layouts[idx].model!=NULL && strcmp(dev->model->name,layouts[idx].model)!=0) - { - if(strcmp(dev->model->name,layouts[idx].model)!=0) - idx++; - } - if(layouts[idx].model==NULL) - { - DBG(DBG_error, "%s: failed to find memory layout for model %s!\n", __func__, dev->model->name); - return SANE_STATUS_INVAL; - } - - /* CLKSET and DRAMSEL */ - val = layouts[idx].dramsel; - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg.find_reg(0x0b).value = val; - - /* prevent further writings by bulk write register */ - dev->reg.remove_reg(0x0b); - - /* setup base address for shading and scanned data. */ - for(i=0;i<10;i++) - { - sanei_genesys_write_register (dev, 0xe0+i, layouts[idx].rx[i]); - } - - DBGCOMPLETED; - return status; -} - -/* * - * initialize ASIC from power on condition - */ -static SANE_Status -gl846_boot (Genesys_Device * dev, SANE_Bool cold) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - DBGSTART; - - /* reset ASIC if cold boot */ - if(cold) - { - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - } - - if(dev->usb_mode == 1) - { - val = 0x14; - } - else - { - val = 0x11; - } - RIE (sanei_genesys_write_0x8c (dev, 0x0f, val)); - - /* test CHKVER */ - RIE (sanei_genesys_read_register (dev, REG40, &val)); - if (val & REG40_CHKVER) - { - RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); - } - - /* Set default values for registers */ - gl846_init_registers (dev); - - /* Write initial registers */ - RIE (dev->model->cmd_set->bulk_write_register(dev, dev->reg)); - - /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ - val = dev->reg.find_reg(0x0b).value & REG0B_DRAMSEL; - val = (val | REG0B_ENBDRAM); - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg.find_reg(0x0b).value = val; - - /* CIS_LINE */ - if (dev->model->is_cis) - { - SETREG (0x08, REG08_CIS_LINE); - RIE (sanei_genesys_write_register (dev, 0x08, dev->reg.find_reg(0x08).value)); - } - - /* set up clocks */ - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0e)); - RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); - - /* setup gpio */ - RIE (gl846_init_gpio (dev)); - - /* setup internal memory layout */ - RIE (gl846_init_memory_layout (dev)); - - SETREG (0xf8, 0x05); - RIE (sanei_genesys_write_register (dev, 0xf8, dev->reg.find_reg(0xf8).value)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -static SANE_Status gl846_init(Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG_INIT (); - DBGSTART; - - status=sanei_genesys_asic_init(dev, 0); - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl846_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not lose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - uint8_t scan, file, email, copy; - switch(s->dev->model->gpo_type) - { - default: - scan=0x01; - file=0x02; - email=0x04; - copy=0x08; - } - RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); - - s->buttons[BUTTON_SCAN_SW].write((val & scan) == 0); - s->buttons[BUTTON_FILE_SW].write((val & file) == 0); - s->buttons[BUTTON_EMAIL_SW].write((val & email) == 0); - s->buttons[BUTTON_COPY_SW].write((val & copy) == 0); - - return status; -} - -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl846_search_strip(Genesys_Device * dev, const Genesys_Sensor& sensor, - SANE_Bool forward, SANE_Bool black) -{ - unsigned int pixels, lines, channels; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg; - size_t size; - int steps, depth, dpi; - unsigned int pass, count, found, x, y; - char title[80]; - GenesysRegister *r; - - DBG(DBG_proc, "%s %s %s\n", __func__, black ? "black" : "white", forward ? "forward" : "reverse"); - - status = gl846_set_fe(dev, sensor, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl846_set_fe() failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl846_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* set up for a gray scan at lowest dpi */ - dpi = 9600; - for (x = 0; x < MAX_RESOLUTIONS; x++) - { - if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) - dpi = dev->model->xdpi_values[x]; - } - channels = 1; - /* 10 MM */ - /* lines = (10 * dpi) / MM_PER_INCH; */ - /* shading calibation is done with dev->motor.base_ydpi */ - lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; - depth = 8; - pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; - size = pixels * channels * lines * (depth / 8); - std::vector data(size); - - dev->scanhead_position_in_steps = 0; - - local_reg = dev->reg; - - SetupParams params; - params.xres = dpi; - params.yres = dpi; - params.startx = 0; - params.starty = 0; - params.pixels = pixels; - params.lines = lines; - params.depth = depth; - params.channels = channels; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::RED; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA; - - status = gl846_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* set up for reverse or forward */ - r = sanei_genesys_get_address (&local_reg, REG02); - if (forward) - r->value &= ~REG02_MTRREV; - else - r->value |= REG02_MTRREV; - - - status = dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl846_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl846_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl846_stop_action failed\n", __func__); - return status; - } - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - sprintf(title, "gl846_search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < 20 && !found) - { - status = dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* now start scan */ - status = gl846_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl846_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl846_stop_action failed\n", __func__); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf(title, "gl846_search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, - pass, y); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - pass++; - } - - if (found) - { - status = SANE_STATUS_GOOD; - DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG(DBG_info, "%s: %s strip not found\n", __func__, black ? "black" : "white"); - } - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a 8 bits scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black) -{ - unsigned int i, j, k, average, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average value on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG(DBG_info, "%s: average = %d\n", __func__, average); - return average; -} - -static SANE_Status -gl846_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t reg04; - unsigned int channels, bpp; - int pass = 0, avg, total_size; - int topavg, bottomavg, resolution, lines; - int top, bottom, black_pixels, pixels; - - DBGSTART; - - /* no gain nor offset for AKM AFE */ - RIE (sanei_genesys_read_register (dev, REG04, ®04)); - if ((reg04 & REG04_FESET) == 0x02) - { - DBGCOMPLETED; - return status; - } - - /* offset calibration is always done in color mode */ - channels = 3; - resolution=sensor.optical_res; - dev->calib_pixels = sensor.sensor_pixels; - lines=1; - bpp=8; - pixels= (sensor.sensor_pixels*resolution) / sensor.optical_res; - black_pixels = (sensor.black_pixels * resolution) / sensor.optical_res; - DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 0; - params.starty = 0; - params.pixels = pixels; - params.lines = lines; - params.depth = bpp; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl846_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_set_motor_power(regs, false); - - /* allocate memory for scans */ - total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ - - std::vector first_line(total_size); - std::vector second_line(total_size); - - /* init gain */ - dev->frontend.set_gain(0, 0); - dev->frontend.set_gain(1, 0); - dev->frontend.set_gain(2, 0); - - /* scan with no move */ - bottom = 10; - dev->frontend.set_offset(0, bottom); - dev->frontend.set_offset(1, bottom); - dev->frontend.set_offset(2, bottom); - - RIE(gl846_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting first line reading\n", __func__); - RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, first_line.data(), total_size)); - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl846_offset%03d.pnm", bottom); - sanei_genesys_write_pnm_file(fn, first_line.data(), bpp, channels, pixels, lines); - } - - bottomavg = dark_average(first_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); - - /* now top value */ - top = 255; - dev->frontend.set_offset(0, top); - dev->frontend.set_offset(1, top); - dev->frontend.set_offset(2, top); - RIE(gl846_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); - - topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.set_offset(0, (top + bottom) / 2); - dev->frontend.set_offset(1, (top + bottom) / 2); - dev->frontend.set_offset(2, (top + bottom) / 2); - - /* scan with no move */ - RIE(gl846_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl846_offset%03d.pnm", dev->frontend.get_offset(1)); - sanei_genesys_write_pnm_file(fn, second_line.data(), bpp, channels, pixels, lines); - } - - avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.get_offset(1); - } - else - { - bottomavg = avg; - bottom = dev->frontend.get_offset(1); - } - } - DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl846_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, int dpi) -{ - int pixels; - int total_size; - uint8_t reg04; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3],coeff; - int val, code, lines; - int resolution; - int bpp; - - DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); - - /* no gain nor offset for AKM AFE */ - RIE (sanei_genesys_read_register (dev, REG04, ®04)); - if ((reg04 & REG04_FESET) == 0x02) - { - DBGCOMPLETED; - return status; - } - - /* coarse gain calibration is always done in color mode */ - channels = 3; - - /* follow CKSEL */ - if(dev->settings.xressettings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - try { - status = gl846_init_scan_regs(dev, sensor, ®s, params); - } catch (...) { - try { - sanei_genesys_set_motor_power(regs, false); - } catch (...) {} - throw; - } - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - RIE (dev->model->cmd_set->bulk_write_register(dev, regs)); - - total_size = pixels * channels * (16/bpp) * lines; - - std::vector line(total_size); - - RIE(gl846_set_fe(dev, sensor, AFE_SET)); - RIE(gl846_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl846_gain.pnm", line.data(), bpp, channels, pixels, lines); - - /* average value on each channel */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = pixels/4; i < (pixels*3/4); i++) - { - if (dev->model->is_cis) - val = line[i + j * pixels]; - else - val = line[i * channels + j]; - - max[j] += val; - } - max[j] = max[j] / (pixels/2); - - gain[j] = ((float) sensor.gain_white_ref*coeff) / max[j]; - - /* turn logical gain value into gain code, checking for overflow */ - code = 283 - 208 / gain[j]; - if (code > 255) - code = 255; - else if (code < 0) - code = 0; - dev->frontend.set_gain(j, code); - - DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], - dev->frontend.get_gain(j)); - } - - if (dev->model->is_cis) { - uint8_t gain0 = dev->frontend.get_gain(0); - if (gain0 > dev->frontend.get_gain(1)) { - gain0 = dev->frontend.get_gain(1); - } - if (gain0 > dev->frontend.get_gain(2)) { - gain0 = dev->frontend.get_gain(2); - } - dev->frontend.set_gain(0, gain0); - dev->frontend.set_gain(1, gain0); - dev->frontend.set_gain(2, gain0); - } - - RIE (gl846_stop_action (dev)); - - status=gl846_slow_back_home (dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - - -/** the gl846 command set */ -static Genesys_Command_Set gl846_cmd_set = { - "gl846-generic", /* the name of this set */ - - nullptr, - - gl846_init, - NULL, - gl846_init_regs_for_coarse_calibration, - gl846_init_regs_for_shading, - gl846_init_regs_for_scan, - - gl846_get_filter_bit, - gl846_get_lineart_bit, - gl846_get_bitset_bit, - gl846_get_gain4_bit, - gl846_get_fast_feed_bit, - gl846_test_buffer_empty_bit, - gl846_test_motor_flag_bit, - - gl846_set_fe, - gl846_set_powersaving, - gl846_save_power, - - gl846_begin_scan, - gl846_end_scan, - - sanei_genesys_send_gamma_table, - - gl846_search_start_position, - - gl846_offset_calibration, - gl846_coarse_gain_calibration, - gl846_led_calibration, - - NULL, - gl846_slow_back_home, - NULL, - - sanei_genesys_bulk_write_register, - NULL, - sanei_genesys_bulk_read_data, - - gl846_update_hardware_sensors, - - NULL, - NULL, - NULL, - gl846_search_strip, - - sanei_genesys_is_compatible_calibration, - NULL, - gl846_send_shading_data, - gl846_calculate_current_setup, - gl846_boot -}; - -SANE_Status -sanei_gl846_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl846_cmd_set; - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_gl846.h b/backend/genesys_gl846.h deleted file mode 100644 index 797c605..0000000 --- a/backend/genesys_gl846.h +++ /dev/null @@ -1,498 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2012-2013 Stéphane Voltz - - 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 "genesys.h" - -#define REG01 0x01 -#define REG01_CISSET 0x80 -#define REG01_DOGENB 0x40 -#define REG01_DVDSET 0x20 -#define REG01_STAGGER 0x10 -#define REG01_COMPENB 0x08 -#define REG01_TRUEGRAY 0x04 -#define REG01_SHDAREA 0x02 -#define REG01_SCAN 0x01 - -#define REG02 0x02 -#define REG02_NOTHOME 0x80 -#define REG02_ACDCDIS 0x40 -#define REG02_AGOHOME 0x20 -#define REG02_MTRPWR 0x10 -#define REG02_FASTFED 0x08 -#define REG02_MTRREV 0x04 -#define REG02_HOMENEG 0x02 -#define REG02_LONGCURV 0x01 - -#define REG03 0x03 -#define REG03_LAMPDOG 0x80 -#define REG03_AVEENB 0x40 -#define REG03_XPASEL 0x20 -#define REG03_LAMPPWR 0x10 -#define REG03_LAMPTIM 0x0f - -#define REG04 0x04 -#define REG04_LINEART 0x80 -#define REG04_BITSET 0x40 -#define REG04_AFEMOD 0x30 -#define REG04_FILTER 0x0c -#define REG04_FESET 0x03 - -#define REG04S_AFEMOD 4 - -#define REG05 0x05 -#define REG05_DPIHW 0xc0 -#define REG05_DPIHW_600 0x00 -#define REG05_DPIHW_1200 0x40 -#define REG05_DPIHW_2400 0x80 -#define REG05_DPIHW_4800 0xc0 -#define REG05_MTLLAMP 0x30 -#define REG05_GMMENB 0x08 -#define REG05_MTLBASE 0x03 - -#define REG06_SCANMOD 0xe0 -#define REG06S_SCANMOD 5 -#define REG06_PWRBIT 0x10 -#define REG06_GAIN4 0x08 -#define REG06_OPTEST 0x07 - -#define REG07_LAMPSIM 0x80 - -#define REG08_DRAM2X 0x80 -#define REG08_MPENB 0x20 -#define REG08_CIS_LINE 0x10 -#define REG08_IR1ENB 0x08 -#define REG08_IR2ENB 0x04 -#define REG08_ENB24M 0x01 - -#define REG09_MCNTSET 0xc0 -#define REG09_EVEN1ST 0x20 -#define REG09_BLINE1ST 0x10 -#define REG09_BACKSCAN 0x08 -#define REG09_ENHANCE 0x04 -#define REG09_SHORTTG 0x02 -#define REG09_NWAIT 0x01 - -#define REG09S_MCNTSET 6 -#define REG09S_CLKSET 4 - - -#define REG0A_LPWMEN 0x10 - -#define REG0B 0x0b -#define REG0B_DRAMSEL 0x07 -#define REG0B_ENBDRAM 0x08 -#define REG0B_ENBDRAM 0x08 -#define REG0B_RFHDIS 0x10 -#define REG0B_CLKSET 0xe0 -#define REG0B_24MHZ 0x00 -#define REG0B_30MHZ 0x20 -#define REG0B_40MHZ 0x40 -#define REG0B_48MHZ 0x60 -#define REG0B_60MHZ 0x80 - -#define REG0C 0x0c -#define REG0C_CCDLMT 0x0f - -#define REG0D 0x0d -#define REG0D_SCSYNC 0x40 -#define REG0D_CLRERR 0x20 -#define REG0D_FULLSTP 0x10 -#define REG0D_SEND 0x80 -#define REG0D_CLRMCNT 0x04 -#define REG0D_CLRDOCJM 0x02 -#define REG0D_CLRLNCNT 0x01 - -#define REG0F 0x0f - -#define REG16_CTRLHI 0x80 -#define REG16_TOSHIBA 0x40 -#define REG16_TGINV 0x20 -#define REG16_CK1INV 0x10 -#define REG16_CK2INV 0x08 -#define REG16_CTRLINV 0x04 -#define REG16_CKDIS 0x02 -#define REG16_CTRLDIS 0x01 - -#define REG17_TGMODE 0xc0 -#define REG17_TGMODE_NO_DUMMY 0x00 -#define REG17_TGMODE_REF 0x40 -#define REG17_TGMODE_XPA 0x80 -#define REG17_TGW 0x3f -#define REG17S_TGW 0 - -#define REG18 0x18 -#define REG18_CNSET 0x80 -#define REG18_DCKSEL 0x60 -#define REG18_CKTOGGLE 0x10 -#define REG18_CKDELAY 0x0c -#define REG18_CKSEL 0x03 - -#define REG1A_SW2SET 0x80 -#define REG1A_SW1SET 0x40 -#define REG1A_MANUAL3 0x02 -#define REG1A_MANUAL1 0x01 -#define REG1A_CK4INV 0x08 -#define REG1A_CK3INV 0x04 -#define REG1A_LINECLP 0x02 - -#define REG1C 0x1c -#define REG1C_TGTIME 0x07 - -#define REG1D_CK4LOW 0x80 -#define REG1D_CK3LOW 0x40 -#define REG1D_CK1LOW 0x20 -#define REG1D_TGSHLD 0x1f -#define REG1DS_TGSHLD 0 - - -#define REG1E_WDTIME 0xf0 -#define REG1ES_WDTIME 4 -#define REG1E_LINESEL 0x0f -#define REG1ES_LINESEL 0 - -#define REG_FEDCNT 0x1f - -#define REG24 0x1c -#define REG40 0x40 -#define REG40_DOCSNR 0x80 -#define REG40_ADFSNR 0x40 -#define REG40_COVERSNR 0x20 -#define REG40_CHKVER 0x10 -#define REG40_DOCJAM 0x08 -#define REG40_HISPDFLG 0x04 -#define REG40_MOTMFLG 0x02 -#define REG40_DATAENB 0x01 - -#define REG41_PWRBIT 0x80 -#define REG41_BUFEMPTY 0x40 -#define REG41_FEEDFSH 0x20 -#define REG41_SCANFSH 0x10 -#define REG41_HOMESNR 0x08 -#define REG41_LAMPSTS 0x04 -#define REG41_FEBUSY 0x02 -#define REG41_MOTORENB 0x01 - -#define REG58_VSMP 0xf8 -#define REG58S_VSMP 3 -#define REG58_VSMPW 0x07 -#define REG58S_VSMPW 0 - -#define REG59_BSMP 0xf8 -#define REG59S_BSMP 3 -#define REG59_BSMPW 0x07 -#define REG59S_BSMPW 0 - -#define REG5A_ADCLKINV 0x80 -#define REG5A_RLCSEL 0x40 -#define REG5A_CDSREF 0x30 -#define REG5AS_CDSREF 4 -#define REG5A_RLC 0x0f -#define REG5AS_RLC 0 - -#define REG5E_DECSEL 0xe0 -#define REG5ES_DECSEL 5 -#define REG5E_STOPTIM 0x1f -#define REG5ES_STOPTIM 0 - -#define REG60 0x60 -#define REG60_Z1MOD 0x1f -#define REG61 0x61 -#define REG61_Z1MOD 0xff -#define REG62 0x62 -#define REG62_Z1MOD 0xff - -#define REG63 0x63 -#define REG63_Z2MOD 0x1f -#define REG64 0x64 -#define REG64_Z2MOD 0xff -#define REG65 0x65 -#define REG65_Z2MOD 0xff - -#define REG60S_STEPSEL 5 -#define REG60_STEPSEL 0xe0 -#define REG60_FULLSTEP 0x00 -#define REG60_HALFSTEP 0x20 -#define REG60_EIGHTHSTEP 0x60 -#define REG60_16THSTEP 0x80 - -#define REG63S_FSTPSEL 5 -#define REG63_FSTPSEL 0xe0 -#define REG63_FULLSTEP 0x00 -#define REG63_HALFSTEP 0x20 -#define REG63_EIGHTHSTEP 0x60 -#define REG63_16THSTEP 0x80 - -#define REG67 0x67 -#define REG67_MTRPWM 0x80 - -#define REG68 0x68 -#define REG68_FASTPWM 0x80 - -#define REG6B 0x6b -#define REG6B_MULTFILM 0x80 -#define REG6B_GPOM13 0x40 -#define REG6B_GPOM12 0x20 -#define REG6B_GPOM11 0x10 -#define REG6B_GPO18 0x02 -#define REG6B_GPO17 0x01 - -#define REG6C 0x6c -#define REG6C_GPIO16 0x80 -#define REG6C_GPIO15 0x40 -#define REG6C_GPIO14 0x20 -#define REG6C_GPIO13 0x10 -#define REG6C_GPIO12 0x08 -#define REG6C_GPIO11 0x04 -#define REG6C_GPIO10 0x02 -#define REG6C_GPIO9 0x01 -#define REG6C_GPIOH 0xff -#define REG6C_GPIOL 0xff - -#define REG6D 0x6d -#define REG6E 0x6e -#define REG6F 0x6f -#define REG7E 0x7e - -#define REG87_ACYCNRLC 0x10 -#define REG87_ENOFFSET 0x08 -#define REG87_LEDADD 0x04 -#define REG87_CK4ADC 0x02 -#define REG87_AUTOCONF 0x01 - -#define REG9E 0x9e -#define REG9F 0x9f - -#define REGA6 0xa6 -#define REGA7 0xa7 -#define REGA8 0xa8 -#define REGA9 0xa9 -#define REGAB 0xab - -#define REG_EXPR 0x10 -#define REG_EXPG 0x12 -#define REG_EXPB 0x14 -#define REG_EXPDMY 0x19 -#define REG_STEPNO 0x21 -#define REG_FWDSTEP 0x22 -#define REG_BWDSTEP 0x23 -#define REG_FASTNO 0x24 -#define REG_DPISET 0x2c -#define REG_STRPIXEL 0x30 -#define REG_ENDPIXEL 0x32 -#define REG_LINCNT 0x25 -#define REG_MAXWD 0x35 -#define REG_LPERIOD 0x38 -#define REG_FEEDL 0x3d -#define REG_FMOVDEC 0x5f -#define REG_FSHDEC 0x69 -#define REG_FMOVNO 0x6a -#define REG_CK1MAP 0x74 -#define REG_CK3MAP 0x77 -#define REG_CK4MAP 0x7a - -#define REGF8 0xf8 -#define REGF8_MAXSEL 0xf0 -#define REGF8_SMAXSEL 4 -#define REGF8_MINSEL 0x0f - -#define SETREG(adr,val) { dev->reg.init_reg(adr, val); } - - -/** set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -static SANE_Status gl846_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, SetupParams& params); - -/* Send the low-level scan command */ -static SANE_Status gl846_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, SANE_Bool start_motor); - -/* Send the stop scan command */ -static SANE_Status gl846_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool check_stop); - -static SANE_Status gl846_init (Genesys_Device * dev); - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move - * */ -static SANE_Status -gl846_feed (Genesys_Device * dev, unsigned int steps); - -static SANE_Status -gl846_stop_action (Genesys_Device * dev); - -static SANE_Status -gl846_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home); - -static SANE_Status -gl846_boot (Genesys_Device * dev, SANE_Bool cold); - - - -typedef struct -{ - uint8_t sensor_id; - uint8_t r6b; - uint8_t r6c; - uint8_t r6d; - uint8_t r6e; - uint8_t r6f; - uint8_t ra6; - uint8_t ra7; - uint8_t ra8; - uint8_t ra9; -} Gpio_Profile; - -static Gpio_Profile gpios[]={ - { GPO_IMG101, 0x72, 0x1f, 0xa4, 0x13, 0xa7, 0x11, 0xff, 0x19, 0x05}, - { GPO_PLUSTEK3800, 0x30, 0x01, 0x80, 0x2d, 0x80, 0x0c, 0x8f, 0x08, 0x04}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -}; - -typedef struct -{ - const char *model; - uint8_t dramsel; - /* shading data address */ - uint8_t rd0; - uint8_t rd1; - uint8_t rd2; - /* scanned data address */ - uint8_t rx[24]; -} Memory_layout; - -static Memory_layout layouts[]={ - /* Image formula 101 */ - { - "canon-image-formula-101", - 0x8b, - 0x0a, 0x1b, 0x00, - { /* RED ODD START / RED ODD END */ - 0x00, 0xb0, 0x05, 0xe7, /* [0x00b0, 0x05e7] 1336*4000w */ - /* RED EVEN START / RED EVEN END */ - 0x05, 0xe8, 0x0b, 0x1f, /* [0x05e8, 0x0b1f] */ - /* GREEN ODD START / GREEN ODD END */ - 0x0b, 0x20, 0x10, 0x57, /* [0x0b20, 0x1057] */ - /* GREEN EVEN START / GREEN EVEN END */ - 0x10, 0x58, 0x15, 0x8f, /* [0x1058, 0x158f] */ - /* BLUE ODD START / BLUE ODD END */ - 0x15, 0x90, 0x1a, 0xc7, /* [0x1590,0x1ac7] */ - /* BLUE EVEN START / BLUE EVEN END */ - 0x1a, 0xc8, 0x1f, 0xff /* [0x1ac8,0x1fff] */ - } - }, - /* OpticBook 3800 */ - { - "plustek-opticbook-3800", - 0x2a, - 0x0a, 0x0a, 0x0a, - { /* RED ODD START / RED ODD END */ - 0x00, 0x68, 0x03, 0x00, - /* RED EVEN START / RED EVEN END */ - 0x03, 0x01, 0x05, 0x99, - /* GREEN ODD START / GREEN ODD END */ - 0x05, 0x9a, 0x08, 0x32, - /* GREEN EVEN START / GREEN EVEN END */ - 0x08, 0x33, 0x0a, 0xcb, - /* BLUE ODD START / BLUE ODD END */ - 0x0a, 0xcc, 0x0d, 0x64, - /* BLUE EVEN START / BLUE EVEN END */ - 0x0d, 0x65, 0x0f, 0xfd - } - }, - /* list terminating entry */ - { NULL, 0, 0, 0, 0, {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0} } -}; - -/** @brief structure for sensor settings - * this structure describes the sensor settings to use for a given - * exposure. - */ -typedef struct { - int sensor_type; /**> sensor id */ - int dpi; /**> maximum dpi for which data are valid */ - int exposure; /**> exposure */ - int ck1map; /**> CK1MAP */ - int ck3map; /**> CK3MAP */ - int ck4map; /**> CK4MAP */ - int segcnt; /**> SEGCNT */ - int expdummy; /**> exposure dummy */ - int expr; /**> initial red exposure */ - int expg; /**> initial green exposure */ - int expb; /**> initial blue exposure */ - size_t *order; /**> order of sub-segments */ - uint8_t r17; /**> TG width */ -} Sensor_Profile; - -/** - * order of the scanned pixel - */ -static size_t order_01[]={0,1}; - -/** - * database of sensor profiles - */ -static Sensor_Profile sensors[]={ - {CCD_IMG101, 1200, 11000, 60, 159, 85, 5136, 255, 0, 0, 0, order_01 , 0x13}, - {CCD_PLUSTEK3800, 1200, 11000, 60, 159, 85, 5136, 255, 0, 0, 0, order_01 , 0x13}, -}; - -/* base motor slopes in full step unit */ -/* target=((exposure * dpi) / base_dpi)>>step_type; */ -static uint32_t img101_high[] = {22000, 22000, 22000, 18450, 15974, 14284, 13054, 12076, 11286, 10660, 10100, 9632, 9224, 8864, 8532, 8250, 7986, 7750, 7530, 7330, 7142, 6972, 6810, 6656, 6518, 6384, 6264, 6150, 6038, 5930, 5834, 5732, 5642, 5560, 5476, 5398, 5324, 5252, 5180, 5112, 5050, 4990, 4926, 4868, 4816, 4760, 4708, 4658, 4608, 4562, 4516, 4472, 4428, 4384, 4344, 4306, 4266, 4230, 4194, 4156, 4122, 4088, 4054, 4022, 3990, 3960, 3930, 3900, 3872, 3842, 3816, 3790, 3762, 3736, 3710, 3686, 3662, 3638, 3614, 3590, 3570, 3548, 3526, 3506, 3484, 3462, 3442, 3424, 3402, 3384, 3366, 3346, 3328, 3310, 3292, 3276, 3258, 3242, 3224, 3208, 3192, 3176, 3162, 3146, 3130, 3114, 3100, 3086, 3072, 3058, 3044, 3030, 3016, 3002, 2990, 2976, 2964, 2950, 2938, 2926, 2914, 2902, 2890, 2878, 2866, 2854, 2844, 2832, 2820, 2810, 2800, 2790, 2778, 2768, 2756, 2748, 2738, 2726, 2716, 2708, 2698, 2688, 2678, 2668, 2660, 2650, 2642, 2632, 2624, 2616, 2606, 2598, 2588, 2580, 2572, 2564, 2556, 2548, 2540, 2530, 2522, 2516, 2508, 2500, 2492, 2486, 2476, 2470, 2462, 2454, 2448, 2440, 2434, 2426, 2420, 2412, 2406, 2400, 2392, 2386, 2378, 2372, 2366, 2360, 2354, 2346, 2340, 2334, 2328, 2322, 2314, 2310, 2304, 2296, 2292, 2286, 2280, 2274, 2268, 2262, 2256, 2252, 2246, 2240, 2234, 2230, 2224, 2218, 2214, 2208, 2202, 2196, 2192, 2188, 2182, 2176, 2172, 2166, 2162, 2156, 2152, 2146, 2142, 2136, 2132, 2128, 2124, 2118, 2114, 2108, 2104, 2100, 2096, 2092, 2086, 2082, 2078, 2072, 2068, 2064, 2060, 2056, 2052, 2048, 2044, 2038, 2034, 2030, 2026, 2022, 2018, 2014, 2010, 2006, 2002, 1998, 1994, 1990, 1988, 1984, 1980, 1976, 1972, 1968, 1964, 1960, 1956, 1952, 1950, 1946, 1942, 1938, 1934, 1932, 1928, 1924, 1920, 1918, 1914, 1910, 1908, 1904, 1900, 1898, 1894, 1890, 1888, 1884, 1880, 1878, 1874, 1870, 1868, 1864, 1862, 1858, 1854, 1852, 1848, 1846, 1842, 1840, 1836, 1834, 1830, 1828, 1824, 1822, 1818, 1816, 1812, 1810, 1806, 1804, 1800, 1798, 1794, 1792, 1790, 1786, 1784, 1780, 1778, 1776, 1772, 1770, 1768, 1764, 1762, 1758, 1756, 1754, 1752, 1748, 1746, 1744, 1740, 1738, 1736, 1734, 1730, 1728, 1726, 1724, 1720, 1718, 1716, 1714, 1710, 1708, 1706, 1704, 1700, 1698, 1696, 1694, 1692, 1688, 1686, 1684, 1682, 1680, 1676, 1674, 1672, 1670, 1668, 1666, 1664, 1662, 1660, 1656, 1654, 1652, 1650, 1648, 1646, 1644, 1642, 1638, 1636, 1634, 1632, 1630, 1628, 1626, 1624, 1622, 1620, 1618, 1616, 1614, 1612, 1610, 1608, 1606, 1604, 1602, 1600, 1598, 1596, 1594, 1592, 1590, 1588, 1586, 1584, 1582, 1580, 1578, 1576, 1574, 1572, 1570, 1568, 1566, 1564, 1562, 1560, 1558, 1556, 1556, 1554, 1552, 1550, 1548, 1546, 1544, 1542, 1540, 1538, 1536, 1536, 1534, 1532, 1530, 1528, 1526, 1524, 1522, 1522, 1520, 1518, 1516, 1514, 1512, 1510, 1510, 1508, 1506, 1504, 1502, 1500, 1500, 1498, 1496, 1494, 1492, 1490, 1490, 1488, 1486, 1484, 1482, 1482, 1480, 1478, 1476, 1474, 1474, 1472, 1470, 1468, 1466, 1466, 1464, 1462, 1460, 1460, 1458, 1456, 1454, 1454, 1452, 1450, 1448, 1448, 1446, 1444, 1442, 1442, 1440, 1438, 1438, 1436, 1434, 1432, 1432, 1430, 1428, 1426, 1426, 1424, 1422, 1422, 1420, 1418, 1418, 1416, 1414, 1412, 1412, 1410, 1408, 1408, 1406, 1404, 1404, 1402, 1400, 1400, 1398, 1396, 1394, 1394, 1392, 1390, 1390, 1388, 1388, 1386, 1384, 1384, 1382, 1380, 1380, 1378, 1376, 1376, 1374, 1374, 1372, 1370, 1370, 1368, 1366, 1366, 1364, 1362, 1362, 1360, 1360, 1358, 1356, 1356, 1354, 1352, 1352, 1350, 1350, 1348, 1348, 1346, 1344, 1344, 1342, 1340, 1340, 1338, 1338, 1336, 1336, 1334, 1332, 1332, 1330, 1330, 1328, 1328, 1326, 1324, 1324, 1322, 1322, 1320, 1318, 1318, 1316, 1316, 1314, 1314, 1312, 1310, 1310, 1308, 1308, 1306, 1306, 1304, 1304, 1302, 1302, 1300, 1300, 1298, 1298, 1296, 1294, 1294, 1292, 1292, 1290, 1290, 1288, 1288, 1286, 1286, 1284, 1284, 1282, 1282, 1280, 1280, 1278, 1278, 1276, 1276, 1274, 1272, 1272, 1270, 1270, 1270, 1268, 1268, 1266, 1264, 1264, 1262, 1262, 1260, 1260, 1260, 1258, 1258, 1256, 1254, 1254, 1254, 1252, 1252, 1250, 1250, 1248, 1248, 1246, 1246, 1244, 1244, 1242, 1242, 1240, 1240, 1238, 1238, 1236, 1236, 1236, 1234, 1234, 1232, 1232, 1230, 1230, 1228, 1228, 1226, 1226, 1226, 1224, 1224, 1222, 1222, 1220, 1220, 1218, 1218, 1218, 1216, 1216, 1214, 1214, 1212, 1212, 1210, 1210, 1210, 1208, 1208, 1206, 1206, 1204, 1204, 1204, 1202, 1202, 1200, 1200, 1198, 1198, 1198, 1196, 1196, 1194, 1194, 1192, 1192, 1192, 1190, 1190, 1188, 1188, 1188, 1186, 1186, 1184, 1184, 1182, 1182, 1182, 1180, 1180, 1180, 1178, 1178, 1176, 1176, 1174, 1174, 1174, 1172, 1172, 1172, 1170, 1170, 1168, 1168, 1168, 1166, 1166, 1164, 1164, 1164, 1162, 1162, 1160, 1160, 1160, 1158, 1158, 1156, 1156, 1156, 1154, 1154, 1154, 1152, 1152, 1152, 1150, 1150, 1148, 1148, 1148, 1146, 1146, 1146, 1144, 1144, 1142, 1142, 1142, 1140, 1140, 1140, 1138, 1138, 1136, 1136, 1136, 1134, 1134, 1134, 1132, 1132, 1132, 1130, 1130, 1130, 1128, 1128, 1126, 1126, 1126, 1124, 1124, 1124, 1122, 1122, 1122, 1120, 1120, 1120, 1118, 1118, 1118, 1116, 1116, 1116, 1114, 1114, 1114, 1112, 1112, 1112, 1110, 1110, 1110, 1108, 1108, 1108, 1106, 1106, 1106, 1104, 1104, 1104, 1102, 1102, 1102, 1100, 1100, 1100, 1098, 1098, 1098, 1096, 1096, 1096, 1094, 1094, 1094, 1092, 1092, 1092, 1090, 1090, 1090, 1088, 1088, 1088, 1086, 1086, 1086, 1086, 1084, 1084, 1084, 1082, 1082, 1082, 1080, 1080, 1080, 1078, 1078, 1078, 1078, 1076, 1076, 1076, 1074, 1074, 1074, 1072, 1072, 1072, 1072, 1070, 1070, 1070, 1068, 1068, 1068, 1066, 1066, 1066, 1064, 1064, 1064, 1064, 1062, 1062, 1062, 1060, 1060, 1060, 1058, 1058, 1058, 1058, 1056, 1056, 1056, 1054, 1054, 1054, 1054, 1052, 1052, 1052, 1050, 1050, 1050, 1050, 1048, 1048, 1048, 1046, 1046, 1046, 1046, 1044, 1044, 1044, 1044, 1042, 1042, 1042, 1040, 1040, 1040, 1040, 1038, 1038, 1038, 1036, 1036, 1036, 1036, 1034, 1034, 1034, 1034, 1032, 1032, 1032, 1030, 1030, 1030, 1030, 1028, 1028, 1028, 1028, 1026, 1026, 1026, 1026, 1024, 1024, 1024, 1022, 1022, 1022, 1022, 1020, 1020, 1020, 1020, 1018, 1018, 1018, 1018, 1016, 1016, 1016, 1016, 1014, 1014, 1014, 1014, 1012, 1012, 1012, 1012, 1010, 1010, 1010, 1010, 1008, 1008, 1008, 1008, 1006, 1006, 1006, 1006, 1004, 1004, 1004, 1004, 1002, 1002, 1002, 1002, 1000, 1000, 1000, 1000, 0 }; - -/** - * database of motor profiles - */ - -static Motor_Profile gl846_motors[]={ - /* Image Formula 101 */ - {MOTOR_IMG101, 11000, HALF_STEP , img101_high}, - {MOTOR_PLUSTEK3800, 11000, HALF_STEP , img101_high}, - - /* end of database entry */ - {0, 0, 0, NULL}, -}; diff --git a/backend/genesys_gl847.cc b/backend/genesys_gl847.cc deleted file mode 100644 index b5748a5..0000000 --- a/backend/genesys_gl847.cc +++ /dev/null @@ -1,3517 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2013 Stéphane Voltz - - - 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. -*/ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_gl847.h" - -#include - -/**************************************************************************** - Mid level functions - ****************************************************************************/ - -static SANE_Bool -gl847_get_fast_feed_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG02); - if (r && (r->value & REG02_FASTFED)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_get_filter_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_FILTER)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_get_lineart_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_LINEART)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_get_bitset_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, REG04); - if (r && (r->value & REG04_BITSET)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_get_gain4_bit (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - - r = sanei_genesys_get_address (regs, 0x06); - if (r && (r->value & REG06_GAIN4)) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_test_buffer_empty_bit (SANE_Byte val) -{ - if (val & REG41_BUFEMPTY) - return SANE_TRUE; - return SANE_FALSE; -} - -static SANE_Bool -gl847_test_motor_flag_bit (SANE_Byte val) -{ - if (val & REG41_MOTORENB) - return SANE_TRUE; - return SANE_FALSE; -} - -/** - * compute the step multiplier used - */ -static int -gl847_get_step_multiplier (Genesys_Register_Set * regs) -{ - GenesysRegister *r = NULL; - int value = 1; - - r = sanei_genesys_get_address (regs, 0x9d); - if (r != NULL) - { - value = (r->value & 0x0f)>>1; - value = 1 << value; - } - DBG (DBG_io, "%s: step multiplier is %d\n", __func__, value); - return value; -} - -/** @brief sensor profile - * search for the database of motor profiles and get the best one. Each - * profile is at a specific dpihw. Use LiDE 110 table by default. - * @param sensor_type sensor id - * @param dpi hardware dpi for the scan - * @return a pointer to a Sensor_Profile struct - */ -static Sensor_Profile *get_sensor_profile(int sensor_type, int dpi) -{ - unsigned int i; - int idx; - - i=0; - idx=-1; - while(i=dpi - && sensors[i].dpimodel->ccd_type, xres); - return sensor_profile->exposure; -} - - -/** @brief sensor specific settings -*/ -static void gl847_setup_sensor(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, int dpi) -{ - GenesysRegister *r; - int dpihw; - uint16_t exp; - - DBGSTART; - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpi); - - for (uint16_t addr = 0x16; addr < 0x1e; addr++) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - for (uint16_t addr = 0x52; addr < 0x52 + 9; addr++) { - regs->set8(addr, sensor.custom_regs.get_value(addr)); - } - - /* set EXPDUMMY and CKxMAP */ - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpi); - Sensor_Profile* sensor_profile=get_sensor_profile(dev->model->ccd_type, dpihw); - - sanei_genesys_set_reg_from_set(regs,REG_EXPDMY,(uint8_t)((sensor_profile->expdummy) & 0xff)); - - /* if no calibration has been done, set default values for exposures */ - exp = sensor.exposure.red; - if(exp==0) - { - exp=sensor_profile->expr; - } - sanei_genesys_set_double(regs,REG_EXPR,exp); - - exp = sensor.exposure.green; - if(exp==0) - { - exp=sensor_profile->expg; - } - sanei_genesys_set_double(regs,REG_EXPG,exp); - - exp = sensor.exposure.blue; - if(exp==0) - { - exp=sensor_profile->expb; - } - sanei_genesys_set_double(regs,REG_EXPB,exp); - - sanei_genesys_set_triple(regs,REG_CK1MAP,sensor_profile->ck1map); - sanei_genesys_set_triple(regs,REG_CK3MAP,sensor_profile->ck3map); - sanei_genesys_set_triple(regs,REG_CK4MAP,sensor_profile->ck4map); - - /* order of the sub-segments */ - dev->order=sensor_profile->order; - - r = sanei_genesys_get_address (regs, 0x17); - r->value = sensor_profile->r17; - - DBGCOMPLETED; -} - - -/** @brief set all registers to default values . - * This function is called only once at the beginning and - * fills register startup values for registers reused across scans. - * Those that are rarely modified or not modified are written - * individually. - * @param dev device structure holding register set to initialize - */ -static void -gl847_init_registers (Genesys_Device * dev) -{ - int lide700=0; - uint8_t val; - - DBGSTART; - /* 700F class needs some different initial settings */ - if (dev->model->model_id == MODEL_CANON_LIDE_700F) - { - lide700 = 1; - } - - dev->reg.clear(); - - SETREG (0x01, 0x82); - SETREG (0x02, 0x18); - SETREG (0x03, 0x50); - SETREG (0x04, 0x12); - SETREG (0x05, 0x80); - SETREG (0x06, 0x50); /* FASTMODE + POWERBIT */ - SETREG (0x08, 0x10); - SETREG (0x09, 0x01); - SETREG (0x0a, 0x00); - SETREG (0x0b, 0x01); - SETREG (0x0c, 0x02); - - /* LED exposures */ - SETREG (0x10, 0x00); - SETREG (0x11, 0x00); - SETREG (0x12, 0x00); - SETREG (0x13, 0x00); - SETREG (0x14, 0x00); - SETREG (0x15, 0x00); - - SETREG (0x16, 0x10); - SETREG (0x17, 0x08); - SETREG (0x18, 0x00); - - /* EXPDMY */ - SETREG (0x19, 0x50); - - SETREG (0x1a, 0x34); - SETREG (0x1b, 0x00); - SETREG (0x1c, 0x02); - SETREG (0x1d, 0x04); - SETREG (0x1e, 0x10); - SETREG (0x1f, 0x04); - SETREG (0x20, 0x02); - SETREG (0x21, 0x10); - SETREG (0x22, 0x7f); - SETREG (0x23, 0x7f); - SETREG (0x24, 0x10); - SETREG (0x25, 0x00); - SETREG (0x26, 0x00); - SETREG (0x27, 0x00); - SETREG (0x2c, 0x09); - SETREG (0x2d, 0x60); - SETREG (0x2e, 0x80); - SETREG (0x2f, 0x80); - SETREG (0x30, 0x00); - SETREG (0x31, 0x10); - SETREG (0x32, 0x15); - SETREG (0x33, 0x0e); - SETREG (0x34, 0x40); - SETREG (0x35, 0x00); - SETREG (0x36, 0x2a); - SETREG (0x37, 0x30); - SETREG (0x38, 0x2a); - SETREG (0x39, 0xf8); - SETREG (0x3d, 0x00); - SETREG (0x3e, 0x00); - SETREG (0x3f, 0x00); - SETREG (0x52, 0x03); - SETREG (0x53, 0x07); - SETREG (0x54, 0x00); - SETREG (0x55, 0x00); - SETREG (0x56, 0x00); - SETREG (0x57, 0x00); - SETREG (0x58, 0x2a); - SETREG (0x59, 0xe1); - SETREG (0x5a, 0x55); - SETREG (0x5e, 0x41); - SETREG (0x5f, 0x40); - SETREG (0x60, 0x00); - SETREG (0x61, 0x21); - SETREG (0x62, 0x40); - SETREG (0x63, 0x00); - SETREG (0x64, 0x21); - SETREG (0x65, 0x40); - SETREG (0x67, 0x80); - SETREG (0x68, 0x80); - SETREG (0x69, 0x20); - SETREG (0x6a, 0x20); - - /* CK1MAP */ - SETREG (0x74, 0x00); - SETREG (0x75, 0x00); - SETREG (0x76, 0x3c); - - /* CK3MAP */ - SETREG (0x77, 0x00); - SETREG (0x78, 0x00); - SETREG (0x79, 0x9f); - - /* CK4MAP */ - SETREG (0x7a, 0x00); - SETREG (0x7b, 0x00); - SETREG (0x7c, 0x55); - - SETREG (0x7d, 0x00); - - /* NOTE: autoconf is a non working option */ - SETREG (0x87, 0x02); - SETREG (0x9d, 0x06); - SETREG (0xa2, 0x0f); - SETREG (0xbd, 0x18); - SETREG (0xfe, 0x08); - - /* gamma[0] and gamma[256] values */ - SETREG (0xbe, 0x00); - SETREG (0xc5, 0x00); - SETREG (0xc6, 0x00); - SETREG (0xc7, 0x00); - SETREG (0xc8, 0x00); - SETREG (0xc9, 0x00); - SETREG (0xca, 0x00); - - /* LiDE 700 fixups */ - if(lide700) - { - SETREG (0x5f, 0x04); - SETREG (0x7d, 0x80); - - /* we write to these registers only once */ - val=0; - sanei_genesys_write_register (dev, REG7E, val); - sanei_genesys_write_register (dev, REG9E, val); - sanei_genesys_write_register (dev, REG9F, val); - sanei_genesys_write_register (dev, REGAB, val); - } - - /* fine tune upon device description */ - dev->reg.find_reg(0x05).value &= ~REG05_DPIHW; - switch (sanei_genesys_find_sensor_any(dev).optical_res) - { - case 600: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_600; - break; - case 1200: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_1200; - break; - case 2400: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_2400; - break; - case 4800: - dev->reg.find_reg(0x05).value |= REG05_DPIHW_4800; - break; - } - - /* initalize calibration reg */ - dev->calib_reg = dev->reg; - - DBGCOMPLETED; -} - -/**@brief send slope table for motor movement - * Send slope_table in machine byte order - * @param dev device to send slope table - * @param table_nr index of the slope table in ASIC memory - * Must be in the [0-4] range. - * @param slope_table pointer to 16 bit values array of the slope table - * @param steps number of elements in the slope table - */ -static SANE_Status -gl847_send_slope_table (Genesys_Device * dev, int table_nr, - uint16_t * slope_table, int steps) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - char msg[10000]; - - DBG (DBG_proc, "%s (table_nr = %d, steps = %d)\n", __func__, - table_nr, steps); - - /* sanity check */ - if(table_nr<0 || table_nr>4) - { - DBG (DBG_error, "%s: invalid table number %d!\n", __func__, table_nr); - return SANE_STATUS_INVAL; - } - - std::vector table(steps * 2); - for (i = 0; i < steps; i++) - { - table[i * 2] = slope_table[i] & 0xff; - table[i * 2 + 1] = slope_table[i] >> 8; - } - - if (DBG_LEVEL >= DBG_io) - { - sprintf (msg, "write slope %d (%d)=", table_nr, steps); - for (i = 0; i < steps; i++) - { - sprintf (msg+strlen(msg), "%d", slope_table[i]); - } - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - /* slope table addresses are fixed */ - status = sanei_genesys_write_ahb(dev, 0x10000000 + 0x4000 * table_nr, steps * 2, table.data()); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: write to AHB failed writing slope table %d (%s)\n", __func__, table_nr, - sane_strstatus(status)); - } - - DBGCOMPLETED; - return status; -} - -/** - * Set register values of Analog Device type frontend - * */ -static SANE_Status -gl847_set_ad_fe (Genesys_Device * dev, uint8_t set) -{ - SANE_Status status = SANE_STATUS_GOOD; - int i; - uint8_t val8; - - DBGSTART; - - /* wait for FE to be ready */ - status = sanei_genesys_get_status (dev, &val8); - while (val8 & REG41_FEBUSY) - { - sanei_genesys_sleep_ms(10); - status = sanei_genesys_get_status (dev, &val8); - }; - - if (set == AFE_INIT) - { - DBG(DBG_proc, "%s(): setting DAC %u\n", __func__, dev->model->dac_type); - - dev->frontend = dev->frontend_initial; - } - - /* reset DAC */ - status = sanei_genesys_fe_write_data (dev, 0x00, 0x80); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* write them to analog frontend */ - status = sanei_genesys_fe_write_data(dev, 0x00, dev->frontend.regs.get_value(0x00)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write reg0: %s\n", __func__, sane_strstatus(status)); - return status; - } - status = sanei_genesys_fe_write_data(dev, 0x01, dev->frontend.regs.get_value(0x01)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write reg1: %s\n", __func__, sane_strstatus(status)); - return status; - } - - for (i = 0; i < 3; i++) - { - status = sanei_genesys_fe_write_data(dev, 0x02 + i, dev->frontend.get_gain(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write gain %d: %s\n", __func__, i, sane_strstatus(status)); - return status; - } - } - for (i = 0; i < 3; i++) - { - status = sanei_genesys_fe_write_data(dev, 0x05 + i, dev->frontend.get_offset(i)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write offset %d: %s\n", __func__, i, - sane_strstatus(status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl847_homsnr_gpio(Genesys_Device *dev) -{ -uint8_t val; -SANE_Status status=SANE_STATUS_GOOD; - - if (dev->model->gpo_type == GPO_CANONLIDE700) - { - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val &= ~REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - } - else - { - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val |= REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - } - return status; -} - -/* Set values of analog frontend */ -static SANE_Status -gl847_set_fe(Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set) -{ - (void) sensor; - - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - DBG(DBG_proc, "%s (%s)\n", __func__, set == AFE_INIT ? "init" : set == AFE_SET ? "set" : set == - AFE_POWER_SAVE ? "powersave" : "huh?"); - - RIE (sanei_genesys_read_register (dev, REG04, &val)); - - /* route to AD devices */ - if ((val & REG04_FESET) == 0x02) - { - return gl847_set_ad_fe (dev, set); - } - - /* for now there is no support yet for wolfson fe */ - DBG(DBG_proc, "%s(): unsupported frontend type %d\n", __func__, - dev->reg.find_reg(0x04).value & REG04_FESET); - - DBGCOMPLETED; - return SANE_STATUS_UNSUPPORTED; -} - - -/** @brief set up motor related register for scan - */ -static SANE_Status -gl847_init_motor_regs_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int scan_exposure_time, - float scan_yres, - int scan_step_type, - unsigned int scan_lines, - unsigned int scan_dummy, - unsigned int feed_steps, - int scan_power_mode, - unsigned int flags) -{ - SANE_Status status = SANE_STATUS_GOOD; - int use_fast_fed; - unsigned int fast_dpi; - uint16_t scan_table[SLOPE_TABLE_SIZE]; - uint16_t fast_table[SLOPE_TABLE_SIZE]; - int scan_steps, fast_steps, factor; - unsigned int feedl, dist; - GenesysRegister *r; - uint32_t z1, z2; - unsigned int min_restep = 0x20; - uint8_t val, effective; - int fast_step_type; - unsigned int ccdlmt,tgtime; - - DBGSTART; - DBG(DBG_proc, "%s : scan_exposure_time=%d, can_yres=%g, scan_step_type=%d, scan_lines=%d, " - "scan_dummy=%d, feed_steps=%d, scan_power_mode=%d, flags=%x\n", __func__, scan_exposure_time, - scan_yres, scan_step_type, scan_lines, scan_dummy, feed_steps, scan_power_mode, flags); - - /* get step multiplier */ - factor = gl847_get_step_multiplier (reg); - - use_fast_fed=0; - /* no fast fed since feed works well */ - if(dev->settings.yres==4444 && feed_steps>100 - && ((flags & MOTOR_FLAG_FEED)==0)) - { - use_fast_fed=1; - } - DBG(DBG_io, "%s: use_fast_fed=%d\n", __func__, use_fast_fed); - - sanei_genesys_set_triple(reg, REG_LINCNT, scan_lines); - DBG(DBG_io, "%s: lincnt=%d\n", __func__, scan_lines); - - /* compute register 02 value */ - r = sanei_genesys_get_address (reg, REG02); - r->value = 0x00; - sanei_genesys_set_motor_power(*reg, true); - - if (use_fast_fed) - r->value |= REG02_FASTFED; - else - r->value &= ~REG02_FASTFED; - - if (flags & MOTOR_FLAG_AUTO_GO_HOME) - r->value |= REG02_AGOHOME | REG02_NOTHOME; - - if ((flags & MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE) - ||(scan_yres>=sensor.optical_res)) - { - r->value |= REG02_ACDCDIS; - } - - /* scan and backtracking slope table */ - sanei_genesys_slope_table(scan_table, - &scan_steps, - scan_yres, - scan_exposure_time, - dev->motor.base_ydpi, - scan_step_type, - factor, - dev->model->motor_type, - gl847_motors); - RIE(gl847_send_slope_table (dev, SCAN_TABLE, scan_table, scan_steps*factor)); - RIE(gl847_send_slope_table (dev, BACKTRACK_TABLE, scan_table, scan_steps*factor)); - - /* fast table */ - fast_dpi=sanei_genesys_get_lowest_ydpi(dev); - fast_step_type=scan_step_type; - if(scan_step_type>=2) - { - fast_step_type=2; - } - - sanei_genesys_slope_table(fast_table, - &fast_steps, - fast_dpi, - scan_exposure_time, - dev->motor.base_ydpi, - fast_step_type, - factor, - dev->model->motor_type, - gl847_motors); - - /* manual override of high start value */ - fast_table[0]=fast_table[1]; - - RIE(gl847_send_slope_table (dev, STOP_TABLE, fast_table, fast_steps*factor)); - RIE(gl847_send_slope_table (dev, FAST_TABLE, fast_table, fast_steps*factor)); - RIE(gl847_send_slope_table (dev, HOME_TABLE, fast_table, fast_steps*factor)); - - /* correct move distance by acceleration and deceleration amounts */ - feedl=feed_steps; - if (use_fast_fed) - { - feedl<<=fast_step_type; - dist=(scan_steps+2*fast_steps)*factor; - /* TODO read and decode REGAB */ - r = sanei_genesys_get_address (reg, 0x5e); - dist += (r->value & 31); - /* FEDCNT */ - r = sanei_genesys_get_address (reg, REG_FEDCNT); - dist += r->value; - } - else - { - feedl<<=scan_step_type; - dist=scan_steps*factor; - if (flags & MOTOR_FLAG_FEED) - dist *=2; - } - DBG(DBG_io2, "%s: scan steps=%d\n", __func__, scan_steps); - DBG(DBG_io2, "%s: acceleration distance=%d\n", __func__, dist); - - /* check for overflow */ - if(distvalue & REG0C_CCDLMT)+1; - - r = sanei_genesys_get_address (reg, REG1C); - tgtime=1<<(r->value & REG1C_TGTIME); - - /* hi res motor speed GPIO */ - RIE (sanei_genesys_read_register (dev, REG6C, &effective)); - - /* if quarter step, bipolar Vref2 */ - if (scan_step_type > 1) - { - if (scan_step_type < 3) - { - val = effective & ~REG6C_GPIO13; - } - else - { - val = effective | REG6C_GPIO13; - } - } - else - { - val = effective; - } - RIE (sanei_genesys_write_register (dev, REG6C, val)); - - /* effective scan */ - RIE (sanei_genesys_read_register (dev, REG6C, &effective)); - val = effective | REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - - min_restep=scan_steps/2-1; - if (min_restep < 1) - min_restep = 1; - r = sanei_genesys_get_address (reg, REG_FWDSTEP); - r->value = min_restep; - r = sanei_genesys_get_address (reg, REG_BWDSTEP); - r->value = min_restep; - - sanei_genesys_calculate_zmode2(use_fast_fed, - scan_exposure_time*ccdlmt*tgtime, - scan_table, - scan_steps*factor, - feedl, - min_restep*factor, - &z1, - &z2); - - DBG(DBG_info, "%s: z1 = %d\n", __func__, z1); - sanei_genesys_set_triple(reg, REG60, z1 | (scan_step_type << (16+REG60S_STEPSEL))); - - DBG(DBG_info, "%s: z2 = %d\n", __func__, z2); - sanei_genesys_set_triple(reg, REG63, z2 | (scan_step_type << (16+REG63S_FSTPSEL))); - - r = sanei_genesys_get_address (reg, 0x1e); - r->value &= 0xf0; /* 0 dummy lines */ - r->value |= scan_dummy; /* dummy lines */ - - r = sanei_genesys_get_address (reg, REG67); - r->value = REG67_MTRPWM; - - r = sanei_genesys_get_address (reg, REG68); - r->value = REG68_FASTPWM; - - r = sanei_genesys_get_address (reg, REG_STEPNO); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FASTNO); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FSHDEC); - r->value = scan_steps; - - r = sanei_genesys_get_address (reg, REG_FMOVNO); - r->value = fast_steps; - - r = sanei_genesys_get_address (reg, REG_FMOVDEC); - r->value = fast_steps; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** @brief set up registers related to sensor - * Set up the following registers - 0x01 - 0x03 - 0x10-0x015 R/G/B exposures - 0x19 EXPDMY - 0x2e BWHI - 0x2f BWLO - 0x04 - 0x87 - 0x05 - 0x2c,0x2d DPISET - 0x30,0x31 STRPIXEL - 0x32,0x33 ENDPIXEL - 0x35,0x36,0x37 MAXWD [25:2] (>>2) - 0x38,0x39 LPERIOD - 0x34 DUMMY - */ -static SANE_Status -gl847_init_optical_regs_scan (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, - unsigned int exposure_time, - int used_res, - unsigned int start, - unsigned int pixels, - int channels, - int depth, - SANE_Bool half_ccd, ColorFilter color_filter, int flags) -{ - unsigned int words_per_line; - unsigned int startx, endx, used_pixels; - unsigned int dpiset, dpihw,segnb,cksel,factor; - unsigned int bytes; - GenesysRegister *r; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s : exposure_time=%d, used_res=%d, start=%d, pixels=%d, channels=%d, depth=%d, " - "half_ccd=%d, flags=%x\n", __func__, exposure_time, used_res, start, pixels, channels, depth, - half_ccd, flags); - - /* resolution is divided according to CKSEL */ - r = sanei_genesys_get_address (reg, REG18); - cksel= (r->value & REG18_CKSEL)+1; - DBG(DBG_io2, "%s: cksel=%d\n", __func__, cksel); - - /* to manage high resolution device while keeping good - * low resolution scanning speed, we make hardware dpi vary */ - dpihw=sanei_genesys_compute_dpihw(dev, sensor, used_res * cksel); - factor=sensor.optical_res/dpihw; - DBG(DBG_io2, "%s: dpihw=%d (factor=%d)\n", __func__, dpihw, factor); - - /* sensor parameters */ - Sensor_Profile* sensor_profile=get_sensor_profile(dev->model->ccd_type, dpihw); - gl847_setup_sensor(dev, sensor, reg, dpihw); - dpiset = used_res * cksel; - - /* start and end coordinate in optical dpi coordinates */ - startx = start/cksel+sensor.CCD_start_xoffset; - used_pixels=pixels/cksel; - - /* end of sensor window */ - endx = startx + used_pixels; - - /* sensors are built from 600 dpi segments for LiDE 100/200 - * and 1200 dpi for the 700F */ - if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR) - { - segnb=dpihw/600; - } - else - { - segnb=1; - } - - /* compute pixel coordinate in the given dpihw space, - * taking segments into account */ - startx/=factor*segnb; - endx/=factor*segnb; - dev->len=endx-startx; - dev->dist=0; - dev->skip=0; - - /* in cas of multi-segments sensor, we have to add the witdh - * of the sensor crossed by the scan area */ - if (dev->model->flags & GENESYS_FLAG_SIS_SENSOR && segnb>1) - { - dev->dist = sensor_profile->segcnt; - } - - /* use a segcnt rounded to next even number */ - endx += ((dev->dist+1)&0xfffe)*(segnb-1); - used_pixels=endx-startx; - - status = gl847_set_fe(dev, sensor, AFE_SET); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set frontend: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* enable shading */ - r = sanei_genesys_get_address (reg, REG01); - r->value &= ~REG01_SCAN; - r->value |= REG01_SHDAREA; - if ((flags & OPTICAL_FLAG_DISABLE_SHADING) || - (dev->model->flags & GENESYS_FLAG_NO_CALIBRATION)) - { - r->value &= ~REG01_DVDSET; - } - else - { - r->value |= REG01_DVDSET; - } - - r = sanei_genesys_get_address (reg, REG03); - r->value &= ~REG03_AVEENB; - - sanei_genesys_set_lamp_power(dev, sensor, *reg, !(flags & OPTICAL_FLAG_DISABLE_LAMP)); - - /* BW threshold */ - r = sanei_genesys_get_address (reg, 0x2e); - r->value = dev->settings.threshold; - r = sanei_genesys_get_address (reg, 0x2f); - r->value = dev->settings.threshold; - - /* monochrome / color scan */ - r = sanei_genesys_get_address (reg, REG04); - switch (depth) - { - case 1: - r->value &= ~REG04_BITSET; - r->value |= REG04_LINEART; - break; - case 8: - r->value &= ~(REG04_LINEART | REG04_BITSET); - break; - case 16: - r->value &= ~REG04_LINEART; - r->value |= REG04_BITSET; - break; - } - - r->value &= ~(REG04_FILTER | REG04_AFEMOD); - if (channels == 1) - { - switch (color_filter) - { - - case ColorFilter::RED: - r->value |= 0x14; - break; - case ColorFilter::BLUE: - r->value |= 0x1c; - break; - case ColorFilter::GREEN: - r->value |= 0x18; - break; - default: - break; // should not happen - } - } - else - r->value |= 0x10; /* mono */ - - /* register 05 */ - r = sanei_genesys_get_address (reg, REG05); - - /* set up dpihw */ - r->value &= ~REG05_DPIHW; - switch(dpihw) - { - case 600: - r->value |= REG05_DPIHW_600; - break; - case 1200: - r->value |= REG05_DPIHW_1200; - break; - case 2400: - r->value |= REG05_DPIHW_2400; - break; - case 4800: - r->value |= REG05_DPIHW_4800; - break; - } - - /* enable gamma tables */ - if (flags & OPTICAL_FLAG_DISABLE_GAMMA) - r->value &= ~REG05_GMMENB; - else - r->value |= REG05_GMMENB; - - /* CIS scanners can do true gray by setting LEDADD */ - /* we set up LEDADD only when asked */ - if (dev->model->is_cis == SANE_TRUE) - { - r = sanei_genesys_get_address (reg, 0x87); - r->value &= ~REG87_LEDADD; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG87_LEDADD; - } - /* RGB weighting - r = sanei_genesys_get_address (reg, 0x01); - r->value &= ~REG01_TRUEGRAY; - if (channels == 1 && (flags & OPTICAL_FLAG_ENABLE_LEDADD)) - { - r->value |= REG01_TRUEGRAY; - }*/ - } - - /* words(16bit) before gamma, conversion to 8 bit or lineart*/ - words_per_line = (used_pixels * dpiset) / dpihw; - bytes=depth/8; - if (depth == 1) - { - words_per_line = (words_per_line+7)/8 ; - dev->len = (dev->len >> 3) + ((dev->len & 7) ? 1 : 0); - dev->dist = (dev->dist >> 3) + ((dev->dist & 7) ? 1 : 0); - } - else - { - words_per_line *= bytes; - dev->dist *= bytes; - dev->len *= bytes; - } - - dev->bpl = words_per_line; - dev->cur=0; - dev->segnb=segnb; - dev->line_interp = 0; - - sanei_genesys_set_double(reg,REG_DPISET,dpiset); - DBG (DBG_io2, "%s: dpiset used=%d\n", __func__, dpiset); - - sanei_genesys_set_double(reg,REG_STRPIXEL,startx); - sanei_genesys_set_double(reg,REG_ENDPIXEL,endx); - DBG (DBG_io2, "%s: startx=%d\n", __func__, startx); - DBG (DBG_io2, "%s: endx =%d\n", __func__, endx); - - DBG (DBG_io2, "%s: used_pixels=%d\n", __func__, used_pixels); - DBG (DBG_io2, "%s: pixels =%d\n", __func__, pixels); - DBG (DBG_io2, "%s: depth =%d\n", __func__, depth); - DBG (DBG_io2, "%s: dev->bpl =%lu\n", __func__, (unsigned long)dev->bpl); - DBG (DBG_io2, "%s: dev->len =%lu\n", __func__, (unsigned long)dev->len); - DBG (DBG_io2, "%s: dev->dist =%lu\n", __func__, (unsigned long)dev->dist); - DBG (DBG_io2, "%s: dev->segnb =%lu\n", __func__, (unsigned long)dev->segnb); - - words_per_line *= channels; - dev->wpl = words_per_line; - - dev->oe_buffer.clear(); - dev->oe_buffer.alloc(dev->wpl); - - /* MAXWD is expressed in 4 words unit */ - sanei_genesys_set_triple(reg, REG_MAXWD, (words_per_line >> 2)); - DBG(DBG_io2, "%s: words_per_line used=%d\n", __func__, words_per_line); - - sanei_genesys_set_double(reg, REG_LPERIOD, exposure_time); - DBG(DBG_io2, "%s: exposure_time used=%d\n", __func__, exposure_time); - - r = sanei_genesys_get_address (reg, 0x34); - r->value = sensor.dummy_pixel; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -static SANE_Status -gl847_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SetupParams& params) - -{ - params.assert_valid(); - - int used_res; - int start, used_pixels; - int bytes_per_line; - int move; - unsigned int lincnt; - unsigned int oflags; /**> optical flags */ - unsigned int mflags; /**> motor flags */ - int exposure_time; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int scan_step_type = 1; - int scan_power_mode = 0; - int max_shift; - size_t requested_buffer_size, read_buffer_size; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - - /* we may have 2 domains for ccd: xres below or above half ccd max dpi */ - if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) - { - half_ccd = SANE_TRUE; - } - else - { - half_ccd = SANE_FALSE; - } - - /* optical_res */ - optical_res = sensor.optical_res; - if (half_ccd) - optical_res /= 2; - - /* stagger */ - if ((!half_ccd) && (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE)) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG(DBG_info, "%s : stagger=%d lines\n", __func__, stagger); - - /* used_res */ - if (params.flags & SCAN_FLAG_USE_OPTICAL_RES) - { - used_res = optical_res; - } - else - { - /* resolution is choosen from a list */ - used_res = params.xres; - } - - /* compute scan parameters values */ - /* pixels are allways given at full optical resolution */ - /* use detected left margin and fixed value */ - /* start */ - /* add x coordinates */ - start = params.startx; - - if (stagger > 0) - start |= 1; - - /* compute correct pixels number */ - /* pixels */ - used_pixels = (params.pixels * optical_res) / params.xres; - - /* round up pixels number if needed */ - if (used_pixels * params.xres < params.pixels * optical_res) - used_pixels++; - - dummy = 3-params.channels; - -/* slope_dpi */ -/* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) - slope_dpi = params.yres * params.channels; - else - slope_dpi = params.yres; - - slope_dpi = slope_dpi * (1 + dummy); - - exposure_time = gl847_compute_exposure (dev, used_res); - scan_step_type = sanei_genesys_compute_step_type(gl847_motors, dev->model->motor_type, exposure_time); - - DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - DBG(DBG_info, "%s : scan_step_type=%d\n", __func__, scan_step_type); - -/*** optical parameters ***/ - /* in case of dynamic lineart, we use an internal 8 bit gray scan - * to generate 1 lineart data */ - if (params.flags & SCAN_FLAG_DYNAMIC_LINEART) { - params.depth = 8; - } - - /* we enable true gray for cis scanners only, and just when doing - * scan since color calibration is OK for this mode - */ - oflags = 0; - if(params.flags & SCAN_FLAG_DISABLE_SHADING) - oflags |= OPTICAL_FLAG_DISABLE_SHADING; - if(params.flags & SCAN_FLAG_DISABLE_GAMMA) - oflags |= OPTICAL_FLAG_DISABLE_GAMMA; - if(params.flags & SCAN_FLAG_DISABLE_LAMP) - oflags |= OPTICAL_FLAG_DISABLE_LAMP; - - if (dev->model->is_cis && dev->settings.true_gray) - { - oflags |= OPTICAL_FLAG_ENABLE_LEDADD; - } - - status = gl847_init_optical_regs_scan (dev, sensor, - reg, - exposure_time, - used_res, - start, - used_pixels, - params.channels, - params.depth, - half_ccd, - params.color_filter, - oflags); - - if (status != SANE_STATUS_GOOD) - return status; - -/*** motor parameters ***/ - - /* max_shift */ - max_shift=sanei_genesys_compute_max_shift(dev,params.channels,params.yres,params.flags); - - /* lincnt */ - lincnt = params.lines + max_shift + stagger; - - /* add tl_y to base movement */ - move = params.starty; - DBG(DBG_info, "%s: move=%d steps\n", __func__, move); - - mflags=0; - if(params.flags & SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE) - mflags |= MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE; - if(params.flags & SCAN_FLAG_FEEDING) - mflags |= MOTOR_FLAG_FEED; - - status = gl847_init_motor_regs_scan (dev, sensor, - reg, - exposure_time, - slope_dpi, - scan_step_type, - dev->model->is_cis ? lincnt * - params.channels : lincnt, dummy, move, - scan_power_mode, - mflags); - - if (status != SANE_STATUS_GOOD) - return status; - - - /*** prepares data reordering ***/ - -/* words_per_line */ - bytes_per_line = (used_pixels * used_res) / optical_res; - bytes_per_line = (bytes_per_line * params.channels * params.depth) / 8; - - requested_buffer_size = 8 * bytes_per_line; - - read_buffer_size = - 2 * requested_buffer_size + - ((max_shift + stagger) * used_pixels * params.channels * params.depth) / 8; - - dev->read_buffer.clear(); - dev->read_buffer.alloc(read_buffer_size); - - dev->lines_buffer.clear(); - dev->lines_buffer.alloc(read_buffer_size); - - dev->shrink_buffer.clear(); - dev->shrink_buffer.alloc(requested_buffer_size); - - dev->out_buffer.clear(); - dev->out_buffer.alloc((8 * params.pixels * params.channels * params.depth) / 8); - - dev->read_bytes_left = bytes_per_line * lincnt; - - DBG(DBG_info, "%s: physical bytes to read = %lu\n", __func__, (u_long) dev->read_bytes_left); - dev->read_active = SANE_TRUE; - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - -/* TODO: should this be done elsewhere? */ - /* scan bytes to send to the frontend */ - /* theory : - target_size = - (params.pixels * params.lines * channels * depth) / 8; - but it suffers from integer overflow so we do the following: - - 1 bit color images store color data byte-wise, eg byte 0 contains - 8 bits of red data, byte 1 contains 8 bits of green, byte 2 contains - 8 bits of blue. - This does not fix the overflow, though. - 644mp*16 = 10gp, leading to an overflow - -- pierre - */ - - dev->total_bytes_read = 0; - if (params.depth == 1) - dev->total_bytes_to_read = - ((params.pixels * params.lines) / 8 + - (((params.pixels * params.lines) % 8) ? 1 : 0)) * - params.channels; - else - dev->total_bytes_to_read = - params.pixels * params.lines * params.channels * (params.depth / 8); - - DBG(DBG_info, "%s: total bytes to send = %lu\n", __func__, (u_long) dev->total_bytes_to_read); -/* END TODO */ - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static void -gl847_calculate_current_setup(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int depth; - int start; - - int used_res; - int used_pixels; - unsigned int lincnt; - int exposure_time; - int stagger; - - int slope_dpi = 0; - int dummy = 0; - int max_shift; - - SANE_Bool half_ccd; /* false: full CCD res is used, true, half max CCD res is used */ - int optical_res; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - /* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * sensor.optical_res) / MM_PER_INCH; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; // not used - params.starty = 0; // not used - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = 0; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, params); - -/* half_ccd */ - /* we have 2 domains for ccd: xres below or above half ccd max dpi */ - if (sensor.get_ccd_size_divisor_for_dpi(params.xres) > 1) { - half_ccd = SANE_TRUE; - } else { - half_ccd = SANE_FALSE; - } - - /* optical_res */ - optical_res = sensor.optical_res; - - /* stagger */ - if (dev->model->flags & GENESYS_FLAG_STAGGERED_LINE) - stagger = (4 * params.yres) / dev->motor.base_ydpi; - else - stagger = 0; - DBG(DBG_info, "%s: stagger=%d lines\n", __func__, stagger); - - /* resolution is choosen from a fixed list */ - used_res = params.xres; - - /* compute scan parameters values */ - /* pixels are allways given at half or full CCD optical resolution */ - /* use detected left margin and fixed value */ - - /* compute correct pixels number */ - used_pixels = (params.pixels * optical_res) / used_res; - dummy = 3 - params.channels; - - /* slope_dpi */ - /* cis color scan is effectively a gray scan with 3 gray lines per color - line and a FILTER of 0 */ - if (dev->model->is_cis) { - slope_dpi = params.yres * params.channels; - } else { - slope_dpi = params.yres; - } - - slope_dpi = slope_dpi * (1 + dummy); - - exposure_time = gl847_compute_exposure (dev, used_res); - DBG(DBG_info, "%s : exposure_time=%d pixels\n", __func__, exposure_time); - - /* max_shift */ - max_shift = sanei_genesys_compute_max_shift(dev, params.channels, params.yres, 0); - - /* lincnt */ - lincnt = params.lines + max_shift + stagger; - - dev->current_setup.params = params; - dev->current_setup.pixels = (used_pixels * used_res) / optical_res; - dev->current_setup.lines = lincnt; - dev->current_setup.depth = params.depth; - dev->current_setup.channels = params.channels; - dev->current_setup.exposure_time = exposure_time; - dev->current_setup.xres = used_res; - dev->current_setup.yres = params.yres; - dev->current_setup.ccd_size_divisor = half_ccd ? 2 : 1; - dev->current_setup.stagger = stagger; - dev->current_setup.max_shift = max_shift + stagger; - - DBGCOMPLETED; -} - -/*for fast power saving methods only, like disabling certain amplifiers*/ -static SANE_Status -gl847_save_power (Genesys_Device * dev, SANE_Bool enable) -{ - DBG(DBG_proc, "%s: enable = %d\n", __func__, enable); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl847_set_powersaving (Genesys_Device * dev, int delay /* in minutes */ ) -{ - DBG(DBG_proc, "%s (delay = %d)\n", __func__, delay); - if (dev == NULL) - return SANE_STATUS_INVAL; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl847_start_action (Genesys_Device * dev) -{ - return sanei_genesys_write_register (dev, 0x0f, 0x01); -} - -static SANE_Status -gl847_stop_action (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val40, val; - unsigned int loop; - - DBGSTART; - - /* post scan gpio : without that HOMSNR is unreliable */ - gl847_homsnr_gpio(dev); - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* only stop action if needed */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG)) - { - DBG(DBG_info, "%s: already stopped\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - /* ends scan */ - val = dev->reg.get8(REG01); - val &= ~REG01_SCAN; - sanei_genesys_set_reg_from_set(&dev->reg, REG01, val); - status = sanei_genesys_write_register (dev, REG01, val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to write register 01: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_sleep_ms(100); - - loop = 10; - while (loop > 0) - { - status = sanei_genesys_get_status (dev, &val); - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - status = sanei_genesys_read_register (dev, REG40, &val40); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* if scanner is in command mode, we are done */ - if (!(val40 & REG40_DATAENB) && !(val40 & REG40_MOTMFLG) - && !(val & REG41_MOTORENB)) - { - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - sanei_genesys_sleep_ms(100); - loop--; - } - - DBGCOMPLETED; - return SANE_STATUS_IO_ERROR; -} - -/* Send the low-level scan command */ -static SANE_Status -gl847_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, Genesys_Register_Set * reg, - SANE_Bool start_motor) -{ - (void) sensor; - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - GenesysRegister *r; - - DBGSTART; - - /* clear GPIO 10 */ - if (dev->model->gpo_type != GPO_CANONLIDE700) - { - RIE (sanei_genesys_read_register (dev, REG6C, &val)); - val &= ~REG6C_GPIO10; - RIE (sanei_genesys_write_register (dev, REG6C, val)); - } - - val = REG0D_CLRLNCNT; - RIE (sanei_genesys_write_register (dev, REG0D, val)); - val = REG0D_CLRMCNT; - RIE (sanei_genesys_write_register (dev, REG0D, val)); - - RIE (sanei_genesys_read_register (dev, REG01, &val)); - val |= REG01_SCAN; - RIE (sanei_genesys_write_register (dev, REG01, val)); - r = sanei_genesys_get_address (reg, REG01); - r->value = val; - - if (start_motor) - { - RIE (sanei_genesys_write_register (dev, REG0F, 1)); - } - else - { - RIE (sanei_genesys_write_register (dev, REG0F, 0)); - } - - DBGCOMPLETED; - - return status; -} - - -/* Send the stop scan command */ -static SANE_Status -gl847_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, - SANE_Bool check_stop) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_proc, "%s (check_stop = %d)\n", __func__, check_stop); - if (reg == NULL) - return SANE_STATUS_INVAL; - - if (dev->model->is_sheetfed == SANE_TRUE) - { - status = SANE_STATUS_GOOD; - } - else /* flat bed scanners */ - { - status = gl847_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - } - - DBGCOMPLETED; - return status; -} - -/** rewind scan - * Move back by the same amount of distance than previous scan. - * @param dev device to rewind - * @returns SANE_STATUS_GOOD on success - */ -#if 0 /* disabled to fix #7 */ -static -SANE_Status gl847_rewind(Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t byte; - - DBGSTART; - - /* set motor reverse */ - RIE (sanei_genesys_read_register (dev, 0x02, &byte)); - byte |= 0x04; - RIE (sanei_genesys_write_register(dev, 0x02, byte)); - - /* and start scan, then wait completion */ - RIE (gl847_begin_scan (dev, dev->reg, SANE_TRUE)); - do - { - sanei_genesys_sleep_ms(100); - RIE (sanei_genesys_read_register (dev, REG40, &byte)); - } - while(byte & REG40_MOTMFLG); - RIE (gl847_end_scan (dev, dev->reg, SANE_TRUE)); - - /* restore direction */ - RIE (sanei_genesys_read_register (dev, 0x02, &byte)); - byte &= 0xfb; - RIE (sanei_genesys_write_register(dev, 0x02, byte)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} -#endif - -/** Park head - * Moves the slider to the home (top) position slowly - * @param dev device to park - * @param wait_until_home true to make the function waiting for head - * to be home before returning, if fals returne immediately - * @returns SANE_STATUS_GOO on success */ -static -SANE_Status -gl847_slow_back_home (Genesys_Device * dev, SANE_Bool wait_until_home) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - float resolution; - uint8_t val; - int loop = 0; - ScanColorMode scan_mode; - - DBG(DBG_proc, "%s (wait_until_home = %d)\n", __func__, wait_until_home); - - /* post scan gpio : without that HOMSNR is unreliable */ - gl847_homsnr_gpio(dev); - - /* first read gives HOME_SENSOR true */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - sanei_genesys_sleep_ms(100); - - /* second is reliable */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, sane_strstatus(status)); - return status; - } - if (DBG_LEVEL >= DBG_io) - { - sanei_genesys_print_status (val); - } - - /* is sensor at home? */ - if (val & HOMESNR) - { - DBG(DBG_info, "%s: already at home, completed\n", __func__); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - - local_reg = dev->reg; - - resolution=sanei_genesys_get_lowest_ydpi(dev); - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - /* TODO add scan_mode to the API */ - scan_mode = dev->settings.scan_mode; - dev->settings.scan_mode = ScanColorMode::LINEART; - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 100; - params.starty = 30000; - params.pixels = 100; - params.lines = 100; - params.depth = 8; - params.channels = 1; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::RED; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl847_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - dev->settings.scan_mode = scan_mode; - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT | REG0D_CLRMCNT)); - - /* set up for reverse */ - r = sanei_genesys_get_address (&local_reg, REG02); - r->value |= REG02_MTRREV; - - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - - try { - status = gl847_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl847_stop_action(dev); - } catch (...) {} - try { - // restore original registers - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl847_stop_action (dev); - /* send original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - /* post scan gpio : without that HOMSNR is unreliable */ - gl847_homsnr_gpio(dev); - - if (wait_until_home) - { - while (loop < 300) /* do not wait longer then 30 seconds */ - { - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - if (val & HOMESNR) /* home sensor */ - { - DBG(DBG_info, "%s: reached home position\n", __func__); - gl847_stop_action (dev); - dev->scanhead_position_in_steps = 0; - DBGCOMPLETED; - return SANE_STATUS_GOOD; - } - sanei_genesys_sleep_ms(100); - ++loop; - } - - /* when we come here then the scanner needed too much time for this, so we better stop the motor */ - gl847_stop_action (dev); - DBG(DBG_error, "%s: timeout while waiting for scanhead to go home\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - DBG(DBG_info, "%s: scanhead is still moving\n", __func__); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/* Automatically set top-left edge of the scan area by scanning a 200x200 pixels - area at 600 dpi from very top of scanner */ -static SANE_Status -gl847_search_start_position (Genesys_Device * dev) -{ - int size; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg; - int steps; - - int pixels = 600; - int dpi = 300; - - DBG(DBG_proc, "%s\n", __func__); - - local_reg = dev->reg; - - /* sets for a 200 lines * 600 pixels */ - /* normal scan with no shading */ - - // FIXME: the current approach of doing search only for one resolution does not work on scanners - // whith employ different sensors with potentially different settings. - auto& sensor = sanei_genesys_find_sensor_for_write(dev, dpi); - - SetupParams params; - params.xres = dpi; - params.yres = dpi; - params.startx = 0; - params.starty = 0; /*we should give a small offset here~60 steps */ - params.pixels = 600; - params.lines = dev->model->search_lines; - params.depth = 8; - params.channels = 1; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::GREEN; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl847_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* send to scanner */ - status = dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - size = pixels * dev->model->search_lines; - - std::vector data(size); - - status = gl847_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl847_search_position.pnm", data.data(), 8, 1, pixels, - dev->model->search_lines); - - status = gl847_end_scan(dev, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to end scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* update regs to copy ASIC internal state */ - dev->reg = local_reg; - -/*TODO: find out where sanei_genesys_search_reference_point - stores information, and use that correctly*/ - status = - sanei_genesys_search_reference_point(dev, sensor, data.data(), 0, dpi, pixels, - dev->model->search_lines); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set search reference point: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - return SANE_STATUS_GOOD; -} - -/* - * sets up register for coarse gain calibration - * todo: check it for scanners using it */ -static SANE_Status -gl847_init_regs_for_coarse_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t channels; - uint8_t cksel; - - DBG(DBG_proc, "%s\n", __func__); - - - cksel = (regs.find_reg(0x18).value & REG18_CKSEL) + 1; /* clock speed = 1..4 clocks */ - - /* set line size */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else { - channels = 1; - } - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = 0; - params.starty = 0; - params.pixels = sensor.optical_res / cksel; - params.lines = 20; - params.depth = 16; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl847_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_info, "%s: optical sensor res: %d dpi, actual res: %d\n", __func__, - sensor.optical_res / cksel, dev->settings.xres); - - status = - dev->model->cmd_set->bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move in base_dpi line count - * */ -static SANE_Status -gl847_feed (Genesys_Device * dev, unsigned int steps) -{ - Genesys_Register_Set local_reg; - SANE_Status status = SANE_STATUS_GOOD; - GenesysRegister *r; - float resolution; - uint8_t val; - - DBGSTART; - DBG(DBG_io, "%s: steps=%d\n", __func__, steps); - - local_reg = dev->reg; - - resolution=sanei_genesys_get_lowest_ydpi(dev); - const auto& sensor = sanei_genesys_find_sensor(dev, resolution); - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 0; - params.starty = steps; - params.pixels = 100; - params.lines = 3; - params.depth = 8; - params.channels = 3; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_FEEDING | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl847_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to set up registers: %s\n", __func__, sane_strstatus(status)); - DBGCOMPLETED; - return status; - } - - /* set exposure to zero */ - sanei_genesys_set_triple(&local_reg,REG_EXPR,0); - sanei_genesys_set_triple(&local_reg,REG_EXPG,0); - sanei_genesys_set_triple(&local_reg,REG_EXPB,0); - - /* clear scan and feed count */ - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRLNCNT)); - RIE (sanei_genesys_write_register (dev, REG0D, REG0D_CLRMCNT)); - - /* set up for no scan */ - r = sanei_genesys_get_address(&local_reg, REG01); - r->value &= ~REG01_SCAN; - - /* send registers */ - RIE (dev->model->cmd_set->bulk_write_register(dev, local_reg)); - - try { - status = gl847_start_action (dev); - } catch (...) { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - try { - gl847_stop_action(dev); - } catch (...) {} - try { - // restore original registers - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - } catch (...) {} - throw; - } - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to start motor: %s\n", __func__, sane_strstatus(status)); - gl847_stop_action (dev); - - /* restore original registers */ - dev->model->cmd_set->bulk_write_register(dev, dev->reg); - return status; - } - - /* wait until feed count reaches the required value, but do not - * exceed 30s */ - do - { - status = sanei_genesys_get_status (dev, &val); - } - while (status == SANE_STATUS_GOOD && !(val & FEEDFSH)); - - /* then stop scanning */ - RIE(gl847_stop_action (dev)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/* init registers for shading calibration */ -static SANE_Status -gl847_init_regs_for_shading(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - float move; - - DBGSTART; - dev->calib_channels = 3; - - /* initial calibration reg values */ - regs = dev->reg; - - dev->calib_resolution = sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); - dev->calib_total_bytes_to_read = 0; - dev->calib_lines = dev->model->shading_lines; - if(dev->calib_resolution==4800) - dev->calib_lines *= 2; - dev->calib_pixels = (sensor.sensor_pixels*dev->calib_resolution)/sensor.optical_res; - DBG(DBG_io, "%s: calib_lines = %d\n", __func__, (int)dev->calib_lines); - DBG(DBG_io, "%s: calib_pixels = %d\n", __func__, (int)dev->calib_pixels); - - /* this is aworkaround insufficent distance for slope - * motor acceleration TODO special motor slope for shading */ - move=1; - if(dev->calib_resolution<1200) - { - move=40; - } - - SetupParams params; - params.xres = dev->calib_resolution; - params.yres = dev->calib_resolution; - params.startx = 0; - params.starty = move; - params.pixels = dev->calib_pixels; - params.lines = dev->calib_lines; - params.depth = 16; - params.channels = dev->calib_channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl847_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = dev->model->cmd_set->bulk_write_register(dev, regs); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* we use GENESYS_FLAG_SHADING_REPARK */ - dev->scanhead_position_in_steps = 0; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** @brief set up registers for the actual scan - */ -static SANE_Status -gl847_init_regs_for_scan (Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int channels; - int flags; - int depth; - float move; - int move_dpi; - float start; - - SANE_Status status = SANE_STATUS_GOOD; - - DBG(DBG_info, "%s ", __func__); - debug_dump(DBG_info, dev->settings); - - /* channels */ - if (dev->settings.scan_mode == ScanColorMode::COLOR_SINGLE_PASS) - channels = 3; - else - channels = 1; - - /* depth */ - depth = dev->settings.depth; - if (dev->settings.scan_mode == ScanColorMode::LINEART) - depth = 1; - - - /* steps to move to reach scanning area: - - first we move to physical start of scanning - either by a fixed steps amount from the black strip - or by a fixed amount from parking position, - minus the steps done during shading calibration - - then we move by the needed offset whitin physical - scanning area - - assumption: steps are expressed at maximum motor resolution - - we need: - SANE_Fixed y_offset; - SANE_Fixed y_size; - SANE_Fixed y_offset_calib; - mm_to_steps()=motor dpi / 2.54 / 10=motor dpi / MM_PER_INCH */ - - /* if scanner uses GENESYS_FLAG_SEARCH_START y_offset is - relative from origin, else, it is from parking position */ - - move_dpi = dev->motor.base_ydpi; - - move = SANE_UNFIX (dev->model->y_offset); - move += dev->settings.tl_y; - move = (move * move_dpi) / MM_PER_INCH; - move -= dev->scanhead_position_in_steps; - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - /* fast move to scan area */ - /* we don't move fast the whole distance since it would involve - * computing acceleration/deceleration distance for scan - * resolution. So leave a remainder for it so scan makes the final - * move tuning */ - if(channels*dev->settings.yres>=600 && move>700) - { - status = gl847_feed (dev, move-500); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to move to scan area\n", __func__); - return status; - } - move=500; - } - - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - DBG(DBG_info, "%s: move=%f steps\n", __func__, move); - - /* start */ - start = SANE_UNFIX (dev->model->x_offset); - start += dev->settings.tl_x; - start = (start * sensor.optical_res) / MM_PER_INCH; - - flags = 0; - - /* emulated lineart from gray data is required for now */ - if(dev->settings.scan_mode == ScanColorMode::LINEART - && dev->settings.dynamic_lineart) - { - flags |= SCAN_FLAG_DYNAMIC_LINEART; - } - - /* backtracking isn't handled well, so don't enable it */ - flags |= SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE; - - SetupParams params; - params.xres = dev->settings.xres; - params.yres = dev->settings.yres; - params.startx = start; - params.starty = move; - params.pixels = dev->settings.pixels; - params.lines = dev->settings.lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = dev->settings.scan_mode; - params.color_filter = dev->settings.color_filter; - params.flags = flags; - - status = gl847_init_scan_regs(dev, sensor, &dev->reg, params); - - if (status != SANE_STATUS_GOOD) - return status; - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - - -/** - * Send shading calibration data. The buffer is considered to always hold values - * for all the channels. - */ -static SANE_Status -gl847_send_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * data, int size) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint32_t addr, length, i, x, factor, pixels; - uint32_t dpiset, dpihw, strpixel, endpixel; - uint16_t tempo; - uint32_t lines, channels; - uint8_t val,*ptr,*src; - - DBGSTART; - DBG(DBG_io2, "%s: writing %d bytes of shading data\n", __func__, size); - - /* shading data is plit in 3 (up to 5 with IR) areas - write(0x10014000,0x00000dd8) - URB 23429 bulk_out len 3544 wrote 0x33 0x10 0x.... - write(0x1003e000,0x00000dd8) - write(0x10068000,0x00000dd8) - */ - length = (uint32_t) (size / 3); - sanei_genesys_get_double(&dev->reg,REG_STRPIXEL,&tempo); - strpixel=tempo; - sanei_genesys_get_double(&dev->reg,REG_ENDPIXEL,&tempo); - endpixel=tempo; - - /* compute deletion factor */ - sanei_genesys_get_double(&dev->reg,REG_DPISET,&tempo); - dpiset=tempo; - DBG(DBG_io2, "%s: STRPIXEL=%d, ENDPIXEL=%d, PIXELS=%d, DPISET=%d\n", __func__, strpixel, endpixel, - endpixel-strpixel, dpiset); - dpihw=sanei_genesys_compute_dpihw(dev, sensor, dpiset); - factor=dpihw/dpiset; - DBG(DBG_io2, "%s: factor=%d\n", __func__, factor); - - if(DBG_LEVEL>=DBG_data) - { - dev->binary=fopen("binary.pnm","wb"); - sanei_genesys_get_triple(&dev->reg, REG_LINCNT, &lines); - channels=dev->current_setup.channels; - if(dev->binary!=NULL) - { - fprintf(dev->binary,"P5\n%d %d\n%d\n",(endpixel-strpixel)/factor*channels,lines/channels,255); - } - } - - pixels=endpixel-strpixel; - - /* since we're using SHDAREA, substract startx coordinate from shading */ - strpixel-=((sensor.CCD_start_xoffset*600)/sensor.optical_res); - - /* turn pixel value into bytes 2x16 bits words */ - strpixel*=2*2; - pixels*=2*2; - - std::vector buffer(pixels, 0); - - DBG(DBG_io2, "%s: using chunks of %d (0x%04x) bytes\n", __func__, pixels, pixels); - - /* base addr of data has been written in reg D0-D4 in 4K word, so AHB address - * is 8192*reg value */ - - /* write actual color channel data */ - for(i=0;i<3;i++) - { - /* build up actual shading data by copying the part from the full width one - * to the one corresponding to SHDAREA */ - ptr = buffer.data(); - - /* iterate on both sensor segment */ - for(x=0;xmodel->y_offset_calib); - move = (move * (dev->motor.base_ydpi/4)) / MM_PER_INCH; - if(move>20) - { - RIE(gl847_feed (dev, move)); - } - DBG(DBG_io, "%s: move=%f steps\n", __func__, move); - - /* offset calibration is always done in color mode */ - channels = 3; - depth=16; - used_res=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); - Sensor_Profile* sensor_profile=get_sensor_profile(dev->model->ccd_type, used_res); - num_pixels = (sensor.sensor_pixels*used_res)/sensor.optical_res; - - /* initial calibration reg values */ - regs = dev->reg; - - SetupParams params; - params.xres = used_res; - params.yres = used_res; - params.startx = 0; - params.starty = 0; - params.pixels = num_pixels; - params.lines = 1; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl847_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - total_size = num_pixels * channels * (depth/8) * 1; /* colors * bytes_per_color * scan lines */ - std::vector line(total_size); - - /* initial loop values and boundaries */ - exp[0]=sensor_profile->expr; - exp[1]=sensor_profile->expg; - exp[2]=sensor_profile->expb; - - bottom[0]=29000; - bottom[1]=29000; - bottom[2]=29000; - - top[0]=41000; - top[1]=51000; - top[2]=51000; - - turn = 0; - - /* no move during led calibration */ - sanei_genesys_set_motor_power(regs, false); - do - { - /* set up exposure */ - sanei_genesys_set_double(®s,REG_EXPR,exp[0]); - sanei_genesys_set_double(®s,REG_EXPG,exp[1]); - sanei_genesys_set_double(®s,REG_EXPB,exp[2]); - - /* write registers and scan data */ - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - - DBG(DBG_info, "%s: starting line reading\n", __func__); - RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); - - /* stop scanning */ - RIE(gl847_stop_action (dev)); - - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl847_led_%02d.pnm", turn); - sanei_genesys_write_pnm_file(fn, line.data(), depth, channels, num_pixels, 1); - } - - /* compute average */ - for (j = 0; j < channels; j++) - { - avg[j] = 0; - for (i = 0; i < num_pixels; i++) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * num_pixels + 1] * 256 + - line[i * 2 + j * 2 * num_pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - avg[j] += val; - } - - avg[j] /= num_pixels; - } - - DBG(DBG_info, "%s: average: %d,%d,%d\n", __func__, avg[0], avg[1], avg[2]); - - /* check if exposure gives average within the boundaries */ - acceptable = SANE_TRUE; - for(i=0;i<3;i++) - { - if(avg[i]top[i]) - { - exp[i]=(exp[i]*top[i])/avg[i]; - acceptable = SANE_FALSE; - } - } - - turn++; - } - while (!acceptable && turn < 100); - - DBG(DBG_info, "%s: acceptable exposure: %d,%d,%d\n", __func__, exp[0], exp[1], exp[2]); - - /* set these values as final ones for scan */ - sanei_genesys_set_double(&dev->reg,REG_EXPR,exp[0]); - sanei_genesys_set_double(&dev->reg,REG_EXPG,exp[1]); - sanei_genesys_set_double(&dev->reg,REG_EXPB,exp[2]); - - /* store in this struct since it is the one used by cache calibration */ - sensor.exposure.red = exp[0]; - sensor.exposure.green = exp[1]; - sensor.exposure.blue = exp[2]; - - /* go back home */ - if(move>20) - { - status=gl847_slow_back_home (dev, SANE_TRUE); - } - - DBGCOMPLETED; - return status; -} - -/** - * set up GPIO/GPOE for idle state - */ -static SANE_Status -gl847_init_gpio (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx=0; - - DBGSTART; - - /* search GPIO profile */ - while(gpios[idx].sensor_id!=0 && dev->model->gpo_type!=gpios[idx].sensor_id) - { - idx++; - } - if(gpios[idx].sensor_id==0) - { - DBG(DBG_error, "%s: failed to find GPIO profile for sensor_id=%d\n", __func__, - dev->model->ccd_type); - return SANE_STATUS_INVAL; - } - - RIE (sanei_genesys_write_register (dev, REGA7, gpios[idx].ra7)); - RIE (sanei_genesys_write_register (dev, REGA6, gpios[idx].ra6)); - - RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); - RIE (sanei_genesys_write_register (dev, REG6C, 0x00)); - - RIE (sanei_genesys_write_register (dev, REG6B, gpios[idx].r6b)); - RIE (sanei_genesys_write_register (dev, REG6C, gpios[idx].r6c)); - RIE (sanei_genesys_write_register (dev, REG6D, gpios[idx].r6d)); - RIE (sanei_genesys_write_register (dev, REG6E, gpios[idx].r6e)); - RIE (sanei_genesys_write_register (dev, REG6F, gpios[idx].r6f)); - - RIE (sanei_genesys_write_register (dev, REGA8, gpios[idx].ra8)); - RIE (sanei_genesys_write_register (dev, REGA9, gpios[idx].ra9)); - - DBGCOMPLETED; - return status; -} - -/** - * set memory layout by filling values in dedicated registers - */ -static SANE_Status -gl847_init_memory_layout (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - int idx = 0; - uint8_t val; - - DBG(DBG_proc, "%s\n" , __func__); - - /* point to per model memory layout */ - idx = 0; - if (dev->model->model_id == MODEL_CANON_LIDE_100) - { - idx = 0; - } - if (dev->model->model_id == MODEL_CANON_LIDE_200) - { - idx = 1; - } - if (dev->model->model_id == MODEL_CANON_CANOSCAN_5600F) - { - idx = 2; - } - if (dev->model->model_id == MODEL_CANON_LIDE_700F) - { - idx = 3; - } - - /* CLKSET nd DRAMSEL */ - val = layouts[idx].dramsel; - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg.find_reg(0x0b).value = val; - - /* prevent further writings by bulk write register */ - dev->reg.remove_reg(0x0b); - - /* setup base address for shading data. */ - /* values must be multiplied by 8192=0x4000 to give address on AHB */ - /* R-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd0, layouts[idx].rd0); - /* G-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd1, layouts[idx].rd1); - /* B-Channel shading bank0 address setting for CIS */ - sanei_genesys_write_register (dev, 0xd2, layouts[idx].rd2); - - /* setup base address for scanned data. */ - /* values must be multiplied by 1024*2=0x0800 to give address on AHB */ - /* R-Channel ODD image buffer 0x0124->0x92000 */ - /* size for each buffer is 0x16d*1k word */ - sanei_genesys_write_register (dev, 0xe0, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xe1, layouts[idx].re1); - /* R-Channel ODD image buffer end-address 0x0291->0x148800 => size=0xB6800*/ - sanei_genesys_write_register (dev, 0xe2, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xe3, layouts[idx].re3); - - /* R-Channel EVEN image buffer 0x0292 */ - sanei_genesys_write_register (dev, 0xe4, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xe5, layouts[idx].re5); - /* R-Channel EVEN image buffer end-address 0x03ff*/ - sanei_genesys_write_register (dev, 0xe6, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xe7, layouts[idx].re7); - - /* same for green, since CIS, same addresses */ - sanei_genesys_write_register (dev, 0xe8, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xe9, layouts[idx].re1); - sanei_genesys_write_register (dev, 0xea, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xeb, layouts[idx].re3); - sanei_genesys_write_register (dev, 0xec, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xed, layouts[idx].re5); - sanei_genesys_write_register (dev, 0xee, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xef, layouts[idx].re7); - -/* same for blue, since CIS, same addresses */ - sanei_genesys_write_register (dev, 0xf0, layouts[idx].re0); - sanei_genesys_write_register (dev, 0xf1, layouts[idx].re1); - sanei_genesys_write_register (dev, 0xf2, layouts[idx].re2); - sanei_genesys_write_register (dev, 0xf3, layouts[idx].re3); - sanei_genesys_write_register (dev, 0xf4, layouts[idx].re4); - sanei_genesys_write_register (dev, 0xf5, layouts[idx].re5); - sanei_genesys_write_register (dev, 0xf6, layouts[idx].re6); - sanei_genesys_write_register (dev, 0xf7, layouts[idx].re7); - - DBGCOMPLETED; - return status; -} - -/* * - * initialize ASIC from power on condition - */ -static SANE_Status -gl847_boot (Genesys_Device * dev, SANE_Bool cold) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - - DBGSTART; - - /* reset ASIC if cold boot */ - if(cold) - { - RIE (sanei_genesys_write_register (dev, 0x0e, 0x01)); - RIE (sanei_genesys_write_register (dev, 0x0e, 0x00)); - } - - /* test CHKVER */ - RIE (sanei_genesys_read_register (dev, REG40, &val)); - if (val & REG40_CHKVER) - { - RIE (sanei_genesys_read_register (dev, 0x00, &val)); - DBG(DBG_info, "%s: reported version for genesys chip is 0x%02x\n", __func__, val); - } - - /* Set default values for registers */ - gl847_init_registers (dev); - - /* Write initial registers */ - RIE (dev->model->cmd_set->bulk_write_register(dev, dev->reg)); - - /* Enable DRAM by setting a rising edge on bit 3 of reg 0x0b */ - val = dev->reg.find_reg(0x0b).value & REG0B_DRAMSEL; - val = (val | REG0B_ENBDRAM); - RIE (sanei_genesys_write_register (dev, REG0B, val)); - dev->reg.find_reg(0x0b).value = val; - - /* CIS_LINE */ - SETREG (0x08, REG08_CIS_LINE); - RIE (sanei_genesys_write_register (dev, 0x08, dev->reg.find_reg(0x08).value)); - - /* set up end access */ - RIE (sanei_genesys_write_0x8c (dev, 0x10, 0x0b)); - RIE (sanei_genesys_write_0x8c (dev, 0x13, 0x0e)); - - /* setup gpio */ - RIE (gl847_init_gpio (dev)); - - /* setup internal memory layout */ - RIE (gl847_init_memory_layout (dev)); - - SETREG (0xf8, 0x01); - RIE (sanei_genesys_write_register (dev, 0xf8, dev->reg.find_reg(0xf8).value)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** - * initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home - */ -static SANE_Status gl847_init (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - - DBG_INIT (); - DBGSTART; - - status=sanei_genesys_asic_init(dev, 0); - - DBGCOMPLETED; - return status; -} - -static SANE_Status -gl847_update_hardware_sensors (Genesys_Scanner * s) -{ - /* do what is needed to get a new set of events, but try to not lose - any of them. - */ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - uint8_t scan, file, email, copy; - switch(s->dev->model->gpo_type) - { - case GPO_CANONLIDE700: - scan=0x04; - file=0x02; - email=0x01; - copy=0x08; - break; - default: - scan=0x01; - file=0x02; - email=0x04; - copy=0x08; - } - RIE (sanei_genesys_read_register (s->dev, REG6D, &val)); - - s->buttons[BUTTON_SCAN_SW].write((val & scan) == 0); - s->buttons[BUTTON_FILE_SW].write((val & file) == 0); - s->buttons[BUTTON_EMAIL_SW].write((val & email) == 0); - s->buttons[BUTTON_COPY_SW].write((val & copy) == 0); - - return status; -} - -/** @brief search for a full width black or white strip. - * This function searches for a black or white stripe across the scanning area. - * When searching backward, the searched area must completely be of the desired - * color since this area will be used for calibration which scans forward. - * @param dev scanner device - * @param forward SANE_TRUE if searching forward, SANE_FALSE if searching backward - * @param black SANE_TRUE if searching for a black strip, SANE_FALSE for a white strip - * @return SANE_STATUS_GOOD if a matching strip is found, SANE_STATUS_UNSUPPORTED if not - */ -static SANE_Status -gl847_search_strip (Genesys_Device * dev, const Genesys_Sensor& sensor, - SANE_Bool forward, SANE_Bool black) -{ - unsigned int pixels, lines, channels; - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set local_reg; - size_t size; - int steps, depth, dpi; - unsigned int pass, count, found, x, y; - char title[80]; - GenesysRegister *r; - - DBG(DBG_proc, "%s %s %s\n", __func__, black ? "black" : "white", forward ? "forward" : "reverse"); - - gl847_set_fe(dev, sensor, AFE_SET); - status = gl847_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to stop: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* set up for a gray scan at lowest dpi */ - dpi = 9600; - for (x = 0; x < MAX_RESOLUTIONS; x++) - { - if (dev->model->xdpi_values[x] > 0 && dev->model->xdpi_values[x] < dpi) - dpi = dev->model->xdpi_values[x]; - } - channels = 1; - /* 10 MM */ - /* lines = (10 * dpi) / MM_PER_INCH; */ - /* shading calibation is done with dev->motor.base_ydpi */ - lines = (dev->model->shading_lines * dpi) / dev->motor.base_ydpi; - depth = 8; - pixels = (sensor.sensor_pixels * dpi) / sensor.optical_res; - size = pixels * channels * lines * (depth / 8); - std::vector data(size); - dev->scanhead_position_in_steps = 0; - - local_reg = dev->reg; - - SetupParams params; - params.xres = dpi; - params.yres = dpi; - params.startx = 0; - params.starty = 0; - params.pixels = pixels; - params.lines = lines; - params.depth = depth; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::GRAY; - params.color_filter = ColorFilter::RED; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA; - - status = gl847_init_scan_regs(dev, sensor, &local_reg, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup for scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* set up for reverse or forward */ - r = sanei_genesys_get_address(&local_reg, REG02); - if (forward) - r->value &= ~REG02_MTRREV; - else - r->value |= REG02_MTRREV; - - - status = dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl847_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl847_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl847_stop_action failed\n", __func__); - return status; - } - - pass = 0; - if (DBG_LEVEL >= DBG_data) - { - sprintf(title, "gl847_search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); - } - - /* loop until strip is found or maximum pass number done */ - found = 0; - while (pass < 20 && !found) - { - status = - dev->model->cmd_set->bulk_write_register(dev, local_reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: Failed to bulk write registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* now start scan */ - status = gl847_begin_scan(dev, sensor, &local_reg, SANE_TRUE); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to begin scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - /* waits for valid data */ - do - sanei_genesys_test_buffer_empty (dev, &steps); - while (steps); - - /* now we're on target, we can read data */ - status = sanei_genesys_read_data_from_scanner(dev, data.data(), size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read data: %s\n", __func__, sane_strstatus(status)); - return status; - } - - status = gl847_stop_action (dev); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: gl847_stop_action failed\n", __func__); - return status; - } - - if (DBG_LEVEL >= DBG_data) - { - sprintf(title, "gl847_search_strip_%s_%s%02d.pnm", - black ? "black" : "white", forward ? "fwd" : "bwd", (int)pass); - sanei_genesys_write_pnm_file(title, data.data(), depth, channels, pixels, lines); - } - - /* search data to find black strip */ - /* when searching forward, we only need one line of the searched color since we - * will scan forward. But when doing backward search, we need all the area of the - * same color */ - if (forward) - { - for (y = 0; y < lines && !found; y++) - { - count = 0; - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - - /* at end of line, if count >= 3%, line is not fully of the desired color - * so we must go to next line of the buffer */ - /* count*100/pixels < 3 */ - if ((count * 100) / pixels < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found forward during pass %d at line %d\n", __func__, - pass, y); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - } - else /* since calibration scans are done forward, we need the whole area - to be of the required color when searching backward */ - { - count = 0; - for (y = 0; y < lines; y++) - { - /* count of white/black pixels depending on the color searched */ - for (x = 0; x < pixels; x++) - { - /* when searching for black, detect white pixels */ - if (black && data[y * pixels + x] > 90) - { - count++; - } - /* when searching for white, detect black pixels */ - if (!black && data[y * pixels + x] < 60) - { - count++; - } - } - } - - /* at end of area, if count >= 3%, area is not fully of the desired color - * so we must go to next buffer */ - if ((count * 100) / (pixels * lines) < 3) - { - found = 1; - DBG(DBG_data, "%s: strip found backward during pass %d \n", __func__, pass); - } - else - { - DBG(DBG_data, "%s: pixels=%d, count=%d (%d%%)\n", __func__, pixels, count, - (100 * count) / pixels); - } - } - pass++; - } - - if (found) - { - status = SANE_STATUS_GOOD; - DBG(DBG_info, "%s: %s strip found\n", __func__, black ? "black" : "white"); - } - else - { - status = SANE_STATUS_UNSUPPORTED; - DBG(DBG_info, "%s: %s strip not found\n", __func__, black ? "black" : "white"); - } - - DBGCOMPLETED; - return status; -} - -/** - * average dark pixels of a 8 bits scan - */ -static int -dark_average (uint8_t * data, unsigned int pixels, unsigned int lines, - unsigned int channels, unsigned int black) -{ - unsigned int i, j, k, average, count; - unsigned int avg[3]; - uint8_t val; - - /* computes average value on black margin */ - for (k = 0; k < channels; k++) - { - avg[k] = 0; - count = 0; - for (i = 0; i < lines; i++) - { - for (j = 0; j < black; j++) - { - val = data[i * channels * pixels + j + k]; - avg[k] += val; - count++; - } - } - if (count) - avg[k] /= count; - DBG(DBG_info, "%s: avg[%d] = %d\n", __func__, k, avg[k]); - } - average = 0; - for (i = 0; i < channels; i++) - average += avg[i]; - average /= channels; - DBG(DBG_info, "%s: average = %d\n", __func__, average); - return average; -} - -static SANE_Status -gl847_offset_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t reg04; - unsigned int channels, bpp; - int pass = 0, avg, total_size; - int topavg, bottomavg, resolution, lines; - int top, bottom, black_pixels, pixels; - - DBGSTART; - - /* no gain nor offset for AKM AFE */ - RIE (sanei_genesys_read_register (dev, REG04, ®04)); - if ((reg04 & REG04_FESET) == 0x02) - { - DBGCOMPLETED; - return status; - } - - /* offset calibration is always done in color mode */ - channels = 3; - resolution=sensor.optical_res; - dev->calib_pixels = sensor.sensor_pixels; - lines=1; - bpp=8; - pixels= (sensor.sensor_pixels*resolution) / sensor.optical_res; - black_pixels = (sensor.black_pixels * resolution) / sensor.optical_res; - DBG(DBG_io2, "%s: black_pixels=%d\n", __func__, black_pixels); - - SetupParams params; - params.xres = resolution; - params.yres = resolution; - params.startx = 0; - params.starty = 0; - params.pixels = pixels; - params.lines = lines; - params.depth = bpp; - params.channels = channels; - params.scan_method = dev->settings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - status = gl847_init_scan_regs(dev, sensor, ®s, params); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - sanei_genesys_set_motor_power(regs, false); - - /* allocate memory for scans */ - total_size = pixels * channels * lines * (bpp/8); /* colors * bytes_per_color * scan lines */ - - std::vector first_line(total_size); - std::vector second_line(total_size); - - /* init gain */ - dev->frontend.set_gain(0, 0); - dev->frontend.set_gain(1, 0); - dev->frontend.set_gain(2, 0); - - /* scan with no move */ - bottom = 10; - dev->frontend.set_offset(0, bottom); - dev->frontend.set_offset(1, bottom); - dev->frontend.set_offset(2, bottom); - - RIE(gl847_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting first line reading\n", __func__); - RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, first_line.data(), total_size)); - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl847_offset%03d.pnm", bottom); - sanei_genesys_write_pnm_file(fn, first_line.data(), bpp, channels, pixels, lines); - } - - bottomavg = dark_average (first_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_io2, "%s: bottom avg=%d\n", __func__, bottomavg); - - /* now top value */ - top = 255; - dev->frontend.set_offset(0, top); - dev->frontend.set_offset(1, top); - dev->frontend.set_offset(2, top); - RIE(gl847_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); - - topavg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_io2, "%s: top avg=%d\n", __func__, topavg); - - /* loop until acceptable level */ - while ((pass < 32) && (top - bottom > 1)) - { - pass++; - - /* settings for new scan */ - dev->frontend.set_offset(0, (top + bottom) / 2); - dev->frontend.set_offset(1, (top + bottom) / 2); - dev->frontend.set_offset(2, (top + bottom) / 2); - - /* scan with no move */ - RIE(gl847_set_fe(dev, sensor, AFE_SET)); - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - DBG(DBG_info, "%s: starting second line reading\n", __func__); - RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner (dev, second_line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) - { - char fn[30]; - snprintf(fn, 30, "gl847_offset%03d.pnm", dev->frontend.get_offset(1)); - sanei_genesys_write_pnm_file(fn, second_line.data(), bpp, channels, pixels, lines); - } - - avg = dark_average(second_line.data(), pixels, lines, channels, black_pixels); - DBG(DBG_info, "%s: avg=%d offset=%d\n", __func__, avg, dev->frontend.get_offset(1)); - - /* compute new boundaries */ - if (topavg == avg) - { - topavg = avg; - top = dev->frontend.get_offset(1); - } - else - { - bottomavg = avg; - bottom = dev->frontend.get_offset(1); - } - } - DBG(DBG_info, "%s: offset=(%d,%d,%d)\n", __func__, - dev->frontend.get_offset(0), - dev->frontend.get_offset(1), - dev->frontend.get_offset(2)); - - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -static SANE_Status -gl847_coarse_gain_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, int dpi) -{ - int pixels; - int total_size; - uint8_t reg04; - int i, j, channels; - SANE_Status status = SANE_STATUS_GOOD; - int max[3]; - float gain[3],coeff; - int val, code, lines; - int resolution; - int bpp; - - DBG(DBG_proc, "%s: dpi = %d\n", __func__, dpi); - - /* no gain nor offset for AKM AFE */ - RIE (sanei_genesys_read_register (dev, REG04, ®04)); - if ((reg04 & REG04_FESET) == 0x02) - { - DBGCOMPLETED; - return status; - } - - /* coarse gain calibration is always done in color mode */ - channels = 3; - - /* follow CKSEL */ - if(dev->settings.xressettings.scan_method; - params.scan_mode = ScanColorMode::COLOR_SINGLE_PASS; - params.color_filter = dev->settings.color_filter; - params.flags = SCAN_FLAG_DISABLE_SHADING | - SCAN_FLAG_DISABLE_GAMMA | - SCAN_FLAG_SINGLE_LINE | - SCAN_FLAG_IGNORE_LINE_DISTANCE; - - try { - status = gl847_init_scan_regs(dev, sensor, ®s, params); - } catch (...) { - try { - sanei_genesys_set_motor_power(regs, false); - } catch (...) {} - throw; - } - - sanei_genesys_set_motor_power(regs, false); - - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to setup scan: %s\n", __func__, sane_strstatus(status)); - return status; - } - - RIE(dev->model->cmd_set->bulk_write_register(dev, regs)); - - total_size = pixels * channels * (16/bpp) * lines; - - std::vector line(total_size); - - RIE(gl847_set_fe(dev, sensor, AFE_SET)); - RIE(gl847_begin_scan(dev, sensor, ®s, SANE_TRUE)); - RIE(sanei_genesys_read_data_from_scanner(dev, line.data(), total_size)); - - if (DBG_LEVEL >= DBG_data) - sanei_genesys_write_pnm_file("gl847_gain.pnm", line.data(), bpp, channels, pixels, lines); - - /* average value on each channel */ - for (j = 0; j < channels; j++) - { - max[j] = 0; - for (i = pixels/4; i < (pixels*3/4); i++) - { - if(bpp==16) - { - if (dev->model->is_cis) - val = - line[i * 2 + j * 2 * pixels + 1] * 256 + - line[i * 2 + j * 2 * pixels]; - else - val = - line[i * 2 * channels + 2 * j + 1] * 256 + - line[i * 2 * channels + 2 * j]; - } - else - { - if (dev->model->is_cis) - val = line[i + j * pixels]; - else - val = line[i * channels + j]; - } - - max[j] += val; - } - max[j] = max[j] / (pixels/2); - - gain[j] = ((float) sensor.gain_white_ref*coeff) / max[j]; - - /* turn logical gain value into gain code, checking for overflow */ - code = 283 - 208 / gain[j]; - if (code > 255) - code = 255; - else if (code < 0) - code = 0; - dev->frontend.set_gain(j, code); - - DBG(DBG_proc, "%s: channel %d, max=%d, gain = %f, setting:%d\n", __func__, j, max[j], gain[j], - dev->frontend.get_gain(j)); - } - - if (dev->model->is_cis) { - uint8_t gain0 = dev->frontend.get_gain(0); - if (gain0 > dev->frontend.get_gain(1)) { - gain0 = dev->frontend.get_gain(1); - } - if (gain0 > dev->frontend.get_gain(2)) { - gain0 = dev->frontend.get_gain(2); - } - dev->frontend.set_gain(0, gain0); - dev->frontend.set_gain(1, gain0); - dev->frontend.set_gain(2, gain0); - } - - if (channels == 1) { - dev->frontend.set_gain(0, dev->frontend.get_gain(1)); - dev->frontend.set_gain(2, dev->frontend.get_gain(1)); - } - - RIE (gl847_stop_action (dev)); - - status=gl847_slow_back_home (dev, SANE_TRUE); - - DBGCOMPLETED; - return status; -} - - -/** the gl847 command set */ -static Genesys_Command_Set gl847_cmd_set = { - "gl847-generic", /* the name of this set */ - - nullptr, - - gl847_init, - NULL, /*gl847_init_regs_for_warmup*/ - gl847_init_regs_for_coarse_calibration, - gl847_init_regs_for_shading, - gl847_init_regs_for_scan, - - gl847_get_filter_bit, - gl847_get_lineart_bit, - gl847_get_bitset_bit, - gl847_get_gain4_bit, - gl847_get_fast_feed_bit, - gl847_test_buffer_empty_bit, - gl847_test_motor_flag_bit, - - gl847_set_fe, - gl847_set_powersaving, - gl847_save_power, - - gl847_begin_scan, - gl847_end_scan, - - sanei_genesys_send_gamma_table, - - gl847_search_start_position, - - gl847_offset_calibration, - gl847_coarse_gain_calibration, - gl847_led_calibration, - - NULL, - gl847_slow_back_home, - NULL, /* disable gl847_rewind, see #7 */ - - sanei_genesys_bulk_write_register, - NULL, - sanei_genesys_bulk_read_data, - - gl847_update_hardware_sensors, - - NULL, /* no known gl847 sheetfed scanner */ - NULL, /* no known gl847 sheetfed scanner */ - NULL, /* no known gl847 sheetfed scanner */ - gl847_search_strip, - - sanei_genesys_is_compatible_calibration, - NULL, - gl847_send_shading_data, - gl847_calculate_current_setup, - gl847_boot -}; - -SANE_Status -sanei_gl847_init_cmd_set (Genesys_Device * dev) -{ - dev->model->cmd_set = &gl847_cmd_set; - return SANE_STATUS_GOOD; -} diff --git a/backend/genesys_gl847.h b/backend/genesys_gl847.h deleted file mode 100644 index 7af9c36..0000000 --- a/backend/genesys_gl847.h +++ /dev/null @@ -1,510 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2013 Stéphane Voltz - - 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 "genesys.h" - -#define REG01 0x01 -#define REG01_CISSET 0x80 -#define REG01_DOGENB 0x40 -#define REG01_DVDSET 0x20 -#define REG01_STAGGER 0x10 -#define REG01_COMPENB 0x08 -#define REG01_TRUEGRAY 0x04 -#define REG01_SHDAREA 0x02 -#define REG01_SCAN 0x01 - -#define REG02 0x02 -#define REG02_NOTHOME 0x80 -#define REG02_ACDCDIS 0x40 -#define REG02_AGOHOME 0x20 -#define REG02_MTRPWR 0x10 -#define REG02_FASTFED 0x08 -#define REG02_MTRREV 0x04 -#define REG02_HOMENEG 0x02 -#define REG02_LONGCURV 0x01 - -#define REG03 0x03 -#define REG03_LAMPDOG 0x80 -#define REG03_AVEENB 0x40 -#define REG03_XPASEL 0x20 -#define REG03_LAMPPWR 0x10 -#define REG03_LAMPTIM 0x0f - -#define REG04 0x04 -#define REG04_LINEART 0x80 -#define REG04_BITSET 0x40 -#define REG04_AFEMOD 0x30 -#define REG04_FILTER 0x0c -#define REG04_FESET 0x03 - -#define REG04S_AFEMOD 4 - -#define REG05 0x05 -#define REG05_DPIHW 0xc0 -#define REG05_DPIHW_600 0x00 -#define REG05_DPIHW_1200 0x40 -#define REG05_DPIHW_2400 0x80 -#define REG05_DPIHW_4800 0xc0 -#define REG05_MTLLAMP 0x30 -#define REG05_GMMENB 0x08 -#define REG05_MTLBASE 0x03 - -#define REG06_SCANMOD 0xe0 -#define REG06S_SCANMOD 5 -#define REG06_PWRBIT 0x10 -#define REG06_GAIN4 0x08 -#define REG06_OPTEST 0x07 - -#define REG07_LAMPSIM 0x80 - -#define REG08_DRAM2X 0x80 -#define REG08_MPENB 0x20 -#define REG08_CIS_LINE 0x10 -#define REG08_IR1ENB 0x08 -#define REG08_IR2ENB 0x04 -#define REG08_ENB24M 0x01 - -#define REG09_MCNTSET 0xc0 -#define REG09_EVEN1ST 0x20 -#define REG09_BLINE1ST 0x10 -#define REG09_BACKSCAN 0x08 -#define REG09_ENHANCE 0x04 -#define REG09_SHORTTG 0x02 -#define REG09_NWAIT 0x01 - -#define REG09S_MCNTSET 6 -#define REG09S_CLKSET 4 - - -#define REG0A_LPWMEN 0x10 - -#define REG0B 0x0b -#define REG0B_DRAMSEL 0x07 -#define REG0B_ENBDRAM 0x08 -#define REG0B_ENBDRAM 0x08 -#define REG0B_RFHDIS 0x10 -#define REG0B_CLKSET 0xe0 -#define REG0B_24MHZ 0x00 -#define REG0B_30MHZ 0x20 -#define REG0B_40MHZ 0x40 -#define REG0B_48MHZ 0x60 -#define REG0B_60MHZ 0x80 - -#define REG0C 0x0c -#define REG0C_CCDLMT 0x0f - -#define REG0D 0x0d -#define REG0D_FULLSTP 0x10 -#define REG0D_SEND 0x80 -#define REG0D_CLRMCNT 0x04 -#define REG0D_CLRDOCJM 0x02 -#define REG0D_CLRLNCNT 0x01 - -#define REG0F 0x0f - -#define REG16_CTRLHI 0x80 -#define REG16_TOSHIBA 0x40 -#define REG16_TGINV 0x20 -#define REG16_CK1INV 0x10 -#define REG16_CK2INV 0x08 -#define REG16_CTRLINV 0x04 -#define REG16_CKDIS 0x02 -#define REG16_CTRLDIS 0x01 - -#define REG17_TGMODE 0xc0 -#define REG17_TGMODE_NO_DUMMY 0x00 -#define REG17_TGMODE_REF 0x40 -#define REG17_TGMODE_XPA 0x80 -#define REG17_TGW 0x3f -#define REG17S_TGW 0 - -#define REG18 0x18 -#define REG18_CNSET 0x80 -#define REG18_DCKSEL 0x60 -#define REG18_CKTOGGLE 0x10 -#define REG18_CKDELAY 0x0c -#define REG18_CKSEL 0x03 - -#define REG1A_SW2SET 0x80 -#define REG1A_SW1SET 0x40 -#define REG1A_MANUAL3 0x02 -#define REG1A_MANUAL1 0x01 -#define REG1A_CK4INV 0x08 -#define REG1A_CK3INV 0x04 -#define REG1A_LINECLP 0x02 - -#define REG1C 0x1c -#define REG1C_TGTIME 0x07 - -#define REG1D_CK4LOW 0x80 -#define REG1D_CK3LOW 0x40 -#define REG1D_CK1LOW 0x20 -#define REG1D_TGSHLD 0x1f -#define REG1DS_TGSHLD 0 - - -#define REG1E_WDTIME 0xf0 -#define REG1ES_WDTIME 4 -#define REG1E_LINESEL 0x0f -#define REG1ES_LINESEL 0 - -#define REG_FEDCNT 0x1f - -#define REG24 0x1c -#define REG40 0x40 -#define REG40_CHKVER 0x10 -#define REG40_HISPDFLG 0x04 -#define REG40_MOTMFLG 0x02 -#define REG40_DATAENB 0x01 - -#define REG41_PWRBIT 0x80 -#define REG41_BUFEMPTY 0x40 -#define REG41_FEEDFSH 0x20 -#define REG41_SCANFSH 0x10 -#define REG41_HOMESNR 0x08 -#define REG41_LAMPSTS 0x04 -#define REG41_FEBUSY 0x02 -#define REG41_MOTORENB 0x01 - -#define REG58_VSMP 0xf8 -#define REG58S_VSMP 3 -#define REG58_VSMPW 0x07 -#define REG58S_VSMPW 0 - -#define REG59_BSMP 0xf8 -#define REG59S_BSMP 3 -#define REG59_BSMPW 0x07 -#define REG59S_BSMPW 0 - -#define REG5A_ADCLKINV 0x80 -#define REG5A_RLCSEL 0x40 -#define REG5A_CDSREF 0x30 -#define REG5AS_CDSREF 4 -#define REG5A_RLC 0x0f -#define REG5AS_RLC 0 - -#define REG5E_DECSEL 0xe0 -#define REG5ES_DECSEL 5 -#define REG5E_STOPTIM 0x1f -#define REG5ES_STOPTIM 0 - -#define REG60 0x60 -#define REG60_Z1MOD 0x1f -#define REG61 0x61 -#define REG61_Z1MOD 0xff -#define REG62 0x62 -#define REG62_Z1MOD 0xff - -#define REG63 0x63 -#define REG63_Z2MOD 0x1f -#define REG64 0x64 -#define REG64_Z2MOD 0xff -#define REG65 0x65 -#define REG65_Z2MOD 0xff - -#define REG60S_STEPSEL 5 -#define REG60_STEPSEL 0xe0 -#define REG60_FULLSTEP 0x00 -#define REG60_HALFSTEP 0x20 -#define REG60_EIGHTHSTEP 0x60 -#define REG60_16THSTEP 0x80 - -#define REG63S_FSTPSEL 5 -#define REG63_FSTPSEL 0xe0 -#define REG63_FULLSTEP 0x00 -#define REG63_HALFSTEP 0x20 -#define REG63_EIGHTHSTEP 0x60 -#define REG63_16THSTEP 0x80 - -#define REG67 0x67 -#define REG67_MTRPWM 0x80 - -#define REG68 0x68 -#define REG68_FASTPWM 0x80 - -#define REG6B 0x6b -#define REG6B_MULTFILM 0x80 -#define REG6B_GPOM13 0x40 -#define REG6B_GPOM12 0x20 -#define REG6B_GPOM11 0x10 -#define REG6B_GPO18 0x02 -#define REG6B_GPO17 0x01 - -#define REG6C 0x6c -#define REG6C_GPIO16 0x80 -#define REG6C_GPIO15 0x40 -#define REG6C_GPIO14 0x20 -#define REG6C_GPIO13 0x10 -#define REG6C_GPIO12 0x08 -#define REG6C_GPIO11 0x04 -#define REG6C_GPIO10 0x02 -#define REG6C_GPIO9 0x01 -#define REG6C_GPIOH 0xff -#define REG6C_GPIOL 0xff - -#define REG6D 0x6d -#define REG6E 0x6e -#define REG6F 0x6f -#define REG7E 0x7e - -#define REG87_LEDADD 0x04 - -#define REG9E 0x9e -#define REG9F 0x9f - -#define REGA6 0xa6 -#define REGA7 0xa7 -#define REGA8 0xa8 -#define REGA9 0xa9 -#define REGAB 0xab - -#define REG_EXPR 0x10 -#define REG_EXPG 0x12 -#define REG_EXPB 0x14 -#define REG_EXPDMY 0x19 -#define REG_STEPNO 0x21 -#define REG_FWDSTEP 0x22 -#define REG_BWDSTEP 0x23 -#define REG_FASTNO 0x24 -#define REG_DPISET 0x2c -#define REG_STRPIXEL 0x30 -#define REG_ENDPIXEL 0x32 -#define REG_LINCNT 0x25 -#define REG_MAXWD 0x35 -#define REG_LPERIOD 0x38 -#define REG_FEEDL 0x3d -#define REG_FMOVDEC 0x5f -#define REG_FSHDEC 0x69 -#define REG_FMOVNO 0x6a -#define REG_CK1MAP 0x74 -#define REG_CK3MAP 0x77 -#define REG_CK4MAP 0x7a - -#define SETREG(adr,val) { dev->reg.init_reg(adr, val); } - -/** set up registers for an actual scan - * - * this function sets up the scanner to scan in normal or single line mode - */ -static SANE_Status gl847_init_scan_regs(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, SetupParams& params); - -/* Send the low-level scan command */ -static SANE_Status gl847_begin_scan (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set * reg, SANE_Bool start_motor); - -/* Send the stop scan command */ -static SANE_Status gl847_end_scan (Genesys_Device * dev, Genesys_Register_Set * reg, SANE_Bool check_stop); - -static SANE_Status gl847_init (Genesys_Device * dev); - -/** @brief moves the slider to steps at motor base dpi - * @param dev device to work on - * @param steps number of steps to move - * */ -static SANE_Status -gl847_feed (Genesys_Device * dev, unsigned int steps); - -typedef struct -{ - uint8_t sensor_id; - uint8_t r6b; - uint8_t r6c; - uint8_t r6d; - uint8_t r6e; - uint8_t r6f; - uint8_t ra6; - uint8_t ra7; - uint8_t ra8; - uint8_t ra9; -} Gpio_Profile; - -static Gpio_Profile gpios[]={ - { GPO_CANONLIDE200, 0x02, 0xf9, 0x20, 0xff, 0x00, 0x04, 0x04, 0x00, 0x00}, - { GPO_CANONLIDE700, 0x06, 0xdb, 0xff, 0xff, 0x80, 0x15, 0x07, 0x20, 0x10}, - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, -}; - -typedef struct -{ - uint8_t dramsel; - uint8_t rd0; - uint8_t rd1; - uint8_t rd2; - uint8_t re0; - uint8_t re1; - uint8_t re2; - uint8_t re3; - uint8_t re4; - uint8_t re5; - uint8_t re6; - uint8_t re7; -} Memory_layout; - -static Memory_layout layouts[]={ - /* LIDE 100 */ - { - 0x29, - 0x0a, 0x15, 0x20, - 0x00, 0xac, 0x02, 0x55, 0x02, 0x56, 0x03, 0xff - }, - /* LIDE 200 */ - { - 0x29, - 0x0a, 0x1f, 0x34, - 0x01, 0x24, 0x02, 0x91, 0x02, 0x92, 0x03, 0xff - }, - /* 5600F */ - { - 0x29, - 0x0a, 0x1f, 0x34, - 0x01, 0x24, 0x02, 0x91, 0x02, 0x92, 0x03, 0xff - }, - /* LIDE 700F */ - { - 0x2a, - 0x0a, 0x33, 0x5c, - 0x02, 0x14, 0x09, 0x09, 0x09, 0x0a, 0x0f, 0xff - } -}; - -/** @brief structure for sensor settings - * this structure describes the sensor settings to use for a given - * exposure. - */ -typedef struct { - int sensor_type; /**> sensor id */ - int dpi; /**> maximum dpi for which data are valid */ - int exposure; /**> exposure */ - int ck1map; /**> CK1MAP */ - int ck3map; /**> CK3MAP */ - int ck4map; /**> CK4MAP */ - int segcnt; /**> SEGCNT */ - int expdummy; /**> exposure dummy */ - int expr; /**> initial red exposure */ - int expg; /**> initial green exposure */ - int expb; /**> initial blue exposure */ - size_t *order; /**> order of sub-segments */ - uint8_t r17; /**> TG width */ -} Sensor_Profile; - -static size_t order_01[]={0,1}; -static size_t order_0213[]={0,2,1,3}; -static size_t order_0246[]={0,2,4,6,1,3,5,7}; - -static size_t new_order[]={0,1,2,3}; -static size_t order_0145[]={0,1,4,5,2,3,6,7}; - -/** - * database of sensor profiles - */ -static Sensor_Profile sensors[]={ - {CIS_CANONLIDE100, 200, 2848, 60, 159, 85, 5136, 255, 410, 275, 203, NULL , 0x0a}, - {CIS_CANONLIDE100, 300, 1424, 60, 159, 85, 5136, 255, 410, 275, 203, NULL , 0x0a}, - {CIS_CANONLIDE100, 600, 1432, 60, 159, 85, 5136, 255, 410, 275, 203, NULL , 0x0a}, - {CIS_CANONLIDE100, 1200, 2712, 60, 159, 85, 5136, 255, 746, 478, 353, order_01 , 0x08}, - {CIS_CANONLIDE100, 2400, 5280, 60, 159, 85, 5136, 255, 1417, 909, 643, order_0213, 0x06}, - /* - {CIS_CANONLIDE200, 150, 2848, 240, 636, 340, 5144, 0, 255, 637, 637, 637}, - {CIS_CANONLIDE200, 300, 1424, 240, 636, 340, 5144, 0, 255, 637, 637, 637}, - */ - {CIS_CANONLIDE200, 200, 2848, 60, 159, 85, 5136, 255, 410, 275, 203, NULL , 0x0a}, - {CIS_CANONLIDE200, 300, 1424, 60, 159, 85, 5136, 255, 410, 275, 203, NULL , 0x0a}, - {CIS_CANONLIDE200, 600, 1432, 60, 159, 85, 5136, 255, 410, 275, 203, NULL , 0x0a}, - {CIS_CANONLIDE200, 1200, 2712, 60, 159, 85, 5136, 255, 746, 478, 353, order_01 , 0x08}, - {CIS_CANONLIDE200, 2400, 5280, 60, 159, 85, 5136, 255, 1417, 909, 643, order_0213, 0x06}, - {CIS_CANONLIDE200, 4800, 10416, 60, 159, 85, 5136, 255, 2692, 1728, 1221, order_0246, 0x04}, - - /* LiDE 700F */ - {CIS_CANONLIDE700, 150, 2848, 135, 249, 85, 5187, 255, 465, 310, 239, NULL , 0x0c}, - {CIS_CANONLIDE700, 300, 1424, 135, 249, 85, 5187, 255, 465, 310, 239, NULL , 0x0c}, - {CIS_CANONLIDE700, 600, 1504, 135, 249, 85, 5187, 255, 465, 310, 239, NULL , 0x0c}, - {CIS_CANONLIDE700, 1200, 2696, 135, 249, 85, 5187, 255, 1464, 844, 555, order_01 , 0x0a}, - {CIS_CANONLIDE700, 2400, 10576, 135, 249, 85, 5187, 255, 2798, 1558, 972, new_order , 0x08}, - {CIS_CANONLIDE700, 4800, 10576, 135, 249, 85, 5187, 255, 2798, 1558, 972, order_0145, 0x06}, -}; - -/* base motor sopes in full step unit */ -/* target=((exposure * dpi) / base_dpi)>>step_type; */ -static uint32_t lide200_base[] = { 46876, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2343, 2336, 2329, 2322, 2314, 2307, 2300,2292,2285,2278,2271,2263,2256,2249,2241,2234,2227,2219,2212,2205,2198,2190,2183,2176,2168,2161,2154,2146,2139,2132,2125,2117,2110,2103,2095,2088,2081,2073,2066,2059,2052,2044,2037,2030,2022,2015,2008,2001,1993,1986,1979,1971,1964,1957,1949,1942,1935,1928,1920,1913,1906,1898,1891,1884,1876,1869,1862,1855,1847,1840,1833,1825,1818,1811,1803,1796,1789,1782,1774,1767,1760,1752,1745,1738,1731,1723,1716,1709,1701,1694,1687,1679,1672,1665,1658,1650,1643,1636,1628,1621,1614,1606,1599,1592,1585,1577,1570,1563,1555,1548,1541,1533,1526,1519,1512,1504,1497,1490,1482,1475,1468,1461,1453,1446,1439,1431,1424,1417,1409,1402,1395,1388,1380,1373,1366,1358,1351,1344,1336,1329,1322,1315,1307,1300,1293,1285,1278,1271,1263,1256,1249,1242,1234,1227,1220,1212,1205,1198,1191,1183,1176,1169,1161,1154,1147,1139,1132,1125,1118,1110,1103,1096,1088,1081,1074,1066,1059,1052,1045,1037,1030,1023,1015,1008,1001,993,986,979,972,964,957,950,942,935,928,921,913,906,899,891,884,877,869,862,855,848,840,833,826,818,811,804,796,789,782,775,767,760,753,745,738,731,723,716,709,702,694,687,680,672,665,658,651,643,636,629,621,614,607,599,592,585,578,570,563,556,534,534, 0}; -static uint32_t lide200_medium[] = { 46876, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136, 8136,2343, 2336, 2329, 2322, 2314, 2307, 2300,2292,2285,2278,2271,2263,2256,2249,2241,2234,2227,2219,2212,2205,2198,2190,2183,2176,2168,2161,2154,2146,2139,2132,2125,2117,2110,2103,2095,2088,2081,2073,2066,2059,2052,2044,2037,2030,2022,2015,2008,2001,1993,1986,1979,1971,1964,1957,1949,1942,1935,1928,1920,1913,1906,1898,1891,1884,1876,1869,1862,1855,1847,1840,1833,1825,1818,1811,1803,1796,1789,1782,1774,1767,1760,1752,1745,1738,1731,1723,1716,1709,1701,1694,1687,1679,1672,1665,1658,1650,1643,1636,1628,1621,1614,1606,1599,1592,1585,1577,1570,1563,1555,1548,1541,1533,1526,1519,1512,1504,1497,1490,1482,1475,1468,1461,1453,1446,1439,1431,1424,1417,1409,1402,1395,1388,1380,1373,1366,1358,1351,1344,1336,1329,1322,1315,1307,1300,1293,1285,1278,1271,1263,1256,1249,1242,1234,1227,1220,1212,1205,1198,1191,1183,1176,1169,1161,1154,1147,1139,1132,1125,1118,1110,1103,1096,1088,1081,1074,1066,1059,1052,1045,1037,1030,1023,1015,1008,1001,993,986,979,972,964,957,950,942,935,928,921,913,906,899,891,884,877,869,862,855,848,840,833,826,818,811,804,796,789,782,775,767,760,753,745,738,731,723,716,709,702,694,687,680,672,665,658,651,643,636,629,621,614,607,599,592,585,578,570,563,556,534,534, 0}; -static uint32_t lide200_high[] = { 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 31680, 2219,2212,2205,2198,2190,2183,2176,2168,2161,2154,2146,2139,2132,2125,2117,2110,2103,2095,2088,2081,2073,2066,2059,2052,2044,2037,2030,2022,2015,2008,2001,1993,1986,1979,1971,1964,1957,1949,1942,1935,1928,1920,1913,1906,1898,1891,1884,1876,1869,1862,1855,1847,1840,1833,1825,1818,1811,1803,1796,1789,1782,1774,1767,1760,1752,1745,1738,1731,1723,1716,1709,1701,1694,1687,1679,1672,1665,1658,1650,1643,1636,1628,1621,1614,1606,1599,1592,1585,1577,1570,1563,1555,1548,1541,1533,1526,1519,1512,1504,1497,1490,1482,1475,1468,1461,1453,1446,1439,1431,1424,1417,1409,1402,1395,1388,1380,1373,1366,1358,1351,1344,1336,1329,1322,1315,1307,1300,1293,1285,1278,1271,1263,1256,1249,1242,1234,1227,1220,1212,1205,1198,1191,1183,1176,1169,1161,1154,1147,1139,1132,1125,1118,1110,1103,1096,1088,1081,1074,1066,1059,1052,1045,1037,1030,1023,1015,1008,1001,993,986,979,972,964,957,950,942,935,928,921,913,906,899,891,884,877,869,862,855,848,840,833,826,818,811,804,796,789,782,775,767,760,753,745,738,731,723,716,709,702,694,687,680,672,665,658,651,643,636,629,621,614,607,599,592,585,578,570,563,556,534,534, 0}; -static uint32_t lide700_medium[] = { 46876,2342,2342,2342,2342,2342,2342,2342,2342,2302,2286,2274,2266,2258,2252,2244,2240,2234,2228,2224,2218,2216,2210,2208,2202,2200,2194,2192,2190,2186,2182,2180,2176,2174,2172,2170,2166,2162,2160,2156,2154,2152,2150,2150,2146,2144,2142,2140,2136,2134,2132,2130,2130,2128,2124,2122,2120,2120,2118,2116,2112,2112,2110,2108,2106,2106,2104,2102,2102,2098,2096,2094,2094,2092,2090,2090,2086,2084,2084,2082,2082,2080,2078,2078,2076,2074,2074,2070,2070,2068,2066,2066,2064,2064,2062,2062,2060,2058,2058,2054,2054,2052,2052,2050,2050,2048,2048,2046,2046,2044,2042,2042,2040,2040,2038,2038,2034,2034,2032,2032,2030,2030,2028,2028,2026,2026,2022,2022}; -static uint32_t lide700_high[] = { 46876,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864,15864}; -/* 5190 trop - * 5186 pas assez - */ -/* -static uint32_t lide200_max[] = { 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 124992, 2219,2212,2205,2198,2190,2183,2176,2168,2161,2154,2146,2139,2132,2125,2117,2110,2103,2095,2088,2081,2073,2066,2059,2052,2044,2037,2030,2022,2015,2008,2001,1993,1986,1979,1971,1964,1957,1949,1942,1935,1928,1920,1913,1906,1898,1891,1884,1876,1869,1862,1855,1847,1840,1833,1825,1818,1811,1803,1796,1789,1782,1774,1767,1760,1752,1745,1738,1731,1723,1716,1709,1701,1694,1687,1679,1672,1665,1658,1650,1643,1636,1628,1621,1614,1606,1599,1592,1585,1577,1570,1563,1555,1548,1541,1533,1526,1519,1512,1504,1497,1490,1482,1475,1468,1461,1453,1446,1439,1431,1424,1417,1409,1402,1395,1388,1380,1373,1366,1358,1351,1344,1336,1329,1322,1315,1307,1300,1293,1285,1278,1271,1263,1256,1249,1242,1234,1227,1220,1212,1205,1198,1191,1183,1176,1169,1161,1154,1147,1139,1132,1125,1118,1110,1103,1096,1088,1081,1074,1066,1059,1052,1045,1037,1030,1023,1015,1008,1001,993,986,979,972,964,957,950,942,935,928,921,913,906,899,891,884,877,869,862,855,848,840,833,826,818,811,804,796,789,782,775,767,760,753,745,738,731,723,716,709,702,694,687,680,672,665,658,651,643,636,629,621,614,607,599,592,585,578,570,563,556,534,534, 0}; -*/ - -/** - * database of motor profiles - */ - -static Motor_Profile gl847_motors[]={ - /* LiDE 100 */ - {MOTOR_CANONLIDE100, 2848, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE100, 1424, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE100, 1432, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE100, 2712, QUARTER_STEP, lide200_medium}, - {MOTOR_CANONLIDE100, 5280, EIGHTH_STEP , lide200_high}, - - /* LiDE 200 */ - {MOTOR_CANONLIDE200, 2848, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE200, 1424, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE200, 1432, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE200, 2712, QUARTER_STEP, lide200_medium}, - {MOTOR_CANONLIDE200, 5280, EIGHTH_STEP , lide200_high}, - {MOTOR_CANONLIDE200, 10416, EIGHTH_STEP , lide200_high}, - - /* LiDE 700F */ - {MOTOR_CANONLIDE700, 2848, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE700, 1424, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE700, 1504, HALF_STEP , lide200_base}, - {MOTOR_CANONLIDE700, 2696, HALF_STEP , lide700_medium}, /* 2696 , 2838 */ - {MOTOR_CANONLIDE700, 10576, EIGHTH_STEP, lide700_high}, - - /* end of database entry */ - {0, 0, 0, NULL}, -}; diff --git a/backend/genesys_low.cc b/backend/genesys_low.cc deleted file mode 100644 index 097375f..0000000 --- a/backend/genesys_low.cc +++ /dev/null @@ -1,2059 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2010-2013 Stéphane Voltz - - - 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. -*/ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_low.h" -#include "assert.h" - -#include - - -Genesys_Device::~Genesys_Device() -{ - clear(); - - if (file_name != nullptr) - free(file_name); -} - -void Genesys_Device::clear() -{ - read_buffer.clear(); - lines_buffer.clear(); - shrink_buffer.clear(); - out_buffer.clear(); - binarize_buffer.clear(); - local_buffer.clear(); - - calib_file.clear(); - - calibration_cache.clear(); - - white_average_data.clear(); - dark_average_data.clear(); -} - -/* ------------------------------------------------------------------------ */ -/* functions calling ASIC specific functions */ -/* ------------------------------------------------------------------------ */ - -/** - * setup the hardware dependent functions - */ -SANE_Status -sanei_genesys_init_cmd_set (Genesys_Device * dev) -{ - DBG_INIT (); - switch (dev->model->asic_type) - { - case GENESYS_GL646: - return sanei_gl646_init_cmd_set (dev); - case GENESYS_GL841: - return sanei_gl841_init_cmd_set (dev); - case GENESYS_GL843: - return sanei_gl843_init_cmd_set (dev); - case GENESYS_GL845: /* since only a few reg bits differs - we handle both together */ - case GENESYS_GL846: - return sanei_gl846_init_cmd_set (dev); - case GENESYS_GL847: - return sanei_gl847_init_cmd_set (dev); - case GENESYS_GL124: - return sanei_gl124_init_cmd_set (dev); - default: - return SANE_STATUS_INVAL; - } -} - -/* ------------------------------------------------------------------------ */ -/* General IO and debugging functions */ -/* ------------------------------------------------------------------------ */ - -SANE_Status sanei_genesys_write_file(const char *filename, uint8_t * data, size_t length) -{ - FILE *out; - - out = fopen (filename, "w"); - if (!out) { - DBG(DBG_error, "%s: could nor open %s for writing: %s\n", __func__, filename, - strerror(errno)); - return SANE_STATUS_INVAL; - } - fwrite(data, 1, length, out); - fclose(out); - - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - -/* Write data to a pnm file (e.g. calibration). For debugging only */ -/* data is RGB or grey, with little endian byte order */ -SANE_Status -sanei_genesys_write_pnm_file (const char *filename, uint8_t * data, int depth, - int channels, int pixels_per_line, int lines) -{ - FILE *out; - int count; - - DBG(DBG_info, "%s: depth=%d, channels=%d, ppl=%d, lines=%d\n", __func__,depth, channels, - pixels_per_line, lines); - - out = fopen (filename, "w"); - if (!out) - { - DBG(DBG_error, "%s: could nor open %s for writing: %s\n", __func__, filename, - strerror(errno)); - return SANE_STATUS_INVAL; - } - if(depth==1) - { - fprintf (out, "P4\n%d\n%d\n", pixels_per_line, lines); - } - else - { - fprintf (out, "P%c\n%d\n%d\n%d\n", channels == 1 ? '5' : '6', - pixels_per_line, lines, (int) pow (2, depth) - 1); - } - if (channels == 3) - { - for (count = 0; count < (pixels_per_line * lines * 3); count++) - { - if (depth == 16) - fputc (*(data + 1), out); - fputc (*(data++), out); - if (depth == 16) - data++; - } - } - else - { - if (depth==1) - { - pixels_per_line/=8; - } - for (count = 0; count < (pixels_per_line * lines); count++) - { - switch (depth) - { - case 8: - fputc (*(data + count), out); - break; - case 16: - fputc (*(data + 1), out); - fputc (*(data), out); - data += 2; - break; - default: - fputc(data[count], out); - break; - } - } - } - fclose (out); - - DBG(DBG_proc, "%s: finished\n", __func__); - return SANE_STATUS_GOOD; -} - -/* ------------------------------------------------------------------------ */ -/* Read and write RAM, registers and AFE */ -/* ------------------------------------------------------------------------ */ - -extern unsigned sanei_genesys_get_bulk_max_size(Genesys_Device * dev) -{ - /* Genesys supports 0xFE00 maximum size in general, wheraus GL646 supports - 0xFFC0. We use 0xF000 because that's the packet limit in the Linux usbmon - USB capture stack. By default it limits packet size to b_size / 5 where - b_size is the size of the ring buffer. By default it's 300*1024, so the - packet is limited 61440 without any visibility to acquiring software. - */ - if (dev->model->asic_type == GENESYS_GL124 || - dev->model->asic_type == GENESYS_GL846 || - dev->model->asic_type == GENESYS_GL847) { - return 0xeff0; - } - return 0xf000; -} - -void sanei_genesys_bulk_read_data_send_header(Genesys_Device* dev, size_t len) -{ - DBG_HELPER(dbg); - - uint8_t outdata[8]; - if (dev->model->asic_type == GENESYS_GL124 || - dev->model->asic_type == GENESYS_GL846 || - dev->model->asic_type == GENESYS_GL847) - { - // hard coded 0x10000000 address - outdata[0] = 0; - outdata[1] = 0; - outdata[2] = 0; - outdata[3] = 0x10; - } else if (dev->model->asic_type == GENESYS_GL841 || - dev->model->asic_type == GENESYS_GL843) { - outdata[0] = BULK_IN; - outdata[1] = BULK_RAM; - outdata[2] = VALUE_BUFFER & 0xff; - outdata[3] = (VALUE_BUFFER >> 8) & 0xff; - } else { - outdata[0] = BULK_IN; - outdata[1] = BULK_RAM; - outdata[2] = 0x00; - outdata[3] = 0x00; - } - - /* data size to transfer */ - outdata[4] = (len & 0xff); - outdata[5] = ((len >> 8) & 0xff); - outdata[6] = ((len >> 16) & 0xff); - outdata[7] = ((len >> 24) & 0xff); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, - sizeof(outdata), outdata); -} - -SANE_Status sanei_genesys_bulk_read_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, - size_t len) -{ - DBG_HELPER(dbg); - - // currently supported: GL646, GL841, GL843, GL846, GL847, GL124 - size_t size, target; - uint8_t *buffer; - - unsigned is_addr_used = 1; - unsigned has_header_before_each_chunk = 0; - if (dev->model->asic_type == GENESYS_GL124 || - dev->model->asic_type == GENESYS_GL846 || - dev->model->asic_type == GENESYS_GL847) - { - is_addr_used = 0; - has_header_before_each_chunk = 1; - } - - if (is_addr_used) { - DBG(DBG_io, "%s: requesting %lu bytes from 0x%02x addr\n", __func__, (u_long) len, addr); - } else { - DBG(DBG_io, "%s: requesting %lu bytes\n", __func__, (u_long) len); - } - - if (len == 0) - return SANE_STATUS_GOOD; - - if (is_addr_used) { - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, 0x00, - 1, &addr); - } - - target = len; - buffer = data; - - size_t max_in_size = sanei_genesys_get_bulk_max_size(dev); - - if (!has_header_before_each_chunk) { - sanei_genesys_bulk_read_data_send_header(dev, len); - } - - // loop until computed data size is read - while (target) { - if (target > max_in_size) { - size = max_in_size; - } else { - size = target; - } - - if (has_header_before_each_chunk) { - sanei_genesys_bulk_read_data_send_header(dev, size); - } - - DBG(DBG_io2, "%s: trying to read %lu bytes of data\n", __func__, (u_long) size); - - dev->usb_dev.bulk_read(data, &size); - - DBG(DBG_io2, "%s: read %lu bytes, %lu remaining\n", __func__, - (u_long) size, (u_long) (target - size)); - - target -= size; - data += size; - } - - if (DBG_LEVEL >= DBG_data && dev->binary!=NULL) { - fwrite(buffer, len, 1, dev->binary); - } - - return SANE_STATUS_GOOD; -} - -SANE_Status sanei_genesys_bulk_write_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, - size_t len) -{ - DBG_HELPER(dbg); - - // supported: GL646, GL841, GL843 - size_t size; - uint8_t outdata[8]; - - DBG(DBG_io, "%s writing %lu bytes\n", __func__, (u_long) len); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, - 1, &addr); - - - size_t max_out_size = sanei_genesys_get_bulk_max_size(dev); - - while (len) { - if (len > max_out_size) - size = max_out_size; - else - size = len; - - if (dev->model->asic_type == GENESYS_GL841) { - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - outdata[2] = VALUE_BUFFER & 0xff; - outdata[3] = (VALUE_BUFFER >> 8) & 0xff; - } else { - outdata[0] = BULK_OUT; - outdata[1] = BULK_RAM; - outdata[2] = 0x00; - outdata[3] = 0x00; - } - - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x00, - sizeof(outdata), outdata); - - dev->usb_dev.bulk_write(data, &size); - - DBG(DBG_io2, "%s: wrote %lu bytes, %lu remaining\n", __func__, (u_long) size, - (u_long) (len - size)); - - len -= size; - data += size; - } - - return SANE_STATUS_GOOD; -} - -/** @brief write to one high (addr >= 0x100) register - * write to a register which address is higher than 0xff. - * @param dev opened device to write to - * @param reg LSB of register address - * @param val value to write - */ -SANE_Status -sanei_genesys_write_hregister (Genesys_Device * dev, uint16_t reg, uint8_t val) -{ - DBG_HELPER(dbg); - - uint8_t buffer[2]; - - buffer[0]=reg & 0xff; - buffer[1]=val; - - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, 0x100 | VALUE_SET_REGISTER, INDEX, - 2, buffer); - - DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); - - return SANE_STATUS_GOOD; -} - -/** @brief read from one high (addr >= 0x100) register - * Read to a register which address is higher than 0xff. Second byte is check to detect - * physical link errors. - * @param dev opened device to read from - * @param reg LSB of register address - * @param val value to write - */ -SANE_Status -sanei_genesys_read_hregister (Genesys_Device * dev, uint16_t reg, uint8_t * val) -{ - DBG_HELPER(dbg); - - SANE_Byte value[2]; - - dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, 0x100 | VALUE_GET_REGISTER, - 0x22+((reg & 0xff)<<8), 2, value); - - *val=value[0]; - DBG(DBG_io2, "%s(0x%02x)=0x%02x\n", __func__, reg, *val); - - /* check usb link status */ - if((value[1] & 0xff) != 0x55) - { - DBG(DBG_error,"%s: invalid read, scanner unplugged ?\n", __func__); - return SANE_STATUS_IO_ERROR; - } - return SANE_STATUS_GOOD; -} - -/** - * Write to one GL847 ASIC register -URB 10 control 0x40 0x04 0x83 0x00 len 2 wrote 0xa6 0x04 - */ -static SANE_Status -sanei_genesys_write_gl847_register (Genesys_Device * dev, uint8_t reg, uint8_t val) -{ - DBG_HELPER(dbg); - - uint8_t buffer[2]; - - buffer[0]=reg; - buffer[1]=val; - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER, INDEX, - 2, buffer); - - DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); - - return SANE_STATUS_GOOD; -} - -/** - * Write to one ASIC register - */ -SANE_Status -sanei_genesys_write_register (Genesys_Device * dev, uint16_t reg, uint8_t val) -{ - DBG_HELPER(dbg); - - SANE_Byte reg8; - - /* 16 bit register address space */ - if(reg>255) - { - return sanei_genesys_write_hregister(dev, reg, val); - } - - /* route to gl847 function if needed */ - if(dev->model->asic_type==GENESYS_GL847 - || dev->model->asic_type==GENESYS_GL845 - || dev->model->asic_type==GENESYS_GL846 - || dev->model->asic_type==GENESYS_GL124) - { - return sanei_genesys_write_gl847_register(dev, reg, val); - } - - reg8=reg & 0xff; - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, - 1, ®8); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_WRITE_REGISTER, INDEX, - 1, &val); - - DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, val); - - return SANE_STATUS_GOOD; -} - -/** - * @brief write command to 0x8c endpoint - * Write a value to 0x8c end point (end access), for USB firmware related operations - * Known values are 0x0f, 0x11 for USB 2.0 data transfer and 0x0f,0x14 for USB1.1 - * @param dev device to write to - * @param index index of the command - * @param val value to write - */ -SANE_Status -sanei_genesys_write_0x8c(Genesys_Device * dev, uint8_t index, uint8_t val) -{ - DBG_HELPER_ARGS(dbg, "0x%02x,0x%02x", index, val); - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_BUF_ENDACCESS, index, - 1, &val); - return SANE_STATUS_GOOD; -} - -/* read reg 0x41: - * URB 164 control 0xc0 0x04 0x8e 0x4122 len 2 read 0xfc 0x55 - */ -static SANE_Status -sanei_genesys_read_gl847_register (Genesys_Device * dev, uint16_t reg, uint8_t * val) -{ - DBG_HELPER(dbg); - SANE_Status status = SANE_STATUS_GOOD; - SANE_Byte value[2]; - - dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_BUFFER, VALUE_GET_REGISTER, 0x22+(reg<<8), - 2, value); - - *val=value[0]; - DBG(DBG_io2, "%s(0x%02x)=0x%02x\n", __func__, reg, *val); - - /* check usb link status */ - if((value[1] & 0xff) != 0x55) - { - DBG(DBG_error,"%s: invalid read, scanner unplugged ?\n", __func__); - status=SANE_STATUS_IO_ERROR; - } - return status; -} - -/* Read from one register */ -SANE_Status -sanei_genesys_read_register (Genesys_Device * dev, uint16_t reg, uint8_t * val) -{ - DBG_HELPER(dbg); - - SANE_Byte reg8; - - /* 16 bit register address space */ - if(reg>255) - { - return sanei_genesys_read_hregister(dev, reg, val); - } - - /* route to gl847 function if needed */ - if(dev->model->asic_type==GENESYS_GL847 - || dev->model->asic_type==GENESYS_GL845 - || dev->model->asic_type==GENESYS_GL846 - || dev->model->asic_type==GENESYS_GL124) - return sanei_genesys_read_gl847_register(dev, reg, val); - - /* 8 bit register address space */ - reg8=(SANE_Byte)(reg& 0Xff); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_REGISTER, VALUE_SET_REGISTER, INDEX, - 1, ®8); - - *val = 0; - - dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_READ_REGISTER, INDEX, - 1, val); - - DBG(DBG_io, "%s (0x%02x, 0x%02x) completed\n", __func__, reg, *val); - - return SANE_STATUS_GOOD; -} - -/* Set address for writing data */ -SANE_Status -sanei_genesys_set_buffer_address (Genesys_Device * dev, uint32_t addr) -{ - SANE_Status status = SANE_STATUS_GOOD; - - if(dev->model->asic_type==GENESYS_GL847 - || dev->model->asic_type==GENESYS_GL845 - || dev->model->asic_type==GENESYS_GL846 - || dev->model->asic_type==GENESYS_GL124) - { - DBG(DBG_warn, "%s: shouldn't be used for GL846+ ASICs\n", __func__); - return SANE_STATUS_GOOD; - } - - DBG(DBG_io, "%s: setting address to 0x%05x\n", __func__, addr & 0xfffffff0); - - addr = addr >> 4; - - status = sanei_genesys_write_register (dev, 0x2b, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while writing low byte: %s\n", __func__, sane_strstatus(status)); - return status; - } - - addr = addr >> 8; - status = sanei_genesys_write_register (dev, 0x2a, (addr & 0xff)); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while writing high byte: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_io, "%s: completed\n", __func__); - - return status; -} - -/**@brief read data from analog frontend (AFE) - * @param dev device owning the AFE - * @param addr register address to read - * @param data placeholder for the result - * @return SANE_STATUS_GOOD is OK, else the error code - */ -SANE_Status -sanei_genesys_fe_read_data (Genesys_Device * dev, uint8_t addr, - uint16_t *data) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t value; - Genesys_Register_Set reg; - - - DBG(DBG_proc, "%s: start\n", __func__); - - reg.init_reg(0x50, addr); - - /* set up read address */ - status = dev->model->cmd_set->bulk_write_register(dev, reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while bulk writing registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - /* read data */ - RIE (sanei_genesys_read_register (dev, 0x46, &value)); - *data=256*value; - RIE (sanei_genesys_read_register (dev, 0x47, &value)); - *data+=value; - - DBG(DBG_io, "%s (0x%02x, 0x%04x)\n", __func__, addr, *data); - DBG(DBG_proc, "%s: completed\n", __func__); - - return status; -} - -/*@brief write data to analog frontend - * writes data to analog frontend to set it up accordingly - * to the sensor settings (exposure, timings, color, bit depth, ...) - * @param dev devie owning the AFE to write to - * @param addr AFE rister address - * @param data value to write to AFE register - **/ -SANE_Status -sanei_genesys_fe_write_data (Genesys_Device * dev, uint8_t addr, - uint16_t data) -{ - SANE_Status status = SANE_STATUS_GOOD; - Genesys_Register_Set reg(Genesys_Register_Set::SEQUENTIAL); - - DBG(DBG_io, "%s (0x%02x, 0x%04x)\n", __func__, addr, data); - - reg.init_reg(0x51, addr); - if (dev->model->asic_type == GENESYS_GL124) { - reg.init_reg(0x5d, (data / 256) & 0xff); - reg.init_reg(0x5e, data & 0xff); - } else { - reg.init_reg(0x3a, (data / 256) & 0xff); - reg.init_reg(0x3b, data & 0xff); - } - - status = dev->model->cmd_set->bulk_write_register(dev, reg); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed while bulk writing registers: %s\n", __func__, - sane_strstatus(status)); - return status; - } - - DBG(DBG_io, "%s: completed\n", __func__); - - return status; -} - -/* ------------------------------------------------------------------------ */ -/* Medium level functions */ -/* ------------------------------------------------------------------------ */ - -/** read the status register - */ -SANE_Status -sanei_genesys_get_status (Genesys_Device * dev, uint8_t * status) -{ - if(dev->model->asic_type==GENESYS_GL124) - return sanei_genesys_read_hregister(dev, 0x101, status); - return sanei_genesys_read_register (dev, 0x41, status); -} - -/** - * decodes and prints content of status register - * @param val value read from status register - */ -void sanei_genesys_print_status (uint8_t val) -{ - char msg[80]; - - sprintf (msg, "%s%s%s%s%s%s%s%s", - val & PWRBIT ? "PWRBIT " : "", - val & BUFEMPTY ? "BUFEMPTY " : "", - val & FEEDFSH ? "FEEDFSH " : "", - val & SCANFSH ? "SCANFSH " : "", - val & HOMESNR ? "HOMESNR " : "", - val & LAMPSTS ? "LAMPSTS " : "", - val & FEBUSY ? "FEBUSY " : "", - val & MOTORENB ? "MOTORENB" : ""); - DBG(DBG_info, "status=%s\n", msg); -} - -#if 0 -/* returns pixels per line from register set */ -/*candidate for moving into chip specific files?*/ -static int -genesys_pixels_per_line (Genesys_Register_Set * reg) -{ - int pixels_per_line; - - pixels_per_line = - sanei_genesys_read_reg_from_set (reg, - 0x32) * 256 + - sanei_genesys_read_reg_from_set (reg, 0x33); - pixels_per_line -= - (sanei_genesys_read_reg_from_set (reg, 0x30) * 256 + - sanei_genesys_read_reg_from_set (reg, 0x31)); - - return pixels_per_line; -} - -/* returns dpiset from register set */ -/*candidate for moving into chip specific files?*/ -static int -genesys_dpiset (Genesys_Register_Set * reg) -{ - int dpiset; - - dpiset = - sanei_genesys_read_reg_from_set (reg, - 0x2c) * 256 + - sanei_genesys_read_reg_from_set (reg, 0x2d); - - return dpiset; -} -#endif - -/** read the number of valid words in scanner's RAM - * ie registers 42-43-44 - */ -/*candidate for moving into chip specific files?*/ -SANE_Status -sanei_genesys_read_valid_words (Genesys_Device * dev, unsigned int *words) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t value; - - DBGSTART; - switch (dev->model->asic_type) - { - case GENESYS_GL124: - RIE (sanei_genesys_read_hregister (dev, 0x102, &value)); - *words = (value & 0x03); - RIE (sanei_genesys_read_hregister (dev, 0x103, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_hregister (dev, 0x104, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_hregister (dev, 0x105, &value)); - *words = *words * 256 + value; - break; - - case GENESYS_GL845: - case GENESYS_GL846: - RIE (sanei_genesys_read_register (dev, 0x42, &value)); - *words = (value & 0x02); - RIE (sanei_genesys_read_register (dev, 0x43, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_register (dev, 0x44, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_register (dev, 0x45, &value)); - *words = *words * 256 + value; - break; - - case GENESYS_GL847: - RIE (sanei_genesys_read_register (dev, 0x42, &value)); - *words = (value & 0x03); - RIE (sanei_genesys_read_register (dev, 0x43, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_register (dev, 0x44, &value)); - *words = *words * 256 + value; - RIE (sanei_genesys_read_register (dev, 0x45, &value)); - *words = *words * 256 + value; - break; - - default: - RIE (sanei_genesys_read_register (dev, 0x44, &value)); - *words = value; - RIE (sanei_genesys_read_register (dev, 0x43, &value)); - *words += (value * 256); - RIE (sanei_genesys_read_register (dev, 0x42, &value)); - if (dev->model->asic_type == GENESYS_GL646) - *words += ((value & 0x03) * 256 * 256); - else - *words += ((value & 0x0f) * 256 * 256); - } - - DBG(DBG_proc, "%s: %d words\n", __func__, *words); - DBGCOMPLETED; - return SANE_STATUS_GOOD; -} - -/** read the number of lines scanned - * ie registers 4b-4c-4d - */ -SANE_Status -sanei_genesys_read_scancnt (Genesys_Device * dev, unsigned int *words) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t value; - - DBG(DBG_proc, "%s: start\n", __func__); - - if (dev->model->asic_type == GENESYS_GL124) - { - RIE (sanei_genesys_read_hregister (dev, 0x10b, &value)); - *words = (value & 0x0f) << 16; - RIE (sanei_genesys_read_hregister (dev, 0x10c, &value)); - *words += (value << 8); - RIE (sanei_genesys_read_hregister (dev, 0x10d, &value)); - *words += value; - } - else - { - RIE (sanei_genesys_read_register (dev, 0x4d, &value)); - *words = value; - RIE (sanei_genesys_read_register (dev, 0x4c, &value)); - *words += (value * 256); - RIE (sanei_genesys_read_register (dev, 0x4b, &value)); - if (dev->model->asic_type == GENESYS_GL646) - *words += ((value & 0x03) * 256 * 256); - else - *words += ((value & 0x0f) * 256 * 256); - } - - DBG(DBG_proc, "%s: %d lines\n", __func__, *words); - return SANE_STATUS_GOOD; -} - -/** @brief Check if the scanner's internal data buffer is empty - * @param *dev device to test for data - * @param *empty return value - * @return empty will be set to SANE_TRUE if there is no scanned data. - **/ -SANE_Status -sanei_genesys_test_buffer_empty (Genesys_Device * dev, SANE_Bool * empty) -{ - uint8_t val = 0; - SANE_Status status = SANE_STATUS_GOOD; - - sanei_genesys_sleep_ms(1); - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: failed to read buffer status: %s\n", __func__, sane_strstatus(status)); - return status; - } - - if (dev->model->cmd_set->test_buffer_empty_bit (val)) - { - /* fix timing issue on USB3 (or just may be too fast) hardware - * spotted by John S. Weber - */ - sanei_genesys_sleep_ms(1); - DBG(DBG_io2, "%s: buffer is empty\n", __func__); - *empty = SANE_TRUE; - return SANE_STATUS_GOOD; - } - - *empty = SANE_FALSE; - - DBG(DBG_io, "%s: buffer is filled\n", __func__); - return SANE_STATUS_GOOD; -} - - -/* Read data (e.g scanned image) from scan buffer */ -SANE_Status -sanei_genesys_read_data_from_scanner (Genesys_Device * dev, uint8_t * data, - size_t size) -{ - SANE_Status status = SANE_STATUS_GOOD; - int time_count = 0; - unsigned int words = 0; - - DBG(DBG_proc, "%s (size = %lu bytes)\n", __func__, (u_long) size); - - if (size & 1) - DBG(DBG_info, "WARNING %s: odd number of bytes\n", __func__); - - /* wait until buffer not empty for up to 5 seconds */ - do - { - status = sanei_genesys_read_valid_words (dev, &words); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: checking for empty buffer failed: %s\n", __func__, - sane_strstatus(status)); - return status; - } - if (words == 0) - { - sanei_genesys_sleep_ms(10); - time_count++; - } - } - while ((time_count < 2500*2) && (words == 0)); - - if (words == 0) /* timeout, buffer does not get filled */ - { - DBG(DBG_error, "%s: timeout, buffer does not get filled\n", __func__); - return SANE_STATUS_IO_ERROR; - } - - status = dev->model->cmd_set->bulk_read_data (dev, 0x45, data, size); - if (status != SANE_STATUS_GOOD) - { - DBG(DBG_error, "%s: reading bulk data failed: %s\n", __func__, sane_strstatus(status)); - return status; - } - - DBG(DBG_proc, "%s: completed\n", __func__); - return SANE_STATUS_GOOD; -} -SANE_Status -sanei_genesys_read_feed_steps (Genesys_Device * dev, unsigned int *steps) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t value; - - DBG(DBG_proc, "%s\n", __func__); - - if (dev->model->asic_type == GENESYS_GL124) - { - RIE (sanei_genesys_read_hregister (dev, 0x108, &value)); - *steps = (value & 0x1f) << 16; - RIE (sanei_genesys_read_hregister (dev, 0x109, &value)); - *steps += (value << 8); - RIE (sanei_genesys_read_hregister (dev, 0x10a, &value)); - *steps += value; - } - else - { - RIE (sanei_genesys_read_register (dev, 0x4a, &value)); - *steps = value; - RIE (sanei_genesys_read_register (dev, 0x49, &value)); - *steps += (value * 256); - RIE (sanei_genesys_read_register (dev, 0x48, &value)); - if (dev->model->asic_type == GENESYS_GL646) - *steps += ((value & 0x03) * 256 * 256); - else if (dev->model->asic_type == GENESYS_GL841) - *steps += ((value & 0x0f) * 256 * 256); - else - *steps += ((value & 0x1f) * 256 * 256); - } - - DBG(DBG_proc, "%s: %d steps\n", __func__, *steps); - return SANE_STATUS_GOOD; -} - -void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, bool set) -{ - static const uint8_t REG03_LAMPPWR = 0x10; - - if (set) { - regs.find_reg(0x03).value |= REG03_LAMPPWR; - - if (dev->model->asic_type == GENESYS_GL841) { - sanei_genesys_set_exposure(regs, sanei_genesys_fixup_exposure(sensor.exposure)); - regs.set8(0x19, 0x50); - } - - if (dev->model->asic_type == GENESYS_GL843) { - sanei_genesys_set_exposure(regs, sensor.exposure); - } - } else { - regs.find_reg(0x03).value &= ~REG03_LAMPPWR; - - if (dev->model->asic_type == GENESYS_GL841) { - sanei_genesys_set_exposure(regs, {0x0101, 0x0101, 0x0101}); - regs.set8(0x19, 0xff); - } - - if (dev->model->asic_type == GENESYS_GL843) { - if (dev->model->model_id != MODEL_CANON_CANOSCAN_8600F) { - // BUG: datasheet says we shouldn't set exposure to zero - sanei_genesys_set_exposure(regs, {0, 0, 0}); - } - } - } - regs.state.is_lamp_on = set; -} - -void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set) -{ - static const uint8_t REG02_MTRPWR = 0x10; - - if (set) { - regs.find_reg(0x02).value |= REG02_MTRPWR; - } else { - regs.find_reg(0x02).value &= ~REG02_MTRPWR; - } -} - -/** - * Write to many registers at once - * Note: sequential call to write register, no effective - * bulk write implemented. - * @param dev device to write to - * @param reg pointer to an array of registers - * @param elems size of the array - */ -SANE_Status sanei_genesys_bulk_write_register(Genesys_Device * dev, Genesys_Register_Set& reg) -{ - DBG_HELPER(dbg); - - SANE_Status status = SANE_STATUS_GOOD; - - if (dev->model->asic_type == GENESYS_GL646 || - dev->model->asic_type == GENESYS_GL841) - { - uint8_t outdata[8]; - std::vector buffer; - buffer.reserve(reg.size() * 2); - - /* copy registers and values in data buffer */ - for (const auto& r : reg) { - buffer.push_back(r.address); - buffer.push_back(r.value); - } - - DBG(DBG_io, "%s (elems= %lu, size = %lu)\n", __func__, (u_long) reg.size(), - (u_long) buffer.size()); - - if (dev->model->asic_type == GENESYS_GL646) { - outdata[0] = BULK_OUT; - outdata[1] = BULK_REGISTER; - outdata[2] = 0x00; - outdata[3] = 0x00; - outdata[4] = (buffer.size() & 0xff); - outdata[5] = ((buffer.size() >> 8) & 0xff); - outdata[6] = ((buffer.size() >> 16) & 0xff); - outdata[7] = ((buffer.size() >> 24) & 0xff); - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, INDEX, - sizeof(outdata), outdata); - - size_t write_size = buffer.size(); - - dev->usb_dev.bulk_write(buffer.data(), &write_size); - } else { - for (size_t i = 0; i < reg.size();) { - size_t c = reg.size() - i; - if (c > 32) /*32 is max on GL841. checked that.*/ - c = 32; - - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_SET_REGISTER, - INDEX, c * 2, buffer.data() + i * 2); - - i += c; - } - } - } else { - for (const auto& r : reg) { - status = sanei_genesys_write_register (dev, r.address, r.value); - if (status != SANE_STATUS_GOOD) - return status; - } - } - - DBG (DBG_io, "%s: wrote %lu registers\n", __func__, (u_long) reg.size()); - return status; -} - - - -/** - * writes a block of data to AHB - * @param dn USB device index - * @param usb_mode usb mode : 1 usb 1.1, 2 usb 2.0 - * @param addr AHB address to write to - * @param size size of the chunk of data - * @param data pointer to the data to write - */ -SANE_Status -sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t size, uint8_t * data) -{ - DBG_HELPER(dbg); - - uint8_t outdata[8]; - size_t written,blksize; - SANE_Status status = SANE_STATUS_GOOD; - int i; - char msg[100]="AHB="; - - outdata[0] = addr & 0xff; - outdata[1] = ((addr >> 8) & 0xff); - outdata[2] = ((addr >> 16) & 0xff); - outdata[3] = ((addr >> 24) & 0xff); - outdata[4] = (size & 0xff); - outdata[5] = ((size >> 8) & 0xff); - outdata[6] = ((size >> 16) & 0xff); - outdata[7] = ((size >> 24) & 0xff); - - if (DBG_LEVEL >= DBG_io) - { - for (i = 0; i < 8; i++) - { - sprintf (msg+strlen(msg), " 0x%02x", outdata[i]); - } - DBG (DBG_io, "%s: write(0x%08x,0x%08x)\n", __func__, addr,size); - DBG (DBG_io, "%s: %s\n", __func__, msg); - } - - // write addr and size for AHB - dev->usb_dev.control_msg(REQUEST_TYPE_OUT, REQUEST_BUFFER, VALUE_BUFFER, 0x01, 8, outdata); - - size_t max_out_size = sanei_genesys_get_bulk_max_size(dev); - - /* write actual data */ - written = 0; - do - { - if (size - written > max_out_size) - { - blksize = max_out_size; - } - else - { - blksize = size - written; - } - dev->usb_dev.bulk_write(data + written, &blksize); - - written += blksize; - } - while (written < size); - - return status; -} - - -std::vector get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, - int color) -{ - if (!dev->gamma_override_tables[color].empty()) { - return dev->gamma_override_tables[color]; - } else { - std::vector ret; - sanei_genesys_create_default_gamma_table(dev, ret, sensor.gamma[color]); - return ret; - } -} - -/** @brief generates gamma buffer to transfer - * Generates gamma table buffer to send to ASIC. Applies - * contrast and brightness if set. - * @param dev device to set up - * @param bits number of bits used by gamma - * @param max value for gamma - * @param size of the gamma table - * @param gamma allocated gamma buffer to fill - * @returns SANE_STATUS_GOOD or SANE_STATUS_NO_MEM - */ -SANE_Status sanei_genesys_generate_gamma_buffer(Genesys_Device * dev, - const Genesys_Sensor& sensor, - int bits, - int max, - int size, - uint8_t *gamma) -{ - std::vector rgamma = get_gamma_table(dev, sensor, GENESYS_RED); - std::vector ggamma = get_gamma_table(dev, sensor, GENESYS_GREEN); - std::vector bgamma = get_gamma_table(dev, sensor, GENESYS_BLUE); - - if(dev->settings.contrast!=0 || dev->settings.brightness!=0) - { - std::vector lut(65536); - sanei_genesys_load_lut((unsigned char *)lut.data(), - bits, - bits, - 0, - max, - dev->settings.contrast, - dev->settings.brightness); - for (int i = 0; i < size; i++) - { - uint16_t value=rgamma[i]; - value=lut[value]; - gamma[i * 2 + size * 0 + 0] = value & 0xff; - gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff; - - value=ggamma[i]; - value=lut[value]; - gamma[i * 2 + size * 2 + 0] = value & 0xff; - gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff; - - value=bgamma[i]; - value=lut[value]; - gamma[i * 2 + size * 4 + 0] = value & 0xff; - gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff; - } - } - else - { - for (int i = 0; i < size; i++) - { - uint16_t value=rgamma[i]; - gamma[i * 2 + size * 0 + 0] = value & 0xff; - gamma[i * 2 + size * 0 + 1] = (value >> 8) & 0xff; - - value=ggamma[i]; - gamma[i * 2 + size * 2 + 0] = value & 0xff; - gamma[i * 2 + size * 2 + 1] = (value >> 8) & 0xff; - - value=bgamma[i]; - gamma[i * 2 + size * 4 + 0] = value & 0xff; - gamma[i * 2 + size * 4 + 1] = (value >> 8) & 0xff; - } - } - - return SANE_STATUS_GOOD; -} - - -/** @brief send gamma table to scanner - * This function sends generic gamma table (ie ones built with - * provided gamma) or the user defined one if provided by - * fontend. Used by gl846+ ASICs - * @param dev device to write to - */ -SANE_Status -sanei_genesys_send_gamma_table(Genesys_Device * dev, const Genesys_Sensor& sensor) -{ - int size; - int i; - uint8_t val; - SANE_Status status = SANE_STATUS_GOOD; - - DBGSTART; - - size = 256 + 1; - - /* allocate temporary gamma tables: 16 bits words, 3 channels */ - std::vector gamma(size * 2 * 3, 255); - - RIE(sanei_genesys_generate_gamma_buffer(dev, sensor, 16, 65535, size, gamma.data())); - - /* loop sending gamma tables NOTE: 0x01000000 not 0x10000000 */ - for (i = 0; i < 3; i++) - { - /* clear corresponding GMM_N bit */ - RIE(sanei_genesys_read_register(dev, 0xbd, &val)); - val &= ~(0x01 << i); - RIE(sanei_genesys_write_register(dev, 0xbd, val)); - - /* clear corresponding GMM_F bit */ - RIE(sanei_genesys_read_register(dev, 0xbe, &val)); - val &= ~(0x01 << i); - RIE(sanei_genesys_write_register(dev, 0xbe, val)); - - // FIXME: currently the last word of each gamma table is not initialied, so to work around - // unstable data, just set it to 0 which is the most likely value of uninitialized memory - // (proper value is probably 0xff) - gamma[size * 2 * i + size * 2 - 2] = 0; - gamma[size * 2 * i + size * 2 - 1] = 0; - - /* set GMM_Z */ - RIE(sanei_genesys_write_register (dev, 0xc5+2*i, gamma[size*2*i+1])); - RIE(sanei_genesys_write_register (dev, 0xc6+2*i, gamma[size*2*i])); - - status = sanei_genesys_write_ahb(dev, 0x01000000 + 0x200 * i, (size-1) * 2, gamma.data() + i * size * 2+2); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: write to AHB failed writing table %d (%s)\n", __func__, - i, sane_strstatus (status)); - break; - } - } - - DBGCOMPLETED; - return status; -} - -/** @brief initialize device - * Initialize backend and ASIC : registers, motor tables, and gamma tables - * then ensure scanner's head is at home. Designed for gl846+ ASICs. - * Detects cold boot (ie first boot since device plugged) in this case - * an extensice setup up is done at hardware level. - * - * @param dev device to initialize - * @param max_regs umber of maximum used registers - * @return SANE_STATUS_GOOD in case of success - */ -SANE_Status -sanei_genesys_asic_init(Genesys_Device* dev, int /*max_regs*/) -{ - DBG_HELPER(dbg); - - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - SANE_Bool cold = SANE_TRUE; - - DBGSTART; - - // URB 16 control 0xc0 0x0c 0x8e 0x0b len 1 read 0x00 */ - dev->usb_dev.control_msg(REQUEST_TYPE_IN, REQUEST_REGISTER, VALUE_GET_REGISTER, 0x00, 1, &val); - - DBG (DBG_io2, "%s: value=0x%02x\n", __func__, val); - DBG (DBG_info, "%s: device is %s\n", __func__, (val & 0x08) ? "USB 1.0" : "USB2.0"); - if (val & 0x08) - { - dev->usb_mode = 1; - } - else - { - dev->usb_mode = 2; - } - - /* check if the device has already been initialized and powered up - * we read register 6 and check PWRBIT, if reset scanner has been - * freshly powered up. This bit will be set to later so that following - * reads can detect power down/up cycle*/ - RIE (sanei_genesys_read_register (dev, 0x06, &val)); - /* test for POWER bit */ - if (val & 0x10) - { - cold = SANE_FALSE; - } - DBG (DBG_info, "%s: device is %s\n", __func__, cold ? "cold" : "warm"); - - /* don't do anything if backend is initialized and hardware hasn't been - * replug */ - if (dev->already_initialized && !cold) - { - DBG (DBG_info, "%s: already initialized, nothing to do\n", __func__); - return SANE_STATUS_GOOD; - } - - /* set up hardware and registers */ - RIE (dev->model->cmd_set->asic_boot (dev, cold)); - - /* now hardware part is OK, set up device struct */ - dev->white_average_data.clear(); - dev->dark_average_data.clear(); - - dev->settings.color_filter = ColorFilter::RED; - - /* duplicate initial values into calibration registers */ - dev->calib_reg = dev->reg; - - const auto& sensor = sanei_genesys_find_sensor_any(dev); - - /* Set analog frontend */ - RIE (dev->model->cmd_set->set_fe(dev, sensor, AFE_INIT)); - - dev->already_initialized = SANE_TRUE; - - /* Move to home if needed */ - RIE (dev->model->cmd_set->slow_back_home (dev, SANE_TRUE)); - dev->scanhead_position_in_steps = 0; - - /* Set powersaving (default = 15 minutes) */ - RIE (dev->model->cmd_set->set_powersaving (dev, 15)); - - return status; -} - -/** - * Wait for the scanning head to park - */ -SANE_Status -sanei_genesys_wait_for_home (Genesys_Device * dev) -{ - SANE_Status status = SANE_STATUS_GOOD; - uint8_t val; - int loop; - int max=300; - - DBGSTART; - - /* clear the parking status whatever the outcome of the function */ - dev->parking=SANE_FALSE; - - /* read initial status, if head isn't at home and motor is on - * we are parking, so we wait. - * gl847/gl124 need 2 reads for reliable results */ - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - return status; - } - sanei_genesys_sleep_ms(10); - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - return status; - } - - /* if at home, return */ - if(val & HOMESNR) - { - DBG (DBG_info, - "%s: already at home\n", __func__); - return status; - } - - /* loop for 30 s max, polling home sensor */ - loop = 0; - do - { - sanei_genesys_sleep_ms(100); - status = sanei_genesys_get_status (dev, &val); - if (status != SANE_STATUS_GOOD) - { - DBG (DBG_error, - "%s: failed to read home sensor: %s\n", __func__, - sane_strstatus (status)); - return status; - } - if (DBG_LEVEL >= DBG_io2) - { - sanei_genesys_print_status (val); - } - ++loop; - } - while (loop < max && !(val & HOMESNR) && status == SANE_STATUS_GOOD); - - /* if after the timeout, head is still not parked, error out */ - if(loop >= max && !(val & HOMESNR) && status == SANE_STATUS_GOOD) - { - DBG (DBG_error, "%s: failed to reach park position %ds\n", __func__, max/10); - return SANE_STATUS_IO_ERROR; - } - - DBGCOMPLETED; - return status; -} - -/**@brief compute hardware sensor dpi to use - * compute the sensor hardware dpi based on target resolution. - * A lower dpihw enable faster scans. - * @param dev device used for the scan - * @param xres x resolution of the scan - * @return the hardware dpi to use - */ -int sanei_genesys_compute_dpihw(Genesys_Device *dev, const Genesys_Sensor& sensor, int xres) -{ - /* some scanners use always hardware dpi for sensor */ - if (dev->model->flags & GENESYS_FLAG_FULL_HWDPI_MODE) - { - return sensor.optical_res; - } - - /* can't be below 600 dpi */ - if (xres <= 600) - { - return 600; - } - if (xres <= sensor.optical_res / 4) - { - return sensor.optical_res / 4; - } - if (xres <= sensor.optical_res / 2) - { - return sensor.optical_res / 2; - } - return sensor.optical_res; -} - -// sanei_genesys_compute_dpihw returns the dpihw that is written to register. -// However the number of pixels depends on half_ccd mode -int sanei_genesys_compute_dpihw_calibration(Genesys_Device *dev, const Genesys_Sensor& sensor, - int xres) -{ - if (dev->model->model_id == MODEL_CANON_CANOSCAN_8600F) - { - // real resolution is half of the "official" resolution - half_ccd mode - int hwres = sensor.optical_res / sensor.get_ccd_size_divisor_for_dpi(xres); - - if (xres <= hwres / 4) - { - return hwres / 4; - } - if (xres <= hwres / 2) - { - return hwres / 2; - } - return hwres; - } - - return sanei_genesys_compute_dpihw(dev, sensor, xres); -} - -/** @brief motor profile - * search for the database of motor profiles and get the best one. Each - * profile is at full step and at a reference exposure. Use first entry - * by default. - * @param motors motor profile database - * @param motor_type motor id - * @param exposure exposure time - * @return a pointer to a Motor_Profile struct - */ -Motor_Profile *sanei_genesys_get_motor_profile(Motor_Profile *motors, int motor_type, int exposure) -{ - unsigned int i; - int idx; - - i=0; - idx=-1; - while(motors[i].exposure!=0) - { - /* exact match */ - if(motors[i].motor_type==motor_type && motors[i].exposure==exposure) - { - return &(motors[i]); - } - - /* closest match */ - if(motors[i].motor_type==motor_type) - { - /* if profile exposure is higher than the required one, - * the entry is a candidate for the closest match */ - if(motors[i].exposure>=exposure) - { - if(idx<0) - { - /* no match found yet */ - idx=i; - } - else - { - /* test for better match */ - if(motors[i].exposurestep_type; -} - -/** @brief generate slope table - * Generate the slope table to use for the scan using a reference slope - * table. - * @param slope pointer to the slope table to fill - * @param steps pointer to return used step number - * @param dpi desired motor resolution - * @param exposure exposure used - * @param base_dpi base resolution of the motor - * @param step_type step type used for scan - * @param factor shrink factor for the slope - * @param motor_type motor id - * @param motors motor profile database - */ -int sanei_genesys_slope_table(uint16_t *slope, - int *steps, - int dpi, - int exposure, - int base_dpi, - int step_type, - int factor, - int motor_type, - Motor_Profile *motors) -{ -int sum, i; -uint16_t target,current; -Motor_Profile *profile; - - /* required speed */ - target=((exposure * dpi) / base_dpi)>>step_type; - DBG (DBG_io2, "%s: exposure=%d, dpi=%d, target=%d\n", __func__, exposure, dpi, target); - - /* fill result with target speed */ - for(i=0;itable[0]; - - /* loop on profile copying and apply step type */ - while(profile->table[i]!=0 && current>=target) - { - slope[i]=current; - sum+=slope[i]; - i++; - current=profile->table[i]>>step_type; - } - - /* ensure last step is required speed in case profile doesn't contain it */ - if(current!=0 && currenttable[i]==0 && DBG_LEVEL >= DBG_warn && current>target) - { - DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too low ?\n",__func__,target); - } - if(i<3 && DBG_LEVEL >= DBG_warn) - { - DBG (DBG_warn,"%s: short slope table, failed to reach %d. target too high ?\n",__func__,target); - } - - /* align on factor */ - while(i%factor!=0) - { - slope[i+1]=slope[i]; - sum+=slope[i]; - i++; - } - - /* ensure minimal slope size */ - while(i<2*factor) - { - slope[i+1]=slope[i]; - sum+=slope[i]; - i++; - } - - // return used steps and taken time - *steps=i/factor; - return sum; -} - -/** @brief returns the lowest possible ydpi for the device - * Parses device entry to find lowest motor dpi. - * @param dev device description - * @return lowest motor resolution - */ -int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev) -{ - int min=20000; - int i=0; - - while(dev->model->ydpi_values[i]!=0) - { - if(dev->model->ydpi_values[i]model->ydpi_values[i]; - } - i++; - } - return min; -} - -/** @brief returns the lowest possible dpi for the device - * Parses device entry to find lowest motor or sensor dpi. - * @param dev device description - * @return lowest motor resolution - */ -int sanei_genesys_get_lowest_dpi(Genesys_Device *dev) -{ - int min=20000; - int i=0; - - while(dev->model->ydpi_values[i]!=0) - { - if(dev->model->ydpi_values[i]model->ydpi_values[i]; - } - i++; - } - i=0; - while(dev->model->xdpi_values[i]!=0) - { - if(dev->model->xdpi_values[i]model->xdpi_values[i]; - } - i++; - } - return min; -} - -/** @brief check is a cache entry may be used - * Compares current settings with the cache entry and return - * SANE_TRUE if they are compatible. - * A calibration cache is compatible if color mode and x dpi match the user - * requested scan. In the case of CIS scanners, dpi isn't a criteria. - * flatbed cache entries are considred too old and then expires if they - * are older than the expiration time option, forcing calibration at least once - * then given time. */ -bool sanei_genesys_is_compatible_calibration(Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Calibration_Cache * cache, int for_overwrite) -{ -#ifdef HAVE_SYS_TIME_H - struct timeval time; -#endif - int compatible = 1, resolution; - - DBGSTART; - - if(dev->model->cmd_set->calculate_current_setup==NULL) - { - DBG (DBG_proc, "%s: no calculate_setup, non compatible cache\n", __func__); - return false; - } - - dev->model->cmd_set->calculate_current_setup(dev, sensor); - - DBG (DBG_proc, "%s: checking\n", __func__); - - /* a calibration cache is compatible if color mode and x dpi match the user - * requested scan. In the case of CIS scanners, dpi isn't a criteria */ - if (dev->model->is_cis == SANE_FALSE) - { - resolution = dev->settings.xres; - if(resolution>sensor.optical_res) - { - resolution=sensor.optical_res; - } - compatible = (resolution == ((int) cache->used_setup.xres)); - } - else - { - resolution=sanei_genesys_compute_dpihw(dev, sensor, dev->settings.xres); - compatible = (resolution == ((int) sanei_genesys_compute_dpihw(dev, sensor,cache->used_setup.xres))); - } - DBG (DBG_io, "%s: after resolution check current compatible=%d\n", __func__, compatible); - if (dev->current_setup.ccd_size_divisor != cache->used_setup.ccd_size_divisor) - { - DBG (DBG_io, "%s: half_ccd=%d, used=%d\n", __func__, - dev->current_setup.ccd_size_divisor, cache->used_setup.ccd_size_divisor); - compatible = 0; - } - if (dev->current_setup.params.scan_method != cache->used_setup.params.scan_method) - { - DBG (DBG_io, "%s: current method=%d, used=%d\n", __func__, - static_cast(dev->current_setup.params.scan_method), - static_cast(cache->used_setup.params.scan_method)); - compatible = 0; - } - if (!compatible) - { - DBG (DBG_proc, "%s: completed, non compatible cache\n", __func__); - return false; - } - - /* a cache entry expires after afetr expiration time for non sheetfed scanners */ - /* this is not taken into account when overwriting cache entries */ -#ifdef HAVE_SYS_TIME_H - if(for_overwrite == SANE_FALSE && dev->settings.expiration_time >=0) - { - gettimeofday (&time, NULL); - if ((time.tv_sec - cache->last_calibration > dev->settings.expiration_time*60) - && (dev->model->is_sheetfed == SANE_FALSE) - && (dev->settings.scan_method == ScanMethod::FLATBED)) - { - DBG (DBG_proc, "%s: expired entry, non compatible cache\n", __func__); - return false; - } - } -#endif - - DBGCOMPLETED; - return true; -} - - -/** @brief compute maximum line distance shift - * compute maximum line distance shift for the motor and sensor - * combination. Line distance shift is the distance between different - * color component of CCD sensors. Since these components aren't at - * the same physical place, they scan diffrent lines. Software must - * take this into account to accurately mix color data. - * @param dev device session to compute max_shift for - * @param channels number of color channels for the scan - * @param yres motor resolution used for the scan - * @param flags scan flags - * @return 0 or line distance shift - */ -int sanei_genesys_compute_max_shift(Genesys_Device *dev, - int channels, - int yres, - int flags) -{ - int max_shift; - - max_shift=0; - if (channels > 1 && !(flags & SCAN_FLAG_IGNORE_LINE_DISTANCE)) - { - max_shift = dev->ld_shift_r; - if (dev->ld_shift_b > max_shift) - max_shift = dev->ld_shift_b; - if (dev->ld_shift_g > max_shift) - max_shift = dev->ld_shift_g; - max_shift = (max_shift * yres) / dev->motor.base_ydpi; - } - return max_shift; -} - -/** @brief build lookup table for digital enhancements - * 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. - * @param lut pointer where to store the generated lut - * @param in_bits number of bits for in values - * @param out_bits number of bits of out values - * @param out_min minimal out value - * @param out_max maximal out value - * @param slope slope of the generated data - * @param offset offset of the generated data - */ -SANE_Status -sanei_genesys_load_lut (unsigned char * lut, - int in_bits, - int out_bits, - int out_min, - int out_max, - int slope, - int offset) -{ - SANE_Status ret = SANE_STATUS_GOOD; - int i, j; - double shift, rise; - int max_in_val = (1 << in_bits) - 1; - int max_out_val = (1 << out_bits) - 1; - uint8_t *lut_p8 = lut; - uint16_t *lut_p16 = (uint16_t *) lut; - - DBGSTART; - - /* slope is converted to rise per unit run: - * first [-127,127] to [-.999,.999] - * then to [-PI/4,PI/4] then [0,PI/2] - * 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 / 128 * M_PI_4 + M_PI_4) * 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; - - /* cap data to required range */ - if (j < out_min) - { - j = out_min; - } - else if (j > out_max) - { - j = out_max; - } - - /* copy result according to bit depth */ - if (out_bits <= 8) - { - *lut_p8 = j; - lut_p8++; - } - else - { - *lut_p16 = j; - lut_p16++; - } - } - - DBGCOMPLETED; - return ret; -} - -void sanei_genesys_usleep(unsigned int useconds) -{ - usleep(useconds); -} - -void sanei_genesys_sleep_ms(unsigned int milliseconds) -{ - sanei_genesys_usleep(milliseconds * 1000); -} - -static std::unique_ptr>> s_functions_run_at_backend_exit; - -void add_function_to_run_at_backend_exit(std::function function) -{ - if (!s_functions_run_at_backend_exit) - s_functions_run_at_backend_exit.reset(new std::vector>()); - s_functions_run_at_backend_exit->push_back(std::move(function)); -} - -void run_functions_at_backend_exit() -{ - for (auto it = s_functions_run_at_backend_exit->rbegin(); - it != s_functions_run_at_backend_exit->rend(); ++it) - { - (*it)(); - } - s_functions_run_at_backend_exit.release(); -} - -void debug_dump(unsigned level, const Genesys_Settings& settings) -{ - DBG(level, "settings:\n" - "Resolution X/Y : %u / %u dpi\n" - "Lines : %u\n" - "Pixels per line : %u\n" - "Depth : %u\n" - "Start position X/Y : %.3f/%.3f\n" - "Scan mode : %d\n\n", - settings.xres, settings.yres, - settings.lines, settings.pixels, settings.depth, - settings.tl_x, settings.tl_y, - static_cast(settings.scan_mode)); -} - -void debug_dump(unsigned level, const SetupParams& params) -{ - DBG(level, "settings:\n" - "Resolution X/Y : %u / %u dpi\n" - "Lines : %u\n" - "Pixels per line : %u\n" - "Depth : %u\n" - "Channels : %u\n" - "Start position X/Y : %g / %g\n" - "Scan mode : %d\n" - "Color filter : %d\n" - "Flags : %x\n", - params.xres, params.yres, - params.lines, params.pixels, - params.depth, params.channels, - params.startx, params.starty, - static_cast(params.scan_mode), - static_cast(params.color_filter), - params.flags); -} - -void debug_dump(unsigned level, const Genesys_Current_Setup& setup) -{ - DBG(level, "current_setup:\n" - "Pixels: %d\n" - "Lines: %d\n" - "Depth: %d\n" - "Channels: %d\n" - "exposure_time: %d\n" - "Resolution X/Y: %g %g\n" - "ccd_size_divisor: %d\n" - "stagger: %d\n" - "max_shift: %d\n", - setup.pixels, - setup.lines, - setup.depth, - setup.channels, - setup.exposure_time, - setup.xres, setup.yres, - setup.ccd_size_divisor, - setup.stagger, - setup.max_shift); -} diff --git a/backend/genesys_low.h b/backend/genesys_low.h deleted file mode 100644 index e750808..0000000 --- a/backend/genesys_low.h +++ /dev/null @@ -1,2042 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2003 Oliver Rauch - Copyright (C) 2003, 2004 Henning Meier-Geinitz - Copyright (C) 2004, 2005 Gerhard Jaeger - Copyright (C) 2004-2013 Stéphane Voltz - Copyright (C) 2005-2009 Pierre Willenbrock - Copyright (C) 2006 Laurent Charpentier - Parts of the structs have been taken from the gt68xx backend by - Sergey Vlasov et al. - - 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. -*/ - -#ifndef GENESYS_LOW_H -#define GENESYS_LOW_H - - -#include "../include/sane/config.h" - -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_MKDIR -#include -#include -#endif - -#include "../include/sane/sane.h" -#include "../include/sane/sanei.h" -#include "../include/sane/saneopts.h" - -#include "../include/sane/sanei_backend.h" -#include "../include/sane/sanei_usb.h" - -#include "../include/_stdint.h" - -#include "genesys_error.h" -#include "genesys_sanei.h" -#include "genesys_serialize.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define FREE_IFNOT_NULL(x) if(x!=NULL) { free(x); x=NULL;} - -#define GENESYS_RED 0 -#define GENESYS_GREEN 1 -#define GENESYS_BLUE 2 - -/* Flags */ -#define GENESYS_FLAG_UNTESTED (1 << 0) /**< Print a warning for these scanners */ -#define GENESYS_FLAG_14BIT_GAMMA (1 << 1) /**< use 14bit Gamma table instead of 12 */ -#define GENESYS_FLAG_LAZY_INIT (1 << 2) /**< skip extensive ASIC test at init */ -#define GENESYS_FLAG_XPA (1 << 3) -#define GENESYS_FLAG_SKIP_WARMUP (1 << 4) /**< skip genesys_warmup() */ -/** @brief offset calibration flag - * signals that the scanner does offset calibration. In this case off_calibration() and - * coarse_gain_calibration() functions must be implemented - */ -#define GENESYS_FLAG_OFFSET_CALIBRATION (1 << 5) -#define GENESYS_FLAG_SEARCH_START (1 << 6) /**< do start search before scanning */ -#define GENESYS_FLAG_REPARK (1 << 7) /**< repark head (and check for lock) by - moving without scanning */ -#define GENESYS_FLAG_DARK_CALIBRATION (1 << 8) /**< do dark calibration */ -#define GENESYS_FLAG_STAGGERED_LINE (1 << 9) /**< pixel columns are shifted vertically for hi-res modes */ - -#define GENESYS_FLAG_MUST_WAIT (1 << 10) /**< tells wether the scanner must wait for the head when parking */ - - -#define GENESYS_FLAG_HAS_UTA (1 << 11) /**< scanner has a transparency adapter */ - -#define GENESYS_FLAG_DARK_WHITE_CALIBRATION (1 << 12) /**< yet another calibration method. does white and dark shading in one run, depending on a black and a white strip*/ -#define GENESYS_FLAG_CUSTOM_GAMMA (1 << 13) /**< allow custom gamma tables */ -#define GENESYS_FLAG_NO_CALIBRATION (1 << 14) /**< allow scanners to use skip the calibration, needed for sheetfed scanners */ -#define GENESYS_FLAG_SIS_SENSOR (1 << 16) /**< handling of multi-segments sensors in software */ -#define GENESYS_FLAG_SHADING_NO_MOVE (1 << 17) /**< scanner doesn't move sensor during shading calibration */ -#define GENESYS_FLAG_SHADING_REPARK (1 << 18) /**< repark head between shading scans */ -#define GENESYS_FLAG_FULL_HWDPI_MODE (1 << 19) /**< scanner always use maximum hw dpi to setup the sensor */ -// scanner has infrared transparency scanning capability -#define GENESYS_FLAG_HAS_UTA_INFRARED (1 << 20) - -#define GENESYS_HAS_NO_BUTTONS 0 /**< scanner has no supported button */ -#define GENESYS_HAS_SCAN_SW (1 << 0) /**< scanner has SCAN button */ -#define GENESYS_HAS_FILE_SW (1 << 1) /**< scanner has FILE button */ -#define GENESYS_HAS_COPY_SW (1 << 2) /**< scanner has COPY button */ -#define GENESYS_HAS_EMAIL_SW (1 << 3) /**< scanner has EMAIL button */ -#define GENESYS_HAS_PAGE_LOADED_SW (1 << 4) /**< scanner has paper in detection */ -#define GENESYS_HAS_OCR_SW (1 << 5) /**< scanner has OCR button */ -#define GENESYS_HAS_POWER_SW (1 << 6) /**< scanner has power button */ -#define GENESYS_HAS_CALIBRATE (1 << 7) /**< scanner has 'calibrate' software button to start calibration */ -#define GENESYS_HAS_EXTRA_SW (1 << 8) /**< scanner has extra function button */ - -/* USB control message values */ -#define REQUEST_TYPE_IN (USB_TYPE_VENDOR | USB_DIR_IN) -#define REQUEST_TYPE_OUT (USB_TYPE_VENDOR | USB_DIR_OUT) -#define REQUEST_REGISTER 0x0c -#define REQUEST_BUFFER 0x04 -#define VALUE_BUFFER 0x82 -#define VALUE_SET_REGISTER 0x83 -#define VALUE_READ_REGISTER 0x84 -#define VALUE_WRITE_REGISTER 0x85 -#define VALUE_INIT 0x87 -#define GPIO_OUTPUT_ENABLE 0x89 -#define GPIO_READ 0x8a -#define GPIO_WRITE 0x8b -#define VALUE_BUF_ENDACCESS 0x8c -#define VALUE_GET_REGISTER 0x8e -#define INDEX 0x00 - -/* todo: used? -#define VALUE_READ_STATUS 0x86 -*/ - -/* Read/write bulk data/registers */ -#define BULK_OUT 0x01 -#define BULK_IN 0x00 -#define BULK_RAM 0x00 -#define BULK_REGISTER 0x11 - -#define BULKOUT_MAXSIZE 0xF000 - -/* AFE values */ -#define AFE_INIT 1 -#define AFE_SET 2 -#define AFE_POWER_SAVE 4 - -#define LOWORD(x) ((uint16_t)((x) & 0xffff)) -#define HIWORD(x) ((uint16_t)((x) >> 16)) -#define LOBYTE(x) ((uint8_t)((x) & 0xFF)) -#define HIBYTE(x) ((uint8_t)((x) >> 8)) - -/* Global constants */ -/* TODO: emove this leftover of early backend days */ -#define MOTOR_SPEED_MAX 350 -#define DARK_VALUE 0 - -#define PWRBIT 0x80 -#define BUFEMPTY 0x40 -#define FEEDFSH 0x20 -#define SCANFSH 0x10 -#define HOMESNR 0x08 -#define LAMPSTS 0x04 -#define FEBUSY 0x02 -#define MOTORENB 0x01 - -#define GENESYS_MAX_REGS 256 - -enum class ScanMethod : unsigned { - // normal scan method - FLATBED = 0, - // scan using transparency adaptor - TRANSPARENCY = 1, - // scan using transparency adaptor via infrared channel - TRANSPARENCY_INFRARED = 2 -}; - -inline void serialize(std::istream& str, ScanMethod& x) -{ - unsigned value; - serialize(str, value); - x = static_cast(value); -} - -inline void serialize(std::ostream& str, ScanMethod& x) -{ - unsigned value = static_cast(x); - serialize(str, value); -} - -enum class ScanColorMode : unsigned { - LINEART = 0, - HALFTONE, - GRAY, - COLOR_SINGLE_PASS -}; - -inline void serialize(std::istream& str, ScanColorMode& x) -{ - unsigned value; - serialize(str, value); - x = static_cast(value); -} - -inline void serialize(std::ostream& str, ScanColorMode& x) -{ - unsigned value = static_cast(x); - serialize(str, value); -} - -enum class ColorFilter : unsigned { - RED = 0, - GREEN, - BLUE, - NONE -}; - -inline void serialize(std::istream& str, ColorFilter& x) -{ - unsigned value; - serialize(str, value); - x = static_cast(value); -} - -inline void serialize(std::ostream& str, ColorFilter& x) -{ - unsigned value = static_cast(x); - serialize(str, value); -} - -struct GenesysRegister { - uint16_t address = 0; - uint8_t value = 0; -}; - -inline bool operator<(const GenesysRegister& lhs, const GenesysRegister& rhs) -{ - return lhs.address < rhs.address; -} - -struct GenesysRegisterSetState { - bool is_lamp_on = false; - bool is_xpa_on = false; -}; - -class Genesys_Register_Set { -public: - using container = std::vector; - using iterator = typename container::iterator; - using const_iterator = typename container::const_iterator; - - // FIXME: this shouldn't live here, but in a separate struct that contains Genesys_Register_Set - GenesysRegisterSetState state; - - enum Options { - SEQUENTIAL = 1 - }; - - Genesys_Register_Set() - { - registers_.reserve(GENESYS_MAX_REGS); - } - - // by default the register set is sorted by address. In certain cases it's importand to send - // the registers in certain order: use the SEQUENTIAL option for that - Genesys_Register_Set(Options opts) : Genesys_Register_Set() - { - if ((opts & SEQUENTIAL) == SEQUENTIAL) { - sorted_ = false; - } - } - - void init_reg(uint16_t address, uint8_t default_value) - { - if (find_reg_index(address) >= 0) { - set8(address, default_value); - return; - } - GenesysRegister reg; - reg.address = address; - reg.value = default_value; - registers_.push_back(reg); - if (sorted_) - std::sort(registers_.begin(), registers_.end()); - } - - void remove_reg(uint16_t address) - { - int i = find_reg_index(address); - if (i < 0) { - throw std::runtime_error("the register does not exist"); - } - registers_.erase(registers_.begin() + i); - } - - GenesysRegister& find_reg(uint16_t address) - { - int i = find_reg_index(address); - if (i < 0) { - throw std::runtime_error("the register does not exist"); - } - return registers_[i]; - } - - const GenesysRegister& find_reg(uint16_t address) const - { - int i = find_reg_index(address); - if (i < 0) { - throw std::runtime_error("the register does not exist"); - } - return registers_[i]; - } - - GenesysRegister* find_reg_address(uint16_t address) - { - return &find_reg(address); - } - - const GenesysRegister* find_reg_address(uint16_t address) const - { - return &find_reg(address); - } - - void set8(uint16_t address, uint8_t value) - { - find_reg(address).value = value; - } - - void set8_mask(uint16_t address, uint8_t value, uint8_t mask) - { - auto& reg = find_reg(address); - reg.value = (reg.value & ~mask) | value; - } - - void set16(uint16_t address, uint16_t value) - { - find_reg(address).value = (value >> 8) & 0xff; - find_reg(address + 1).value = value & 0xff; - } - - void set24(uint16_t address, uint32_t value) - { - find_reg(address).value = (value >> 16) & 0xff; - find_reg(address + 1).value = (value >> 8) & 0xff; - find_reg(address + 2).value = value & 0xff; - } - - uint8_t get8(uint16_t address) const - { - return find_reg(address).value; - } - - uint16_t get16(uint16_t address) const - { - return (find_reg(address).value << 8) | find_reg(address + 1).value; - } - - uint32_t get24(uint16_t address) const - { - return (find_reg(address).value << 16) | - (find_reg(address + 1).value << 8) | - find_reg(address + 2).value; - } - - void clear() { registers_.clear(); } - size_t size() const { return registers_.size(); } - - iterator begin() { return registers_.begin(); } - const_iterator begin() const { return registers_.begin(); } - - iterator end() { return registers_.end(); } - const_iterator end() const { return registers_.end(); } - -private: - int find_reg_index(uint16_t address) const - { - if (!sorted_) { - for (size_t i = 0; i < registers_.size(); i++) { - if (registers_[i].address == address) { - return i; - } - } - return -1; - } - - GenesysRegister search; - search.address = address; - auto it = std::lower_bound(registers_.begin(), registers_.end(), search); - if (it == registers_.end()) - return -1; - if (it->address != address) - return -1; - return std::distance(registers_.begin(), it); - } - - // registers are stored in a sorted vector - bool sorted_ = true; - std::vector registers_; -}; - -template -struct AssignableArray : public std::array { - AssignableArray() = default; - AssignableArray(const AssignableArray&) = default; - AssignableArray& operator=(const AssignableArray&) = default; - - AssignableArray& operator=(std::initializer_list init) - { - if (init.size() != std::array::size()) - throw std::runtime_error("An array of incorrect size assigned"); - std::copy(init.begin(), init.end(), std::array::begin()); - return *this; - } -}; - -struct GenesysRegisterSetting { - GenesysRegisterSetting() = default; - - GenesysRegisterSetting(uint16_t p_address, uint8_t p_value) : - address(p_address), value(p_value) - {} - - GenesysRegisterSetting(uint16_t p_address, uint8_t p_value, uint8_t p_mask) : - address(p_address), value(p_value), mask(p_mask) - {} - - uint16_t address = 0; - uint8_t value = 0; - uint8_t mask = 0xff; - - bool operator==(const GenesysRegisterSetting& other) const - { - return address == other.address && value == other.value && mask == other.mask; - } -}; - -template -void serialize(Stream& str, GenesysRegisterSetting& reg) -{ - serialize(str, reg.address); - serialize(str, reg.value); - serialize(str, reg.mask); -} - -class GenesysRegisterSettingSet { -public: - using container = std::vector; - using iterator = typename container::iterator; - using const_iterator = typename container::const_iterator; - - GenesysRegisterSettingSet() = default; - GenesysRegisterSettingSet(std::initializer_list ilist) : regs_(ilist) {} - - iterator begin() { return regs_.begin(); } - const_iterator begin() const { return regs_.begin(); } - iterator end() { return regs_.end(); } - const_iterator end() const { return regs_.end(); } - - GenesysRegisterSetting& operator[](size_t i) { return regs_[i]; } - const GenesysRegisterSetting& operator[](size_t i) const { return regs_[i]; } - - size_t size() const { return regs_.size(); } - bool empty() const { return regs_.empty(); } - void clear() { regs_.clear(); } - - void push_back(GenesysRegisterSetting reg) { regs_.push_back(reg); } - - void merge(const GenesysRegisterSettingSet& other) - { - for (const auto& reg : other) { - set_value(reg.address, reg.value); - } - } - - uint8_t get_value(uint16_t address) const - { - for (const auto& reg : regs_) { - if (reg.address == address) - return reg.value; - } - throw std::runtime_error("Unknown register"); - } - - void set_value(uint16_t address, uint8_t value) - { - for (auto& reg : regs_) { - if (reg.address == address) { - reg.value = value; - return; - } - } - push_back(GenesysRegisterSetting(address, value)); - } - - friend void serialize(std::istream& str, GenesysRegisterSettingSet& reg); - friend void serialize(std::ostream& str, GenesysRegisterSettingSet& reg); - - bool operator==(const GenesysRegisterSettingSet& other) const - { - return regs_ == other.regs_; - } - -private: - std::vector regs_; -}; - -inline void serialize(std::istream& str, GenesysRegisterSettingSet& reg) -{ - reg.clear(); - const size_t max_register_address = - 1 << (sizeof(GenesysRegisterSetting::address) * CHAR_BIT); - serialize(str, reg.regs_, max_register_address); -} - -inline void serialize(std::ostream& str, GenesysRegisterSettingSet& reg) -{ - serialize(str, reg.regs_); -} - -struct GenesysFrontendLayout -{ - std::array offset_addr = {}; - std::array gain_addr = {}; - - bool operator==(const GenesysFrontendLayout& other) const - { - return offset_addr == other.offset_addr && gain_addr == other.gain_addr; - } -}; - -/** @brief Data structure to set up analog frontend. - The analog frontend converts analog value from image sensor to digital value. It has its own - control registers which are set up with this structure. The values are written using - sanei_genesys_fe_write_data. - */ -struct Genesys_Frontend -{ - Genesys_Frontend() = default; - - // id of the frontend description - uint8_t fe_id = 0; - - // all registers of the frontend - GenesysRegisterSettingSet regs; - - // extra control registers - std::array reg2 = {}; - - GenesysFrontendLayout layout; - - void set_offset(unsigned which, uint8_t value) - { - regs.set_value(layout.offset_addr[which], value); - } - - void set_gain(unsigned which, uint8_t value) - { - regs.set_value(layout.gain_addr[which], value); - } - - uint8_t get_offset(unsigned which) const - { - return regs.get_value(layout.offset_addr[which]); - } - - uint8_t get_gain(unsigned which) const - { - return regs.get_value(layout.gain_addr[which]); - } - - bool operator==(const Genesys_Frontend& other) const - { - return fe_id == other.fe_id && - regs == other.regs && - reg2 == other.reg2 && - layout == other.layout; - } -}; - -template -void serialize(Stream& str, Genesys_Frontend& x) -{ - serialize(str, x.fe_id); - serialize_newline(str); - serialize(str, x.regs); - serialize_newline(str); - serialize(str, x.reg2); - serialize_newline(str); - serialize(str, x.layout.offset_addr); - serialize(str, x.layout.gain_addr); -} - -struct SensorExposure { - uint16_t red, green, blue; -}; - -struct Genesys_Sensor { - - Genesys_Sensor() = default; - ~Genesys_Sensor() = default; - - // id of the sensor description - uint8_t sensor_id = 0; - int optical_res = 0; - - // the minimum and maximum resolution this sensor is usable at. -1 means that the resolution - // can be any. - int min_resolution = -1; - int max_resolution = -1; - - // the scan method used with the sensor - ScanMethod method = ScanMethod::FLATBED; - - // CCD may present itself as half or quarter-size CCD on certain resolutions - int ccd_size_divisor = 1; - - int black_pixels = 0; - // value of the dummy register - int dummy_pixel = 0; - // last pixel of CCD margin at optical resolution - int CCD_start_xoffset = 0; - // total pixels used by the sensor - int sensor_pixels = 0; - // TA CCD target code (reference gain) - int fau_gain_white_ref = 0; - // CCD target code (reference gain) - int gain_white_ref = 0; - - // red, green and blue initial exposure values - SensorExposure exposure; - - int exposure_lperiod = -1; - - GenesysRegisterSettingSet custom_regs; - GenesysRegisterSettingSet custom_fe_regs; - - // red, green and blue gamma coefficient for default gamma tables - AssignableArray gamma; - - int get_ccd_size_divisor_for_dpi(int xres) const - { - if (ccd_size_divisor >= 4 && xres * 4 <= optical_res) { - return 4; - } - if (ccd_size_divisor >= 2 && xres * 2 <= optical_res) { - return 2; - } - return 1; - } - - bool operator==(const Genesys_Sensor& other) const - { - return sensor_id == other.sensor_id && - optical_res == other.optical_res && - min_resolution == other.min_resolution && - max_resolution == other.max_resolution && - method == other.method && - ccd_size_divisor == other.ccd_size_divisor && - black_pixels == other.black_pixels && - dummy_pixel == other.dummy_pixel && - CCD_start_xoffset == other.CCD_start_xoffset && - sensor_pixels == other.sensor_pixels && - fau_gain_white_ref == other.fau_gain_white_ref && - gain_white_ref == other.gain_white_ref && - exposure.blue == other.exposure.blue && - exposure.green == other.exposure.green && - exposure.red == other.exposure.red && - exposure_lperiod == other.exposure_lperiod && - custom_regs == other.custom_regs && - custom_fe_regs == other.custom_fe_regs && - gamma == other.gamma; - } -}; - -template -void serialize(Stream& str, Genesys_Sensor& x) -{ - serialize(str, x.sensor_id); - serialize(str, x.optical_res); - serialize(str, x.min_resolution); - serialize(str, x.max_resolution); - serialize(str, x.method); - serialize(str, x.ccd_size_divisor); - serialize(str, x.black_pixels); - serialize(str, x.dummy_pixel); - serialize(str, x.CCD_start_xoffset); - serialize(str, x.sensor_pixels); - serialize(str, x.fau_gain_white_ref); - serialize(str, x.gain_white_ref); - serialize_newline(str); - serialize(str, x.exposure.blue); - serialize(str, x.exposure.green); - serialize(str, x.exposure.red); - serialize(str, x.exposure_lperiod); - serialize_newline(str); - serialize(str, x.custom_regs); - serialize_newline(str); - serialize(str, x.custom_fe_regs); - serialize_newline(str); - serialize(str, x.gamma); -} - -struct Genesys_Gpo -{ - Genesys_Gpo() = default; - - Genesys_Gpo(uint8_t id, const std::array& v, const std::array& e) - { - gpo_id = id; - value[0] = v[0]; - value[1] = v[1]; - enable[0] = e[0]; - enable[1] = e[1]; - } - - // Genesys_Gpo - uint8_t gpo_id = 0; - - // registers 0x6c and 0x6d on GL841, GL842, GL843, GL846, GL848 and possibly others - uint8_t value[2] = { 0, 0 }; - - // registers 0x6e and 0x6f on GL841, GL842, GL843, GL846, GL848 and possibly others - uint8_t enable[2] = { 0, 0 }; -}; - -struct Genesys_Motor_Slope -{ - Genesys_Motor_Slope() = default; - Genesys_Motor_Slope(int p_maximum_start_speed, int p_maximum_speed, int p_minimum_steps, - float p_g) : - maximum_start_speed(p_maximum_start_speed), - maximum_speed(p_maximum_speed), - minimum_steps(p_minimum_steps), - g(p_g) - {} - - // maximum speed allowed when accelerating from standstill. Unit: pixeltime/step - int maximum_start_speed = 0; - // maximum speed allowed. Unit: pixeltime/step - int maximum_speed = 0; - // number of steps used for default curve - int minimum_steps = 0; - - /* power for non-linear acceleration curves. - vs*(1-i^g)+ve*(i^g) where - vs = start speed, ve = end speed, - i = 0.0 for first entry and i = 1.0 for last entry in default table - */ - float g = 0; -}; - - -struct Genesys_Motor -{ - Genesys_Motor() = default; - Genesys_Motor(uint8_t p_motor_id, int p_base_ydpi, int p_optical_ydpi, int p_max_step_type, - int p_power_mode_count, - const std::vector>& p_slopes) : - motor_id(p_motor_id), - base_ydpi(p_base_ydpi), - optical_ydpi(p_optical_ydpi), - max_step_type(p_max_step_type), - power_mode_count(p_power_mode_count), - slopes(p_slopes) - {} - - // id of the motor description - uint8_t motor_id = 0; - // motor base steps. Unit: 1/inch - int base_ydpi = 0; - // maximum resolution in y-direction. Unit: 1/inch - int optical_ydpi = 0; - // maximum step type. 0-2 - int max_step_type = 0; - // number of power modes - int power_mode_count = 0; - // slopes to derive individual slopes from - std::vector> slopes; -}; - -typedef enum Genesys_Color_Order -{ - COLOR_ORDER_RGB, - COLOR_ORDER_BGR -} -Genesys_Color_Order; - - -#define MAX_RESOLUTIONS 13 -#define MAX_DPI 4 - -#define GENESYS_GL646 646 -#define GENESYS_GL841 841 -#define GENESYS_GL843 843 -#define GENESYS_GL845 845 -#define GENESYS_GL846 846 -#define GENESYS_GL847 847 -#define GENESYS_GL848 848 -#define GENESYS_GL123 123 -#define GENESYS_GL124 124 - -enum Genesys_Model_Type -{ - MODEL_UMAX_ASTRA_4500 = 0, - MODEL_CANON_LIDE_50, - MODEL_PANASONIC_KV_SS080, - MODEL_HP_SCANJET_4850C, - MODEL_HP_SCANJET_G4010, - MODEL_HP_SCANJET_G4050, - MODEL_CANON_CANOSCAN_4400F, - MODEL_CANON_CANOSCAN_8400F, - MODEL_CANON_CANOSCAN_8600F, - MODEL_CANON_LIDE_100, - MODEL_CANON_LIDE_110, - MODEL_CANON_LIDE_120, - MODEL_CANON_LIDE_210, - MODEL_CANON_LIDE_220, - MODEL_CANON_CANOSCAN_5600F, - MODEL_CANON_LIDE_700F, - MODEL_CANON_LIDE_200, - MODEL_CANON_LIDE_60, - MODEL_CANON_LIDE_80, - MODEL_HP_SCANJET_2300C, - MODEL_HP_SCANJET_2400C, - MODEL_VISIONEER_STROBE_XP200, - MODEL_HP_SCANJET_3670C, - MODEL_PLUSTEK_OPTICPRO_ST12, - MODEL_PLUSTEK_OPTICPRO_ST24, - MODEL_MEDION_MD5345, - MODEL_VISIONEER_STROBE_XP300, - MODEL_SYSCAN_DOCKETPORT_665, - MODEL_VISIONEER_ROADWARRIOR, - MODEL_SYSCAN_DOCKETPORT_465, - MODEL_VISIONEER_STROBE_XP100_REVISION3, - MODEL_PENTAX_DSMOBILE_600, - MODEL_SYSCAN_DOCKETPORT_467, - MODEL_SYSCAN_DOCKETPORT_685, - MODEL_SYSCAN_DOCKETPORT_485, - MODEL_DCT_DOCKETPORT_487, - MODEL_VISIONEER_7100, - MODEL_XEROX_2400, - MODEL_XEROX_TRAVELSCANNER_100, - MODEL_PLUSTEK_OPTICPRO_3600, - MODEL_HP_SCANJET_N6310, - MODEL_PLUSTEK_OPTICBOOK_3800, - MODEL_CANON_IMAGE_FORMULA_101 -}; - -enum Genesys_Dac_Type -{ - DAC_WOLFSON_UMAX = 0, - DAC_WOLFSON_ST12, - DAC_WOLFSON_ST24, - DAC_WOLFSON_5345, - DAC_WOLFSON_HP2400, - DAC_WOLFSON_HP2300, - DAC_CANONLIDE35, - DAC_AD_XP200, - DAC_WOLFSON_XP300, - DAC_WOLFSON_HP3670, - DAC_WOLFSON_DSM600, - DAC_CANONLIDE200, - DAC_KVSS080, - DAC_G4050, - DAC_CANONLIDE110, - DAC_PLUSTEK_3600, - DAC_CANONLIDE700, - DAC_CS8400F, - DAC_CS8600F, - DAC_IMG101, - DAC_PLUSTEK3800, - DAC_CANONLIDE80, - DAC_CANONLIDE120 -}; - -enum Genesys_Sensor_Type -{ - CCD_UMAX = 0, - CCD_ST12, // SONY ILX548: 5340 Pixel ??? - CCD_ST24, // SONY ILX569: 10680 Pixel ??? - CCD_5345, - CCD_HP2400, - CCD_HP2300, - CCD_CANONLIDE35, - CIS_XP200, // CIS sensor for Strobe XP200, - CCD_HP3670, - CCD_DP665, - CCD_ROADWARRIOR, - CCD_DSMOBILE600, - CCD_XP300, - CCD_DP685, - CIS_CANONLIDE200, - CIS_CANONLIDE100, - CCD_KVSS080, - CCD_G4050, - CIS_CANONLIDE110, - CCD_PLUSTEK_3600, - CCD_HP_N6310, - CIS_CANONLIDE700, - CCD_CS4400F, - CCD_CS8400F, - CCD_CS8600F, - CCD_IMG101, - CCD_PLUSTEK3800, - CIS_CANONLIDE210, - CIS_CANONLIDE80, - CIS_CANONLIDE220, - CIS_CANONLIDE120, -}; - -enum Genesys_Gpo_Type -{ - GPO_UMAX, - GPO_ST12, - GPO_ST24, - GPO_5345, - GPO_HP2400, - GPO_HP2300, - GPO_CANONLIDE35, - GPO_XP200, - GPO_XP300, - GPO_HP3670, - GPO_DP665, - GPO_DP685, - GPO_CANONLIDE200, - GPO_KVSS080, - GPO_G4050, - GPO_CANONLIDE110, - GPO_PLUSTEK_3600, - GPO_CANONLIDE210, - GPO_HP_N6310, - GPO_CANONLIDE700, - GPO_CS4400F, - GPO_CS8400F, - GPO_CS8600F, - GPO_IMG101, - GPO_PLUSTEK3800, - GPO_CANONLIDE80, - GPO_CANONLIDE120 -}; - -enum Genesys_Motor_Type -{ - MOTOR_UMAX = 0, - MOTOR_5345, - MOTOR_ST24, - MOTOR_HP2400, - MOTOR_HP2300, - MOTOR_CANONLIDE35, - MOTOR_XP200, - MOTOR_XP300, - MOTOR_HP3670, - MOTOR_DP665, - MOTOR_ROADWARRIOR, - MOTOR_DSMOBILE_600, - MOTOR_CANONLIDE200, - MOTOR_CANONLIDE100, - MOTOR_KVSS080, - MOTOR_G4050, - MOTOR_CANONLIDE110, - MOTOR_PLUSTEK_3600, - MOTOR_CANONLIDE700, - MOTOR_CS8400F, - MOTOR_CS8600F, - MOTOR_IMG101, - MOTOR_PLUSTEK3800, - MOTOR_CANONLIDE210, - MOTOR_CANONLIDE80, - MOTOR_CANONLIDE120 -}; - -/* Forward typedefs */ -typedef struct Genesys_Device Genesys_Device; -struct Genesys_Scanner; -typedef struct Genesys_Calibration_Cache Genesys_Calibration_Cache; - -/** - * Scanner command set description. - * - * This description contains parts which are common to all scanners with the - * same command set, but may have different optical resolution and other - * parameters. - */ -typedef struct Genesys_Command_Set -{ - /** @name Identification */ - /*@{ */ - - /** Name of this command set */ - SANE_String_Const name; - - /*@} */ - - bool (*needs_home_before_init_regs_for_scan) (Genesys_Device* dev); - - /** For ASIC initialization */ - SANE_Status (*init) (Genesys_Device * dev); - - SANE_Status (*init_regs_for_warmup) (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, - int *channels, int *total_size); - SANE_Status (*init_regs_for_coarse_calibration) (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set& regs); - SANE_Status (*init_regs_for_shading) (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs); - SANE_Status (*init_regs_for_scan) (Genesys_Device * dev, const Genesys_Sensor& sensor); - - SANE_Bool (*get_filter_bit) (Genesys_Register_Set * reg); - SANE_Bool (*get_lineart_bit) (Genesys_Register_Set * reg); - SANE_Bool (*get_bitset_bit) (Genesys_Register_Set * reg); - SANE_Bool (*get_gain4_bit) (Genesys_Register_Set * reg); - SANE_Bool (*get_fast_feed_bit) (Genesys_Register_Set * reg); - - SANE_Bool (*test_buffer_empty_bit) (SANE_Byte val); - SANE_Bool (*test_motor_flag_bit) (SANE_Byte val); - - SANE_Status (*set_fe) (Genesys_Device * dev, const Genesys_Sensor& sensor, uint8_t set); - SANE_Status (*set_powersaving) (Genesys_Device * dev, int delay); - SANE_Status (*save_power) (Genesys_Device * dev, SANE_Bool enable); - - SANE_Status (*begin_scan) (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set * regs, - SANE_Bool start_motor); - SANE_Status (*end_scan) (Genesys_Device * dev, - Genesys_Register_Set * regs, - SANE_Bool check_stop); - - /** - * Send gamma tables to ASIC - */ - SANE_Status (*send_gamma_table) (Genesys_Device * dev, const Genesys_Sensor& sensor); - - SANE_Status (*search_start_position) (Genesys_Device * dev); - SANE_Status (*offset_calibration) (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs); - SANE_Status (*coarse_gain_calibration) (Genesys_Device * dev, - const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, int dpi); - SANE_Status (*led_calibration) (Genesys_Device * dev, Genesys_Sensor& sensor, - Genesys_Register_Set& regs); - - void (*wait_for_motor_stop) (Genesys_Device* dev); - SANE_Status (*slow_back_home) (Genesys_Device * dev, SANE_Bool wait_until_home); - SANE_Status (*rewind) (Genesys_Device * dev); - - SANE_Status (*bulk_write_register) (Genesys_Device * dev, - Genesys_Register_Set& regs); - - SANE_Status (*bulk_write_data) (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len); - - SANE_Status (*bulk_read_data) (Genesys_Device * dev, uint8_t addr, - uint8_t * data, size_t len); - - // Updates hardware sensor information in Genesys_Scanner.val[]. - SANE_Status (*update_hardware_sensors) (struct Genesys_Scanner * s); - - /* functions for sheetfed scanners */ - /** - * load document into scanner - */ - SANE_Status (*load_document) (Genesys_Device * dev); - /** - * detects is the scanned document has left scanner. In this - * case it updates the amount of data to read and set up - * flags in the dev struct - */ - SANE_Status (*detect_document_end) (Genesys_Device * dev); - /** - * eject document from scanner - */ - SANE_Status (*eject_document) (Genesys_Device * dev); - /** - * search for an black or white area in forward or reverse - * direction */ - SANE_Status (*search_strip) (Genesys_Device * dev, const Genesys_Sensor& sensor, - SANE_Bool forward, SANE_Bool black); - - bool (*is_compatible_calibration) (Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Calibration_Cache* cache, SANE_Bool for_overwrite); - - /* functions for transparency adapter */ - /** - * move scanning head to transparency adapter - */ - SANE_Status (*move_to_ta) (Genesys_Device * dev); - - /** - * write shading data calibration to ASIC - */ - SANE_Status (*send_shading_data) (Genesys_Device * dev, const Genesys_Sensor& sensor, - uint8_t * data, int size); - - // calculate current scan setup - void (*calculate_current_setup) (Genesys_Device * dev, const Genesys_Sensor& sensor); - - /** - * cold boot init function - */ - SANE_Status (*asic_boot) (Genesys_Device * dev, SANE_Bool cold); - -} Genesys_Command_Set; - -/** @brief structure to describe a scanner model - * This structure describes a model. It is composed of information on the - * sensor, the motor, scanner geometry and flags to drive operation. - */ -typedef struct Genesys_Model -{ - SANE_String_Const name; - SANE_String_Const vendor; - SANE_String_Const model; - SANE_Int model_id; - - SANE_Int asic_type; /* ASIC type gl646 or gl841 */ - Genesys_Command_Set *cmd_set; /* pointers to low level functions */ - - SANE_Int xdpi_values[MAX_RESOLUTIONS]; /* possible x resolutions */ - SANE_Int ydpi_values[MAX_RESOLUTIONS]; /* possible y resolutions */ - SANE_Int bpp_gray_values[MAX_DPI]; /* possible depths in gray mode */ - SANE_Int bpp_color_values[MAX_DPI]; /* possible depths in color mode */ - - SANE_Fixed x_offset; /* Start of scan area in mm */ - SANE_Fixed y_offset; /* Start of scan area in mm (Amount of - feeding needed to get to the medium) */ - SANE_Fixed x_size; /* Size of scan area in mm */ - SANE_Fixed y_size; /* Size of scan area in mm */ - - SANE_Fixed y_offset_calib; /* Start of white strip in mm */ - SANE_Fixed x_offset_mark; /* Start of black mark in mm */ - - SANE_Fixed x_offset_ta; /* Start of scan area in TA mode in mm */ - SANE_Fixed y_offset_ta; /* Start of scan area in TA mode in mm */ - SANE_Fixed x_size_ta; /* Size of scan area in TA mode in mm */ - SANE_Fixed y_size_ta; /* Size of scan area in TA mode in mm */ - - SANE_Fixed y_offset_calib_ta; /* Start of white strip in TA mode in mm */ - - SANE_Fixed post_scan; /* Size of scan area after paper sensor stops - sensing document in mm */ - SANE_Fixed eject_feed; /* Amount of feeding needed to eject document - after finishing scanning in mm */ - - /* Line-distance correction (in pixel at optical_ydpi) for CCD scanners */ - SANE_Int ld_shift_r; /* red */ - SANE_Int ld_shift_g; /* green */ - SANE_Int ld_shift_b; /* blue */ - - Genesys_Color_Order line_mode_color_order; /* Order of the CCD/CIS colors */ - - SANE_Bool is_cis; /* Is this a CIS or CCD scanner? */ - SANE_Bool is_sheetfed; /* Is this sheetfed scanner? */ - - SANE_Int ccd_type; /* which SENSOR type do we have ? */ - SANE_Int dac_type; /* which DAC do we have ? */ - SANE_Int gpo_type; /* General purpose output type */ - SANE_Int motor_type; /* stepper motor type */ - SANE_Word flags; /* Which hacks are needed for this scanner? */ - SANE_Word buttons; /* Button flags, described existing buttons for the model */ - /*@} */ - SANE_Int shading_lines; /* how many lines are used for shading calibration */ - SANE_Int shading_ta_lines; // how many lines are used for shading calibration in TA mode - SANE_Int search_lines; /* how many lines are used to search start position */ -} Genesys_Model; - -struct Genesys_Settings -{ - ScanMethod scan_method = ScanMethod::FLATBED; - ScanColorMode scan_mode = ScanColorMode::LINEART; - - // horizontal dpi - int xres = 0; - // vertical dpi - int yres = 0; - - //x start on scan table in mm - double tl_x = 0; - // y start on scan table in mm - double tl_y = 0; - - // number of lines at scan resolution - unsigned int lines = 0; - // number of pixels at scan resolution - unsigned int pixels = 0; - - // bit depth of the scan - unsigned int depth = 0; - - ColorFilter color_filter = ColorFilter::NONE; - - // true if scan is true gray, false if monochrome scan - int true_gray = 0; - - // lineart threshold - int threshold = 0; - - // lineart threshold curve for dynamic rasterization - int threshold_curve = 0; - - // Disable interpolation for xres::max(); - - // resolution in x direction - unsigned xres = NOT_SET; - // resolution in y direction - unsigned yres = NOT_SET; - // start pixel in X direction, from dummy_pixel + 1 - float startx = -1; - // start pixel in Y direction, counted according to base_ydpi - float starty = -1; - // the number of pixels in X direction - unsigned pixels = NOT_SET; - // the number of pixels in Y direction - unsigned lines = NOT_SET; - // the depth of the scan in bits. Allowed are 1, 8, 16 - unsigned depth = NOT_SET; - // the number of channels - unsigned channels = NOT_SET; - - ScanMethod scan_method = static_cast(NOT_SET); - - ScanColorMode scan_mode = static_cast(NOT_SET); - - ColorFilter color_filter = static_cast(NOT_SET); - - unsigned flags = NOT_SET; - - void assert_valid() const - { - if (xres == NOT_SET || yres == NOT_SET || startx < 0 || starty < 0 || - pixels == NOT_SET || lines == NOT_SET ||depth == NOT_SET || channels == NOT_SET || - scan_method == static_cast(NOT_SET) || - scan_mode == static_cast(NOT_SET) || - color_filter == static_cast(NOT_SET) || - flags == NOT_SET) - { - throw std::runtime_error("SetupParams are not valid"); - } - } - - bool operator==(const SetupParams& other) const - { - return xres == other.xres && - yres == other.yres && - startx == other.startx && - starty == other.starty && - pixels == other.pixels && - lines == other.lines && - depth == other.depth && - channels == other.channels && - scan_method == other.scan_method && - scan_mode == other.scan_mode && - color_filter == other.color_filter && - flags == other.flags; - } -}; - -template -void serialize(Stream& str, SetupParams& x) -{ - serialize(str, x.xres); - serialize(str, x.yres); - serialize(str, x.startx); - serialize(str, x.starty); - serialize(str, x.pixels); - serialize(str, x.lines); - serialize(str, x.depth); - serialize(str, x.channels); - serialize(str, x.scan_method); - serialize(str, x.scan_mode); - serialize(str, x.color_filter); - serialize(str, x.flags); -} - -struct Genesys_Current_Setup -{ - // params used for this setup - SetupParams params; - - // pixel count expected from scanner - int pixels = 0; - // line count expected from scanner - int lines = 0; - // depth expected from scanner - int depth = 0; - // channel count expected from scanner - int channels = 0; - - // used exposure time - int exposure_time = 0; - // used xres - float xres = 0; - // used yres - float yres = 0; - // half ccd mode - unsigned ccd_size_divisor = 1; - SANE_Int stagger = 0; - // max shift of any ccd component, including staggered pixels - SANE_Int max_shift = 0; - - bool operator==(const Genesys_Current_Setup& other) const - { - return params == other.params && - pixels == other.pixels && - lines == other.lines && - depth == other.depth && - channels == other.channels && - exposure_time == other.exposure_time && - xres == other.xres && - yres == other.yres && - ccd_size_divisor == other.ccd_size_divisor && - stagger == other.stagger && - max_shift == other.max_shift; - } -}; - -template -void serialize(Stream& str, Genesys_Current_Setup& x) -{ - serialize(str, x.params); - serialize_newline(str); - serialize(str, x.pixels); - serialize(str, x.lines); - serialize(str, x.depth); - serialize(str, x.channels); - serialize(str, x.exposure_time); - serialize(str, x.xres); - serialize(str, x.yres); - serialize(str, x.ccd_size_divisor); - serialize(str, x.stagger); - serialize(str, x.max_shift); -} - -struct Genesys_Buffer -{ - Genesys_Buffer() = default; - - size_t size() const { return buffer_.size(); } - size_t avail() const { return avail_; } - size_t pos() const { return pos_; } - - // TODO: refactor code that uses this function to no longer use it - void set_pos(size_t pos) { pos_ = pos; } - - void alloc(size_t size); - void clear(); - - void reset(); - - uint8_t* get_write_pos(size_t size); - uint8_t* get_read_pos(); // TODO: mark as const - - void produce(size_t size); - void consume(size_t size); - -private: - std::vector buffer_; - // current position in read buffer - size_t pos_ = 0; - // data bytes currently in buffer - size_t avail_ = 0; -}; - -struct Genesys_Calibration_Cache -{ - Genesys_Calibration_Cache() = default; - ~Genesys_Calibration_Cache() = default; - - // used to check if entry is compatible - Genesys_Current_Setup used_setup; - time_t last_calibration = 0; - - Genesys_Frontend frontend; - Genesys_Sensor sensor; - - size_t calib_pixels = 0; - size_t calib_channels = 0; - size_t average_size = 0; - std::vector white_average_data; - std::vector dark_average_data; - - bool operator==(const Genesys_Calibration_Cache& other) const - { - return used_setup == other.used_setup && - last_calibration == other.last_calibration && - frontend == other.frontend && - sensor == other.sensor && - calib_pixels == other.calib_pixels && - calib_channels == other.calib_channels && - average_size == other.average_size && - white_average_data == other.white_average_data && - dark_average_data == other.dark_average_data; - } -}; - -template -void serialize(Stream& str, Genesys_Calibration_Cache& x) -{ - serialize(str, x.used_setup); - serialize_newline(str); - serialize(str, x.last_calibration); - serialize_newline(str); - serialize(str, x.frontend); - serialize_newline(str); - serialize(str, x.sensor); - serialize_newline(str); - serialize(str, x.calib_pixels); - serialize(str, x.calib_channels); - serialize(str, x.average_size); - serialize_newline(str); - serialize(str, x.white_average_data); - serialize_newline(str); - serialize(str, x.dark_average_data); -} - -/** - * Describes the current device status for the backend - * session. This should be more accurately called - * Genesys_Session . - */ -struct Genesys_Device -{ - Genesys_Device() = default; - ~Genesys_Device(); - - using Calibration = std::vector; - - // frees commonly used data - void clear(); - - UsbDevice usb_dev; - SANE_Word vendorId = 0; /**< USB vendor identifier */ - SANE_Word productId = 0; /**< USB product identifier */ - - // USB mode: - // 0: not set - // 1: USB 1.1 - // 2: USB 2.0 - SANE_Int usb_mode = 0; - - SANE_String file_name = nullptr; - std::string calib_file; - - // if enabled, no calibration data will be loaded or saved to files - SANE_Int force_calibration = 0; - Genesys_Model *model = nullptr; - - Genesys_Register_Set reg; - Genesys_Register_Set calib_reg; - Genesys_Settings settings; - Genesys_Frontend frontend, frontend_initial; - Genesys_Gpo gpo; - Genesys_Motor motor; - uint8_t control[6] = {}; - time_t init_date = 0; - - size_t average_size = 0; - // number of pixels used during shading calibration - size_t calib_pixels = 0; - // number of lines used during shading calibration - size_t calib_lines = 0; - size_t calib_channels = 0; - size_t calib_resolution = 0; - // bytes to read from USB when calibrating. If 0, this is not set - size_t calib_total_bytes_to_read = 0; - // certain scanners support much higher resolution when scanning transparency, but we can't - // read whole width of the scanner as a single line at that resolution. Thus for stuff like - // calibration we want to read only the possible calibration area. - size_t calib_pixels_offset = 0; - - // gamma overrides. If a respective array is not empty then it means that the gamma for that - // color is overridden. - std::vector gamma_override_tables[3]; - - std::vector white_average_data; - std::vector dark_average_data; - uint16_t dark[3] = {}; - - SANE_Bool already_initialized = 0; - SANE_Int scanhead_position_in_steps = 0; - SANE_Int lamp_off_time = 0; - - SANE_Bool read_active = 0; - // signal wether the park command has been issued - SANE_Bool parking = 0; - - // for sheetfed scanner's, is TRUE when there is a document in the scanner - SANE_Bool document = 0; - - SANE_Bool needs_home_ta = 0; - - Genesys_Buffer read_buffer; - Genesys_Buffer lines_buffer; - Genesys_Buffer shrink_buffer; - Genesys_Buffer out_buffer; - - // buffer for digital lineart from gray data - Genesys_Buffer binarize_buffer = {}; - // local buffer for gray data during dynamix lineart - Genesys_Buffer local_buffer = {}; - - // bytes to read from scanner - size_t read_bytes_left = 0; - - // total bytes read sent to frontend - size_t total_bytes_read = 0; - // total bytes read to be sent to frontend - size_t total_bytes_to_read = 0; - // asic's word per line - size_t wpl = 0; - - // contains the real used values - Genesys_Current_Setup current_setup; - - // look up table used in dynamic rasterization - unsigned char lineart_lut[256] = {}; - - Calibration calibration_cache; - - // used red line-distance shift - SANE_Int ld_shift_r = 0; - // used green line-distance shift - SANE_Int ld_shift_g = 0; - // used blue line-distance shift - SANE_Int ld_shift_b = 0; - // number of segments composing the sensor - int segnb = 0; - // number of lines used in line interpolation - int line_interp = 0; - // number of scan lines used during scan - int line_count = 0; - // bytes per full scan widthline - size_t bpl = 0; - // bytes distance between an odd and an even pixel - size_t dist = 0; - // number of even pixels - size_t len = 0; - // current pixel position within sub window - size_t cur = 0; - // number of bytes to skip at start of line - size_t skip = 0; - - // array describing the order of the sub-segments of the sensor - size_t* order = nullptr; - - // buffer to handle even/odd data - Genesys_Buffer oe_buffer = {}; - - // when true the scanned picture is first buffered to allow software image enhancements - SANE_Bool buffer_image = 0; - - // image buffer where the scanned picture is stored - std::vector img_buffer; - - // binary logger file - FILE *binary = nullptr; -}; - -typedef struct Genesys_USB_Device_Entry -{ - SANE_Word vendor; /**< USB vendor identifier */ - SANE_Word product; /**< USB product identifier */ - Genesys_Model *model; /**< Scanner model information */ -} Genesys_USB_Device_Entry; - -/** - * structure for motor database - */ -typedef struct { - int motor_type; /**< motor id */ - int exposure; /**< exposure for the slope table */ - int step_type; /**< default step type for given exposure */ - uint32_t *table; // 0-terminated slope table at full step (i.e. step_type == 0) -} Motor_Profile; - -#define FULL_STEP 0 -#define HALF_STEP 1 -#define QUARTER_STEP 2 -#define EIGHTH_STEP 3 - -#define SLOPE_TABLE_SIZE 1024 - -#define SCAN_TABLE 0 /* table 1 at 0x4000 for gl124 */ -#define BACKTRACK_TABLE 1 /* table 2 at 0x4800 for gl124 */ -#define STOP_TABLE 2 /* table 3 at 0x5000 for gl124 */ -#define FAST_TABLE 3 /* table 4 at 0x5800 for gl124 */ -#define HOME_TABLE 4 /* table 5 at 0x6000 for gl124 */ - -#define SCAN_FLAG_SINGLE_LINE 0x001 -#define SCAN_FLAG_DISABLE_SHADING 0x002 -#define SCAN_FLAG_DISABLE_GAMMA 0x004 -#define SCAN_FLAG_DISABLE_BUFFER_FULL_MOVE 0x008 -#define SCAN_FLAG_IGNORE_LINE_DISTANCE 0x010 -#define SCAN_FLAG_USE_OPTICAL_RES 0x020 -#define SCAN_FLAG_DISABLE_LAMP 0x040 -#define SCAN_FLAG_DYNAMIC_LINEART 0x080 -#define SCAN_FLAG_CALIBRATION 0x100 -#define SCAN_FLAG_FEEDING 0x200 -#define SCAN_FLAG_USE_XPA 0x400 -#define SCAN_FLAG_ENABLE_LEDADD 0x800 -#define MOTOR_FLAG_AUTO_GO_HOME 0x01 -#define MOTOR_FLAG_DISABLE_BUFFER_FULL_MOVE 0x02 -#define MOTOR_FLAG_FEED 0x04 -#define MOTOR_FLAG_USE_XPA 0x08 - -/** @name "Optical flags" */ -/*@{ optical flags available when setting up sensor for scan */ - -#define OPTICAL_FLAG_DISABLE_GAMMA 0x01 /**< disable gamma correction */ -#define OPTICAL_FLAG_DISABLE_SHADING 0x02 /**< disable shading correction */ -#define OPTICAL_FLAG_DISABLE_LAMP 0x04 /**< turn off lamp */ -#define OPTICAL_FLAG_ENABLE_LEDADD 0x08 /**< enable true CIS gray by enabling LED addition */ -#define OPTICAL_FLAG_DISABLE_DOUBLE 0x10 /**< disable automatic x-direction double data expansion */ -#define OPTICAL_FLAG_STAGGER 0x20 /**< disable stagger correction */ -#define OPTICAL_FLAG_USE_XPA 0x40 /**< use XPA lamp rather than regular one */ - -/*@} */ - -/*--------------------------------------------------------------------------*/ -/* common functions needed by low level specific functions */ -/*--------------------------------------------------------------------------*/ - -inline GenesysRegister* sanei_genesys_get_address(Genesys_Register_Set* regs, uint16_t addr) -{ - auto* ret = regs->find_reg_address(addr); - if (ret == nullptr) { - DBG(DBG_error, "%s: failed to find address for register 0x%02x, crash expected !\n", - __func__, addr); - } - return ret; -} - -inline uint8_t sanei_genesys_read_reg_from_set(Genesys_Register_Set* regs, uint16_t address) -{ - return regs->get8(address); -} - -inline void sanei_genesys_set_reg_from_set(Genesys_Register_Set* regs, uint16_t address, - uint8_t value) -{ - regs->set8(address, value); -} - -extern SANE_Status sanei_genesys_init_cmd_set (Genesys_Device * dev); - -extern SANE_Status -sanei_genesys_read_register (Genesys_Device * dev, uint16_t reg, uint8_t * val); - -extern SANE_Status -sanei_genesys_write_register (Genesys_Device * dev, uint16_t reg, uint8_t val); - -extern SANE_Status -sanei_genesys_read_hregister (Genesys_Device * dev, uint16_t reg, uint8_t * val); - -extern SANE_Status -sanei_genesys_write_hregister (Genesys_Device * dev, uint16_t reg, uint8_t val); - -extern SANE_Status -sanei_genesys_bulk_write_register(Genesys_Device * dev, - Genesys_Register_Set& regs); - -extern SANE_Status sanei_genesys_write_0x8c (Genesys_Device * dev, uint8_t index, uint8_t val); - -extern unsigned sanei_genesys_get_bulk_max_size(Genesys_Device * dev); - -extern SANE_Status sanei_genesys_bulk_read_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, - size_t len); - -extern SANE_Status sanei_genesys_bulk_write_data(Genesys_Device * dev, uint8_t addr, uint8_t* data, - size_t len); - -extern SANE_Status sanei_genesys_get_status (Genesys_Device * dev, uint8_t * status); - -extern void sanei_genesys_print_status (uint8_t val); - -extern SANE_Status -sanei_genesys_write_ahb(Genesys_Device* dev, uint32_t addr, uint32_t size, uint8_t * data); - -extern void sanei_genesys_init_structs (Genesys_Device * dev); - -const Genesys_Sensor& sanei_genesys_find_sensor_any(Genesys_Device* dev); -Genesys_Sensor& sanei_genesys_find_sensor_any_for_write(Genesys_Device* dev); -const Genesys_Sensor& sanei_genesys_find_sensor(Genesys_Device* dev, int dpi, - ScanMethod scan_method = ScanMethod::FLATBED); -Genesys_Sensor& sanei_genesys_find_sensor_for_write(Genesys_Device* dev, int dpi, - ScanMethod scan_method = ScanMethod::FLATBED); - -extern SANE_Status -sanei_genesys_init_shading_data (Genesys_Device * dev, const Genesys_Sensor& sensor, - int pixels_per_line); - -extern SANE_Status sanei_genesys_read_valid_words (Genesys_Device * dev, - unsigned int *steps); - -extern SANE_Status sanei_genesys_read_scancnt (Genesys_Device * dev, - unsigned int *steps); - -extern SANE_Status sanei_genesys_read_feed_steps (Genesys_Device * dev, - unsigned int *steps); - -void sanei_genesys_set_lamp_power(Genesys_Device* dev, const Genesys_Sensor& sensor, - Genesys_Register_Set& regs, bool set); - -void sanei_genesys_set_motor_power(Genesys_Register_Set& regs, bool set); - -extern void -sanei_genesys_calculate_zmode2 (SANE_Bool two_table, - uint32_t exposure_time, - uint16_t * slope_table, - int reg21, - int move, int reg22, uint32_t * z1, - uint32_t * z2); - -extern void -sanei_genesys_calculate_zmode (uint32_t exposure_time, - uint32_t steps_sum, - uint16_t last_speed, uint32_t feedl, - uint8_t fastfed, uint8_t scanfed, - uint8_t fwdstep, uint8_t tgtime, - uint32_t * z1, uint32_t * z2); - -extern SANE_Status -sanei_genesys_set_buffer_address (Genesys_Device * dev, uint32_t addr); - -/** @brief Reads data from frontend register. - * Reads data from the given frontend register. May be used to query - * analog frontend status by reading the right register. - */ -extern SANE_Status -sanei_genesys_fe_read_data (Genesys_Device * dev, uint8_t addr, - uint16_t *data); -/** @brief Write data to frontend register. - * Writes data to analog frontend register at the given address. - * The use and address of registers change from model to model. - */ -extern SANE_Status -sanei_genesys_fe_write_data (Genesys_Device * dev, uint8_t addr, - uint16_t data); - -extern SANE_Int -sanei_genesys_exposure_time2 (Genesys_Device * dev, - float ydpi, int step_type, int endpixel, - int led_exposure, int power_mode); - -extern SANE_Int -sanei_genesys_exposure_time (Genesys_Device * dev, Genesys_Register_Set * reg, - int xdpi); -extern SANE_Int -sanei_genesys_generate_slope_table (uint16_t * slope_table, unsigned int max_steps, - unsigned int use_steps, uint16_t stop_at, - uint16_t vstart, uint16_t vend, - unsigned int steps, double g, - unsigned int *used_steps, unsigned int *vfinal); - -extern SANE_Int -sanei_genesys_create_slope_table (Genesys_Device * dev, - uint16_t * slope_table, int steps, - int step_type, int exposure_time, - SANE_Bool same_speed, double yres, - int power_mode); - -SANE_Int -sanei_genesys_create_slope_table3 (Genesys_Device * dev, - uint16_t * slope_table, int max_step, - unsigned int use_steps, - int step_type, int exposure_time, - double yres, - unsigned int *used_steps, - unsigned int *final_exposure, - int power_mode); - -void sanei_genesys_create_default_gamma_table(Genesys_Device* dev, - std::vector& gamma_table, float gamma); - -std::vector get_gamma_table(Genesys_Device* dev, const Genesys_Sensor& sensor, - int color); - -SANE_Status sanei_genesys_send_gamma_table(Genesys_Device * dev, const Genesys_Sensor& sensor); - -extern SANE_Status sanei_genesys_start_motor (Genesys_Device * dev); - -extern SANE_Status sanei_genesys_stop_motor (Genesys_Device * dev); - -extern SANE_Status -sanei_genesys_search_reference_point(Genesys_Device * dev, Genesys_Sensor& sensor, - uint8_t * data, - int start_pixel, int dpi, int width, - int height); - -extern SANE_Status sanei_genesys_write_file(const char *filename, uint8_t* data, size_t length); - -extern SANE_Status -sanei_genesys_write_pnm_file (const char *filename, uint8_t * data, int depth, - int channels, int pixels_per_line, int lines); - -extern SANE_Status -sanei_genesys_test_buffer_empty (Genesys_Device * dev, SANE_Bool * empty); - -extern SANE_Status -sanei_genesys_read_data_from_scanner (Genesys_Device * dev, uint8_t * data, - size_t size); - -inline void sanei_genesys_set_double(Genesys_Register_Set* regs, uint16_t addr, uint16_t value) -{ - regs->set16(addr, value); -} - -inline void sanei_genesys_set_triple(Genesys_Register_Set* regs, uint16_t addr, uint32_t value) -{ - regs->set24(addr, value); -} - -inline void sanei_genesys_get_double(Genesys_Register_Set* regs, uint16_t addr, uint16_t* value) -{ - *value = regs->get16(addr); -} - -inline void sanei_genesys_get_triple(Genesys_Register_Set* regs, uint16_t addr, uint32_t* value) -{ - *value = regs->get24(addr); -} - -inline void sanei_genesys_set_exposure(Genesys_Register_Set& regs, const SensorExposure& exposure) -{ - regs.set8(0x10, (exposure.red >> 8) & 0xff); - regs.set8(0x11, exposure.red & 0xff); - regs.set8(0x12, (exposure.green >> 8) & 0xff); - regs.set8(0x13, exposure.green & 0xff); - regs.set8(0x14, (exposure.blue >> 8) & 0xff); - regs.set8(0x15, exposure.blue & 0xff); -} - -inline uint16_t sanei_genesys_fixup_exposure_value(uint16_t value) -{ - if ((value & 0xff00) == 0) { - value |= 0x100; - } - if ((value & 0x00ff) == 0) { - value |= 0x1; - } - return value; -} - -inline SensorExposure sanei_genesys_fixup_exposure(SensorExposure exposure) -{ - exposure.red = sanei_genesys_fixup_exposure_value(exposure.red); - exposure.green = sanei_genesys_fixup_exposure_value(exposure.green); - exposure.blue = sanei_genesys_fixup_exposure_value(exposure.blue); - return exposure; -} - -extern SANE_Status -sanei_genesys_wait_for_home(Genesys_Device *dev); - -extern SANE_Status -sanei_genesys_asic_init(Genesys_Device *dev, SANE_Bool cold); - -int sanei_genesys_compute_dpihw(Genesys_Device *dev, const Genesys_Sensor& sensor, int xres); - -int sanei_genesys_compute_dpihw_calibration(Genesys_Device *dev, const Genesys_Sensor& sensor, - int xres); - -extern -Motor_Profile *sanei_genesys_get_motor_profile(Motor_Profile *motors, int motor_type, int exposure); - -extern -int sanei_genesys_compute_step_type(Motor_Profile *motors, int motor_type, int exposure); - -extern -int sanei_genesys_slope_table(uint16_t *slope, int *steps, int dpi, int exposure, int base_dpi, int step_type, int factor, int motor_type, Motor_Profile *motors); - -/** @brief find lowest motor resolution for the device. - * Parses the resolution list for motor and - * returns the lowest value. - * @param dev for which to find the lowest motor resolution - * @return the lowest available motor resolution for the device - */ -extern -int sanei_genesys_get_lowest_ydpi(Genesys_Device *dev); - -/** @brief find lowest resolution for the device. - * Parses the resolution list for motor and sensor and - * returns the lowest value. - * @param dev for which to find the lowest resolution - * @return the lowest available resolution for the device - */ -extern -int sanei_genesys_get_lowest_dpi(Genesys_Device *dev); - -extern bool -sanei_genesys_is_compatible_calibration (Genesys_Device * dev, const Genesys_Sensor& sensor, - Genesys_Calibration_Cache * cache, - int for_overwrite); - -/** @brief compute maximum line distance shift - * compute maximum line distance shift for the motor and sensor - * combination. Line distance shift is the distance between different - * color component of CCD sensors. Since these components aren't at - * the same physical place, they scan diffrent lines. Software must - * take this into account to accurately mix color data. - * @param dev device session to compute max_shift for - * @param channels number of color channels for the scan - * @param yres motor resolution used for the scan - * @param flags scan flags - * @return 0 or line distance shift - */ -extern -int sanei_genesys_compute_max_shift(Genesys_Device *dev, - int channels, - int yres, - int flags); - -extern SANE_Status -sanei_genesys_load_lut (unsigned char * lut, - int in_bits, - int out_bits, - int out_min, - int out_max, - int slope, - int offset); - -extern SANE_Status -sanei_genesys_generate_gamma_buffer(Genesys_Device * dev, - const Genesys_Sensor& sensor, - int bits, - int max, - int size, - uint8_t *gamma); - -/*---------------------------------------------------------------------------*/ -/* ASIC specific functions declarations */ -/*---------------------------------------------------------------------------*/ -extern SANE_Status sanei_gl646_init_cmd_set (Genesys_Device * dev); -extern SANE_Status sanei_gl841_init_cmd_set (Genesys_Device * dev); -extern SANE_Status sanei_gl843_init_cmd_set (Genesys_Device * dev); -extern SANE_Status sanei_gl846_init_cmd_set (Genesys_Device * dev); -extern SANE_Status sanei_gl847_init_cmd_set (Genesys_Device * dev); -extern SANE_Status sanei_gl124_init_cmd_set (Genesys_Device * dev); - -// same as usleep, except that it does nothing if testing mode is enabled -extern void sanei_genesys_usleep(unsigned int useconds); - -// same as sanei_genesys_usleep just that the duration is in milliseconds -extern void sanei_genesys_sleep_ms(unsigned int milliseconds); - -void add_function_to_run_at_backend_exit(std::function function); - -// calls functions added via add_function_to_run_at_backend_exit() in reverse order of being -// added. -void run_functions_at_backend_exit(); - -template -class StaticInit { -public: - StaticInit() = default; - StaticInit(const StaticInit&) = delete; - StaticInit& operator=(const StaticInit&) = delete; - - template - void init(Args&& ... args) - { - ptr_ = std::unique_ptr(new T(std::forward(args)...)); - add_function_to_run_at_backend_exit([this](){ deinit(); }); - } - - void deinit() - { - ptr_.release(); - } - - const T* operator->() const { return ptr_.get(); } - T* operator->() { return ptr_.get(); } - const T& operator*() const { return *ptr_.get(); } - T& operator*() { return *ptr_.get(); } - -private: - std::unique_ptr ptr_; -}; - -extern StaticInit> s_sensors; -void genesys_init_sensor_tables(); -void genesys_init_frontend_tables(); - -void debug_dump(unsigned level, const Genesys_Settings& settings); -void debug_dump(unsigned level, const SetupParams& params); -void debug_dump(unsigned level, const Genesys_Current_Setup& setup); - -#endif /* not GENESYS_LOW_H */ diff --git a/backend/genesys_sanei.cc b/backend/genesys_sanei.cc deleted file mode 100644 index 5b5b40a..0000000 --- a/backend/genesys_sanei.cc +++ /dev/null @@ -1,140 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2019 Povilas Kanapickas - - 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. -*/ - -#define DEBUG_DECLARE_ONLY - -#include "genesys_sanei.h" - -UsbDevice::~UsbDevice() -{ - if (is_open()) { - DBG(DBG_error, "UsbDevice not closed; closing automatically"); - close(); - } -} - -void UsbDevice::open(const char* dev_name) -{ - DBG_HELPER(dbg); - - if (is_open()) { - throw SaneException("device already open"); - } - int device_num = 0; - - dbg.status("open device"); - TIE(sanei_usb_open(dev_name, &device_num)); - - name_ = dev_name; - device_num_ = device_num; - is_open_ = true; -} - -void UsbDevice::clear_halt() -{ - DBG_HELPER(dbg); - assert_is_open(); - TIE(sanei_usb_clear_halt(device_num_)); -} - -void UsbDevice::reset() -{ - DBG_HELPER(dbg); - assert_is_open(); - TIE(sanei_usb_reset(device_num_)); -} - -void UsbDevice::close() -{ - DBG_HELPER(dbg); - assert_is_open(); - - // we can't do much if closing fails, so we close the device on our side regardless of the - // function succeeds - int device_num = device_num_; - - set_not_open(); - sanei_usb_close(device_num); -} - -void UsbDevice::get_vendor_product(int& vendor, int& product) -{ - DBG_HELPER(dbg); - assert_is_open(); - TIE(sanei_usb_get_vendor_product(device_num_, &vendor, &product)); -} - -void UsbDevice::control_msg(int rtype, int reg, int value, int index, int length, uint8_t* data) -{ - DBG_HELPER(dbg); - assert_is_open(); - TIE(sanei_usb_control_msg(device_num_, rtype, reg, value, index, length, data)); -} - -void UsbDevice::bulk_read(uint8_t* buffer, size_t* size) -{ - DBG_HELPER(dbg); - assert_is_open(); - TIE(sanei_usb_read_bulk(device_num_, buffer, size)); -} - -void UsbDevice::bulk_write(const uint8_t* buffer, size_t* size) -{ - DBG_HELPER(dbg); - assert_is_open(); - TIE(sanei_usb_write_bulk(device_num_, buffer, size)); -} - -void UsbDevice::assert_is_open() const -{ - if (!is_open()) { - throw SaneException("device not open"); - } -} - -void UsbDevice::set_not_open() -{ - device_num_ = 0; - is_open_ = false; - name_ = ""; -} diff --git a/backend/genesys_sanei.h b/backend/genesys_sanei.h deleted file mode 100644 index 0e41600..0000000 --- a/backend/genesys_sanei.h +++ /dev/null @@ -1,97 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2019 Povilas Kanapickas - - 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. -*/ - -#ifndef BACKEND_GENESYS_SANEI_H -#define BACKEND_GENESYS_SANEI_H - -#include "genesys_error.h" -#include "../include/sane/sanei_usb.h" - -#include -#include - -class UsbDevice { -public: - UsbDevice() = default; - UsbDevice(const UsbDevice& other) = delete; - UsbDevice& operator=(const UsbDevice&) = delete; - - UsbDevice(UsbDevice&& other) : - name_(other.name_), - is_open_(other.is_open_), - device_num_(other.device_num_) - { - other.set_not_open(); - } - - ~UsbDevice(); - - bool is_open() const { return is_open_; } - - int device_number() const { return device_num_; } - - const std::string& name() const { return name_; } - - void open(const char* dev_name); - - void clear_halt(); - void reset(); - void close(); - - void get_vendor_product(int& vendor, int& product); - - void control_msg(int rtype, int reg, int value, int index, int length, uint8_t* data); - void bulk_read(uint8_t* buffer, size_t* size); - void bulk_write(const uint8_t* buffer, size_t* size); - -private: - - void assert_is_open() const; - void set_not_open(); - - std::string name_; - bool is_open_ = false; - int device_num_ = 0; -}; - -#endif // BACKEND_GENESYS_SANEI_H diff --git a/backend/genesys_serialize.cc b/backend/genesys_serialize.cc deleted file mode 100644 index e69de29..0000000 diff --git a/backend/genesys_serialize.h b/backend/genesys_serialize.h deleted file mode 100644 index 481e872..0000000 --- a/backend/genesys_serialize.h +++ /dev/null @@ -1,144 +0,0 @@ -/* sane - Scanner Access Now Easy. - - Copyright (C) 2019 Povilas Kanapickas - - 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. -*/ - -#ifndef BACKEND_GENESYS_SERIALIZE_H -#define BACKEND_GENESYS_SERIALIZE_H - -#include "genesys_error.h" -#include -#include -#include -#include -#include - -// it would be best to use something like boost.serialization - -inline void serialize_newline(std::ostream& str) { str << '\n'; } -inline void serialize_newline(std::istream& str) { (void) str; } - -inline void serialize(std::ostream& str, char x) { str << static_cast(x) << " "; } -inline void serialize(std::istream& str, char& x) { int v; str >> v; x = v; } -inline void serialize(std::ostream& str, unsigned char x) { str << static_cast(x) << " "; } -inline void serialize(std::istream& str, unsigned char& x) { unsigned v; str >> v; x = v; } -inline void serialize(std::ostream& str, signed char x) { str << static_cast(x) << " "; } -inline void serialize(std::istream& str, signed char& x) { int v; str >> v; x = v; } -inline void serialize(std::ostream& str, short x) { str << x << " "; } -inline void serialize(std::istream& str, short& x) { str >> x; } -inline void serialize(std::ostream& str, unsigned short x) { str << x << " "; } -inline void serialize(std::istream& str, unsigned short& x) { str >> x; } -inline void serialize(std::ostream& str, int x) { str << x << " "; } -inline void serialize(std::istream& str, int& x) { str >> x; } -inline void serialize(std::ostream& str, unsigned int x) { str << x << " "; } -inline void serialize(std::istream& str, unsigned int& x) { str >> x; } -inline void serialize(std::ostream& str, long x) { str << x << " "; } -inline void serialize(std::istream& str, long& x) { str >> x; } -inline void serialize(std::ostream& str, unsigned long x) { str << x << " "; } -inline void serialize(std::istream& str, unsigned long& x) { str >> x; } -inline void serialize(std::ostream& str, long long x) { str << x << " "; } -inline void serialize(std::istream& str, long long& x) { str >> x; } -inline void serialize(std::ostream& str, unsigned long long x) { str << x << " "; } -inline void serialize(std::istream& str, unsigned long long& x) { str >> x; } -inline void serialize(std::ostream& str, float x) { str << x << " "; } -inline void serialize(std::istream& str, float& x) { str >> x; } -inline void serialize(std::ostream& str, double x) { str << x << " "; } -inline void serialize(std::istream& str, double& x) { str >> x; } -inline void serialize(std::ostream& str, const std::string& x) { str << x << " "; } -inline void serialize(std::istream& str, std::string& x) { str >> x; } - -template -void serialize(std::ostream& str, std::vector& x) -{ - serialize(str, x.size()); - serialize_newline(str); - - for (auto& item : x) { - serialize(str, item); - serialize_newline(str); - } -} - -template -void serialize(std::istream& str, std::vector& x, - size_t max_size = std::numeric_limits::max()) -{ - size_t new_size; - serialize(str, new_size); - - if (new_size > max_size) { - throw SaneException("Too large std::vector to deserialize"); - } - x.reserve(new_size); - for (size_t i = 0; i < new_size; ++i) { - T item; - serialize(str, item); - x.push_back(item); - } -} - -template -void serialize(std::ostream& str, std::array& x) -{ - serialize(str, x.size()); - serialize_newline(str); - - for (auto& item : x) { - serialize(str, item); - serialize_newline(str); - } -} - -template -void serialize(std::istream& str, std::array& x) -{ - size_t new_size; - serialize(str, new_size); - - if (new_size > Size) { - throw SaneException("Incorrect std::array size to deserialize"); - } - for (auto& item : x) { - serialize(str, item); - } -} - -#endif diff --git a/backend/gt68xx.c b/backend/gt68xx.c index fb3bfb4..00190fe 100644 --- a/backend/gt68xx.c +++ b/backend/gt68xx.c @@ -752,7 +752,7 @@ init_options (GT68xx_Scanner * s) /* calibration needed */ s->opt[OPT_NEED_CALIBRATION_SW].name = "need-calibration"; - s->opt[OPT_NEED_CALIBRATION_SW].title = SANE_I18N ("Need calibration"); + s->opt[OPT_NEED_CALIBRATION_SW].title = SANE_I18N ("Needs calibration"); s->opt[OPT_NEED_CALIBRATION_SW].desc = SANE_I18N ("The scanner needs calibration for the current settings"); s->opt[OPT_NEED_CALIBRATION_SW].type = SANE_TYPE_BOOL; s->opt[OPT_NEED_CALIBRATION_SW].unit = SANE_UNIT_NONE; @@ -947,25 +947,30 @@ download_firmware_file (GT68xx_Device * dev) if (strncmp (dev->model->firmware_name, PATH_SEP, 1) != 0) { /* probably filename only */ - snprintf (filename, PATH_MAX, "%s%s%s%s%s%s%s", + snprintf (filename, sizeof(filename), "%s%s%s%s%s%s%s", STRINGIFY (PATH_SANE_DATA_DIR), PATH_SEP, "sane", PATH_SEP, "gt68xx", PATH_SEP, dev->model->firmware_name); - snprintf (dirname, PATH_MAX, "%s%s%s%s%s", + snprintf (dirname, sizeof(dirname), "%s%s%s%s%s", STRINGIFY (PATH_SANE_DATA_DIR), PATH_SEP, "sane", PATH_SEP, "gt68xx"); - strncpy (basename, dev->model->firmware_name, PATH_MAX); + strncpy (basename, dev->model->firmware_name, sizeof(basename) - 1); + basename[sizeof(basename) - 1] = '\0'; } else { /* absolute path */ char *pos; - strncpy (filename, dev->model->firmware_name, PATH_MAX); - strncpy (dirname, dev->model->firmware_name, PATH_MAX); + strncpy (filename, dev->model->firmware_name, sizeof(filename) - 1); + filename[sizeof(filename) - 1] = '\0'; + strncpy (dirname, dev->model->firmware_name, sizeof(dirname) - 1); + dirname[sizeof(dirname) - 1] = '\0'; + pos = strrchr (dirname, PATH_SEP[0]); if (pos) pos[0] = '\0'; - strncpy (basename, pos + 1, PATH_MAX); + strncpy (basename, pos + 1, sizeof(basename) - 1); + basename[sizeof(basename) - 1] = '\0'; } /* first, try to open with exact case */ @@ -994,11 +999,16 @@ download_firmware_file (GT68xx_Device * dev) { direntry = readdir (dir); if (direntry - && (strncasecmp (direntry->d_name, basename, PATH_MAX) == - 0)) + && (strncasecmp (direntry->d_name, basename, PATH_MAX) == 0)) { - snprintf (filename, PATH_MAX, "%s%s%s", - dirname, PATH_SEP, direntry->d_name); + int len = snprintf (filename, sizeof(filename), "%s%s%s", + dirname, PATH_SEP, direntry->d_name); + if ((len < 0) || (len >= (int) sizeof(filename))) + { + DBG (5, "download_firmware: filepath `%s%s%s' too long\n", + dirname, PATH_SEP, direntry->d_name); + status = SANE_STATUS_INVAL; + } break; } } diff --git a/backend/hp-option.h b/backend/hp-option.h index d1795e1..a6da585 100644 --- a/backend/hp-option.h +++ b/backend/hp-option.h @@ -118,7 +118,7 @@ # define SANE_NAME_MATRIX_TYPE "matrix-type" # define SANE_TITLE_MATRIX_TYPE SANE_I18N("Color Matrix") /* FIXME: better description */ -# define SANE_DESC_MATRIX_TYPE SANE_I18N("Set the scanners color matrix.") +# define SANE_DESC_MATRIX_TYPE SANE_I18N("Set the scanner's color matrix.") #endif #ifndef SANE_NAME_MATRIX_RGB diff --git a/backend/hp-scl.c b/backend/hp-scl.c index a7376e6..fae7f97 100644 --- a/backend/hp-scl.c +++ b/backend/hp-scl.c @@ -523,8 +523,8 @@ sanei_hp_nonscsi_new (HpScsi * newp, const char * devname, HpConnect connect) } /* For SCSI-devices we would have the inquire command here */ - strncpy ((char *)new->inq_data, "\003zzzzzzzHP ------ R000", - sizeof (new->inq_data)); + memcpy (new->inq_data, "\003zzzzzzzHP ------ R000", + sizeof (new->inq_data)); new->bufp = new->buf + HP_SCSI_CMD_LEN; new->devname = sanei_hp_alloc ( strlen ( devname ) + 1 ); diff --git a/backend/hp3900_config.c b/backend/hp3900_config.c index 830243b..dba5302 100644 --- a/backend/hp3900_config.c +++ b/backend/hp3900_config.c @@ -1049,7 +1049,7 @@ static SANE_Byte *cfg_motor_resource_get(SANE_Byte *size) if (rst != NULL) { - bzero(rst, sizeof(SANE_Byte) * 32); + memset(rst, 0, sizeof(SANE_Byte) * 32); switch(RTS_Debug->dev_model) { diff --git a/backend/hp3900_debug.c b/backend/hp3900_debug.c index b8cd8f1..7b21c8d 100644 --- a/backend/hp3900_debug.c +++ b/backend/hp3900_debug.c @@ -761,7 +761,7 @@ dbg_buffer (SANE_Int level, char *title, SANE_Byte * buffer, SANE_Int size, snprintf (sline, 80, " BF: "); else snprintf (sline, 80, " "); - bzero (&text, sizeof (text)); + memset (&text, 0, sizeof (text)); } data = _B0 (buffer[cont]); text[col] = (data > 31) ? data : '·'; @@ -776,7 +776,7 @@ dbg_buffer (SANE_Int level, char *title, SANE_Byte * buffer, SANE_Int size, start + offset - 8); sline = strcat (sline, sdata); DBG (level, "%s", sline); - bzero (sline, 81); + memset (sline, 0, 81); } } if (col > 0) @@ -791,7 +791,7 @@ dbg_buffer (SANE_Int level, char *title, SANE_Byte * buffer, SANE_Int size, start + offset - 8); sline = strcat (sline, sdata); DBG (level, "%s", sline); - bzero (sline, 81); + memset (sline, 0, 81); } free (sdata); } diff --git a/backend/hp3900_rts8822.c b/backend/hp3900_rts8822.c index bbd1e38..d76763d 100644 --- a/backend/hp3900_rts8822.c +++ b/backend/hp3900_rts8822.c @@ -63,7 +63,7 @@ #include #include -#include /* bzero() */ +#include /* memset() */ #include /* clock() */ #include /* truncf() */ #include /* tolower() */ @@ -630,12 +630,12 @@ RTS_Alloc () { SANE_Int rst = OK; - bzero (dev, sizeof (struct st_device)); + memset (dev, 0, sizeof (struct st_device)); /* initial registers */ dev->init_regs = malloc (sizeof (SANE_Byte) * RT_BUFFER_LEN); if (dev->init_regs != NULL) - bzero (dev->init_regs, sizeof (SANE_Byte) * RT_BUFFER_LEN); + memset (dev->init_regs, 0, sizeof (SANE_Byte) * RT_BUFFER_LEN); else rst = ERROR; @@ -643,7 +643,7 @@ RTS_Alloc () { dev->scanning = malloc (sizeof (struct st_scanning)); if (dev->scanning != NULL) - bzero (dev->scanning, sizeof (struct st_scanning)); + memset (dev->scanning, 0, sizeof (struct st_scanning)); else rst = ERROR; } @@ -652,7 +652,7 @@ RTS_Alloc () { dev->Reading = malloc (sizeof (struct st_readimage)); if (dev->Reading != NULL) - bzero (dev->Reading, sizeof (struct st_readimage)); + memset (dev->Reading, 0, sizeof (struct st_readimage)); else rst = ERROR; } @@ -661,7 +661,7 @@ RTS_Alloc () { dev->Resize = malloc (sizeof (struct st_resize)); if (dev->Resize != NULL) - bzero (dev->Resize, sizeof (struct st_resize)); + memset (dev->Resize, 0, sizeof (struct st_resize)); else rst = ERROR; } @@ -670,7 +670,7 @@ RTS_Alloc () { dev->status = malloc (sizeof (struct st_status)); if (dev->status != NULL) - bzero (dev->status, sizeof (struct st_status)); + memset (dev->status, 0, sizeof (struct st_status)); else rst = ERROR; } @@ -1255,7 +1255,7 @@ Load_Chipset (struct st_device *dev) { SANE_Int model; - bzero (dev->chipset, sizeof (struct st_chip)); + memset (dev->chipset, 0, sizeof (struct st_chip)); /* get chipset model of selected scanner */ model = cfg_chipset_model_get (RTS_Debug->dev_model); @@ -1611,7 +1611,7 @@ RTS_Scanner_SetParams (struct st_device *dev, struct params *param) compression = FALSE; /* resetting low level config */ - bzero (&hwdcfg, sizeof (struct st_hwdconfig)); + memset (&hwdcfg, 0, sizeof (struct st_hwdconfig)); /* setting low level config */ hwdcfg.scantype = scan.scantype; @@ -1650,7 +1650,7 @@ SetScanParams (struct st_device *dev, SANE_Byte * Regs, dbg_ScanParams (scancfg); dbg_hwdcfg (hwdcfg); - bzero (&mycoords, sizeof (struct st_coords)); + memset (&mycoords, 0, sizeof (struct st_coords)); /* Copy scancfg to scan2 */ memcpy (&scan2, scancfg, sizeof (struct st_scanparams)); @@ -3675,7 +3675,7 @@ Init_Registers (struct st_device *dev) DBG (DBG_FNC, "+ Init_Registers:\n"); /* Lee dev->init_regs */ - bzero (dev->init_regs, RT_BUFFER_LEN); + memset (dev->init_regs, 0, RT_BUFFER_LEN); RTS_ReadRegs (dev->usb_handle, dev->init_regs); Read_FE3E (dev, &v1619); @@ -4116,7 +4116,7 @@ Lamp_Status_Get (struct st_device *dev, SANE_Byte * flb_lamp, case RTS8822BL_03A: *flb_lamp = ((data2 & 0x40) != 0) ? 1 : 0; *tma_lamp = (((data2 & 0x20) != 0) - && ((data1 & 0x10) == 1)) ? 1 : 0; + && ((data1 & 0x10) != 0)) ? 1 : 0; break; default: if ((_B1 (data1) & 0x10) == 0) @@ -4825,8 +4825,8 @@ Refs_Analyze_Pattern (struct st_scanparams *scancfg, if ((scancfg->coord.width - dist) > 1) { /* clear buffers */ - bzero (color_sum, sizeof (double) * buffersize); - bzero (color_dif, sizeof (double) * buffersize); + memset (color_sum, 0, sizeof (double) * buffersize); + memset (color_dif, 0, sizeof (double) * buffersize); for (xpos = 0; xpos < scancfg->coord.width; xpos++) { @@ -4875,8 +4875,8 @@ Refs_Analyze_Pattern (struct st_scanparams *scancfg, if ((scancfg->coord.height - dist) > 1) { /* clear buffers */ - bzero (color_sum, sizeof (double) * buffersize); - bzero (color_dif, sizeof (double) * buffersize); + memset (color_sum, 0, sizeof (double) * buffersize); + memset (color_dif, 0, sizeof (double) * buffersize); for (ypos = 0; ypos < scancfg->coord.height; ypos++) { @@ -4924,8 +4924,8 @@ Refs_Analyze_Pattern (struct st_scanparams *scancfg, if ((scancfg->coord.width - dist) > 1) { /* clear buffers */ - bzero (color_sum, sizeof (double) * buffersize); - bzero (color_dif, sizeof (double) * buffersize); + memset (color_sum, 0, sizeof (double) * buffersize); + memset (color_dif, 0, sizeof (double) * buffersize); for (xpos = 0; xpos < scancfg->coord.width; xpos++) { @@ -6188,7 +6188,7 @@ Reading_DestroyBuffers (struct st_device *dev) dev->scanning->imagebuffer = NULL; } - bzero (dev->Reading, sizeof (struct st_readimage)); + memset (dev->Reading, 0, sizeof (struct st_readimage)); return OK; } @@ -6462,7 +6462,7 @@ RTS_ScanCounter_Inc (struct st_device *dev) break; default: /* value is 4 bytes size starting from address 0x21 in lsb format */ - bzero (&somebuffer, sizeof (somebuffer)); + memset (&somebuffer, 0, sizeof (somebuffer)); somebuffer[4] = 0x0c; RTS_EEPROM_ReadInteger (dev->usb_handle, 0x21, &idata); @@ -7786,7 +7786,7 @@ Scan_Read_BufferA (struct st_device *dev, SANE_Int buffer_size, SANE_Int arg2, opStatus = Reading_Wait (dev, rd->Channels_per_dot, rd->Channel_size, iAmount, - &rd->Bytes_Available, 10, sc); + &rd->Bytes_Available, 60, sc); /* If something fails, perhaps we can read some bytes... */ if (opStatus != OK) @@ -8072,7 +8072,7 @@ Scan_Start (struct st_device *dev) dbg_ScanParams (&scancfg); /* reserva buffer 6 dwords en fa84-fa9f */ - bzero (&hwdcfg, sizeof (struct st_hwdconfig)); + memset (&hwdcfg, 0, sizeof (struct st_hwdconfig)); /* wait till lamp is at home (should use timeout windows driver doesn't use it) @@ -10009,7 +10009,7 @@ Shading_apply (struct st_device *dev, SANE_Byte * Regs, } /*3d4c */ - bzero (&calbuffers, sizeof (struct st_cal2)); + memset (&calbuffers, 0, sizeof (struct st_cal2)); /* If black shading correction is enabled ... */ if ((Regs[0x1cf] & 8) != 0) @@ -10340,7 +10340,7 @@ RTS_GetImage (struct st_device *dev, SANE_Byte * Regs, (struct st_hwdconfig *) malloc (sizeof (struct st_hwdconfig)); if (hwdcfg != NULL) { - bzero (hwdcfg, sizeof (struct st_hwdconfig)); + memset (hwdcfg, 0, sizeof (struct st_hwdconfig)); if (((options & 2) != 0) || ((_B1 (options) & 1) != 0)) { @@ -10404,7 +10404,7 @@ RTS_GetImage (struct st_device *dev, SANE_Byte * Regs, sizeof (SANE_Byte)); if (myRegs != NULL) { - bzero (myRegs, + memset (myRegs, 0, RT_BUFFER_LEN * sizeof (SANE_Byte)); RTS_Setup (dev, myRegs, &scan, hwdcfg, gain_offset); @@ -10547,7 +10547,7 @@ Refs_Detect (struct st_device *dev, SANE_Byte * Regs, SANE_Int resolution_x, *x = *y = 0; /* default */ /* set configuration to scan a little area at the top-left corner */ - bzero (&scancfg, sizeof (struct st_scanparams)); + memset (&scancfg, 0, sizeof (struct st_scanparams)); scancfg.depth = 8; scancfg.colormode = CM_GRAY; scancfg.channel = CL_RED; @@ -10588,7 +10588,7 @@ Refs_Detect (struct st_device *dev, SANE_Byte * Regs, SANE_Int resolution_x, pwmlamplevel = 0; Lamp_PWM_use (dev, 1); - bzero (&gain_offset, sizeof (struct st_gain_offset)); + memset (&gain_offset, 0, sizeof (struct st_gain_offset)); for (C = CL_RED; C <= CL_BLUE; C++) { gain_offset.pag[C] = 3; @@ -11290,7 +11290,7 @@ Head_Relocate (struct st_device *dev, SANE_Int speed, SANE_Int direction, struct st_motormove mymotor; struct st_motorpos mtrpos; - bzero (&mymotor, sizeof (struct st_motormove)); + memset (&mymotor, 0, sizeof (struct st_motormove)); memcpy (Regs, dev->init_regs, RT_BUFFER_LEN * sizeof (SANE_Byte)); if (speed < dev->motormove_count) @@ -11338,7 +11338,7 @@ Calib_CreateFixedBuffers () (USHORT *) malloc (0x7f8 * sizeof (USHORT)); if (fixed_black_shading[channel] != NULL) - bzero (fixed_black_shading[channel], 0x7f8 * sizeof (USHORT)); + memset (fixed_black_shading[channel], 0, 0x7f8 * sizeof (USHORT)); else ret = ERROR; @@ -11348,7 +11348,7 @@ Calib_CreateFixedBuffers () (USHORT *) malloc (0x7f8 * sizeof (USHORT)); if (fixed_white_shading[channel] != NULL) - bzero (fixed_white_shading[channel], 0x7f8 * sizeof (USHORT)); + memset (fixed_white_shading[channel], 0, 0x7f8 * sizeof (USHORT)); else ret = ERROR; @@ -12779,7 +12779,7 @@ Calib_WhiteShading_3 (struct st_device *dev, /*a743 */ if (lf130 > 0) - bzero (buffer1, lf130 * sizeof (double)); + memset (buffer1, 0, lf130 * sizeof (double)); /*a761 */ if (lf12c > 0) @@ -12959,7 +12959,7 @@ Calib_WhiteShading_3 (struct st_device *dev, /*a743 */ if (lf130 > 0) - bzero (buffer1, lf130 * sizeof (double)); + memset (buffer1, 0, lf130 * sizeof (double)); /*a761 */ if (lf12c > 0) @@ -13325,14 +13325,14 @@ Calib_BlackShading (struct st_device *dev, if (scancfg.depth > 8) { /*8bb2 */ - bzero (&dbvalue, 6 * sizeof (double)); + memset (&dbvalue, 0, 6 * sizeof (double)); position = 0; if (bytes_per_line > 0) { do { - bzero (&buff3, 0x8000 * sizeof (SANE_Int)); + memset (&buff3, 0, 0x8000 * sizeof (SANE_Int)); sumatorio = 0; ptr = buffer + position; current_line = 0; @@ -13435,14 +13435,14 @@ Calib_BlackShading (struct st_device *dev, else { /*8eb6 */ - bzero (&dbvalue, 6 * sizeof (double)); + memset (&dbvalue, 0, 6 * sizeof (double)); position = 0; if (bytes_per_line > 0) { do { - bzero (&buff2, 256 * sizeof (SANE_Byte)); + memset (&buff2, 0, 256 * sizeof (SANE_Byte)); sumatorio = 0; /* ptr points to the next position of the first line */ ptr = buffer + position; @@ -13634,7 +13634,7 @@ Calibration (struct st_device *dev, SANE_Byte * Regs, Calib_LoadConfig (dev, &calibcfg, scan.scantype, scancfg->resolution_x, scancfg->depth); - bzero (&calibdata->gain_offset, sizeof (struct st_gain_offset)); /*[42b3654] */ + memset (&calibdata->gain_offset, 0, sizeof (struct st_gain_offset)); /*[42b3654] */ for (a = CL_RED; a <= CL_BLUE; a++) { myCalib->WRef[a] = calibcfg.WRef[a]; @@ -14110,7 +14110,7 @@ Init_Vars (void) hp_gamma = malloc (sizeof (struct st_gammatables)); if (hp_gamma != NULL) - bzero (hp_gamma, sizeof (struct st_gammatables)); + memset (hp_gamma, 0, sizeof (struct st_gammatables)); else rst = ERROR; @@ -14118,7 +14118,7 @@ Init_Vars (void) { RTS_Debug = malloc (sizeof (struct st_debug_opts)); if (RTS_Debug != NULL) - bzero (RTS_Debug, sizeof (struct st_debug_opts)); + memset (RTS_Debug, 0, sizeof (struct st_debug_opts)); else rst = ERROR; } @@ -14127,7 +14127,7 @@ Init_Vars (void) { default_gain_offset = malloc (sizeof (struct st_gain_offset)); if (default_gain_offset != NULL) - bzero (default_gain_offset, sizeof (struct st_gain_offset)); + memset (default_gain_offset, 0, sizeof (struct st_gain_offset)); else rst = ERROR; } @@ -14136,7 +14136,7 @@ Init_Vars (void) { calibdata = malloc (sizeof (struct st_calibration_data)); if (calibdata != NULL) - bzero (calibdata, sizeof (struct st_calibration_data)); + memset (calibdata, 0, sizeof (struct st_calibration_data)); else rst = ERROR; } @@ -14145,7 +14145,7 @@ Init_Vars (void) { wshading = malloc (sizeof (struct st_shading)); if (wshading != NULL) - bzero (wshading, sizeof (struct st_shading)); + memset (wshading, 0, sizeof (struct st_shading)); else rst = ERROR; } @@ -14467,7 +14467,7 @@ WShading_Calibrate (struct st_device *dev, SANE_Byte * Regs, DBG (DBG_FNC, "> WShading_Calibrate(*myCalib)\n"); - bzero (&myCalibTable, sizeof (struct st_gain_offset)); + memset (&myCalibTable, 0, sizeof (struct st_gain_offset)); for (C = CL_RED; C <= CL_BLUE; C++) { myCalibTable.pag[C] = 3; @@ -14687,7 +14687,7 @@ motor_pos (struct st_device *dev, SANE_Byte * Regs, DBG (DBG_FNC, "> Calib_test(*myCalib)\n"); - bzero (&myCalibTable, sizeof (struct st_gain_offset)); + memset (&myCalibTable, 0, sizeof (struct st_gain_offset)); calibcfg = (struct st_calibration_config *) @@ -14821,7 +14821,7 @@ Calib_BlackShading_jkd (struct st_device *dev, SANE_Byte * Regs, DBG (DBG_FNC, "> Calib_BlackShading_jkd(*myCalib)\n"); - bzero (&myCalibTable, sizeof (struct st_gain_offset)); + memset (&myCalibTable, 0, sizeof (struct st_gain_offset)); for (C = CL_RED; C <= CL_BLUE; C++) { myCalibTable.pag[C] = 3; @@ -14955,7 +14955,7 @@ Calib_test (struct st_device *dev, SANE_Byte * Regs, DBG (DBG_FNC, "> Calib_test(*myCalib)\n"); - bzero (&myCalibTable, sizeof (struct st_gain_offset)); + memset (&myCalibTable, 0, sizeof (struct st_gain_offset)); calibcfg = (struct st_calibration_config *) diff --git a/backend/hp3900_sane.c b/backend/hp3900_sane.c index 410e35e..f8ed139 100644 --- a/backend/hp3900_sane.c +++ b/backend/hp3900_sane.c @@ -1405,7 +1405,7 @@ options_init (TScanner * scanner) pDesc->title = SANE_I18N ("Scanner model"); pDesc->desc = SANE_I18N - ("Allows one to test device behaviour with other supported models"); + ("Allows one to test device behavior with other supported models"); pDesc->type = SANE_TYPE_STRING; pDesc->size = max_string_size (scanner->list_models); pDesc->constraint_type = SANE_CONSTRAINT_STRING_LIST; @@ -1419,7 +1419,7 @@ options_init (TScanner * scanner) case opt_negative: pDesc->name = "opt_negative"; pDesc->title = SANE_I18N ("Negative"); - pDesc->desc = SANE_I18N ("Image colours will be inverted"); + pDesc->desc = SANE_I18N ("Image colors will be inverted"); pDesc->type = SANE_TYPE_BOOL; pDesc->unit = SANE_UNIT_NONE; pDesc->size = sizeof (SANE_Word); @@ -1991,6 +1991,7 @@ option_get (TScanner * scanner, SANE_Int optid, void *result) /* scanner buttons */ case opt_button_0: get_button_status (scanner); + // fall through case opt_button_1: case opt_button_2: case opt_button_3: diff --git a/backend/hp3900_usb.c b/backend/hp3900_usb.c index 440c963..99623b4 100644 --- a/backend/hp3900_usb.c +++ b/backend/hp3900_usb.c @@ -459,7 +459,7 @@ show_buffer (SANE_Int level, SANE_Byte * buffer, SANE_Int size) sdata = (char *) malloc (256); if (sdata != NULL) { - bzero (sline, 256); + memset (sline, 0, 256); for (cont = 0; cont < size; cont++) { if (col == 0) @@ -480,7 +480,7 @@ show_buffer (SANE_Int level, SANE_Byte * buffer, SANE_Int size) snprintf (sdata, 255, " : %i\n", offset - 8); sline = strcat (sline, sdata); DBG (level, "%s", sline); - bzero (sline, 256); + memset (sline, 0, 256); } } if (col > 0) @@ -494,7 +494,7 @@ show_buffer (SANE_Int level, SANE_Byte * buffer, SANE_Int size) snprintf (sdata, 255, " : %i\n", offset - 8); sline = strcat (sline, sdata); DBG (level, "%s", sline); - bzero (sline, 256); + memset (sline, 0, 256); } free (sdata); } diff --git a/backend/hpsj5s.c b/backend/hpsj5s.c index 786a8d6..77fcc46 100644 --- a/backend/hpsj5s.c +++ b/backend/hpsj5s.c @@ -961,8 +961,7 @@ GetCalibration () { /*WARNING!!! Deadlock possible! */ bTest = CallFunctionWithRetVal (0xB5); } - while ((((bTest & 0x80) == 1) && ((bTest & 0x3F) <= 2)) || - (((bTest & 0x80) == 0) && ((bTest & 0x3F) >= 5))); + while ((bTest & 0x80) ? (bTest & 0x3F) <= 2 : (bTest & 0x3F) >= 5); CallFunctionWithParameter (0xCD, 0); /*Skip this line for ECP: */ @@ -1150,8 +1149,7 @@ CalibrateScanElements () usleep (1); } while ((timeout < 1000) && - ((((bTest & 0x80) == 1) && ((bTest & 0x3F) <= 2)) || - (((bTest & 0x80) == 0) && ((bTest & 0x3F) >= 5)))); + ((bTest & 0x80) ? (bTest & 0x3F) <= 2 : (bTest & 0x3F) >= 5)); /*Let's read it... */ if(timeout < 1000) @@ -1218,8 +1216,7 @@ CalibrateScanElements () usleep (1); } while ((timeout < 1000) && - ((((bTest & 0x80) == 1) && ((bTest & 0x3F) <= 2)) || - (((bTest & 0x80) == 0) && ((bTest & 0x3F) >= 5)))); + ((bTest & 0x80) ? (bTest & 0x3F) <= 2 : (bTest & 0x3F) >= 5)); /*Let's read it... */ if(timeout < 1000) diff --git a/backend/ibm.c b/backend/ibm.c index e527a04..1f26226 100644 --- a/backend/ibm.c +++ b/backend/ibm.c @@ -248,12 +248,14 @@ attach (const char *devnam, Ibm_Device ** devp) dev->sane.name = strdup (devnam); dev->sane.vendor = "IBM"; - str = malloc (sizeof(ibuf.product) + sizeof(ibuf.revision) + 1); + + size_t prod_rev_size = sizeof(ibuf.product) + sizeof(ibuf.revision) + 1; + str = malloc (prod_rev_size); if (str) { - str[0] = '\0'; - strncat (str, (char *)ibuf.product, sizeof(ibuf.product)); - strncat (str, (char *)ibuf.revision, sizeof(ibuf.revision)); + snprintf (str, prod_rev_size, "%.*s%.*s", + (int) sizeof(ibuf.product), (const char *) ibuf.product, + (int) sizeof(ibuf.revision), (const char *) ibuf.revision); } dev->sane.model = str; dev->sane.type = "flatbed scanner"; diff --git a/backend/kodakaio.c b/backend/kodakaio.c index c8cc9a7..d5c2857 100644 --- a/backend/kodakaio.c +++ b/backend/kodakaio.c @@ -3276,12 +3276,11 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) case OPT_BR_X: case OPT_BR_Y: - sval->w = *((SANE_Word *) value); - if (SANE_UNFIX(sval->w) == 0) { + if (SANE_UNFIX(*((SANE_Word *) value)) == 0) { DBG(17, "invalid br-x or br-y\n"); return SANE_STATUS_INVAL; } - /* passthru */ + // fall through case OPT_TL_X: case OPT_TL_Y: sval->w = *((SANE_Word *) value); diff --git a/backend/kvs1025_opt.c b/backend/kvs1025_opt.c index 71fbf89..628f056 100644 --- a/backend/kvs1025_opt.c +++ b/backend/kvs1025_opt.c @@ -226,7 +226,7 @@ static const int go_image_emphasis_val[] = { static SANE_String_Const go_gamma_list[] = { SANE_I18N ("normal"), SANE_I18N ("crt"), - SANE_I18N ("linier"), + SANE_I18N ("linear"), NULL }; static const int go_gamma_val[] = { diff --git a/backend/kvs20xx_opt.c b/backend/kvs20xx_opt.c index fc527f3..e4b841b 100644 --- a/backend/kvs20xx_opt.c +++ b/backend/kvs20xx_opt.c @@ -230,7 +230,7 @@ kvs20xx_init_options (struct scanner *s) o->title = SANE_I18N ("Length control mode"); o->desc = SANE_I18N - ("Length Control Mode is a mode that the scanner reads up to the shorter length of actual" + ("Length Control Mode causes the scanner to read the shorter of either the length of the actual" " paper or logical document length."); o->type = SANE_TYPE_BOOL; o->unit = SANE_UNIT_NONE; diff --git a/backend/kvs40xx.c b/backend/kvs40xx.c index 6c19e55..6416d64 100644 --- a/backend/kvs40xx.c +++ b/backend/kvs40xx.c @@ -524,9 +524,10 @@ static SANE_Status read_image_simplex(SANE_Handle handle) return st; } -static SANE_Status read_data(struct scanner *s) +static void * read_data (void *arg) { - SANE_Status st; + struct scanner *s = (struct scanner *) arg; + SANE_Status st; int duplex = s->val[DUPLEX].w; s->read = 0; s->side = SIDE_FRONT; @@ -549,7 +550,7 @@ static SANE_Status read_data(struct scanner *s) return SANE_STATUS_GOOD; err: s->scanning = 0; - return st; + return (void *) st; } /* Start scanning */ @@ -640,7 +641,7 @@ sane_start (SANE_Handle handle) goto err; } - if (pthread_create (&s->thread, NULL, (void *(*)(void *)) read_data, s)) + if (pthread_create (&s->thread, NULL, read_data, s)) { st = SANE_STATUS_IO_ERROR; goto err; diff --git a/backend/kvs40xx_opt.c b/backend/kvs40xx_opt.c index 2bf9a5c..c812f2c 100644 --- a/backend/kvs40xx_opt.c +++ b/backend/kvs40xx_opt.c @@ -228,8 +228,8 @@ static SANE_String_Const lamp_list[] = { }; static SANE_String_Const dfeed_sence_list[] = { SANE_I18N ("Normal"), - SANE_I18N ("High sensivity"), - SANE_I18N ("Low sensivity"), + SANE_I18N ("High sensitivity"), + SANE_I18N ("Low sensitivity"), NULL }; @@ -393,8 +393,8 @@ kvs40xx_init_options (struct scanner *s) o->title = SANE_I18N ("Length control mode"); o->desc = SANE_I18N - ("Length Control Mode is a mode that the scanner reads up to the shorter length of actual" - " paper or logical document length."); + ("Length Control Mode causes the scanner to read the shorter of either the length of the actual" + " paper or logical document length"); o->type = SANE_TYPE_BOOL; o->unit = SANE_UNIT_NONE; s->val[LENGTHCTL].w = SANE_FALSE; @@ -715,7 +715,7 @@ kvs40xx_init_options (struct scanner *s) o->title = SANE_I18N ("JPEG compression"); o->desc = SANE_I18N - ("JPEG compression (yours application must be able to uncompress)"); + ("JPEG compression (your application must be able to uncompress)"); o->type = SANE_TYPE_BOOL; o->unit = SANE_UNIT_NONE; @@ -805,8 +805,8 @@ kvs40xx_init_options (struct scanner *s) o = &s->opt[STOP_SKEW]; o->name = "stop-skew"; - o->title = SANE_I18N ("Stop scanner when a paper have been skewed"); - o->desc = SANE_I18N ("Scanner will be stop when a paper have been skewed"); + o->title = SANE_I18N ("Stop scanner if a sheet is skewed"); + o->desc = SANE_I18N ("Scanner will stop if a sheet is skewed"); o->type = SANE_TYPE_BOOL; o->unit = SANE_UNIT_NONE; s->val[STOP_SKEW].w = SANE_FALSE; @@ -814,7 +814,7 @@ kvs40xx_init_options (struct scanner *s) o = &s->opt[CROP]; o->name = "crop"; o->title = SANE_I18N ("Crop actual image area"); - o->desc = SANE_I18N ("Scanner automatically detect image area and crop it"); + o->desc = SANE_I18N ("Scanner will automatically detect image area and crop to it"); o->type = SANE_TYPE_BOOL; o->unit = SANE_UNIT_NONE; s->val[CROP].w = SANE_FALSE; @@ -824,7 +824,7 @@ kvs40xx_init_options (struct scanner *s) o = &s->opt[MIRROR]; o->name = "mirror"; o->title = SANE_I18N ("Mirror image"); - o->desc = SANE_I18N ("It is right and left reversing"); + o->desc = SANE_I18N ("Left/right mirror image"); o->type = SANE_TYPE_BOOL; o->unit = SANE_UNIT_NONE; s->val[MIRROR].w = SANE_FALSE; diff --git a/backend/magicolor.c b/backend/magicolor.c index 3b27a85..af9fb1a 100644 --- a/backend/magicolor.c +++ b/backend/magicolor.c @@ -2789,12 +2789,11 @@ setvalue(SANE_Handle handle, SANE_Int option, void *value, SANE_Int *info) case OPT_BR_X: case OPT_BR_Y: - sval->w = *((SANE_Word *) value); - if (SANE_UNFIX(sval->w) == 0) { + if (SANE_UNFIX(*((SANE_Word *) value)) == 0) { DBG(17, "invalid br-x or br-y\n"); return SANE_STATUS_INVAL; } - /* passthru */ + // fall through case OPT_TL_X: case OPT_TL_Y: sval->w = *((SANE_Word *) value); diff --git a/backend/microtek.c b/backend/microtek.c index 05f8003..c3b87ec 100644 --- a/backend/microtek.c +++ b/backend/microtek.c @@ -3444,6 +3444,7 @@ sane_control_option (SANE_Handle handle, case OPT_RESOLUTION: if (info) *info |= SANE_INFO_RELOAD_PARAMS; + // fall through case OPT_SPEED: case OPT_PREVIEW: case OPT_BACKTRACK: diff --git a/backend/mustek_pp.c b/backend/mustek_pp.c index 912c3bd..bb97f86 100644 --- a/backend/mustek_pp.c +++ b/backend/mustek_pp.c @@ -160,8 +160,6 @@ free_cfg_options(int *numoptions, Mustek_pp_config_option** options) /* do_eof: * closes the pipeline * - * ChangeLog: - * * Description: * closes the pipe (read-only end) */ @@ -180,8 +178,6 @@ do_eof (Mustek_pp_Handle *hndl) /* do_stop: * ends the reader_process and stops the scanner * - * ChangeLog: - * * Description: * kills the reader process with a SIGTERM and cancels the scanner */ @@ -218,8 +214,6 @@ do_stop(Mustek_pp_Handle *hndl) /* sigterm_handler: * cancel scanner when receiving a SIGTERM * - * ChangeLog: - * * Description: * just exit... reader_process takes care that nothing bad will happen * @@ -247,8 +241,6 @@ sigterm_handler (int signal __UNUSED__) /* reader_process: * receives data from the scanner and stuff it into the pipeline * - * ChangeLog: - * * Description: * The signal handle for SIGTERM is initialized. * @@ -318,8 +310,6 @@ reader_process (Mustek_pp_Handle * hndl, int pipe) /* sane_attach: * adds a new entry to the Mustek_pp_Device *devlist list * - * ChangeLog: - * * Description: * After memory for a new device entry is allocated, the * parameters for the device are determined by a call to @@ -382,8 +372,6 @@ sane_attach (SANE_String_Const port, SANE_String_Const name, SANE_Int driver, SA /* init_options: * Sets up the option descriptors for a device * - * ChangeLog: - * * Description: */ static void @@ -626,8 +614,6 @@ init_options(Mustek_pp_Handle *hndl) * Attempts to attach a device to the list after parsing of a section * of the configuration file. * - * ChangeLog: - * * Description: * After parsing a scanner section of the config file, this function * is called to look for a driver with a matching name. When found, @@ -691,8 +677,6 @@ attach_device(SANE_String *driver, SANE_String *name, /* sane_init: * Reads configuration file and registers hardware driver * - * ChangeLog: - * * Description: * in *version_code the SANE version this backend was compiled with and the * version of the backend is returned. The value of authorize is stored in @@ -1001,8 +985,6 @@ sane_init (SANE_Int * version_code, SANE_Auth_Callback authorize) /* sane_exit: * Unloads all drivers and frees allocated memory * - * ChangeLog: - * * Description: * All open devices are closed first. Then all registered devices * are removed. @@ -1051,8 +1033,6 @@ sane_exit (void) /* sane_get_devices: * Returns a list of registered devices * - * ChangeLog: - * * Description: * A possible present old device_list is removed first. A new * devarray is allocated and filled with pointers to the @@ -1093,8 +1073,6 @@ sane_get_devices (const SANE_Device *** device_list, /* sane_open: * opens a device and prepares it for operation * - * ChangeLog: - * * Description: * The device identified by ``devicename'' is looked * up in the list, or if devicename is zero, the @@ -1201,8 +1179,6 @@ sane_open (SANE_String_Const devicename, SANE_Handle * handle) /* sane_close: * closes a given device and frees all resources * - * ChangeLog: - * * Description: * The handle is searched in the list of active handles. * If it's found, the handle is removed. @@ -1261,8 +1237,6 @@ sane_close (SANE_Handle handle) /* sane_get_option_descriptor: * does what it says * - * ChangeLog: - * * Description: * */ @@ -1285,8 +1259,6 @@ sane_get_option_descriptor (SANE_Handle handle, SANE_Int option) /* sane_control_option: * Reads or writes an option * - * ChangeLog: - * * Desription: * If a pointer to info is given, the value is initialized to zero * while scanning options cannot be read or written. next a basic @@ -1523,8 +1495,6 @@ sane_control_option (SANE_Handle handle, SANE_Int option, /* sane_get_parameters: * returns the set of parameters, that is used for the next scan * - * ChangeLog: - * * Description: * * First of all it is impossible to change the parameter set @@ -1716,8 +1686,6 @@ sane_get_parameters (SANE_Handle handle, SANE_Parameters * params) /* sane_start: * starts the scan. data aquisition will start immedially * - * ChangeLog: - * * Description: * */ @@ -1775,8 +1743,6 @@ sane_start (SANE_Handle handle) /* sane_read: * receives data from pipeline and passes it to the caller * - * ChangeLog: - * * Description: * ditto */ @@ -1877,8 +1843,6 @@ sane_read (SANE_Handle handle, SANE_Byte * buf, SANE_Int max_len, /* sane_cancel: * stops a scan and ends the reader process * - * ChangeLog: - * * Description: * */ @@ -1900,8 +1864,6 @@ sane_cancel (SANE_Handle handle) /* sane_set_io_mode: * toggles between blocking and non-blocking reading * - * ChangeLog: - * * Description: * */ @@ -1930,8 +1892,6 @@ sane_set_io_mode (SANE_Handle handle, SANE_Bool non_blocking) /* sane_get_select_fd: * returns the pipeline fd for direct reading * - * ChangeLog: - * * Description: * to allow the frontend to receive the data directly it * can read from the pipeline itself diff --git a/backend/mustek_usb2_transparent.c b/backend/mustek_usb2_transparent.c index 33adcc0..74f7b52 100644 --- a/backend/mustek_usb2_transparent.c +++ b/backend/mustek_usb2_transparent.c @@ -1382,7 +1382,7 @@ Transparent_LineCalibration16Bits (unsigned short wTAShadingMinus) memset (lpBuf, 0, 50); stream = fopen ("/root/darkshading(Tra).pnm", "wb+\n"); - sprintf (lpBuf, "P6\n%d %d\n65535\n", wCalWidth * wCalHeight); + sprintf (lpBuf, "P6\n%d %d\n65535\n", wCalWidth, wCalHeight); fwrite (lpBuf, sizeof (SANE_Byte), strlen (lpBuf), stream); fwrite (lpDarkData, sizeof (SANE_Byte), wCalWidth * wCalHeight * 3 * 2, stream); fclose (stream); diff --git a/backend/nec.c b/backend/nec.c index f12e997..d123be0 100644 --- a/backend/nec.c +++ b/backend/nec.c @@ -349,6 +349,9 @@ sense_handler(int fd, u_char *sense_buffer, void *ss) DBG(5, "Scanner not ready: undocumented reason\n"); return SANE_STATUS_IO_ERROR; } + default: + DBG(5, "Scanner not ready: unknown sense code\n"); + return SANE_STATUS_IO_ERROR; } case 0x03: /* medium error */ DBG(5, "medium error: undocumented reason\n"); @@ -2306,6 +2309,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_BR_Y: if (info && s->val[option].w != *(SANE_Word *) val) *info |= SANE_INFO_RELOAD_PARAMS; + // fall through case OPT_NUM_OPTS: case OPT_THRESHOLD: /* xxx theoretically, we could use OPT_THRESHOLD in diff --git a/backend/niash.c b/backend/niash.c index bbc90d3..b62bdba 100644 --- a/backend/niash.c +++ b/backend/niash.c @@ -768,6 +768,7 @@ _InitOptions (TScanner * s) SANE_CAP_SOFT_SELECT | SANE_CAP_SOFT_DETECT | SANE_CAP_INACTIVE | SANE_CAP_EMULATED; pVal->w = 50; + break; default: DBG (DBG_ERR, "Uninitialised option %d\n", i); diff --git a/backend/pieusb_buffer.h b/backend/pieusb_buffer.h index 3724a40..282595a 100644 --- a/backend/pieusb_buffer.h +++ b/backend/pieusb_buffer.h @@ -48,6 +48,10 @@ #include "pieusb.h" #include "../include/sane/sanei_ir.h" +#ifndef L_tmpnam +#define L_tmpnam 20 +#endif + struct Pieusb_Read_Buffer { SANE_Uint* data; /* image data - always store as 16 bit values; mmap'ed */ diff --git a/backend/pieusb_specific.c b/backend/pieusb_specific.c index ce107cf..1b5f0f4 100644 --- a/backend/pieusb_specific.c +++ b/backend/pieusb_specific.c @@ -322,7 +322,7 @@ pieusb_initialize_device_definition (Pieusb_Device_Definition* dev, Pieusb_Scann buf = malloc(9); if (buf == NULL) return SANE_STATUS_NO_MEM; - strncpy(buf, inq->vendor, 8); + memcpy(buf, inq->vendor, 8); pp = buf + 8; *pp-- = '\0'; while (*pp == ' ') *pp-- = '\0'; @@ -332,7 +332,7 @@ pieusb_initialize_device_definition (Pieusb_Device_Definition* dev, Pieusb_Scann buf = malloc(17); if (buf == NULL) return SANE_STATUS_NO_MEM; - strncpy(buf, inq->product, 16); + memcpy(buf, inq->product, 16); pp = buf + 16; *pp-- = '\0'; while (*pp == ' ') *pp-- = '\0'; @@ -346,7 +346,7 @@ pieusb_initialize_device_definition (Pieusb_Device_Definition* dev, Pieusb_Scann buf = malloc(5); if (buf == NULL) return SANE_STATUS_NO_MEM; - strncpy(buf, inq->productRevision, 4); + memcpy(buf, inq->productRevision, 4); pp = buf + 4; *pp-- = '\0'; while (*pp == ' ') *pp-- = '\0'; 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" diff --git a/backend/pixma.conf.in b/backend/pixma.conf.in index 3f5c61a..d6184b4 100644 --- a/backend/pixma.conf.in +++ b/backend/pixma.conf.in @@ -1,5 +1,10 @@ # pixma.conf configuration for the sane pixma backend # +# disable network scanner detection. +# This must be the first not commented line +# Uncomment the following line: +# networking=no +# # bjnp-timeout=5000 # Specify the timeout (in ms) to be used for all the folllowing # scanners. @@ -16,10 +21,12 @@ # port number can normally be left out, port 8612 is used as default # The timeout parameter sets a timeout value for the scanner on # the same line -# Example: +# Examples using bjnp: # bjnp://myscanner.my.domain:8612 // uses the default 1000ms timeout # bjnp-timeout=5000 # bjnp://printer-1.pheasant.org // will use the 5000 ms timeout # bjnp://scanner.bad-network.org/timeout=1500 // timeout set to 1500 ms # bjnp-timeout=3000 // will be used for auto-detected scanners # +# Example using for a scanner using mfnp including the optional timeout: +# mfnp://scanner.bad-network.org/timeout=1500 diff --git a/backend/pixma.h b/backend/pixma.h deleted file mode 100644 index 370203a..0000000 --- a/backend/pixma.h +++ /dev/null @@ -1,502 +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. - */ -#ifndef PIXMA_H -#define PIXMA_H - -/*! - * \mainpage Scanner driver for Canon PIXMA MP series - * \section example Sample code for application - * \code - * pixma_set_debug_level(level); - * pixma_init(); - * nscanners = pixma_find_scanners(); - * devnr = choose_scanner(nscanners); - * scanner = pixma_open(devnr); - * setup_param(param); - * pixma_check_scan_param(scanner, param); - * do { - * if (I_need_events && - * (ev = pixma_wait_event(scanner, timeout)) > 0) { - * handle_event(ev); - * } - * pixma_scan(scanner, param); - * while ((count = pixma_read_image(scanner, buf, len)) > 0) { - * write(buf, count); - * if (error_occured_in_write) { - * pixma_cancel(scanner); - * } - * } - * } while (!enough); - * pixma_close(scanner); - * pixma_cleanup(); - * \endcode - * - * Note: pixma_cancel() can be called asynchronously to - * interrupt pixma_read_image(). It does not cancel the operation - * immediately. pixma_read_image() must be called until it - * returns zero or an error (probably \c PIXMA_ECANCELED). - * - * \section reference Reference - * - \subpage API - * - \subpage IO - * - \subpage subdriver - * - \subpage debug - */ - -/*! - * \defgroup API The driver API - * \brief The driver API. - * - * The return value of functions that returns \c int has the following - * meaning if not otherwise specified: - * - >= 0 if succeeded - * - < 0 if failed - */ - -#ifdef HAVE_STDINT_H -# include /* available in ISO C99 */ -#else -# include -typedef uint8_t uint8_t; -typedef uint16_t uint16_t; -typedef uint32_t uint32_t; -#endif /* HAVE_STDINT_H */ - -#ifdef HAVE_INTTYPES_H -# include /* available in ISO C99 */ -#endif /* HAVE_INTTYPES_H */ - -/** \addtogroup API - * @{ */ -/** Don't forget to update the backend version in the SANE Backend specification - * file: doc/descriptions/pixma.desc !!! - */ -/** \name Version of the driver */ -/**@{*/ -#define PIXMA_VERSION_MAJOR 0 -#define PIXMA_VERSION_MINOR 23 -#define PIXMA_VERSION_BUILD 0 -/**@}*/ - -/** \name Error codes */ -/**@{*/ -#define PIXMA_EIO -1 -#define PIXMA_ENODEV -2 -#define PIXMA_EACCES -3 -#define PIXMA_ENOMEM -4 -#define PIXMA_EINVAL -5 -#define PIXMA_EBUSY -6 -#define PIXMA_ECANCELED -7 -#define PIXMA_ENOTSUP -8 -#define PIXMA_ETIMEDOUT -9 -#define PIXMA_EPROTO -10 -#define PIXMA_EPAPER_JAMMED -11 -#define PIXMA_ECOVER_OPEN -12 -#define PIXMA_ENO_PAPER -13 -#define PIXMA_EOF -14 -/**@}*/ - -/** \name Capabilities for using with pixma_config_t::cap */ -/**@{*/ -#define PIXMA_CAP_EASY_RGB (1 << 0) -#define PIXMA_CAP_GRAY (1 << 1) -#define PIXMA_CAP_ADF (1 << 2) -#define PIXMA_CAP_48BIT (1 << 3) -#define PIXMA_CAP_GAMMA_TABLE (1 << 4) -#define PIXMA_CAP_EVENTS (1 << 5) -#define PIXMA_CAP_TPU (1 << 6) -#define PIXMA_CAP_ADFDUP ((1 << 7) | PIXMA_CAP_ADF) -#define PIXMA_CAP_CIS (0) -#define PIXMA_CAP_CCD (1 << 8) -#define PIXMA_CAP_LINEART (1 << 9) -#define PIXMA_CAP_NEGATIVE (1 << 10) -#define PIXMA_CAP_TPUIR ((1 << 11) | PIXMA_CAP_TPU) -#define PIXMA_CAP_ADF_WAIT (1 << 12) -#define PIXMA_CAP_ADF_JPEG (1 << 13) -#define PIXMA_CAP_EXPERIMENT (1 << 31) -/**@}*/ - -/** \name Button events and related information returned by pixma_wait_event() */ -/**@{*/ -#define PIXMA_EV_NONE 0 -#define PIXMA_EV_ACTION_MASK (0xffffff) -#define PIXMA_EV_BUTTON1 (1 << 24) -#define PIXMA_EV_BUTTON2 (2 << 24) -#define PIXMA_EV_TARGET_MASK (0xff) -#define PIXMA_EV_ORIGINAL_MASK (0xff00) -#define PIXMA_EV_DPI_MASK (0xff0000) - -#define GET_EV_TARGET(x) (x & PIXMA_EV_TARGET_MASK) -#define GET_EV_ORIGINAL(x) ( (x & PIXMA_EV_ORIGINAL_MASK) >> 8 ) -#define GET_EV_DPI(x) ( (x & PIXMA_EV_DPI_MASK) >> 16 ) - -/**@}*/ -/** @} end of API group */ - -#define PIXMA_CONFIG_FILE "pixma.conf" -#define MAX_CONF_DEVICES 15 - -struct pixma_t; -struct pixma_scan_ops_t; -struct pixma_scan_param_t; -struct pixma_config_t; -struct pixma_cmdbuf_t; -struct pixma_imagebuf_t; -struct pixma_device_status_t; - -typedef struct pixma_t pixma_t; -typedef struct pixma_scan_ops_t pixma_scan_ops_t; -typedef struct pixma_scan_param_t pixma_scan_param_t; -typedef struct pixma_config_t pixma_config_t; -typedef struct pixma_cmdbuf_t pixma_cmdbuf_t; -typedef struct pixma_imagebuf_t pixma_imagebuf_t; -typedef struct pixma_device_status_t pixma_device_status_t; - - -/** \addtogroup API - * @{ */ -/** String index constants */ -typedef enum pixma_string_index_t -{ - PIXMA_STRING_MODEL, - PIXMA_STRING_ID, - PIXMA_STRING_LAST -} pixma_string_index_t; - -/** Paper sources */ -typedef enum pixma_paper_source_t -{ - PIXMA_SOURCE_FLATBED, - PIXMA_SOURCE_ADF, - PIXMA_SOURCE_TPU, - PIXMA_SOURCE_ADFDUP /* duplex */ -} pixma_paper_source_t; - -/** Scan modes */ -typedef enum pixma_scan_mode_t -{ - /* standard scan modes */ - PIXMA_SCAN_MODE_COLOR, - PIXMA_SCAN_MODE_GRAY, - /* TPU scan modes for negatives */ - PIXMA_SCAN_MODE_NEGATIVE_COLOR, - PIXMA_SCAN_MODE_NEGATIVE_GRAY, - /* extended scan modes for 48 bit flatbed scanners */ - PIXMA_SCAN_MODE_COLOR_48, - PIXMA_SCAN_MODE_GRAY_16, - /* 1 bit lineart scan mode */ - PIXMA_SCAN_MODE_LINEART, - /* TPUIR scan mode */ - PIXMA_SCAN_MODE_TPUIR -} pixma_scan_mode_t; - -typedef enum pixma_hardware_status_t -{ - PIXMA_HARDWARE_OK, - PIXMA_HARDWARE_ERROR -} pixma_hardware_status_t; - -typedef enum pixma_lamp_status_t -{ - PIXMA_LAMP_OK, - PIXMA_LAMP_WARMING_UP, - PIXMA_LAMP_OFF, - PIXMA_LAMP_ERROR -} pixma_lamp_status_t; - -typedef enum pixma_adf_status_t -{ - PIXMA_ADF_OK, - PIXMA_ADF_NO_PAPER, - PIXMA_ADF_JAMMED, - PIXMA_ADF_COVER_OPEN, - PIXMA_ADF_ERROR -} pixma_adf_status_t; - -typedef enum pixma_calibration_status_t -{ - PIXMA_CALIBRATION_OK, - PIXMA_CALIBRATION_IN_PROGRESS, - PIXMA_CALIBRATION_OFF, - PIXMA_CALIBRATION_ERROR -} pixma_calibration_status_t; - -/** Device status. */ -struct pixma_device_status_t -{ - pixma_hardware_status_t hardware; - pixma_lamp_status_t lamp; - pixma_adf_status_t adf; - pixma_calibration_status_t cal; -}; - -/** Scan parameters. */ -struct pixma_scan_param_t -{ - /** Size in bytes of one image line (row). - * line_size >= depth / 8 * channels * w
- * This field will be set by pixma_check_scan_param(). */ - uint64_t line_size; - - /** Size in bytes of the whole image. - * image_size = line_size * h
- * This field will be set by pixma_check_scan_param(). */ - uint64_t image_size; - - /** Channels per pixel. 1 = grayscale and lineart, 3 = color */ - unsigned channels; - - /** Bits per channels. - * 1 = 1 bit B/W lineart (flatbed) - * 8 = 8 bit grayscale, - * 24 bit color (both flatbed) - * 16 = 16 bit grayscale (TPU, flatbed not implemeted), - * 48 bit color (TPU, flatbed not implemented) */ - unsigned depth; - - /*@{ */ - /** Resolution. Valid values are 75,150,300,600,1200... */ - unsigned xdpi, ydpi; - /*@} */ - - /*! \name Scan area in pixels - * (0,0) = top left; positive x extends to the right; positive y to the - * bottom; in pixels. - * xs is the offset in x direction of the selected scan range relative - * to the range read from the scanner and wx the width in x direction - * of the scan line read from scanner. */ - /*@{ */ - unsigned x, y, w, h, xs, wx; - /*@} */ - - /** Flag indicating whether the offset correction for TPU scans - * was already performed (to avoid repeated corrections). - * Currently only used in pixma_mp810.c sub-driver */ - unsigned tpu_offset_added; - - /* Flag indicating if data from scanner will be in JPEG format */ - unsigned mode_jpeg; - - /** Flag indicating whether a software-lineart scan is in progress - * 0 = other scan - * 1 = software-lineart scan */ - unsigned software_lineart; - - /** Threshold for software-lineart scans */ - unsigned threshold; - - /** lineart threshold curve for dynamic rasterization */ - unsigned threshold_curve; - - /* look up table used in dynamic rasterization */ - unsigned char lineart_lut[256]; - - /** Gamma table. 4096 entries, 12 bit => 8 bit. If \c NULL, default gamma - * specified by subdriver will be used. */ - const uint8_t *gamma_table; - - /** \see #pixma_paper_source_t */ - pixma_paper_source_t source; - - /** \see #pixma_scan_mode_t */ - pixma_scan_mode_t mode; - - /** The current page # in the same ADF scan session, 0 in non ADF */ - unsigned adf_pageid; - - /** adf-wait */ - unsigned adf_wait; - unsigned frontend_cancel; -}; - -/** PIXMA model information */ -struct pixma_config_t -{ - /* If you change this structure, don't forget to update the device list in - * subdrivers. */ - const char *name; /**< Model name. */ - const char *model; /**< Short model */ - uint16_t vid; /**< USB Vendor ID */ - uint16_t pid; /**< USB Product ID */ - unsigned iface; /**< USB Interface number */ - const pixma_scan_ops_t *ops; /**< Subdriver ops */ - unsigned xdpi; /**< Maximum horizontal resolution[DPI] */ - unsigned ydpi; /**< Maximum vertical resolution[DPI] */ - unsigned adftpu_min_dpi; /**< Maximum horizontal resolution[DPI] for adf/tpu - * only needed if ADF/TPU has another min. dpi value than 75 dpi */ - unsigned adftpu_max_dpi; /**< Maximum vertical resolution[DPI] for adf/tpu - * only needed if ADF/TPU has another max. dpi value than xdpi */ - unsigned tpuir_min_dpi; /**< Minimum resolution[DPI] for tpu-ir - * only needed if TPU-IR has another min. dpi value than 75 dpi */ - unsigned tpuir_max_dpi; /**< Maximum resolution[DPI] for tpu-ir - * only needed if TPU-IR has another max. dpi value than xdpi */ - unsigned width; /**< Maximum width of scannable area in pixels at 75DPI */ - unsigned height; /**< Maximum height of scannable area in pixels at 75DPI */ - unsigned cap; /**< Capability bitfield \see PIXMA_CAP_* */ -}; - - -/* Defined in pixma_common.c */ - -/** Initialize the driver. It must be called before any other functions - * except pixma_set_debug_level(). */ -int pixma_init (void); - -/** Free resources allocated by the driver. */ -void pixma_cleanup (void); - -/** Set the debug level. - * \param[in] level the debug level - * - 0 No debug output at all - * - 1 Only errors and warning - * - 2 General information - * - 3 Debugging messages - * - 10 USB traffic dump */ -void pixma_set_debug_level (int level); - -/** Find scanners. The device number used in pixma_open(), - * pixma_get_device_model(), pixma_get_device_id() and - * pixma_get_device_config() must be less than the value returned by the last - * call of this function. - * - * \return The number of scanners found currently. The return value is - * guaranteed to be valid until the next call to pixma_find_scanners(). */ -int pixma_find_scanners (const char **conf_devices); - -/** Return the model name of the device \a devnr. */ -const char *pixma_get_device_model (unsigned devnr); - -/** Return the unique ID of the device \a devnr. */ -const char *pixma_get_device_id (unsigned devnr); - -/** Return the device configuration of the device \a devnr. */ -const struct pixma_config_t *pixma_get_device_config (unsigned devnr); - -/** Open a connection to the scanner \a devnr. - * \param[in] devnr The scanner number - * \param[out] handle The device handle - * \see pixma_find_scanners() */ -int pixma_open (unsigned devnr, pixma_t ** handle); - -/** Close the connection to the scanner. The scanning process is aborted - * if necessary before the function returns. */ -void pixma_close (pixma_t * s); - -/** Initiate an image acquisition process. You must keep \a sp valid until the - * image acquisition process has finished. */ -int pixma_scan (pixma_t *, pixma_scan_param_t * sp); - -/** Read a block of image data. It blocks until there is at least one byte - * available or an error occurs. - * - * \param[out] buf Pointer to the buffer - * \param[in] len Size of the buffer - * - * \retval count Number of bytes written to the buffer or error. Possible - * return value: - * - count = 0 for end of image - * - count = \a len - * - 0 < count < \a len if and only if it is the last block. - * - count < 0 for error */ -int pixma_read_image (pixma_t *, void *buf, unsigned len); - -#if 0 -/** Read a block of image data and write to \a fd. - * \param[in] fd output file descriptor - * \see pixma_read_image() */ -int pixma_read_image_write (pixma_t *, int fd); -#endif - -/** Cancel the scanning process. No effect if no scanning process is in - * progress. It can be called asynchronously e.g. within a signal - * handle. pixma_cancel() doesn't abort the operation immediately. It - * guarantees that the current call or, at the latest, the next call to - * pixma_read_image() will return zero or an error (probably PIXMA_ECANCELED). */ -void pixma_cancel (pixma_t *); - -/** Check the scan parameters. This function can change your parameters to - * match the device capability, e.g. adjust width and height to the available - * area. - * \return PIXMA_EINVAL for invalid parameters. */ -int pixma_check_scan_param (pixma_t *, pixma_scan_param_t *); - -/** Wait until a scanner button is pressed or it times out. It should not be - * called during image acquisition is in progress. - * \param[in] timeout in milliseconds, less than 0 means forever - * \return - * - \c PIXMA_EV_NONE if it timed out. - * - non-zero value indicates which button was pressed. - * \see PIXMA_EV_* - */ -uint32_t pixma_wait_event (pixma_t *, int timeout); - -/** Activate connection to scanner */ -int pixma_activate_connection (pixma_t *); - -/** De-activate connection to scanner */ - -int pixma_deactivate_connection (pixma_t *); - - -/** Enable or disable background tasks. Currently, the only one task - * is submitting interrupt URB in background. - * \param[in] enabled if not zero, enable background task. - * \see pixma_set_interrupt_mode() */ -int pixma_enable_background (pixma_t *, int enabled); - -/** Read the current device status. - * \param[out] status the current device status - * \return 0 if succeeded. Otherwise, failed. - */ -int pixma_get_device_status (pixma_t *, pixma_device_status_t * status); - -const char *pixma_get_string (pixma_t *, pixma_string_index_t); -const pixma_config_t *pixma_get_config (pixma_t *); -void pixma_fill_gamma_table (double gamma, uint8_t * table, unsigned n); -const char *pixma_strerror (int error); - -/** @} end of API group */ - -#endif diff --git a/backend/pixma/pixma.c b/backend/pixma/pixma.c new file mode 100644 index 0000000..f763496 --- /dev/null +++ b/backend/pixma/pixma.c @@ -0,0 +1,2166 @@ +/* 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 (SANE_Bool local_only) +{ + unsigned i, nscanners; + + cleanup_device_list (); + nscanners = pixma_find_scanners (conf_devices, local_only); + 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) +{ + if (!device_list) + return SANE_STATUS_INVAL; + find_scanners (local_only); + *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, SANE_FALSE); + 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" diff --git a/backend/pixma/pixma.h b/backend/pixma/pixma.h new file mode 100644 index 0000000..c2df3cc --- /dev/null +++ b/backend/pixma/pixma.h @@ -0,0 +1,506 @@ +/* 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. + */ +#ifndef PIXMA_H +#define PIXMA_H + +#include "../include/sane/sane.h" + + +/*! + * \mainpage Scanner driver for Canon PIXMA MP series + * \section example Sample code for application + * \code + * pixma_set_debug_level(level); + * pixma_init(); + * nscanners = pixma_find_scanners(); + * devnr = choose_scanner(nscanners); + * scanner = pixma_open(devnr); + * setup_param(param); + * pixma_check_scan_param(scanner, param); + * do { + * if (I_need_events && + * (ev = pixma_wait_event(scanner, timeout)) > 0) { + * handle_event(ev); + * } + * pixma_scan(scanner, param); + * while ((count = pixma_read_image(scanner, buf, len)) > 0) { + * write(buf, count); + * if (error_occured_in_write) { + * pixma_cancel(scanner); + * } + * } + * } while (!enough); + * pixma_close(scanner); + * pixma_cleanup(); + * \endcode + * + * Note: pixma_cancel() can be called asynchronously to + * interrupt pixma_read_image(). It does not cancel the operation + * immediately. pixma_read_image() must be called until it + * returns zero or an error (probably \c PIXMA_ECANCELED). + * + * \section reference Reference + * - \subpage API + * - \subpage IO + * - \subpage subdriver + * - \subpage debug + */ + +/*! + * \defgroup API The driver API + * \brief The driver API. + * + * The return value of functions that returns \c int has the following + * meaning if not otherwise specified: + * - >= 0 if succeeded + * - < 0 if failed + */ + +#ifdef HAVE_STDINT_H +# include /* available in ISO C99 */ +#else +# include +typedef uint8_t uint8_t; +typedef uint16_t uint16_t; +typedef uint32_t uint32_t; +#endif /* HAVE_STDINT_H */ + +#ifdef HAVE_INTTYPES_H +# include /* available in ISO C99 */ +#endif /* HAVE_INTTYPES_H */ + +/** \addtogroup API + * @{ */ +/** Don't forget to update the backend version in the SANE Backend specification + * file: doc/descriptions/pixma.desc !!! + */ +/** \name Version of the driver */ +/**@{*/ +#define PIXMA_VERSION_MAJOR 0 +#define PIXMA_VERSION_MINOR 27 +#define PIXMA_VERSION_BUILD 0 +/**@}*/ + +/** \name Error codes */ +/**@{*/ +#define PIXMA_EIO -1 +#define PIXMA_ENODEV -2 +#define PIXMA_EACCES -3 +#define PIXMA_ENOMEM -4 +#define PIXMA_EINVAL -5 +#define PIXMA_EBUSY -6 +#define PIXMA_ECANCELED -7 +#define PIXMA_ENOTSUP -8 +#define PIXMA_ETIMEDOUT -9 +#define PIXMA_EPROTO -10 +#define PIXMA_EPAPER_JAMMED -11 +#define PIXMA_ECOVER_OPEN -12 +#define PIXMA_ENO_PAPER -13 +#define PIXMA_EOF -14 +/**@}*/ + +/** \name Capabilities for using with pixma_config_t::cap */ +/**@{*/ +#define PIXMA_CAP_EASY_RGB (1 << 0) +#define PIXMA_CAP_GRAY (1 << 1) +#define PIXMA_CAP_ADF (1 << 2) +#define PIXMA_CAP_48BIT (1 << 3) +#define PIXMA_CAP_GAMMA_TABLE (1 << 4) +#define PIXMA_CAP_EVENTS (1 << 5) +#define PIXMA_CAP_TPU (1 << 6) +#define PIXMA_CAP_ADFDUP ((1 << 7) | PIXMA_CAP_ADF) +#define PIXMA_CAP_CIS (0) +#define PIXMA_CAP_CCD (1 << 8) +#define PIXMA_CAP_LINEART (1 << 9) +#define PIXMA_CAP_NEGATIVE (1 << 10) +#define PIXMA_CAP_TPUIR ((1 << 11) | PIXMA_CAP_TPU) +#define PIXMA_CAP_ADF_WAIT (1 << 12) +#define PIXMA_CAP_ADF_JPEG (1 << 13) +#define PIXMA_CAP_EXPERIMENT (1 << 31) +/**@}*/ + +/** \name Button events and related information returned by pixma_wait_event() */ +/**@{*/ +#define PIXMA_EV_NONE 0 +#define PIXMA_EV_ACTION_MASK (0xffffff) +#define PIXMA_EV_BUTTON1 (1 << 24) +#define PIXMA_EV_BUTTON2 (2 << 24) +#define PIXMA_EV_TARGET_MASK (0xff) +#define PIXMA_EV_ORIGINAL_MASK (0xff00) +#define PIXMA_EV_DPI_MASK (0xff0000) + +#define GET_EV_TARGET(x) (x & PIXMA_EV_TARGET_MASK) +#define GET_EV_ORIGINAL(x) ( (x & PIXMA_EV_ORIGINAL_MASK) >> 8 ) +#define GET_EV_DPI(x) ( (x & PIXMA_EV_DPI_MASK) >> 16 ) + +/**@}*/ +/** @} end of API group */ + +#define PIXMA_CONFIG_FILE "pixma.conf" +#define MAX_CONF_DEVICES 15 + +struct pixma_t; +struct pixma_scan_ops_t; +struct pixma_scan_param_t; +struct pixma_config_t; +struct pixma_cmdbuf_t; +struct pixma_imagebuf_t; +struct pixma_device_status_t; + +typedef struct pixma_t pixma_t; +typedef struct pixma_scan_ops_t pixma_scan_ops_t; +typedef struct pixma_scan_param_t pixma_scan_param_t; +typedef struct pixma_config_t pixma_config_t; +typedef struct pixma_cmdbuf_t pixma_cmdbuf_t; +typedef struct pixma_imagebuf_t pixma_imagebuf_t; +typedef struct pixma_device_status_t pixma_device_status_t; + + +/** \addtogroup API + * @{ */ +/** String index constants */ +typedef enum pixma_string_index_t +{ + PIXMA_STRING_MODEL, + PIXMA_STRING_ID, + PIXMA_STRING_LAST +} pixma_string_index_t; + +/** Paper sources */ +typedef enum pixma_paper_source_t +{ + PIXMA_SOURCE_FLATBED, + PIXMA_SOURCE_ADF, + PIXMA_SOURCE_TPU, + PIXMA_SOURCE_ADFDUP /* duplex */ +} pixma_paper_source_t; + +/** Scan modes */ +typedef enum pixma_scan_mode_t +{ + /* standard scan modes */ + PIXMA_SCAN_MODE_COLOR, + PIXMA_SCAN_MODE_GRAY, + /* TPU scan modes for negatives */ + PIXMA_SCAN_MODE_NEGATIVE_COLOR, + PIXMA_SCAN_MODE_NEGATIVE_GRAY, + /* extended scan modes for 48 bit flatbed scanners */ + PIXMA_SCAN_MODE_COLOR_48, + PIXMA_SCAN_MODE_GRAY_16, + /* 1 bit lineart scan mode */ + PIXMA_SCAN_MODE_LINEART, + /* TPUIR scan mode */ + PIXMA_SCAN_MODE_TPUIR +} pixma_scan_mode_t; + +typedef enum pixma_hardware_status_t +{ + PIXMA_HARDWARE_OK, + PIXMA_HARDWARE_ERROR +} pixma_hardware_status_t; + +typedef enum pixma_lamp_status_t +{ + PIXMA_LAMP_OK, + PIXMA_LAMP_WARMING_UP, + PIXMA_LAMP_OFF, + PIXMA_LAMP_ERROR +} pixma_lamp_status_t; + +typedef enum pixma_adf_status_t +{ + PIXMA_ADF_OK, + PIXMA_ADF_NO_PAPER, + PIXMA_ADF_JAMMED, + PIXMA_ADF_COVER_OPEN, + PIXMA_ADF_ERROR +} pixma_adf_status_t; + +typedef enum pixma_calibration_status_t +{ + PIXMA_CALIBRATION_OK, + PIXMA_CALIBRATION_IN_PROGRESS, + PIXMA_CALIBRATION_OFF, + PIXMA_CALIBRATION_ERROR +} pixma_calibration_status_t; + +/** Device status. */ +struct pixma_device_status_t +{ + pixma_hardware_status_t hardware; + pixma_lamp_status_t lamp; + pixma_adf_status_t adf; + pixma_calibration_status_t cal; +}; + +/** Scan parameters. */ +struct pixma_scan_param_t +{ + /** Size in bytes of one image line (row). + * line_size >= depth / 8 * channels * w
+ * This field will be set by pixma_check_scan_param(). */ + uint64_t line_size; + + /** Size in bytes of the whole image. + * image_size = line_size * h
+ * This field will be set by pixma_check_scan_param(). */ + uint64_t image_size; + + /** Channels per pixel. 1 = grayscale and lineart, 3 = color */ + unsigned channels; + + /** Bits per channels. + * 1 = 1 bit B/W lineart (flatbed) + * 8 = 8 bit grayscale, + * 24 bit color (both flatbed) + * 16 = 16 bit grayscale (TPU, flatbed not implemeted), + * 48 bit color (TPU, flatbed not implemented) */ + unsigned depth; + + /*@{ */ + /** Resolution. Valid values are 75,150,300,600,1200... */ + unsigned xdpi, ydpi; + /*@} */ + + /*! \name Scan area in pixels + * (0,0) = top left; positive x extends to the right; positive y to the + * bottom; in pixels. + * xs is the offset in x direction of the selected scan range relative + * to the range read from the scanner and wx the width in x direction + * of the scan line read from scanner. */ + /*@{ */ + unsigned x, y, w, h, xs, wx; + /*@} */ + + /** Flag indicating whether the offset correction for TPU scans + * was already performed (to avoid repeated corrections). + * Currently only used in pixma_mp800.c sub-driver */ + unsigned tpu_offset_added; + + /* Flag indicating if data from scanner will be in JPEG format */ + unsigned mode_jpeg; + + /** Flag indicating whether a software-lineart scan is in progress + * 0 = other scan + * 1 = software-lineart scan */ + unsigned software_lineart; + + /** Threshold for software-lineart scans */ + unsigned threshold; + + /** lineart threshold curve for dynamic rasterization */ + unsigned threshold_curve; + + /* look up table used in dynamic rasterization */ + unsigned char lineart_lut[256]; + + /** Gamma table. 4096 entries, 12 bit => 8 bit. If \c NULL, default gamma + * specified by subdriver will be used. */ + const uint8_t *gamma_table; + + /** \see #pixma_paper_source_t */ + pixma_paper_source_t source; + + /** \see #pixma_scan_mode_t */ + pixma_scan_mode_t mode; + + /** The current page # in the same ADF scan session, 0 in non ADF */ + unsigned adf_pageid; + + /** adf-wait */ + unsigned adf_wait; + unsigned frontend_cancel; +}; + +/** PIXMA model information */ +struct pixma_config_t +{ + /* If you change this structure, don't forget to update the device list in + * subdrivers. */ + const char *name; /**< Model name. */ + const char *model; /**< Short model */ + uint16_t vid; /**< USB Vendor ID */ + uint16_t pid; /**< USB Product ID */ + unsigned iface; /**< USB Interface number */ + const pixma_scan_ops_t *ops; /**< Subdriver ops */ + unsigned min_xdpi; /**< Minimum horizontal resolution[DPI] */ + unsigned xdpi; /**< Maximum horizontal resolution[DPI] */ + unsigned ydpi; /**< Maximum vertical resolution[DPI] */ + unsigned adftpu_min_dpi; /**< Maximum horizontal resolution[DPI] for adf/tpu + * only needed if ADF/TPU has another min. dpi value than 75 dpi */ + unsigned adftpu_max_dpi; /**< Maximum vertical resolution[DPI] for adf/tpu + * only needed if ADF/TPU has another max. dpi value than xdpi */ + unsigned tpuir_min_dpi; /**< Minimum resolution[DPI] for tpu-ir + * only needed if TPU-IR has another min. dpi value than 75 dpi */ + unsigned tpuir_max_dpi; /**< Maximum resolution[DPI] for tpu-ir + * only needed if TPU-IR has another max. dpi value than xdpi */ + unsigned width; /**< Maximum width of scannable area in pixels at 75DPI */ + unsigned height; /**< Maximum height of scannable area in pixels at 75DPI */ + unsigned cap; /**< Capability bitfield \see PIXMA_CAP_* */ +}; + + +/* Defined in pixma_common.c */ + +/** Initialize the driver. It must be called before any other functions + * except pixma_set_debug_level(). */ +int pixma_init (void); + +/** Free resources allocated by the driver. */ +void pixma_cleanup (void); + +/** Set the debug level. + * \param[in] level the debug level + * - 0 No debug output at all + * - 1 Only errors and warning + * - 2 General information + * - 3 Debugging messages + * - 10 USB traffic dump */ +void pixma_set_debug_level (int level); + +/** Find scanners. The device number used in pixma_open(), + * pixma_get_device_model(), pixma_get_device_id() and + * pixma_get_device_config() must be less than the value returned by the last + * call of this function. + * + * \return The number of scanners found currently. The return value is + * guaranteed to be valid until the next call to pixma_find_scanners(). */ +int pixma_find_scanners (const char **conf_devices, SANE_Bool local_only); + +/** Return the model name of the device \a devnr. */ +const char *pixma_get_device_model (unsigned devnr); + +/** Return the unique ID of the device \a devnr. */ +const char *pixma_get_device_id (unsigned devnr); + +/** Return the device configuration of the device \a devnr. */ +const struct pixma_config_t *pixma_get_device_config (unsigned devnr); + +/** Open a connection to the scanner \a devnr. + * \param[in] devnr The scanner number + * \param[out] handle The device handle + * \see pixma_find_scanners() */ +int pixma_open (unsigned devnr, pixma_t ** handle); + +/** Close the connection to the scanner. The scanning process is aborted + * if necessary before the function returns. */ +void pixma_close (pixma_t * s); + +/** Initiate an image acquisition process. You must keep \a sp valid until the + * image acquisition process has finished. */ +int pixma_scan (pixma_t *, pixma_scan_param_t * sp); + +/** Read a block of image data. It blocks until there is at least one byte + * available or an error occurs. + * + * \param[out] buf Pointer to the buffer + * \param[in] len Size of the buffer + * + * \retval count Number of bytes written to the buffer or error. Possible + * return value: + * - count = 0 for end of image + * - count = \a len + * - 0 < count < \a len if and only if it is the last block. + * - count < 0 for error */ +int pixma_read_image (pixma_t *, void *buf, unsigned len); + +#if 0 +/** Read a block of image data and write to \a fd. + * \param[in] fd output file descriptor + * \see pixma_read_image() */ +int pixma_read_image_write (pixma_t *, int fd); +#endif + +/** Cancel the scanning process. No effect if no scanning process is in + * progress. It can be called asynchronously e.g. within a signal + * handle. pixma_cancel() doesn't abort the operation immediately. It + * guarantees that the current call or, at the latest, the next call to + * pixma_read_image() will return zero or an error (probably PIXMA_ECANCELED). */ +void pixma_cancel (pixma_t *); + +/** Check the scan parameters. This function can change your parameters to + * match the device capability, e.g. adjust width and height to the available + * area. + * \return PIXMA_EINVAL for invalid parameters. */ +int pixma_check_scan_param (pixma_t *, pixma_scan_param_t *); + +/** Wait until a scanner button is pressed or it times out. It should not be + * called during image acquisition is in progress. + * \param[in] timeout in milliseconds, less than 0 means forever + * \return + * - \c PIXMA_EV_NONE if it timed out. + * - non-zero value indicates which button was pressed. + * \see PIXMA_EV_* + */ +uint32_t pixma_wait_event (pixma_t *, int timeout); + +/** Activate connection to scanner */ +int pixma_activate_connection (pixma_t *); + +/** De-activate connection to scanner */ + +int pixma_deactivate_connection (pixma_t *); + + +/** Enable or disable background tasks. Currently, the only one task + * is submitting interrupt URB in background. + * \param[in] enabled if not zero, enable background task. + * \see pixma_set_interrupt_mode() */ +int pixma_enable_background (pixma_t *, int enabled); + +/** Read the current device status. + * \param[out] status the current device status + * \return 0 if succeeded. Otherwise, failed. + */ +int pixma_get_device_status (pixma_t *, pixma_device_status_t * status); + +const char *pixma_get_string (pixma_t *, pixma_string_index_t); +const pixma_config_t *pixma_get_config (pixma_t *); +void pixma_fill_gamma_table (double gamma, uint8_t * table, unsigned n); +const char *pixma_strerror (int error); + +/** @} end of API group */ + +#endif diff --git a/backend/pixma/pixma_bjnp.c b/backend/pixma/pixma_bjnp.c new file mode 100644 index 0000000..34ba918 --- /dev/null +++ b/backend/pixma/pixma_bjnp.c @@ -0,0 +1,2645 @@ +/* SANE - Scanner Access Now Easy. + + Copyright (C) 2008 2012 by Louis Lagendijk + + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. +*/ + +#undef BACKEND_NAME +#define BACKEND_NAME bjnp + +#include "../include/sane/config.h" +#include "../include/sane/sane.h" + +/* + * Standard types etc + */ +#ifdef HAVE_STDLIB_H +#include +#endif +#ifdef HAVE_STRING_H +#include +#endif +#include +#include +#ifdef HAVE_STDINT_H +#include +#endif +#ifdef HAVE_SYS_TYPES_H +#include +#endif +#ifdef HAVE_SYS_TIME_H +#include +#endif +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif + +/* + * networking stuff + */ +#ifdef HAVE_SYS_SOCKET_H +#include +#endif +#ifdef HAVE_NETINET_IN_H +#include +#endif +#include +#include +#include +#include +#ifdef HAVE_IFADDRS_H +#include +#endif +#ifdef HAVE_SYS_SELECT_H +#include +#endif +#ifdef HAVE_PWD_H +#include +#endif +#include +#ifdef HAVE_FCNTL_H +#include +#endif + +#include "pixma_bjnp_private.h" +#include "pixma_bjnp.h" +/* #include "pixma_rename.h" */ +#include "pixma.h" +#include "pixma_common.h" + +#ifndef SSIZE_MAX +# define SSIZE_MAX LONG_MAX +#endif + +/* static data */ +static bjnp_device_t device[BJNP_NO_DEVICES]; +static int bjnp_no_devices = 0; + +/* + * Private functions + */ + +static const struct pixma_config_t *lookup_scanner(const char *makemodel, + const struct pixma_config_t *const pixma_devices[]) +{ + int i; + const struct pixma_config_t *cfg; + char *match; + + for (i = 0; pixma_devices[i]; i++) + { + /* loop through the device classes (mp150, mp730 etc) */ + for (cfg = pixma_devices[i]; cfg->name; cfg++) + { + /* loop through devices in class */ + PDBG( bjnp_dbg( LOG_DEBUG3, "lookup_scanner: Checking for %s in %s\n", makemodel, cfg->model)); + if ((match = strcasestr (makemodel, cfg->model)) != NULL) + { + /* possible match found, make sure it is not a partial match */ + /* MP600 and MP600R are different models! */ + /* some models contain ranges, so check for a '-' too */ + + if ((match[strlen(cfg->model)] == ' ') || + (match[strlen(cfg->model)] == '\0') || + (match[strlen(cfg->model)] == '-')) + { + PDBG( bjnp_dbg (LOG_DEBUG, "lookup_scanner: Scanner model found: Name %s(%s) matches %s\n", cfg->model, cfg->name, makemodel)); + return cfg; + } + } + } + } + PDBG( bjnp_dbg (LOG_DEBUG, "lookup_scanner: Scanner model %s not found, giving up!\n", makemodel)); + return NULL; +} + +static void +u8tohex (char *string, const uint8_t *value, int len ) +{ + int i; + int x; + const char hdigit[16] = + { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', + 'e', 'f' + }; + for (i = 0; i < len; i++) + { + x = value[i]; + string[ 2 * i ] = hdigit[(x >> 4) & 0xf]; + string[ 2 * i + 1] = hdigit[x & 0xf]; + } + string[2 * len ] = '\0'; +} + +static void +u32tohex (uint32_t x, char *str) +{ + uint8_t uint8[4]; + uint8[0] = (uint8_t)(x >> 24); + uint8[1] = (uint8_t)(x >> 16); + uint8[2] = (uint8_t)(x >> 8); + uint8[3] = (uint8_t)x ; + u8tohex(str, uint8, 4); +} + +static void +bjnp_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 > DBG_LEVEL) + return; + if (level == DBG_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 (p, d + ofs + c, 1); + p[2] = ' '; + p += 3; + if (c == 7) + { + p[0] = ' '; + p++; + } + } + p[0] = '\0'; + bjnp_dbg (level, "%s\n", line); + ofs += c; + } + if (len > plen) + bjnp_dbg(level, "......\n"); +} + +static int sa_is_equal( const bjnp_sockaddr_t * sa1, const bjnp_sockaddr_t * sa2) +{ + if ((sa1 == NULL) || (sa2 == NULL) ) + return 0; + + if (sa1->addr.sa_family == sa2-> addr.sa_family) + { + if( sa1 -> addr.sa_family == AF_INET) + { + if ( (sa1->ipv4.sin_port == sa2->ipv4.sin_port) && + (sa1->ipv4.sin_addr.s_addr == sa2->ipv4.sin_addr.s_addr)) + { + return 1; + } + } +#ifdef ENABLE_IPV6 + else if (sa1 -> addr.sa_family == AF_INET6 ) + { + if ( (sa1-> ipv6.sin6_port == sa2->ipv6.sin6_port) && + (memcmp(&(sa1->ipv6.sin6_addr), &(sa2->ipv6.sin6_addr), sizeof(struct in6_addr)) == 0)) + { + return 1; + } + } +#endif + } + return 0; +} + +static int +sa_size( const bjnp_sockaddr_t *sa) +{ + switch (sa -> addr.sa_family) + { + case AF_INET: + return (sizeof(struct sockaddr_in) ); +#ifdef ENABLE_IPV6 + case AF_INET6: + return (sizeof(struct sockaddr_in6) ); +#endif + default: + /* should not occur */ + return sizeof( bjnp_sockaddr_t ); + } +} + +static int +get_protocol_family( const bjnp_sockaddr_t *sa) +{ + switch (sa -> addr.sa_family) + { + case AF_INET: + return PF_INET; + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + return PF_INET6; + break; +#endif + default: + /* should not occur */ + return -1; + } +} + +static void +get_address_info ( const bjnp_sockaddr_t *addr, char * addr_string, int *port) +{ + char tmp_addr[BJNP_HOST_MAX]; + if ( addr->addr.sa_family == AF_INET) + { + inet_ntop( AF_INET, &(addr -> ipv4.sin_addr.s_addr), addr_string, BJNP_HOST_MAX); + *port = ntohs (addr->ipv4.sin_port); + } +#ifdef ENABLE_IPV6 + else if (addr->addr.sa_family == AF_INET6) + { + inet_ntop( AF_INET6, addr -> ipv6.sin6_addr.s6_addr, tmp_addr, sizeof(tmp_addr) ); + + if (IN6_IS_ADDR_LINKLOCAL( &(addr -> ipv6.sin6_addr) ) ) + sprintf(addr_string, "[%s%%%d]", tmp_addr, addr -> ipv6.sin6_scope_id); + + *port = ntohs (addr->ipv6.sin6_port); + } +#endif + else + { + /* unknown address family, should not occur */ + strcpy(addr_string, "Unknown address family"); + *port = 0; + } +} + +static int +parse_IEEE1284_to_model (char *scanner_id, char *model) +{ +/* + * parses the IEEE1284 ID of the scanner to retrieve make and model + * of the scanner + * Returns: 0 = not found + * 1 = found, model is set + */ + + char s[BJNP_IEEE1284_MAX]; + char *tok; + char * model_str; + + strncpy (s, scanner_id, BJNP_IEEE1284_MAX); + s[BJNP_IEEE1284_MAX - 1] = '\0'; + model[0] = '\0'; + + tok = strtok (s, ";"); + while (tok != NULL) + { + /* MDL contains make and model */ + + if (strncmp (tok, "MDL:", strlen("MDL:")) == 0) + { + model_str = tok + strlen("MDL:"); + strncpy (model, model_str, BJNP_MODEL_MAX); + model[BJNP_MODEL_MAX -1] = '\0'; + return 1; + } + tok = strtok (NULL, ";"); + } + return 0; +} + +static int +charTo2byte (char *d, const char *s, int len) +{ + /* + * copy ASCII string to UTF-16 unicode string + * len is length of destination buffer + * Returns: number of characters copied + */ + + int done = 0; + int copied = 0; + int i; + + len = len / 2; + for (i = 0; i < len; i++) + { + d[2 * i] = '\0'; + if (s[i] == '\0') + { + done = 1; + } + if (done == 0) + { + d[2 * i + 1] = s[i]; + copied++; + } + else + d[2 * i + 1] = '\0'; + } + return copied; +} + +static bjnp_protocol_defs_t *get_protocol_by_method( char *method) +{ + int i = 0; + while ( bjnp_protocol_defs[i].method_string != NULL) + { + if (strcmp(method, bjnp_protocol_defs[i].method_string) == 0) + { + return &bjnp_protocol_defs[i]; + } + i++; + } + return NULL; +} + +static bjnp_protocol_defs_t *get_protocol_by_proto_string( char *proto_string) +{ + int i = 0; + while ( bjnp_protocol_defs[i].proto_string != NULL) + { + if (strncmp(proto_string, bjnp_protocol_defs[i].proto_string, 4) == 0) + { + return &bjnp_protocol_defs[i]; + } + i++; + } + return NULL; +} + +static char * +getusername (void) +{ + static char noname[] = "sane_pixma"; + struct passwd *pwdent; + +#ifdef HAVE_PWD_H + if (((pwdent = getpwuid (geteuid ())) != NULL) && (pwdent->pw_name != NULL)) + return pwdent->pw_name; +#endif + return noname; +} + + +static char * +determine_scanner_serial (const char *hostname, const char * mac_address, char *serial) +{ + char *dot; + char copy[BJNP_HOST_MAX]; + + /* determine a "serial number" for the scanner */ + /* if available we use the hostname or ipv4 address of the printer */ + /* if we only have a literal ipv6 address, we use the mac-address */ + + strcpy(copy, hostname); + if (strlen (copy) >= SERIAL_MAX) + { + /* make the string fit into the serial */ + /* if this is a FQDN, not an ip-address, remove domain part of the name */ + if ((dot = strchr (copy, '.')) != NULL) + { + *dot = '\0'; + } + } + /* check if name is still to long. If so use the mac-address */ + if (strlen(copy) >= SERIAL_MAX) + { + strcpy(copy, mac_address); + } + strcpy( serial, copy ); + return serial; +} + +static int +bjnp_open_tcp (int devno) +{ + int sock; + int val; + bjnp_sockaddr_t *addr = device[devno].addr; + char host[BJNP_HOST_MAX]; + int port; + int connect_timeout = BJNP_TIMEOUT_TCP_CONNECT; + + get_address_info( addr, host, &port); + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_open_tcp: Setting up a TCP socket, dest: %s port %d\n", + host, port ) ); + + if ((sock = socket (get_protocol_family( addr ) , SOCK_STREAM, 0)) < 0) + { + PDBG (bjnp_dbg (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not create socket: %s\n", + strerror (errno))); + return -1; + } + + val = 1; + setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val)); + +#if 0 + val = 1; + setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof (val)); + + val = 1; +#endif + + /* + * Using TCP_NODELAY improves responsiveness, especially on systems + * with a slow loopback interface... + */ + + val = 1; + setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)); + +/* + * Close this socket when starting another process... + */ + + fcntl (sock, F_SETFD, FD_CLOEXEC); + + while (connect_timeout > 0) + { + if (connect + (sock, &(addr->addr), sa_size(device[devno].addr)) == 0) + { + device[devno].tcp_socket = sock; + return 0; + } + PDBG (bjnp_dbg( LOG_INFO, "bjnp_open_tcp: INFO - Can not yet connect over TCP to scanner: %s, retrying\n", + strerror(errno))); + usleep(BJNP_TCP_CONNECT_INTERVAL * BJNP_USLEEP_MS); + connect_timeout = connect_timeout - BJNP_TCP_CONNECT_INTERVAL; + } + PDBG (bjnp_dbg + (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not connect to scanner, giving up!")); + return -1; +} + +static int +split_uri (const char *devname, char *method, char *host, char *port, + char *args) +{ + char copy[1024]; + char *start; + char next; + int i; + + strncpy (copy, devname, 1024); + copy[1023] = '\0'; + start = copy; + +/* + * retrieve method + */ + i = 0; + while ((start[i] != '\0') && (start[i] != ':')) + { + i++; + } + + if (((strncmp (start + i, "://", 3) != 0)) || (i > BJNP_METHOD_MAX -1 )) + { + PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find method in %s (offset %d)\n", + devname, i)); + return -1; + } + + start[i] = '\0'; + strcpy (method, start); + start = start + i + 3; + +/* + * retrieve host + */ + + if (start[0] == '[') + { + /* literal IPv6 address */ + + char *end_of_address = strchr(start, ']'); + + if ( ( end_of_address == NULL) || + ( (end_of_address[1] != ':') && (end_of_address[1] != '/' ) && (end_of_address[1] != '\0' )) || + ( (end_of_address - start) >= BJNP_HOST_MAX ) ) + { + PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find hostname or address in %s\n", devname)); + return -1; + } + next = end_of_address[1]; + *end_of_address = '\0'; + strcpy(host, start + 1); + start = end_of_address + 2; + } + else + { + i = 0; + while ((start[i] != '\0') && (start[i] != '/') && (start[i] != ':')) + { + i++; + } + next = start[i]; + start[i] = '\0'; + if ((i == 0) || (i >= BJNP_HOST_MAX ) ) + { + PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find hostname or address in %s\n", devname)); + return -1; + } + strcpy (host, start); + start = start + i +1; + } + + +/* + * retrieve port number + */ + + if (next != ':') + strcpy(port, ""); + else + { + char *end_of_port = strchr(start, '/'); + if (end_of_port == NULL) + { + next = '\0'; + } + else + { + next = *end_of_port; + *end_of_port = '\0'; + } + if ((strlen(start) == 0) || (strlen(start) >= BJNP_PORT_MAX ) ) + { + PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find port in %s (have \"%s\")\n", devname, start)); + return -1; + } + strcpy(port, start); + start = end_of_port + 1; + } + +/* + * Retrieve arguments + */ + + if (next == '/') + { + i = strlen(start); + if ( i >= BJNP_ARGS_MAX) + { + PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Argument string too long in %s\n", devname)); + } + strcpy (args, start); + } + else + strcpy (args, ""); + return 0; +} + + + +static void +set_cmd_from_string (char* protocol_string, struct BJNP_command *cmd, char cmd_code, int payload_len) +{ + /* + * Set command buffer with command code, session_id and length of payload + * Returns: sequence number of command + */ + + memcpy (cmd->BJNP_id, protocol_string, sizeof (cmd->BJNP_id)); + cmd->dev_type = BJNP_CMD_SCAN; + cmd->cmd_code = cmd_code; + cmd->unknown1 = htons (0); + + /* device not yet opened, use 0 for serial and session) */ + cmd->seq_no = htons (0); + cmd->session_id = htons (0); + cmd->payload_len = htonl (payload_len); +} + +static void +set_cmd_for_dev (int devno, struct BJNP_command *cmd, char cmd_code, int payload_len) +{ + /* + * Set command buffer with command code, session_id and length of payload + * Returns: sequence number of command + */ + + memcpy(cmd->BJNP_id, device[devno].protocol_string, sizeof (cmd->BJNP_id)); + cmd->dev_type = BJNP_CMD_SCAN; + cmd->cmd_code = cmd_code; + cmd->unknown1 = htons (0); + cmd->seq_no = htons (++(device[devno].serial)); + cmd->session_id = (cmd_code == CMD_UDP_POLL ) ? 0 : htons (device[devno].session_id); + device[devno].last_cmd = cmd_code; + cmd->payload_len = htonl (payload_len); +} + +static int +bjnp_setup_udp_socket ( const int dev_no ) +{ + /* + * Setup a udp socket for the given device + * Returns the socket or -1 in case of error + */ + + int sockfd; + char addr_string[256]; + int port; + bjnp_sockaddr_t * addr = device[dev_no].addr; + + get_address_info( addr, addr_string, &port); + + PDBG (bjnp_dbg (LOG_DEBUG, "setup_udp_socket: Setting up a UDP socket, dest: %s port %d\n", + addr_string, port ) ); + + if ((sockfd = socket (get_protocol_family( addr ), SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + PDBG (bjnp_dbg + (LOG_CRIT, "setup_udp_socket: ERROR - can not open socket - %s\n", + strerror (errno))); + return -1; + } + + if (connect + (sockfd, &(device[dev_no].addr->addr), sa_size(device[dev_no].addr) )!= 0) + { + PDBG (bjnp_dbg + (LOG_CRIT, "setup_udp_socket: ERROR - connect failed- %s\n", + strerror (errno))); + close(sockfd); + return -1; + } + return sockfd; +} + +static int +udp_command (const int dev_no, char *command, int cmd_len, char *response, + int resp_len) +{ + /* + * send udp command to given device and recieve the response` + * returns: the legth of the response or -1 + */ + int sockfd; + struct timeval timeout; + int result; + int try, attempt; + int numbytes; + fd_set fdset; + struct BJNP_command *resp = (struct BJNP_command *) response; + struct BJNP_command *cmd = (struct BJNP_command *) command; + + if ( (sockfd = bjnp_setup_udp_socket(dev_no) ) == -1 ) + { + PDBG (bjnp_dbg( LOG_CRIT, "udp_command: ERROR - Can not setup socket\n") ); + return -1; + } + + for (try = 0; try < BJNP_UDP_RETRY_MAX; try++) + { + if ((numbytes = send (sockfd, command, cmd_len, 0)) != cmd_len) + { + PDBG (bjnp_dbg + (LOG_NOTICE, "udp_command: ERROR - Sent %d bytes, expected %d\n", + numbytes, cmd_len)); + continue; + } + + attempt = 0; + + /* wait for data to be received, ignore signals being received */ + /* skip late udp responses (they have an incorrect sequence number */ + do + { + FD_ZERO (&fdset); + FD_SET (sockfd, &fdset); + + timeout.tv_sec = device[dev_no].bjnp_ip_timeout /1000; + timeout.tv_usec = device[dev_no].bjnp_ip_timeout %1000; + } + while (((result = + select (sockfd + 1, &fdset, NULL, NULL, &timeout)) <= 0) + && (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS) + && resp-> seq_no != cmd->seq_no); + + if (result <= 0) + { + PDBG (bjnp_dbg + (LOG_NOTICE, "udp_command: ERROR - select failed: %s\n", + result == 0 ? "timed out" : strerror (errno))); + continue; + } + + if ((numbytes = recv (sockfd, response, resp_len, 0)) == -1) + { + PDBG (bjnp_dbg + (LOG_NOTICE, "udp_command: ERROR - recv failed: %s", + strerror (errno))); + continue; + } + close(sockfd); + return numbytes; + } + + /* no response even after retry */ + + close(sockfd); + PDBG (bjnp_dbg + (LOG_CRIT, "udp_command: ERROR - no data received (timeout = %d)\n", device[dev_no].bjnp_ip_timeout ) ); + return -1; +} + +static int +get_scanner_id (const int dev_no, char *model) +{ + /* + * get scanner identity + * Sets model (make and model) + * Return 0 on success, -1 in case of errors + */ + + struct BJNP_command cmd; + struct IDENTITY *id; + char scanner_id[BJNP_IEEE1284_MAX]; + int resp_len; + char resp_buf[BJNP_RESP_MAX]; + int id_len; + + /* set defaults */ + + strcpy (model, "Unidentified scanner"); + + set_cmd_for_dev (dev_no, &cmd, CMD_UDP_GET_ID, 0); + + PDBG (bjnp_dbg (LOG_DEBUG2, "get_scanner_id: Get scanner identity\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &cmd, + sizeof (struct BJNP_command))); + + if ( ( resp_len = udp_command (dev_no, (char *) &cmd, sizeof (struct BJNP_command), + resp_buf, BJNP_RESP_MAX) ) < (int)sizeof(struct BJNP_command) ) + { + PDBG (bjnp_dbg (LOG_DEBUG, "get_scanner_id: ERROR - Failed to retrieve scanner identity:\n")); + return -1; + } + PDBG (bjnp_dbg (LOG_DEBUG2, "get_scanner_id: scanner identity:\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); + + id = (struct IDENTITY *) resp_buf; + + if (device[dev_no].protocol == PROTOCOL_BJNP) + { + id_len = MIN(ntohl( id-> cmd.payload_len ) - sizeof(id-> payload.bjnp.id_len), BJNP_IEEE1284_MAX); + strncpy(scanner_id, id->payload.bjnp.id, id_len); + scanner_id[id_len] = '\0'; + } + else + { + id_len = MIN(ntohl( id-> cmd.payload_len ), BJNP_IEEE1284_MAX); + strncpy(scanner_id, id->payload.mfnp.id, id_len); + scanner_id[id_len] = '\0'; + } + PDBG (bjnp_dbg (LOG_INFO, "get_scanner_id: Scanner identity string = %s - length = %d\n", scanner_id, id_len)); + + /* get make&model from IEEE1284 id */ + + if (model != NULL) + { + parse_IEEE1284_to_model (scanner_id, model); + PDBG (bjnp_dbg (LOG_INFO, "get_scanner_id: Scanner model = %s\n", model)); + } + return 0; +} + +static int +get_scanner_name(const bjnp_sockaddr_t *scanner_sa, char *host) +{ + /* + * Parse identify command responses to ip-address + * and hostname. Return qulity of the address + */ + + struct addrinfo *results; + struct addrinfo *result; + char ip_address[BJNP_HOST_MAX]; + int port; + int error; + int match = 0; + int level; + char service[64]; + +#ifdef ENABLE_IPV6 + if ( ( scanner_sa -> addr.sa_family == AF_INET6 ) && + ( IN6_IS_ADDR_LINKLOCAL( &(scanner_sa -> ipv6.sin6_addr ) ) ) ) + level = BJNP_ADDRESS_IS_LINK_LOCAL; + else +#endif + level = BJNP_ADDRESS_IS_GLOBAL; + + get_address_info( scanner_sa, ip_address, &port ); + + /* do reverse name lookup, if hostname can not be found return ip-address */ + + if( (error = getnameinfo( &(scanner_sa -> addr) , sa_size( scanner_sa), + host, BJNP_HOST_MAX , NULL, 0, NI_NAMEREQD) ) != 0 ) + { + PDBG (bjnp_dbg(LOG_INFO, "get_scanner_name: Name for %s not found : %s\n", + ip_address, gai_strerror(error) ) ); + strcpy(host, ip_address); + return level; + } + else + { + sprintf(service, "%d", port); + /* some buggy routers return rubbish if reverse lookup fails, so + * we do a forward lookup on the received name to see if the result matches */ + + if (getaddrinfo(host , service, NULL, &results) == 0) + { + result = results; + + while (result != NULL) + { + if(sa_is_equal( scanner_sa, (bjnp_sockaddr_t *)result-> ai_addr)) + { + /* found match, good */ + PDBG (bjnp_dbg (LOG_INFO, + "get_scanner_name: Forward lookup for %s succeeded, using as hostname\n", host)); + match = 1; + level = BJNP_ADDRESS_HAS_FQDN; + break; + } + result = result-> ai_next; + } + freeaddrinfo(results); + + if (match != 1) + { + PDBG (bjnp_dbg (LOG_INFO, + "get_scanner_name: Forward lookup for %s succeeded, IP-address does not match, using IP-address %s instead\n", + host, ip_address)); + strcpy (host, ip_address); + } + } + else + { + /* forward lookup failed, use ip-address */ + PDBG ( bjnp_dbg (LOG_INFO, "get_scanner_name: Forward lookup of %s failed, using IP-address", ip_address)); + strcpy (host, ip_address); + } + } + return level; +} + +static int +get_port_from_sa(const bjnp_sockaddr_t scanner_sa) +{ +#ifdef ENABLE_IPV6 + if ( scanner_sa.addr.sa_family == AF_INET6 ) + { + return ntohs(scanner_sa.ipv6.sin6_port); + } + else +#endif + if ( scanner_sa.addr.sa_family == AF_INET ) + { + return ntohs(scanner_sa.ipv4.sin_port); + } + return -1; +} + +static int create_broadcast_socket( const bjnp_sockaddr_t * local_addr ) +{ + int sockfd = -1; + int broadcast = 1; + int ipv6_v6only = 1; + + + if ((sockfd = socket (local_addr-> addr.sa_family, SOCK_DGRAM, 0)) == -1) + { + PDBG (bjnp_dbg + (LOG_CRIT, "create_broadcast_socket: ERROR - can not open socket - %s", + strerror (errno))); + return -1; + } + + /* Set broadcast flag on socket */ + + if (setsockopt + (sockfd, SOL_SOCKET, SO_BROADCAST, (const char *) &broadcast, + sizeof (broadcast)) != 0) + { + PDBG (bjnp_dbg + (LOG_CRIT, + "create_broadcast_socket: ERROR - setting socket option SO_BROADCAST failed - %s", + strerror (errno))); + close (sockfd); + return -1; + }; + + /* For an IPv6 socket, bind to v6 only so a V6 socket can co-exist with a v4 socket */ + if ( (local_addr -> addr.sa_family == AF_INET6) && ( setsockopt + (sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &ipv6_v6only, + sizeof (ipv6_v6only)) != 0) ) + { + PDBG (bjnp_dbg + (LOG_CRIT, + "create_broadcast_socket: ERROR - setting socket option IPV6_V6ONLY failed - %s", + strerror (errno))); + close (sockfd); + return -1; + }; + + if (bind + (sockfd, &(local_addr->addr), + (socklen_t) sa_size( local_addr)) != 0) + { + PDBG (bjnp_dbg + (LOG_CRIT, + "create_broadcast_socket: ERROR - bind socket to local address failed - %s\n", + strerror (errno))); + close (sockfd); + return -1; + } + return sockfd; +} + +static int +prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, + const bjnp_sockaddr_t *broadcast_sa, bjnp_sockaddr_t * dest_sa) +{ + /* + * Prepare a socket for broadcast or multicast + * Input: + * if_name: the name of the interface + * local_sa: local address to use + * broadcast_sa: broadcast address to use, if NULL we use all hosts + * dest_sa: (write) where to return destination address of broadcast + * retuns: open socket or -1 + */ + + int socket = -1; + bjnp_sockaddr_t local_sa_copy; + + if ( local_sa == NULL ) + { + PDBG (bjnp_dbg (LOG_DEBUG, + "prepare_socket: %s is not a valid IPv4 interface, skipping...\n", + if_name)); + return -1; + } + + memset( &local_sa_copy, 0, sizeof(local_sa_copy) ); + memcpy( &local_sa_copy, local_sa, sa_size(local_sa) ); + + switch( local_sa_copy.addr.sa_family ) + { + case AF_INET: + { + local_sa_copy.ipv4.sin_port = htons(BJNP_PORT_SCAN); + + if (local_sa_copy.ipv4.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) + { + /* not a valid interface */ + + PDBG (bjnp_dbg (LOG_DEBUG, + "prepare_socket: %s is not a valid IPv4 interface, skipping...\n", + if_name)); + return -1; + } + + + /* send broadcasts to the broadcast address of the interface */ + + memcpy(dest_sa, broadcast_sa, sa_size(dest_sa) ); + + /* we fill port when we send the broadcast */ + dest_sa -> ipv4.sin_port = htons(0); + + if ( (socket = create_broadcast_socket( &local_sa_copy) ) != -1) + { + PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: %s is IPv4 capable, sending broadcast, socket = %d\n", + if_name, socket)); + } + else + { + PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: ERROR - %s is IPv4 capable, but failed to create a socket.\n", + if_name)); + return -1; + } + } + break; +#ifdef ENABLE_IPV6 + case AF_INET6: + { + local_sa_copy.ipv6.sin6_port = htons(BJNP_PORT_SCAN); + + if (IN6_IS_ADDR_LOOPBACK( &(local_sa_copy.ipv6.sin6_addr) ) ) + { + /* not a valid interface */ + + PDBG (bjnp_dbg (LOG_DEBUG, + "prepare_socket: %s is not a valid IPv6 interface, skipping...\n", + if_name)); + return -1; + } + else + { + dest_sa -> ipv6.sin6_family = AF_INET6; + + /* We fill port when we send the broadcast */ + dest_sa -> ipv6.sin6_port = htons(0); + + inet_pton(AF_INET6, "ff02::1", dest_sa -> ipv6.sin6_addr.s6_addr); + if ( (socket = create_broadcast_socket( &local_sa_copy ) ) != -1) + { + PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: %s is IPv6 capable, sending broadcast, socket = %d\n", + if_name, socket)); + } + else + { + PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: ERROR - %s is IPv6 capable, but failed to create a socket.\n", + if_name)); + return -1; + } + } + } + break; +#endif + + default: + socket = -1; + } + return socket; +} + +static int +bjnp_send_broadcast (int sockfd, const bjnp_sockaddr_t * broadcast_addr, int port, + struct BJNP_command cmd, int size) +{ + int num_bytes; + bjnp_sockaddr_t dest_addr; + + /* set address to send packet to broadcast address of interface, */ + /* with port set to the destination port */ + + memcpy(&dest_addr, broadcast_addr, sizeof(dest_addr)); + if( dest_addr.addr.sa_family == AF_INET) + { + dest_addr.ipv4.sin_port = htons(port); + } +#ifdef ENABLE_IPV6 + if( dest_addr.addr.sa_family == AF_INET6) + { + dest_addr.ipv6.sin6_port = htons(port); + } +#endif + + if ((num_bytes = sendto (sockfd, &cmd, size, 0, + &(dest_addr.addr), + sa_size( broadcast_addr)) ) != size) + { + PDBG (bjnp_dbg (LOG_INFO, + "bjnp_send_broadcast: Socket: %d: ERROR - sent only %x = %d bytes of packet, error = %s\n", + sockfd, num_bytes, num_bytes, strerror (errno))); + /* not allowed, skip this interface */ + + return -1; + } + return sockfd; +} + +static void +bjnp_finish_job (int devno) +{ +/* + * Signal end of scanjob to scanner + */ + + char resp_buf[BJNP_RESP_MAX]; + int resp_len; + struct BJNP_command cmd; + + set_cmd_for_dev (devno, &cmd, CMD_UDP_CLOSE, 0); + + PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_finish_job: Finish scanjob\n")); + PDBG (bjnp_hexdump + (LOG_DEBUG2, (char *) &cmd, sizeof (struct BJNP_command))); + resp_len = + udp_command (devno, (char *) &cmd, sizeof (struct BJNP_command), resp_buf, + BJNP_RESP_MAX); + + if (resp_len != sizeof (struct BJNP_command)) + { + PDBG (bjnp_dbg + (LOG_INFO, + "bjnp_finish_job: ERROR - Received %d characters on close scanjob command, expected %d\n", + resp_len, (int) sizeof (struct BJNP_command))); + return; + } + PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_finish_job: Finish scanjob response\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); + +} + +#ifdef PIXMA_BJNP_USE_STATUS +static int +bjnp_poll_scanner (int devno, char type,char *hostname, char *user, SANE_Byte *status, int size) +{ +/* + * send details of user to the scanner + */ + + char cmd_buf[BJNP_CMD_MAX]; + char resp_buf[BJNP_RESP_MAX]; + int resp_len; + int len = 0; /* payload length */ + int buf_len; /* length of the whole command buffer */ + struct POLL_DETAILS *poll; + struct POLL_RESPONSE *response; + char user_host[256]; + time_t t; + int user_host_len; + + poll = (struct POLL_DETAILS *) cmd_buf; + memset( poll, 0, sizeof( struct POLL_DETAILS)); + memset( &resp_buf, 0, sizeof( resp_buf) ); + + + /* create payload */ + poll->type = htons(type); + + user_host_len = sizeof( poll -> extensions.type2.user_host); + snprintf(user_host, (user_host_len /2) ,"%s %s", user, hostname); + user_host[ user_host_len /2 + 1] = '\0'; + + switch( type) { + case 0: + len = 80; + break; + case 1: + charTo2byte(poll->extensions.type1.user_host, user_host, user_host_len); + len = 80; + break; + case 2: + poll->extensions.type2.dialog = htonl(device[devno].dialog); + charTo2byte(poll->extensions.type2.user_host, user_host, user_host_len); + poll->extensions.type2.unknown_1 = htonl(0x14); + poll->extensions.type2.unknown_2 = htonl(0x10); + t = time (NULL); + strftime (poll->extensions.type2.ascii_date, + sizeof (poll->extensions.type2.ascii_date), + "%Y%m%d%H%M%S", localtime (&t)); + len = 116; + break; + case 5: + poll->extensions.type5.dialog = htonl(device[devno].dialog); + charTo2byte(poll->extensions.type5.user_host, user_host, user_host_len); + poll->extensions.type5.unknown_1 = htonl(0x14); + poll->extensions.type5.key = htonl(device[devno].status_key); + len = 100; + break; + default: + PDBG (bjnp_dbg (LOG_INFO, "bjnp_poll_scanner: unknown packet type: %d\n", type)); + return -1; + }; + /* we can only now set the header as we now know the length of the payload */ + set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_POLL, + len); + + buf_len = len + sizeof(struct BJNP_command); + PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_poll_scanner: Poll details (type %d)\n", type)); + PDBG (bjnp_hexdump (LOG_DEBUG2, cmd_buf, + buf_len)); + + resp_len = udp_command (devno, cmd_buf, buf_len, resp_buf, BJNP_RESP_MAX); + + if (resp_len > 0) + { + PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_poll_scanner: Poll details response:\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); + response = (struct POLL_RESPONSE *) resp_buf; + + device[devno].dialog = ntohl( response -> dialog ); + + if ( response -> result[3] == 1 ) + { + return BJNP_RESTART_POLL; + } + if ( (response -> result[2] & 0x80) != 0) + { + memcpy( status, response->status, size); + PDBG( bjnp_dbg(LOG_INFO, "bjnp_poll_scanner: received button status!\n")); + PDBG (bjnp_hexdump( LOG_DEBUG2, status, size )); + device[devno].status_key = ntohl( response -> key ); + return size; + } + } + return 0; +} +#endif + +static void +bjnp_send_job_details (int devno, char *hostname, char *user, char *title) +{ +/* + * send details of scanjob to scanner + */ + + char cmd_buf[BJNP_CMD_MAX]; + char resp_buf[BJNP_RESP_MAX]; + int resp_len; + struct JOB_DETAILS *job; + struct BJNP_command *resp; + + /* send job details command */ + + set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_JOB_DETAILS, + sizeof (*job) - sizeof (struct BJNP_command)); + + /* create payload */ + + job = (struct JOB_DETAILS *) (cmd_buf); + charTo2byte (job->unknown, "", sizeof (job->unknown)); + charTo2byte (job->hostname, hostname, sizeof (job->hostname)); + charTo2byte (job->username, user, sizeof (job->username)); + charTo2byte (job->jobtitle, title, sizeof (job->jobtitle)); + + PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_send_job_details: Job details\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, cmd_buf, + (sizeof (struct BJNP_command) + sizeof (*job)))); + + resp_len = udp_command (devno, cmd_buf, + sizeof (struct JOB_DETAILS), resp_buf, + BJNP_RESP_MAX); + + if (resp_len > 0) + { + PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_send_job_details: Job details response:\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); + resp = (struct BJNP_command *) resp_buf; + device[devno].session_id = ntohs (resp->session_id); + } +} + +static int +bjnp_get_scanner_mac_address ( int devno, char *mac_address ) +{ +/* + * send discover to scanner + */ + + char cmd_buf[BJNP_CMD_MAX]; + char resp_buf[BJNP_RESP_MAX]; + int resp_len; + struct DISCOVER_RESPONSE *resp = (struct DISCOVER_RESPONSE * )&resp_buf;; + + /* send job details command */ + + set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_DISCOVER, 0); + resp_len = udp_command (devno, cmd_buf, + sizeof (struct BJNP_command), resp_buf, + BJNP_RESP_MAX); + + if (resp_len > 0) + { + PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_get_scanner_mac_address: Discover response:\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); + u8tohex( mac_address, resp -> mac_addr, sizeof( resp -> mac_addr ) ); + return 0; + } + return -1; +} + +static int +bjnp_write (int devno, const SANE_Byte * buf, size_t count) +{ +/* + * This function writes TCP data to the scanner. + * Returns: number of bytes written to the scanner + */ + int sent_bytes; + int terrno; + struct SCAN_BUF bjnp_buf; + + if (device[devno].scanner_data_left) + { + PDBG (bjnp_dbg + (LOG_CRIT, "bjnp_write: ERROR - scanner data left = 0x%lx = %ld\n", + (unsigned long) device[devno].scanner_data_left, + (unsigned long) device[devno].scanner_data_left)); + } + /* set BJNP command header */ + + set_cmd_for_dev (devno, (struct BJNP_command *) &bjnp_buf, CMD_TCP_SEND, count); + memcpy (bjnp_buf.scan_data, buf, count); + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_write: sending 0x%lx = %ld bytes\n", + (unsigned long) count, (unsigned long) count); + PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &bjnp_buf, + sizeof (struct BJNP_command) + count))); + + if ((sent_bytes = + send (device[devno].tcp_socket, &bjnp_buf, + sizeof (struct BJNP_command) + count, 0)) < + (ssize_t) (sizeof (struct BJNP_command) + count)) + { + /* return result from write */ + terrno = errno; + PDBG (bjnp_dbg (LOG_CRIT, "bjnp_write: ERROR - Could not send data!\n")); + errno = terrno; + return sent_bytes; + } + /* correct nr of bytes sent for length of command */ + + else if (sent_bytes != (int) (sizeof (struct BJNP_command) + count)) + { + errno = EIO; + return -1; + } + return count; +} + +static int +bjnp_send_read_request (int devno) +{ +/* + * This function reads responses from the scanner. + * Returns: 0 on success, else -1 + * + */ + int sent_bytes; + int terrno; + struct BJNP_command bjnp_buf; + + if (device[devno].scanner_data_left) + PDBG (bjnp_dbg + (LOG_CRIT, + "bjnp_send_read_request: ERROR - scanner data left = 0x%lx = %ld\n", + (unsigned long) device[devno].scanner_data_left, + (unsigned long) device[devno].scanner_data_left)); + + /* set BJNP command header */ + + set_cmd_for_dev (devno, (struct BJNP_command *) &bjnp_buf, CMD_TCP_REQ, 0); + + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_send_read_req sending command\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &bjnp_buf, + sizeof (struct BJNP_command))); + + if ((sent_bytes = + send (device[devno].tcp_socket, &bjnp_buf, sizeof (struct BJNP_command), + 0)) < 0) + { + /* return result from write */ + terrno = errno; + PDBG (bjnp_dbg + (LOG_CRIT, "bjnp_send_read_request: ERROR - Could not send data!\n")); + errno = terrno; + return -1; + } + return 0; +} + +static SANE_Status +bjnp_recv_header (int devno, size_t *payload_size ) +{ +/* + * This function receives the response header to bjnp commands. + * devno device number + * size: return value for data size returned by scanner + * Returns: + * SANE_STATUS_IO_ERROR when any IO error occurs + * SANE_STATUS_GOOD in case no errors were encountered + */ + struct BJNP_command resp_buf; + fd_set input; + struct timeval timeout; + int recv_bytes; + int terrno; + int result; + int fd; + int attempt; + + PDBG (bjnp_dbg + (LOG_DEBUG, "bjnp_recv_header: receiving response header\n") ); + fd = device[devno].tcp_socket; + + *payload_size = 0; + attempt = 0; + do + { + /* wait for data to be received, ignore signals being received */ + FD_ZERO (&input); + FD_SET (fd, &input); + + timeout.tv_sec = device[devno].bjnp_ip_timeout /1000; + timeout.tv_usec = device[devno].bjnp_ip_timeout %1000; + } + while ( ( (result = select (fd + 1, &input, NULL, NULL, &timeout)) <= 0) && + (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS)); + + if (result < 0) + { + terrno = errno; + PDBG (bjnp_dbg (LOG_CRIT, + "bjnp_recv_header: ERROR - could not read response header (select): %s!\n", + strerror (terrno))); + errno = terrno; + return SANE_STATUS_IO_ERROR; + } + else if (result == 0) + { + terrno = errno; + PDBG (bjnp_dbg (LOG_CRIT, + "bjnp_recv_header: ERROR - could not read response header (select timed out after %d ms)!\n", + device[devno].bjnp_ip_timeout ) ); + errno = terrno; + return SANE_STATUS_IO_ERROR; + } + + /* get response header */ + + if ((recv_bytes = + recv (fd, (char *) &resp_buf, + sizeof (struct BJNP_command), + 0)) != sizeof (struct BJNP_command)) + { + terrno = errno; + if (recv_bytes == 0) + { + PDBG (bjnp_dbg (LOG_CRIT, + "bjnp_recv_header: ERROR - (recv) Scanner closed the TCP-connection!\n")); + } else { + PDBG (bjnp_dbg (LOG_CRIT, + "bjnp_recv_header: ERROR - (recv) could not read response header, received %d bytes!\n", + recv_bytes)); + PDBG (bjnp_dbg + (LOG_CRIT, "bjnp_recv_header: ERROR - (recv) error: %s!\n", + strerror (terrno))); + } + errno = terrno; + return SANE_STATUS_IO_ERROR; + } + + if (resp_buf.cmd_code != device[devno].last_cmd) + { + PDBG (bjnp_dbg + (LOG_CRIT, + "bjnp_recv_header: ERROR - Received response has cmd code %d, expected %d\n", + resp_buf.cmd_code, device[devno].last_cmd)); + return SANE_STATUS_IO_ERROR; + } + + if (ntohs (resp_buf.seq_no) != (uint16_t) device[devno].serial) + { + PDBG (bjnp_dbg + (LOG_CRIT, + "bjnp_recv_header: ERROR - Received response has serial %d, expected %d\n", + (int) ntohs (resp_buf.seq_no), (int) device[devno].serial)); + return SANE_STATUS_IO_ERROR; + } + + /* got response header back, retrieve length of payload */ + + + *payload_size = ntohl (resp_buf.payload_len); + PDBG (bjnp_dbg + (LOG_DEBUG, "bjnp_recv_header: TCP response header(payload data = %ld bytes):\n", + *payload_size) ); + PDBG (bjnp_hexdump + (LOG_DEBUG2, (char *) &resp_buf, sizeof (struct BJNP_command))); + return SANE_STATUS_GOOD; +} + +static int +bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *protocol_defs, int ip_timeout) +{ + /* initialize device structure */ + + char name[BJNP_HOST_MAX]; + + device[dn].open = 0; +#ifdef PIXMA_BJNP_USE_STATUS + device[dn].polling_status = BJNP_POLL_STOPPED; + device[dn].dialog = 0; + device[dn].status_key = 0; +#endif + device[dn].protocol = protocol_defs->protocol_version; + device[dn].protocol_string = protocol_defs->proto_string; + device[dn].tcp_socket = -1; + + device[dn].addr = (bjnp_sockaddr_t *) malloc(sizeof ( bjnp_sockaddr_t) ); + memset( device[dn].addr, 0, sizeof( bjnp_sockaddr_t ) ); + memcpy(device[dn].addr, sa, sa_size((bjnp_sockaddr_t *)sa) ); + device[dn].address_level = get_scanner_name(sa, name); + device[dn].session_id = 0; + device[dn].serial = -1; + device[dn].bjnp_ip_timeout = ip_timeout; + device[dn].bjnp_scanner_timeout = 1000; + device[dn].scanner_data_left = 0; + device[dn].last_cmd = 0; + device[dn].blocksize = BJNP_BLOCKSIZE_START; + device[dn].last_block = 0; + /* fill mac_address */ + + if (bjnp_get_scanner_mac_address(dn, device[dn].mac_address) != 0 ) + { + PDBG (bjnp_dbg + (LOG_CRIT, "bjnp_init_device_structure: Cannot read mac address, skipping this scanner\n" ) ); + device[dn].open = 0; + return -1; + } + device[dn].open = 1; + return 0; +} + +static void +bjnp_free_device_structure( int dn) +{ + if (device[dn].addr != NULL) + { + free (device[dn].addr ); + device[dn].addr = NULL; + } + device[dn].open = 0; +} + +static SANE_Status +bjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len) +{ +/* + * This function receives the payload data. + * NOTE: len may not exceed SSIZE_MAX (as that is max for recv) + * len will be restricted to SSIZE_MAX to be sure + * Returns: number of bytes of payload received from device + */ + + fd_set input; + struct timeval timeout; + ssize_t recv_bytes; + int terrno; + int result; + int fd; + int attempt; + + PDBG (bjnp_dbg + (LOG_DEBUG, "bjnp_recv_data: read response payload (0x%lx bytes max), buffer: 0x%lx, start_pos: 0x%lx\n", + (long) *len, (long) buffer, (long) start_pos)); + + + if (*len == 0) + { + /* nothing to do */ + PDBG (bjnp_dbg + (LOG_DEBUG, "bjnp_recv_data: Nothing to do (%ld bytes requested)\n", + (long) *len)); + return SANE_STATUS_GOOD; + } + else if ( *len > SSIZE_MAX ) + { + PDBG (bjnp_dbg + (LOG_DEBUG, "bjnp_recv_data: WARNING - requested block size (%ld) exceeds maximum, setting to maximum %ld\n", + (long)*len, SSIZE_MAX)); + *len = SSIZE_MAX; + } + + fd = device[devno].tcp_socket; + attempt = 0; + do + { + /* wait for data to be received, retry on a signal being received */ + FD_ZERO (&input); + FD_SET (fd, &input); + timeout.tv_sec = device[devno].bjnp_ip_timeout /1000; + timeout.tv_usec = device[devno].bjnp_ip_timeout %1000; + } + while (((result = select (fd + 1, &input, NULL, NULL, &timeout)) <= 0) && + (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS)); + + if (result < 0) + { + terrno = errno; + PDBG (bjnp_dbg (LOG_CRIT, + "bjnp_recv_data: ERROR - could not read response payload (select failed): %s!\n", + strerror (errno))); + errno = terrno; + *len = 0; + return SANE_STATUS_IO_ERROR; + } + else if (result == 0) + { + terrno = errno; + PDBG (bjnp_dbg (LOG_CRIT, + "bjnp_recv_data: ERROR - could not read response payload (select timed out after %d ms)!\n", + device[devno].bjnp_ip_timeout) ); + errno = terrno; + *len = 0; + return SANE_STATUS_IO_ERROR; + } + + if ((recv_bytes = recv (fd, buffer + start_pos, *len, 0)) < 0) + { + terrno = errno; + PDBG (bjnp_dbg (LOG_CRIT, + "bjnp_recv_data: ERROR - could not read response payload (%ld + %ld = %ld) (recv): %s!\n", + (long) buffer, (long) start_pos, (long) buffer + start_pos, strerror (errno))); + errno = terrno; + *len = 0; + return SANE_STATUS_IO_ERROR; + } + PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_recv_data: Received TCP response payload (%ld bytes):\n", + (unsigned long) recv_bytes)); + PDBG (bjnp_hexdump (LOG_DEBUG2, buffer, recv_bytes)); + + *len = recv_bytes; + return SANE_STATUS_GOOD; +} + +static BJNP_Status +bjnp_allocate_device (SANE_String_Const devname, + SANE_Int * dn, char *resulting_host) +{ + char method[BJNP_METHOD_MAX]; + char host[BJNP_HOST_MAX]; + char port[BJNP_PORT_MAX] = ""; + char args[BJNP_ARGS_MAX]; + bjnp_protocol_defs_t *protocol_defs; + struct addrinfo *res, *cur; + struct addrinfo hints; + int result; + int i; + int ip_timeout = BJNP_TIMEOUT_DEFAULT; + + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_allocate_device(%s) %d\n", devname, bjnp_no_devices)); + + if (split_uri (devname, method, host, port, args) != 0) + { + return BJNP_STATUS_INVAL; + } + + if (strlen (args) > 0) + { + /* get device specific ip timeout if any */ + + if (strncmp(args, "timeout=", strlen("timeout=")) == 0) + { + ip_timeout = atoi(args + strlen("timeout=")); + } else { + PDBG (bjnp_dbg + (LOG_CRIT, + "bjnp_allocate_device: ERROR - Unrecognized argument: %s\n", + devname)); + + return BJNP_STATUS_INVAL; + } + } + if ( (protocol_defs = get_protocol_by_method(method)) == NULL) + { + PDBG (bjnp_dbg + (LOG_CRIT, "bjnp_allocate_device: ERROR - URI %s contains invalid method: %s\n", + devname, method)); + return BJNP_STATUS_INVAL; + } + + if (strlen(port) == 0) + { + sprintf( port, "%d", protocol_defs->default_port ); + } + + hints.ai_flags = 0; +#ifdef ENABLE_IPV6 + hints.ai_family = AF_UNSPEC; +#else + hints.ai_family = AF_INET; +#endif + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = 0; + hints.ai_addrlen = 0; + hints.ai_addr = NULL; + hints.ai_canonname = NULL; + hints.ai_next = NULL; + + result = getaddrinfo (host, port, &hints, &res ); + if (result != 0 ) + { + PDBG (bjnp_dbg (LOG_CRIT, "bjnp_allocate_device: ERROR - Cannot resolve host: %s port %s\n", host, port)); + return SANE_STATUS_INVAL; + } + + /* Check if a device number is already allocated to any of the scanner's addresses */ + + cur = res; + while( cur != NULL) + { + /* create a new device structure for this address */ + + if (bjnp_no_devices == BJNP_NO_DEVICES) + { + PDBG (bjnp_dbg + (LOG_CRIT, + "bjnp_allocate_device: WARNING - Too many devices, ran out of device structures, cannot add %s\n", + devname)); + freeaddrinfo(res); + return BJNP_STATUS_INVAL; + } + if (bjnp_init_device_structure( bjnp_no_devices, (bjnp_sockaddr_t *)cur -> ai_addr, + protocol_defs, ip_timeout) != 0) + { + /* giving up on this address, try next one if any */ + cur = cur->ai_next; + continue; + } + for (i = 0; i < bjnp_no_devices; i++) + { + + /* Check if found the scanner before, if so we use the best address + * but still make sure the scanner is listed only once. + * We check for matching addresses as wel as matching mac_addresses as + * an IPv6 host can have multiple adresses */ + + if ( strcmp( device[i].mac_address, device[bjnp_no_devices].mac_address ) == 0 ) + { + if ( device[i].address_level < device[bjnp_no_devices].address_level ) + { + /* use the new address instead as it is better */ + free (device[i].addr); + device[i].addr = device[bjnp_no_devices].addr; + device[bjnp_no_devices].addr = NULL; + device[i].address_level = device[bjnp_no_devices].address_level; + } + + /* Leave timeout values unchanged, as they were probably specified by the user */ + + freeaddrinfo(res); + *dn = i; + bjnp_free_device_structure( bjnp_no_devices); + return BJNP_STATUS_ALREADY_ALLOCATED; + } + } + cur = cur->ai_next; + } + freeaddrinfo(res); + + if (device[bjnp_no_devices].open == 0) + { + PDBG (bjnp_dbg(LOG_NOTICE, "bjnp_allocate_device: Cannot access scanner, skipping!")); + return BJNP_STATUS_INVAL; + } + + PDBG (bjnp_dbg (LOG_INFO, "bjnp_allocate_device: Scanner not yet in our list, added it: %s:%s\n", host, port)); + + /* Commit new device structure */ + + *dn = bjnp_no_devices; + bjnp_no_devices++; + + /* return hostname if required */ + + if (resulting_host != NULL) + { + strcpy (resulting_host, host); + } + + return BJNP_STATUS_GOOD; +} + +static void add_scanner(SANE_Int *dev_no, + const char *uri, + SANE_Status (*attach_bjnp) + (SANE_String_Const devname, + SANE_String_Const serial, + const struct pixma_config_t *cfg), + const struct pixma_config_t *const pixma_devices[]) + +{ + char scanner_host[BJNP_HOST_MAX]; + char serial[BJNP_SERIAL_MAX]; + char makemodel[BJNP_MODEL_MAX]; + const struct pixma_config_t *cfg = NULL; + + /* Allocate device structure for scanner */ + switch (bjnp_allocate_device (uri, dev_no, scanner_host)) + { + case BJNP_STATUS_GOOD: + if (get_scanner_id (*dev_no, makemodel) != 0) + { + PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: ERROR - Cannot read scanner make & model: %s\n", + uri)); + } + else + { + /* + * fetch scanner configuration + */ + if ((cfg = lookup_scanner(makemodel, pixma_devices)) == (struct pixma_config_t *)NULL) + { + PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: Scanner %s is not supported, model is unknown! Please report upstream\n", makemodel)); + break; + } + + /* + * inform caller of found scanner + */ + + determine_scanner_serial (scanner_host, device[*dev_no].mac_address, serial); + + switch (attach_bjnp (uri, serial, cfg)) + { + case SANE_STATUS_GOOD: + PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner added: %s, serial %s, mac address: %s.\n", + uri, serial, device[*dev_no].mac_address)); + break; + default: + PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: unexpected error (out of memory?), adding %s\n", makemodel)); + } + } + + break; + case BJNP_STATUS_ALREADY_ALLOCATED: + PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: Scanner at %s was added before, good!\n", + uri)); + break; + + case BJNP_STATUS_INVAL: + PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: Scanner at %s can not be added\n", + uri)); + break; + } +} + +int add_timeout_to_uri(char *uri, int timeout, int max_len) +{ + char method[BJNP_METHOD_MAX]; + char host[BJNP_HOST_MAX]; + char port_str[BJNP_PORT_MAX]; + char args[BJNP_HOST_MAX]; + int port; + bjnp_protocol_defs_t *proto_struct; + + if (split_uri(uri, method, host, port_str, args ) != 0) + { + return -1; + } + + port = atoi(port_str); + + if (port == 0) + { + proto_struct = get_protocol_by_method(method); + if (proto_struct == NULL) + { + PDBG (bjnp_dbg (LOG_NOTICE, "uri: %s: Method %s cannot be recognized\n", uri, method)); + } + else + { + port = proto_struct-> default_port; + } + } + + /* add timeout value only if missing in URI */ + + if (strstr(args, "timeout=") == NULL) + { + sprintf(args, "timeout=%d", timeout); + } + + snprintf(uri, max_len -1, "%s://%s:%d/%s", method,host, port, args); + uri[max_len - 1] = '\0'; + return 0; +} + +/** Public functions **/ + +/** Initialize sanei_bjnp. + * + * Call this before any other sanei_bjnp function. + */ +extern void +sanei_bjnp_init (void) +{ + DBG_INIT(); + bjnp_no_devices = 0; +} + +/** + * Find devices that implement the bjnp protocol + * + * The function attach is called for every device which has been found. + * + * @param attach attach function + * + * @return SANE_STATUS_GOOD - on success (even if no scanner was found) + */ +extern SANE_Status +sanei_bjnp_find_devices (const char **conf_devices, + SANE_Status (*attach_bjnp) + (SANE_String_Const devname, + SANE_String_Const serial, + const struct pixma_config_t *cfg), + const struct pixma_config_t *const pixma_devices[]) +{ + int numbytes = 0; + struct BJNP_command cmd; + unsigned char resp_buf[2048]; + struct DISCOVER_RESPONSE *disc_resp = ( struct DISCOVER_RESPONSE *) & resp_buf; + int socket_fd[BJNP_SOCK_MAX]; + int no_sockets; + int i; + int j; + int attempt; + int last_socketfd = 0; + fd_set fdset; + fd_set active_fdset; + struct timeval timeout; + char scanner_host[HOST_NAME_MAX]; + char uri[HOST_NAME_MAX + 32]; + int dev_no; + int port; + int auto_detect = 1; + int timeout_default = BJNP_TIMEOUT_DEFAULT; + bjnp_sockaddr_t broadcast_addr[BJNP_SOCK_MAX]; + bjnp_sockaddr_t scanner_sa; + socklen_t socklen; + bjnp_protocol_defs_t *protocol_defs; + + memset( broadcast_addr, 0, sizeof( broadcast_addr) ); + memset( &scanner_sa, 0 ,sizeof( scanner_sa ) ); + PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_find_devices, pixma backend version: %d.%d.%d\n", + PIXMA_VERSION_MAJOR, PIXMA_VERSION_MINOR, PIXMA_VERSION_BUILD)); + bjnp_no_devices = 0; + + for (i=0; i < BJNP_SOCK_MAX; i++) + { + socket_fd[i] = -1; + } + + /* parse config file */ + + if (conf_devices[0] != NULL) + { + if (strcmp(conf_devices[0], "networking=no") == 0) + { + /* networking=no may only occur on the first non-commented line */ + + PDBG (bjnp_dbg( LOG_DEBUG, "sanei_bjnp_find_devices: Networked scanner detection is disabled in configuration file.\n" ) ); + return SANE_STATUS_GOOD; + } + /* parse configuration file */ + + for (i = 0; conf_devices[i] != NULL; i++) + { + if (strncmp(conf_devices[i], "bjnp-timeout=", strlen("bjnp-timeout="))== 0) + { + timeout_default = atoi(conf_devices[i] + strlen("bjnp-timeout=") ); + PDBG ( bjnp_dbg (LOG_DEBUG, "Set new default timeout value: %d ms.", timeout_default)); + continue; + } + else if (strncmp(conf_devices[i], "auto_detection=no", strlen("auto_detection=no"))== 0) + { + auto_detect = 0; + PDBG ( bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: auto detection of scanners disabled")); + continue; + } + else + { + PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Adding scanner from pixma.conf: %s\n", conf_devices[i])); + memcpy(uri, conf_devices[i], sizeof(uri)); + add_timeout_to_uri(uri, timeout_default, sizeof(uri)); + add_scanner(&dev_no, uri, attach_bjnp, pixma_devices); + } + } + PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Added all specified scanners.\n")); + } + else + { + PDBG (bjnp_dbg( LOG_DEBUG, "sanei_bjnp_find_devices: Configuration file is empty, No devices specified.\n" ) ); + } + + if (auto_detect == 0) + { + return SANE_STATUS_GOOD; + } + /* + * Send UDP DISCOVER to discover scanners and return the list of scanners found + */ + + PDBG (bjnp_dbg( LOG_DEBUG, "sanei_bjnp_find_devices: Start auto-detection.\n" ) ); + FD_ZERO (&fdset); + + no_sockets = 0; +#ifdef HAVE_IFADDRS_H + { + struct ifaddrs *interfaces = NULL; + struct ifaddrs *interface; + getifaddrs (&interfaces); + + /* create a socket for each suitable interface */ + + interface = interfaces; + while ((no_sockets < BJNP_SOCK_MAX) && (interface != NULL)) + { + if ( ! (interface -> ifa_flags & IFF_POINTOPOINT) && + ( (socket_fd[no_sockets] = + prepare_socket( interface -> ifa_name, + (bjnp_sockaddr_t *) interface -> ifa_addr, + (bjnp_sockaddr_t *) interface -> ifa_broadaddr, + &broadcast_addr[no_sockets] ) ) != -1 ) ) + { + /* track highest used socket for later use in select */ + if (socket_fd[no_sockets] > last_socketfd) + { + last_socketfd = socket_fd[no_sockets]; + } + FD_SET (socket_fd[no_sockets], &fdset); + no_sockets++; + } + interface = interface->ifa_next; + } + freeifaddrs (interfaces); + } +#else + /* we have no easy way to find interfaces with their broadcast addresses. */ + /* use global broadcast and all-hosts instead */ + { + bjnp_sockaddr_t local; + bjnp_sockaddr_t bc_addr; + + memset( &local, 0, sizeof( local) ); + local.ipv4.sin_family = AF_INET; + local.ipv4.sin_addr.s_addr = htonl (INADDR_ANY); + + bc_addr.ipv4.sin_family = AF_INET; + bc_addr.ipv4.sin_port = htons(0); + bc_addr.ipv4.sin_addr.s_addr = htonl (INADDR_BROADCAST); + + socket_fd[no_sockets] = prepare_socket( "any_interface", + &local, + &bc_addr, + &broadcast_addr[no_sockets] ); + if (socket_fd[no_sockets] >= 0) + { + FD_SET (socket_fd[no_sockets], &fdset); + if (socket_fd[no_sockets] > last_socketfd) + { + last_socketfd = socket_fd[no_sockets]; + } + no_sockets++; + } +#ifdef ENABLE_IPV6 + local.ipv6.sin6_family = AF_INET6; + local.ipv6.sin6_addr = in6addr_any; + + socket_fd[no_sockets] = prepare_socket( "any_interface", + &local, + NULL, + &broadcast_addr[no_sockets] ); + if (socket_fd[no_sockets] >= 0) + { + FD_SET (socket_fd[no_sockets], &fdset); + if (socket_fd[no_sockets] > last_socketfd) + { + last_socketfd = socket_fd[no_sockets]; + } + no_sockets++; + } +#endif + } +#endif + + /* send BJNP_MAX_BROADCAST_ATTEMPTS broadcasts on each prepared socket */ + for (attempt = 0; attempt < BJNP_MAX_BROADCAST_ATTEMPTS; attempt++) + { + for ( i=0; i < no_sockets; i++) + { + j = 0; + while(bjnp_protocol_defs[j].protocol_version != PROTOCOL_NONE) + { + set_cmd_from_string (bjnp_protocol_defs[j].proto_string, &cmd, CMD_UDP_DISCOVER, 0); + bjnp_send_broadcast ( socket_fd[i], &broadcast_addr[i], + bjnp_protocol_defs[j].default_port, cmd, sizeof (cmd)); + j++; + } + } + /* wait for some time between broadcast packets */ + usleep (BJNP_BROADCAST_INTERVAL * BJNP_USLEEP_MS); + } + + /* wait for a UDP response */ + + timeout.tv_sec = 0; + timeout.tv_usec = BJNP_BC_RESPONSE_TIMEOUT * BJNP_USLEEP_MS; + + + active_fdset = fdset; + + while (select (last_socketfd + 1, &active_fdset, NULL, NULL, &timeout) > 0) + { + PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Select returned, time left %d.%d....\n", + (int) timeout.tv_sec, (int) timeout.tv_usec)); + for (i = 0; i < no_sockets; i++) + { + if (FD_ISSET (socket_fd[i], &active_fdset)) + { + socklen = sizeof(scanner_sa); + if ((numbytes = + recvfrom (socket_fd[i], resp_buf, sizeof (resp_buf), 0, + &(scanner_sa.addr), &socklen ) ) == -1) + { + PDBG (bjnp_dbg + (LOG_INFO, "sanei_find_devices: no data received")); + break; + } + else + { + PDBG (bjnp_dbg (LOG_DEBUG2, "sanei_find_devices: Discover response:\n")); + PDBG (bjnp_hexdump (LOG_DEBUG2, &resp_buf, numbytes)); + + /* check if something sensible is returned */ + protocol_defs = get_protocol_by_proto_string(disc_resp-> response.BJNP_id); + if ( (numbytes < (int)sizeof (struct BJNP_command)) || + (protocol_defs == NULL)) + { + /* not a valid response, assume not a scanner */ + + char bjnp_id[5]; + strncpy(bjnp_id, disc_resp-> response.BJNP_id, 4); + bjnp_id[4] = '\0'; + PDBG (bjnp_dbg (LOG_INFO, + "sanei_find_devices: Invalid discover response! Length = %d, Id = %s\n", + numbytes, bjnp_id ) ); + break; + } + if ( !(disc_resp -> response.dev_type & 0x80) ) + { + /* not a response, a command from somebody else or */ + /* a discover command that we generated */ + break; + } + }; + + port = get_port_from_sa(scanner_sa); + /* scanner found, get IP-address or hostname */ + get_scanner_name( &scanner_sa, scanner_host); + + /* construct URI */ + sprintf (uri, "%s://%s:%d/timeout=%d", protocol_defs->method_string, scanner_host, + port, timeout_default); + + add_scanner( &dev_no, uri, attach_bjnp, pixma_devices); + + } + } + active_fdset = fdset; + timeout.tv_sec = 0; + timeout.tv_usec = BJNP_BC_RESPONSE_TIMEOUT * BJNP_USLEEP_MS; + } + PDBG (bjnp_dbg (LOG_DEBUG, "sanei_find_devices: scanner discovery finished...\n")); + + for (i = 0; i < no_sockets; i++) + close (socket_fd[i]); + + return SANE_STATUS_GOOD; +} + +/** Open a BJNP device. + * + * The device is opened by its name devname and the device number is + * returned in dn on success. + * + * Device names consist of an URI + * Where: + * type = bjnp + * hostname = resolvable name or IP-address + * port = 8612 for a scanner + * An example could look like this: bjnp://host.domain:8612 + * + * @param devname name of the device to open + * @param dn device number + * + * @return + * - SANE_STATUS_GOOD - on success + * - SANE_STATUS_ACCESS_DENIED - if the file couldn't be accessed due to + * permissions + * - SANE_STATUS_INVAL - on every other error + */ + +extern SANE_Status +sanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn) +{ + int result; + + PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_open(%s, %d):\n", devname, *dn)); + + result = bjnp_allocate_device (devname, dn, NULL); + if ( (result != BJNP_STATUS_GOOD) && (result != BJNP_STATUS_ALREADY_ALLOCATED ) ) { + return SANE_STATUS_INVAL; + } + return SANE_STATUS_GOOD; +} + +/** Close a BJNP device. + * + * @param dn device number + */ + +void +sanei_bjnp_close (SANE_Int dn) +{ + PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_close(%d):\n", dn)); + + device[dn].open = 0; + sanei_bjnp_deactivate(dn); +} + +/** Activate BJNP device connection + * + * @param dn device number + */ + +SANE_Status +sanei_bjnp_activate (SANE_Int dn) +{ + char hostname[256]; + char pid_str[64]; + + PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_activate (%d)\n", dn)); + gethostname (hostname, 256); + hostname[255] = '\0'; + sprintf (pid_str, "Process ID = %d", getpid ()); + + bjnp_send_job_details (dn, hostname, getusername (), pid_str); + + if (bjnp_open_tcp (dn) != 0) + { + return SANE_STATUS_INVAL; + } + + return SANE_STATUS_GOOD; +} + +/** Deactivate BJNP device connection + * + * @paran dn device number + */ + +SANE_Status +sanei_bjnp_deactivate (SANE_Int dn) +{ + PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_deactivate (%d)\n", dn)); + if ( device[dn].tcp_socket != -1) + { + bjnp_finish_job (dn); + close (device[dn].tcp_socket); + device[dn].tcp_socket = -1; + } + return SANE_STATUS_GOOD; +} + +/** Set the timeout for interrupt reads. + * we do not use it for bulk reads! + * @param timeout the new timeout in ms + */ +extern void +sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout) +{ + PDBG (bjnp_dbg (LOG_INFO, "bjnp_set_timeout to %d\n", + timeout)); + + device[devno].bjnp_scanner_timeout = timeout; +} + +/** Initiate a bulk transfer read. + * + * Read up to size bytes from the device to buffer. After the read, size + * contains the number of bytes actually read. + * + * @param dn device number + * @param buffer buffer to store read data in + * @param size size of the data + * + * @return + * - SANE_STATUS_GOOD - on succes + * - SANE_STATUS_EOF - if zero bytes have been read + * - SANE_STATUS_IO_ERROR - if an error occured during the read + * - SANE_STATUS_INVAL - on every other error + * + */ + +extern SANE_Status +sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) +{ + SANE_Status result; + SANE_Status error; + size_t recvd; + size_t read_size; + size_t read_size_max; + size_t requested; + + PDBG (bjnp_dbg + (LOG_INFO, "bjnp_read_bulk(dn=%d, bufferptr=%lx, 0x%lx = %ld)\n", dn, + (long) buffer, (unsigned long) *size, (unsigned long) *size)); + + recvd = 0; + requested = *size; + + PDBG (bjnp_dbg + (LOG_DEBUG, "bjnp_read_bulk: 0x%lx = %ld bytes available at start\n", + (unsigned long) device[dn].scanner_data_left, + (unsigned long) device[dn].scanner_data_left ) ); + + while ( (recvd < requested) && !( device[dn].last_block && (device[dn].scanner_data_left == 0)) ) + { + PDBG (bjnp_dbg + (LOG_DEBUG, + "bjnp_read_bulk: Already received 0x%lx = %ld bytes, backend requested 0x%lx = %ld bytes\n", + (unsigned long) recvd, (unsigned long) recvd, + (unsigned long) requested, (unsigned long)requested )); + + /* Check first if there is data in flight from the scanner */ + + if (device[dn].scanner_data_left == 0) + { + /* There is no data in flight from the scanner, send new read request */ + + PDBG (bjnp_dbg (LOG_DEBUG, + "bjnp_read_bulk: No (more) scanner data available, requesting more( blocksize = %ld = %lx\n", + (long int) device[dn].blocksize, (long int) device[dn].blocksize )); + + if ((error = bjnp_send_read_request (dn)) != SANE_STATUS_GOOD) + { + *size = recvd; + return SANE_STATUS_IO_ERROR; + } + if ( ( error = bjnp_recv_header (dn, &(device[dn].scanner_data_left) ) ) != SANE_STATUS_GOOD) + { + *size = recvd; + return SANE_STATUS_IO_ERROR; + } + /* correct blocksize if applicable */ + + device[dn].blocksize = MAX (device[dn].blocksize, device[dn].scanner_data_left); + + if ( device[dn].scanner_data_left < device[dn].blocksize) + { + /* the scanner will not react at all to a read request, when no more data is available */ + /* we now determine end of data by comparing the payload size to the maximun blocksize */ + /* this block is shorter than blocksize, so after this block we are done */ + + device[dn].last_block = 1; + } + } + + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: In flight: 0x%lx = %ld bytes available\n", + (unsigned long) device[dn].scanner_data_left, + (unsigned long) device[dn].scanner_data_left)); + + /* read as many bytes as needed and available */ + + read_size_max = MIN( device[dn].scanner_data_left, (requested - recvd) ); + read_size = read_size_max; + + PDBG (bjnp_dbg + (LOG_DEBUG, + "bjnp_read_bulk: Try to read 0x%lx = %ld (of max 0x%lx = %ld) bytes\n", + (unsigned long) read_size_max, + (unsigned long) read_size_max, + (unsigned long) device[dn].scanner_data_left, + (unsigned long) device[dn].scanner_data_left) ); + + result = bjnp_recv_data (dn, buffer , recvd, &read_size); + if (result != SANE_STATUS_GOOD) + { + *size = recvd; + return SANE_STATUS_IO_ERROR; + } + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: Expected at most %ld bytes, received this time: %ld\n", + read_size_max, read_size) ); + + device[dn].scanner_data_left = device[dn].scanner_data_left - read_size; + recvd = recvd + read_size; + } + + PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: %s: Returning %ld bytes, backend expexts %ld\n", + (recvd == *size)? "OK": "NOTICE",recvd, *size ) ); + *size = recvd; + if ( *size == 0 ) + return SANE_STATUS_EOF; + return SANE_STATUS_GOOD; +} + +/** Initiate a bulk transfer write. + * + * Write up to size bytes from buffer to the device. After the write size + * contains the number of bytes actually written. + * + * @param dn device number + * @param buffer buffer to write to device + * @param size size of the data + * + * @return + * - SANE_STATUS_GOOD - on succes + * - SANE_STATUS_IO_ERROR - if an error occured during the write + * - SANE_STATUS_INVAL - on every other error + */ + +extern SANE_Status +sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size) +{ + ssize_t sent; + size_t recvd; + uint32_t buf; + size_t payload_size; + + /* Write received data to scanner */ + + sent = bjnp_write (dn, buffer, *size); + if (sent < 0) + return SANE_STATUS_IO_ERROR; + if (sent != (int) *size) + { + PDBG (bjnp_dbg + (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Sent only %ld bytes to scanner, expected %ld!!\n", + (unsigned long) sent, (unsigned long) *size)); + return SANE_STATUS_IO_ERROR; + } + + if (bjnp_recv_header (dn, &payload_size) != SANE_STATUS_GOOD) + { + PDBG (bjnp_dbg (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Could not read response to command!\n")); + return SANE_STATUS_IO_ERROR; + } + + if (payload_size != 4) + { + PDBG (bjnp_dbg (LOG_CRIT, + "sanei_bjnp_write_bulk: ERROR - Scanner length of write confirmation = 0x%lx bytes = %ld, expected %d!!\n", + (unsigned long) payload_size, + (unsigned long) payload_size, 4)); + return SANE_STATUS_IO_ERROR; + } + recvd = payload_size; + if ((bjnp_recv_data (dn, (unsigned char *) &buf, 0, &recvd) != + SANE_STATUS_GOOD) || (recvd != payload_size)) + { + PDBG (bjnp_dbg (LOG_CRIT, + "sanei_bjnp_write_bulk: ERROR - Could not read length of data confirmed by device\n")); + return SANE_STATUS_IO_ERROR; + } + recvd = ntohl (buf); + if (recvd != *size) + { + PDBG (bjnp_dbg + (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Scanner confirmed %ld bytes, expected %ld!!\n", + (unsigned long) recvd, (unsigned long) *size)); + return SANE_STATUS_IO_ERROR; + } + /* we can expect data from the scanner */ + + device[dn].last_block = 0; + + return SANE_STATUS_GOOD; +} + +/** Initiate a interrupt transfer read. + * + * Read up to size bytes from the interrupt endpoint from the device to + * buffer. After the read, size contains the number of bytes actually read. + * + * @param dn device number + * @param buffer buffer to store read data in + * @param size size of the data + * + * @return + * - SANE_STATUS_GOOD - on succes + * - SANE_STATUS_EOF - if zero bytes have been read + * - SANE_STATUS_IO_ERROR - if an error occured during the read + * - SANE_STATUS_INVAL - on every other error + * + */ + +extern SANE_Status +sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) +{ +#ifndef PIXMA_BJNP_USE_STATUS + PDBG (bjnp_dbg + (LOG_INFO, "bjnp_read_int(%d, bufferptr, 0x%lx = %ld):\n", dn, + (unsigned long) *size, (unsigned long) *size)); + + memset (buffer, 0, *size); + sleep (1); + return SANE_STATUS_IO_ERROR; +#else + + char hostname[256]; + int resp_len; + int timeout; + int interval; + + PDBG (bjnp_dbg + (LOG_INFO, "bjnp_read_int(%d, bufferptr, 0x%lx = %ld):\n", dn, + (unsigned long) *size, (unsigned long) *size)); + + memset (buffer, 0, *size); + + gethostname (hostname, 32); + hostname[32] = '\0'; + + + switch (device[dn].polling_status) + { + case BJNP_POLL_STOPPED: + + /* establish dialog */ + + if ( (bjnp_poll_scanner (dn, 0, hostname, getusername (), buffer, *size ) != 0) || + (bjnp_poll_scanner (dn, 1, hostname, getusername (), buffer, *size ) != 0) ) + { + PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: WARNING - Failed to setup read_intr dialog with device!\n")); + device[dn].dialog = 0; + device[dn].status_key = 0; + return SANE_STATUS_IO_ERROR; + } + device[dn].polling_status = BJNP_POLL_STARTED; + + /* fall through */ + case BJNP_POLL_STARTED: + /* we use only seonds (rounded up) accuracy between poll attempts */ + timeout = device[dn].bjnp_scanner_timeout /1000 + 1; + if (device[dn].bjnp_scanner_timeout %1000 > 0) + { + timeout++; + + } + interval = 1; + do + { + if ( (resp_len = bjnp_poll_scanner (dn, 2, hostname, getusername (), buffer, *size ) ) < 0 ) + { + PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: Poll failed, Restarting polling dialog!\n")); + device[dn].polling_status = BJNP_POLL_STOPPED; + *size = 0; + return SANE_STATUS_EOF; + } + *size = (size_t) resp_len; + if ( resp_len > 0 ) + { + device[dn].polling_status = BJNP_POLL_STATUS_RECEIVED; + return SANE_STATUS_GOOD; + } + timeout = timeout - interval; + if (timeout <= 0) + return SANE_STATUS_EOF; + sleep(interval); + } while ( timeout > 0 ) ; + break; + case BJNP_POLL_STATUS_RECEIVED: + if ( (resp_len = bjnp_poll_scanner (dn, 5, hostname, getusername (), buffer, *size ) ) < 0 ) + { + PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: Restarting polling dialog!\n")); + device[dn].polling_status = BJNP_POLL_STOPPED; + *size = 0; + break; + } + } + return SANE_STATUS_EOF; +#endif +} diff --git a/backend/pixma/pixma_bjnp.h b/backend/pixma/pixma_bjnp.h new file mode 100644 index 0000000..79e084e --- /dev/null +++ b/backend/pixma/pixma_bjnp.h @@ -0,0 +1,201 @@ +/* SANE - Scanner Access Now Easy. + + Copyright (C) 2008 by Louis Lagendijk + based on sane_usb.h: + Copyright (C) 2003, 2005 Rene Rebe (sanei_read_int,sanei_set_timeout) + Copyright (C) 2001, 2002 Henning Meier-Geinitz + + This file is part of the SANE package. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. +*/ +/** @file sanei_bjnp.h + * This file provides a generic BJNP interface. + */ + +#ifndef sanei_bjnp_h +#define sanei_bjnp_h + +#include "../include/sane/config.h" +#include "../include/sane/sane.h" +#include "pixma.h" + +#ifdef HAVE_STDLIB_H +#include /* for size_t */ +#endif + +/** Initialize sanei_bjnp. + * + * Call this before any other sanei_bjnp function. + */ +extern void sanei_bjnp_init (void); + +/** Find scanners responding to a BJNP broadcast. + * + * The function sanei_bjnp_attach is called for every device which has + * been found. + * Serial is the address of the scanner in human readable form of max + * SERIAL_MAX characters + * @param conf_devices list of pre-configures device URI's to attach + * @param attach attach function + * @param pixma_devices device informatio needed by attach function + * + * @return SANE_STATUS_GOOD - on success (even if no scanner was found) + */ + +#define SERIAL_MAX 16 + +extern SANE_Status +sanei_bjnp_find_devices (const char **conf_devices, + SANE_Status (*attach_bjnp) + (SANE_String_Const devname, + SANE_String_Const serial, + const struct pixma_config_t *cfg), + const struct pixma_config_t *const pixma_devices[]); + +/** Open a BJNP device. + * + * The device is opened by its name devname and the device number is + * returned in dn on success. + * + * Device names consist of an URI + * Where: + * method = bjnp + * hostname = resolvable name or IP-address + * port = 8612 for a bjnp scanner, 8610 for a mfnp device + * An example could look like this: bjnp://host.domain:8612 + * + * @param devname name of the device to open + * @param dn device number + * + * @return + * - SANE_STATUS_GOOD - on success + * - SANE_STATUS_ACCESS_DENIED - if the file couldn't be accessed due to + * permissions + * - SANE_STATUS_INVAL - on every other error + */ +extern SANE_Status sanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn); + +/** Close a BJNP device. + * + * @param dn device number + */ + +extern void sanei_bjnp_close (SANE_Int dn); + +/** Activate a BJNP device connection + * + * @param dn device number + */ + +extern SANE_Status sanei_bjnp_activate (SANE_Int dn); + +/** De-activate a BJNP device connection + * + * @param dn device number + */ + +extern SANE_Status sanei_bjnp_deactivate (SANE_Int dn); + +/** Set the libbjnp timeout for bulk and interrupt reads. + * + * @param devno device number + * @param timeout the new timeout in ms + */ +extern void sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout); + +/** Check if sanei_bjnp_set_timeout() is available. + */ +#define HAVE_SANEI_BJNP_SET_TIMEOUT + +/** Initiate a bulk transfer read. + * + * Read up to size bytes from the device to buffer. After the read, size + * contains the number of bytes actually read. + * + * @param dn device number + * @param buffer buffer to store read data in + * @param size size of the data + * + * @return + * - SANE_STATUS_GOOD - on succes + * - SANE_STATUS_EOF - if zero bytes have been read + * - SANE_STATUS_IO_ERROR - if an error occured during the read + * - SANE_STATUS_INVAL - on every other error + * + */ +extern SANE_Status +sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size); + +/** Initiate a bulk transfer write. + * + * Write up to size bytes from buffer to the device. After the write size + * contains the number of bytes actually written. + * + * @param dn device number + * @param buffer buffer to write to device + * @param size size of the data + * + * @return + * - SANE_STATUS_GOOD - on succes + * - SANE_STATUS_IO_ERROR - if an error occured during the write + * - SANE_STATUS_INVAL - on every other error + */ +extern SANE_Status +sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size); + +/** Initiate a interrupt transfer read. + * + * Read up to size bytes from the interrupt endpoint from the device to + * buffer. After the read, size contains the number of bytes actually read. + * + * @param dn device number + * @param buffer buffer to store read data in + * @param size size of the data + * + * @return + * - SANE_STATUS_GOOD - on succes + * - SANE_STATUS_EOF - if zero bytes have been read + * - SANE_STATUS_IO_ERROR - if an error occured during the read + * - SANE_STATUS_INVAL - on every other error + * + */ + +extern SANE_Status +sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size); + +/*------------------------------------------------------*/ +#endif /* sanei_bjnp_h */ diff --git a/backend/pixma/pixma_bjnp_private.h b/backend/pixma/pixma_bjnp_private.h new file mode 100644 index 0000000..edfb330 --- /dev/null +++ b/backend/pixma/pixma_bjnp_private.h @@ -0,0 +1,384 @@ +/* SANE - Scanner Access Now Easy. + + Copyright (C) 2008 by Louis Lagendijk + + This file is part of the SANE package. + + Data structures and definitions for + bjnp backend for the Common UNIX Printing System (CUPS). + + These coded instructions, statements, and computer programs are the + property of Louis Lagendijk and are protected by Federal copyright + law. Distribution and use rights are outlined in the file "LICENSE.txt" + "LICENSE" which should have been included with this file. If this + file is missing or damaged, see the license at "http://www.cups.org/". + + This file is subject to the Apple OS-Developed Software exception. + + SANE 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. + + SANE 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 sane; see the file COPYING. If not, write to the Free + Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. +*/ + +/* + * BJNP definitions + */ + +/* selection of options */ +/* This works now, disable when it gives you problems */ +#define PIXMA_BJNP_USE_STATUS 1 + +/* sizes */ + +#define BJNP_PRINTBUF_MAX 1400 /* size of printbuffer */ +#define BJNP_CMD_MAX 2048 /* size of BJNP response buffer */ +#define BJNP_RESP_MAX 2048 /* size of BJNP response buffer */ +#define BJNP_SOCK_MAX 256 /* maximum number of open sockets */ +#define BJNP_MODEL_MAX 64 /* max allowed size for make&model */ +#define BJNP_STATUS_MAX 256 /* max size for status string */ +#define BJNP_IEEE1284_MAX 1024 /* max. allowed size of IEEE1284 id */ +#define BJNP_METHOD_MAX 16 /* max length of method */ +#define BJNP_HOST_MAX 128 /* max length of hostname or address */ +#define BJNP_PORT_MAX 64 /* max length of port string */ +#define BJNP_ARGS_MAX 128 /* max length of argument string */ +#define BJNP_SERIAL_MAX 16 /* maximum length of serial number */ +#define BJNP_NO_DEVICES 16 /* max number of open devices */ +#define BJNP_SCAN_BUF_MAX 65536 /* size of scanner data intermediate buffer */ +#define BJNP_BLOCKSIZE_START 512 /* startsize for last block detection */ + +/* timers */ +#define BJNP_BROADCAST_INTERVAL 10 /* ms between broadcasts */ +#define BJNP_BC_RESPONSE_TIMEOUT 500 /* waiting time for broadc. responses */ +#define BJNP_TIMEOUT_DEFAULT 10000 /* minimum tiemout value for network operations */ +#define BJNP_TIMEOUT_TCP_CONNECT 2000 /* timeout for tcp connect attempts in ms */ +#define BJNP_USLEEP_MS 1000 /* sleep for 1 msec */ +#define BJNP_TCP_CONNECT_INTERVAL 100 /* TCP retry interval in ms */ + +/* retries */ +#define BJNP_MAX_SELECT_ATTEMPTS 3 /* max nr of retries on select (EINTR) */ +#define BJNP_MAX_BROADCAST_ATTEMPTS 2 /* number of broadcast packets to be sent */ +#define BJNP_UDP_RETRY_MAX 3 /* max nt of retries on a udp command */ + +#define bjnp_dbg DBG +#include "../include/sane/sanei_debug.h" + +/* loglevel definitions */ + +#define LOG_CRIT 0 +#define LOG_NOTICE 1 +#define LOG_INFO 2 +#define LOG_DEBUG 3 +#define LOG_DEBUG2 4 +#define LOG_DEBUG3 5 + +#define BJNP_RESTART_POLL -1 + +/*************************************/ +/* BJNP protocol related definitions */ +/*************************************/ + +/* port numbers */ +typedef enum bjnp_port_e +{ + MFNP_PORT_SCAN = 8610, + BJNP_PORT_PRINT = 8611, + BJNP_PORT_SCAN = 8612, + BJNP_PORT_3 = 8613, + BJNP_PORT_4 = 8614 +} bjnp_port_t; + +typedef enum +{ + PROTOCOL_BJNP = 0, + PROTOCOL_MFNP = 1, + PROTOCOL_NONE =2 +} bjnp_protocol_t; + +typedef struct +{ + bjnp_protocol_t protocol_version; + int default_port; + char * proto_string; + char * method_string; +} bjnp_protocol_defs_t; + +bjnp_protocol_defs_t bjnp_protocol_defs[] = +{ + {PROTOCOL_BJNP, BJNP_PORT_SCAN,"BJNP", "bjnp"}, + {PROTOCOL_MFNP, MFNP_PORT_SCAN,"MFNP", "mfnp"}, + {PROTOCOL_NONE, -1, NULL, NULL} +}; + +/* commands */ +typedef enum bjnp_cmd_e +{ + CMD_UDP_DISCOVER = 0x01, /* discover if service type is listening at this port */ + CMD_UDP_START_SCAN = 0x02, /* start scan pressed, sent from scanner to 224.0.0.1 */ + CMD_UDP_JOB_DETAILS = 0x10, /* send print/ scanner job owner details */ + CMD_UDP_CLOSE = 0x11, /* request connection closure */ + CMD_UDP_GET_STATUS = 0x20, /* get printer status */ + CMD_TCP_REQ = 0x20, /* read data from device */ + CMD_TCP_SEND = 0x21, /* send data to device */ + CMD_UDP_GET_ID = 0x30, /* get printer identity */ + CMD_UDP_POLL = 0x32 /* poll scanner for button status */ +} bjnp_cmd_t; + +/* command type */ + +typedef enum uint8_t +{ + BJNP_CMD_PRINT = 0x1, /* printer command */ + BJNP_CMD_SCAN = 0x2, /* scanner command */ + BJNP_RES_PRINT = 0x81, /* printer response */ + BJNP_RES_SCAN = 0x82 /* scanner response */ +} bjnp_cmd_type_t; + +/***************************/ +/* BJNP protocol structure */ +/***************************/ + +/* The common protocol header */ + +struct __attribute__ ((__packed__)) BJNP_command +{ + char BJNP_id[4]; /* string: BJNP */ + uint8_t dev_type; /* 1 = printer, 2 = scanner */ + /* responses have MSB set */ + uint8_t cmd_code; /* command code/response code */ + int16_t unknown1; /* unknown, always 0? */ + int16_t seq_no; /* sequence number */ + uint16_t session_id; /* session id for printing */ + uint32_t payload_len; /* length of command buffer */ +}; + +/* Layout of the init response buffer */ + +struct __attribute__ ((__packed__)) DISCOVER_RESPONSE +{ + struct BJNP_command response; /* reponse header */ + char unknown1[4]; /* 00 01 08 00 */ + char mac_len; /* length of mac address */ + char addr_len; /* length of address field */ + unsigned char mac_addr[6]; /* printers mac address */ + union { + struct __attribute__ ((__packed__)) { + unsigned char ipv4_addr[4]; + } ipv4; + struct __attribute__ ((__packed__)) { + unsigned char ipv6_addr_1[16]; + unsigned char ipv6_addr_2[16]; + } ipv6; + } addresses; +}; + +/* layout of payload for the JOB_DETAILS command */ + +struct __attribute__ ((__packed__)) JOB_DETAILS +{ + struct BJNP_command cmd; /* command header */ + char unknown[8]; /* don't know what these are for */ + char hostname[64]; /* hostname of sender */ + char username[64]; /* username */ + char jobtitle[256]; /* job title */ +}; + +/* layout of the poll command, not everything is complete */ + +struct __attribute__ ((__packed__)) POLL_DETAILS +{ + struct BJNP_command cmd; /* command header */ + uint16_t type; /* 0, 1, 2 or 5 */ + /* 05 = reset status */ + union { + struct __attribute__ ((__packed__)) { + char empty0[78]; /* type 0 has only 0 */ + } type0; /* length = 80 */ + + struct __attribute__ ((__packed__)) { + char empty1[6]; /* 0 */ + char user_host[64]; /* unicode user hostname */ + uint64_t emtpy2; /* 0 */ + } type1; /* length = 80 */ + + struct __attribute__ ((__packed__)) { + uint16_t empty_1; /* 00 00 */ + uint32_t dialog; /* constant dialog id, from previous response */ + char user_host[64]; /* unicode user hostname */ + uint32_t unknown_1; /* 00 00 00 14 */ + uint32_t empty_2[5]; /* only 0 */ + uint32_t unknown_2; /* 00 00 00 10 */ + char ascii_date[16]; /* YYYYMMDDHHMMSS only for type 2 */ + } type2; /* length = 116 */ + + struct __attribute__ ((__packed__)) { + uint16_t empty_1; /* 00 00 */ + uint32_t dialog; /* constant dialog id, from previous response */ + char user_host[64]; /* unicode user hostname */ + uint32_t unknown_1; /* 00 00 00 14 */ + uint32_t key; /* copied from key field in status msg */ + uint32_t unknown_3[5]; /* only 0 */ + } type5; /* length = 100 */ + + } extensions; +}; + +/* the poll response layout */ + +struct __attribute__ ((__packed__)) POLL_RESPONSE +{ + struct BJNP_command cmd; /* command header */ + + unsigned char result[4]; /* unknown stuff, result[2] = 80 -> status is available*/ + /* result[8] is dialog, size? */ + uint32_t dialog; /* to be returned in next request */ + uint32_t unknown_2; /* returns the 00 00 00 14 from unknown_2 in request */ + uint32_t key; /* to be returned in type 5 status reset */ + unsigned char status[20]; /* interrupt status */ +}; + +/* Layout of ID and status responses */ + +struct __attribute__ ((__packed__)) IDENTITY +{ + struct BJNP_command cmd; + union __attribute__ ((__packed__)) + { + struct __attribute__ ((__packed__)) payload_s + { + uint16_t id_len; /* length of identity */ + char id[BJNP_IEEE1284_MAX]; /* identity */ + } bjnp; + struct __attribute__ ((__packed__)) mfnp + { + char id[BJNP_IEEE1284_MAX]; + } mfnp; + } payload; +}; + + +/* response to TCP print command */ + +struct __attribute__ ((__packed__)) SCAN_BUF +{ + struct BJNP_command cmd; + char scan_data[65536]; +}; + +/**************************/ +/* Local enum definitions */ +/**************************/ + +typedef enum bjnp_paper_status_e +{ + BJNP_PAPER_UNKNOWN = -1, + BJNP_PAPER_OK = 0, + BJNP_PAPER_OUT = 1 +} bjnp_paper_status_t; + +typedef enum +{ + BJNP_STATUS_GOOD, + BJNP_STATUS_INVAL, + BJNP_STATUS_ALREADY_ALLOCATED +} BJNP_Status; + +/* button polling */ + +typedef enum +{ + BJNP_POLL_STOPPED = 0, + BJNP_POLL_STARTED = 1, + BJNP_POLL_STATUS_RECEIVED = 2 +} BJNP_polling_status_e; + +typedef union +{ + struct sockaddr_storage storage; + struct sockaddr addr; + struct sockaddr_in ipv4; + struct sockaddr_in6 ipv6; +} bjnp_sockaddr_t; + +typedef enum +{ + BJNP_ADDRESS_IS_LINK_LOCAL = 0, + BJNP_ADDRESS_IS_GLOBAL = 1, + BJNP_ADDRESS_HAS_FQDN = 2 +} bjnp_address_type_t; + + +/* + * Device information for opened devices + */ + +typedef struct device_s +{ + int open; /* connection to scanner is opened */ + + /* protocol version */ + int protocol; + char *protocol_string; + + /* sockets */ + + int tcp_socket; /* open tcp socket for communcation to scannner */ + int16_t serial; /* sequence number of command */ + + /* communication state */ + + int session_id; /* session id used in bjnp protocol for TCP packets */ + int last_cmd; /* last command sent */ + + /* TCP bulk read state information */ + + size_t blocksize; /* size of (TCP) blocks returned by the scanner */ + size_t scanner_data_left; /* TCP data left from last read request */ + char last_block; /* last TCP read command was shorter than blocksize */ + + /* device information */ + char mac_address[BJNP_HOST_MAX]; + /* mac-address, used as device serial no */ + bjnp_sockaddr_t * addr; /* ip-address of the scanner */ + int address_level; /* link local, public or has a FQDN */ + int bjnp_scanner_timeout; /* timeout (msec) for next poll command */ + int bjnp_ip_timeout; /* device specific min timeout for the IP-protocol */ + +#ifdef PIXMA_BJNP_USE_STATUS + /* polling state information */ + + char polling_status; /* status polling ongoing */ + uint32_t dialog; /* poll dialog */ + uint32_t status_key; /* key of last received status message */ +#endif +} bjnp_device_t; diff --git a/backend/pixma/pixma_common.c b/backend/pixma/pixma_common.c new file mode 100644 index 0000000..7b7ecec --- /dev/null +++ b/backend/pixma/pixma_common.c @@ -0,0 +1,1187 @@ +/* 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 +#include +#include /* pow(C90) */ + +#include /* gettimeofday(4.3BSD) */ +#include /* usleep */ + +#include "pixma_rename.h" +#include "pixma_common.h" +#include "pixma_io.h" + +#include "../include/sane/sanei_usb.h" +#include "../include/sane/sane.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_mp800_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_mp800_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(jout_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, SANE_Bool local_only) +{ + return pixma_collect_devices (conf_devices, pixma_devices, local_only); +} + +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); +} diff --git a/backend/pixma/pixma_common.h b/backend/pixma/pixma_common.h new file mode 100644 index 0000000..c0ed4ba --- /dev/null +++ b/backend/pixma/pixma_common.h @@ -0,0 +1,232 @@ +/* SANE - Scanner Access Now Easy. + + Copyright (C) 2011-2019 Rolf Bensch + 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. + */ +#ifndef PIXMA_COMMON_H +#define PIXMA_COMMON_H + + +#include /* time_t */ +#include "pixma.h" + + +/*! \defgroup subdriver Subdriver Interface + * \brief Subdriver interface. */ + +/*! \defgroup debug Debug utilities + * \brief Debug utilities. */ + +#ifdef NDEBUG +# define PDBG(x) do {} while(0) +# define PASSERT(x) do {} while(0) +#else +# define PDBG(x) x +# define PASSERT(x) do { \ + if (!(x)) \ + pixma_dbg(1, "ASSERT failed:%s:%d: " \ + #x "\n", __FILE__, __LINE__); \ + } while(0) +#endif + + +#define PIXMA_STATUS_OK 0x0606 +#define PIXMA_STATUS_FAILED 0x1515 +#define PIXMA_STATUS_BUSY 0x1414 + +#define PIXMA_MAX_ID_LEN 30 + +/* These may have been defined elsewhere */ +#ifndef MIN +#define MIN(x,y) (((x) < (y)) ? (x):(y)) +#endif +#ifndef MAX +#define MAX(x,y) (((x) < (y)) ? (y):(x)) +#endif +#define ALIGN_SUP(x,n) (((x) + (n) - 1) / (n) * (n)) +#define ALIGN_INF(x,n) (((x) / (n)) * (n)) + +struct pixma_io_t; + +struct pixma_limits_t +{ + unsigned xdpi, ydpi; + unsigned width, height; +}; + +struct pixma_cmdbuf_t +{ + unsigned cmd_header_len, res_header_len, cmd_len_field_ofs; + unsigned expected_reslen, cmdlen; + int reslen; + unsigned size; + uint8_t *buf; +}; + +struct pixma_imagebuf_t +{ + uint8_t *wptr, *wend; + const uint8_t *rptr, *rend; +}; + +struct pixma_t +{ + pixma_t *next; + struct pixma_io_t *io; + const pixma_scan_ops_t *ops; + pixma_scan_param_t *param; + const pixma_config_t *cfg; + char id[PIXMA_MAX_ID_LEN + 1]; + int cancel; /* NOTE: It can be set in a signal handler. */ + uint32_t events; + void *subdriver; /* can be used by model driver. */ + int rec_tmo; /* receive timeout [s] */ + + /* private */ + uint64_t cur_image_size; + pixma_imagebuf_t imagebuf; + unsigned scanning:1; + unsigned underrun:1; +}; + +/** \addtogroup subdriver + * @{ */ +/** Scan operations for subdriver. */ +struct pixma_scan_ops_t +{ + /** Allocate a data structure for the subdriver. It is called after the + * core driver connected to the scanner. The subdriver should reset the + * scanner to a known state in this function. */ + int (*open) (pixma_t *); + + /** Free resources allocated by the subdriver. Don't forget to send abort + * command to the scanner if it is scanning. */ + void (*close) (pixma_t *); + + /** Setup the scanner for scan parameters defined in \a s->param. */ + int (*scan) (pixma_t * s); + + /** Fill a buffer with image data. The subdriver has two choices: + * -# Fill the buffer pointed by ib->wptr directly and leave + * ib->rptr and ib->rend untouched. The length of the buffer is + * ib->wend - ib->wptr. It must update ib->wptr accordingly. + * -# Update ib->rptr and ib->rend to point to the beginning and + * the end of the internal buffer resp. The length of the buffer + * is ib->rend - ib->rptr. This function is called again if + * and only if pixma_read_image() has copied the whole buffer. + * + * The subdriver must wait until there is at least one byte to read or + * return 0 for the end of image. */ + int (*fill_buffer) (pixma_t *, pixma_imagebuf_t * ib); + + /** Cancel the scan operation if necessary and free resources allocated in + * scan(). */ + void (*finish_scan) (pixma_t *); + + /** [Optional] Wait for a user's event, e.g. button event. \a timeout is + * in milliseconds. If an event occured before it's timed out, flags in + * \a s->events should be set accordingly. + * \see PIXMA_EV_* */ + void (*wait_event) (pixma_t * s, int timeout); + + /** Check the scan parameters. The parameters can be adjusted if they are + * out of range, e.g. width > max_width. */ + int (*check_param) (pixma_t *, pixma_scan_param_t *); + + /** Read the device status. \see pixma_get_device_status() */ + int (*get_status) (pixma_t *, pixma_device_status_t *); +}; + + +/** \name Funtions for read and write big-endian integer values */ +/**@{*/ +void pixma_set_be16 (uint16_t x, uint8_t * buf); +void pixma_set_be32 (uint32_t x, uint8_t * buf); +uint16_t pixma_get_be16 (const uint8_t * buf); +uint32_t pixma_get_be32 (const uint8_t * buf); +/**@}*/ + +/** \name Utility functions */ +/**@{*/ +uint8_t pixma_sum_bytes (const void *data, unsigned len); +int pixma_check_dpi (unsigned dpi, unsigned max); +void pixma_sleep (unsigned long usec); +void pixma_get_time (time_t * sec, uint32_t * usec); +uint8_t * pixma_r_to_ir (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c); +uint8_t * pixma_rgb_to_gray (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c); +uint8_t * pixma_binarize_line(pixma_scan_param_t *, uint8_t * dst, uint8_t * src, unsigned width, unsigned c); +/**@}*/ + +/** \name Command related functions */ +/**@{*/ +int pixma_cmd_transaction (pixma_t *, const void *cmd, unsigned cmdlen, + void *data, unsigned expected_len); +int pixma_check_result (pixma_cmdbuf_t *); +uint8_t *pixma_newcmd (pixma_cmdbuf_t *, unsigned cmd, + unsigned dataout, unsigned datain); +int pixma_exec (pixma_t *, pixma_cmdbuf_t *); +int pixma_exec_short_cmd (pixma_t *, pixma_cmdbuf_t *, unsigned cmd); +int pixma_map_status_errno (unsigned status); +/**@}*/ + +#define pixma_fill_checksum(start, end) do { \ + *(end) = -pixma_sum_bytes(start, (end)-(start)); \ +} while(0) + +/** @} end of group subdriver */ + +/** \addtogroup debug + * @{ */ +void pixma_set_debug_level (int level); +#ifndef NDEBUG +void pixma_hexdump (int level, const void *d_, unsigned len); + +/* len: length of data or error code. + size: if >= 0, force to print 'size' bytes. + max: maximum number of bytes to print(-1 means no limit). */ +void pixma_dump (int level, const char *type, const void *data, int len, + int size, int max); +# define DEBUG_DECLARE_ONLY +# include "../include/sane/sanei_debug.h" +#endif /* NDEBUG */ +/** @} end of group debug */ + +#endif diff --git a/backend/pixma/pixma_imageclass.c b/backend/pixma/pixma_imageclass.c new file mode 100644 index 0000000..ce0c37d --- /dev/null +++ b/backend/pixma/pixma_imageclass.c @@ -0,0 +1,985 @@ +/* SANE - Scanner Access Now Easy. + + Copyright (C) 2011-2019 Rolf Bensch + Copyright (C) 2007-2009 Nicolas Martin, + Copyright (C) 2008 Dennis Lou, dlou 99 at yahoo dot com + + 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. + */ + +/* + * imageCLASS backend based on pixma_mp730.c + */ + +#include "../include/sane/config.h" + +#include +#include +#include + +#include "pixma_rename.h" +#include "pixma_common.h" +#include "pixma_io.h" + + +#ifdef __GNUC__ +# define UNUSED(v) (void) v +#else +# define UNUSED(v) +#endif + +#define IMAGE_BLOCK_SIZE (0x80000) +#define MAX_CHUNK_SIZE (0x1000) +#define MIN_CHUNK_SIZE (0x0200) +#define CMDBUF_SIZE 512 + +#define MF4100_PID 0x26a3 +#define MF4600_PID 0x26b0 +#define MF4010_PID 0x26b4 +#define MF4200_PID 0x26b5 +#define MF4360_PID 0x26ec +#define D480_PID 0x26ed +#define MF4320_PID 0x26ee +#define D420_PID 0x26ef +#define MF3200_PID 0x2684 +#define MF6500_PID 0x2686 +/* generation 2 scanners (>=0x2707) */ +#define MF8300_PID 0x2708 +#define MF4500_PID 0x2736 +#define MF4410_PID 0x2737 +#define D550_PID 0x2738 +#define MF3010_PID 0x2759 +#define MF4570_PID 0x275a +#define MF4800_PID 0x2773 +#define MF4700_PID 0x2774 +#define MF8200_PID 0x2779 +/* the following are all untested */ +#define MF5630_PID 0x264e +#define MF5650_PID 0x264f +#define MF8100_PID 0x2659 +#define MF5880_PID 0x26f9 +#define MF6680_PID 0x26fa +#define MF8030_PID 0x2707 +#define IR1133_PID 0x2742 +#define MF5900_PID 0x2743 +#define D530_PID 0x2775 +#define MF8500_PID 0x277a +#define MF6100_PID 0x278e +#define MF820_PID 0x27a6 +#define MF220_PID 0x27a8 +#define MF210_PID 0x27a9 +#define MF620_PID 0x27b4 +#define MF410_PID 0x27c0 +#define MF510_PID 0x27c2 +#define MF230_PID 0x27d1 +#define MF240_PID 0x27d2 +#define MF630_PID 0x27e1 +#define MF634_PID 0x27e2 +#define MF730_PID 0x27e4 +#define MF731_PID 0x27e5 +#define D570_PID 0x27e8 +#define MF110_PID 0x27ed +#define MF520_PID 0x27f0 +#define MF420_PID 0x27f1 +#define MF260_PID 0x27f4 +#define MF740_PID 0x27fb +#define MF743_PID 0x27fc +#define MF640_PID 0x27fe +#define MF645_PID 0x27fd + + +enum iclass_state_t +{ + state_idle, + state_warmup, /* MF4200 always warm/calibrated; others? */ + state_scanning, + state_finished +}; + +enum iclass_cmd_t +{ + cmd_start_session = 0xdb20, + cmd_select_source = 0xdd20, + cmd_scan_param = 0xde20, + cmd_status = 0xf320, + cmd_abort_session = 0xef20, + cmd_read_image = 0xd420, + cmd_read_image2 = 0xd460, /* New multifunctionals, such as MF4410 */ + cmd_error_info = 0xff20, + + cmd_activate = 0xcf60 +}; + +typedef struct iclass_t +{ + enum iclass_state_t state; + pixma_cmdbuf_t cb; + unsigned raw_width; + uint8_t current_status[12]; + + uint8_t *buf, *blkptr, *lineptr; + unsigned buf_len, blk_len; + + unsigned last_block; + + uint8_t generation; /* New multifunctionals are (generation == 2) */ + + uint8_t adf_state; /* handle adf scanning */ +} iclass_t; + + +static int is_scanning_from_adf (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_ADF + || s->param->source == PIXMA_SOURCE_ADFDUP); +} + +static int is_scanning_from_adfdup (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_ADFDUP); +} + +static void iclass_finish_scan (pixma_t * s); + +/* checksumming is sometimes different than pixmas */ +static int +iclass_exec (pixma_t * s, pixma_cmdbuf_t * cb, char invcksum) +{ + if (cb->cmdlen > cb->cmd_header_len) + pixma_fill_checksum (cb->buf + cb->cmd_header_len, + cb->buf + cb->cmdlen - 2); + cb->buf[cb->cmdlen - 1] = invcksum ? -cb->buf[cb->cmdlen - 2] : 0; + cb->reslen = + pixma_cmd_transaction (s, cb->buf, cb->cmdlen, cb->buf, + cb->expected_reslen); + return pixma_check_result (cb); +} + +static int +has_paper (pixma_t * s) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + return ((mf->current_status[1] & 0x0f) == 0 /* allow 0x10 as ADF paper OK */ + || mf->current_status[1] == 81); /* allow 0x51 as ADF paper OK */ +} + +static int +abort_session (pixma_t * s) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mf->cb, cmd_abort_session); +} + +static int +query_status (pixma_t * s) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mf->cb, cmd_status, 0, 12); + error = pixma_exec (s, &mf->cb); + if (error >= 0) + { + memcpy (mf->current_status, data, 12); + /*DBG (3, "Current status: paper=0x%02x cal=%u lamp=%u\n", + data[1], data[8], data[7]);*/ + PDBG (pixma_dbg (3, "Current status: paper=0x%02x cal=%u lamp=%u\n", + data[1], data[8], data[7])); + } + return error; +} + +static int +activate (pixma_t * s, uint8_t x) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + uint8_t *data = pixma_newcmd (&mf->cb, cmd_activate, 10, 0); + data[0] = 1; + data[3] = x; + switch (s->cfg->pid) + { + case MF4200_PID: + case MF4600_PID: + case MF6500_PID: + case D480_PID: + case D420_PID: + case MF4360_PID: + case MF4100_PID: + case MF8300_PID: + return iclass_exec (s, &mf->cb, 1); + break; + default: + return pixma_exec (s, &mf->cb); + } +} + +static int +start_session (pixma_t * s) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mf->cb, cmd_start_session); +} + +static int +select_source (pixma_t * s) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + uint8_t *data = pixma_newcmd (&mf->cb, cmd_select_source, 10, 0); + data[0] = (is_scanning_from_adf(s)) ? 2 : 1; + /* special settings for MF6100 */ + data[5] = is_scanning_from_adfdup(s) ? 3 : ((s->cfg->pid == MF6100_PID && s->param->source == PIXMA_SOURCE_ADF) ? 1 : 0); + switch (s->cfg->pid) + { + case MF4200_PID: + case MF4600_PID: + case MF6500_PID: + case D480_PID: + case D420_PID: + case MF4360_PID: + case MF4100_PID: + case MF8300_PID: + return iclass_exec (s, &mf->cb, 0); + break; + default: + return pixma_exec (s, &mf->cb); + } +} + +static int +send_scan_param (pixma_t * s) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + uint8_t *data; + + data = pixma_newcmd (&mf->cb, cmd_scan_param, 0x2e, 0); + pixma_set_be16 (s->param->xdpi | 0x1000, data + 0x04); + pixma_set_be16 (s->param->ydpi | 0x1000, data + 0x06); + pixma_set_be32 (s->param->x, data + 0x08); + pixma_set_be32 (s->param->y, data + 0x0c); + pixma_set_be32 (mf->raw_width, data + 0x10); + pixma_set_be32 (s->param->h, data + 0x14); + data[0x18] = (s->param->channels == 1) ? 0x04 : 0x08; + data[0x19] = s->param->channels * ((s->param->depth == 1) ? 8 : s->param->depth); /* bits per pixel */ + data[0x1f] = 0x7f; + data[0x20] = 0xff; + data[0x23] = 0x81; + switch (s->cfg->pid) + { + case MF4200_PID: + case MF4600_PID: + case MF6500_PID: + case D480_PID: + case D420_PID: + case MF4360_PID: + case MF4100_PID: + case MF8300_PID: + return iclass_exec (s, &mf->cb, 0); + break; + default: + return pixma_exec (s, &mf->cb); + } +} + +static int +request_image_block (pixma_t * s, unsigned flag, uint8_t * info, + unsigned * size, uint8_t * data, unsigned * datalen) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + int error; + unsigned expected_len; + const int hlen = 2 + 6; + + memset (mf->cb.buf, 0, 11); + /* generation 2 scanners use cmd_read_image2. + * MF6100, ... are exceptions */ + pixma_set_be16 (((mf->generation >= 2 + && s->cfg->pid != MF6100_PID) ? cmd_read_image2 : cmd_read_image), mf->cb.buf); + mf->cb.buf[8] = flag; + mf->cb.buf[10] = 0x06; + expected_len = (mf->generation >= 2 || + s->cfg->pid == MF4600_PID || + s->cfg->pid == MF6500_PID || + s->cfg->pid == MF8030_PID) ? 512 : hlen; + mf->cb.reslen = pixma_cmd_transaction (s, mf->cb.buf, 11, mf->cb.buf, expected_len); + if (mf->cb.reslen >= hlen) + { + *info = mf->cb.buf[2]; + *size = pixma_get_be16 (mf->cb.buf + 6); /* 16bit size */ + error = 0; + + if (mf->generation >= 2 || + s->cfg->pid == MF4600_PID || + s->cfg->pid == MF6500_PID || + s->cfg->pid == MF8030_PID) + { /* 32bit size */ + *datalen = mf->cb.reslen - hlen; + *size = (*datalen + hlen == 512) ? pixma_get_be32 (mf->cb.buf + 4) - *datalen : *size; + memcpy (data, mf->cb.buf + hlen, *datalen); + } + PDBG (pixma_dbg (11, "*request_image_block***** size = %u *****\n", *size)); + } + else + { + error = PIXMA_EPROTO; + } + return error; +} + +static int +read_image_block (pixma_t * s, uint8_t * data, unsigned size) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + int error; + unsigned maxchunksize, chunksize, count = 0; + + maxchunksize = MAX_CHUNK_SIZE * ((mf->generation >= 2 || + s->cfg->pid == MF4600_PID || + s->cfg->pid == MF6500_PID || + s->cfg->pid == MF8030_PID) ? 4 : 1); + while (size) + { + if (size >= maxchunksize) + chunksize = maxchunksize; + else if (size < MIN_CHUNK_SIZE) + chunksize = size; + else + chunksize = size - (size % MIN_CHUNK_SIZE); + error = pixma_read (s->io, data, chunksize); + if (error < 0) + return count; + count += error; + data += error; + size -= error; + } + return count; +} + +static int +read_error_info (pixma_t * s, void *buf, unsigned size) +{ + unsigned len = 16; + iclass_t *mf = (iclass_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mf->cb, cmd_error_info, 0, len); + switch (s->cfg->pid) + { + case MF4200_PID: + case MF4600_PID: + case MF6500_PID: + case D480_PID: + case D420_PID: + case MF4360_PID: + case MF4100_PID: + case MF8300_PID: + error = iclass_exec (s, &mf->cb, 0); + break; + default: + error = pixma_exec (s, &mf->cb); + } + if (error < 0) + return error; + if (buf && len < size) + { + size = len; + /* NOTE: I've absolutely no idea what the returned data mean. */ + memcpy (buf, data, size); + error = len; + } + return error; +} + +static int +handle_interrupt (pixma_t * s, int timeout) +{ + uint8_t buf[16]; + int len; + + len = pixma_wait_interrupt (s->io, buf, sizeof (buf), timeout); + if (len == PIXMA_ETIMEDOUT) + return 0; + if (len < 0) + return len; + if (len != 16) + { + PDBG (pixma_dbg + (1, "WARNING:unexpected interrupt packet length %d\n", len)); + return PIXMA_EPROTO; + } + if (buf[12] & 0x40) + query_status (s); + if (buf[15] & 1) + s->events = PIXMA_EV_BUTTON1; + return 1; +} + +static int +step1 (pixma_t * s) +{ + int error; + int rec_tmo; + iclass_t *mf = (iclass_t *) s->subdriver; + + /* don't wait full timeout for 1st command */ + rec_tmo = s->rec_tmo; /* save globel timeout */ + s->rec_tmo = 2; /* set timeout to 2 seconds */ + error = query_status (s); + s->rec_tmo = rec_tmo; /* restore global timeout */ + if (error < 0) + { + PDBG (pixma_dbg (1, "WARNING: Resend first USB command after timeout!\n")); + error = query_status (s); + } + if (error < 0) + return error; + + /* wait for inserted paper */ + if (s->param->adf_wait != 0 && is_scanning_from_adf(s)) + { + int tmo = s->param->adf_wait; + + while (!has_paper (s) && --tmo >= 0 && !s->param->frontend_cancel) + { + if ((error = query_status (s)) < 0) + return error; + pixma_sleep (1000000); + PDBG (pixma_dbg(2, "No paper in ADF. Timed out in %d sec.\n", tmo)); + } + /* canceled from frontend */ + if (s->param->frontend_cancel) + { + return PIXMA_ECANCELED; + } + } + /* no paper inserted + * => abort session */ + if (is_scanning_from_adf(s) && !has_paper (s)) + { + return PIXMA_ENO_PAPER; + } + /* activate only seen for generation 1 scanners */ + if (mf->generation == 1) + { + if (error >= 0) + error = activate (s, 0); + if (error >= 0) + error = activate (s, 4); + } + return error; +} + +/* line in=rrr... ggg... bbb... line out=rgbrgbrgb... */ +static void +pack_rgb (const uint8_t * src, unsigned nlines, unsigned w, uint8_t * dst) +{ + unsigned w2, stride; + + w2 = 2 * w; + stride = 3 * w; + for (; nlines != 0; nlines--) + { + unsigned x; + for (x = 0; x != w; x++) + { + *dst++ = src[x + 0]; + *dst++ = src[x + w]; + *dst++ = src[x + w2]; + } + src += stride; + } +} + +static int +iclass_open (pixma_t * s) +{ + iclass_t *mf; + uint8_t *buf; + + mf = (iclass_t *) calloc (1, sizeof (*mf)); + if (!mf) + return PIXMA_ENOMEM; + + buf = (uint8_t *) malloc (CMDBUF_SIZE); + if (!buf) + { + free (mf); + return PIXMA_ENOMEM; + } + + s->subdriver = mf; + mf->state = state_idle; + + mf->cb.buf = buf; + mf->cb.size = CMDBUF_SIZE; + mf->cb.res_header_len = 2; + mf->cb.cmd_header_len = 10; + mf->cb.cmd_len_field_ofs = 7; + + /* adf scanning */ + mf->adf_state = state_idle; + + /* set generation = 2 for new multifunctionals */ + mf->generation = (s->cfg->pid >= MF8030_PID) ? 2 : 1; + PDBG (pixma_dbg (3, "*iclass_open***** This is a generation %d scanner. *****\n", mf->generation)); + + PDBG (pixma_dbg (3, "Trying to clear the interrupt buffer...\n")); + if (handle_interrupt (s, 200) == 0) + { + PDBG (pixma_dbg (3, " no packets in buffer\n")); + } + return 0; +} + +static void +iclass_close (pixma_t * s) +{ + iclass_t *mf = (iclass_t *) s->subdriver; + + iclass_finish_scan (s); + free (mf->cb.buf); + free (mf->buf); + free (mf); + s->subdriver = NULL; +} + +static int +iclass_check_param (pixma_t * s, pixma_scan_param_t * sp) +{ + UNUSED (s); + + /* PDBG (pixma_dbg (4, "*iclass_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, line_size=%" PRIu64 " , h=%u*****\n", + sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->line_size, sp->h)); */ + + sp->depth = 8; + sp->software_lineart = 0; + if (sp->mode == PIXMA_SCAN_MODE_LINEART) + { + sp->software_lineart = 1; + sp->channels = 1; + sp->depth = 1; + } + + if (sp->software_lineart == 1) + { + unsigned w_max; + + /* for software lineart line_size and w must be a multiple of 8 */ + sp->line_size = ALIGN_SUP (sp->w, 8) * sp->channels; + sp->w = ALIGN_SUP (sp->w, 8); + + /* do not exceed the scanner capability */ + w_max = s->cfg->width * s->cfg->xdpi / 75; + w_max -= w_max % 32; + if (sp->w > w_max) + sp->w = w_max; + } + else + sp->line_size = ALIGN_SUP (sp->w, 32) * sp->channels; + + /* Some exceptions here for particular devices */ + /* Those devices can scan up to Legal 14" with ADF, but A4 11.7" in flatbed */ + /* PIXMA_CAP_ADF also works for PIXMA_CAP_ADFDUP */ + if ((s->cfg->cap & PIXMA_CAP_ADF) && sp->source == PIXMA_SOURCE_FLATBED) + sp->h = MIN (sp->h, 877 * sp->xdpi / 75); + + /* PDBG (pixma_dbg (4, "*iclass_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, line_size=%" PRIu64 " , h=%u*****\n", + sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->line_size, sp->h)); */ + + return 0; +} + +static int +iclass_scan (pixma_t * s) +{ + int error, n; + iclass_t *mf = (iclass_t *) s->subdriver; + uint8_t *buf, ignore; + unsigned buf_len, ignore2; + + if (mf->state != state_idle) + return PIXMA_EBUSY; + + /* clear interrupt packets buffer */ + while (handle_interrupt (s, 0) > 0) + { + } + + mf->raw_width = ALIGN_SUP (s->param->w, 32); + PDBG (pixma_dbg (3, "raw_width = %u\n", mf->raw_width)); + + n = IMAGE_BLOCK_SIZE / s->param->line_size + 1; + buf_len = (n + 1) * s->param->line_size + IMAGE_BLOCK_SIZE; + if (buf_len > mf->buf_len) + { + buf = (uint8_t *) realloc (mf->buf, buf_len); + if (!buf) + return PIXMA_ENOMEM; + mf->buf = buf; + mf->buf_len = buf_len; + } + mf->lineptr = mf->buf; + mf->blkptr = mf->buf + n * s->param->line_size; + mf->blk_len = 0; + + error = step1 (s); + if (error >= 0 + && (s->param->adf_pageid == 0 || mf->generation == 1 || mf->adf_state == state_idle)) + { /* single sheet or first sheet from ADF */ + PDBG (pixma_dbg (3, "*iclass_scan***** start scanning *****\n")); + error = start_session (s); + if (error >= 0) + mf->state = state_scanning; + if (error >= 0) + error = select_source (s); + } + else if (error >= 0) + { /* next sheet from ADF */ + PDBG (pixma_dbg (3, "*iclass_scan***** scan next sheet from ADF *****\n")); + mf->state = state_scanning; + } + if (error >= 0) + error = send_scan_param (s); + if (error >= 0) + error = request_image_block (s, 0, &ignore, &ignore2, &ignore, &ignore2); + if (error < 0) + { + iclass_finish_scan (s); + return error; + } + mf->last_block = 0; + + /* ADF scanning active */ + if (is_scanning_from_adf (s)) + mf->adf_state = state_scanning; + return 0; +} + + +static int +iclass_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) +{ + int error, n; + iclass_t *mf = (iclass_t *) s->subdriver; + unsigned block_size, lines_size, lineart_lines_size, first_block_size; + uint8_t info; + +/* + * 1. send a block request cmd (d4 20 00... 04 00 06) + * 2. examine the response for block size and/or end-of-scan flag + * 3. read the block one chunk at a time + * 4. repeat until have enough to process >=1 lines + */ + do + { + do + { + if (s->cancel) + return PIXMA_ECANCELED; + if (mf->last_block) + { + /* end of image */ + mf->state = state_finished; + return 0; + } + + first_block_size = 0; + error = request_image_block (s, 4, &info, &block_size, + mf->blkptr + mf->blk_len, &first_block_size); + /* add current block to remainder of previous */ + mf->blk_len += first_block_size; + if (error < 0) + { + /* NOTE: seen in traffic logs but don't know the meaning. */ + read_error_info (s, NULL, 0); + if (error == PIXMA_ECANCELED) + return error; + } + + /* info: 0x28 = end; 0x38 = end + ADF empty */ + mf->last_block = info & 0x38; + if ((info & ~0x38) != 0) + { + PDBG (pixma_dbg (1, "WARNING: Unexpected result header\n")); + PDBG (pixma_hexdump (1, &info, 1)); + } + + if (block_size == 0) + { + /* no image data at this moment. */ + /*pixma_sleep(100000); *//* FIXME: too short, too long? */ + handle_interrupt (s, 100); + } + } + while (block_size == 0 && first_block_size == 0); + + error = read_image_block (s, mf->blkptr + mf->blk_len, block_size); + block_size = error; + if (error < 0) + return error; + + /* add current block to remainder of previous */ + mf->blk_len += block_size; + /* n = number of full lines (rows) we have in the buffer. */ + n = mf->blk_len / ((s->param->mode == PIXMA_SCAN_MODE_LINEART) ? mf->raw_width : s->param->line_size); + if (n != 0) + { + /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** Processing with n=%d, w=%i, line_size=%" PRIu64 ", raw_width=%u ***** \n", + n, s->param->w, s->param->line_size, mf->raw_width)); */ + /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** scan_mode=%d, lineptr=%" PRIu64 ", blkptr=%" PRIu64 " \n", + s->param->mode, (uint64_t)mf->lineptr, (uint64_t)mf->blkptr)); */ + + /* gray to lineart convert + * mf->lineptr : image line + * mf->blkptr : scanned image block as grayscale + * s->param->w : image width + * s->param->line_size : scanned image width */ + if (s->param->mode == PIXMA_SCAN_MODE_LINEART) + { + int i; + uint8_t *sptr, *dptr; + + /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** Processing lineart *****\n")); */ + + /* process ALL lines */ + sptr = mf->blkptr; + dptr = mf->lineptr; + for (i = 0; i < n; i++, sptr += mf->raw_width) + dptr = pixma_binarize_line (s->param, dptr, sptr, s->param->line_size, 1); + } + else if (s->param->channels != 1 && + mf->generation == 1 && + s->cfg->pid != MF4600_PID && + s->cfg->pid != MF6500_PID && + s->cfg->pid != MF8030_PID) + { + /* color and not MF46xx or MF65xx */ + pack_rgb (mf->blkptr, n, mf->raw_width, mf->lineptr); + } + else + { + /* grayscale */ + memcpy (mf->lineptr, mf->blkptr, n * s->param->line_size); + } + /* cull remainder and shift left */ + lineart_lines_size = n * s->param->line_size / 8; + lines_size = n * ((s->param->mode == PIXMA_SCAN_MODE_LINEART) ? mf->raw_width : s->param->line_size); + mf->blk_len -= lines_size; + memcpy (mf->blkptr, mf->blkptr + lines_size, mf->blk_len); + } + } + while (n == 0); + + /* output full lines, keep partial lines for next block + * ib->rptr : start of image buffer + * ib->rend : end of image buffer */ + ib->rptr = mf->lineptr; + ib->rend = mf->lineptr + (s->param->mode == PIXMA_SCAN_MODE_LINEART ? lineart_lines_size : lines_size); + /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** rptr=%" PRIu64 ", rend=%" PRIu64 ", diff=%ld \n", + (uint64_t)ib->rptr, (uint64_t)ib->rend, ib->rend - ib->rptr)); */ + return ib->rend - ib->rptr; +} + +static void +iclass_finish_scan (pixma_t * s) +{ + int error; + iclass_t *mf = (iclass_t *) s->subdriver; + + switch (mf->state) + { + /* fall through */ + case state_warmup: + case state_scanning: + error = abort_session (s); + if (error < 0) + PDBG (pixma_dbg + (1, "WARNING:abort_session() failed %s\n", + pixma_strerror (error))); + /* fall through */ + case state_finished: + query_status (s); + query_status (s); + if (mf->generation == 1) + { /* activate only seen for generation 1 scanners */ + activate (s, 0); + query_status (s); + } + /* generation = 1: + * 0x28 = last block (no multi page scan) + * generation >= 2: + * 0x38 = last block and ADF empty (generation >= 2) + * 0x28 = last block and Paper in ADF (multi page scan) + * some generation 2 scanners don't use 0x38 for ADF empty => check status */ + if (mf->last_block==0x38 /* generation 2 scanner ADF empty */ + || (mf->generation == 1 && mf->last_block == 0x28) /* generation 1 scanner last block */ + || (mf->generation >= 2 && !has_paper(s))) /* check status: no paper in ADF */ + { + /* ADFDUP scan: wait for 8sec to throw last page out of ADF feeder */ + if (is_scanning_from_adfdup(s)) + { + PDBG (pixma_dbg (4, "*iclass_finish_scan***** sleep for 8s *****\n")); + pixma_sleep(8000000); /* sleep for 8s */ + query_status (s); + } + PDBG (pixma_dbg (3, "*iclass_finish_scan***** abort session *****\n")); + abort_session (s); + mf->adf_state = state_idle; + mf->last_block = 0; + } + else + PDBG (pixma_dbg (3, "*iclass_finish_scan***** wait for next page from ADF *****\n")); + + mf->state = state_idle; + /* fall through */ + case state_idle: + break; + } +} + +static void +iclass_wait_event (pixma_t * s, int timeout) +{ + /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for + * instance. */ + while (s->events == 0 && handle_interrupt (s, timeout) > 0) + { + } +} + +static int +iclass_get_status (pixma_t * s, pixma_device_status_t * status) +{ + int error; + + error = query_status (s); + if (error < 0) + return error; + status->hardware = PIXMA_HARDWARE_OK; + status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; + return 0; +} + + +static const pixma_scan_ops_t pixma_iclass_ops = { + iclass_open, + iclass_close, + iclass_scan, + iclass_fill_buffer, + iclass_finish_scan, + iclass_wait_event, + iclass_check_param, + iclass_get_status +}; + +#define DEV(name, model, pid, dpi, adftpu_max_dpi, w, h, cap) { \ + name, /* name */ \ + model, /* model */ \ + 0x04a9, pid, /* vid pid */ \ + 1, /* iface */ \ + &pixma_iclass_ops, /* ops */ \ + 0, /* min_xdpi not used in this subdriver */ \ + dpi, dpi, /* xdpi, ydpi */ \ + 0, /* adftpu_min_dpi not used in this subdriver */ \ + adftpu_max_dpi, /* adftpu_max_dpi */ \ + 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ + w, h, /* width, height */ \ + PIXMA_CAP_LINEART| /* all scanners have software lineart */ \ + PIXMA_CAP_ADF_WAIT| /* adf wait for all ADF and ADFDUP scanners */ \ + PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ +} +const pixma_config_t pixma_iclass_devices[] = { + DEV ("Canon imageCLASS MF4270", "MF4270", MF4200_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS MF4150", "MF4100", MF4100_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS MF4690", "MF4690", MF4600_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS D420", "D420", D420_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), + DEV ("Canon imageCLASS D480", "D480", D480_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), + DEV ("Canon imageCLASS MF4360", "MF4360", MF4360_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), + DEV ("Canon imageCLASS MF4320", "MF4320", MF4320_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS MF4010", "MF4010", MF4010_PID, 600, 0, 640, 877, 0), + DEV ("Canon imageCLASS MF3240", "MF3240", MF3200_PID, 600, 0, 640, 877, 0), + DEV ("Canon imageClass MF6500", "MF6500", MF6500_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS MF4410", "MF4410", MF4410_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS D550", "D550", D550_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF4500 Series", "MF4500", MF4500_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF3010", "MF3010", MF3010_PID, 600, 0, 640, 877, 0), + DEV ("Canon i-SENSYS MF4700 Series", "MF4700", MF4700_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF4800 Series", "MF4800", MF4800_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS MF4570dw", "MF4570dw", MF4570_PID, 600, 0, 640, 877, 0), + DEV ("Canon i-SENSYS MF8200C Series", "MF8200C", MF8200_PID, 600, 300, 640, 1050, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF8300 Series", "MF8300", MF8300_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS D530", "D530", D530_PID, 600, 0, 640, 877, 0), + /* FIXME: the following capabilities all need updating/verifying */ + DEV ("Canon imageCLASS MF5630", "MF5630", MF5630_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon laserBase MF5650", "MF5650", MF5650_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageCLASS MF8170c", "MF8170c", MF8100_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon imageClass MF8030", "MF8030", MF8030_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF5880dn", "MF5880", MF5880_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF6680dn", "MF6680", MF6680_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), + DEV ("Canon imageRUNNER 1133", "iR1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF5900 Series", "MF5900", MF5900_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF8500C Series", "MF8500C", MF8500_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF6100 Series", "MF6100", MF6100_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon imageClass MF810/820", "MF810/820", MF820_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF220 Series", "MF220", MF220_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF210 Series", "MF210", MF210_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF620 Series", "MF620", MF620_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), + DEV ("Canon i-SENSYS MF410 Series", "MF410", MF410_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF510 Series", "MF510", MF510_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF230 Series", "MF230", MF230_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */ + DEV ("Canon i-SENSYS MF240 Series", "MF240", MF240_PID, 600, 300, 634, 1050, PIXMA_CAP_ADF), /* max. w = 215mm, */ + /* TODO: fix black stripes for 216mm @ 600dpi */ + DEV ("Canon i-SENSYS MF630 Series", "MF630", MF630_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF730 Series", "MF730", MF730_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF731C", "MF731", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF633C/MF635C", "MF633C/635C", MF630_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ + DEV ("Canon imageCLASS MF634C", "MF632C/634C", MF634_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon imageCLASS MF733C", "MF731C/733C", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* however, we need this for ethernet/wifi */ + DEV ("Canon imageCLASS D570", "D570", D570_PID, 600, 0, 640, 877, 0), + DEV ("Canon i-SENSYS MF110 Series", "MF110", MF110_PID, 600, 0, 640, 1050, 0), + DEV ("Canon i-SENSYS MF520 Series", "MF520", MF520_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF420 Series", "MF420", MF420_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF260 Series", "MF260", MF260_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF740 Series", "MF740", MF740_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF741C/743C", "MF741C/743C", MF743_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), /* ADFDUP restricted to 300dpi */ + DEV ("Canon i-SENSYS MF640 Series", "MF642C/643C/644C", MF640_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), + DEV ("Canon i-SENSYS MF645C", "MF645C", MF645_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ + DEV (NULL, NULL, 0, 0, 0, 0, 0, 0) +}; diff --git a/backend/pixma/pixma_io.h b/backend/pixma/pixma_io.h new file mode 100644 index 0000000..715bab5 --- /dev/null +++ b/backend/pixma/pixma_io.h @@ -0,0 +1,186 @@ +/* SANE - Scanner Access Now Easy. + + 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. + */ +#ifndef PIXMA_IO_H +#define PIXMA_IO_H + +/* TODO: move to pixma_common.h, to reduce the number of files */ + +/*! + * \defgroup IO IO interface + * \brief The IO interface. + * + * Return value of functions that return \c int if not otherwise specified: + * - >= if succeeded + * - < 0 if failed (e.g. \c PIXMA_ETIMEDOUT) + * . + * @{ + */ + +/** Timeout for pixma_read() in milliseconds */ +#define PIXMA_BULKIN_TIMEOUT 1000 +/** Timeout for pixma_write() in milliseconds */ +#define PIXMA_BULKOUT_TIMEOUT 1000 + + +struct pixma_io_t; +struct pixma_config_t; + +/** IO handle */ +typedef struct pixma_io_t pixma_io_t; + + +/** Initialize IO module. It must be called before any other functions in this + * module. + * \return 0 on success or + * - \c PIXMA_ENOMEM + * - \c PIXMA_EACCES + * - \c PIXMA_EIO */ +int pixma_io_init (void); + +/** Shutdown all connections and free resources allocated in this module. */ +void pixma_io_cleanup (void); + +/** Find devices currently connected to the computer. + * \c devnr passed to functions + * - pixma_get_device_config() + * - pixma_get_device_id() + * - pixma_connect() + * . + * should be less than the number of devices returned by this function. + * \param[in] pixma_devices A \c NULL terminated array of pointers to + * array of pixma_config_t which is terminated by setting + * pixma_config_t::name to \c NULL. + * \return Number of devices found */ +unsigned pixma_collect_devices (const char ** conf_devices, + const struct pixma_config_t *const + pixma_devices[], SANE_Bool local_only); + +/** Get device configuration. */ +const struct pixma_config_t *pixma_get_device_config (unsigned devnr); + +/** Get a unique ID of the device \a devnr. */ +const char *pixma_get_device_id (unsigned devnr); + +/** Connect to the device and claim the scanner interface. + * \param[in] devnr + * \param[out] handle + * \return 0 on success or + * - \c PIXMA_ENODEV the device is gone from the system. + * - \c PIXMA_EINVAL \a devnr is invalid. + * - \c PIXMA_EBUSY + * - \c PIXMA_EACCES + * - \c PIXMA_ENOMEM + * - \c PIXMA_EIO */ +int pixma_connect (unsigned devnr, pixma_io_t ** handle); + +/** Release the scanner interface and disconnect from the device. */ +void pixma_disconnect (pixma_io_t *); + +/** Activate connection to scanner */ +int pixma_activate (pixma_io_t *); + +/** De-activate connection to scanner */ +int pixma_deactivate (pixma_io_t *); + +/** Reset the USB interface. \warning Use with care! */ +int pixma_reset_device (pixma_io_t *); + +/** Write data to the device. This function may not be interrupted by signals. + * It will return iff + * - \a len bytes have been successfully written or + * - an error (inclusive timeout) occured. + * . + * \note Calling pixma_write(io, buf, n1) and pixma(io, buf+n1, n2) may + * not be the same as pixma_write(io, buf, n1+n2) if n1 is not + * multiple of the maximum packet size of the endpoint. + * \param[in] cmd Data + * \param[in] len Length of data + * \return Number of bytes successfully written (always = \a len) or + * - \c PIXMA_ETIMEDOUT + * - \c PIXMA_EIO + * - \c PIXMA_ENOMEM + * \see #PIXMA_BULKOUT_TIMEOUT */ +int pixma_write (pixma_io_t *, const void *cmd, unsigned len); + +/** Read data from the device. This function may not be interrupted by signals. + * It will return iff + * - \a size bytes have been successfully read, + * - a short packet has been read or + * - an error (inclusive timeout) occured. + * . + * \param[out] buf + * \param[in] size of the buffer + * \return Number of bytes successfully read. A return value of zero means that + * a zero length USB packet was received. Or + * - \c PIXMA_ETIMEDOUT + * - \c PIXMA_EIO + * - \c PIXMA_ENOMEM + * \see #PIXMA_BULKIN_TIMEOUT */ +int pixma_read (pixma_io_t *, void *buf, unsigned size); + +/** Wait for an interrupt. This function can be interrupted by signals. + * \a size should be less than or equal to the maximum packet size. + * \param[out] buf + * \param[in] size of the buffer + * \param[in] timeout in milliseconds; if < 0, wait forever. + * \return Number of bytes successfully read or + * - \c PIXMA_ETIMEDOUT + * - \c PIXMA_EIO + * - \c PIXMA_ENOMEM + * - \c PIXMA_ECANCELED if it was interrupted by a signal. */ +int pixma_wait_interrupt (pixma_io_t *, void *buf, unsigned size, + int timeout); + +/** Enable or disable background interrupt monitoring. + * Background mode is enabled by default. + * \param[in] background if not zero, a URB is submitted in background + * for interrupt endpoint. + * \return 0 on success or + * - \c PIXMA_ENOTSUP + * - \c PIXMA_EIO + * - \c PIXMA_ENOMEM */ +int pixma_set_interrupt_mode (pixma_io_t *, int background); + +/** @} end of IO group */ + +#endif diff --git a/backend/pixma/pixma_io_sanei.c b/backend/pixma/pixma_io_sanei.c new file mode 100644 index 0000000..c30b404 --- /dev/null +++ b/backend/pixma/pixma_io_sanei.c @@ -0,0 +1,556 @@ +/* SANE - Scanner Access Now Easy. + * For limitations, see function sanei_usb_get_vendor_product(). + + Copyright (C) 2011-2019 Rolf Bensch + 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 +#include /* INT_MAX */ + +#include "pixma_rename.h" +#include "pixma_common.h" +#include "pixma_io.h" +#include "pixma_bjnp.h" + +#include "../include/sane/sanei_usb.h" +#include "../include/sane/sane.h" + + +#ifdef __GNUC__ +# define UNUSED(v) (void) v +#else +# define UNUSED(v) +#endif + +/* MAC OS X does not support timeouts in darwin/libusb interrupt reads + * This is a very basic turnaround for MAC OS X + * Button scan will not work with this wrapper */ +#ifdef __APPLE__ +# define sanei_usb_read_int sanei_usb_read_bulk +#endif + + +struct pixma_io_t +{ + pixma_io_t *next; + int interface; + SANE_Int dev; +}; + +typedef struct scanner_info_t +{ + struct scanner_info_t *next; + char *devname; + int interface; + const pixma_config_t *cfg; + char serial[PIXMA_MAX_ID_LEN + 1]; /* "xxxxyyyy_zzzzzzz..." + x = vid, y = pid, z = serial */ +} scanner_info_t; + +#define INT_USB 0 +#define INT_BJNP 1 + +static scanner_info_t *first_scanner = NULL; +static pixma_io_t *first_io = NULL; +static unsigned nscanners; + + +static scanner_info_t * +get_scanner_info (unsigned devnr) +{ + scanner_info_t *si; + for (si = first_scanner; si && devnr != 0; --devnr, si = si->next) + { + } + return si; +} + +static SANE_Status +attach (SANE_String_Const devname) +{ + scanner_info_t *si; + + si = (scanner_info_t *) calloc (1, sizeof (*si)); + if (!si) + return SANE_STATUS_NO_MEM; + si->devname = strdup (devname); + if (!si->devname) + return SANE_STATUS_NO_MEM; + si -> interface = INT_USB; + si->next = first_scanner; + first_scanner = si; + nscanners++; + return SANE_STATUS_GOOD; +} + + +static SANE_Status +attach_bjnp (SANE_String_Const devname, + SANE_String_Const serial, + const struct pixma_config_t *cfg) +{ + scanner_info_t *si; + + si = (scanner_info_t *) calloc (1, sizeof (*si)); + if (!si) + return SANE_STATUS_NO_MEM; + si->devname = strdup (devname); + if (!si->devname) + return SANE_STATUS_NO_MEM; + + si->cfg = cfg; + sprintf(si->serial, "%s_%s", cfg->model, serial); + si -> interface = INT_BJNP; + si->next = first_scanner; + first_scanner = si; + nscanners++; + return SANE_STATUS_GOOD; +} + +static void +clear_scanner_list (void) +{ + scanner_info_t *si = first_scanner; + while (si) + { + scanner_info_t *temp = si; + free (si->devname); + si = si->next; + free (temp); + } + nscanners = 0; + first_scanner = NULL; +} + +static SANE_Status +get_descriptor (SANE_Int dn, SANE_Int type, SANE_Int descidx, + SANE_Int index, SANE_Int length, SANE_Byte * data) +{ + return sanei_usb_control_msg (dn, 0x80, USB_REQ_GET_DESCRIPTOR, + ((type & 0xff) << 8) | (descidx & 0xff), + index, length, data); +} + +static SANE_Status +get_string_descriptor (SANE_Int dn, SANE_Int index, SANE_Int lang, + SANE_Int length, SANE_Byte * data) +{ + return get_descriptor (dn, USB_DT_STRING, index, lang, length, data); +} + +static void +u16tohex (uint16_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 >> 12) & 0xf]; + str[1] = hdigit[(x >> 8) & 0xf]; + str[2] = hdigit[(x >> 4) & 0xf]; + str[3] = hdigit[x & 0xf]; + str[4] = '\0'; +} + +static void +read_serial_number (scanner_info_t * si) +{ + uint8_t unicode[2 * (PIXMA_MAX_ID_LEN - 9) + 2]; + uint8_t ddesc[18]; + int iSerialNumber; + SANE_Int usb; + char *serial = si->serial; + + u16tohex (si->cfg->vid, serial); + u16tohex (si->cfg->pid, serial + 4); + + if (SANE_STATUS_GOOD != sanei_usb_open (si->devname, &usb)) + return; + if (get_descriptor (usb, USB_DT_DEVICE, 0, 0, 18, ddesc) + != SANE_STATUS_GOOD) + goto done; + iSerialNumber = ddesc[16]; + if (iSerialNumber != 0) + { + int i, len; + SANE_Status status; + + /*int iSerialNumber = ddesc[16];*/ + /* Read the first language code. Assumed that there is at least one. */ + if (get_string_descriptor (usb, 0, 0, 4, unicode) != SANE_STATUS_GOOD) + goto done; + /* Read the serial number string. */ + status = get_string_descriptor (usb, iSerialNumber, + unicode[3] * 256 + unicode[2], + sizeof (unicode), unicode); + if (status != SANE_STATUS_GOOD) + goto done; + /* Assumed charset: Latin1 */ + len = unicode[0]; + if (len > (int) sizeof (unicode)) + { + len = sizeof (unicode); + PDBG (pixma_dbg (1, "WARNING:Truncated serial number\n")); + } + serial[8] = '_'; + for (i = 2; i < len; i += 2) + { + serial[9 + i / 2 - 1] = unicode[i]; + } + serial[9 + i / 2 - 1] = '\0'; + } + else + { + PDBG (pixma_dbg (1, "WARNING:No serial number\n")); + } +done: + sanei_usb_close (usb); +} + +static int +map_error (SANE_Status ss) +{ + switch (ss) + { + case SANE_STATUS_GOOD: + return 0; + case SANE_STATUS_UNSUPPORTED: + return PIXMA_ENODEV; + case SANE_STATUS_DEVICE_BUSY: + return PIXMA_EBUSY; + case SANE_STATUS_INVAL: + return PIXMA_EINVAL; + case SANE_STATUS_IO_ERROR: + return PIXMA_EIO; + case SANE_STATUS_NO_MEM: + return PIXMA_ENOMEM; + case SANE_STATUS_ACCESS_DENIED: + return PIXMA_EACCES; + case SANE_STATUS_CANCELLED: + return PIXMA_ECANCELED; + case SANE_STATUS_JAMMED: + return PIXMA_EPAPER_JAMMED; + case SANE_STATUS_COVER_OPEN: + return PIXMA_ECOVER_OPEN; + case SANE_STATUS_NO_DOCS: + return PIXMA_ENO_PAPER; + case SANE_STATUS_EOF: + return PIXMA_EOF; +#ifdef SANE_STATUS_HW_LOCKED + case SANE_STATUS_HW_LOCKED: /* unused by pixma */ +#endif +#ifdef SANE_STATUS_WARMING_UP + case SANE_STATUS_WARMING_UP: /* unused by pixma */ +#endif + break; + } + PDBG (pixma_dbg (1, "BUG:Unmapped SANE Status code %d\n", ss)); + return PIXMA_EIO; /* should not happen */ +} + + +int +pixma_io_init (void) +{ + sanei_usb_init (); + sanei_bjnp_init(); + nscanners = 0; + return 0; +} + +void +pixma_io_cleanup (void) +{ + while (first_io) + pixma_disconnect (first_io); + clear_scanner_list (); +} + +unsigned +pixma_collect_devices (const char **conf_devices, + const struct pixma_config_t *const pixma_devices[], SANE_Bool local_only) +{ + unsigned i, j; + struct scanner_info_t *si; + const struct pixma_config_t *cfg; + + clear_scanner_list (); + j = 0; + for (i = 0; pixma_devices[i]; i++) + { + for (cfg = pixma_devices[i]; cfg->name; cfg++) + { + sanei_usb_find_devices (cfg->vid, cfg->pid, attach); + si = first_scanner; + while (j < nscanners) + { + PDBG (pixma_dbg (3, "pixma_collect_devices() found %s at %s\n", + cfg->name, si->devname)); + si->cfg = cfg; + read_serial_number (si); + si = si->next; + j++; + } + } + } + if (! local_only) + sanei_bjnp_find_devices(conf_devices, attach_bjnp, pixma_devices); + + si = first_scanner; + while (j < nscanners) + { + PDBG (pixma_dbg (3, "pixma_collect_devices() found %s at %s\n", + si->cfg->name, si->devname)); + si = si->next; + j++; + + } + return nscanners; +} + +const pixma_config_t * +pixma_get_device_config (unsigned devnr) +{ + const scanner_info_t *si = get_scanner_info (devnr); + return (si) ? si->cfg : NULL; +} + +const char * +pixma_get_device_id (unsigned devnr) +{ + const scanner_info_t *si = get_scanner_info (devnr); + return (si) ? si->serial : NULL; +} + +int +pixma_connect (unsigned devnr, pixma_io_t ** handle) +{ + pixma_io_t *io; + SANE_Int dev; + const scanner_info_t *si; + int error; + + *handle = NULL; + si = get_scanner_info (devnr); + if (!si) + return PIXMA_EINVAL; + if (si-> interface == INT_BJNP) + error = map_error (sanei_bjnp_open (si->devname, &dev)); + else + error = map_error (sanei_usb_open (si->devname, &dev)); + + if (error < 0) + return error; + io = (pixma_io_t *) calloc (1, sizeof (*io)); + if (!io) + { + if (si -> interface == INT_BJNP) + sanei_bjnp_close (dev); + else + sanei_usb_close (dev); + return PIXMA_ENOMEM; + } + io->next = first_io; + first_io = io; + io->dev = dev; + io->interface = si->interface; + *handle = io; + return 0; +} + + +void +pixma_disconnect (pixma_io_t * io) +{ + pixma_io_t **p; + + if (!io) + return; + for (p = &first_io; *p && *p != io; p = &((*p)->next)) + { + } + PASSERT (*p); + if (!(*p)) + return; + if (io-> interface == INT_BJNP) + sanei_bjnp_close (io->dev); + else + sanei_usb_close (io->dev); + *p = io->next; + free (io); +} + +int pixma_activate (pixma_io_t * io) +{ + int error; + if (io->interface == INT_BJNP) + { + error = map_error(sanei_bjnp_activate (io->dev)); + } + else + /* noop for USB interface */ + error = 0; + return error; +} + +int pixma_deactivate (pixma_io_t * io) +{ + int error; + if (io->interface == INT_BJNP) + { + error = map_error(sanei_bjnp_deactivate (io->dev)); + } + else + /* noop for USB interface */ + error = 0; + return error; + +} + +int +pixma_reset_device (pixma_io_t * io) +{ + UNUSED (io); + return PIXMA_ENOTSUP; +} + +int +pixma_write (pixma_io_t * io, const void *cmd, unsigned len) +{ + size_t count = len; + int error; + + if (io->interface == INT_BJNP) + { + sanei_bjnp_set_timeout (io->dev, PIXMA_BULKOUT_TIMEOUT); + error = map_error (sanei_bjnp_write_bulk (io->dev, cmd, &count)); + } + else + { +#ifdef HAVE_SANEI_USB_SET_TIMEOUT + sanei_usb_set_timeout (PIXMA_BULKOUT_TIMEOUT); +#endif + error = map_error (sanei_usb_write_bulk (io->dev, cmd, &count)); + } + if (error == PIXMA_EIO) + error = PIXMA_ETIMEDOUT; /* FIXME: SANE doesn't have ETIMEDOUT!! */ + if (count != len) + { + PDBG (pixma_dbg (1, "WARNING:pixma_write(): count(%u) != len(%u)\n", + (unsigned) count, len)); + error = PIXMA_EIO; + } + if (error >= 0) + error = count; + PDBG (pixma_dump (10, "OUT ", cmd, error, len, 128)); + return error; +} + +int +pixma_read (pixma_io_t * io, void *buf, unsigned size) +{ + size_t count = size; + int error; + + if (io-> interface == INT_BJNP) + { + sanei_bjnp_set_timeout (io->dev, PIXMA_BULKIN_TIMEOUT); + error = map_error (sanei_bjnp_read_bulk (io->dev, buf, &count)); + } + else + { +#ifdef HAVE_SANEI_USB_SET_TIMEOUT + sanei_usb_set_timeout (PIXMA_BULKIN_TIMEOUT); +#endif + error = map_error (sanei_usb_read_bulk (io->dev, buf, &count)); + } + + if (error == PIXMA_EIO) + error = PIXMA_ETIMEDOUT; /* FIXME: SANE doesn't have ETIMEDOUT!! */ + if (error >= 0) + error = count; + PDBG (pixma_dump (10, "IN ", buf, error, -1, 128)); + return error; +} + +int +pixma_wait_interrupt (pixma_io_t * io, void *buf, unsigned size, int timeout) +{ + size_t count = size; + int error; + + /* FIXME: What is the meaning of "timeout" in sanei_usb? */ + if (timeout < 0) + timeout = INT_MAX; + else if (timeout < 100) + timeout = 100; + if (io-> interface == INT_BJNP) + { + sanei_bjnp_set_timeout (io->dev, timeout); + error = map_error (sanei_bjnp_read_int (io->dev, buf, &count)); + } + else + { +#ifdef HAVE_SANEI_USB_SET_TIMEOUT + sanei_usb_set_timeout (timeout); +#endif + error = map_error (sanei_usb_read_int (io->dev, buf, &count)); + } + if (error == PIXMA_EIO || + (io->interface == INT_BJNP && error == PIXMA_EOF)) /* EOF is a bjnp timeout error! */ + error = PIXMA_ETIMEDOUT; /* FIXME: SANE doesn't have ETIMEDOUT!! */ + if (error == 0) + error = count; + if (error != PIXMA_ETIMEDOUT) + PDBG (pixma_dump (10, "INTR", buf, error, -1, -1)); + return error; +} + +int +pixma_set_interrupt_mode (pixma_io_t * s, int background) +{ + UNUSED (s); + return (background) ? PIXMA_ENOTSUP : 0; +} diff --git a/backend/pixma/pixma_mp150.c b/backend/pixma/pixma_mp150.c new file mode 100644 index 0000000..3973702 --- /dev/null +++ b/backend/pixma/pixma_mp150.c @@ -0,0 +1,1817 @@ +/* SANE - Scanner Access Now Easy. + + Copyright (C) 2011-2019 Rolf Bensch + Copyright (C) 2007-2009 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. + */ +/* test cases + 1. short USB packet (must be no -ETIMEDOUT) + 2. cancel using button on the printer (look for abort command) + 3. start scan while busy (status 0x1414) + 4. cancel using ctrl-c (must send abort command) + */ + +#include "../include/sane/config.h" + +#include +#include +#include +#include /* localtime(C90) */ + +#include "pixma_rename.h" +#include "pixma_common.h" +#include "pixma_io.h" + +/* Some macro code to enhance readability */ +#define RET_IF_ERR(x) do { \ + if ((error = (x)) < 0) \ + return error; \ + } while(0) + +#define WAIT_INTERRUPT(x) do { \ + error = handle_interrupt (s, x); \ + if (s->cancel) \ + return PIXMA_ECANCELED; \ + if (error != PIXMA_ECANCELED && error < 0) \ + return error; \ + } while(0) + +#ifdef __GNUC__ +# define UNUSED(v) (void) v +#else +# define UNUSED(v) +#endif + +/* Size of the command buffer should be multiple of wMaxPacketLength and + greater than 4096+24. + 4096 = size of gamma table. 24 = header + checksum */ +#define IMAGE_BLOCK_SIZE (512*1024) +#define CMDBUF_SIZE (4096 + 24) +#define DEFAULT_GAMMA 2.0 /***** Gamma different from 1.0 is potentially impacting color profile generation *****/ +#define UNKNOWN_PID 0xffff + + +#define CANON_VID 0x04a9 + +/* Generation 1 */ +#define MP150_PID 0x1709 +#define MP170_PID 0x170a +#define MP450_PID 0x170b +#define MP500_PID 0x170c +#define MP530_PID 0x1712 + +/* Generation 2 */ +#define MP160_PID 0x1714 +#define MP180_PID 0x1715 +#define MP460_PID 0x1716 +#define MP510_PID 0x1717 +#define MP600_PID 0x1718 +#define MP600R_PID 0x1719 + +#define MP140_PID 0x172b + +/* Generation 3 */ +/* PIXMA 2007 vintage */ +#define MX7600_PID 0x171c +#define MP210_PID 0x1721 +#define MP220_PID 0x1722 +#define MP470_PID 0x1723 +#define MP520_PID 0x1724 +#define MP610_PID 0x1725 +#define MX300_PID 0x1727 +#define MX310_PID 0x1728 +#define MX700_PID 0x1729 +#define MX850_PID 0x172c + +/* PIXMA 2008 vintage */ +#define MP630_PID 0x172e +#define MP620_PID 0x172f +#define MP540_PID 0x1730 +#define MP480_PID 0x1731 +#define MP240_PID 0x1732 +#define MP260_PID 0x1733 +#define MP190_PID 0x1734 + +/* PIXMA 2009 vintage */ +#define MX860_PID 0x1735 +#define MX320_PID 0x1736 /* untested */ +#define MX330_PID 0x1737 + +/* Generation 4 */ +#define MP250_PID 0x173a +#define MP270_PID 0x173b +#define MP490_PID 0x173c +#define MP550_PID 0x173d +#define MP560_PID 0x173e +#define MP640_PID 0x173f + +/* PIXMA 2010 vintage */ +#define MX340_PID 0x1741 +#define MX350_PID 0x1742 +#define MX870_PID 0x1743 + +/* 2010 new devices (untested) */ +#define MP280_PID 0x1746 +#define MP495_PID 0x1747 +#define MG5100_PID 0x1748 +#define MG5200_PID 0x1749 +#define MG6100_PID 0x174a + +/* PIXMA 2011 vintage */ +#define MX360_PID 0x174d +#define MX410_PID 0x174e +#define MX420_PID 0x174f +#define MX880_PID 0x1750 + +/* Generation 5 */ +/* 2011 new devices (untested) */ +#define MG2100_PID 0x1751 +#define MG3100_PID 0x1752 +#define MG4100_PID 0x1753 +#define MG5300_PID 0x1754 +#define MG6200_PID 0x1755 +#define MP493_PID 0x1757 +#define E500_PID 0x1758 + +/* 2012 new devices (untested) */ +#define MX370_PID 0x1759 +#define MX430_PID 0x175B +#define MX510_PID 0x175C +#define MX710_PID 0x175D +#define MX890_PID 0x175E +#define E600_PID 0x175A +#define MG4200_PID 0x1763 + +/* 2013 new devices */ +#define MP230_PID 0x175F +#define MG6300_PID 0x1765 + +/* 2013 new devices (untested) */ +#define MG2200_PID 0x1760 +#define E510_PID 0x1761 +#define MG3200_PID 0x1762 +#define MG5400_PID 0x1764 +#define MX390_PID 0x1766 +#define E610_PID 0x1767 +#define MX450_PID 0x1768 +#define MX520_PID 0x1769 +#define MX720_PID 0x176a +#define MX920_PID 0x176b +#define MG2400_PID 0x176c +#define MG2500_PID 0x176d +#define MG3500_PID 0x176e +#define MG6500_PID 0x176f +#define MG6400_PID 0x1770 +#define MG5500_PID 0x1771 +#define MG7100_PID 0x1772 + +/* 2014 new devices (untested) */ +#define MX470_PID 0x1774 +#define MX530_PID 0x1775 +#define MB5000_PID 0x1776 +#define MB5300_PID 0x1777 +#define MB2000_PID 0x1778 +#define MB2300_PID 0x1779 +#define E400_PID 0x177a +#define E560_PID 0x177b +#define MG7500_PID 0x177c +#define MG6600_PID 0x177e +#define MG5600_PID 0x177f +#define MG2900_PID 0x1780 +#define E460_PID 0x1788 + +/* 2015 new devices (untested) */ +#define MX490_PID 0x1787 +#define E480_PID 0x1789 +#define MG3600_PID 0x178a +#define MG7700_PID 0x178b +#define MG6900_PID 0x178c +#define MG6800_PID 0x178d +#define MG5700_PID 0x178e + +/* 2016 new devices (untested) */ +#define MB2700_PID 0x1792 +#define MB2100_PID 0x1793 +#define G3000_PID 0x1794 +#define G2000_PID 0x1795 +#define TS9000_PID 0x179f +#define TS8000_PID 0x1800 +#define TS6000_PID 0x1801 +#define TS5000_PID 0x1802 +#define MG3000_PID 0x180b +#define E470_PID 0x180c +#define E410_PID 0x181e + +/* 2017 new devices (untested) */ +#define G4000_PID 0x181d +#define TS6100_PID 0x1822 +#define TS5100_PID 0x1825 +#define TS3100_PID 0x1827 +#define E3100_PID 0x1828 + +/* 2018 new devices (untested) */ +#define MB5400_PID 0x178f +#define MB5100_PID 0x1790 +#define TS9100_PID 0x1820 +#define TR8500_PID 0x1823 +#define TR7500_PID 0x1824 +#define TS9500_PID 0x185c +#define LIDE400_PID 0x1912 /* tested */ +#define LIDE300_PID 0x1913 /* tested */ + +/* 2019 new devices (untested) */ +#define TS8100_PID 0x1821 +#define G2010_PID 0x183a +#define G3010_PID 0x183b +#define G4010_PID 0x183d +#define TS9180_PID 0x183e +#define TS8180_PID 0x183f +#define TS6180_PID 0x1840 +#define TR8580_PID 0x1841 +#define TS8130_PID 0x1842 +#define TS6130_PID 0x1843 +#define TR8530_PID 0x1844 +#define TR7530_PID 0x1845 +#define XK50_PID 0x1846 +#define XK70_PID 0x1847 +#define TR4500_PID 0x1854 +#define E4200_PID 0x1855 +#define TS6200_PID 0x1856 +#define TS6280_PID 0x1857 +#define TS6230_PID 0x1858 +#define TS8200_PID 0x1859 +#define TS8280_PID 0x185a +#define TS8230_PID 0x185b +#define TS9580_PID 0x185d +#define TR9530_PID 0x185e +#define G6000_PID 0x1865 +#define G6080_PID 0x1866 +#define XK80_PID 0x1873 +#define TS5300_PID 0x188b +#define TS5380_PID 0x188c +#define TS6300_PID 0x188d +#define TS6380_PID 0x188e +#define TS7330_PID 0x188f +#define TS8300_PID 0x1890 +#define TS8380_PID 0x1891 +#define TS8330_PID 0x1892 +#define XK60_PID 0x1893 +#define TS6330_PID 0x1894 +#define TS3300_PID 0x18a2 +#define E3300_PID 0x18a3 + +/* Generation 4 XML messages that encapsulates the Pixma protocol messages */ +#define XML_START_1 \ +"\ +\ +StartJob\ +00000001\ +1" + +#define XML_START_2 \ +"\ +\ +VendorCmd\ +00000001\ +ModeShift1\ +" + +#define XML_END \ +"\ +\ +EndJob\ +00000001\ +" + +#define XML_OK "OK" + +enum mp150_state_t +{ + state_idle, + state_warmup, + state_scanning, + state_transfering, + state_finished +}; + +enum mp150_cmd_t +{ + cmd_start_session = 0xdb20, + cmd_select_source = 0xdd20, + cmd_gamma = 0xee20, + cmd_scan_param = 0xde20, + cmd_status = 0xf320, + cmd_abort_session = 0xef20, + cmd_time = 0xeb80, + cmd_read_image = 0xd420, + cmd_error_info = 0xff20, + + cmd_scan_param_3 = 0xd820, + cmd_scan_start_3 = 0xd920, + cmd_status_3 = 0xda20, +}; + +typedef struct mp150_t +{ + enum mp150_state_t state; + pixma_cmdbuf_t cb; + uint8_t *imgbuf; + uint8_t current_status[16]; + unsigned last_block; + uint8_t generation; + /* for Generation 3 shift */ + uint8_t *linebuf; + uint8_t *data_left_ofs; + unsigned data_left_len; + uint8_t adf_state; /* handle adf scanning */ + unsigned scale; /* Scale factor for lower resolutions, the + * scanner doesn't support. We scale down the + * image after scanning minimum possible + * resolution. + */ + +} mp150_t; + +/* + STAT: 0x0606 = ok, + 0x1515 = failed (PIXMA_ECANCELED), + 0x1414 = busy (PIXMA_EBUSY) + + Transaction scheme + 1. command_header/data | result_header + 2. command_header | result_header/data + 3. command_header | result_header/image_data + + - data has checksum in the last byte. + - image_data has no checksum. + - data and image_data begins in the same USB packet as + command_header or result_header. + + command format #1: + u16be cmd + u8[6] 0 + u8[4] 0 + u32be PLEN parameter length + u8[PLEN-1] parameter + u8 parameter check sum + result: + u16be STAT + u8 0 + u8 0 or 0x21 if STAT == 0x1414 + u8[4] 0 + + command format #2: + u16be cmd + u8[6] 0 + u8[4] 0 + u32be RLEN result length + result: + u16be STAT + u8[6] 0 + u8[RLEN-1] result + u8 result check sum + + command format #3: (only used by read_image_block) + u16be 0xd420 + u8[6] 0 + u8[4] 0 + u32be max. block size + 8 + result: + u16be STAT + u8[6] 0 + u8 block info bitfield: 0x8 = end of scan, 0x10 = no more paper, 0x20 = no more data + u8[3] 0 + u32be ILEN image data size + u8[ILEN] image data + */ + +static void mp150_finish_scan (pixma_t * s); + +static int +is_scanning_from_adf (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_ADF + || s->param->source == PIXMA_SOURCE_ADFDUP); +} + +static int +is_scanning_from_adfdup (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_ADFDUP); +} + +static int +is_scanning_jpeg (pixma_t *s) +{ + return s->param->mode_jpeg; +} + +static int +send_xml_dialog (pixma_t * s, const char * xml_message) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + int datalen; + + datalen = pixma_cmd_transaction (s, xml_message, strlen (xml_message), + mp->cb.buf, 1024); + if (datalen < 0) + return datalen; + + mp->cb.buf[datalen] = 0; + + PDBG (pixma_dbg (10, "XML message sent to scanner:\n%s\n", xml_message)); + PDBG (pixma_dbg (10, "XML response back from scanner:\n%s\n", mp->cb.buf)); + + return (strcasestr ((const char *) mp->cb.buf, XML_OK) != NULL); +} + +static int +start_session (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + + pixma_newcmd (&mp->cb, cmd_start_session, 0, 0); + mp->cb.buf[3] = 0x00; + return pixma_exec (s, &mp->cb); +} + +static int +start_scan_3 (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + + pixma_newcmd (&mp->cb, cmd_scan_start_3, 0, 0); + mp->cb.buf[3] = 0x00; + return pixma_exec (s, &mp->cb); +} + +static int +is_calibrated (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + if (mp->generation >= 3) + { + return ((mp->current_status[0] & 0x01) == 1 || (mp->current_status[0] & 0x02) == 2); + } + if (mp->generation == 1) + { + return (mp->current_status[8] == 1); + } + else + { + return (mp->current_status[9] == 1); + } +} + +static int +has_paper (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + + if (is_scanning_from_adfdup (s)) + return (mp->current_status[1] == 0 || mp->current_status[2] == 0); + else + return (mp->current_status[1] == 0); +} + +static void +drain_bulk_in (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + while (pixma_read (s->io, mp->imgbuf, IMAGE_BLOCK_SIZE) >= 0); +} + +static int +abort_session (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + mp->adf_state = state_idle; /* reset adf scanning */ + return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); +} + +static int +select_source (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + uint8_t *data; + + data = pixma_newcmd (&mp->cb, cmd_select_source, 12, 0); + data[5] = ((mp->generation == 2) ? 1 : 0); + switch (s->param->source) + { + case PIXMA_SOURCE_FLATBED: + data[0] = 1; + data[1] = 1; + break; + + case PIXMA_SOURCE_ADF: + data[0] = 2; + data[5] = 1; + data[6] = 1; + break; + + case PIXMA_SOURCE_ADFDUP: + data[0] = 2; + data[5] = 3; + data[6] = 3; + break; + + default: + return PIXMA_EPROTO; + } + return pixma_exec (s, &mp->cb); +} + +static int +send_gamma_table (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + const uint8_t *lut = s->param->gamma_table; + uint8_t *data; + + if (mp->generation == 1) + { + data = pixma_newcmd (&mp->cb, cmd_gamma, 4096 + 8, 0); + data[0] = (s->param->channels == 3) ? 0x10 : 0x01; + pixma_set_be16 (0x1004, data + 2); + if (lut) + memcpy (data + 4, lut, 4096); + else + pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 4096); + } + else + { + /* FIXME: Gamma table for 2nd generation: 1024 * uint16_le */ + data = pixma_newcmd (&mp->cb, cmd_gamma, 2048 + 8, 0); + data[0] = 0x10; + pixma_set_be16 (0x0804, data + 2); + if (lut) + { + int i; + for (i = 0; i < 1024; i++) + { + int j = (i << 2) + (i >> 8); + data[4 + 2 * i + 0] = lut[j]; + data[4 + 2 * i + 1] = lut[j]; + } + } + else + { + int i; + pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 2048); + for (i = 0; i < 1024; i++) + { + int j = (i << 1) + (i >> 9); + data[4 + 2 * i + 0] = data[4 + j]; + data[4 + 2 * i + 1] = data[4 + j]; + } + } + } + return pixma_exec (s, &mp->cb); +} + +static unsigned +calc_raw_width (const mp150_t * mp, const pixma_scan_param_t * param) +{ + unsigned raw_width; + /* NOTE: Actually, we can send arbitary width to MP150. Lines returned + are always padded to multiple of 4 or 12 pixels. Is this valid for + other models, too? */ + if (mp->generation >= 2) + { + raw_width = ALIGN_SUP ((param->w * mp->scale) + param->xs, 32); + /* PDBG (pixma_dbg (4, "*calc_raw_width***** width %i extended by %i and rounded to %i *****\n", param->w, param->xs, raw_width)); */ + } + else if (param->channels == 1) + { + raw_width = ALIGN_SUP (param->w + param->xs, 12); + } + else + { + raw_width = ALIGN_SUP (param->w + param->xs, 4); + } + return raw_width; +} + +static unsigned +get_cis_line_size (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + + /*PDBG (pixma_dbg (4, "%s: line_size=%ld, w=%d, wx=%d, scale=%d\n", + __func__, s->param->line_size, s->param->w, s->param->wx, mp->scale));*/ + + return (s->param->wx ? s->param->line_size / s->param->w * s->param->wx + : s->param->line_size) * mp->scale; +} + +static int +send_scan_param (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + uint8_t *data; + unsigned xdpi = s->param->xdpi * mp->scale; + unsigned ydpi = s->param->xdpi * mp->scale; + unsigned x = s->param->x * mp->scale; + unsigned xs = s->param->xs; + unsigned y = s->param->y * mp->scale; + unsigned wx = calc_raw_width (mp, s->param); + unsigned h = MIN (s->param->h, s->cfg->height * s->param->ydpi / 75) * mp->scale; + + if (mp->generation <= 2) + { + PDBG (pixma_dbg (4, "*send_scan_param gen. 1-2 ***** Setting: xdpi=%hi ydpi=%hi x=%i y=%i wx=%i ***** \n", + xdpi, ydpi, x-xs, y, wx)); + data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x30, 0); + pixma_set_be16 (xdpi | 0x8000, data + 0x04); + pixma_set_be16 (ydpi | 0x8000, data + 0x06); + pixma_set_be32 (x, data + 0x08); + if (mp->generation == 2) + pixma_set_be32 (x - s->param->xs, data + 0x08); + pixma_set_be32 (y, data + 0x0c); + pixma_set_be32 (wx, data + 0x10); + pixma_set_be32 (h, data + 0x14); + data[0x18] = (s->param->channels != 1) ? 0x08 : 0x04; + data[0x19] = ((s->param->software_lineart) ? 8 : s->param->depth) + * s->param->channels; /* bits per pixel */ + data[0x1a] = 0; + data[0x20] = 0xff; + data[0x23] = 0x81; + data[0x26] = 0x02; + data[0x27] = 0x01; + } + else + { + PDBG (pixma_dbg (4, "*send_scan_param gen. 3+ ***** Setting: xdpi=%hi ydpi=%hi x=%i xs=%i y=%i wx=%i h=%i ***** \n", + xdpi, ydpi, x, xs, y, wx, h)); + data = pixma_newcmd (&mp->cb, cmd_scan_param_3, 0x38, 0); + data[0x00] = (is_scanning_from_adf (s)) ? 0x02 : 0x01; + data[0x01] = 0x01; + data[0x02] = 0x01; + if (is_scanning_from_adfdup (s)) + { + data[0x02] = 0x03; + data[0x03] = 0x03; + } + if (is_scanning_jpeg (s)) + { + data[0x03] = 0x01; + } + else + { + data[0x05] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ + } + pixma_set_be16 (xdpi | 0x8000, data + 0x08); + pixma_set_be16 (ydpi | 0x8000, data + 0x0a); + pixma_set_be32 (x - xs, data + 0x0c); + pixma_set_be32 (y, data + 0x10); + pixma_set_be32 (wx, data + 0x14); + pixma_set_be32 (h, data + 0x18); + data[0x1c] = (s->param->channels != 1) ? 0x08 : 0x04; + + data[0x1d] = ((s->param->software_lineart) ? 8 : s->param->depth) + * s->param->channels; /* bits per pixel */ + + data[0x1f] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ + data[0x20] = 0xff; + if (is_scanning_jpeg (s)) + { + data[0x21] = 0x83; + } + else + { + data[0x21] = 0x81; + } + data[0x23] = 0x02; + data[0x24] = 0x01; + + switch (s->cfg->pid) + { + case MG5300_PID: + /* unknown values (perhaps counter) for MG5300 series---values must be 0x30-0x39: decimal 0-9 */ + data[0x26] = 0x32; /* using example values from a real scan here */ + data[0x27] = 0x31; + data[0x28] = 0x34; + data[0x29] = 0x35; + break; + + default: + break; + } + + data[0x30] = 0x01; + } + return pixma_exec (s, &mp->cb); +} + +static int +query_status_3 (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + uint8_t *data; + int error, status_len; + + status_len = 8; + data = pixma_newcmd (&mp->cb, cmd_status_3, 0, status_len); + RET_IF_ERR (pixma_exec (s, &mp->cb)); + memcpy (mp->current_status, data, status_len); + return error; +} + +static int +query_status (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + uint8_t *data; + int error, status_len; + + status_len = (mp->generation == 1) ? 12 : 16; + data = pixma_newcmd (&mp->cb, cmd_status, 0, status_len); + RET_IF_ERR (pixma_exec (s, &mp->cb)); + memcpy (mp->current_status, data, status_len); + PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u busy=%u\n", + data[1], data[8], data[7], data[9])); + return error; +} + +#if 0 +static int +send_time (pixma_t * s) +{ + /* Why does a scanner need a time? */ + time_t now; + struct tm *t; + uint8_t *data; + mp150_t *mp = (mp150_t *) s->subdriver; + + data = pixma_newcmd (&mp->cb, cmd_time, 20, 0); + pixma_get_time (&now, NULL); + t = localtime (&now); + strftime ((char *) data, 16, "%y/%m/%d %H:%M", t); + PDBG (pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); + return pixma_exec (s, &mp->cb); +} +#endif + +/* TODO: Simplify this function. Read the whole data packet in one shot. */ +static int +read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) +{ + uint8_t cmd[16]; + mp150_t *mp = (mp150_t *) s->subdriver; + const int hlen = 8 + 8; + int error, datalen; + + memset (cmd, 0, sizeof (cmd)); + pixma_set_be16 (cmd_read_image, cmd); + if ((mp->last_block & 0x20) == 0) + pixma_set_be32 ((IMAGE_BLOCK_SIZE / 65536) * 65536 + 8, cmd + 0xc); + else + pixma_set_be32 (32 + 8, cmd + 0xc); + + mp->state = state_transfering; + mp->cb.reslen = + pixma_cmd_transaction (s, cmd, sizeof (cmd), mp->cb.buf, 512); + datalen = mp->cb.reslen; + if (datalen < 0) + return datalen; + + memcpy (header, mp->cb.buf, hlen); + + if (datalen >= hlen) + { + datalen -= hlen; + memcpy (data, mp->cb.buf + hlen, datalen); + data += datalen; + if (mp->cb.reslen == 512) + { + error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen); + RET_IF_ERR (error); + datalen += error; + } + } + + mp->state = state_scanning; + mp->cb.expected_reslen = 0; + RET_IF_ERR (pixma_check_result (&mp->cb)); + if (mp->cb.reslen < hlen) + return PIXMA_EPROTO; + return datalen; +} + +static int +read_error_info (pixma_t * s, void *buf, unsigned size) +{ + unsigned len = 16; + mp150_t *mp = (mp150_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); + RET_IF_ERR (pixma_exec (s, &mp->cb)); + if (buf && len < size) + { + size = len; + /* NOTE: I've absolutely no idea what the returned data mean. */ + memcpy (buf, data, size); + error = len; + } + return error; +} + +/* +handle_interrupt() waits until it receives an interrupt packet or times out. +It calls send_time() and query_status() if necessary. Therefore, make sure +that handle_interrupt() is only called from a safe context for send_time() +and query_status(). + + Returns: + 0 timed out + 1 an interrupt packet received + PIXMA_ECANCELED interrupted by signal + <0 error +*/ +static int +handle_interrupt (pixma_t * s, int timeout) +{ + uint8_t buf[64]; + int len; + + len = pixma_wait_interrupt (s->io, buf, sizeof (buf), timeout); + if (len == PIXMA_ETIMEDOUT) + return 0; + if (len < 0) + return len; + if (len%16) /* len must be a multiple of 16 bytes */ + { + PDBG (pixma_dbg + (1, "WARNING:unexpected interrupt packet length %d\n", len)); + return PIXMA_EPROTO; + } + + /* s->event = 0x0brroott + * b: button + * oo: original + * tt: target + * rr: scan resolution + * poll event with 'scanimage -A' */ + if (s->cfg->pid == MG5300_PID + || s->cfg->pid == MG5400_PID + || s->cfg->pid == MG6200_PID + || s->cfg->pid == MG6300_PID + || s->cfg->pid == MX520_PID + || s->cfg->pid == MX720_PID + || s->cfg->pid == MX920_PID + || s->cfg->pid == MB2300_PID + || s->cfg->pid == MB5000_PID + || s->cfg->pid == MB5400_PID) + /* button no. in buf[7] + * size in buf[10] 01=A4; 02=Letter; 08=10x15; 09=13x18; 0b=auto + * format in buf[11] 01=JPEG; 02=TIFF; 03=PDF; 04=Kompakt-PDF + * dpi in buf[12] 01=75; 02=150; 03=300; 04=600 + * target = format; original = size; scan-resolution = dpi */ + { + if (buf[7] & 1) + s->events = PIXMA_EV_BUTTON1 | buf[11] | buf[10]<<8 | buf[12]<<16; /* color scan */ + if (buf[7] & 2) + s->events = PIXMA_EV_BUTTON2 | buf[11] | buf[10]<<8 | buf[12]<<16; /* b/w scan */ + } + else if (s->cfg->pid == LIDE300_PID + || s->cfg->pid == LIDE400_PID) + /* unknown value in buf[4] + * target in buf[0x13] + * always set button-1 */ + { + if (buf[0x13]) + s->events = PIXMA_EV_BUTTON1 | buf[0x13]; + } + else + /* button no. in buf[0] + * original in buf[0] + * target in buf[1] */ + { + /* More than one event can be reported at the same time. */ + if (buf[3] & 1) + /* FIXME: This function makes trouble with a lot of scanners + send_time (s); + */ + PDBG (pixma_dbg (1, "WARNING:send_time() disabled!\n")); + if (buf[9] & 2) + query_status (s); + if (buf[0] & 2) + s->events = PIXMA_EV_BUTTON2 | buf[1] | ((buf[0] & 0xf0) << 4); /* b/w scan */ + if (buf[0] & 1) + s->events = PIXMA_EV_BUTTON1 | buf[1] | ((buf[0] & 0xf0) << 4); /* color scan */ + } + return 1; +} + +static int +wait_until_ready (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + int error, tmo = 120; /* some scanners need a long timeout */ + + RET_IF_ERR ((mp->generation >= 3) ? query_status_3 (s) + : query_status (s)); + while (!is_calibrated (s)) + { + WAIT_INTERRUPT (1000); + if (mp->generation >= 3) + RET_IF_ERR (query_status_3 (s)); + else if (s->cfg->pid == MP600_PID || + s->cfg->pid == MP600R_PID) + RET_IF_ERR (query_status (s)); + if (--tmo == 0) + { + PDBG (pixma_dbg (1, "WARNING:Timed out in wait_until_ready()\n")); + PDBG (query_status (s)); + return PIXMA_ETIMEDOUT; + } + } + return 0; +} + +static void +reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, unsigned n, + unsigned m, unsigned w, unsigned line_size) +{ + unsigned i; + + for (i = 0; i < w; i++) + { + memcpy (linebuf + c * (n * (i % m) + i / m), sptr + c * i, c); + } + memcpy (sptr, linebuf, line_size); +} + +/* the scanned image must be shrinked by factor "scale" + * the image can be formatted as rgb (c=3) or gray (c=1) + * we need to crop the left side (xs) + * we ignore more pixels inside scanned line (wx), behind needed line (w) + * + * example (scale=2): + * line | pixel[0] | pixel[1] | ... | pixel[w-1] + * --------- + * 0 | rgbrgb | rgbrgb | ... | rgbrgb + * wx*c | rgbrgb | rgbrgb | ... | rgbrgb + */ +uint8_t * +shrink_image (uint8_t * dptr, uint8_t * sptr, unsigned xs, unsigned w, + unsigned wx, unsigned scale, unsigned c) +{ + unsigned i, ic; + uint16_t pixel; + uint8_t *dst = dptr; /* don't change dptr */ + uint8_t *src = sptr; /* don't change sptr */ + + /*PDBG (pixma_dbg (4, "%s: w=%d, wx=%d, c=%d, scale=%d\n", + __func__, w, wx, c, scale)); + PDBG (pixma_dbg (4, "\tdptr=%ld, sptr=%ld\n", + dptr, sptr));*/ + + /* crop left side */ + src += c * xs; + + /* process line */ + for (i = 0; i < w; i++) + { + /* process rgb or gray pixel */ + for (ic = 0; ic < c; ic++) + { +#if 0 + dst[ic] = src[ic]; +#else + pixel = 0; + + /* sum shrink pixels */ + for (unsigned m = 0; m < scale; m++) /* get pixels from shrinked lines */ + { + for (unsigned n = 0; n < scale; n++) /* get pixels from same line */ + { + pixel += src[ic + c * n + wx * c * m]; + } + } + dst[ic] = pixel / (scale * scale); +#endif + } + + /* jump over shrinked data */ + src += c * scale; + /* next pixel */ + dst += c; + } + + return dst; +} + +/* This function deals with Generation >= 3 high dpi images. + * Each complete line in mp->imgbuf is processed for reordering pixels above + * 600 dpi for Generation >= 3. */ +static unsigned +post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + unsigned c, lines, line_size, n, m, cw, cx; + uint8_t *sptr, *dptr, *gptr, *cptr; + + if (s->param->mode_jpeg) + { + /* No post-processing, send raw JPEG data to main */ + ib->rptr = mp->imgbuf; + ib->rend = mp->data_left_ofs; + return 0; /* # of non processed bytes */ + } + + /* process image sizes */ + c = s->param->channels + * ((s->param->software_lineart) ? 8 : s->param->depth) / 8; /* color channels count */ + cw = c * s->param->w; /* image width */ + cx = c * s->param->xs; /* x-offset */ + + /* special image format parameters + * n: no. of sub-images + * m: sub-image width + */ + if (mp->generation >= 3) + n = s->param->xdpi / 600; + else + n = s->param->xdpi / 2400; + if (s->cfg->pid == MP600_PID || s->cfg->pid == MP600R_PID) + n = s->param->xdpi / 1200; + m = (n > 0) ? s->param->wx / n : 1; + + /* Initialize pointers */ + sptr = dptr = gptr = cptr = mp->imgbuf; + + /* walk through complete received lines */ + line_size = get_cis_line_size (s); + lines = (mp->data_left_ofs - mp->imgbuf) / line_size; + if (lines > 0) + { + unsigned i; + + /*PDBG (pixma_dbg (4, "*post_process_image_data***** Processing with c=%u, n=%u, m=%u, wx=%i, line_size=%u, cx=%u, cw=%u ***** \n", + c, n, m, s->param->wx, line_size, cx, cw));*/ + /*PDBG (pixma_dbg (4, "*post_process_image_data***** lines = %i ***** \n", lines));*/ + + for (i = 0; i < lines; i++, sptr += line_size) + { + /*PDBG (pixma_dbg (4, "*post_process_image_data***** Processing with c=%u, n=%u, m=%u, w=%i, line_size=%u ***** \n", + c, n, m, s->param->wx, line_size));*/ + /*PDBG (pixma_dbg (4, "*post_process_image_data***** Pointers: sptr=%lx, dptr=%lx, linebuf=%lx ***** \n", + sptr, dptr, mp->linebuf));*/ + + /* special image format for *most* devices at high dpi. + * MP220, MX360 and generation 5 scanners are exceptions */ + if (n > 1 + && s->cfg->pid != MP220_PID + && s->cfg->pid != MP490_PID + && s->cfg->pid != MX360_PID + && (mp->generation < 5 + /* generation 5 scanners *with* special image format */ + || s->cfg->pid == MG2200_PID + || s->cfg->pid == MG3200_PID + || s->cfg->pid == MG4200_PID + || s->cfg->pid == MG5600_PID + || s->cfg->pid == MG5700_PID + || s->cfg->pid == MG6200_PID + || s->cfg->pid == MP230_PID + || s->cfg->pid == MX470_PID + || s->cfg->pid == MX510_PID + || s->cfg->pid == MX520_PID)) + reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, line_size); + + + /* scale image */ + if (mp->scale > 1) + { + /* Crop line inside shrink_image() */ + shrink_image(cptr, sptr, s->param->xs, s->param->w, s->param->wx, mp->scale, c); + } + else + { + /* Crop line to selected borders */ + memmove(cptr, sptr + cx, cw); + } + + /* Color / Gray to Lineart convert */ + if (s->param->software_lineart) + cptr = gptr = pixma_binarize_line (s->param, gptr, cptr, s->param->w, c); + else + cptr += cw; + } + } + ib->rptr = mp->imgbuf; + ib->rend = cptr; + return mp->data_left_ofs - sptr; /* # of non processed bytes */ +} + +static int +mp150_open (pixma_t * s) +{ + mp150_t *mp; + uint8_t *buf; + + mp = (mp150_t *) calloc (1, sizeof (*mp)); + if (!mp) + return PIXMA_ENOMEM; + + buf = (uint8_t *) malloc (CMDBUF_SIZE + IMAGE_BLOCK_SIZE); + if (!buf) + { + free (mp); + return PIXMA_ENOMEM; + } + + s->subdriver = mp; + mp->state = state_idle; + + mp->cb.buf = buf; + mp->cb.size = CMDBUF_SIZE; + mp->cb.res_header_len = 8; + mp->cb.cmd_header_len = 16; + mp->cb.cmd_len_field_ofs = 14; + + mp->imgbuf = buf + CMDBUF_SIZE; + + /* General rules for setting Pixma protocol generation # */ + mp->generation = (s->cfg->pid >= MP160_PID) ? 2 : 1; + + if (s->cfg->pid >= MX7600_PID) + mp->generation = 3; + + if (s->cfg->pid >= MP250_PID) + mp->generation = 4; + + if (s->cfg->pid >= MG2100_PID) /* this scanners generation doesn't need */ + mp->generation = 5; /* special image conversion @ high dpi */ + + /* And exceptions to be added here */ + if (s->cfg->pid == MP140_PID) + mp->generation = 2; + + PDBG (pixma_dbg (3, "*mp150_open***** This is a generation %d scanner. *****\n", mp->generation)); + + /* adf scanning */ + mp->adf_state = state_idle; + + if (mp->generation < 4) + { + query_status (s); + handle_interrupt (s, 200); + } + return 0; +} + +static void +mp150_close (pixma_t * s) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + + mp150_finish_scan (s); + free (mp->cb.buf); + free (mp); + s->subdriver = NULL; +} + +static int +mp150_check_param (pixma_t * s, pixma_scan_param_t * sp) +{ + mp150_t *mp = (mp150_t *) s->subdriver; + + /* PDBG (pixma_dbg (4, "*mp150_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", + sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */ + + /* MP150 only supports 8 bit per channel in color and grayscale mode */ + if (sp->depth != 1) + { + sp->software_lineart = 0; + sp->depth = 8; + } + else + { + /* software lineart */ + sp->software_lineart = 1; + sp->depth = 1; + sp->channels = 1; + } + + /* for software lineart w must be a multiple of 8 */ + if (sp->software_lineart == 1 && sp->w % 8) + { + unsigned w_max; + + sp->w += 8 - (sp->w % 8); + + /* do not exceed the scanner capability */ + w_max = s->cfg->width * s->cfg->xdpi / 75; + w_max -= w_max % 8; + if (sp->w > w_max) + sp->w = w_max; + } + + if (mp->generation >= 2) + { + /* mod 32 and expansion of the X scan limits */ + /*PDBG (pixma_dbg (4, "*mp150_check_param***** ----- Initially: x=%i, y=%i, w=%i, h=%i *****\n", sp->x, sp->y, sp->w, sp->h));*/ + sp->xs = (sp->x * mp->scale) % 32; + } + else + sp->xs = 0; + /*PDBG (pixma_dbg (4, "*mp150_check_param***** Selected origin, origin shift: %i, %i *****\n", sp->x, sp->xs));*/ + sp->wx = calc_raw_width (mp, sp); + sp->line_size = sp->w * sp->channels * (((sp->software_lineart) ? 8 : sp->depth) / 8); /* bytes per line per color after cropping */ + /*PDBG (pixma_dbg (4, "*mp150_check_param***** Final scan width and line-size: %i, %li *****\n", sp->wx, sp->line_size));*/ + + /* Some exceptions here for particular devices */ + /* Those devices can scan up to legal 14" with ADF, but A4 11.7" in flatbed */ + /* PIXMA_CAP_ADF also works for PIXMA_CAP_ADFDUP */ + if ((s->cfg->cap & PIXMA_CAP_ADF) && sp->source == PIXMA_SOURCE_FLATBED) + sp->h = MIN (sp->h, 877 * sp->xdpi / 75); + + if (sp->source == PIXMA_SOURCE_ADF || sp->source == PIXMA_SOURCE_ADFDUP) + { + uint8_t k = 1; + + /* ADF/ADF duplex mode: max scan res is 600 dpi, at least for generation 4+ */ + if (mp->generation >= 4) + k = sp->xdpi / MIN (sp->xdpi, 600); + sp->x /= k; + sp->xs /= k; + sp->y /= k; + sp->w /= k; + sp->wx /= k; + sp->h /= k; + sp->xdpi /= k; + sp->ydpi = sp->xdpi; + } + + sp->mode_jpeg = (s->cfg->cap & PIXMA_CAP_ADF_JPEG) && + (sp->source == PIXMA_SOURCE_ADF || + sp->source == PIXMA_SOURCE_ADFDUP); + + mp->scale = 1; + if (s->cfg->min_xdpi && sp->xdpi < s->cfg->min_xdpi) + { + mp->scale = s->cfg->min_xdpi / sp->xdpi; + } + /*PDBG (pixma_dbg (4, "*mp150_check_param***** xdpi=%u, min_xdpi=%u, scale=%u *****\n", + sp->xdpi, s->cfg->min_xdpi, mp->scale));*/ + + /*PDBG (pixma_dbg (4, "*mp150_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", + sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx));*/ + return 0; +} + +static int +mp150_scan (pixma_t * s) +{ + int error = 0, tmo; + mp150_t *mp = (mp150_t *) s->subdriver; + + if (mp->state != state_idle) + return PIXMA_EBUSY; + + /* no paper inserted after first adf page => abort session */ + if (s->param->adf_pageid && is_scanning_from_adf(s) && mp->adf_state == state_idle) + { + return PIXMA_ENO_PAPER; + } + + /* Generation 4+: send XML dialog */ + /* adf: first page or idle */ + if (mp->generation >= 4 && mp->adf_state == state_idle) + { + if (!send_xml_dialog (s, XML_START_1)) + return PIXMA_EPROTO; + if (!send_xml_dialog (s, XML_START_2)) + return PIXMA_EPROTO; + } + + /* clear interrupt packets buffer */ + while (handle_interrupt (s, 0) > 0) + { + } + + /* FIXME: Duplex ADF: check paper status only before odd pages (1,3,5,...). */ + if (is_scanning_from_adf (s)) + { + if ((error = query_status (s)) < 0) + return error; + + /* wait for inserted paper + * timeout: 10 sec */ + tmo = 10; + while (!has_paper (s) && --tmo >= 0) + { + if ((error = query_status (s)) < 0) + return error; + WAIT_INTERRUPT (1000); + PDBG (pixma_dbg + (2, "No paper in ADF. Timed out in %d sec.\n", tmo)); + } + + /* no paper inserted + * => abort session */ + if (!has_paper (s)) + { + PDBG (pixma_dbg (4, "*mp150_scan***** no paper in ADF *****\n")); + error = abort_session (s); + if (error < 0) + return error; + + /* Generation 4+: send XML dialog */ + /* adf: first page or idle */ + if (mp->generation >= 4 && mp->adf_state == state_idle) + { + if (!send_xml_dialog (s, XML_END)) + return PIXMA_EPROTO; + } + + return PIXMA_ENO_PAPER; + } + } + + tmo = 10; + /* adf: first page or idle */ + if (mp->generation <= 2 || mp->adf_state == state_idle) + { /* single sheet or first sheet from ADF */ + PDBG (pixma_dbg (4, "*mp150_scan***** start scanning *****\n")); + error = start_session (s); + while (error == PIXMA_EBUSY && --tmo >= 0) + { + if (s->cancel) + { + error = PIXMA_ECANCELED; + break; + } + PDBG (pixma_dbg + (2, "Scanner is busy. Timed out in %d sec.\n", tmo + 1)); + pixma_sleep (1000000); + error = start_session (s); + } + if (error == PIXMA_EBUSY || error == PIXMA_ETIMEDOUT) + { + /* The scanner maybe hangs. We try to empty output buffer of the + * scanner and issue the cancel command. */ + PDBG (pixma_dbg (2, "Scanner hangs? Sending abort_session command.\n")); + drain_bulk_in (s); + abort_session (s); + pixma_sleep (500000); + error = start_session (s); + } + if ((error >= 0) || (mp->generation >= 3)) + mp->state = state_warmup; + if ((error >= 0) && (mp->generation <= 2)) + error = select_source (s); + if ((error >= 0) && !is_scanning_jpeg (s)) + { + int i; + + for (i = (mp->generation >= 3) ? 3 : 1 ; i > 0 && error >= 0; i--) + error = send_gamma_table (s); + } + } + else /* ADF pageid != 0 and gen3 or above */ + { /* next sheet from ADF */ + PDBG (pixma_dbg (4, "*mp150_scan***** scan next sheet from ADF *****\n")); + pixma_sleep (1000000); + } + if ((error >= 0) || (mp->generation >= 3)) + mp->state = state_warmup; + if (error >= 0) + error = send_scan_param (s); + if ((error >= 0) && (mp->generation >= 3)) + error = start_scan_3 (s); + if (error < 0) + { + mp->last_block = 0x38; /* Force abort session if ADF scan */ + mp150_finish_scan (s); + return error; + } + + /* ADF scanning active */ + if (is_scanning_from_adf (s)) + mp->adf_state = state_scanning; + return 0; +} + +static int +mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) +{ + int error; + mp150_t *mp = (mp150_t *) s->subdriver; + unsigned block_size, bytes_received, proc_buf_size, line_size; + uint8_t header[16]; + + if (mp->state == state_warmup) + { + RET_IF_ERR (wait_until_ready (s)); + pixma_sleep (1000000); /* No need to sleep, actually, but Window's driver + * sleep 1.5 sec. */ + mp->state = state_scanning; + mp->last_block = 0; + + line_size = get_cis_line_size (s); + proc_buf_size = 2 * line_size; + mp->cb.buf = realloc (mp->cb.buf, + CMDBUF_SIZE + IMAGE_BLOCK_SIZE + proc_buf_size); + if (!mp->cb.buf) + return PIXMA_ENOMEM; + mp->linebuf = mp->cb.buf + CMDBUF_SIZE; + mp->imgbuf = mp->data_left_ofs = mp->linebuf + line_size; + mp->data_left_len = 0; + } + + do + { + if (s->cancel) + { + PDBG (pixma_dbg (4, "*mp150_fill_buffer***** s->cancel *****\n")); + return PIXMA_ECANCELED; + } + if ((mp->last_block & 0x28) == 0x28) + { /* end of image */ + PDBG (pixma_dbg (4, "*mp150_fill_buffer***** end of image *****\n")); + mp->state = state_finished; + return 0; + } + /*PDBG (pixma_dbg (4, "*mp150_fill_buffer***** moving %u bytes into buffer *****\n", mp->data_left_len));*/ + memmove (mp->imgbuf, mp->data_left_ofs, mp->data_left_len); + error = read_image_block (s, header, mp->imgbuf + mp->data_left_len); + if (error < 0) + { + PDBG (pixma_dbg (4, "*mp150_fill_buffer***** scanner error (%d): end scan *****\n", error)); + mp->last_block = 0x38; /* end scan in mp150_finish_scan() */ + if (error == PIXMA_ECANCELED) + { + /* NOTE: I see this in traffic logs but I don't know its meaning. */ + read_error_info (s, NULL, 0); + } + return error; + } + + bytes_received = error; + /*PDBG (pixma_dbg (4, "*mp150_fill_buffer***** %u bytes received by read_image_block *****\n", bytes_received));*/ + block_size = pixma_get_be32 (header + 12); + mp->last_block = header[8] & 0x38; + if ((header[8] & ~0x38) != 0) + { + PDBG (pixma_dbg (1, "WARNING: Unexpected result header\n")); + PDBG (pixma_hexdump (1, header, 16)); + } + PASSERT (bytes_received == block_size); + + if (block_size == 0) + { /* no image data at this moment. */ + pixma_sleep (10000); + } + /* Post-process the image data */ + mp->data_left_ofs = mp->imgbuf + mp->data_left_len + bytes_received; + mp->data_left_len = post_process_image_data (s, ib); + mp->data_left_ofs -= mp->data_left_len; + } + while (ib->rend == ib->rptr); + + return ib->rend - ib->rptr; +} + +static void +mp150_finish_scan (pixma_t * s) +{ + int error; + mp150_t *mp = (mp150_t *) s->subdriver; + + switch (mp->state) + { + case state_transfering: + drain_bulk_in (s); + /* fall through */ + case state_scanning: + case state_warmup: + case state_finished: + /* FIXME: to process several pages ADF scan, must not send + * abort_session and start_session between pages (last_block=0x28) */ + if (mp->generation <= 2 || !is_scanning_from_adf (s) || mp->last_block == 0x38) + { + PDBG (pixma_dbg (4, "*mp150_finish_scan***** abort session *****\n")); + error = abort_session (s); /* FIXME: it probably doesn't work in duplex mode! */ + if (error < 0) + PDBG (pixma_dbg (1, "WARNING:abort_session() failed %d\n", error)); + + /* Generation 4+: send XML end of scan dialog */ + if (mp->generation >= 4) + { + if (!send_xml_dialog (s, XML_END)) + PDBG (pixma_dbg (1, "WARNING:XML_END dialog failed \n")); + } + } + else + PDBG (pixma_dbg (4, "*mp150_finish_scan***** wait for next page from ADF *****\n")); + + mp->state = state_idle; + /* fall through */ + case state_idle: + break; + } +} + +static void +mp150_wait_event (pixma_t * s, int timeout) +{ + /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for + * instance. */ + while (s->events == 0 && handle_interrupt (s, timeout) > 0) + { + } +} + +static int +mp150_get_status (pixma_t * s, pixma_device_status_t * status) +{ + int error; + + RET_IF_ERR (query_status (s)); + status->hardware = PIXMA_HARDWARE_OK; + status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; + status->cal = + (is_calibrated (s)) ? PIXMA_CALIBRATION_OK : PIXMA_CALIBRATION_OFF; + return 0; +} + +static const pixma_scan_ops_t pixma_mp150_ops = { + mp150_open, + mp150_close, + mp150_scan, + mp150_fill_buffer, + mp150_finish_scan, + mp150_wait_event, + mp150_check_param, + mp150_get_status +}; + +#define DEVICE(name, model, pid, min_dpi, dpi, adftpu_min_dpi, adftpu_max_dpi, w, h, cap) { \ + name, /* name */ \ + model, /* model */ \ + CANON_VID, pid, /* vid pid */ \ + 0, /* iface */ \ + &pixma_mp150_ops, /* ops */ \ + min_dpi, /* min_xdpi */ \ + dpi, 2*(dpi), /* xdpi, ydpi */ \ + adftpu_min_dpi, adftpu_max_dpi, /* adftpu_min_dpi, adftpu_max_dpi */ \ + 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ + w, h, /* width, height */ \ + PIXMA_CAP_EASY_RGB| \ + PIXMA_CAP_GRAY| /* CIS with native grayscale */ \ + PIXMA_CAP_LINEART| /* all scanners with software lineart */ \ + PIXMA_CAP_GAMMA_TABLE|PIXMA_CAP_EVENTS|cap \ +} + +#define END_OF_DEVICE_LIST DEVICE(NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0) + +const pixma_config_t pixma_mp150_devices[] = { + /* Generation 1: CIS */ + DEVICE ("Canon PIXMA MP150", "MP150", MP150_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP170", "MP170", MP170_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP450", "MP450", MP450_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP500", "MP500", MP500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP530", "MP530", MP530_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + + /* Generation 2: CIS */ + DEVICE ("Canon PIXMA MP140", "MP140", MP140_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP160", "MP160", MP160_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP180", "MP180", MP180_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP460", "MP460", MP460_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP510", "MP510", MP510_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP600", "MP600", MP600_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP600R", "MP600R", MP600R_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Generation 3: CIS */ + DEVICE ("Canon PIXMA MP210", "MP210", MP210_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP220", "MP220", MP220_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP470", "MP470", MP470_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP520", "MP520", MP520_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP610", "MP610", MP610_PID, 0, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), + + DEVICE ("Canon PIXMA MX300", "MX300", MX300_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MX310", "MX310", MX310_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX700", "MX700", MX700_PID, 0, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX850", "MX850", MX850_PID, 0, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon PIXMA MX7600", "MX7600", MX7600_PID, 0, 4800, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + + DEVICE ("Canon PIXMA MP630", "MP630", MP630_PID, 0, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP620", "MP620", MP620_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP540", "MP540", MP540_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP480", "MP480", MP480_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP240", "MP240", MP240_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP260", "MP260", MP260_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP190", "MP190", MP190_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* PIXMA 2009 vintage */ + DEVICE ("Canon PIXMA MX320", "MX320", MX320_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX330", "MX330", MX330_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX860", "MX860", MX860_PID, 0, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), +/* width and height adjusted to flatbed size 21.8 x 30.2 cm^2 respective + * Not sure if anything's going wrong here, leaving as is + DEVICE ("Canon PIXMA MX860", "MX860", MX860_PID, 0, 2400, 0, 0, 638, 880, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP),*/ + + /* PIXMA 2010 vintage */ + DEVICE ("Canon PIXMA MX340", "MX340", MX340_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX350", "MX350", MX350_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX870", "MX870", MX870_PID, 0, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + + /* PIXMA 2011 vintage */ + DEVICE ("Canon PIXMA MX360", "MX360", MX360_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX410", "MX410", MX410_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX420", "MX420", MX420_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX880 Series", "MX880", MX880_PID, 0, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + + /* Generation 4: CIS */ + DEVICE ("Canon PIXMA MP640", "MP640", MP640_PID, 0, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP560", "MP560", MP560_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP550", "MP550", MP550_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP490", "MP490", MP490_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP250", "MP250", MP250_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP270", "MP270", MP270_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2010) Generation 4 CIS */ + DEVICE ("Canon PIXMA MP280", "MP280", MP280_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), /* TODO: 1200dpi doesn't work yet */ + DEVICE ("Canon PIXMA MP495", "MP495", MP495_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG5100", "MG5100", MG5100_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG5200", "MG5200", MG5200_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6100", "MG6100", MG6100_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2011) Generation 5 CIS */ + DEVICE ("Canon PIXMA MG2100", "MG2100", MG2100_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG3100", "MG3100", MG3100_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG4100", "MG4100", MG4100_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG5300", "MG5300", MG5300_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6200", "MG6200", MG6200_PID, 0, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MP493", "MP493", MP493_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E500", "E500", E500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2012) Generation 5 CIS */ + DEVICE ("Canon PIXMA MX370 Series", "MX370", MX370_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX430 Series", "MX430", MX430_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX510 Series", "MX510", MX510_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX710 Series", "MX710", MX710_PID, 0, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon PIXMA MX890 Series", "MX890", MX890_PID, 0, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon PIXMA E600 Series", "E600", E600_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MG4200", "MG4200", MG4200_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2013) Generation 5 CIS */ + DEVICE ("Canon PIXMA E510", "E510", E510_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E610", "E610", E610_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MP230", "MP230", MP230_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG2200 Series", "MG2200", MG2200_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG3200 Series", "MG3200", MG3200_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG5400 Series", "MG5400", MG5400_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6300 Series", "MG6300", MG6300_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MX390 Series", "MX390", MX390_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX450 Series", "MX450", MX450_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX520 Series", "MX520", MX520_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX720 Series", "MX720", MX720_PID, 0, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon PIXMA MX920 Series", "MX920", MX920_PID, 0, 2400, 0, 600, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon PIXMA MG2400 Series", "MG2400", MG2400_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG2500 Series", "MG2500", MG2500_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG3500 Series", "MG3500", MG3500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG5500 Series", "MG5500", MG5500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6400 Series", "MG6400", MG6400_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6500 Series", "MG6500", MG6500_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG7100 Series", "MG7100", MG7100_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2014) Generation 5 CIS */ + DEVICE ("Canon PIXMA MX470 Series", "MX470", MX470_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MX530 Series", "MX530", MX530_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon MAXIFY MB5000 Series", "MB5000", MB5000_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), + DEVICE ("Canon MAXIFY MB5300 Series", "MB5300", MB5300_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon MAXIFY MB2000 Series", "MB2000", MB2000_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP | PIXMA_CAP_ADF_JPEG), + DEVICE ("Canon MAXIFY MB2100 Series", "MB2100", MB2100_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), + DEVICE ("Canon MAXIFY MB2300 Series", "MB2300", MB2300_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), + DEVICE ("Canon MAXIFY MB2700 Series", "MB2700", MB2700_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), + DEVICE ("Canon PIXMA E400", "E400", E400_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E560", "E560", E560_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG7500 Series", "MG7500", MG7500_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6600 Series", "MG6600", MG6600_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG5600 Series", "MG5600", MG5600_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG2900 Series", "MG2900", MG2900_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E460 Series", "E460", E460_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2015) Generation 5 CIS */ + DEVICE ("Canon PIXMA MX490 Series", "MX490", MX490_PID, 0, 600, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA E480 Series", "E480", E480_PID, 0, 600, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MG3600 Series", "MG3600", MG3600_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG7700 Series", "MG7700", MG7700_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6900 Series", "MG6900", MG6900_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG6800 Series", "MG6800", MG6800_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG5700 Series", "MG5700", MG5700_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2016) Generation 5 CIS */ + DEVICE ("Canon PIXMA G3000", "G3000", G3000_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G2000", "G2000", G2000_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS9000 Series", "TS9000", TS9000_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8000 Series", "TS8000", TS8000_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6000 Series", "TS6000", TS6000_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS5000 Series", "TS5000", TS5000_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA MG3000 Series", "MG3000", MG3000_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E470 Series", "E470", E470_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E410 Series", "E410", E410_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2017) Generation 5 CIS */ + DEVICE ("Canon PIXMA G4000", "G4000", G4000_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6100 Series", "TS6100", TS6100_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS5100 Series", "TS5100", TS5100_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS3100 Series", "TS3100", TS3100_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E3100 Series", "E3100", E3100_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2018) Generation 5 CIS */ + DEVICE ("Canon MAXIFY MB5400 Series", "MB5400", MB5400_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP | PIXMA_CAP_ADF_JPEG), + DEVICE ("Canon MAXIFY MB5100 Series", "MB5100", MB5100_PID, 0, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), + DEVICE ("Canon PIXMA TS9100 Series", "TS9100", TS9100_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TR8500 Series", "TR8500", TR8500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TR7500 Series", "TR7500", TR7500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TS9500 Series", "TS9500", TS9500_PID, 0, 1200, 0, 600, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("CanoScan LiDE 400", "LIDE400", LIDE400_PID, 300, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("CanoScan LiDE 300", "LIDE300", LIDE300_PID, 300, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + + /* Latest devices (2019) Generation 5 CIS */ + DEVICE ("Canon PIXMA TS8100 Series", "TS8100", TS8100_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G2010 Series", "G2010", G2010_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G3010 Series", "G3010", G3010_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G4010 Series", "G4010", G4010_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TS9180 Series", "TS9180", TS9180_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8180 Series", "TS8180", TS8180_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6180 Series", "TS6180", TS6180_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TR8580 Series", "TR8580", TR8580_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TS8130 Series", "TS8130", TS8130_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6130 Series", "TS6130", TS6130_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TR8530 Series", "TR8530", TR8530_PID, 0, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TR7530 Series", "TR7530", TR7530_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXUS XK50 Series", "XK50", XK50_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXUS XK70 Series", "XK70", XK70_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TR4500 Series", "TR4500", TR4500_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA E4200 Series", "E4200", E4200_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TS6200 Series", "TS6200", TS6200_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6280 Series", "TS6280", TS6280_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6230 Series", "TS6230", TS6230_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8200 Series", "TS8200", TS8200_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8280 Series", "TS8280", TS8280_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8230 Series", "TS8230", TS8230_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS9580 Series", "TS9580", TS9580_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA TR9530 Series", "TR9530", TR9530_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA G6000 Series", "G6000", G6000_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA G6080 Series", "G6080", G6080_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXUS XK80 Series", "XK80", XK80_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS5300 Series", "TS5300", TS5300_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS5380 Series", "TS5380", TS5380_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6300 Series", "TS6300", TS6300_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6380 Series", "TS6380", TS6380_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS7330 Series", "TS7330", TS7330_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8380 Series", "TS8380", TS8380_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS8330 Series", "TS8330", TS8330_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA XK60 Series", "XK60", XK60_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS6330 Series", "TS6330", TS6330_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA TS3300 Series", "TS3300", TS3300_PID, 0, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), + DEVICE ("Canon PIXMA E3300 Series", "E3300", E3300_PID, 0, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), + + END_OF_DEVICE_LIST +}; diff --git a/backend/pixma/pixma_mp730.c b/backend/pixma/pixma_mp730.c new file mode 100644 index 0000000..93d518b --- /dev/null +++ b/backend/pixma/pixma_mp730.c @@ -0,0 +1,846 @@ +/* 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 +#include /* localtime(C90) */ + +#include "pixma_rename.h" +#include "pixma_common.h" +#include "pixma_io.h" + + +#ifdef __GNUC__ +# define UNUSED(v) (void) v +#else +# define UNUSED(v) +#endif + +#define IMAGE_BLOCK_SIZE (0xc000) +#define CMDBUF_SIZE 512 + +#define MP10_PID 0x261f + +#define MP730_PID 0x262f +#define MP700_PID 0x2630 + +#define MP5_PID 0x2635 /* untested */ + +#define MP360_PID 0x263c +#define MP370_PID 0x263d +#define MP390_PID 0x263e +#define MP375R_PID 0x263f /* untested */ + +#define MP740_PID 0x264c /* Untested */ +#define MP710_PID 0x264d + +#define MF5730_PID 0x265d /* Untested */ +#define MF5750_PID 0x265e /* Untested */ +#define MF5770_PID 0x265f +#define MF3110_PID 0x2660 + +#define IR1020_PID 0x26e6 + +enum mp730_state_t +{ + state_idle, + state_warmup, + state_scanning, + state_transfering, + state_finished +}; + +enum mp730_cmd_t +{ + cmd_start_session = 0xdb20, + cmd_select_source = 0xdd20, + cmd_gamma = 0xee20, + cmd_scan_param = 0xde20, + cmd_status = 0xf320, + cmd_abort_session = 0xef20, + cmd_time = 0xeb80, + cmd_read_image = 0xd420, + cmd_error_info = 0xff20, + + cmd_activate = 0xcf60, + cmd_calibrate = 0xe920 +}; + +typedef struct mp730_t +{ + enum mp730_state_t state; + pixma_cmdbuf_t cb; + unsigned raw_width; + uint8_t current_status[12]; + + uint8_t *buf, *imgbuf, *lbuf; + unsigned imgbuf_len; + + unsigned last_block:1; +} mp730_t; + + +static void mp730_finish_scan (pixma_t * s); + +static int +has_paper (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + return (mp->current_status[1] == 0); +} + +static void +drain_bulk_in (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + while (pixma_read (s->io, mp->imgbuf, IMAGE_BLOCK_SIZE) >= 0); +} + +static int +abort_session (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); +} + +static int +query_status (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mp->cb, cmd_status, 0, 12); + error = pixma_exec (s, &mp->cb); + if (error >= 0) + { + memcpy (mp->current_status, data, 12); + PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u\n", + data[1], data[8], data[7])); + } + return error; +} + +static int +activate (pixma_t * s, uint8_t x) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + uint8_t *data = pixma_newcmd (&mp->cb, cmd_activate, 10, 0); + data[0] = 1; + data[3] = x; + return pixma_exec (s, &mp->cb); +} + +static int +start_session (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mp->cb, cmd_start_session); +} + +static int +select_source (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + uint8_t *data = pixma_newcmd (&mp->cb, cmd_select_source, 10, 0); + switch (s->param->source) + { + case PIXMA_SOURCE_ADF: + data[0] = 2; + break; + + case PIXMA_SOURCE_ADFDUP: + data[0] = 2; + data[5] = 3; + break; + + default: + data[0] = 1; + break; + } + return pixma_exec (s, &mp->cb); +} + +static int +send_scan_param (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + uint8_t *data; + + data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x2e, 0); + pixma_set_be16 (s->param->xdpi | 0x1000, data + 0x04); + pixma_set_be16 (s->param->ydpi | 0x1000, data + 0x06); + pixma_set_be32 (s->param->x, data + 0x08); + pixma_set_be32 (s->param->y, data + 0x0c); + pixma_set_be32 (mp->raw_width, data + 0x10); + pixma_set_be32 (s->param->h, data + 0x14); + + if (s->param->channels == 1) + { + if (s->param->depth == 1) + data[0x18] = 0x01; + else + data[0x18] = 0x04; + } + else + data[0x18] = 0x08; + + data[0x19] = s->param->channels * s->param->depth; /* bits per pixel, for lineart should be 0x01 */ + data[0x1e] = (s->param->depth == 1) ? 0x80 : 0x00; /* modify for lineart: 0x80 NEW */ + data[0x1f] = (s->param->depth == 1) ? 0x80 : 0x7f; /* modify for lineart: 0x80 */ + data[0x20] = (s->param->depth == 1) ? 0x01 : 0xff; /* modify for lineart: 0x01 */ + data[0x23] = 0x81; + + return pixma_exec (s, &mp->cb); +} + +static int +calibrate (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mp->cb, cmd_calibrate); +} + +static int +read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) +{ + static const uint8_t cmd[10] = /* 0xd420 cmd */ + { 0xd4, 0x20, 0, 0, 0, 0, 0, IMAGE_BLOCK_SIZE / 256, 4, 0 }; + mp730_t *mp = (mp730_t *) s->subdriver; + const int hlen = 2 + 4; + int error, datalen; + + mp->state = state_transfering; + mp->cb.reslen = + pixma_cmd_transaction (s, cmd, sizeof (cmd), mp->cb.buf, 512); + datalen = mp->cb.reslen; + if (datalen < 0) + return datalen; + + memcpy (header, mp->cb.buf, hlen); + if (datalen >= hlen) + { + datalen -= hlen; + memcpy (data, mp->cb.buf + hlen, datalen); + data += datalen; + if (mp->cb.reslen == 512) + { + error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen); + if (error < 0) + return error; + datalen += error; + } + } + + mp->state = state_scanning; + mp->cb.expected_reslen = 0; + error = pixma_check_result (&mp->cb); + if (error < 0) + return error; + if (mp->cb.reslen < hlen) + return PIXMA_EPROTO; + return datalen; +} + +static int +send_time (pixma_t * s) +{ + /* Why does a scanner need a time? */ + time_t now; + struct tm *t; + uint8_t *data; + mp730_t *mp = (mp730_t *) s->subdriver; + + data = pixma_newcmd (&mp->cb, cmd_time, 20, 0); + pixma_get_time (&now, NULL); + t = localtime (&now); + strftime ((char *) data, 16, "%y/%m/%d %H:%M", t); + PDBG (pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); + return pixma_exec (s, &mp->cb); +} + +static int +handle_interrupt (pixma_t * s, int timeout) +{ + uint8_t buf[16]; + int len; + + len = pixma_wait_interrupt (s->io, buf, sizeof (buf), timeout); + if (len == PIXMA_ETIMEDOUT) + return 0; + if (len < 0) + return len; + switch (s->cfg->pid) + { + case MP360_PID: + case MP370_PID: + case MP375R_PID: + case MP390_PID: + case MF5730_PID: + case MF5750_PID: + case MF5770_PID: + case MF3110_PID: + case IR1020_PID: + if (len != 16) + { + PDBG (pixma_dbg + (1, "WARNING:unexpected interrupt packet length %d\n", len)); + return PIXMA_EPROTO; + } + if (buf[12] & 0x40) + query_status (s); + if (buf[10] & 0x40) + send_time (s); + /* FIXME: following is unverified! */ + if (buf[15] & 1) + s->events = PIXMA_EV_BUTTON2; /* b/w scan */ + if (buf[15] & 2) + s->events = PIXMA_EV_BUTTON1; /* color scan */ + break; + + case MP5_PID: + case MP10_PID: + case MP700_PID: + case MP730_PID: + case MP710_PID: + case MP740_PID: + if (len != 8) + { + PDBG (pixma_dbg + (1, "WARNING:unexpected interrupt packet length %d\n", len)); + return PIXMA_EPROTO; + } + if (buf[7] & 0x10) + s->events = PIXMA_EV_BUTTON1; + if (buf[5] & 8) + send_time (s); + break; + + default: + PDBG (pixma_dbg (1, "WARNING:unknown interrupt, please report!\n")); + PDBG (pixma_hexdump (1, buf, len)); + } + return 1; +} + +static int +has_ccd_sensor (pixma_t * s) +{ + return (s->cfg->pid == MP360_PID || + s->cfg->pid == MP370_PID || + s->cfg->pid == MP375R_PID || + s->cfg->pid == MP390_PID || + s->cfg->pid == MF5730_PID || + s->cfg->pid == MF5750_PID || + s->cfg->pid == MF5770_PID); +} + +static int +read_error_info (pixma_t * s, void *buf, unsigned size) +{ + unsigned len = 16; + mp730_t *mp = (mp730_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); + error = pixma_exec (s, &mp->cb); + if (error < 0) + return error; + if (buf && len < size) + { + size = len; + /* NOTE: I've absolutely no idea what the returned data mean. */ + memcpy (buf, data, size); + error = len; + } + return error; +} + +static int +step1 (pixma_t * s) +{ + int error; + + error = query_status (s); + if (error < 0) + return error; + if ((s->param->source == PIXMA_SOURCE_ADF + || s->param->source == PIXMA_SOURCE_ADFDUP) + && !has_paper (s)) + return PIXMA_ENO_PAPER; + if (has_ccd_sensor (s)) + { + switch (s->cfg->pid) + { + case MF5730_PID: + case MF5750_PID: + case MF5770_PID: + /* MF57x0: Wait 10 sec before starting for 1st page only */ + if (s->param->adf_pageid == 0) + { + int tmo = 10; /* like Windows driver, 10 sec CCD calibration ? */ + while (--tmo >= 0) + { + error = handle_interrupt (s, 1000); \ + if (s->cancel) \ + return PIXMA_ECANCELED; \ + if (error != PIXMA_ECANCELED && error < 0) \ + return error; + PDBG (pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo)); + } + } + break; + + default: + break; + } + + activate (s, 0); + error = calibrate (s); + + switch (s->cfg->pid) + { + case MF5730_PID: + case MF5750_PID: + case MF5770_PID: + /* MF57x0: calibration returns PIXMA_STATUS_FAILED */ + if (error == PIXMA_ECANCELED) + error = read_error_info (s, NULL, 0); + break; + + default: + break; + } + + // ignore result from calibrate() + // don't interrupt @ PIXMA_STATUS_BUSY + error = 0; + } + if (error >= 0) + error = activate (s, 0); + if (error >= 0) + error = activate (s, 4); + return error; +} + +static void +pack_rgb (const uint8_t * src, unsigned nlines, unsigned w, uint8_t * dst) +{ + unsigned w2, stride; + + w2 = 2 * w; + stride = 3 * w; + for (; nlines != 0; nlines--) + { + unsigned x; + for (x = 0; x != w; x++) + { + *dst++ = src[x + 0]; + *dst++ = src[x + w]; + *dst++ = src[x + w2]; + } + src += stride; + } +} + +static int +mp730_open (pixma_t * s) +{ + mp730_t *mp; + uint8_t *buf; + + mp = (mp730_t *) calloc (1, sizeof (*mp)); + if (!mp) + return PIXMA_ENOMEM; + + buf = (uint8_t *) malloc (CMDBUF_SIZE); + if (!buf) + { + free (mp); + return PIXMA_ENOMEM; + } + + s->subdriver = mp; + mp->state = state_idle; + + mp->cb.buf = buf; + mp->cb.size = CMDBUF_SIZE; + mp->cb.res_header_len = 2; + mp->cb.cmd_header_len = 10; + mp->cb.cmd_len_field_ofs = 7; + + PDBG (pixma_dbg (3, "Trying to clear the interrupt buffer...\n")); + if (handle_interrupt (s, 200) == 0) + { + PDBG (pixma_dbg (3, " no packets in buffer\n")); + } + return 0; +} + +static void +mp730_close (pixma_t * s) +{ + mp730_t *mp = (mp730_t *) s->subdriver; + + mp730_finish_scan (s); + free (mp->cb.buf); + free (mp->buf); + free (mp); + s->subdriver = NULL; +} + +static unsigned +calc_raw_width (pixma_t * s, const pixma_scan_param_t * sp) +{ + unsigned raw_width; + /* FIXME: Does MP730 need the alignment? */ + /* TODO test: MP710/740 */ + if (sp->channels == 1) + { + if (sp->depth == 8) /* grayscale */ + { + if (s->cfg->pid == MP5_PID || + s->cfg->pid == MP10_PID || + s->cfg->pid == MP700_PID || + s->cfg->pid == MP730_PID || + s->cfg->pid == MP360_PID || + s->cfg->pid == MP370_PID || + s->cfg->pid == MP375R_PID || + s->cfg->pid == MP390_PID || + s->cfg->pid == IR1020_PID) + raw_width = ALIGN_SUP (sp->w, 4); + else + raw_width = ALIGN_SUP (sp->w, 12); + } + else /* depth = 1 : LINEART */ + raw_width = ALIGN_SUP (sp->w, 16); + } + else + raw_width = ALIGN_SUP (sp->w, 4); + return raw_width; +} + +static int +mp730_check_param (pixma_t * s, pixma_scan_param_t * sp) +{ + uint8_t k = 1; + + /* check if channels is 3, or if depth is 1 then channels also 1 else set depth to 8 */ + if ((sp->channels==3) || !(sp->channels==1 && sp->depth==1)) + { + sp->depth=8; + } + /* for MP5, MP10, MP360/370, MP700/730 in grayscale & lineart modes, max scan res is 600 dpi */ + if (s->cfg->pid == MP5_PID || + s->cfg->pid == MP10_PID || + s->cfg->pid == MP700_PID || + s->cfg->pid == MP730_PID || + s->cfg->pid == MP360_PID || + s->cfg->pid == MP370_PID || + s->cfg->pid == MP375R_PID || + s->cfg->pid == MP390_PID) + { + if (sp->channels == 1) + k = sp->xdpi / MIN (sp->xdpi, 600); + } + + sp->x /= k; + sp->y /= k; + sp->h /= k; + sp->xdpi /= k; + sp->ydpi = sp->xdpi; + + sp->w = calc_raw_width (s, sp); + sp->w /= k; + sp->line_size = (calc_raw_width (s, sp) * sp->channels * sp->depth) / 8; + + return 0; +} + +static int +mp730_scan (pixma_t * s) +{ + int error, n; + mp730_t *mp = (mp730_t *) s->subdriver; + uint8_t *buf; + + if (mp->state != state_idle) + return PIXMA_EBUSY; + + /* clear interrupt packets buffer */ + while (handle_interrupt (s, 0) > 0) + { + } + + mp->raw_width = calc_raw_width (s, s->param); + PDBG (pixma_dbg (3, "raw_width = %u\n", mp->raw_width)); + + n = IMAGE_BLOCK_SIZE / s->param->line_size + 1; + buf = (uint8_t *) malloc ((n + 1) * s->param->line_size + IMAGE_BLOCK_SIZE); + if (!buf) + return PIXMA_ENOMEM; + mp->buf = buf; + mp->lbuf = buf; + mp->imgbuf = buf + n * s->param->line_size; + mp->imgbuf_len = 0; + + error = step1 (s); + if (error >= 0) + error = start_session (s); + if (error >= 0) + mp->state = state_scanning; + if (error >= 0) + error = select_source (s); + if (error >= 0) + error = send_scan_param (s); + if (error < 0) + { + mp730_finish_scan (s); + return error; + } + mp->last_block = 0; + return 0; +} + +static int +mp730_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) +{ + int error, n; + mp730_t *mp = (mp730_t *) s->subdriver; + unsigned block_size, bytes_received; + uint8_t header[16]; + + do + { + do + { + if (s->cancel) + return PIXMA_ECANCELED; + if (mp->last_block) /* end of image */ + return 0; + + error = read_image_block (s, header, mp->imgbuf + mp->imgbuf_len); + if (error < 0) + return error; + + bytes_received = error; + block_size = pixma_get_be16 (header + 4); + mp->last_block = ((header[2] & 0x28) == 0x28); + if (mp->last_block) + { /* end of image */ + mp->state = state_finished; + } + if ((header[2] & ~0x38) != 0) + { + PDBG (pixma_dbg (1, "WARNING: Unexpected result header\n")); + PDBG (pixma_hexdump (1, header, 16)); + } + PASSERT (bytes_received == block_size); + + if (block_size == 0) + { + /* no image data at this moment. */ + /*pixma_sleep(100000); *//* FIXME: too short, too long? */ + handle_interrupt (s, 100); + } + } + while (block_size == 0); + + /* TODO: simplify! */ + mp->imgbuf_len += bytes_received; + n = mp->imgbuf_len / s->param->line_size; + /* n = number of full lines (rows) we have in the buffer. */ + if (n != 0) + { + if (s->param->channels != 1 && + s->cfg->pid != MF5730_PID && + s->cfg->pid != MF5750_PID && + s->cfg->pid != MF5770_PID && + s->cfg->pid != MF3110_PID && + s->cfg->pid != IR1020_PID) + { + /* color, and not an MF57x0 nor MF3110 */ + pack_rgb (mp->imgbuf, n, mp->raw_width, mp->lbuf); + } + else + /* grayscale/lineart or MF57x0 or MF3110 */ + memcpy (mp->lbuf, mp->imgbuf, n * s->param->line_size); + + block_size = n * s->param->line_size; + mp->imgbuf_len -= block_size; + memcpy (mp->imgbuf, mp->imgbuf + block_size, mp->imgbuf_len); + } + } + while (n == 0); + + ib->rptr = mp->lbuf; + ib->rend = mp->lbuf + block_size; + return ib->rend - ib->rptr; +} + +static void +mp730_finish_scan (pixma_t * s) +{ + int error, aborted = 0; + mp730_t *mp = (mp730_t *) s->subdriver; + + switch (mp->state) + { + case state_transfering: + drain_bulk_in (s); + /* fall through */ + case state_scanning: + case state_warmup: + aborted = 1; + error = abort_session (s); + if (error < 0) + PDBG (pixma_dbg + (1, "WARNING:abort_session() failed %s\n", + pixma_strerror (error))); + /* fall through */ + case state_finished: + query_status (s); + query_status (s); + activate (s, 0); + + // MF57x0 devices don't require abort_session() after the last page + if (!aborted && + (s->param->source == PIXMA_SOURCE_ADF || + s->param->source == PIXMA_SOURCE_ADFDUP) && + has_paper (s) && + (s->cfg->pid == MF5730_PID || + s->cfg->pid == MF5750_PID || + s->cfg->pid == MF5770_PID || + s->cfg->pid == IR1020_PID)) + { + error = abort_session (s); + if (error < 0) + PDBG (pixma_dbg + (1, "WARNING:abort_session() failed %s\n", + pixma_strerror (error))); + } + + mp->buf = mp->lbuf = mp->imgbuf = NULL; + mp->state = state_idle; + /* fall through */ + case state_idle: + break; + } +} + +static void +mp730_wait_event (pixma_t * s, int timeout) +{ + /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for + * instance. */ + while (s->events == 0 && handle_interrupt (s, timeout) > 0) + { + } +} + +static int +mp730_get_status (pixma_t * s, pixma_device_status_t * status) +{ + int error; + + error = query_status (s); + if (error < 0) + return error; + status->hardware = PIXMA_HARDWARE_OK; + status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; + return 0; +} + + +static const pixma_scan_ops_t pixma_mp730_ops = { + mp730_open, + mp730_close, + mp730_scan, + mp730_fill_buffer, + mp730_finish_scan, + mp730_wait_event, + mp730_check_param, + mp730_get_status +}; + +/* TODO: implement adftpu_min_dpi & adftpu_max_dpi for grayscale & lineart */ +#define DEVICE(name, model, pid, dpi, w, h, cap) { \ + name, /* name */ \ + model, /* model */ \ + 0x04a9, pid, /* vid pid */ \ + 1, /* iface */ \ + &pixma_mp730_ops, /* ops */ \ + 0, /* min_xdpi not used in this subdriver */ \ + dpi, dpi, /* xdpi, ydpi */ \ + 0, 0, /* adftpu_min_dpi & adftpu_max_dpi not used in this subdriver */ \ + 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ + w, h, /* width, height */ \ + PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ +} +const pixma_config_t pixma_mp730_devices[] = { +/* TODO: check area limits */ + DEVICE ("PIXUS MP5/SmartBase MPC190/imageCLASS MPC190","MP5", MP5_PID, 600, 636, 868, PIXMA_CAP_LINEART),/* color scan can do 600x1200 */ + DEVICE ("PIXUS MP10/SmartBase MPC200/imageCLASS MPC200","MP10", MP10_PID, 600, 636, 868, PIXMA_CAP_LINEART),/* color scan can do 600x1200 */ + DEVICE ("PIXMA MP360", "MP360", MP360_PID, 1200, 636, 868, PIXMA_CAP_LINEART), + DEVICE ("PIXMA MP370", "MP370", MP370_PID, 1200, 636, 868, PIXMA_CAP_LINEART), + DEVICE ("PIXMA MP375R", "MP375R", MP375R_PID, 1200, 636, 868, PIXMA_CAP_LINEART), + DEVICE ("PIXMA MP390", "MP390", MP390_PID, 1200, 636, 868, PIXMA_CAP_LINEART), + DEVICE ("PIXMA MP700", "MP700", MP700_PID, 1200, 638, 877 /*1035 */ , PIXMA_CAP_LINEART), + DEVICE ("PIXMA MP710", "MP710", MP710_PID, 1200, 637, 868, PIXMA_CAP_LINEART), + DEVICE ("PIXMA MP730", "MP730", MP730_PID, 1200, 637, 868, PIXMA_CAP_ADF | PIXMA_CAP_LINEART), + DEVICE ("PIXMA MP740", "MP740", MP740_PID, 1200, 637, 868, PIXMA_CAP_ADF | PIXMA_CAP_LINEART), + + DEVICE ("Canon imageCLASS MF5730", "MF5730", MF5730_PID, 1200, 636, 868, PIXMA_CAP_ADF), + DEVICE ("Canon imageCLASS MF5750", "MF5750", MF5750_PID, 1200, 636, 868, PIXMA_CAP_ADF), + DEVICE ("Canon imageCLASS MF5770", "MF5770", MF5770_PID, 1200, 636, 868, PIXMA_CAP_ADF), + DEVICE ("Canon imageCLASS MF3110", "MF3110", MF3110_PID, 600, 636, 868, 0), + + DEVICE ("Canon iR 1020/1024/1025", "iR1020", IR1020_PID, 600, 636, 868, PIXMA_CAP_ADFDUP), + + DEVICE (NULL, NULL, 0, 0, 0, 0, 0) +}; diff --git a/backend/pixma/pixma_mp750.c b/backend/pixma/pixma_mp750.c new file mode 100644 index 0000000..7f00023 --- /dev/null +++ b/backend/pixma/pixma_mp750.c @@ -0,0 +1,972 @@ +/* SANE - Scanner Access Now Easy. + + Copyright (C) 2011-2019 Rolf Bensch + 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. + */ + +/**************************************************************************** + * Credits should go to Martin Schewe (http://pixma.schewe.com) who analysed + * the protocol of MP750. + ****************************************************************************/ + +#include "../include/sane/config.h" + +#include +#include + +#include "pixma_rename.h" +#include "pixma_common.h" +#include "pixma_io.h" + +/* TODO: remove lines marked with SIM. They are inserted so that I can test + the subdriver with the simulator. WY */ + +#ifdef __GNUC__ +# define UNUSED(v) (void) v +#else +# define UNUSED(v) +#endif + +#define IMAGE_BLOCK_SIZE 0xc000 +#define CMDBUF_SIZE 512 +#define HAS_PAPER(s) (s[1] == 0) +#define IS_WARMING_UP(s) (s[7] != 3) +#define IS_CALIBRATED(s) (s[8] == 0xf) + +#define MP750_PID 0x1706 +#define MP760_PID 0x1708 +#define MP780_PID 0x1707 + + +enum mp750_state_t +{ + state_idle, + state_warmup, + state_scanning, + state_transfering, + state_finished +}; + +enum mp750_cmd_t +{ + cmd_start_session = 0xdb20, + cmd_select_source = 0xdd20, + cmd_scan_param = 0xde20, + cmd_status = 0xf320, + cmd_abort_session = 0xef20, + cmd_time = 0xeb80, + cmd_read_image = 0xd420, + + cmd_activate = 0xcf60, + cmd_calibrate = 0xe920, + cmd_error_info = 0xff20 +}; + +typedef struct mp750_t +{ + enum mp750_state_t state; + pixma_cmdbuf_t cb; + unsigned raw_width, raw_height; + uint8_t current_status[12]; + + uint8_t *buf, *rawimg, *img; + /* make new buffer for rgb_to_gray to act on */ + uint8_t *imgcol; + unsigned line_size; /* need in 2 functions */ + + unsigned rawimg_left, imgbuf_len, last_block_size, imgbuf_ofs; + int shifted_bytes; + int stripe_shift; /* for 2400dpi */ + unsigned last_block; + + unsigned monochrome:1; + unsigned needs_abort:1; +} mp750_t; + + + +static void mp750_finish_scan (pixma_t * s); +static void check_status (pixma_t * s); + +static int +has_paper (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + return HAS_PAPER (mp->current_status); +} + +static int +is_warming_up (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + return IS_WARMING_UP (mp->current_status); +} + +static int +is_calibrated (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + return IS_CALIBRATED (mp->current_status); +} + +static void +drain_bulk_in (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + while (pixma_read (s->io, mp->buf, IMAGE_BLOCK_SIZE) >= 0); +} + +static int +abort_session (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); +} + +static int +query_status (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mp->cb, cmd_status, 0, 12); + error = pixma_exec (s, &mp->cb); + if (error >= 0) + { + memcpy (mp->current_status, data, 12); + PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u\n", + data[1], data[8], data[7])); + } + return error; +} + +static int +activate (pixma_t * s, uint8_t x) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + uint8_t *data = pixma_newcmd (&mp->cb, cmd_activate, 10, 0); + data[0] = 1; + data[3] = x; + return pixma_exec (s, &mp->cb); +} + +static int +activate_cs (pixma_t * s, uint8_t x) +{ + /*SIM*/ check_status (s); + return activate (s, x); +} + +static int +start_session (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mp->cb, cmd_start_session); +} + +static int +select_source (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + uint8_t *data = pixma_newcmd (&mp->cb, cmd_select_source, 10, 0); + data[0] = (s->param->source == PIXMA_SOURCE_ADF) ? 2 : 1; + data[1] = 1; + return pixma_exec (s, &mp->cb); +} + +static int +has_ccd_sensor (pixma_t * s) +{ + return ((s->cfg->cap & PIXMA_CAP_CCD) != 0); +} + +static int +is_ccd_grayscale (pixma_t * s) +{ + return (has_ccd_sensor (s) && (s->param->channels == 1)); +} + +/* CCD sensors don't have a Grayscale mode, but use color mode instead */ +static unsigned +get_cis_ccd_line_size (pixma_t * s) +{ + return (s->param->wx ? s->param->line_size / s->param->w * s->param->wx + : s->param->line_size) * ((is_ccd_grayscale (s)) ? 3 : 1); +} + +static int +send_scan_param (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + uint8_t *data; + + data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x2e, 0); + pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x04); + pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x06); + pixma_set_be32 (s->param->x, data + 0x08); + pixma_set_be32 (s->param->y, data + 0x0c); + pixma_set_be32 (mp->raw_width, data + 0x10); + pixma_set_be32 (mp->raw_height, data + 0x14); + data[0x18] = 8; /* 8 = color, 4 = grayscale(?) */ + /* GH: No, there is no grayscale for CCD devices, Windows shows same */ + data[0x19] = s->param->depth * ((is_ccd_grayscale (s)) ? 3 : s->param->channels); /* bits per pixel */ + data[0x20] = 0xff; + data[0x23] = 0x81; + data[0x26] = 0x02; + data[0x27] = 0x01; + data[0x29] = mp->monochrome ? 0 : 1; + + return pixma_exec (s, &mp->cb); +} + +static int +calibrate (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mp->cb, cmd_calibrate); +} + +static int +calibrate_cs (pixma_t * s) +{ + /*SIM*/ check_status (s); + return calibrate (s); +} + +static int +request_image_block_ex (pixma_t * s, unsigned *size, uint8_t * info, + unsigned flag) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + int error; + + memset (mp->cb.buf, 0, 10); + pixma_set_be16 (cmd_read_image, mp->cb.buf); + mp->cb.buf[7] = *size >> 8; + mp->cb.buf[8] = 4 | flag; + mp->cb.reslen = pixma_cmd_transaction (s, mp->cb.buf, 10, mp->cb.buf, 6); + mp->cb.expected_reslen = 0; + error = pixma_check_result (&mp->cb); + if (error >= 0) + { + if (mp->cb.reslen == 6) + { + *info = mp->cb.buf[2]; + *size = pixma_get_be16 (mp->cb.buf + 4); + } + else + { + error = PIXMA_EPROTO; + } + } + return error; +} + +static int +request_image_block (pixma_t * s, unsigned *size, uint8_t * info) +{ + return request_image_block_ex (s, size, info, 0); +} + +static int +request_image_block2 (pixma_t * s, uint8_t * info) +{ + unsigned temp = 0; + return request_image_block_ex (s, &temp, info, 0x20); +} + +static int +read_image_block (pixma_t * s, uint8_t * data) +{ + int count, temp; + + count = pixma_read (s->io, data, IMAGE_BLOCK_SIZE); + if (count < 0) + return count; + if (count == IMAGE_BLOCK_SIZE) + { + int error = pixma_read (s->io, &temp, 0); + if (error < 0) + { + PDBG (pixma_dbg + (1, "WARNING: reading zero-length packet failed %d\n", error)); + } + } + return count; +} + +static int +read_error_info (pixma_t * s, void *buf, unsigned size) +{ + unsigned len = 16; + mp750_t *mp = (mp750_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); + error = pixma_exec (s, &mp->cb); + if (error >= 0 && buf) + { + if (len < size) + size = len; + /* NOTE: I've absolutely no idea what the returned data mean. */ + memcpy (buf, data, size); + error = len; + } + return error; +} + +static int +send_time (pixma_t * s) +{ + /* TODO: implement send_time() */ + UNUSED (s); + PDBG (pixma_dbg (3, "send_time() is not yet implemented.\n")); + return 0; +} + +static int +handle_interrupt (pixma_t * s, int timeout) +{ + int error; + uint8_t intr[16]; + + error = pixma_wait_interrupt (s->io, intr, sizeof (intr), timeout); + if (error == PIXMA_ETIMEDOUT) + return 0; + if (error < 0) + return error; + if (error != 16) + { + PDBG (pixma_dbg (1, "WARNING: unexpected interrupt packet length %d\n", + error)); + return PIXMA_EPROTO; + } + + if (intr[10] & 0x40) + send_time (s); + if (intr[12] & 0x40) + query_status (s); + if (intr[15] & 1) + s->events = PIXMA_EV_BUTTON2; /* b/w scan */ + if (intr[15] & 2) + s->events = PIXMA_EV_BUTTON1; /* color scan */ + return 1; +} + +static void +check_status (pixma_t * s) +{ + while (handle_interrupt (s, 0) > 0); +} + +static int +step1 (pixma_t * s) +{ + int error, tmo; + + error = activate (s, 0); + if (error < 0) + return error; + error = query_status (s); + if (error < 0) + return error; + if (s->param->source == PIXMA_SOURCE_ADF && !has_paper (s)) + return PIXMA_ENO_PAPER; + error = activate_cs (s, 0); + /*SIM*/ if (error < 0) + return error; + error = activate_cs (s, 0x20); + if (error < 0) + return error; + + tmo = 60; + error = calibrate_cs (s); + while (error == PIXMA_EBUSY && --tmo >= 0) + { + if (s->cancel) + return PIXMA_ECANCELED; + PDBG (pixma_dbg + (2, "Scanner is busy. Timed out in %d sec.\n", tmo + 1)); + pixma_sleep (1000000); + error = calibrate_cs (s); + } + return error; +} + +static void +shift_rgb (const uint8_t * src, unsigned pixels, + int sr, int sg, int sb, int stripe_shift, + int line_size, uint8_t * dst) +{ + unsigned st; + + for (; pixels != 0; pixels--) + { + st = (pixels % 2 == 0) ? -2 * stripe_shift * line_size : 0; + *(dst++ + sr + st) = *src++; + *(dst++ + sg + st) = *src++; + *(dst++ + sb + st) = *src++; + } +} + +static uint8_t * +rgb_to_gray (uint8_t * gptr, const uint8_t * cptr, unsigned pixels, unsigned c) +{ + unsigned i, j, g; + + /* gptr: destination gray scale buffer */ + /* cptr: source color scale buffer */ + /* c: 3 for 3-channel single-byte data, 6 for double-byte data */ + + for (i=0; i < pixels; i++) + { + for (j = 0, g = 0; j < 3; j++) + { + g += *cptr++; + if (c == 6) g += (*cptr++ << 8); + } + g /= 3; + *gptr++ = g; + if (c == 6) *gptr++ = (g >> 8); + } + return gptr; +} + +static int +calc_component_shifting (pixma_t * s) +{ + switch (s->cfg->pid) + { + case MP760_PID: + switch (s->param->ydpi) + { + case 300: + return 3; + case 600: + return 6; + default: + return s->param->ydpi / 75; + } + /* never reached */ + break; + + case MP750_PID: + case MP780_PID: + default: + return 2 * s->param->ydpi / 75; + } +} + +static void +workaround_first_command (pixma_t * s) +{ + /* FIXME: Send a dummy command because the device doesn't response to the + first command that is sent directly after the USB interface has been + set up. Why? USB isn't set up properly? */ + uint8_t cmd[10]; + int error; + + if (s->cfg->pid == MP750_PID) + return; /* MP750 doesn't have this problem(?) */ + + PDBG (pixma_dbg + (1, + "Work-around for the problem: device doesn't response to the first command.\n")); + memset (cmd, 0, sizeof (cmd)); + pixma_set_be16 (cmd_calibrate, cmd); + error = pixma_write (s->io, cmd, 10); + if (error != 10) + { + if (error < 0) + { + PDBG (pixma_dbg + (1, " Sending a dummy command failed: %s\n", + pixma_strerror (error))); + } + else + { + PDBG (pixma_dbg + (1, " Sending a dummy command failed: count = %d\n", error)); + } + return; + } + error = pixma_read (s->io, cmd, sizeof (cmd)); + if (error >= 0) + { + PDBG (pixma_dbg + (1, " Got %d bytes response from a dummy command.\n", error)); + } + else + { + PDBG (pixma_dbg + (1, " Reading response of a dummy command failed: %s\n", + pixma_strerror (error))); + } +} + +static int +mp750_open (pixma_t * s) +{ + mp750_t *mp; + uint8_t *buf; + + mp = (mp750_t *) calloc (1, sizeof (*mp)); + if (!mp) + return PIXMA_ENOMEM; + + buf = (uint8_t *) malloc (CMDBUF_SIZE); + if (!buf) + { + free (mp); + return PIXMA_ENOMEM; + } + + s->subdriver = mp; + mp->state = state_idle; + + /* ofs: 0 1 2 3 4 5 6 7 8 9 + cmd: cmd1 cmd2 00 00 00 00 00 00 00 00 + data length-^^^^^ => cmd_len_field_ofs + |--------- cmd_header_len --------| + + res: res1 res2 + |---------| res_header_len + */ + mp->cb.buf = buf; + mp->cb.size = CMDBUF_SIZE; + mp->cb.res_header_len = 2; + mp->cb.cmd_header_len = 10; + mp->cb.cmd_len_field_ofs = 7; + + handle_interrupt (s, 200); + workaround_first_command (s); + return 0; +} + +static void +mp750_close (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + + mp750_finish_scan (s); + free (mp->cb.buf); + free (mp); + s->subdriver = NULL; +} + +static int +mp750_check_param (pixma_t * s, pixma_scan_param_t * sp) +{ + unsigned raw_width; + + UNUSED (s); + + sp->depth = 8; /* FIXME: Does MP750 supports other depth? */ + + /* GH: my implementation */ + /* if ((sp->channels == 3) || (is_ccd_grayscale (s))) + raw_width = ALIGN_SUP (sp->w, 4); + else + raw_width = ALIGN_SUP (sp->w, 12);*/ + + /* the above code gives segmentation fault?!? why... it seems to work in the mp750_scan function */ + raw_width = ALIGN_SUP (sp->w, 4); + + /*sp->line_size = raw_width * sp->channels;*/ + sp->line_size = raw_width * sp->channels * (sp->depth / 8); /* no cropping? */ + return 0; +} + +static int +mp750_scan (pixma_t * s) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + int error; + uint8_t *buf; + unsigned size, dpi, spare; + + dpi = s->param->ydpi; + /* add a stripe shift for 2400dpi */ + mp->stripe_shift = (dpi == 2400) ? 4 : 0; + + if (mp->state != state_idle) + return PIXMA_EBUSY; + + /* clear interrupt packets buffer */ + while (handle_interrupt (s, 0) > 0) + { + } + + /* if (s->param->channels == 1) + mp->raw_width = ALIGN_SUP (s->param->w, 12); + else + mp->raw_width = ALIGN_SUP (s->param->w, 4);*/ + + /* change to use CCD grayscale mode --- why does this give segmentation error at runtime in mp750_check_param? */ + if ((s->param->channels == 3) || (is_ccd_grayscale (s))) + mp->raw_width = ALIGN_SUP (s->param->w, 4); + else + mp->raw_width = ALIGN_SUP (s->param->w, 12); + /* not sure about MP750, but there is no need for aligning at 12 for the MP760/770, MP780/790 since always use CCD color mode */ + + /* modify for stripe shift */ + spare = 2 * calc_component_shifting (s) + 2 * mp->stripe_shift; /* FIXME: or maybe (2*... + 1)? */ + mp->raw_height = s->param->h + spare; + PDBG (pixma_dbg (3, "raw_width=%u raw_height=%u dpi=%u\n", + mp->raw_width, mp->raw_height, dpi)); + + /* PDBG (pixma_dbg (4, "line_size=%"PRIu64"\n",s->param->line_size)); */ + + mp->line_size = get_cis_ccd_line_size (s); /* scanner hardware line_size multiplied by 3 for CCD grayscale */ + + size = 8 + 2 * IMAGE_BLOCK_SIZE + spare * mp->line_size; + buf = (uint8_t *) malloc (size); + if (!buf) + return PIXMA_ENOMEM; + mp->buf = buf; + mp->rawimg = buf; + mp->imgbuf_ofs = spare * mp->line_size; + mp->imgcol = mp->rawimg + IMAGE_BLOCK_SIZE + 8; /* added to make rgb->gray */ + mp->img = mp->rawimg + IMAGE_BLOCK_SIZE + 8; + mp->imgbuf_len = IMAGE_BLOCK_SIZE + mp->imgbuf_ofs; + mp->rawimg_left = 0; + mp->last_block_size = 0; + mp->shifted_bytes = -(int) mp->imgbuf_ofs; + + error = step1 (s); + if (error >= 0) + error = start_session (s); + if (error >= 0) + mp->state = state_warmup; + if (error >= 0) + error = select_source (s); + if (error >= 0) + error = send_scan_param (s); + if (error < 0) + { + mp750_finish_scan (s); + return error; + } + return 0; +} + + +static int +mp750_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) +{ + mp750_t *mp = (mp750_t *) s->subdriver; + int error; + uint8_t info; + unsigned block_size, bytes_received, n; + int shift[3], base_shift; + int c; + + c = ((is_ccd_grayscale (s)) ? 3 : s->param->channels) * s->param->depth / 8; /* single-byte or double-byte data */ + + if (mp->state == state_warmup) + { + int tmo = 60; + + query_status (s); + check_status (s); + /*SIM*/ while (!is_calibrated (s) && --tmo >= 0) + { + if (s->cancel) + return PIXMA_ECANCELED; + if (handle_interrupt (s, 1000) > 0) + { + block_size = 0; + error = request_image_block (s, &block_size, &info); + /*SIM*/ if (error < 0) + return error; + } + } + if (tmo < 0) + { + PDBG (pixma_dbg (1, "WARNING: Timed out waiting for calibration\n")); + return PIXMA_ETIMEDOUT; + } + pixma_sleep (100000); + query_status (s); + if (is_warming_up (s) || !is_calibrated (s)) + { + PDBG (pixma_dbg (1, "WARNING: Wrong status: wup=%d cal=%d\n", + is_warming_up (s), is_calibrated (s))); + return PIXMA_EPROTO; + } + block_size = 0; + request_image_block (s, &block_size, &info); + /*SIM*/ mp->state = state_scanning; + mp->last_block = 0; + } + + /* TODO: Move to other place, values are constant. */ + base_shift = calc_component_shifting (s) * mp->line_size; + if (s->param->source == PIXMA_SOURCE_ADF) + { + shift[0] = 0; + shift[1] = -base_shift; + shift[2] = -2 * base_shift; + } + else + { + shift[0] = -2 * base_shift; + shift[1] = -base_shift; + shift[2] = 0; + } + + do + { + if (mp->last_block_size > 0) + { + block_size = mp->imgbuf_len - mp->last_block_size; + memcpy (mp->img, mp->img + mp->last_block_size, block_size); + } + + do + { + if (s->cancel) + return PIXMA_ECANCELED; + if (mp->last_block) + { + /* end of image */ + info = mp->last_block; + if (info != 0x38) + { + query_status (s); + /*SIM*/ while ((info & 0x28) != 0x28) + { + pixma_sleep (10000); + error = request_image_block2 (s, &info); + if (s->cancel) + return PIXMA_ECANCELED; /* FIXME: Is it safe to cancel here? */ + if (error < 0) + return error; + } + } + mp->needs_abort = (info != 0x38); + mp->last_block = info; + mp->state = state_finished; + return 0; + } + + check_status (s); + /*SIM*/ while (handle_interrupt (s, 1) > 0); + /*SIM*/ block_size = IMAGE_BLOCK_SIZE; + error = request_image_block (s, &block_size, &info); + if (error < 0) + { + if (error == PIXMA_ECANCELED) + read_error_info (s, NULL, 0); + return error; + } + mp->last_block = info; + if ((info & ~0x38) != 0) + { + PDBG (pixma_dbg (1, "WARNING: Unknown info byte %x\n", info)); + } + if (block_size == 0) + { + /* no image data at this moment. */ + pixma_sleep (10000); + } + } + while (block_size == 0); + + error = read_image_block (s, mp->rawimg + mp->rawimg_left); + if (error < 0) + { + mp->state = state_transfering; + return error; + } + bytes_received = error; + PASSERT (bytes_received == block_size); + + /* TODO: simplify! */ + mp->rawimg_left += bytes_received; + n = mp->rawimg_left / 3; + /* n = number of pixels in the buffer? */ + + /* Color to Grayscale converion for CCD sensor */ + if (is_ccd_grayscale (s)) { + shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, + mp->imgcol + mp->imgbuf_ofs); + /* dst: img, src: imgcol */ + rgb_to_gray (mp->img, mp->imgcol, n, c); /* cropping occurs later? */ + PDBG (pixma_dbg (4, "*fill_buffer: did grayscale conversion \n")); + } + /* Color image processing */ + else { + shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, + mp->img + mp->imgbuf_ofs); + PDBG (pixma_dbg (4, "*fill_buffer: no grayscale conversion---keep color \n")); + } + + /* entering remaining unprocessed bytes after last complete pixel into mp->rawimg buffer -- no influence on mp->img */ + n *= 3; + mp->shifted_bytes += n; + mp->rawimg_left -= n; /* rawimg_left = 0, 1 or 2 bytes left in the buffer. */ + mp->last_block_size = n; + memcpy (mp->rawimg, mp->rawimg + n, mp->rawimg_left); + + } + while (mp->shifted_bytes <= 0); + + if ((unsigned) mp->shifted_bytes < mp->last_block_size) + { + if (is_ccd_grayscale (s)) + ib->rptr = mp->img + mp->last_block_size/3 - mp->shifted_bytes/3; /* testing---works OK */ + else + ib->rptr = mp->img + mp->last_block_size - mp->shifted_bytes; + } + else + ib->rptr = mp->img; + if (is_ccd_grayscale (s)) + ib->rend = mp->img + mp->last_block_size/3; /* testing---works OK */ + else + ib->rend = mp->img + mp->last_block_size; + return ib->rend - ib->rptr; +} + +static void +mp750_finish_scan (pixma_t * s) +{ + int error; + mp750_t *mp = (mp750_t *) s->subdriver; + + switch (mp->state) + { + case state_transfering: + drain_bulk_in (s); + /* fall through */ + case state_scanning: + case state_warmup: + error = abort_session (s); + if (error == PIXMA_ECANCELED) + read_error_info (s, NULL, 0); + /* fall through */ + case state_finished: + if (s->param->source == PIXMA_SOURCE_FLATBED) + { + /*SIM*/ query_status (s); + if (abort_session (s) == PIXMA_ECANCELED) + { + read_error_info (s, NULL, 0); + query_status (s); + } + } + query_status (s); + /*SIM*/ activate (s, 0); + if (mp->needs_abort) + { + mp->needs_abort = 0; + abort_session (s); + } + free (mp->buf); + mp->buf = mp->rawimg = NULL; + mp->state = state_idle; + /* fall through */ + case state_idle: + break; + } +} + +static void +mp750_wait_event (pixma_t * s, int timeout) +{ + /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for + * instance. */ + while (s->events == 0 && handle_interrupt (s, timeout) > 0) + { + } +} + +static int +mp750_get_status (pixma_t * s, pixma_device_status_t * status) +{ + int error; + + error = query_status (s); + if (error < 0) + return error; + status->hardware = PIXMA_HARDWARE_OK; + status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; + status->cal = + (is_calibrated (s)) ? PIXMA_CALIBRATION_OK : PIXMA_CALIBRATION_OFF; + status->lamp = (is_warming_up (s)) ? PIXMA_LAMP_WARMING_UP : PIXMA_LAMP_OK; + return 0; +} + + +static const pixma_scan_ops_t pixma_mp750_ops = { + mp750_open, + mp750_close, + mp750_scan, + mp750_fill_buffer, + mp750_finish_scan, + mp750_wait_event, + mp750_check_param, + mp750_get_status +}; + +#define DEVICE(name, model, pid, dpi, cap) { \ + name, /* name */ \ + model, /* model */ \ + 0x04a9, pid, /* vid pid */ \ + 0, /* iface */ \ + &pixma_mp750_ops, /* ops */ \ + 0, /* min_xdpi not used in this subdriver */ \ + dpi, 2*(dpi), /* xdpi, ydpi */ \ + 0, 0, /* adftpu_min_dpi & adftpu_max_dpi not used in this subdriver */ \ + 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ + 637, 877, /* width, height */ \ + PIXMA_CAP_CCD| /* all scanners with CCD */ \ + PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ +} + +const pixma_config_t pixma_mp750_devices[] = { + DEVICE ("Canon PIXMA MP750", "MP750", MP750_PID, 2400, PIXMA_CAP_ADF), + DEVICE ("Canon PIXMA MP760/770", "MP760/770", MP760_PID, 2400, PIXMA_CAP_TPU), + DEVICE ("Canon PIXMA MP780/790", "MP780/790", MP780_PID, 2400, PIXMA_CAP_ADF), + DEVICE (NULL, NULL, 0, 0, 0) +}; diff --git a/backend/pixma/pixma_mp800.c b/backend/pixma/pixma_mp800.c new file mode 100644 index 0000000..feef611 --- /dev/null +++ b/backend/pixma/pixma_mp800.c @@ -0,0 +1,2434 @@ +/* SANE - Scanner Access Now Easy. + + Copyright (C) 2011-2019 Rolf Bensch + Copyright (C) 2007-2009 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. + */ +/* test cases + 1. short USB packet (must be no -ETIMEDOUT) + 2. cancel using button on the printer (look for abort command) + 3. start scan while busy (status 0x1414) + 4. cancel using ctrl-c (must send abort command) + */ + +#define TPU_48 /* uncomment to activate TPU scan at 48 bits */ +/*#define DEBUG_TPU_48*//* uncomment to debug 48 bits TPU on a non TPU device */ +/*#define DEBUG_TPU_24*//* uncomment to debug 24 bits TPU on a non TPU device */ + +/*#define TPUIR_USE_RGB*/ /* uncomment to use RGB channels and convert them to gray; otherwise use R channel only */ + +#include "../include/sane/config.h" + +#include +#include +#include +#include /* localtime(C90) */ + +#include "pixma_rename.h" +#include "pixma_common.h" +#include "pixma_io.h" + +/* Some macro code to enhance readability */ +#define RET_IF_ERR(x) do { \ + if ((error = (x)) < 0) \ + return error; \ + } while(0) + +#define WAIT_INTERRUPT(x) do { \ + error = handle_interrupt (s, x); \ + if (s->cancel) \ + return PIXMA_ECANCELED; \ + if (error != PIXMA_ECANCELED && error < 0) \ + return error; \ + } while(0) + +#ifdef __GNUC__ +# define UNUSED(v) (void) v +#else +# define UNUSED(v) +#endif + +/* Size of the command buffer should be multiple of wMaxPacketLength and + greater than 4096+24. + 4096 = size of gamma table. 24 = header + checksum */ +#define IMAGE_BLOCK_SIZE (512*1024) +#define CMDBUF_SIZE (4096 + 24) +#define DEFAULT_GAMMA 2.0 /***** Gamma different from 1.0 is potentially impacting color profile generation *****/ +#define UNKNOWN_PID 0xffff + +#define CANON_VID 0x04a9 + +/* Generation 1 */ +#define MP800_PID 0x170d +#define MP800R_PID 0x170e +#define MP830_PID 0x1713 + +/* Generation 2 */ +#define MP810_PID 0x171a +#define MP960_PID 0x171b + +/* Generation 3 */ +/* PIXMA 2007 vintage */ +#define MP970_PID 0x1726 + +/* Flatbed scanner CCD (2007) */ +#define CS8800F_PID 0x1901 + +/* PIXMA 2008 vintage */ +#define MP980_PID 0x172d + +/* Generation 4 */ +#define MP990_PID 0x1740 + +/* Flatbed scanner CCD (2010) */ +#define CS9000F_PID 0x1908 + +/* 2010 new device (untested) */ +#define MG8100_PID 0x174b /* CCD */ + +/* 2011 new device (untested) */ +#define MG8200_PID 0x1756 /* CCD */ + +/* 2013 new device */ +#define CS9000F_MII_PID 0x190d + +/* Generation 4 XML messages that encapsulates the Pixma protocol messages */ +#define XML_START_1 \ +"\ +\ +StartJob\ +00000001\ +1" + +#define XML_START_2 \ +"\ +\ +VendorCmd\ +00000001\ +ModeShift1\ +" + +#define XML_END \ +"\ +\ +EndJob\ +00000001\ +" + +#define XML_OK "OK" + +enum mp810_state_t +{ + state_idle, + state_warmup, + state_scanning, + state_transfering, + state_finished +}; + +enum mp810_cmd_t +{ + cmd_start_session = 0xdb20, + cmd_select_source = 0xdd20, + cmd_gamma = 0xee20, + cmd_scan_param = 0xde20, + cmd_status = 0xf320, + cmd_abort_session = 0xef20, + cmd_time = 0xeb80, + cmd_read_image = 0xd420, + cmd_error_info = 0xff20, + + cmd_start_calibrate_ccd_3 = 0xd520, + cmd_end_calibrate_ccd_3 = 0xd720, + cmd_scan_param_3 = 0xd820, + cmd_scan_start_3 = 0xd920, + cmd_status_3 = 0xda20, + cmd_get_tpu_info_3 = 0xf520, + cmd_set_tpu_info_3 = 0xea20, + + cmd_e920 = 0xe920 /* seen in MP800 */ +}; + +typedef struct mp810_t +{ + enum mp810_state_t state; + pixma_cmdbuf_t cb; + uint8_t *imgbuf; + uint8_t current_status[16]; + unsigned last_block; + uint8_t generation; + /* for Generation 3 and CCD shift */ + uint8_t *linebuf; + uint8_t *data_left_ofs; + unsigned data_left_len; + int shift[3]; + unsigned color_shift; + unsigned stripe_shift; + unsigned stripe_shift2; /* added for MP810, MP960 at 4800dpi & 9000F at 9600dpi */ + unsigned jumplines; /* added for MP810, MP960 at 4800dpi & 9000F at 9600dpi */ + uint8_t tpu_datalen; + uint8_t tpu_data[0x40]; +} mp810_t; + +/* + STAT: 0x0606 = ok, + 0x1515 = failed (PIXMA_ECANCELED), + 0x1414 = busy (PIXMA_EBUSY) + + Transaction scheme + 1. command_header/data | result_header + 2. command_header | result_header/data + 3. command_header | result_header/image_data + + - data has checksum in the last byte. + - image_data has no checksum. + - data and image_data begins in the same USB packet as + command_header or result_header. + + command format #1: + u16be cmd + u8[6] 0 + u8[4] 0 + u32be PLEN parameter length + u8[PLEN-1] parameter + u8 parameter check sum + result: + u16be STAT + u8 0 + u8 0 or 0x21 if STAT == 0x1414 + u8[4] 0 + + command format #2: + u16be cmd + u8[6] 0 + u8[4] 0 + u32be RLEN result length + result: + u16be STAT + u8[6] 0 + u8[RLEN-1] result + u8 result check sum + + command format #3: (only used by read_image_block) + u16be 0xd420 + u8[6] 0 + u8[4] 0 + u32be max. block size + 8 + result: + u16be STAT + u8[6] 0 + u8 block info bitfield: 0x8 = end of scan, 0x10 = no more paper, 0x20 = no more data + u8[3] 0 + u32be ILEN image data size + u8[ILEN] image data + */ + +static void mp810_finish_scan (pixma_t * s); + +static int is_scanning_from_adf (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_ADF + || s->param->source == PIXMA_SOURCE_ADFDUP); +} + +static int is_scanning_from_adfdup (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_ADFDUP); +} + +static int is_scanning_from_tpu (pixma_t * s) +{ + return (s->param->source == PIXMA_SOURCE_TPU); +} + +static int send_xml_dialog (pixma_t * s, const char * xml_message) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + int datalen; + + datalen = pixma_cmd_transaction (s, xml_message, strlen (xml_message), + mp->cb.buf, 1024); + if (datalen < 0) + return datalen; + + mp->cb.buf[datalen] = 0; + + PDBG(pixma_dbg (10, "XML message sent to scanner:\n%s\n", xml_message)); + PDBG(pixma_dbg (10, "XML response back from scanner:\n%s\n", mp->cb.buf)); + + return (strcasestr ((const char *) mp->cb.buf, XML_OK) != NULL); +} + +static void new_cmd_tpu_msg (pixma_t *s, pixma_cmdbuf_t * cb, uint16_t cmd) +{ + pixma_newcmd (cb, cmd, 0, 0); + cb->buf[3] = (is_scanning_from_tpu (s)) ? 0x01 : 0x00; +} + +static int start_session (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + + new_cmd_tpu_msg (s, &mp->cb, cmd_start_session); + return pixma_exec (s, &mp->cb); +} + +static int start_scan_3 (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + + new_cmd_tpu_msg (s, &mp->cb, cmd_scan_start_3); + return pixma_exec (s, &mp->cb); +} + +static int send_cmd_start_calibrate_ccd_3 (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + + pixma_newcmd (&mp->cb, cmd_start_calibrate_ccd_3, 0, 0); + mp->cb.buf[3] = 0x01; + return pixma_exec (s, &mp->cb); +} + +static int is_calibrated (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + if (mp->generation >= 3) + { + return ((mp->current_status[0] & 0x01) == 1); + } + if (mp->generation == 1) + { + return (mp->current_status[8] == 1); + } + else + { + return (mp->current_status[9] == 1); + } +} + +static int has_paper (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + + if (is_scanning_from_adfdup (s)) + return (mp->current_status[1] == 0 || mp->current_status[2] == 0); + else + return (mp->current_status[1] == 0); +} + +static void drain_bulk_in (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + while (pixma_read (s->io, mp->imgbuf, IMAGE_BLOCK_SIZE) >= 0) + ; +} + +static int abort_session (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); +} + +static int send_cmd_e920 (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + return pixma_exec_short_cmd (s, &mp->cb, cmd_e920); +} + +static int select_source (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + uint8_t *data; + + data = pixma_newcmd (&mp->cb, cmd_select_source, 12, 0); + data[5] = ((mp->generation == 2) ? 1 : 0); + switch (s->param->source) + { + case PIXMA_SOURCE_FLATBED: + data[0] = 1; + data[1] = 1; + break; + + case PIXMA_SOURCE_ADF: + data[0] = 2; + data[5] = 1; + data[6] = 1; + break; + + case PIXMA_SOURCE_ADFDUP: + data[0] = 2; + data[5] = 3; + data[6] = 3; + break; + + case PIXMA_SOURCE_TPU: + data[0] = 4; + data[1] = 2; + break; + } + return pixma_exec (s, &mp->cb); +} + +static int send_get_tpu_info_3 (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mp->cb, cmd_get_tpu_info_3, 0, 0x34); + RET_IF_ERR(pixma_exec (s, &mp->cb)); + memcpy (mp->tpu_data, data, 0x34); + return error; +} + +static int send_set_tpu_info (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + uint8_t *data; + + if (mp->tpu_datalen == 0) + return 0; + data = pixma_newcmd (&mp->cb, cmd_set_tpu_info_3, 0x34, 0); + memcpy (data, mp->tpu_data, 0x34); + return pixma_exec (s, &mp->cb); +} + +static int send_gamma_table (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + const uint8_t *lut = s->param->gamma_table; + uint8_t *data; + + if (mp->generation == 1) + { + data = pixma_newcmd (&mp->cb, cmd_gamma, 4096 + 8, 0); + data[0] = (s->param->channels == 3) ? 0x10 : 0x01; + pixma_set_be16 (0x1004, data + 2); + if (lut) + memcpy (data + 4, lut, 4096); + else + pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 4096); + } + else + { + /* FIXME: Gamma table for 2nd generation: 1024 * uint16_le */ + data = pixma_newcmd (&mp->cb, cmd_gamma, 2048 + 8, 0); + data[0] = 0x10; + pixma_set_be16 (0x0804, data + 2); + if (lut) + { + int i; + for (i = 0; i < 1024; i++) + { + int j = (i << 2) + (i >> 8); + data[4 + 2 * i + 0] = lut[j]; + data[4 + 2 * i + 1] = lut[j]; + } + } + else + { + int i; + pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 2048); + for (i = 0; i < 1024; i++) + { + int j = (i << 1) + (i >> 9); + data[4 + 2 * i + 0] = data[4 + j]; + data[4 + 2 * i + 1] = data[4 + j]; + } + } + } + return pixma_exec (s, &mp->cb); +} + +static unsigned calc_raw_width (const mp810_t * mp, + const pixma_scan_param_t * param) +{ + unsigned raw_width; + /* NOTE: Actually, we can send arbitary width to MP810. Lines returned + are always padded to multiple of 4 or 12 pixels. Is this valid for + other models, too? */ + if (mp->generation >= 2) + { + raw_width = ALIGN_SUP (param->w + param->xs, 32); + /* PDBG (pixma_dbg (4, "*calc_raw_width***** width %u extended by %u and rounded to %u *****\n", param->w, param->xs, raw_width)); */ + } + else if (param->channels == 1) + { + raw_width = ALIGN_SUP (param->w + param->xs, 12); + } + else + { + raw_width = ALIGN_SUP (param->w + param->xs, 4); + } + return raw_width; +} + +static int has_ccd_sensor (pixma_t * s) +{ + return ((s->cfg->cap & PIXMA_CAP_CCD) != 0); +} + +#if 0 +static int is_color (pixma_t * s) +{ + return (s->param->mode == PIXMA_SCAN_MODE_COLOR); +} + +static int is_color_48 (pixma_t * s) +{ + return (s->param->mode == PIXMA_SCAN_MODE_COLOR_48); +} + +static int is_color_negative (pixma_t * s) +{ + return (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_COLOR); +} + +static int is_color_all (pixma_t * s) +{ + return (is_color (s) || is_color_48 (s) || is_color_negative (s)); +} +#endif + +static int is_gray (pixma_t * s) +{ + return (s->param->mode == PIXMA_SCAN_MODE_GRAY); +} + +static int is_gray_16 (pixma_t * s) +{ + return (s->param->mode == PIXMA_SCAN_MODE_GRAY_16); +} + +static int is_gray_negative (pixma_t * s) +{ + return (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_GRAY); +} + +static int is_gray_all (pixma_t * s) +{ + return (is_gray (s) || is_gray_16 (s) || is_gray_negative (s)); +} + +static int is_lineart (pixma_t * s) +{ + return (s->param->mode == PIXMA_SCAN_MODE_LINEART); +} + +static int is_tpuir (pixma_t * s) +{ + return (s->param->mode == PIXMA_SCAN_MODE_TPUIR); +} + +/* CCD sensors don't have neither a Grayscale mode nor a Lineart mode, + * but use color mode instead */ +static unsigned get_cis_ccd_line_size (pixma_t * s) +{ + return (( + s->param->wx ? s->param->line_size / s->param->w * s->param->wx + : s->param->line_size) + * ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : 1)); +} + +static unsigned calc_shifting (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + + /* If stripes shift needed (CCD devices), how many pixels shift */ + mp->stripe_shift = 0; + mp->stripe_shift2 = 0; + mp->jumplines = 0; + + switch (s->cfg->pid) + { + case MP800_PID: + case MP800R_PID: + case MP830_PID: + if (s->param->xdpi == 2400) + { + if (is_scanning_from_tpu(s)) + mp->stripe_shift = 6; + else + mp->stripe_shift = 3; + } + if (s->param->ydpi > 75) + { + mp->color_shift = s->param->ydpi / ((s->param->ydpi < 1200) ? 150 : 75); + + if (is_scanning_from_tpu (s)) + mp->color_shift = s->param->ydpi / 75; + + /* If you're trying to decipher this color-shifting code, + the following line is where the magic is revealed. */ + mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); + if (is_scanning_from_adf (s)) + { /* ADF */ + mp->shift[0] = 0; + mp->shift[2] = 2 * mp->shift[1]; + } + else + { /* Flatbed or TPU */ + mp->shift[0] = 2 * mp->shift[1]; + mp->shift[2] = 0; + } + } + break; + + case MP970_PID: /* MP970 at 4800 dpi */ + case CS8800F_PID: /* CanoScan 8800F at 4800 dpi */ + if (s->param->xdpi == 4800) + { + if (is_scanning_from_tpu (s)) + mp->stripe_shift = 6; + else + mp->stripe_shift = 3; + } + break; + + case CS9000F_PID: /* CanoScan 9000F at 4800 dpi */ + case CS9000F_MII_PID: + if (s->param->xdpi == 4800) + { + if (is_scanning_from_tpu (s)) + mp->stripe_shift = 6; /* should work for CS9000F same as manual */ + else + mp->stripe_shift = 3; + } + if (s->param->xdpi == 9600) + { + if (is_scanning_from_tpu (s)) + { + /* need to double up for TPU */ + mp->stripe_shift = 6; /* for 1st set of 4 images */ + /* unfortunately there are 2 stripe shifts */ + mp->stripe_shift2 = 6; /* for 2nd set of 4 images */ + mp->jumplines = 32; /* try 33 or 34 */ + } + /* there is no 9600dpi support in flatbed mode */ + } + break; + + case MP960_PID: + if (s->param->xdpi == 2400) + { + if (is_scanning_from_tpu (s)) + mp->stripe_shift = 6; + else + mp->stripe_shift = 3; + } + if (s->param->xdpi == 4800) + { + if (is_scanning_from_tpu (s)) + { + mp->stripe_shift = 6; + mp->stripe_shift2 = 6; + } + else + { + mp->stripe_shift = 3; + mp->stripe_shift2 = 3; + } + mp->jumplines = 33; /* better than 32 or 34 : applies to flatbed & TPU */ + } + break; + + case MP810_PID: + if (s->param->xdpi == 2400) + { + if (is_scanning_from_tpu (s)) + mp->stripe_shift = 6; + else + mp->stripe_shift = 3; + } + if (s->param->xdpi == 4800) + { + if (is_scanning_from_tpu (s)) + { + mp->stripe_shift = 6; + mp->stripe_shift2 = 6; + } + else + { + mp->stripe_shift = 3; + mp->stripe_shift2 = 3; + } + mp->jumplines = 33; /* better than 32 or 34 : applies to flatbed & TPU */ + } + break; + + case MP990_PID: + if (s->param->xdpi == 4800) + { + if (is_scanning_from_tpu (s)) + { + mp->stripe_shift = 6; + mp->stripe_shift2 = 6; + } + else + { + mp->stripe_shift = 3; + mp->stripe_shift2 = 3; + } + mp->jumplines = 34; /* better than 32 or 34 : applies to flatbed & TPU */ + } + break; + + default: /* Default, and all CIS devices */ + break; + } + /* If color plane shift (CCD devices), how many pixels shift */ + mp->color_shift = mp->shift[0] = mp->shift[1] = mp->shift[2] = 0; + if (s->param->ydpi > 75) + { + switch (s->cfg->pid) + { + case MP970_PID: + case CS8800F_PID: /* CanoScan 8800F */ + mp->color_shift = s->param->ydpi / 50; + mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); + mp->shift[0] = 0; + mp->shift[2] = 2 * mp->shift[1]; + break; + + case CS9000F_PID: /* CanoScan 9000F */ + case CS9000F_MII_PID: + mp->color_shift = s->param->ydpi / 30; + mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); + mp->shift[0] = 0; + mp->shift[2] = 2 * mp->shift[1]; + break; + + case MP980_PID: + case MP990_PID: + case MG8200_PID: + if (s->param->ydpi > 150) + { + mp->color_shift = s->param->ydpi / 75; + mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); + mp->shift[0] = 0; + mp->shift[2] = 2 * mp->shift[1]; + } + break; + + case MP810_PID: + case MP960_PID: + mp->color_shift = s->param->ydpi / 50; + if (is_scanning_from_tpu (s)) + mp->color_shift = s->param->ydpi / 50; + mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); + mp->shift[0] = 2 * mp->shift[1]; + mp->shift[2] = 0; + break; + + default: + break; + } + } + /* special settings for 16 bit flatbed mode @ 75 dpi + * minimum of 150 dpi is used yet */ + /* else if (!is_scanning_from_tpu (s)) + { + switch (s->cfg->pid) + { + case CS9000F_PID: + case CS9000F_MII_PID: + if (is_color_48 (s) || is_gray_16 (s)) + { + mp->color_shift = 5; + mp->shift[1] = 0; + mp->shift[0] = 0; + mp->shift[2] = 0; + } + break; + } + } */ + /* PDBG (pixma_dbg (4, "*calc_shifing***** color_shift = %u, stripe_shift = %u, jumplines = %u *****\n", + mp->color_shift, mp->stripe_shift, mp->jumplines)); */ + return (2 * mp->color_shift + mp->stripe_shift + mp->jumplines); /* note impact of stripe shift2 later if needed! */ +} + +static int send_scan_param (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + uint8_t *data; + unsigned raw_width = calc_raw_width (mp, s->param); + unsigned h, h1, h2, shifting; + + /* TPU scan does not support lineart */ + if (is_scanning_from_tpu (s) && is_lineart (s)) + { + return PIXMA_ENOTSUP; + } + + shifting = calc_shifting (s); + h1 = s->param->h + shifting; /* add lines for color shifting */ + /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 1 %u \n", h1 )); */ + if (mp->generation >= 4) /* use most global condition */ + { + /* tested for MP960, 9000F */ + /* add lines for color shifting */ + /* otherwise you cannot scan all lines defined for flatbed mode */ + /* this shouldn't affect TPU mode */ + h2 = s->cfg->height * s->param->ydpi / 75 + shifting; + /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 2 %u = %u max. lines for scanner + %u lines for color shifting \n", h2, s->cfg->height * s->param->ydpi / 75, shifting )); */ + } + else + { + /* TODO: Check for other scanners. */ + h2 = s->cfg->height * s->param->ydpi / 75; /* this might be causing problems for generation 1 devices */ + /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 2 %u \n", h2 )); */ + } + h = MIN (h1, h2); + + if (mp->generation <= 2) + { + data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x30, 0); + pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x04); + pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x06); + pixma_set_be32 (s->param->x, data + 0x08); + if (mp->generation == 2) + pixma_set_be32 (s->param->x - s->param->xs, data + 0x08); + pixma_set_be32 (s->param->y, data + 0x0c); + pixma_set_be32 (raw_width, data + 0x10); + pixma_set_be32 (h, data + 0x14); + data[0x18] = + ((s->param->channels != 1) || is_gray_all (s) || is_lineart (s)) ? + 0x08 : 0x04; + data[0x19] = ((s->param->software_lineart) ? 8 : s->param->depth) + * ((is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels); /* bits per pixel */ + data[0x1a] = (is_scanning_from_tpu (s) ? 1 : 0); + data[0x20] = 0xff; + data[0x23] = 0x81; + data[0x26] = 0x02; + data[0x27] = 0x01; + } + else + { + /* scan parameters: + * ================ + * + * byte | # of | mode | value / description + * | bytes | | + * -----+-------+---------+--------------------------- + * 0x00 | 1 | default | 0x01 + * | | adf | 0x02 + * | | tpu | 0x04 + * | | tpuir | cs9000f: 0x03 + * -----+-------+---------+--------------------------- + * 0x01 | 1 | default | 0x00 + * | | tpu | 0x02 + * -----+-------+---------+--------------------------- + * 0x02 | 1 | default | 0x01 + * | | adfdup | 0x03 + * -----+-------+---------+--------------------------- + * 0x03 | 1 | default | 0x00 + * | | adfdup | 0x03 + * -----+-------+---------+--------------------------- + * 0x04 | 1 | all | 0x00 + * -----+-------+---------+--------------------------- + * 0x05 | 1 | all | 0x01: This one also seen at 0. Don't know yet what's used for. + * -----+-------+---------+--------------------------- + * ... | 1 | all | 0x00 + * -----+-------+---------+--------------------------- + * 0x08 | 2 | all | xdpi | 0x8000 + * -----+-------+---------+--------------------------- + * 0x0a | 2 | all | ydpi | 0x8000: Must be the same as xdpi. + * -----+-------+---------+--------------------------- + * 0x0c | 4 | all | x position of start pixel + * -----+-------+---------+--------------------------- + * 0x10 | 4 | all | y position of start pixel + * -----+-------+---------+--------------------------- + * 0x14 | 4 | all | # of pixels in 1 line + * -----+-------+---------+--------------------------- + * 0x18 | 4 | all | # of scan lines + * -----+-------+---------+--------------------------- + * 0x1c | 1 | all | 0x08 + * | | | 0x04 = relict from cis scanners? + * -----+-------+---------+--------------------------- + * 0x1d | 1 | all | # of bits per pixel + * -----+-------+---------+--------------------------- + * 0x1e | 1 | default | 0x00: paper + * | | tpu | 0x01: positives + * | | tpu | 0x02: negatives + * | | tpuir | 0x01: positives + * -----+-------+---------+--------------------------- + * 0x1f | 1 | all | 0x01 + * | | | cs9000f: 0x00: Not sure if that is because of positives. + * -----+-------+---------+--------------------------- + * 0x20 | 1 | all | 0xff + * -----+-------+---------+--------------------------- + * 0x21 | 1 | all | 0x81 + * -----+-------+---------+--------------------------- + * 0x22 | 1 | all | 0x00 + * -----+-------+---------+--------------------------- + * 0x23 | 1 | all | 0x02 + * -----+-------+---------+--------------------------- + * 0x24 | 1 | all | 0x01 + * -----+-------+---------+--------------------------- + * 0x25 | 1 | default | 0x00; cs8800f: 0x01 + * | | tpu | 0x00; cs9000f, mg8200, mp990: 0x01 + * | | tpuir | cs9000f: 0x00 + * -----+-------+---------+--------------------------- + * ... | 1 | all | 0x00 + * -----+-------+---------+--------------------------- + * 0x30 | 1 | all | 0x01 + * + */ + + data = pixma_newcmd (&mp->cb, cmd_scan_param_3, 0x38, 0); + data[0x00] = is_scanning_from_adf (s) ? 0x02 : 0x01; + data[0x01] = 0x01; + if (is_scanning_from_tpu (s)) + { + data[0x00] = is_tpuir (s) ? 0x03 : 0x04; + data[0x01] = 0x02; + data[0x1e] = 0x02; /* NB: CanoScan 8800F: 0x02->negatives, 0x01->positives, paper->0x00 */ + } + data[0x02] = 0x01; + if (is_scanning_from_adfdup (s)) + { + data[0x02] = 0x03; + data[0x03] = 0x03; + } + if (s->cfg->pid != MG8200_PID) + data[0x05] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ + /* the scanner controls the scan */ + /* no software control needed */ + pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x08); + pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x0a); + /*PDBG (pixma_dbg (4, "*send_scan_param***** Setting: xdpi=%hi ydpi=%hi x=%u y=%u w=%u h=%u ***** \n", + s->param->xdpi,s->param->ydpi,(s->param->x)-(s->param->xs),s->param->y,raw_width,h));*/ + pixma_set_be32 (s->param->x - s->param->xs, data + 0x0c); + pixma_set_be32 (s->param->y, data + 0x10); + pixma_set_be32 (raw_width, data + 0x14); + pixma_set_be32 (h, data + 0x18); + data[0x1c] = ((s->param->channels != 1) || is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 0x08 : 0x04; + +#ifdef DEBUG_TPU_48 + data[0x1d] = 24; +#else + data[0x1d] = (is_scanning_from_tpu (s)) ? 48 + : (((s->param->software_lineart) ? 8 : s->param->depth) + * ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels)); /* bits per pixel */ +#endif + + data[0x1f] = 0x01; /* for 9000F this appears to be 0x00, not sure if that is because of positives */ + + if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID || s->cfg->pid == MG8200_PID) + { + data[0x1f] = 0x00; + } + + data[0x20] = 0xff; + data[0x21] = 0x81; + data[0x23] = 0x02; + data[0x24] = 0x01; + + /* MG8200 & MP990 addition */ + if (s->cfg->pid == MG8200_PID || s->cfg->pid == MP990_PID) + { + if (is_scanning_from_tpu (s)) + { + data[0x25] = 0x01; + } + } + + /* CS8800F & CS9000F addition */ + if (s->cfg->pid == CS8800F_PID || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) + { + if (is_scanning_from_tpu (s)) + { /* TPU */ + /* 0x02->negatives, 0x01->positives, paper->0x00 + * no paper in TPU mode */ + if (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_COLOR + || s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_GRAY) + { + PDBG( + pixma_dbg (4, "*send_scan_param***** TPU scan negatives *****\n")); + data[0x1e] = 0x02; + } + else + { + PDBG( + pixma_dbg (4, "*send_scan_param***** TPU scan positives *****\n")); + data[0x1e] = 0x01; + } + /* CS8800F: 0x00 for TPU color management */ + if (s->cfg->pid == CS8800F_PID) + data[0x25] = 0x00; + /* CS9000F: 0x01 for TPU */ + if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) + data[0x25] = 0x01; + if (s->param->mode == PIXMA_SCAN_MODE_TPUIR) + data[0x25] = 0x00; + } + else + { /* flatbed and ADF */ + /* paper->0x00 */ + data[0x1e] = 0x00; + /* CS8800F: 0x01 normally */ + if (s->cfg->pid == CS8800F_PID) + data[0x25] = 0x01; + /* CS9000F: 0x00 normally */ + if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) + data[0x25] = 0x00; + } + } + + data[0x30] = 0x01; + } + return pixma_exec (s, &mp->cb); +} + +static int query_status_3 (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + uint8_t *data; + int error, status_len; + + status_len = 8; + data = pixma_newcmd (&mp->cb, cmd_status_3, 0, status_len); + RET_IF_ERR(pixma_exec (s, &mp->cb)); + memcpy (mp->current_status, data, status_len); + return error; +} + +static int query_status (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + uint8_t *data; + int error, status_len; + + status_len = (mp->generation == 1) ? 12 : 16; + data = pixma_newcmd (&mp->cb, cmd_status, 0, status_len); + RET_IF_ERR(pixma_exec (s, &mp->cb)); + memcpy (mp->current_status, data, status_len); + PDBG( + pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u busy=%u\n", data[1], data[8], data[7], data[9])); + return error; +} + +#if 0 +static int send_time (pixma_t * s) +{ + /* Why does a scanner need a time? */ + time_t now; + struct tm *t; + uint8_t *data; + mp810_t *mp = (mp810_t *) s->subdriver; + + data = pixma_newcmd (&mp->cb, cmd_time, 20, 0); + pixma_get_time (&now, NULL); + t = localtime (&now); + strftime ((char *) data, 16, "%y/%m/%d %H:%M", t); + PDBG(pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); + return pixma_exec (s, &mp->cb); +} +#endif + +/* TODO: Simplify this function. Read the whole data packet in one shot. */ +static int read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) +{ + uint8_t cmd[16]; + mp810_t *mp = (mp810_t *) s->subdriver; + const int hlen = 8 + 8; + int error, datalen; + + memset (cmd, 0, sizeof(cmd)); + /* PDBG (pixma_dbg (4, "* read_image_block: last_block\n", mp->last_block)); */ + pixma_set_be16 (cmd_read_image, cmd); + if ((mp->last_block & 0x20) == 0) + pixma_set_be32 ((IMAGE_BLOCK_SIZE / 65536) * 65536 + 8, cmd + 0xc); + else + pixma_set_be32 (32 + 8, cmd + 0xc); + + mp->state = state_transfering; + mp->cb.reslen = pixma_cmd_transaction (s, cmd, sizeof(cmd), mp->cb.buf, 512); /* read 1st 512 bytes of image block */ + datalen = mp->cb.reslen; + if (datalen < 0) + return datalen; + + memcpy (header, mp->cb.buf, hlen); + /* PDBG (pixma_dbg (4, "* read_image_block: datalen %i\n", datalen)); */ + /* PDBG (pixma_dbg (4, "* read_image_block: hlen %i\n", hlen)); */ + if (datalen >= hlen) + { + datalen -= hlen; + memcpy (data, mp->cb.buf + hlen, datalen); + data += datalen; + if (mp->cb.reslen == 512) + { /* read the rest of the image block */ + error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen); + RET_IF_ERR(error); + datalen += error; + } + } + + mp->state = state_scanning; + mp->cb.expected_reslen = 0; + RET_IF_ERR(pixma_check_result (&mp->cb)); + if (mp->cb.reslen < hlen) + return PIXMA_EPROTO; + return datalen; +} + +static int read_error_info (pixma_t * s, void *buf, unsigned size) +{ + unsigned len = 16; + mp810_t *mp = (mp810_t *) s->subdriver; + uint8_t *data; + int error; + + data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); + RET_IF_ERR(pixma_exec (s, &mp->cb)); + if (buf && len < size) + { + size = len; + /* NOTE: I've absolutely no idea what the returned data mean. */ + memcpy (buf, data, size); + error = len; + } + return error; +} + +/* + handle_interrupt() waits until it receives an interrupt packet or times out. + It calls send_time() and query_status() if necessary. Therefore, make sure + that handle_interrupt() is only called from a safe context for send_time() + and query_status(). + + Returns: + 0 timed out + 1 an interrupt packet received + PIXMA_ECANCELED interrupted by signal + <0 error + */ +static int handle_interrupt (pixma_t * s, int timeout) +{ + uint8_t buf[64]; /* check max. packet size with 'lsusb -v' for "EP 9 IN" */ + int len; + + len = pixma_wait_interrupt (s->io, buf, sizeof(buf), timeout); + if (len == PIXMA_ETIMEDOUT) + return 0; + if (len < 0) + return len; + if (len%16) /* len must be a multiple of 16 bytes */ + { + PDBG(pixma_dbg (1, "WARNING:unexpected interrupt packet length %d\n", len)); + return PIXMA_EPROTO; + } + + /* s->event = 0x0brroott + * b: button + * oo: original + * tt: target + * rr: scan resolution + * poll event with 'scanimage -A' */ + if (s->cfg->pid == MG8200_PID) + /* button no. in buf[7] + * size in buf[10] 01=A4; 02=Letter; 08=10x15; 09=13x18; 0b=auto + * format in buf[11] 01=JPEG; 02=TIFF; 03=PDF; 04=Kompakt-PDF + * dpi in buf[12] 01=75; 02=150; 03=300; 04=600 + * target = format; original = size; scan-resolution = dpi */ + { + if (buf[7] & 1) + s->events = PIXMA_EV_BUTTON1 | buf[11] | buf[10]<<8 | buf[12]<<16; /* color scan */ + if (buf[7] & 2) + s->events = PIXMA_EV_BUTTON2 | buf[11] | buf[10]<<8 | buf[12]<<16; /* b/w scan */ + } + else if (s->cfg->pid == CS8800F_PID + || s->cfg->pid == CS9000F_PID + || s->cfg->pid == CS9000F_MII_PID) + /* button no. in buf[1] + * target = button no. + * "Finish PDF" is Button-2, all others are Button-1 */ + { + if ((s->cfg->pid == CS8800F_PID && buf[1] == 0x70) + || (s->cfg->pid != CS8800F_PID && buf[1] == 0x50)) + s->events = PIXMA_EV_BUTTON2 | buf[1] >> 4; /* button 2 = cancel / end scan */ + else + s->events = PIXMA_EV_BUTTON1 | buf[1] >> 4; /* button 1 = start scan */ + } + else + /* button no. in buf[0] + * original in buf[0] + * target in buf[1] */ + { + /* More than one event can be reported at the same time. */ + if (buf[3] & 1) + /* FIXME: This function makes trouble with a lot of scanners + send_time (s); + */ + PDBG (pixma_dbg (1, "WARNING:send_time() disabled!\n")); + if (buf[9] & 2) + query_status (s); + + if (buf[0] & 2) + s->events = PIXMA_EV_BUTTON2 | buf[1] | ((buf[0] & 0xf0) << 4); /* b/w scan */ + if (buf[0] & 1) + s->events = PIXMA_EV_BUTTON1 | buf[1] | ((buf[0] & 0xf0) << 4); /* color scan */ + } + return 1; +} + +static int init_ccd_lamp_3 (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + uint8_t *data; + int error, status_len, tmo; + + status_len = 8; + RET_IF_ERR(query_status (s)); + RET_IF_ERR(query_status (s)); + RET_IF_ERR(send_cmd_start_calibrate_ccd_3 (s)); + RET_IF_ERR(query_status (s)); + tmo = 20; /* like Windows driver, CCD lamp adjustment */ + while (--tmo >= 0) + { + data = pixma_newcmd (&mp->cb, cmd_end_calibrate_ccd_3, 0, status_len); + RET_IF_ERR(pixma_exec (s, &mp->cb)); + memcpy (mp->current_status, data, status_len); + PDBG(pixma_dbg (3, "Lamp status: %u , timeout in: %u\n", data[0], tmo)); + if (mp->current_status[0] == 3 || !is_scanning_from_tpu (s)) + break; + WAIT_INTERRUPT(1000); + } + return error; +} + +static int wait_until_ready (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + int error, tmo = 60; + + RET_IF_ERR((mp->generation >= 3) ? query_status_3 (s) : query_status (s)); + while (!is_calibrated (s)) + { + WAIT_INTERRUPT(1000); + if (mp->generation >= 3) + RET_IF_ERR(query_status_3 (s)); + else if (s->cfg->pid == MP800R_PID) + RET_IF_ERR (query_status (s)); + if (--tmo == 0) + { + PDBG(pixma_dbg (1, "WARNING: Timed out in wait_until_ready()\n")); + PDBG(query_status (s)); + return PIXMA_ETIMEDOUT; + } + } + return 0; +} + +/* the RGB images are shifted by # of lines */ +/* the R image is shifted by colshift[0] */ +/* the G image is shifted by colshift[1] */ +/* the B image is shifted by colshift[2] */ +/* usually one of the RGB images must not be shifted */ +/* which one depends on the scanner */ +/* some scanners have an additional stripe shift */ +/* e.g. colshift[0]=0, colshift[1]=1, colshift[2]=2 */ +/* R image is OK: RGBRGBRGB... */ +/* ^^ ^^ ^^ */ +/* || || || */ +/* shift G image: RG|RG|RG|... */ +/* | | | */ +/* shift B image: RGBRGBRGB... */ +/* this doesn't affect the G and B images */ +/* G image will become the R image in the next run */ +/* B image will become the G image in the next run */ +/* the next line will become the B image in the next run */ +static uint8_t * +shift_colors (uint8_t * dptr, uint8_t * sptr, unsigned w, unsigned dpi, + unsigned pid, unsigned c, int * colshft, unsigned strshft) +{ + unsigned i, sr, sg, sb, st; + UNUSED(dpi); + UNUSED(pid); + sr = colshft[0]; + sg = colshft[1]; + sb = colshft[2]; + + /* PDBG (pixma_dbg (4, "*shift_colors***** c=%u, w=%i, sr=%u, sg=%u, sb=%u, strshft=%u ***** \n", + c, w, sr, sg, sb, strshft)); */ + + for (i = 0; i < w; i++) + { + /* stripes shift for MP970 at 4800 dpi, MP810 at 2400 dpi */ + st = (i % 2 == 0) ? strshft : 0; + + *sptr++ = *(dptr++ + sr + st); + if (c == 6) + *sptr++ = *(dptr++ + sr + st); + *sptr++ = *(dptr++ + sg + st); + if (c == 6) + *sptr++ = *(dptr++ + sg + st); + *sptr++ = *(dptr++ + sb + st); + if (c == 6) + *sptr++ = *(dptr++ + sb + st); + } + + return dptr; +} + +static uint8_t * +shift_colorsCS9000 (uint8_t * dptr, uint8_t * sptr, unsigned w, unsigned dpi, + unsigned pid, unsigned c, int * colshft, unsigned strshft, + unsigned strshft2, unsigned jump) + +{ + unsigned i, sr, sg, sb, st, st2; + UNUSED(dpi); + UNUSED(pid); + sr = colshft[0]; + sg = colshft[1]; + sb = colshft[2]; + + for (i = 0; i < w; i++) + { + if (i < (w / 2)) + { + /* stripes shift for 1st 4 images for Canoscan 9000F at 9600dpi */ + st = (i % 2 == 0) ? strshft : 0; + *sptr++ = *(dptr++ + sr + st); + if (c == 6) + *sptr++ = *(dptr++ + sr + st); + *sptr++ = *(dptr++ + sg + st); + if (c == 6) + *sptr++ = *(dptr++ + sg + st); + *sptr++ = *(dptr++ + sb + st); + if (c == 6) + *sptr++ = *(dptr++ + sb + st); + } + if (i >= (w / 2)) + { + /* stripes shift for 2nd 4 images for Canoscan 9000F at 9600dpi */ + st2 = (i % 2 == 0) ? strshft2 : 0; + *sptr++ = *(dptr++ + sr + jump + st2); + if (c == 6) + *sptr++ = *(dptr++ + sr + jump + st2); + *sptr++ = *(dptr++ + sg + jump + st2); + if (c == 6) + *sptr++ = *(dptr++ + sg + jump + st2); + *sptr++ = *(dptr++ + sb + jump + st2); + if (c == 6) + *sptr++ = *(dptr++ + sb + jump + st2); + } + } + return dptr; +} + +static uint8_t * +shift_colorsCS9000_4800 (uint8_t * dptr, uint8_t * sptr, unsigned w, + unsigned dpi, unsigned pid, unsigned c, int * colshft, + unsigned strshft, unsigned strshft2, unsigned jump) + +{ + unsigned i, sr, sg, sb, st2; + UNUSED(dpi); + UNUSED(pid); + UNUSED(strshft); + sr = colshft[0]; + sg = colshft[1]; + sb = colshft[2]; + + for (i = 0; i < w; i++) + { + /* stripes shift for 2nd 4 images + * for Canoscan 9000F with 16 bit flatbed scans at 4800dpi */ + st2 = (i % 2 == 0) ? strshft2 : 0; + *sptr++ = *(dptr++ + sr + jump + st2); + if (c == 6) + *sptr++ = *(dptr++ + sr + jump + st2); + *sptr++ = *(dptr++ + sg + jump + st2); + if (c == 6) + *sptr++ = *(dptr++ + sg + jump + st2); + *sptr++ = *(dptr++ + sb + jump + st2); + if (c == 6) + *sptr++ = *(dptr++ + sb + jump + st2); + } + return dptr; +} + +/* under some conditions some scanners have sub images in one line */ +/* e.g. doubled image, line size = 8 */ +/* line before reordering: px1 px3 px5 px7 px2 px4 px6 px8 */ +/* line after reordering: px1 px2 px3 px4 px5 px6 px7 px8 */ +static void reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, + unsigned n, unsigned m, unsigned w, + unsigned line_size) +{ + unsigned i; + + for (i = 0; i < w; i++) + { /* process complete line */ + memcpy (linebuf + c * (n * (i % m) + i / m), sptr + c * i, c); + } + memcpy (sptr, linebuf, line_size); +} + +/* special reorder matrix for mp960 */ +static void mp960_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, + unsigned n, unsigned m, unsigned w, + unsigned line_size) +{ + unsigned i, i2; + + /* try and copy 2 px at once */ + for (i = 0; i < w; i++) + { /* process complete line */ + i2 = i % 2; + if (i < w / 2) + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m)), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m)), sptr + c * i, c); + } + else + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 1), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 1), sptr + c * i, c); + } + } + + memcpy (sptr, linebuf, line_size); +} + +/* special reorder matrix for mp970 */ +static void mp970_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, + unsigned w, unsigned line_size) +{ + unsigned i, i8; + + for (i = 0; i < w; i++) + { /* process complete line */ + i8 = i % 8; + memcpy (linebuf + c * (i + i8 - ((i8 > 3) ? 7 : 0)), sptr + c * i, c); + } + memcpy (sptr, linebuf, line_size); +} + +/* special reorder matrix for CS9000F */ +static void cs9000f_initial_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, + unsigned c, unsigned n, unsigned m, + unsigned w, unsigned line_size) +{ + unsigned i, i2; + + /* try and copy 2 px at once */ + for (i = 0; i < w; i++) + { /* process complete line */ + i2 = i % 2; + if (i < w / 8) + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m)), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m)), sptr + c * i, c); + } + else if (i >= w / 8 && i < w / 4) + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 1), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 1), sptr + c * i, c); + } + else if (i >= w / 4 && i < 3 * w / 8) + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 2), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 2), sptr + c * i, c); + } + else if (i >= 3 * w / 8 && i < w / 2) + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 3), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 3), sptr + c * i, c); + } + else if (i >= w / 2 && i < 5 * w / 8) + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 4), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 4), sptr + c * i, c); + } + else if (i >= 5 * w / 8 && i < 3 * w / 4) + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 5), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 5), sptr + c * i, c); + } + else if (i >= 3 * w / 4 && i < 7 * w / 8) + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 6), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 6), sptr + c * i, c); + } + else + { + if (i2 == 0) + memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 7), sptr + c * i, c); + else + memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 7), sptr + c * i, c); + } + } + + memcpy (sptr, linebuf, line_size); +} + +/* CS9000F 9600dpi reorder: actually 4800dpi since each pixel is doubled */ +/* need to rearrange each sequence of 16 pairs of pixels as follows: */ +/* start px : 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 */ +/* before : p1a p1b p1c p1d p2a p2b p2c p2d p3a p3b p3c p3d p4a p4b p4c p4d */ +/* after : p1a p3a p1b p3b p1c p3c p1d p3d p2a p4a p2b p4b p2c p4c p2d p4d */ +/* start px : 0 16 2 18 4 20 6 22 8 24 10 26 12 28 14 30 */ +/* change : * * * * * * * * * * * * * * */ +/* no change: * * */ +/* so the 1st and the 3rd set are interleaved, followed by the 2nd and 4th sets interleaved */ +static void cs9000f_second_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, + unsigned c, unsigned w, + unsigned line_size) +{ + unsigned i, i8; + static const int shifts[8] = + { 2, 4, 6, 8, -8, -6, -4, -2 }; + + for (i = 0; i < w; i += 2) + { /* process complete line */ + i8 = (i >> 1) & 0x7; + /* Copy 2 pixels at once */ + memcpy (linebuf + c * (i + shifts[i8]), sptr + c * i, c * 2); + } + + memcpy (sptr, linebuf, line_size); +} + +#ifndef TPU_48 +static unsigned +pack_48_24_bpc (uint8_t * sptr, unsigned n) +{ + unsigned i; + uint8_t *cptr, lsb; + static uint8_t offset = 0; + + cptr = sptr; + if (n % 2 != 0) + PDBG (pixma_dbg (3, "WARNING: misaligned image.\n")); + for (i = 0; i < n; i += 2) + { + /* offset = 1 + (offset % 3); */ + lsb = *sptr++; + *cptr++ = ((*sptr++) << offset) | lsb >> (8 - offset); + } + return (n / 2); +} +#endif + +/* This function deals both with PIXMA CCD sensors producing shifted color + * planes images, Grayscale CCD scan and Generation >= 3 high dpi images. + * Each complete line in mp->imgbuf is processed for shifting CCD sensor + * color planes, reordering pixels above 600 dpi for Generation >= 3, and + * converting to Grayscale for CCD sensors. */ +static unsigned post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + unsigned c, lines, line_size, n, m, cw, cx, reducelines; + uint8_t *sptr, *dptr, *gptr, *cptr; + unsigned /*color_shift, stripe_shift, stripe_shift2,*/ jumplines /*, height*/; + int test; + + /* For testers: */ + /* set this to 1 in order to get unprocessed images next to one another at 9600dpi */ + /* other resolutions should not be affected */ + /* set this to 2 if you want to see the same with jumplines=0 */ + test = 0; + jumplines = 0; + + c = ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels) + * ((s->param->software_lineart) ? 8 : s->param->depth) / 8; + cw = c * s->param->w; + cx = c * s->param->xs; + + /* PDBG (pixma_dbg (4, "*post_process_image_data***** c = %u, cw = %u, cx = %u *****\n", c, cw, cx)); */ + + if (mp->generation >= 3) + n = s->param->xdpi / 600; + else + /* FIXME: maybe need different values for CIS and CCD sensors */ + n = s->param->xdpi / 2400; + + /* Some exceptions to global rules here */ + if (s->cfg->pid == MP970_PID || s->cfg->pid == MP990_PID || s->cfg->pid == MG8200_PID + || s->cfg->pid == CS8800F_PID || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) + n = MIN (n, 4); + + /* exception for 9600dpi on Canoscan 9000F */ + if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) + { + n = 8; + if (test > 0) + n = 1; /* test if 8 images are next to one another */ + } + + /* test if 2 images are next to one another */ + if ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800) && (test > 0)) + { + n = 1; + } + + m = (n > 0) ? s->param->wx / n : 1; + + sptr = dptr = gptr = cptr = mp->imgbuf; + line_size = get_cis_ccd_line_size (s); + /* PDBG (pixma_dbg (4, "*post_process_image_data***** ----- Set n=%u, m=%u, line_size=%u ----- ***** \n", n, m, line_size)); */ + /* PDBG (pixma_dbg (4, "*post_process_image_data***** ----- spr=dpr=%u, linebuf=%u ----- ***** \n", sptr, mp->linebuf)); */ + + lines = (mp->data_left_ofs - mp->imgbuf) / line_size; + /* PDBG (pixma_dbg (4, "*post_process_image_data***** lines = %i > 2 * mp->color_shift + mp->stripe_shift = %i ***** \n", + lines, 2 * mp->color_shift + mp->stripe_shift)); */ + /* PDBG (pixma_dbg (4, "*post_process_image_data***** mp->color_shift = %u, mp->stripe_shift = %u, , mp->stripe_shift2 = %u ***** \n", + mp->color_shift, mp->stripe_shift, mp->stripe_shift2)); */ + + /*color_shift = mp->color_shift;*/ + /*stripe_shift = mp->stripe_shift;*/ + /*stripe_shift2 = mp->stripe_shift2;*/ + jumplines = mp->jumplines; + + /* height not needed here! */ + /* removed to avoid confusion */ + /* height = MIN (s->param->h + calc_shifting (s), + s->cfg->height * s->param->ydpi / 75); */ + + /* have to test if rounding down is OK or not -- currently 0.5 lines is rounded down */ + /* note stripe shifts doubled already in definitions */ + if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600) && (test > 0)) + { + /* using test==2 you can check in GIMP the required offset, and + use the below line (uncommented) and replace XXX with that + number, and then compile again with test set to 1. */ + + jumplines = 32; + if (test == 2) + jumplines = 0; + } + + /* mp960 test */ + if ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800) && (test > 0)) + { + jumplines = 32; + if (test == 2) + jumplines = 0; + } + + reducelines = ((2 * mp->color_shift + mp->stripe_shift) + jumplines); + /* PDBG (pixma_dbg (4, "*post_process_image_data: lines %u, reducelines %u \n", lines, reducelines)); */ + if (lines > reducelines) + { /* (line - reducelines) of image lines can be converted */ + unsigned i; + + lines -= reducelines; + + for (i = 0; i < lines; i++, sptr += line_size) + { /* convert only full image lines */ + /* Color plane and stripes shift needed by e.g. CCD */ + /* PDBG (pixma_dbg (4, "*post_process_image_data***** Processing with c=%u, n=%u, m=%u, w=%i, line_size=%u ***** \n", + c, n, m, s->param->wx, line_size)); */ + if (c >= 3) + { + if (((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) + || ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800)) + || ((s->cfg->pid == MP810_PID) && (s->param->xdpi == 4800))) + { + dptr = shift_colorsCS9000 (dptr, sptr, s->param->wx, s->param->xdpi, + s->cfg->pid, c, mp->shift, + mp->stripe_shift, mp->stripe_shift2, + jumplines * line_size); + } + + else if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) /* 9000F: 16 bit flatbed scan at 4800dpi */ + && ((s->param->mode == PIXMA_SCAN_MODE_COLOR_48) + || (s->param->mode == PIXMA_SCAN_MODE_GRAY_16)) + && (s->param->xdpi == 4800) + && (s->param->source == PIXMA_SOURCE_FLATBED)) + dptr = shift_colorsCS9000_4800 (dptr, sptr, s->param->wx, + s->param->xdpi, s->cfg->pid, c, + mp->shift, mp->stripe_shift, + mp->stripe_shift2, + jumplines * line_size); + + else + /* all except 9000F at 9600dpi */ + dptr = shift_colors (dptr, sptr, s->param->wx, s->param->xdpi, + s->cfg->pid, c, mp->shift, mp->stripe_shift); + } + + /*PDBG (pixma_dbg (4, "*post_process_image_data***** test = %i *****\n", test)); */ + + /*--comment out all between this line and the one below for 9000F tests at 9600dpi or MP960 at 4800dpi ------*/ + /* if ( 0 ) */ + if ((((s->cfg->pid != CS9000F_PID && s->cfg->pid != CS9000F_MII_PID) || (s->param->xdpi < 9600)) + && ((s->cfg->pid != MP960_PID) || (s->param->xdpi < 4800)) + && ((s->cfg->pid != MP810_PID) || (s->param->xdpi < 4800))) + || (test == 0)) + { + /* PDBG (pixma_dbg (4, "*post_process_image_data***** MUST GET HERE WHEN TEST == 0 *****\n")); */ + + if (!((s->cfg->pid == MP810_PID) && (s->param->xdpi == 4800)) + && !((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800)) + && !((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600))) + { /* for both flatbed & TPU */ + /* PDBG (pixma_dbg (4, "*post_process_image_data***** reordering pixels normal n = %i *****\n", n)); */ + reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, line_size); + } + + if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) + { + /* PDBG (pixma_dbg (4, "*post_process_image_data***** cs900f_initial_reorder_pixels n = %i *****\n", n)); */ + /* this combines pixels from 8 images 2px at a time from left to right: 1122334455667788... */ + cs9000f_initial_reorder_pixels (mp->linebuf, sptr, c, n, m, + s->param->wx, line_size); + /* final interleaving */ + cs9000f_second_reorder_pixels (mp->linebuf, sptr, c, s->param->wx, + line_size); + } + + /* comment: special image format for MP960 in flatbed mode + at 4800dpi. It is actually 2400dpi, with each pixel + doubled. The TPU mode has proper pixel ordering */ + if ((((s->cfg->pid == MP960_PID) || (s->cfg->pid == MP810_PID)) && (s->param->xdpi == 4800)) + && (n > 0)) + { + /* for both flatbed & TPU */ + /* PDBG (pixma_dbg (4, "*post_process_image_data***** flatbed mp960_reordering pixels n = %i *****\n", n)); */ + mp960_reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, + line_size); + } + + /* comment: MP970, CS8800F, CS9000F specific reordering for 4800 dpi */ + if ((s->cfg->pid == MP970_PID || s->cfg->pid == CS8800F_PID + || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID + || s->cfg->pid == MP990_PID) && (s->param->xdpi == 4800)) + { + /*PDBG (pixma_dbg (4, "*post_process_image_data***** mp970_reordering pixels n = %i *****\n", n)); */ + mp970_reorder_pixels (mp->linebuf, sptr, c, s->param->wx, line_size); + } + + } + /*-------------------------------------------------------*/ + + /* PDBG (pixma_dbg (4, "*post_process_image_data: sptr=%u, dptr=%u \n", sptr, dptr)); */ + + /* Crop line to selected borders */ + memmove (cptr, sptr + cx, cw); + /* PDBG (pixma_dbg (4, "*post_process_image_data***** crop line: cx=%u, cw=%u ***** \n", cx, cw)); */ + + /* Color to Lineart convert for CCD sensor */ + if (is_lineart (s)) + cptr = gptr = pixma_binarize_line (s->param, gptr, cptr, s->param->w, c); +#ifndef TPUIR_USE_RGB + /* save IR only for CCD sensor */ + else if (is_tpuir (s)) + cptr = gptr = pixma_r_to_ir (gptr, cptr, s->param->w, c); + /* Color to Grayscale convert for CCD sensor */ + else if (is_gray_all (s)) +#else + /* IR *and* Color to Grayscale convert for CCD sensor */ + else if (is_tpuir (s) || is_gray_all (s)) +#endif + cptr = gptr = pixma_rgb_to_gray (gptr, cptr, s->param->w, c); + else + cptr += cw; + } + /* PDBG (pixma_dbg (4, "*post_process_image_data: sptr=%u, dptr=%u \n", sptr, dptr)); */ + } + ib->rptr = mp->imgbuf; + ib->rend = cptr; + return mp->data_left_ofs - sptr; /* # of non processed bytes */ + /* contains shift color data for new lines */ + /* and already received data for the next line */ +} + +static int mp810_open (pixma_t * s) +{ + mp810_t *mp; + uint8_t *buf; + + mp = (mp810_t *) calloc (1, sizeof(*mp)); + if (!mp) + return PIXMA_ENOMEM; + + buf = (uint8_t *) malloc (CMDBUF_SIZE + IMAGE_BLOCK_SIZE); + if (!buf) + { + free (mp); + return PIXMA_ENOMEM; + } + + s->subdriver = mp; + mp->state = state_idle; + + mp->cb.buf = buf; + mp->cb.size = CMDBUF_SIZE; + mp->cb.res_header_len = 8; + mp->cb.cmd_header_len = 16; + mp->cb.cmd_len_field_ofs = 14; + + mp->imgbuf = buf + CMDBUF_SIZE; + + /* General rules for setting Pixma protocol generation # */ + mp->generation = (s->cfg->pid >= MP810_PID) ? 2 : 1; + + if (s->cfg->pid >= MP970_PID) + mp->generation = 3; + + if (s->cfg->pid >= MP990_PID) + mp->generation = 4; + + /* And exceptions to be added here */ + if (s->cfg->pid == CS8800F_PID) + mp->generation = 3; + + if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) + mp->generation = 4; + + /* TPU info data setup */ + mp->tpu_datalen = 0; + + if (mp->generation < 4) + { + /* Canoscan 8800F ignores commands if not initialized */ + if (s->cfg->pid == CS8800F_PID) + abort_session (s); + else + { + query_status (s); + handle_interrupt (s, 200); + if (mp->generation == 3 && has_ccd_sensor (s)) + send_cmd_start_calibrate_ccd_3 (s); + } + } + return 0; +} + +static void mp810_close (pixma_t * s) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + + mp810_finish_scan (s); + free (mp->cb.buf); + free (mp); + s->subdriver = NULL; +} + +static int mp810_check_param (pixma_t * s, pixma_scan_param_t * sp) +{ + mp810_t *mp = (mp810_t *) s->subdriver; + unsigned w_max; + + /* PDBG (pixma_dbg (4, "*mp810_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", + sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */ + + sp->channels = 3; + sp->software_lineart = 0; + switch (sp->mode) + { + /* standard scan modes + * 8 bit per channel in color and grayscale mode + * 16 bit per channel with TPU */ + case PIXMA_SCAN_MODE_GRAY: + case PIXMA_SCAN_MODE_NEGATIVE_GRAY: + case PIXMA_SCAN_MODE_TPUIR: + sp->channels = 1; + /* fall through */ + case PIXMA_SCAN_MODE_COLOR: + case PIXMA_SCAN_MODE_NEGATIVE_COLOR: + sp->depth = 8; +#ifdef TPU_48 +#ifndef DEBUG_TPU_48 + if (sp->source == PIXMA_SOURCE_TPU) +#endif + sp->depth = 16; /* TPU in 16 bits mode */ +#endif + break; + /* extended scan modes for 48 bit flatbed scanners + * 16 bit per channel in color and grayscale mode */ + case PIXMA_SCAN_MODE_GRAY_16: + sp->channels = 1; + sp->depth = 16; + break; + case PIXMA_SCAN_MODE_COLOR_48: + sp->channels = 3; + sp->depth = 16; + break; + /* software lineart + * 1 bit per channel */ + case PIXMA_SCAN_MODE_LINEART: + sp->software_lineart = 1; + sp->channels = 1; + sp->depth = 1; + break; + } + + /* for software lineart w must be a multiple of 8 + * I don't know why is_lineart(s) doesn't work here */ + if (sp->software_lineart == 1 && sp->w % 8) + { + sp->w += 8 - (sp->w % 8); + + /* do not exceed the scanner capability */ + w_max = s->cfg->width * s->cfg->xdpi / 75; + w_max -= w_max % 8; + if (sp->w > w_max) + sp->w = w_max; + } + + if (sp->source == PIXMA_SOURCE_TPU && !sp->tpu_offset_added) + { + unsigned fixed_offset_y; /* TPU offsets for CanoScan 8800F, or other CCD at 300dpi. */ + unsigned max_y; /* max TPU height for CS9000F at 75 dpi */ + + /* CanoScan 8800F and others adding an offset depending on resolution */ + /* CS9000F and others maximum TPU height */ + switch (s->cfg->pid) + { + case CS8800F_PID: + fixed_offset_y = 140; + max_y = MIN (740, s->cfg->height); + break; + case CS9000F_PID: + case CS9000F_MII_PID: + fixed_offset_y = 146; + max_y = MIN (740, s->cfg->height); + break; + default: + fixed_offset_y = 0; + max_y = s->cfg->height; + break; + } + + /* cropping y and h to scanable area */ + max_y *= (sp->ydpi) / 75; + sp->y = MIN(sp->y, max_y); + sp->h = MIN(sp->h, max_y - sp->y); + /* PDBG (pixma_dbg (4, "*mp810_check_param***** Cropping: y=%u, h=%u *****\n", + sp->y, sp->h)); */ + if (!sp->h) + return SANE_STATUS_INVAL; /* no lines */ + + /* Convert the offsets from 300dpi to actual resolution */ + fixed_offset_y = fixed_offset_y * (sp->xdpi) / 300; + + /* In TPU mode, the CS9000F appears to always subtract 146 from the + vertical starting position, but clamps its at 0. Therefore vertical + offsets 0 through 146 (@300 dpi) get all mapped onto the same + physical starting position: line 0. Then, starting from 147, the + offsets get mapped onto successive physical lines: + y line + 0 -> 0 + 1 -> 0 + 2 -> 0 + ... + 146 -> 0 + 147 -> 1 + 148 -> 2 + ... + Since a preview scan is typically made starting from y = 0, but + partial image scans usually start at y >> 147, this results in a + discontinuity in the y to line mapping, resulting in wrong offsets. + To prevent this, we must always add (at least) 146 to the y + offset before it is sent to the scanner. The scanner will then + map y = 0 (146) to the first line, y = 1 (147) to the second line, + and so on. Any distance that is then measured on the preview scan, + can be translated without any discontinuity. + + However, there is one complication: during a preview scan, which + normally covers the whole scan area of the scanner, we should _not_ + add the offset because it will result in a reduced number of lines + being returned (the scan height is clamped in + pixma_check_scan_param()). Since the frontend has no way of telling + that the scan area has been reduced, it would derive an incorrect + effective scan resolution, and any position calculations based on + this would therefore be inaccurate. + + To prevent this, we don't add the offset in case y = 0, which is + typically the case during a preview scan (the scanner effectively + adds the offset for us, see above). In that way we keep the + linearity and we don't affect the scan area during previews. + */ + + if (sp->y > 0) + sp->y += fixed_offset_y; + + /* Prevent repeated corrections as check_param may be called multiple times */ + sp->tpu_offset_added = 1; + } + + if (mp->generation >= 2) + { + /* mod 32 and expansion of the X scan limits */ + /* PDBG (pixma_dbg (4, "*mp810_check_param***** (gen>=2) xs=mod32 ----- Initially: x=%u, y=%u, w=%u, h=%u *****\n", sp->x, sp->y, sp->w, sp->h)); */ + sp->xs = (sp->x) % 32; + } + else + { + sp->xs = 0; + /* PDBG (pixma_dbg (4, "*mp810_check_param***** (else) xs=0 Selected origin, origin shift: %u, %u *****\n", sp->x, sp->xs)); */ + } + sp->wx = calc_raw_width (mp, sp); + sp->line_size = sp->w * sp->channels * (((sp->software_lineart) ? 8 : sp->depth) / 8); /* bytes per line per color after cropping */ + /* PDBG (pixma_dbg (4, "*mp810_check_param***** (else) Final scan width and line-size: %u, %"PRIu64" *****\n", sp->wx, sp->line_size)); */ + + /* highest res is 600, 2400, 4800 or 9600 dpi */ + { + uint8_t k; + + if ((sp->source == PIXMA_SOURCE_ADF || sp->source == PIXMA_SOURCE_ADFDUP) + && mp->generation >= 4) + /* ADF/ADF duplex mode: max scan res is 600 dpi, at least for generation 4 */ + k = sp->xdpi / MIN (sp->xdpi, 600); + else if (sp->source == PIXMA_SOURCE_TPU && sp->mode == PIXMA_SCAN_MODE_TPUIR) + /* TPUIR mode: max scan res is 2400 dpi */ + k = sp->xdpi / MIN (sp->xdpi, 2400); + else if (sp->source == PIXMA_SOURCE_TPU && (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID)) + /* CS9000F in TPU mode */ + k = sp->xdpi / MIN (sp->xdpi, 9600); + else + /* default */ + k = sp->xdpi / MIN (sp->xdpi, 4800); + + sp->x /= k; + sp->xs /= k; + sp->y /= k; + sp->w /= k; + sp->wx /= k; + sp->h /= k; + sp->xdpi /= k; + sp->ydpi = sp->xdpi; + } + + /* lowest res is 75, 150, 300 or 600 dpi */ + { + uint8_t k; + + if (sp->source == PIXMA_SOURCE_TPU && sp->mode == PIXMA_SCAN_MODE_TPUIR) + /* TPUIR mode */ + k = MAX (sp->xdpi, 600) / sp->xdpi; + else if (sp->source == PIXMA_SOURCE_TPU + && ((mp->generation >= 3) || (s->cfg->pid == MP810_PID) || (s->cfg->pid == MP960_PID))) + /* TPU mode for generation 3+ scanners + * MP810, MP960 appear to have a 200dpi mode for low-res scans, not 150 dpi */ + k = MAX (sp->xdpi, 300) / sp->xdpi; + else if (sp->source == PIXMA_SOURCE_TPU + || sp->mode == PIXMA_SCAN_MODE_COLOR_48 || sp->mode == PIXMA_SCAN_MODE_GRAY_16) + /* TPU mode and 16 bit flatbed scans + * TODO: either the frontend (xsane) cannot handle 48 bit flatbed scans @ 75 dpi (prescan) + * or there is a bug in this subdriver */ + k = MAX (sp->xdpi, 150) / sp->xdpi; + else + /* default */ + k = MAX (sp->xdpi, 75) / sp->xdpi; + + sp->x *= k; + sp->xs *= k; + sp->y *= k; + sp->w *= k; + sp->wx *= k; + sp->h *= k; + sp->xdpi *= k; + sp->ydpi = sp->xdpi; + } + + /* PDBG (pixma_dbg (4, "*mp810_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", + sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */ + + return 0; +} + +static int mp810_scan (pixma_t * s) +{ + int error = 0, tmo; + mp810_t *mp = (mp810_t *) s->subdriver; + + if (mp->state != state_idle) + return PIXMA_EBUSY; + + /* Generation 4: send XML dialog */ + if (mp->generation == 4 && s->param->adf_pageid == 0) + { + if (!send_xml_dialog (s, XML_START_1)) + return PIXMA_EPROTO; + if (!send_xml_dialog (s, XML_START_2)) + return PIXMA_EPROTO; + } + + /* clear interrupt packets buffer */ + while (handle_interrupt (s, 0) > 0) + { + } + + /* FIXME: Duplex ADF: check paper status only before odd pages (1,3,5,...). */ + if (is_scanning_from_adf (s)) + { + if ((error = query_status (s)) < 0) + return error; + tmo = 10; + while (!has_paper (s) && --tmo >= 0) + { + WAIT_INTERRUPT(1000); + PDBG(pixma_dbg (2, "No paper in ADF. Timed out in %d sec.\n", tmo)); + } + if (!has_paper (s)) + return PIXMA_ENO_PAPER; + } + + if (has_ccd_sensor (s) && (mp->generation <= 2)) + { + error = send_cmd_e920 (s); + switch (error) + { + case PIXMA_ECANCELED: + case PIXMA_EBUSY: + PDBG(pixma_dbg (2, "cmd e920 or d520 returned %s\n", pixma_strerror (error))); + /* fall through */ + case 0: + query_status (s); + break; + default: + PDBG(pixma_dbg (1, "WARNING: cmd e920 or d520 failed %s\n", pixma_strerror (error))); + return error; + } + tmo = 3; /* like Windows driver, CCD calibration ? */ + while (--tmo >= 0) + { + WAIT_INTERRUPT(1000); + PDBG(pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo)); + } + /* pixma_sleep(2000000); */ + } + + tmo = 10; + if (s->param->adf_pageid == 0 || mp->generation <= 2) + { + error = start_session (s); + while (error == PIXMA_EBUSY && --tmo >= 0) + { + if (s->cancel) + { + error = PIXMA_ECANCELED; + break; + } + PDBG(pixma_dbg (2, "Scanner is busy. Timed out in %d sec.\n", tmo + 1)); + pixma_sleep (1000000); + error = start_session (s); + } + if (error == PIXMA_EBUSY || error == PIXMA_ETIMEDOUT) + { + /* The scanner maybe hangs. We try to empty output buffer of the + * scanner and issue the cancel command. */ + PDBG(pixma_dbg (2, "Scanner hangs? Sending abort_session command.\n")); + drain_bulk_in (s); + abort_session (s); + pixma_sleep (500000); + error = start_session (s); + } + if ((error >= 0) || (mp->generation >= 3)) + mp->state = state_warmup; + if ((error >= 0) && (mp->generation <= 2)) + error = select_source (s); + if ((error >= 0) && (mp->generation >= 3) && has_ccd_sensor (s)) + error = init_ccd_lamp_3 (s); + if ((error >= 0) && !is_scanning_from_tpu (s)) + { + int i; + /* FIXME: 48 bit flatbed scans don't need gamma tables + * the code below doesn't run */ + /*if (is_color_48 (s) || is_gray_16 (s)) + error = 0; + else*/ + for (i = (mp->generation >= 3) ? 3 : 1; i > 0 && error >= 0; i--) + error = send_gamma_table (s); + } + else if (error >= 0) /* in TPU mode, for gen 1, 2, and 3 */ + error = send_set_tpu_info (s); + } + else + /* ADF pageid != 0 and gen3 or above */ + pixma_sleep (1000000); + + if ((error >= 0) || (mp->generation >= 3)) + mp->state = state_warmup; + if (error >= 0) + error = send_scan_param (s); + if ((error >= 0) && (mp->generation >= 3)) + error = start_scan_3 (s); + if (error < 0) + { + mp->last_block = 0x38; /* Force abort session if ADF scan */ + mp810_finish_scan (s); + return error; + } + return 0; +} + +static int mp810_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) +{ + int error; + mp810_t *mp = (mp810_t *) s->subdriver; + unsigned block_size, bytes_received, proc_buf_size, line_size; + uint8_t header[16]; + + if (mp->state == state_warmup) + { /* prepare read image data */ + /* PDBG (pixma_dbg (4, "**mp810_fill_buffer***** warmup *****\n")); */ + + RET_IF_ERR(wait_until_ready (s)); + pixma_sleep (1000000); /* No need to sleep, actually, but Window's driver + * sleep 1.5 sec. */ + mp->state = state_scanning; + mp->last_block = 0; + + line_size = get_cis_ccd_line_size (s); + proc_buf_size = (2 * calc_shifting (s) + 2) * line_size; + mp->cb.buf = realloc (mp->cb.buf, CMDBUF_SIZE + IMAGE_BLOCK_SIZE + proc_buf_size); + if (!mp->cb.buf) + return PIXMA_ENOMEM; + mp->linebuf = mp->cb.buf + CMDBUF_SIZE; + mp->imgbuf = mp->data_left_ofs = mp->linebuf + line_size; + mp->data_left_len = 0; + } + + do + { /* read complete image data from the scanner */ + if (s->cancel) + return PIXMA_ECANCELED; + if ((mp->last_block & 0x28) == 0x28) + { /* end of image */ + mp->state = state_finished; + /* PDBG (pixma_dbg (4, "**mp810_fill_buffer***** end of image *****\n")); */ + return 0; + } + /* PDBG (pixma_dbg (4, "*mp810_fill_buffer***** moving %u bytes into buffer *****\n", mp->data_left_len)); */ + memmove (mp->imgbuf, mp->data_left_ofs, mp->data_left_len); + error = read_image_block (s, header, mp->imgbuf + mp->data_left_len); + if (error < 0) + { + if (error == PIXMA_ECANCELED) + { + /* NOTE: I see this in traffic logs but I don't know its meaning. */ + read_error_info (s, NULL, 0); + } + return error; + } + + bytes_received = error; + /*PDBG (pixma_dbg (4, "*mp810_fill_buffer***** %u bytes received by read_image_block *****\n", bytes_received));*/ + block_size = pixma_get_be32 (header + 12); + mp->last_block = header[8] & 0x38; + if ((header[8] & ~0x38) != 0) + { + PDBG(pixma_dbg (1, "WARNING: Unexpected result header\n")); + PDBG(pixma_hexdump (1, header, 16)); + } + PASSERT(bytes_received == block_size); + + if (block_size == 0) + { /* no image data at this moment. */ + pixma_sleep (10000); + } + /* For TPU at 48 bits/pixel to output at 24 bits/pixel */ +#ifndef DEBUG_TPU_48 +#ifndef TPU_48 + PDBG (pixma_dbg (1, "WARNING: 9000F using 24 instead of 48 bit processing \n")); +#ifndef DEBUG_TPU_24 + if (is_scanning_from_tpu (s)) +#endif + bytes_received = pack_48_24_bpc (mp->imgbuf + mp->data_left_len, bytes_received); +#endif +#endif + /* Post-process the image data */ + mp->data_left_ofs = mp->imgbuf + mp->data_left_len + bytes_received; + mp->data_left_len = post_process_image_data (s, ib); + mp->data_left_ofs -= mp->data_left_len; + /* PDBG (pixma_dbg (4, "* mp810_fill_buffer: data_left_len %u \n", mp->data_left_len)); */ + /* PDBG (pixma_dbg (4, "* mp810_fill_buffer: data_left_ofs %u \n", mp->data_left_ofs)); */ + } + while (ib->rend == ib->rptr); + + return ib->rend - ib->rptr; +} + +static void mp810_finish_scan (pixma_t * s) +{ + int error; + mp810_t *mp = (mp810_t *) s->subdriver; + + switch (mp->state) + { + case state_transfering: + drain_bulk_in (s); + /* fall through */ + case state_scanning: + case state_warmup: + case state_finished: + /* Send the get TPU info message */ + if (is_scanning_from_tpu (s) && mp->tpu_datalen == 0) + send_get_tpu_info_3 (s); + /* FIXME: to process several pages ADF scan, must not send + * abort_session and start_session between pages (last_block=0x28) */ + if (mp->generation <= 2 || !is_scanning_from_adf (s) + || mp->last_block == 0x38) + { + error = abort_session (s); /* FIXME: it probably doesn't work in duplex mode! */ + if (error < 0) + PDBG(pixma_dbg (1, "WARNING:abort_session() failed %d\n", error)); + + /* Generation 4: send XML end of scan dialog */ + if (mp->generation == 4) + { + if (!send_xml_dialog (s, XML_END)) + PDBG(pixma_dbg (1, "WARNING:XML_END dialog failed \n")); + } + } + mp->state = state_idle; + /* fall through */ + case state_idle: + break; + } +} + +static void mp810_wait_event (pixma_t * s, int timeout) +{ + /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for + * instance. */ + while (s->events == 0 && handle_interrupt (s, timeout) > 0) + { + } +} + +static int mp810_get_status (pixma_t * s, pixma_device_status_t * status) +{ + int error; + + RET_IF_ERR(query_status (s)); + status->hardware = PIXMA_HARDWARE_OK; + status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; + status->cal = + (is_calibrated (s)) ? PIXMA_CALIBRATION_OK : PIXMA_CALIBRATION_OFF; + return 0; +} + +static const pixma_scan_ops_t pixma_mp800_ops = +{ + mp810_open, + mp810_close, + mp810_scan, + mp810_fill_buffer, + mp810_finish_scan, + mp810_wait_event, + mp810_check_param, + mp810_get_status +}; + +#define DEVICE(name, model, pid, dpi, adftpu_min_dpi, adftpu_max_dpi, tpuir_min_dpi, tpuir_max_dpi, w, h, cap) { \ + name, /* name */ \ + model, /* model */ \ + CANON_VID, pid, /* vid pid */ \ + 0, /* iface */ \ + &pixma_mp800_ops, /* ops */ \ + 0, /* min_xdpi not used in this subdriver */ \ + dpi, 2*(dpi), /* xdpi, ydpi */ \ + adftpu_min_dpi, adftpu_max_dpi, /* adftpu_min_dpi, adftpu_max_dpi */ \ + tpuir_min_dpi, tpuir_max_dpi, /* tpuir_min_dpi, tpuir_max_dpi */ \ + w, h, /* width, height */ \ + PIXMA_CAP_CCD| /* all scanners with CCD*/ \ + PIXMA_CAP_EASY_RGB| \ + PIXMA_CAP_GRAY| /* all scanners with software grayscale */ \ + PIXMA_CAP_LINEART| /* all scanners with software lineart */ \ + PIXMA_CAP_GAMMA_TABLE|PIXMA_CAP_EVENTS|cap \ +} + +#define END_OF_DEVICE_LIST DEVICE(NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0) + +const pixma_config_t pixma_mp800_devices[] = +{ + /* Generation 1: CCD */ + DEVICE ("Canon PIXMA MP800", "MP800", MP800_PID, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + DEVICE ("Canon PIXMA MP800R", "MP800R", MP800R_PID, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + DEVICE ("Canon PIXMA MP830", "MP830", MP830_PID, 2400, 150, 0, 0, 0, 638, 877, PIXMA_CAP_ADFDUP), + + /* Generation 2: CCD */ + DEVICE ("Canon PIXMA MP810", "MP810", MP810_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + DEVICE ("Canon PIXMA MP960", "MP960", MP960_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + + /* Generation 3 CCD not managed as Generation 2 */ + DEVICE ("Canon Pixma MP970", "MP970", MP970_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + + /* Flatbed scanner CCD (2007) */ + DEVICE ("Canoscan 8800F", "8800F", CS8800F_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT), + + /* PIXMA 2008 vintage CCD */ + DEVICE ("Canon MP980 series", "MP980", MP980_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + + /* Generation 4 CCD */ + DEVICE ("Canon MP990 series", "MP990", MP990_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + + /* Flatbed scanner (2010) */ + DEVICE ("Canoscan 9000F", "9000F", CS9000F_PID, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_TPUIR /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT), + + /* Latest devices (2010) Generation 4 CCD untested */ + DEVICE ("Canon PIXMA MG8100", "MG8100", MG8100_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + + /* Latest devices (2011) Generation 4 CCD untested */ + DEVICE ("Canon PIXMA MG8200", "MG8200", MG8200_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_TPU), + + /* Flatbed scanner (2013) */ + DEVICE ("Canoscan 9000F Mark II", "9000FMarkII", CS9000F_MII_PID, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_TPUIR | PIXMA_CAP_48BIT), + + END_OF_DEVICE_LIST +}; diff --git a/backend/pixma/pixma_rename.h b/backend/pixma/pixma_rename.h new file mode 100644 index 0000000..ad3d960 --- /dev/null +++ b/backend/pixma/pixma_rename.h @@ -0,0 +1,105 @@ +/* SANE - Scanner Access Now Easy. + + 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. + */ +#ifndef PIXMA_RENAME_H +#define PIXMA_RENAME_H + + +#undef BACKEND_NAME +#define BACKEND_NAME pixma + +#define pixma_cancel sanei_pixma_cancel +#define pixma_check_dpi sanei_pixma_check_dpi +#define pixma_check_result sanei_pixma_check_result +#define pixma_check_scan_param sanei_pixma_check_scan_param +#define pixma_cleanup sanei_pixma_cleanup +#define pixma_close sanei_pixma_close +#define pixma_cmd_transaction sanei_pixma_cmd_transaction +#define pixma_collect_devices sanei_pixma_collect_devices +#define pixma_connect sanei_pixma_connect +#define pixma_dbg DBG +#define pixma_disconnect sanei_pixma_disconnect +#define pixma_dump sanei_pixma_dump +#define pixma_enable_background sanei_pixma_enable_background +#define pixma_exec sanei_pixma_exec +#define pixma_exec_short_cmd sanei_pixma_exec_short_cmd +#define pixma_fill_gamma_table sanei_pixma_fill_gamma_table +#define pixma_find_scanners sanei_pixma_find_scanners +#define pixma_get_be16 sanei_pixma_get_be16 +#define pixma_get_be32 sanei_pixma_get_be32 +#define pixma_get_config sanei_pixma_get_config +#define pixma_get_device_config sanei_pixma_get_device_config +#define pixma_get_device_id sanei_pixma_get_device_id +#define pixma_get_device_model sanei_pixma_get_device_model +#define pixma_get_device_status sanei_pixma_get_device_status +#define pixma_get_string sanei_pixma_get_string +#define pixma_get_time sanei_pixma_get_time +#define pixma_hexdump sanei_pixma_hexdump +#define pixma_init sanei_pixma_init +#define pixma_io_cleanup sanei_pixma_io_cleanup +#define pixma_io_init sanei_pixma_io_init +#define pixma_map_status_errno sanei_pixma_map_status_errno +#define pixma_mp150_devices sanei_pixma_mp150_devices +#define pixma_mp730_devices sanei_pixma_mp730_devices +#define pixma_mp750_devices sanei_pixma_mp750_devices +#define pixma_mp800_devices sanei_pixma_mp800_devices +#define pixma_iclass_devices sanei_pixma_iclass_devices +#define pixma_newcmd sanei_pixma_newcmd +#define pixma_open sanei_pixma_open +#define pixma_print_supported_devices sanei_pixma_print_supported_devices +#define pixma_read_image sanei_pixma_read_image +#define pixma_read sanei_pixma_read +#define pixma_reset_device sanei_pixma_reset_device +#define pixma_scan sanei_pixma_scan +#define pixma_set_be16 sanei_pixma_set_be16 +#define pixma_set_be32 sanei_pixma_set_be32 +#define pixma_set_debug_level sanei_pixma_set_debug_level +#define pixma_set_interrupt_mode sanei_pixma_set_interrupt_mode +#define pixma_sleep sanei_pixma_sleep +#define pixma_strerror sanei_pixma_strerror +#define pixma_sum_bytes sanei_pixma_sum_bytes +#define pixma_wait_event sanei_pixma_wait_event +#define pixma_wait_interrupt sanei_pixma_wait_interrupt +#define pixma_write sanei_pixma_write + + +#endif diff --git a/backend/pixma/pixma_sane_options.c b/backend/pixma/pixma_sane_options.c new file mode 100644 index 0000000..2b8f609 --- /dev/null +++ b/backend/pixma/pixma_sane_options.c @@ -0,0 +1,362 @@ +/* Automatically generated from pixma_sane.c */ +static const SANE_Range constraint_gamma_table = + { 0,255,0 }; +static const SANE_Range constraint_gamma = + { SANE_FIX(0.3),SANE_FIX(5),SANE_FIX(0) }; +static const SANE_Range constraint_threshold = + { 0,100,1 }; +static const SANE_Range constraint_threshold_curve = + { 0,127,1 }; +static const SANE_Range constraint_adf_wait = + { 0,3600,1 }; + + +static +int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list) +{ + int i; + for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {} + return i; +} + +static +int build_option_descriptors(struct pixma_sane_t *ss) +{ + SANE_Option_Descriptor *sod; + option_descriptor_t *opt; + + memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX)); + + opt = &(OPT_IN_CTX[opt_opt_num_opts]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_TITLE_NUM_OPTIONS; + sod->desc = SANE_DESC_NUM_OPTIONS; + sod->name = ""; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_DETECT; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_opt_num_opts].info = 0; + opt->def.w = opt_last; + opt->val.w = opt_last; + + opt = &(OPT_IN_CTX[opt__group_1]); + sod = &opt->sod; + sod->type = SANE_TYPE_GROUP; + sod->title = SANE_I18N("Scan mode"); + sod->desc = sod->title; + + opt = &(OPT_IN_CTX[opt_resolution]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_TITLE_SCAN_RESOLUTION; + sod->desc = SANE_DESC_SCAN_RESOLUTION; + sod->name = "resolution"; + sod->unit = SANE_UNIT_DPI; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; + sod->constraint_type = SANE_CONSTRAINT_WORD_LIST; + sod->constraint.word_list = ss->dpi_list; + OPT_IN_CTX[opt_resolution].info = SANE_INFO_RELOAD_PARAMS; + opt->def.w = 75; + opt->val.w = 75; + + opt = &(OPT_IN_CTX[opt_mode]); + sod = &opt->sod; + sod->type = SANE_TYPE_STRING; + sod->title = SANE_TITLE_SCAN_MODE; + sod->desc = SANE_DESC_SCAN_MODE; + sod->name = "mode"; + sod->unit = SANE_UNIT_NONE; + sod->size = 31; + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; + sod->constraint_type = SANE_CONSTRAINT_STRING_LIST; + sod->constraint.string_list = ss->mode_list; + OPT_IN_CTX[opt_mode].info = SANE_INFO_RELOAD_PARAMS; + opt->def.s = SANE_VALUE_SCAN_MODE_COLOR; + opt->val.w = find_string_in_list(opt->def.s, sod->constraint.string_list); + + opt = &(OPT_IN_CTX[opt_source]); + sod = &opt->sod; + sod->type = SANE_TYPE_STRING; + sod->title = SANE_TITLE_SCAN_SOURCE; + sod->desc = SANE_I18N("Selects the scan source (such as a document-feeder). Set source before mode and resolution. Resets mode and resolution to auto values."); + sod->name = "source"; + sod->unit = SANE_UNIT_NONE; + sod->size = 31; + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; + sod->constraint_type = SANE_CONSTRAINT_STRING_LIST; + sod->constraint.string_list = ss->source_list; + OPT_IN_CTX[opt_source].info = 0; + opt->def.s = SANE_I18N("Flatbed"); + opt->val.w = find_string_in_list(opt->def.s, sod->constraint.string_list); + + opt = &(OPT_IN_CTX[opt_button_controlled]); + sod = &opt->sod; + sod->type = SANE_TYPE_BOOL; + sod->title = SANE_I18N("Button-controlled scan"); + sod->desc = SANE_I18N("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."); + sod->name = "button-controlled"; + sod->unit = SANE_UNIT_NONE; + sod->size = sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_INACTIVE; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_button_controlled].info = 0; + opt->def.w = SANE_FALSE; + opt->val.w = SANE_FALSE; + + opt = &(OPT_IN_CTX[opt__group_2]); + sod = &opt->sod; + sod->type = SANE_TYPE_GROUP; + sod->title = SANE_I18N("Gamma"); + sod->desc = sod->title; + + opt = &(OPT_IN_CTX[opt_custom_gamma]); + sod = &opt->sod; + sod->type = SANE_TYPE_BOOL; + sod->title = SANE_TITLE_CUSTOM_GAMMA; + sod->desc = SANE_DESC_CUSTOM_GAMMA; + sod->name = "custom-gamma"; + sod->unit = SANE_UNIT_NONE; + sod->size = sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_custom_gamma].info = 0; + opt->def.w = SANE_TRUE; + opt->val.w = SANE_TRUE; + + opt = &(OPT_IN_CTX[opt_gamma_table]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_TITLE_GAMMA_VECTOR; + sod->desc = SANE_DESC_GAMMA_VECTOR; + sod->name = "gamma-table"; + sod->unit = SANE_UNIT_NONE; + sod->size = 4096 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &constraint_gamma_table; + OPT_IN_CTX[opt_gamma_table].info = 0; + + opt = &(OPT_IN_CTX[opt_gamma]); + sod = &opt->sod; + sod->type = SANE_TYPE_FIXED; + sod->title = SANE_I18N("Gamma function exponent"); + sod->desc = SANE_I18N("Changes intensity of midtones"); + sod->name = "gamma"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &constraint_gamma; + OPT_IN_CTX[opt_gamma].info = 0; + opt->def.w = SANE_FIX(AUTO_GAMMA); + opt->val.w = SANE_FIX(AUTO_GAMMA); + + opt = &(OPT_IN_CTX[opt__group_3]); + sod = &opt->sod; + sod->type = SANE_TYPE_GROUP; + sod->title = SANE_I18N("Geometry"); + sod->desc = sod->title; + + opt = &(OPT_IN_CTX[opt_tl_x]); + sod = &opt->sod; + sod->type = SANE_TYPE_FIXED; + sod->title = SANE_TITLE_SCAN_TL_X; + sod->desc = SANE_DESC_SCAN_TL_X; + sod->name = "tl-x"; + sod->unit = SANE_UNIT_MM; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &ss->xrange; + OPT_IN_CTX[opt_tl_x].info = SANE_INFO_RELOAD_PARAMS; + opt->def.w = SANE_FIX(0); + opt->val.w = SANE_FIX(0); + + opt = &(OPT_IN_CTX[opt_tl_y]); + sod = &opt->sod; + sod->type = SANE_TYPE_FIXED; + sod->title = SANE_TITLE_SCAN_TL_Y; + sod->desc = SANE_DESC_SCAN_TL_Y; + sod->name = "tl-y"; + sod->unit = SANE_UNIT_MM; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &ss->yrange; + OPT_IN_CTX[opt_tl_y].info = SANE_INFO_RELOAD_PARAMS; + opt->def.w = SANE_FIX(0); + opt->val.w = SANE_FIX(0); + + opt = &(OPT_IN_CTX[opt_br_x]); + sod = &opt->sod; + sod->type = SANE_TYPE_FIXED; + sod->title = SANE_TITLE_SCAN_BR_X; + sod->desc = SANE_DESC_SCAN_BR_X; + sod->name = "br-x"; + sod->unit = SANE_UNIT_MM; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &ss->xrange; + OPT_IN_CTX[opt_br_x].info = SANE_INFO_RELOAD_PARAMS; + opt->def.w = sod->constraint.range->max; + opt->val.w = sod->constraint.range->max; + + opt = &(OPT_IN_CTX[opt_br_y]); + sod = &opt->sod; + sod->type = SANE_TYPE_FIXED; + sod->title = SANE_TITLE_SCAN_BR_Y; + sod->desc = SANE_DESC_SCAN_BR_Y; + sod->name = "br-y"; + sod->unit = SANE_UNIT_MM; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &ss->yrange; + OPT_IN_CTX[opt_br_y].info = SANE_INFO_RELOAD_PARAMS; + opt->def.w = sod->constraint.range->max; + opt->val.w = sod->constraint.range->max; + + opt = &(OPT_IN_CTX[opt__group_4]); + sod = &opt->sod; + sod->type = SANE_TYPE_GROUP; + sod->title = SANE_I18N("Buttons"); + sod->desc = sod->title; + + opt = &(OPT_IN_CTX[opt_button_update]); + sod = &opt->sod; + sod->type = SANE_TYPE_BUTTON; + sod->title = SANE_I18N("Update button state"); + sod->desc = sod->title; + sod->name = "button-update"; + sod->unit = SANE_UNIT_NONE; + sod->size = 0; + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_button_update].info = 0; + + opt = &(OPT_IN_CTX[opt_button_1]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_I18N("Button 1"); + sod->desc = sod->title; + sod->name = "button-1"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_button_1].info = 0; + opt->def.w = 0; + opt->val.w = 0; + + opt = &(OPT_IN_CTX[opt_button_2]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_I18N("Button 2"); + sod->desc = sod->title; + sod->name = "button-2"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_button_2].info = 0; + opt->def.w = 0; + opt->val.w = 0; + + opt = &(OPT_IN_CTX[opt_original]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_I18N("Type of original to scan"); + sod->desc = sod->title; + sod->name = "original"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_original].info = 0; + opt->def.w = 0; + opt->val.w = 0; + + opt = &(OPT_IN_CTX[opt_target]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_I18N("Target operation type"); + sod->desc = sod->title; + sod->name = "target"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_target].info = 0; + opt->def.w = 0; + opt->val.w = 0; + + opt = &(OPT_IN_CTX[opt_scan_resolution]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_I18N("Scan resolution"); + sod->desc = sod->title; + sod->name = "scan-resolution"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; + sod->constraint_type = SANE_CONSTRAINT_NONE; + OPT_IN_CTX[opt_scan_resolution].info = 0; + opt->def.w = 0; + opt->val.w = 0; + + opt = &(OPT_IN_CTX[opt__group_5]); + sod = &opt->sod; + sod->type = SANE_TYPE_GROUP; + sod->title = SANE_I18N("Extras"); + sod->desc = sod->title; + + opt = &(OPT_IN_CTX[opt_threshold]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_TITLE_THRESHOLD; + sod->desc = SANE_DESC_THRESHOLD; + sod->name = "threshold"; + sod->unit = SANE_UNIT_PERCENT; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &constraint_threshold; + OPT_IN_CTX[opt_threshold].info = 0; + opt->def.w = 50; + opt->val.w = 50; + + opt = &(OPT_IN_CTX[opt_threshold_curve]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_I18N("Threshold curve"); + sod->desc = SANE_I18N("Dynamic threshold curve, from light to dark, normally 50-65"); + sod->name = "threshold-curve"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &constraint_threshold_curve; + OPT_IN_CTX[opt_threshold_curve].info = 0; + + opt = &(OPT_IN_CTX[opt_adf_wait]); + sod = &opt->sod; + sod->type = SANE_TYPE_INT; + sod->title = SANE_I18N("ADF Waiting Time"); + sod->desc = SANE_I18N("When set, the scanner waits upto the specified time in seconds for a new document inserted into the automatic document feeder."); + sod->name = "adf-wait"; + sod->unit = SANE_UNIT_NONE; + sod->size = 1 * sizeof(SANE_Word); + sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; + sod->constraint_type = SANE_CONSTRAINT_RANGE; + sod->constraint.range = &constraint_adf_wait; + OPT_IN_CTX[opt_adf_wait].info = 0; + opt->def.w = 0; + opt->val.w = 0; + + return 0; + +} diff --git a/backend/pixma/pixma_sane_options.h b/backend/pixma/pixma_sane_options.h new file mode 100644 index 0000000..1472f1f --- /dev/null +++ b/backend/pixma/pixma_sane_options.h @@ -0,0 +1,51 @@ +/* Automatically generated from pixma_sane.c */ + +typedef union { + SANE_Word w; + SANE_Int i; + SANE_Bool b; + SANE_Fixed f; + SANE_String s; + void *ptr; +} option_value_t; + +typedef enum { + opt_opt_num_opts, + opt__group_1, + opt_resolution, + opt_mode, + opt_source, + opt_button_controlled, + opt__group_2, + opt_custom_gamma, + opt_gamma_table, + opt_gamma, + opt__group_3, + opt_tl_x, + opt_tl_y, + opt_br_x, + opt_br_y, + opt__group_4, + opt_button_update, + opt_button_1, + opt_button_2, + opt_original, + opt_target, + opt_scan_resolution, + opt__group_5, + opt_threshold, + opt_threshold_curve, + opt_adf_wait, + opt_last +} option_t; + + +typedef struct { + SANE_Option_Descriptor sod; + option_value_t val,def; + SANE_Word info; +} option_descriptor_t; + + +struct pixma_sane_t; +static int build_option_descriptors(struct pixma_sane_t *ss); diff --git a/backend/pixma/scripts/pixma_gen_options.py b/backend/pixma/scripts/pixma_gen_options.py new file mode 100755 index 0000000..c4c75e0 --- /dev/null +++ b/backend/pixma/scripts/pixma_gen_options.py @@ -0,0 +1,389 @@ +#!/usr/bin/env python + +import sys,os,re + +class Error(Exception): + pass + + +class ParseError(Error): + def __init__(self, errline): + Error.__init__(self, errline) + + +class Struct: + pass + + +def createCNameMap(): + t = '' + for i in range(256): + if ((ord('A') <= i) and (i <= ord('Z'))) or \ + ((ord('a') <= i) and (i <= ord('z'))) or \ + ((ord('0') <= i) and (i <= ord('9'))): + t += chr(i) + else: + t += '_' + return t + + +def seekBegin(f): + while True: + line = f.readline() + if not line: + return False + if line.startswith('BEGIN SANE_Option_Descriptor'): + return True + + +def parseVerbatim(o, line): + words = line.split(None, 1) + if (len(words) < 2) or (words[1][0] != '@'): + return False + o[words[0]] = words[1] + return True + + +def parseLine_type(o, line): + words = line.split(None, 2) + otype = words[1] + o['type'] = 'SANE_TYPE_' + otype.upper() + if otype == 'group': + g.ngroups += 1 + oname = '_group_%d' % g.ngroups + o['size'] = 0 + else: + temp = words[2] + idx = temp.find('[') + if idx == -1: + oname = temp + o['size'] = 1 + else: + oname = temp[0:idx] + o['size'] = int(temp[idx+1:-1]) + o['name'] = oname + + +def parseLine_title(o, line): + o['title'] = line.split(None, 1)[1] + + +def parseLine_desc(o, line): + o['desc'] = line.split(None, 1)[1] + + +def parseLine_unit(o, line): + o['unit'] = 'SANE_UNIT_' + line.split(None, 1)[1].upper() + + +def parseLine_default(o, line): + o['default'] = line.split(None, 1)[1] + + +def parseLine_cap(o, line): + words = line.split() + o['cap'] = ['SANE_CAP_' + s.upper() for s in words[1:]] + + +def parseLine_constraint(o, line): + c = line.split(None,1)[1] + if c[0] == '{': + o['constraint'] = c[1:-1].split('|') + elif c[0] == '(': + o['constraint'] = tuple(c[1:-1].split(',')) + else: + sys.stderr.write('Ignored: %s\n' % line) + + +def parseLine_info(o, line): + words = line.split() + o['info'] = ['SANE_INFO_' + s.upper() for s in words[1:]] + +def parseLine_rem(o, line): + pass + +def normalize(o): + if 'cname' not in o: + cname = o['name'].translate(cnameMap) + o['cname'] = cname + else: + cname = o['cname'] + o['cname_opt'] = 'opt_' + cname + o['cname_con'] = 'constraint_' + cname + if 'title' not in o: + o['title'] = 'NO TITLE' + if 'desc' not in o: + o['desc'] = '@sod->title' % o + if 'unit' not in o: + o['unit'] = 'SANE_UNIT_NONE' + if 'constraint_type' not in o: + if 'constraint' not in o: + ct = 'SANE_CONSTRAINT_NONE' + elif isinstance(o['constraint'], list): + if o['type'] == 'SANE_TYPE_STRING': + ct = 'SANE_CONSTRAINT_STRING_LIST' + else: + ct = 'SANE_CONSTRAINT_WORD_LIST' + elif isinstance(o['constraint'], tuple): + ct = 'SANE_CONSTRAINT_RANGE' + elif isinstance(o['constraint'], str): + oc = o['constraint'] + if oc.startswith('@range'): + ct = 'SANE_CONSTRAINT_RANGE' + elif oc.startswith('@word_list'): + ct = 'SANE_CONSTRAINT_WORD_LIST' + elif oc.startswith('@string_list'): + ct = 'SANE_CONSTRAINT_STRING_LIST' + o['constraint_type'] = ct + return o + + +def parseFile(f): + if not seekBegin(f): + return None + options = [ { + 'name' : '', + 'cname' : 'opt_num_opts', + 'title' : '@SANE_TITLE_NUM_OPTIONS', + 'desc' : '@SANE_DESC_NUM_OPTIONS', + 'type' : 'SANE_TYPE_INT', + 'unit' : 'SANE_UNIT_NONE', + 'size' : 1, + 'cap' : ['SANE_CAP_SOFT_DETECT'], + 'constraint_type' : 'SANE_CONSTRAINT_NONE', + 'default' : '@w = ' + opt_prefix + 'last' + } ] + o = {} + while True: + line = f.readline() + if not line: + break + line = line.strip() + if not line: + continue + token = line.split(None, 1)[0].lower() + if token == 'end': + break + if token == 'type': + if 'name' in o: + options.append(o) + o = {} + funcName = 'parseLine_' + token + if funcName in globals(): + if not parseVerbatim(o, line): + func = globals()[funcName] + func(o, line) + else: + sys.stderr.write('Skip: %s\n' % line) + if 'name' in o: + options.append(o) + return [normalize(o) for o in options] + + +def genHeader(options): + print """ +typedef union { + SANE_Word w; + SANE_Int i; + SANE_Bool b; + SANE_Fixed f; + SANE_String s; + void *ptr; +} option_value_t; +""" + print 'typedef enum {' + for o in options: + print ' %(cname_opt)s,' % o + print ' ' + opt_prefix + 'last' + print '} option_t;' + print """ + +typedef struct { + SANE_Option_Descriptor sod; + option_value_t val,def; + SANE_Word info; +} option_descriptor_t; + + +struct pixma_sane_t; +static int build_option_descriptors(struct pixma_sane_t *ss); +""" + + +def genMinMaxRange(n, t, r): + if t == 'SANE_TYPE_FIXED': + r = ['SANE_FIX(%s)' % x for x in r] + print 'static const SANE_Range ' + n + ' = ' + print ' { ' + r[0] + ',' + r[1] + ',' + r[2] + ' };' + + +def genList(n, t, l): + if t == 'SANE_TYPE_INT': + etype = 'SANE_Word' + l = [str(len(l))] + l + elif t == 'SANE_TYPE_FIXED': + etype = 'SANE_Word' + l = [str(len(l))] + ['SANE_FIX(%s)' % x for x in l] + elif t == 'SANE_TYPE_STRING': + etype = 'SANE_String_Const' + l = ['SANE_I18N("%s")' % x for x in l] + ['NULL'] + print 'static const %s %s[%d] = {' % (etype, n, len(l)) + for x in l[0:-1]: + print '\t' + x + ',' + print '\t' + l[-1] + ' };' + + +def genConstraints(options): + for o in options: + if 'constraint' not in o: continue + c = o['constraint'] + oname = o['cname_con'] + otype = o['type'] + if isinstance(c, tuple): + genMinMaxRange(oname, otype, c) + elif isinstance(c, list): + genList(oname, otype, c) + print + +def buildCodeVerbatim(o): + for f in ('name', 'title', 'desc', 'type', 'unit', 'size', 'cap', + 'constraint_type', 'constraint', 'default'): + if (f not in o): continue + temp = o[f] + if (not isinstance(temp,str)) or \ + (len(temp) < 1) or (temp[0] != '@'): + continue + o['code_' + f] = temp[1:] + +def ccode(o): + buildCodeVerbatim(o) + if 'code_name' not in o: + o['code_name'] = '"' + o['name'] + '"' + for f in ('title', 'desc'): + cf = 'code_' + f + if cf in o: continue + o[cf] = 'SANE_I18N("' + o[f] + '")' + + for f in ('type', 'unit', 'constraint_type'): + cf = 'code_' + f + if cf in o: continue + o[cf] = o[f] + + if 'code_size' not in o: + otype = o['type'] + osize = o['size'] + if otype == 'SANE_TYPE_STRING': + code = str(osize + 1) + elif otype == 'SANE_TYPE_INT' or otype == 'SANE_TYPE_FIXED': + code = str(osize) + ' * sizeof(SANE_Word)' + elif otype == 'SANE_TYPE_BUTTON': + code = '0' + else: + code = 'sizeof(SANE_Word)' + o['code_size'] = code + + if ('code_cap' not in o) and ('cap' in o): + o['code_cap'] = reduce(lambda a,b: a+'|'+b, o['cap']) + else: + o['code_cap'] = '0' + + if ('code_info' not in o) and ('info' in o): + o['code_info'] = reduce(lambda a,b: a+'|'+b, o['info']) + else: + o['code_info'] = '0' + + if ('code_default' not in o) and ('default' in o): + odefault = o['default'] + otype = o['type'] + if odefault == '_MIN': + rhs = 'w = sod->constraint.range->min' + elif odefault == '_MAX': + rhs = 'w = sod->constraint.range->max' + elif otype in ('SANE_TYPE_INT', 'SANE_TYPE_BOOL'): + rhs = 'w = %(default)s' + elif otype == 'SANE_TYPE_FIXED': + rhs = 'w = SANE_FIX(%(default)s)' + elif otype == 'SANE_TYPE_STRING': + rhs = 's = SANE_I18N("%(default)s")' + o['code_default'] = rhs % o + if 'code_default' in o: + code = ' opt->def.%(code_default)s;\n' + if o['constraint_type'] != 'SANE_CONSTRAINT_STRING_LIST': + code += ' opt->val.%(code_default)s;\n' + else: + code += ' opt->val.w = find_string_in_list' \ + '(opt->def.s, sod->constraint.string_list);\n' + o['full_code_default'] = code % o + else: + o['full_code_default'] = '' + + if ('code_constraint' not in o) and ('constraint' in o): + ct = o['constraint_type'] + idx = len('SANE_CONSTRAINT_') + ctype = ct[idx:].lower() + if ctype == 'range': + rhs = '&%(cname_con)s' % o + else: + rhs = '%(cname_con)s' % o + o['code_constraint'] = ctype + ' = ' + rhs + if 'code_constraint' in o: + code = ' sod->constraint.%(code_constraint)s;\n' + o['full_code_constraint'] = code % o + else: + o['full_code_constraint'] = '' + + return o + +def genBuildOptions(options): + print """ +static +int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list) +{ + int i; + for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {} + return i; +} + +static +int build_option_descriptors(struct pixma_sane_t *ss) +{ + SANE_Option_Descriptor *sod; + option_descriptor_t *opt; + + memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX));""" + + for o in options: + o = ccode(o) + otype = o['type'] + code = '\n opt = &(OPT_IN_CTX[%(cname_opt)s]);\n' \ + ' sod = &opt->sod;\n' \ + ' sod->type = %(code_type)s;\n' \ + ' sod->title = %(code_title)s;\n' \ + ' sod->desc = %(code_desc)s;\n' + if otype != 'SANE_TYPE_GROUP': + code += ' sod->name = %(code_name)s;\n' \ + ' sod->unit = %(code_unit)s;\n' \ + ' sod->size = %(code_size)s;\n' \ + ' sod->cap = %(code_cap)s;\n' \ + ' sod->constraint_type = %(code_constraint_type)s;\n' \ + '%(full_code_constraint)s' \ + ' OPT_IN_CTX[%(cname_opt)s].info = %(code_info)s;\n' \ + '%(full_code_default)s' + sys.stdout.write(code % o) + print + print ' return 0;\n' + print '}' + print + +g = Struct() +g.ngroups = 0 +opt_prefix = 'opt_' +con_prefix = 'constraint_' +cnameMap = createCNameMap() +options = parseFile(sys.stdin) +print "/* Automatically generated from pixma_sane.c */" +if (len(sys.argv) == 2) and (sys.argv[1] == 'h'): + genHeader(options) +else: + genConstraints(options) + genBuildOptions(options) diff --git a/backend/pixma_bjnp.c b/backend/pixma_bjnp.c deleted file mode 100644 index 5a9932e..0000000 --- a/backend/pixma_bjnp.c +++ /dev/null @@ -1,2558 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2008 2012 by Louis Lagendijk - - This file is part of the SANE package. - - SANE 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. - - SANE 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 sane; see the file COPYING. If not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. -*/ -#undef BACKEND_NAME -#define BACKEND_NAME bjnp - -#include "../include/sane/config.h" -#include "../include/sane/sane.h" - -/* - * Standard types etc - */ -#ifdef HAVE_STDLIB_H -#include -#endif -#ifdef HAVE_STRING_H -#include -#endif -#include -#include -#ifdef HAVE_STDINT_H -#include -#endif -#ifdef HAVE_SYS_TYPES_H -#include -#endif -#ifdef HAVE_SYS_TIME_H -#include -#endif -#ifdef HAVE_LIMITS_H -#include -#endif - -/* - * networking stuff - */ -#ifdef HAVE_SYS_SOCKET_H -#include -#endif -#ifdef HAVE_NETINET_IN_H -#include -#endif -#include -#include -#include -#include -#ifdef HAVE_IFADDRS_H -#include -#endif -#ifdef HAVE_SYS_SELECT_H -#include -#endif -#ifdef HAVE_PWD_H -#include -#endif -#include -#ifdef HAVE_FCNTL_H -#include -#endif - -#include "pixma_bjnp_private.h" -#include "pixma_bjnp.h" -/* #include "pixma_rename.h" */ -#include "pixma.h" -#include "pixma_common.h" - -#ifndef SSIZE_MAX -# define SSIZE_MAX LONG_MAX -#endif - -/* static data */ -static bjnp_device_t device[BJNP_NO_DEVICES]; -static int bjnp_no_devices = 0; - -/* - * Private functions - */ - -static void -u8tohex (char *string, const uint8_t *value, int len ) -{ - int i; - int x; - const char hdigit[16] = - { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', - 'e', 'f' - }; - for (i = 0; i < len; i++) - { - x = value[i]; - string[ 2 * i ] = hdigit[(x >> 4) & 0xf]; - string[ 2 * i + 1] = hdigit[x & 0xf]; - } - string[2 * len ] = '\0'; -} - -static void -u32tohex (uint32_t x, char *str) -{ - uint8_t uint8[4]; - uint8[0] = (uint8_t)(x >> 24); - uint8[1] = (uint8_t)(x >> 16); - uint8[2] = (uint8_t)(x >> 8); - uint8[3] = (uint8_t)x ; - u8tohex(str, uint8, 4); -} - -static void -bjnp_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 > DBG_LEVEL) - return; - if (level == DBG_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 (p, d + ofs + c, 1); - p[2] = ' '; - p += 3; - if (c == 7) - { - p[0] = ' '; - p++; - } - } - p[0] = '\0'; - bjnp_dbg (level, "%s\n", line); - ofs += c; - } - if (len > plen) - bjnp_dbg(level, "......\n"); -} - -static int sa_is_equal( const bjnp_sockaddr_t * sa1, const bjnp_sockaddr_t * sa2) -{ - if ((sa1 == NULL) || (sa2 == NULL) ) - return 0; - - if (sa1->addr.sa_family == sa2-> addr.sa_family) - { - if( sa1 -> addr.sa_family == AF_INET) - { - if ( (sa1->ipv4.sin_port == sa2->ipv4.sin_port) && - (sa1->ipv4.sin_addr.s_addr == sa2->ipv4.sin_addr.s_addr)) - { - return 1; - } - } -#ifdef ENABLE_IPV6 - else if (sa1 -> addr.sa_family == AF_INET6 ) - { - if ( (sa1-> ipv6.sin6_port == sa2->ipv6.sin6_port) && - (memcmp(&(sa1->ipv6.sin6_addr), &(sa2->ipv6.sin6_addr), sizeof(struct in6_addr)) == 0)) - { - return 1; - } - } -#endif - } - return 0; -} - -static int -sa_size( const bjnp_sockaddr_t *sa) -{ - switch (sa -> addr.sa_family) - { - case AF_INET: - return (sizeof(struct sockaddr_in) ); -#ifdef ENABLE_IPV6 - case AF_INET6: - return (sizeof(struct sockaddr_in6) ); -#endif - default: - /* should not occur */ - return sizeof( bjnp_sockaddr_t ); - } -} - -static int -get_protocol_family( const bjnp_sockaddr_t *sa) -{ - switch (sa -> addr.sa_family) - { - case AF_INET: - return PF_INET; - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - return PF_INET6; - break; -#endif - default: - /* should not occur */ - return -1; - } -} - -static void -get_address_info ( const bjnp_sockaddr_t *addr, char * addr_string, int *port) -{ - char tmp_addr[BJNP_HOST_MAX]; - if ( addr->addr.sa_family == AF_INET) - { - inet_ntop( AF_INET, &(addr -> ipv4.sin_addr.s_addr), addr_string, BJNP_HOST_MAX); - *port = ntohs (addr->ipv4.sin_port); - } -#ifdef ENABLE_IPV6 - else if (addr->addr.sa_family == AF_INET6) - { - inet_ntop( AF_INET6, addr -> ipv6.sin6_addr.s6_addr, tmp_addr, sizeof(tmp_addr) ); - - if (IN6_IS_ADDR_LINKLOCAL( &(addr -> ipv6.sin6_addr) ) ) - sprintf(addr_string, "[%s%%%d]", tmp_addr, addr -> ipv6.sin6_scope_id); - - *port = ntohs (addr->ipv6.sin6_port); - } -#endif - else - { - /* unknown address family, should not occur */ - strcpy(addr_string, "Unknown address family"); - *port = 0; - } -} - -static int -parse_IEEE1284_to_model (char *scanner_id, char *model) -{ -/* - * parses the IEEE1284 ID of the scanner to retrieve make and model - * of the scanner - * Returns: 0 = not found - * 1 = found, model is set - */ - - char s[BJNP_IEEE1284_MAX]; - char *tok; - - strncpy (s, scanner_id, BJNP_IEEE1284_MAX); - s[BJNP_IEEE1284_MAX - 1] = '\0'; - model[0] = '\0'; - - tok = strtok (s, ";"); - while (tok != NULL) - { - /* MDL contains make and model */ - - if (strncmp (tok, "MDL:", 4) == 0) - { - strncpy (model, tok + 4, BJNP_IEEE1284_MAX); - model[BJNP_IEEE1284_MAX -1] = '\0'; - return 1; - } - tok = strtok (NULL, ";"); - } - return 0; -} - -static int -charTo2byte (char *d, const char *s, int len) -{ - /* - * copy ASCII string to UTF-16 unicode string - * len is length of destination buffer - * Returns: number of characters copied - */ - - int done = 0; - int copied = 0; - int i; - - len = len / 2; - for (i = 0; i < len; i++) - { - d[2 * i] = '\0'; - if (s[i] == '\0') - { - done = 1; - } - if (done == 0) - { - d[2 * i + 1] = s[i]; - copied++; - } - else - d[2 * i + 1] = '\0'; - } - return copied; -} - -static bjnp_protocol_defs_t *get_protocol_by_method( char *method) -{ - int i = 0; - while ( bjnp_protocol_defs[i].method_string != NULL) - { - if (strcmp(method, bjnp_protocol_defs[i].method_string) == 0) - { - return &bjnp_protocol_defs[i]; - } - i++; - } - return NULL; -} - -static bjnp_protocol_defs_t *get_protocol_by_proto_string( char *proto_string) -{ - int i = 0; - while ( bjnp_protocol_defs[i].proto_string != NULL) - { - if (strncmp(proto_string, bjnp_protocol_defs[i].proto_string, 4) == 0) - { - return &bjnp_protocol_defs[i]; - } - i++; - } - return NULL; -} - -static char * -getusername (void) -{ - static char noname[] = "sane_pixma"; - struct passwd *pwdent; - -#ifdef HAVE_PWD_H - if (((pwdent = getpwuid (geteuid ())) != NULL) && (pwdent->pw_name != NULL)) - return pwdent->pw_name; -#endif - return noname; -} - - -static char * -determine_scanner_serial (const char *hostname, const char * mac_address, char *serial) -{ - char *dot; - char copy[BJNP_HOST_MAX]; - - /* determine a "serial number" for the scanner */ - /* if available we use the hostname or ipv4 address of the printer */ - /* if we only have a literal ipv6 address, we use the mac-address */ - - strcpy(copy, hostname); - if (strlen (copy) >= SERIAL_MAX) - { - /* make the string fit into the serial */ - /* if this is a FQDN, not an ip-address, remove domain part of the name */ - if ((dot = strchr (copy, '.')) != NULL) - { - *dot = '\0'; - } - } - /* check if name is still to long. If so use the mac-address */ - if (strlen(copy) >= SERIAL_MAX) - { - strcpy(copy, mac_address); - } - strcpy( serial, copy ); - return serial; -} - -static int -bjnp_open_tcp (int devno) -{ - int sock; - int val; - bjnp_sockaddr_t *addr = device[devno].addr; - char host[BJNP_HOST_MAX]; - int port; - - get_address_info( addr, host, &port); - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_open_tcp: Setting up a TCP socket, dest: %s port %d\n", - host, port ) ); - - if ((sock = socket (get_protocol_family( addr ) , SOCK_STREAM, 0)) < 0) - { - PDBG (bjnp_dbg (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not create socket: %s\n", - strerror (errno))); - return -1; - } - - val = 1; - setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &val, sizeof (val)); - -#if 0 - val = 1; - setsockopt (sock, SOL_SOCKET, SO_REUSEPORT, &val, sizeof (val)); - - val = 1; -#endif - - /* - * Using TCP_NODELAY improves responsiveness, especially on systems - * with a slow loopback interface... - */ - - val = 1; - setsockopt (sock, IPPROTO_TCP, TCP_NODELAY, &val, sizeof (val)); - -/* - * Close this socket when starting another process... - */ - - fcntl (sock, F_SETFD, FD_CLOEXEC); - - if (connect - (sock, &(addr->addr), sa_size(device[devno].addr) )!= 0) - { - PDBG (bjnp_dbg - (LOG_CRIT, "bjnp_open_tcp: ERROR - Can not connect to scanner: %s\n", - strerror (errno))); - return -1; - } - device[devno].tcp_socket = sock; - return 0; -} - -static int -split_uri (const char *devname, char *method, char *host, char *port, - char *args) -{ - char copy[1024]; - char *start; - char next; - int i; - - strncpy (copy, devname, 1024); - copy[1023] = '\0'; - start = copy; - -/* - * retrieve method - */ - i = 0; - while ((start[i] != '\0') && (start[i] != ':')) - { - i++; - } - - if (((strncmp (start + i, "://", 3) != 0)) || (i > BJNP_METHOD_MAX -1 )) - { - PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find method in %s (offset %d)\n", - devname, i)); - return -1; - } - - start[i] = '\0'; - strcpy (method, start); - start = start + i + 3; - -/* - * retrieve host - */ - - if (start[0] == '[') - { - /* literal IPv6 address */ - - char *end_of_address = strchr(start, ']'); - - if ( ( end_of_address == NULL) || - ( (end_of_address[1] != ':') && (end_of_address[1] != '/' ) && (end_of_address[1] != '\0' )) || - ( (end_of_address - start) >= BJNP_HOST_MAX ) ) - { - PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find hostname or address in %s\n", devname)); - return -1; - } - next = end_of_address[1]; - *end_of_address = '\0'; - strcpy(host, start + 1); - start = end_of_address + 2; - } - else - { - i = 0; - while ((start[i] != '\0') && (start[i] != '/') && (start[i] != ':')) - { - i++; - } - next = start[i]; - start[i] = '\0'; - if ((i == 0) || (i >= BJNP_HOST_MAX ) ) - { - PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find hostname or address in %s\n", devname)); - return -1; - } - strcpy (host, start); - start = start + i +1; - } - - -/* - * retrieve port number - */ - - if (next != ':') - strcpy(port, ""); - else - { - char *end_of_port = strchr(start, '/'); - if (end_of_port == NULL) - { - next = '\0'; - } - else - { - next = *end_of_port; - *end_of_port = '\0'; - } - if ((strlen(start) == 0) || (strlen(start) >= BJNP_PORT_MAX ) ) - { - PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Can not find port in %s (have \"%s\")\n", devname, start)); - return -1; - } - strcpy(port, start); - start = end_of_port + 1; - } - -/* - * Retrieve arguments - */ - - if (next == '/') - { - i = strlen(start); - if ( i >= BJNP_ARGS_MAX) - { - PDBG (bjnp_dbg (LOG_NOTICE, "split_uri: ERROR - Argument string too long in %s\n", devname)); - } - strcpy (args, start); - } - else - strcpy (args, ""); - return 0; -} - - - -static void -set_cmd_from_string (char* protocol_string, struct BJNP_command *cmd, char cmd_code, int payload_len) -{ - /* - * Set command buffer with command code, session_id and length of payload - * Returns: sequence number of command - */ - - strncpy (cmd->BJNP_id, protocol_string, sizeof (cmd->BJNP_id)); - cmd->dev_type = BJNP_CMD_SCAN; - cmd->cmd_code = cmd_code; - cmd->unknown1 = htons (0); - - /* device not yet opened, use 0 for serial and session) */ - cmd->seq_no = htons (0); - cmd->session_id = htons (0); - cmd->payload_len = htonl (payload_len); -} - -static void -set_cmd_for_dev (int devno, struct BJNP_command *cmd, char cmd_code, int payload_len) -{ - /* - * Set command buffer with command code, session_id and length of payload - * Returns: sequence number of command - */ - - strncpy (cmd->BJNP_id, device[devno].protocol_string, sizeof (cmd->BJNP_id)); - cmd->dev_type = BJNP_CMD_SCAN; - cmd->cmd_code = cmd_code; - cmd->unknown1 = htons (0); - cmd->seq_no = htons (++(device[devno].serial)); - cmd->session_id = (cmd_code == CMD_UDP_POLL ) ? 0 : htons (device[devno].session_id); - device[devno].last_cmd = cmd_code; - cmd->payload_len = htonl (payload_len); -} - -static int -bjnp_setup_udp_socket ( const int dev_no ) -{ - /* - * Setup a udp socket for the given device - * Returns the socket or -1 in case of error - */ - - int sockfd; - char addr_string[256]; - int port; - bjnp_sockaddr_t * addr = device[dev_no].addr; - - get_address_info( addr, addr_string, &port); - - PDBG (bjnp_dbg (LOG_DEBUG, "setup_udp_socket: Setting up a UDP socket, dest: %s port %d\n", - addr_string, port ) ); - - if ((sockfd = socket (get_protocol_family( addr ), SOCK_DGRAM, IPPROTO_UDP)) == -1) - { - PDBG (bjnp_dbg - (LOG_CRIT, "setup_udp_socket: ERROR - can not open socket - %s\n", - strerror (errno))); - return -1; - } - - if (connect - (sockfd, &(device[dev_no].addr->addr), sa_size(device[dev_no].addr) )!= 0) - { - PDBG (bjnp_dbg - (LOG_CRIT, "setup_udp_socket: ERROR - connect failed- %s\n", - strerror (errno))); - close(sockfd); - return -1; - } - return sockfd; -} - -static int -udp_command (const int dev_no, char *command, int cmd_len, char *response, - int resp_len) -{ - /* - * send udp command to given device and recieve the response` - * returns: the legth of the response or -1 - */ - int sockfd; - struct timeval timeout; - int result; - int try, attempt; - int numbytes; - fd_set fdset; - struct BJNP_command *resp = (struct BJNP_command *) response; - struct BJNP_command *cmd = (struct BJNP_command *) command; - - if ( (sockfd = bjnp_setup_udp_socket(dev_no) ) == -1 ) - { - PDBG (bjnp_dbg( LOG_CRIT, "udp_command: ERROR - Can not setup socket\n") ); - return -1; - } - - for (try = 0; try < BJNP_UDP_RETRY_MAX; try++) - { - if ((numbytes = send (sockfd, command, cmd_len, 0)) != cmd_len) - { - PDBG (bjnp_dbg - (LOG_NOTICE, "udp_command: ERROR - Sent %d bytes, expected %d\n", - numbytes, cmd_len)); - continue; - } - - attempt = 0; - - /* wait for data to be received, ignore signals being received */ - /* skip late udp responses (they have an incorrect sequence number */ - do - { - FD_ZERO (&fdset); - FD_SET (sockfd, &fdset); - - timeout.tv_sec = device[dev_no].bjnp_timeout /1000; - timeout.tv_usec = device[dev_no].bjnp_timeout %1000; - } - while (((result = - select (sockfd + 1, &fdset, NULL, NULL, &timeout)) <= 0) - && (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS) - && resp-> seq_no != cmd->seq_no); - - if (result <= 0) - { - PDBG (bjnp_dbg - (LOG_NOTICE, "udp_command: ERROR - select failed: %s\n", - result == 0 ? "timed out" : strerror (errno))); - continue; - } - - if ((numbytes = recv (sockfd, response, resp_len, 0)) == -1) - { - PDBG (bjnp_dbg - (LOG_NOTICE, "udp_command: ERROR - recv failed: %s", - strerror (errno))); - continue; - } - close(sockfd); - return numbytes; - } - - /* no response even after retry */ - - close(sockfd); - PDBG (bjnp_dbg - (LOG_CRIT, "udp_command: ERROR - no data received (timeout = %d)\n", device[dev_no].bjnp_timeout ) ); - return -1; -} - -static int -get_scanner_id (const int dev_no, char *model) -{ - /* - * get scanner identity - * Sets model (make and model) - * Return 0 on success, -1 in case of errors - */ - - struct BJNP_command cmd; - struct IDENTITY *id; - char scanner_id[BJNP_IEEE1284_MAX]; - int resp_len; - char resp_buf[BJNP_RESP_MAX]; - int id_len; - - /* set defaults */ - - strcpy (model, "Unidentified scanner"); - - set_cmd_for_dev (dev_no, &cmd, CMD_UDP_GET_ID, 0); - - PDBG (bjnp_dbg (LOG_DEBUG2, "get_scanner_id: Get scanner identity\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &cmd, - sizeof (struct BJNP_command))); - - if ( ( resp_len = udp_command (dev_no, (char *) &cmd, sizeof (struct BJNP_command), - resp_buf, BJNP_RESP_MAX) ) < (int)sizeof(struct BJNP_command) ) - { - PDBG (bjnp_dbg (LOG_DEBUG, "get_scanner_id: ERROR - Failed to retrieve scanner identity:\n")); - return -1; - } - PDBG (bjnp_dbg (LOG_DEBUG2, "get_scanner_id: scanner identity:\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); - - id = (struct IDENTITY *) resp_buf; - - if (device[dev_no].protocol == PROTOCOL_BJNP) - { - id_len = MIN(ntohl( id-> cmd.payload_len ) - sizeof(id-> payload.bjnp.id_len), BJNP_IEEE1284_MAX); - strncpy(scanner_id, id->payload.bjnp.id, id_len); - scanner_id[id_len] = '\0'; - } - else - { - id_len = MIN(ntohl( id-> cmd.payload_len ), BJNP_IEEE1284_MAX); - strncpy(scanner_id, id->payload.mfnp.id, id_len); - scanner_id[id_len] = '\0'; - } - PDBG (bjnp_dbg (LOG_INFO, "get_scanner_id: Scanner identity string = %s - length = %d\n", scanner_id, id_len)); - - /* get make&model from IEEE1284 id */ - - if (model != NULL) - { - parse_IEEE1284_to_model (scanner_id, model); - PDBG (bjnp_dbg (LOG_INFO, "get_scanner_id: Scanner model = %s\n", model)); - } - return 0; -} - -static int -get_scanner_name(const bjnp_sockaddr_t *scanner_sa, char *host) -{ - /* - * Parse identify command responses to ip-address - * and hostname. Return qulity of the address - */ - - struct addrinfo *results; - struct addrinfo *result; - char ip_address[BJNP_HOST_MAX]; - int port; - int error; - int match = 0; - int level; - char service[64]; - -#ifdef ENABLE_IPV6 - if ( ( scanner_sa -> addr.sa_family == AF_INET6 ) && - ( IN6_IS_ADDR_LINKLOCAL( &(scanner_sa -> ipv6.sin6_addr ) ) ) ) - level = BJNP_ADDRESS_IS_LINK_LOCAL; - else -#endif - level = BJNP_ADDRESS_IS_GLOBAL; - - get_address_info( scanner_sa, ip_address, &port ); - - /* do reverse name lookup, if hostname can not be found return ip-address */ - - if( (error = getnameinfo( &(scanner_sa -> addr) , sa_size( scanner_sa), - host, BJNP_HOST_MAX , NULL, 0, NI_NAMEREQD) ) != 0 ) - { - PDBG (bjnp_dbg(LOG_INFO, "get_scanner_name: Name for %s not found : %s\n", - ip_address, gai_strerror(error) ) ); - strcpy(host, ip_address); - return level; - } - else - { - sprintf(service, "%d", port); - /* some buggy routers return rubbish if reverse lookup fails, so - * we do a forward lookup on the received name to see if the result matches */ - - if (getaddrinfo(host , service, NULL, &results) == 0) - { - result = results; - - while (result != NULL) - { - if(sa_is_equal( scanner_sa, (bjnp_sockaddr_t *)result-> ai_addr)) - { - /* found match, good */ - PDBG (bjnp_dbg (LOG_INFO, - "get_scanner_name: Forward lookup for %s succeeded, using as hostname\n", host)); - match = 1; - level = BJNP_ADDRESS_HAS_FQDN; - break; - } - result = result-> ai_next; - } - freeaddrinfo(results); - - if (match != 1) - { - PDBG (bjnp_dbg (LOG_INFO, - "get_scanner_name: Forward lookup for %s succeeded, IP-address does not match, using IP-address %s instead\n", - host, ip_address)); - strcpy (host, ip_address); - } - } - else - { - /* forward lookup failed, use ip-address */ - PDBG ( bjnp_dbg (LOG_INFO, "get_scanner_name: Forward lookup of %s failed, using IP-address", ip_address)); - strcpy (host, ip_address); - } - } - return level; -} - -static int -get_port_from_sa(const bjnp_sockaddr_t scanner_sa) -{ -#ifdef ENABLE_IPV6 - if ( scanner_sa.addr.sa_family == AF_INET6 ) - { - return ntohs(scanner_sa.ipv6.sin6_port); - } - else -#endif - if ( scanner_sa.addr.sa_family == AF_INET ) - { - return ntohs(scanner_sa.ipv4.sin_port); - } - return -1; -} - -static int create_broadcast_socket( const bjnp_sockaddr_t * local_addr ) -{ - int sockfd = -1; - int broadcast = 1; - int ipv6_v6only = 1; - - - if ((sockfd = socket (local_addr-> addr.sa_family, SOCK_DGRAM, 0)) == -1) - { - PDBG (bjnp_dbg - (LOG_CRIT, "create_broadcast_socket: ERROR - can not open socket - %s", - strerror (errno))); - return -1; - } - - /* Set broadcast flag on socket */ - - if (setsockopt - (sockfd, SOL_SOCKET, SO_BROADCAST, (const char *) &broadcast, - sizeof (broadcast)) != 0) - { - PDBG (bjnp_dbg - (LOG_CRIT, - "create_broadcast_socket: ERROR - setting socket option SO_BROADCAST failed - %s", - strerror (errno))); - close (sockfd); - return -1; - }; - - /* For an IPv6 socket, bind to v6 only so a V6 socket can co-exist with a v4 socket */ - if ( (local_addr -> addr.sa_family == AF_INET6) && ( setsockopt - (sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *) &ipv6_v6only, - sizeof (ipv6_v6only)) != 0) ) - { - PDBG (bjnp_dbg - (LOG_CRIT, - "create_broadcast_socket: ERROR - setting socket option IPV6_V6ONLY failed - %s", - strerror (errno))); - close (sockfd); - return -1; - }; - - if (bind - (sockfd, &(local_addr->addr), - (socklen_t) sa_size( local_addr)) != 0) - { - PDBG (bjnp_dbg - (LOG_CRIT, - "create_broadcast_socket: ERROR - bind socket to local address failed - %s\n", - strerror (errno))); - close (sockfd); - return -1; - } - return sockfd; -} - -static int -prepare_socket(const char *if_name, const bjnp_sockaddr_t *local_sa, - const bjnp_sockaddr_t *broadcast_sa, bjnp_sockaddr_t * dest_sa) -{ - /* - * Prepare a socket for broadcast or multicast - * Input: - * if_name: the name of the interface - * local_sa: local address to use - * broadcast_sa: broadcast address to use, if NULL we use all hosts - * dest_sa: (write) where to return destination address of broadcast - * retuns: open socket or -1 - */ - - int socket = -1; - bjnp_sockaddr_t local_sa_copy; - - if ( local_sa == NULL ) - { - PDBG (bjnp_dbg (LOG_DEBUG, - "prepare_socket: %s is not a valid IPv4 interface, skipping...\n", - if_name)); - return -1; - } - - memset( &local_sa_copy, 0, sizeof(local_sa_copy) ); - memcpy( &local_sa_copy, local_sa, sa_size(local_sa) ); - - switch( local_sa_copy.addr.sa_family ) - { - case AF_INET: - { - local_sa_copy.ipv4.sin_port = htons(BJNP_PORT_SCAN); - - if (local_sa_copy.ipv4.sin_addr.s_addr == htonl (INADDR_LOOPBACK) ) - { - /* not a valid interface */ - - PDBG (bjnp_dbg (LOG_DEBUG, - "prepare_socket: %s is not a valid IPv4 interface, skipping...\n", - if_name)); - return -1; - } - - - /* send broadcasts to the broadcast address of the interface */ - - memcpy(dest_sa, broadcast_sa, sa_size(dest_sa) ); - - /* we fill port when we send the broadcast */ - dest_sa -> ipv4.sin_port = htons(0); - - if ( (socket = create_broadcast_socket( &local_sa_copy) ) != -1) - { - PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: %s is IPv4 capable, sending broadcast, socket = %d\n", - if_name, socket)); - } - else - { - PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: ERROR - %s is IPv4 capable, but failed to create a socket.\n", - if_name)); - return -1; - } - } - break; -#ifdef ENABLE_IPV6 - case AF_INET6: - { - local_sa_copy.ipv6.sin6_port = htons(BJNP_PORT_SCAN); - - if (IN6_IS_ADDR_LOOPBACK( &(local_sa_copy.ipv6.sin6_addr) ) ) - { - /* not a valid interface */ - - PDBG (bjnp_dbg (LOG_DEBUG, - "prepare_socket: %s is not a valid IPv6 interface, skipping...\n", - if_name)); - return -1; - } - else - { - dest_sa -> ipv6.sin6_family = AF_INET6; - - /* We fill port when we send the broadcast */ - dest_sa -> ipv6.sin6_port = htons(0); - - inet_pton(AF_INET6, "ff02::1", dest_sa -> ipv6.sin6_addr.s6_addr); - if ( (socket = create_broadcast_socket( &local_sa_copy ) ) != -1) - { - PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: %s is IPv6 capable, sending broadcast, socket = %d\n", - if_name, socket)); - } - else - { - PDBG (bjnp_dbg (LOG_INFO, "prepare_socket: ERROR - %s is IPv6 capable, but failed to create a socket.\n", - if_name)); - return -1; - } - } - } - break; -#endif - - default: - socket = -1; - } - return socket; -} - -static int -bjnp_send_broadcast (int sockfd, const bjnp_sockaddr_t * broadcast_addr, int port, - struct BJNP_command cmd, int size) -{ - int num_bytes; - bjnp_sockaddr_t dest_addr; - - /* set address to send packet to broadcast address of interface, */ - /* with port set to the destination port */ - - memcpy(&dest_addr, broadcast_addr, sizeof(dest_addr)); - if( dest_addr.addr.sa_family == AF_INET) - { - dest_addr.ipv4.sin_port = htons(port); - } -#ifdef ENABLE_IPV6 - if( dest_addr.addr.sa_family == AF_INET6) - { - dest_addr.ipv6.sin6_port = htons(port); - } -#endif - - if ((num_bytes = sendto (sockfd, &cmd, size, 0, - &(dest_addr.addr), - sa_size( broadcast_addr)) ) != size) - { - PDBG (bjnp_dbg (LOG_INFO, - "bjnp_send_broadcast: Socket: %d: ERROR - sent only %x = %d bytes of packet, error = %s\n", - sockfd, num_bytes, num_bytes, strerror (errno))); - /* not allowed, skip this interface */ - - return -1; - } - return sockfd; -} - -static void -bjnp_finish_job (int devno) -{ -/* - * Signal end of scanjob to scanner - */ - - char resp_buf[BJNP_RESP_MAX]; - int resp_len; - struct BJNP_command cmd; - - set_cmd_for_dev (devno, &cmd, CMD_UDP_CLOSE, 0); - - PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_finish_job: Finish scanjob\n")); - PDBG (bjnp_hexdump - (LOG_DEBUG2, (char *) &cmd, sizeof (struct BJNP_command))); - resp_len = - udp_command (devno, (char *) &cmd, sizeof (struct BJNP_command), resp_buf, - BJNP_RESP_MAX); - - if (resp_len != sizeof (struct BJNP_command)) - { - PDBG (bjnp_dbg - (LOG_INFO, - "bjnp_finish_job: ERROR - Received %d characters on close scanjob command, expected %d\n", - resp_len, (int) sizeof (struct BJNP_command))); - return; - } - PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_finish_job: Finish scanjob response\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); - -} - -#ifdef PIXMA_BJNP_USE_STATUS -static int -bjnp_poll_scanner (int devno, char type,char *hostname, char *user, SANE_Byte *status, int size) -{ -/* - * send details of user to the scanner - */ - - char cmd_buf[BJNP_CMD_MAX]; - char resp_buf[BJNP_RESP_MAX]; - int resp_len; - int len = 0; /* payload length */ - int buf_len; /* length of the whole command buffer */ - struct POLL_DETAILS *poll; - struct POLL_RESPONSE *response; - char user_host[256]; - time_t t; - int user_host_len; - - poll = (struct POLL_DETAILS *) cmd_buf; - memset( poll, 0, sizeof( struct POLL_DETAILS)); - memset( &resp_buf, 0, sizeof( resp_buf) ); - - - /* create payload */ - poll->type = htons(type); - - user_host_len = sizeof( poll -> extensions.type2.user_host); - snprintf(user_host, (user_host_len /2) ,"%s %s", user, hostname); - user_host[ user_host_len /2 + 1] = '\0'; - - switch( type) { - case 0: - len = 80; - break; - case 1: - charTo2byte(poll->extensions.type1.user_host, user_host, user_host_len); - len = 80; - break; - case 2: - poll->extensions.type2.dialog = htonl(device[devno].dialog); - charTo2byte(poll->extensions.type2.user_host, user_host, user_host_len); - poll->extensions.type2.unknown_1 = htonl(0x14); - poll->extensions.type2.unknown_2 = htonl(0x10); - t = time (NULL); - strftime (poll->extensions.type2.ascii_date, - sizeof (poll->extensions.type2.ascii_date), - "%Y%m%d%H%M%S", localtime (&t)); - len = 116; - break; - case 5: - poll->extensions.type5.dialog = htonl(device[devno].dialog); - charTo2byte(poll->extensions.type5.user_host, user_host, user_host_len); - poll->extensions.type5.unknown_1 = htonl(0x14); - poll->extensions.type5.key = htonl(device[devno].status_key); - len = 100; - break; - default: - PDBG (bjnp_dbg (LOG_INFO, "bjnp_poll_scanner: unknown packet type: %d\n", type)); - return -1; - }; - /* we can only now set the header as we now know the length of the payload */ - set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_POLL, - len); - - buf_len = len + sizeof(struct BJNP_command); - PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_poll_scanner: Poll details (type %d)\n", type)); - PDBG (bjnp_hexdump (LOG_DEBUG2, cmd_buf, - buf_len)); - - resp_len = udp_command (devno, cmd_buf, buf_len, resp_buf, BJNP_RESP_MAX); - - if (resp_len > 0) - { - PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_poll_scanner: Poll details response:\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); - response = (struct POLL_RESPONSE *) resp_buf; - - device[devno].dialog = ntohl( response -> dialog ); - - if ( response -> result[3] == 1 ) - { - return BJNP_RESTART_POLL; - } - if ( (response -> result[2] & 0x80) != 0) - { - memcpy( status, response->status, size); - PDBG( bjnp_dbg(LOG_INFO, "bjnp_poll_scanner: received button status!\n")); - PDBG (bjnp_hexdump( LOG_DEBUG2, status, size )); - device[devno].status_key = ntohl( response -> key ); - return size; - } - } - return 0; -} -#endif - -static void -bjnp_send_job_details (int devno, char *hostname, char *user, char *title) -{ -/* - * send details of scanjob to scanner - */ - - char cmd_buf[BJNP_CMD_MAX]; - char resp_buf[BJNP_RESP_MAX]; - int resp_len; - struct JOB_DETAILS *job; - struct BJNP_command *resp; - - /* send job details command */ - - set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_JOB_DETAILS, - sizeof (*job) - sizeof (struct BJNP_command)); - - /* create payload */ - - job = (struct JOB_DETAILS *) (cmd_buf); - charTo2byte (job->unknown, "", sizeof (job->unknown)); - charTo2byte (job->hostname, hostname, sizeof (job->hostname)); - charTo2byte (job->username, user, sizeof (job->username)); - charTo2byte (job->jobtitle, title, sizeof (job->jobtitle)); - - PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_send_job_details: Job details\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, cmd_buf, - (sizeof (struct BJNP_command) + sizeof (*job)))); - - resp_len = udp_command (devno, cmd_buf, - sizeof (struct JOB_DETAILS), resp_buf, - BJNP_RESP_MAX); - - if (resp_len > 0) - { - PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_send_job_details: Job details response:\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); - resp = (struct BJNP_command *) resp_buf; - device[devno].session_id = ntohs (resp->session_id); - } -} - -static int -bjnp_get_scanner_mac_address ( int devno, char *mac_address ) -{ -/* - * send discover to scanner - */ - - char cmd_buf[BJNP_CMD_MAX]; - char resp_buf[BJNP_RESP_MAX]; - int resp_len; - struct DISCOVER_RESPONSE *resp = (struct DISCOVER_RESPONSE * )&resp_buf;; - - /* send job details command */ - - set_cmd_for_dev (devno, (struct BJNP_command *) cmd_buf, CMD_UDP_DISCOVER, 0); - resp_len = udp_command (devno, cmd_buf, - sizeof (struct BJNP_command), resp_buf, - BJNP_RESP_MAX); - - if (resp_len > 0) - { - PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_get_scanner_mac_address: Discover response:\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, resp_buf, resp_len)); - u8tohex( mac_address, resp -> mac_addr, sizeof( resp -> mac_addr ) ); - return 0; - } - return -1; -} - -static int -bjnp_write (int devno, const SANE_Byte * buf, size_t count) -{ -/* - * This function writes TCP data to the scanner. - * Returns: number of bytes written to the scanner - */ - int sent_bytes; - int terrno; - struct SCAN_BUF bjnp_buf; - - if (device[devno].scanner_data_left) - { - PDBG (bjnp_dbg - (LOG_CRIT, "bjnp_write: ERROR - scanner data left = 0x%lx = %ld\n", - (unsigned long) device[devno].scanner_data_left, - (unsigned long) device[devno].scanner_data_left)); - } - /* set BJNP command header */ - - set_cmd_for_dev (devno, (struct BJNP_command *) &bjnp_buf, CMD_TCP_SEND, count); - memcpy (bjnp_buf.scan_data, buf, count); - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_write: sending 0x%lx = %ld bytes\n", - (unsigned long) count, (unsigned long) count); - PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &bjnp_buf, - sizeof (struct BJNP_command) + count))); - - if ((sent_bytes = - send (device[devno].tcp_socket, &bjnp_buf, - sizeof (struct BJNP_command) + count, 0)) < - (ssize_t) (sizeof (struct BJNP_command) + count)) - { - /* return result from write */ - terrno = errno; - PDBG (bjnp_dbg (LOG_CRIT, "bjnp_write: ERROR - Could not send data!\n")); - errno = terrno; - return sent_bytes; - } - /* correct nr of bytes sent for length of command */ - - else if (sent_bytes != (int) (sizeof (struct BJNP_command) + count)) - { - errno = EIO; - return -1; - } - return count; -} - -static int -bjnp_send_read_request (int devno) -{ -/* - * This function reads responses from the scanner. - * Returns: 0 on success, else -1 - * - */ - int sent_bytes; - int terrno; - struct BJNP_command bjnp_buf; - - if (device[devno].scanner_data_left) - PDBG (bjnp_dbg - (LOG_CRIT, - "bjnp_send_read_request: ERROR - scanner data left = 0x%lx = %ld\n", - (unsigned long) device[devno].scanner_data_left, - (unsigned long) device[devno].scanner_data_left)); - - /* set BJNP command header */ - - set_cmd_for_dev (devno, (struct BJNP_command *) &bjnp_buf, CMD_TCP_REQ, 0); - - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_send_read_req sending command\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, (char *) &bjnp_buf, - sizeof (struct BJNP_command))); - - if ((sent_bytes = - send (device[devno].tcp_socket, &bjnp_buf, sizeof (struct BJNP_command), - 0)) < 0) - { - /* return result from write */ - terrno = errno; - PDBG (bjnp_dbg - (LOG_CRIT, "bjnp_send_read_request: ERROR - Could not send data!\n")); - errno = terrno; - return -1; - } - return 0; -} - -static SANE_Status -bjnp_recv_header (int devno, size_t *payload_size ) -{ -/* - * This function receives the response header to bjnp commands. - * devno device number - * size: return value for data size returned by scanner - * Returns: - * SANE_STATUS_IO_ERROR when any IO error occurs - * SANE_STATUS_GOOD in case no errors were encountered - */ - struct BJNP_command resp_buf; - fd_set input; - struct timeval timeout; - int recv_bytes; - int terrno; - int result; - int fd; - int attempt; - - PDBG (bjnp_dbg - (LOG_DEBUG, "bjnp_recv_header: receiving response header\n") ); - fd = device[devno].tcp_socket; - - *payload_size = 0; - attempt = 0; - do - { - /* wait for data to be received, ignore signals being received */ - FD_ZERO (&input); - FD_SET (fd, &input); - - timeout.tv_sec = device[devno].bjnp_timeout /1000; - timeout.tv_usec = device[devno].bjnp_timeout %1000; - } - while ( ( (result = select (fd + 1, &input, NULL, NULL, &timeout)) <= 0) && - (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS)); - - if (result < 0) - { - terrno = errno; - PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_header: ERROR - could not read response header (select): %s!\n", - strerror (terrno))); - errno = terrno; - return SANE_STATUS_IO_ERROR; - } - else if (result == 0) - { - terrno = errno; - PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_header: ERROR - could not read response header (select timed out after %d ms)!\n", - device[devno].bjnp_timeout ) ); - errno = terrno; - return SANE_STATUS_IO_ERROR; - } - - /* get response header */ - - if ((recv_bytes = - recv (fd, (char *) &resp_buf, - sizeof (struct BJNP_command), - 0)) != sizeof (struct BJNP_command)) - { - terrno = errno; - if (recv_bytes == 0) - { - PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_header: ERROR - (recv) Scanner closed the TCP-connection!\n")); - } else { - PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_header: ERROR - (recv) could not read response header, received %d bytes!\n", - recv_bytes)); - PDBG (bjnp_dbg - (LOG_CRIT, "bjnp_recv_header: ERROR - (recv) error: %s!\n", - strerror (terrno))); - } - errno = terrno; - return SANE_STATUS_IO_ERROR; - } - - if (resp_buf.cmd_code != device[devno].last_cmd) - { - PDBG (bjnp_dbg - (LOG_CRIT, - "bjnp_recv_header: ERROR - Received response has cmd code %d, expected %d\n", - resp_buf.cmd_code, device[devno].last_cmd)); - return SANE_STATUS_IO_ERROR; - } - - if (ntohs (resp_buf.seq_no) != (uint16_t) device[devno].serial) - { - PDBG (bjnp_dbg - (LOG_CRIT, - "bjnp_recv_header: ERROR - Received response has serial %d, expected %d\n", - (int) ntohs (resp_buf.seq_no), (int) device[devno].serial)); - return SANE_STATUS_IO_ERROR; - } - - /* got response header back, retrieve length of payload */ - - - *payload_size = ntohl (resp_buf.payload_len); - PDBG (bjnp_dbg - (LOG_DEBUG, "bjnp_recv_header: TCP response header(payload data = %ld bytes):\n", - *payload_size) ); - PDBG (bjnp_hexdump - (LOG_DEBUG2, (char *) &resp_buf, sizeof (struct BJNP_command))); - return SANE_STATUS_GOOD; -} - -static int -bjnp_init_device_structure(int dn, bjnp_sockaddr_t *sa, bjnp_protocol_defs_t *protocol_defs, int min_timeout) -{ - /* initialize device structure */ - - char name[BJNP_HOST_MAX]; - - device[dn].open = 0; -#ifdef PIXMA_BJNP_USE_STATUS - device[dn].polling_status = BJNP_POLL_STOPPED; - device[dn].dialog = 0; - device[dn].status_key = 0; -#endif - device[dn].protocol = protocol_defs->protocol_version; - device[dn].protocol_string = protocol_defs->proto_string; - device[dn].tcp_socket = -1; - - device[dn].addr = (bjnp_sockaddr_t *) malloc(sizeof ( bjnp_sockaddr_t) ); - memset( device[dn].addr, 0, sizeof( bjnp_sockaddr_t ) ); - memcpy(device[dn].addr, sa, sa_size((bjnp_sockaddr_t *)sa) ); - device[dn].address_level = get_scanner_name(sa, name); - device[dn].session_id = 0; - device[dn].serial = -1; - device[dn].bjnp_timeout = min_timeout; - device[dn].bjnp_min_timeout = min_timeout; - device[dn].scanner_data_left = 0; - device[dn].last_cmd = 0; - device[dn].blocksize = BJNP_BLOCKSIZE_START; - device[dn].last_block = 0; - /* fill mac_address */ - - if (bjnp_get_scanner_mac_address(dn, device[dn].mac_address) != 0 ) - { - PDBG (bjnp_dbg - (LOG_CRIT, "bjnp_init_device_structure: Cannot read mac address, skipping this scanner\n" ) ); - return -1; - } - return 0; -} - -static void -bjnp_free_device_structure( int dn) -{ - if (device[dn].addr != NULL) - { - free (device[dn].addr ); - device[dn].addr = NULL; - } - device[dn].open = 0; -} - -static SANE_Status -bjnp_recv_data (int devno, SANE_Byte * buffer, size_t start_pos, size_t * len) -{ -/* - * This function receives the payload data. - * NOTE: len may not exceed SSIZE_MAX (as that is max for recv) - * len will be restricted to SSIZE_MAX to be sure - * Returns: number of bytes of payload received from device - */ - - fd_set input; - struct timeval timeout; - ssize_t recv_bytes; - int terrno; - int result; - int fd; - int attempt; - - PDBG (bjnp_dbg - (LOG_DEBUG, "bjnp_recv_data: read response payload (0x%lx bytes max), buffer: 0x%lx, start_pos: 0x%lx\n", - (long) *len, (long) buffer, (long) start_pos)); - - - if (*len == 0) - { - /* nothing to do */ - PDBG (bjnp_dbg - (LOG_DEBUG, "bjnp_recv_data: Nothing to do (%ld bytes requested)\n", - (long) *len)); - return SANE_STATUS_GOOD; - } - else if ( *len > SSIZE_MAX ) - { - PDBG (bjnp_dbg - (LOG_DEBUG, "bjnp_recv_data: WARNING - requested block size (%ld) exceeds maximum, setting to maximum %ld\n", - (long)*len, SSIZE_MAX)); - *len = SSIZE_MAX; - } - - fd = device[devno].tcp_socket; - attempt = 0; - do - { - /* wait for data to be received, retry on a signal being received */ - FD_ZERO (&input); - FD_SET (fd, &input); - timeout.tv_sec = device[devno].bjnp_timeout /1000; - timeout.tv_usec = device[devno].bjnp_timeout %1000; - } - while (((result = select (fd + 1, &input, NULL, NULL, &timeout)) <= 0) && - (errno == EINTR) && (attempt++ < BJNP_MAX_SELECT_ATTEMPTS)); - - if (result < 0) - { - terrno = errno; - PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_data: ERROR - could not read response payload (select failed): %s!\n", - strerror (errno))); - errno = terrno; - *len = 0; - return SANE_STATUS_IO_ERROR; - } - else if (result == 0) - { - terrno = errno; - PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_data: ERROR - could not read response payload (select timed out after %d ms)!\n", - device[devno].bjnp_timeout) ); - errno = terrno; - *len = 0; - return SANE_STATUS_IO_ERROR; - } - - if ((recv_bytes = recv (fd, buffer + start_pos, *len, 0)) < 0) - { - terrno = errno; - PDBG (bjnp_dbg (LOG_CRIT, - "bjnp_recv_data: ERROR - could not read response payload (%ld + %ld = %ld) (recv): %s!\n", - (long) buffer, (long) start_pos, (long) buffer + start_pos, strerror (errno))); - errno = terrno; - *len = 0; - return SANE_STATUS_IO_ERROR; - } - PDBG (bjnp_dbg (LOG_DEBUG2, "bjnp_recv_data: Received TCP response payload (%ld bytes):\n", - (unsigned long) recv_bytes)); - PDBG (bjnp_hexdump (LOG_DEBUG2, buffer, recv_bytes)); - - *len = recv_bytes; - return SANE_STATUS_GOOD; -} - -static BJNP_Status -bjnp_allocate_device (SANE_String_Const devname, - SANE_Int * dn, char *resulting_host) -{ - char method[BJNP_METHOD_MAX]; - char host[BJNP_HOST_MAX]; - char port[BJNP_PORT_MAX] = ""; - char args[BJNP_ARGS_MAX]; - bjnp_protocol_defs_t *protocol_defs; - struct addrinfo *res, *cur; - struct addrinfo hints; - int result; - int i; - int min_timeout = BJNP_TIMEOUT_DEFAULT; - - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_allocate_device(%s) %d\n", devname, bjnp_no_devices)); - - if (split_uri (devname, method, host, port, args) != 0) - { - return BJNP_STATUS_INVAL; - } - - if (strlen (args) > 0) - { - /* get device specific timeout if any */ - - if (strncmp(args, "timeout=", strlen("timeout=")) == 0) - { - min_timeout = atoi(args + strlen("timeout=")); - if (min_timeout < BJNP_TIMEOUT_DEFAULT) - min_timeout = BJNP_TIMEOUT_DEFAULT; - } else { - PDBG (bjnp_dbg - (LOG_CRIT, - "bjnp_allocate_device: ERROR - Unrecognized argument: %s\n", - devname)); - - return BJNP_STATUS_INVAL; - } - } - if ( (protocol_defs = get_protocol_by_method(method)) == NULL) - { - PDBG (bjnp_dbg - (LOG_CRIT, "bjnp_allocate_device: ERROR - URI %s contains invalid method: %s\n", - devname, method)); - return BJNP_STATUS_INVAL; - } - - if (strlen(port) == 0) - { - sprintf( port, "%d", protocol_defs->default_port ); - } - - hints.ai_flags = 0; -#ifdef ENABLE_IPV6 - hints.ai_family = AF_UNSPEC; -#else - hints.ai_family = AF_INET; -#endif - hints.ai_socktype = SOCK_DGRAM; - hints.ai_protocol = 0; - hints.ai_addrlen = 0; - hints.ai_addr = NULL; - hints.ai_canonname = NULL; - hints.ai_next = NULL; - - result = getaddrinfo (host, port, &hints, &res ); - if (result != 0 ) - { - PDBG (bjnp_dbg (LOG_CRIT, "bjnp_allocate_device: ERROR - Cannot resolve host: %s port %s\n", host, port)); - return SANE_STATUS_INVAL; - } - - /* Check if a device number is already allocated to any of the scanner's addresses */ - - cur = res; - while( cur != NULL) - { - /* create a new device structure for this address */ - - if (bjnp_no_devices == BJNP_NO_DEVICES) - { - PDBG (bjnp_dbg - (LOG_CRIT, - "bjnp_allocate_device: WARNING - Too many devices, ran out of device structures, cannot add %s\n", - devname)); - freeaddrinfo(res); - return BJNP_STATUS_INVAL; - } - if (bjnp_init_device_structure( bjnp_no_devices, (bjnp_sockaddr_t *)cur -> ai_addr, - protocol_defs, min_timeout) != 0) - { - /* giving up on this address, try next one if any */ - break; - } - for (i = 0; i < bjnp_no_devices; i++) - { - - /* Check if found the scanner before, if so we use the best address - * but still make sure the scanner is listed only once. - * We check for matching addresses as wel as matching mac_addresses as - * an IPv6 host can have multiple adresses */ - - if ( strcmp( device[i].mac_address, device[bjnp_no_devices].mac_address ) == 0 ) - { - if ( device[i].address_level < device[bjnp_no_devices].address_level ) - { - /* use the new address instead as it is better */ - free (device[i].addr); - device[i].addr = device[bjnp_no_devices].addr; - device[bjnp_no_devices].addr = NULL; - device[i].address_level = device[bjnp_no_devices].address_level; - } - - /* check if new timeout value was defined (e.g. from sanei_bjnp_device_open) - * if so, use new timout value */ - - if (device[i].bjnp_min_timeout < device[bjnp_no_devices].bjnp_min_timeout) - { - /* use the longer timeout as requested */ - device[i].bjnp_timeout = device[bjnp_no_devices].bjnp_min_timeout; - device[i].bjnp_min_timeout = device[bjnp_no_devices].bjnp_min_timeout; - } - freeaddrinfo(res); - *dn = i; - bjnp_free_device_structure( bjnp_no_devices); - return BJNP_STATUS_ALREADY_ALLOCATED; - } - } - cur = cur->ai_next; - } - freeaddrinfo(res); - - PDBG (bjnp_dbg (LOG_INFO, "bjnp_allocate_device: Scanner not yet in our list, added it: %s:%s\n", host, port)); - - /* Commit new device structure */ - - *dn = bjnp_no_devices; - bjnp_no_devices++; - - /* return hostname if required */ - - if (resulting_host != NULL) - { - strcpy (resulting_host, host); - } - - return BJNP_STATUS_GOOD; -} - -static void add_scanner(SANE_Int *dev_no, - const char *uri, - SANE_Status (*attach_bjnp) - (SANE_String_Const devname, - SANE_String_Const makemodel, - SANE_String_Const serial, - const struct pixma_config_t * - const pixma_devices[]), - const struct pixma_config_t *const pixma_devices[]) - -{ - char scanner_host[BJNP_HOST_MAX]; - char serial[BJNP_SERIAL_MAX]; - char makemodel[BJNP_IEEE1284_MAX]; - - /* Allocate device structure for scanner */ - switch (bjnp_allocate_device (uri, dev_no, scanner_host)) - { - case BJNP_STATUS_GOOD: - if (get_scanner_id (*dev_no, makemodel) != 0) - { - PDBG (bjnp_dbg (LOG_CRIT, "add_scanner: ERROR - Cannot read scanner make & model: %s\n", - uri)); - } - else - { - /* - * inform caller of found scanner - */ - - determine_scanner_serial (scanner_host, device[*dev_no].mac_address, serial); - - attach_bjnp (uri, makemodel, - serial, pixma_devices); - PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: New scanner added: %s, serial %s, mac address: %s.\n", - uri, serial, device[*dev_no].mac_address)); - } - break; - case BJNP_STATUS_ALREADY_ALLOCATED: - PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: Scanner at %s was added before, good!\n", - uri)); - break; - - case BJNP_STATUS_INVAL: - PDBG (bjnp_dbg (LOG_NOTICE, "add_scanner: Scanner at %s can not be added\n", - uri)); - break; - } -} - -int add_default_timeout(char *uri, int timeout, int max_len) -{ - char method[BJNP_METHOD_MAX]; - char host[BJNP_HOST_MAX]; - char port_str[BJNP_PORT_MAX]; - char args[BJNP_HOST_MAX]; - int port; - - if (split_uri(uri, method, host, port_str, args ) != 0) - { - return -1; - } - - port = atoi(port_str); - if (port == 0) - { - port = 8612; - } - - if (strstr(args, "timeout=") == NULL) - { - sprintf(args, "timeout=%d", timeout); - } - - snprintf(uri, max_len -1, "%s://%s:%d/%s", method,host, port, args); - return 0; -} - - -/* - * Public functions - */ - -/** Initialize sanei_bjnp. - * - * Call this before any other sanei_bjnp function. - */ -extern void -sanei_bjnp_init (void) -{ - DBG_INIT(); - bjnp_no_devices = 0; -} - -/** - * Find devices that implement the bjnp protocol - * - * The function attach is called for every device which has been found. - * - * @param attach attach function - * - * @return SANE_STATUS_GOOD - on success (even if no scanner was found) - */ -extern SANE_Status -sanei_bjnp_find_devices (const char **conf_devices, - SANE_Status (*attach_bjnp) - (SANE_String_Const devname, - SANE_String_Const makemodel, - SANE_String_Const serial, - const struct pixma_config_t * - const pixma_devices[]), - const struct pixma_config_t *const pixma_devices[]) -{ - int numbytes = 0; - struct BJNP_command cmd; - unsigned char resp_buf[2048]; - struct DISCOVER_RESPONSE *disc_resp = ( struct DISCOVER_RESPONSE *) & resp_buf; - int socket_fd[BJNP_SOCK_MAX]; - int no_sockets; - int i; - int j; - int attempt; - int last_socketfd = 0; - fd_set fdset; - fd_set active_fdset; - struct timeval timeout; - char scanner_host[256]; - char uri[256]; - int dev_no; - int port; - int timeout_default = BJNP_TIMEOUT_DEFAULT; - bjnp_sockaddr_t broadcast_addr[BJNP_SOCK_MAX]; - bjnp_sockaddr_t scanner_sa; - socklen_t socklen; - bjnp_protocol_defs_t *protocol_defs; - - memset( broadcast_addr, 0, sizeof( broadcast_addr) ); - memset( &scanner_sa, 0 ,sizeof( scanner_sa ) ); - PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_find_devices, pixma backend version: %d.%d.%d\n", - PIXMA_VERSION_MAJOR, PIXMA_VERSION_MINOR, PIXMA_VERSION_BUILD)); - bjnp_no_devices = 0; - - for (i=0; i < BJNP_SOCK_MAX; i++) - { - socket_fd[i] = -1; - } - - /* Add devices from config file */ - - if (conf_devices[0] == NULL) - PDBG (bjnp_dbg( LOG_DEBUG, "sanei_bjnp_find_devices: No devices specified in configuration file.\n" ) ); - - for (i = 0; conf_devices[i] != NULL; i++) - { - if (strncmp(conf_devices[i], "bjnp-timeout=", strlen("bjnp-timeout="))== 0) - { - timeout_default = atoi(conf_devices[i] + strlen("bjnp-timeout=") ); - if (timeout_default < BJNP_TIMEOUT_DEFAULT) - { - timeout_default = BJNP_TIMEOUT_DEFAULT; - } - PDBG ( bjnp_dbg - (LOG_DEBUG, "Set new default timeout value: %d ms.", timeout_default)); - continue; - } - PDBG (bjnp_dbg - (LOG_DEBUG, "sanei_bjnp_find_devices: Adding scanner from pixma.conf: %s\n", conf_devices[i])); - strncpy(uri, conf_devices[i], sizeof(uri)); - add_default_timeout(uri, timeout_default, sizeof(uri)); - add_scanner(&dev_no, uri, attach_bjnp, pixma_devices); - } - PDBG (bjnp_dbg - (LOG_DEBUG, - "sanei_bjnp_find_devices: Added all configured scanners, now do auto detection...\n")); - - /* - * Send UDP DISCOVER to discover scanners and return the list of scanners found - */ - - FD_ZERO (&fdset); - - no_sockets = 0; -#ifdef HAVE_IFADDRS_H - { - struct ifaddrs *interfaces = NULL; - struct ifaddrs *interface; - getifaddrs (&interfaces); - - /* create a socket for each suitable interface */ - - interface = interfaces; - while ((no_sockets < BJNP_SOCK_MAX) && (interface != NULL)) - { - if ( ! (interface -> ifa_flags & IFF_POINTOPOINT) && - ( (socket_fd[no_sockets] = - prepare_socket( interface -> ifa_name, - (bjnp_sockaddr_t *) interface -> ifa_addr, - (bjnp_sockaddr_t *) interface -> ifa_broadaddr, - &broadcast_addr[no_sockets] ) ) != -1 ) ) - { - /* track highest used socket for later use in select */ - if (socket_fd[no_sockets] > last_socketfd) - { - last_socketfd = socket_fd[no_sockets]; - } - FD_SET (socket_fd[no_sockets], &fdset); - no_sockets++; - } - interface = interface->ifa_next; - } - freeifaddrs (interfaces); - } -#else - /* we have no easy way to find interfaces with their broadcast addresses. */ - /* use global broadcast and all-hosts instead */ - { - bjnp_sockaddr_t local; - bjnp_sockaddr_t bc_addr; - - memset( &local, 0, sizeof( local) ); - local.ipv4.sin_family = AF_INET; - local.ipv4.sin_addr.s_addr = htonl (INADDR_ANY); - - bc_addr.ipv4.sin_family = AF_INET; - bc_addr.ipv4.sin_port = htons(0); - bc_addr.ipv4.sin_addr.s_addr = htonl (INADDR_BROADCAST); - - socket_fd[no_sockets] = prepare_socket( "any_interface", - &local, - &bc_addr, - &broadcast_addr[no_sockets] ); - if (socket_fd[no_sockets] >= 0) - { - FD_SET (socket_fd[no_sockets], &fdset); - if (socket_fd[no_sockets] > last_socketfd) - { - last_socketfd = socket_fd[no_sockets]; - } - no_sockets++; - } -#ifdef ENABLE_IPV6 - local.ipv6.sin6_family = AF_INET6; - local.ipv6.sin6_addr = in6addr_any; - - socket_fd[no_sockets] = prepare_socket( "any_interface", - &local, - NULL, - &broadcast_addr[no_sockets] ); - if (socket_fd[no_sockets] >= 0) - { - FD_SET (socket_fd[no_sockets], &fdset); - if (socket_fd[no_sockets] > last_socketfd) - { - last_socketfd = socket_fd[no_sockets]; - } - no_sockets++; - } -#endif - } -#endif - - /* send BJNP_MAX_BROADCAST_ATTEMPTS broadcasts on each prepared socket */ - for (attempt = 0; attempt < BJNP_MAX_BROADCAST_ATTEMPTS; attempt++) - { - for ( i=0; i < no_sockets; i++) - { - j = 0; - while(bjnp_protocol_defs[j].protocol_version != PROTOCOL_NONE) - { - set_cmd_from_string (bjnp_protocol_defs[j].proto_string, &cmd, CMD_UDP_DISCOVER, 0); - bjnp_send_broadcast ( socket_fd[i], &broadcast_addr[i], - bjnp_protocol_defs[j].default_port, cmd, sizeof (cmd)); - j++; - } - } - /* wait for some time between broadcast packets */ - usleep (BJNP_BROADCAST_INTERVAL * BJNP_USLEEP_MS); - } - - /* wait for a UDP response */ - - timeout.tv_sec = 0; - timeout.tv_usec = BJNP_BC_RESPONSE_TIMEOUT * BJNP_USLEEP_MS; - - - active_fdset = fdset; - - while (select (last_socketfd + 1, &active_fdset, NULL, NULL, &timeout) > 0) - { - PDBG (bjnp_dbg (LOG_DEBUG, "sanei_bjnp_find_devices: Select returned, time left %d.%d....\n", - (int) timeout.tv_sec, (int) timeout.tv_usec)); - for (i = 0; i < no_sockets; i++) - { - if (FD_ISSET (socket_fd[i], &active_fdset)) - { - socklen = sizeof(scanner_sa); - if ((numbytes = - recvfrom (socket_fd[i], resp_buf, sizeof (resp_buf), 0, - &(scanner_sa.addr), &socklen ) ) == -1) - { - PDBG (bjnp_dbg - (LOG_INFO, "sanei_find_devices: no data received")); - break; - } - else - { - PDBG (bjnp_dbg (LOG_DEBUG2, "sanei_find_devices: Discover response:\n")); - PDBG (bjnp_hexdump (LOG_DEBUG2, &resp_buf, numbytes)); - - /* check if something sensible is returned */ - protocol_defs = get_protocol_by_proto_string(disc_resp-> response.BJNP_id); - if ( (numbytes < (int)sizeof (struct BJNP_command)) || - (protocol_defs == NULL)) - { - /* not a valid response, assume not a scanner */ - - char bjnp_id[5]; - strncpy(bjnp_id, disc_resp-> response.BJNP_id, 4); - bjnp_id[4] = '\0'; - PDBG (bjnp_dbg (LOG_INFO, - "sanei_find_devices: Invalid discover response! Length = %d, Id = %s\n", - numbytes, bjnp_id ) ); - break; - } - if ( !(disc_resp -> response.dev_type & 0x80) ) - { - /* not a response, a command from somebody else or */ - /* a discover command that we generated */ - break; - } - }; - - port = get_port_from_sa(scanner_sa); - /* scanner found, get IP-address or hostname */ - get_scanner_name( &scanner_sa, scanner_host); - - /* construct URI */ - sprintf (uri, "%s://%s:%d/timeout=%d", protocol_defs->method_string, scanner_host, - port, timeout_default); - - add_scanner( &dev_no, uri, attach_bjnp, pixma_devices); - - } - } - active_fdset = fdset; - timeout.tv_sec = 0; - timeout.tv_usec = BJNP_BC_RESPONSE_TIMEOUT * BJNP_USLEEP_MS; - } - PDBG (bjnp_dbg (LOG_DEBUG, "sanei_find_devices: scanner discovery finished...\n")); - - for (i = 0; i < no_sockets; i++) - close (socket_fd[i]); - - return SANE_STATUS_GOOD; -} - -/** Open a BJNP device. - * - * The device is opened by its name devname and the device number is - * returned in dn on success. - * - * Device names consist of an URI - * Where: - * type = bjnp - * hostname = resolvable name or IP-address - * port = 8612 for a scanner - * An example could look like this: bjnp://host.domain:8612 - * - * @param devname name of the device to open - * @param dn device number - * - * @return - * - SANE_STATUS_GOOD - on success - * - SANE_STATUS_ACCESS_DENIED - if the file couldn't be accessed due to - * permissions - * - SANE_STATUS_INVAL - on every other error - */ - -extern SANE_Status -sanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn) -{ - int result; - - PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_open(%s, %d):\n", devname, *dn)); - - result = bjnp_allocate_device (devname, dn, NULL); - if ( (result != BJNP_STATUS_GOOD) && (result != BJNP_STATUS_ALREADY_ALLOCATED ) ) { - return SANE_STATUS_INVAL; - } - return SANE_STATUS_GOOD; -} - -/** Close a BJNP device. - * - * @param dn device number - */ - -void -sanei_bjnp_close (SANE_Int dn) -{ - PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_close(%d):\n", dn)); - - device[dn].open = 0; - sanei_bjnp_deactivate(dn); -} - -/** Activate BJNP device connection - * - * @param dn device number - */ - -SANE_Status -sanei_bjnp_activate (SANE_Int dn) -{ - char hostname[256]; - char pid_str[64]; - - PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_activate (%d)\n", dn)); - gethostname (hostname, 256); - hostname[255] = '\0'; - sprintf (pid_str, "Process ID = %d", getpid ()); - - bjnp_send_job_details (dn, hostname, getusername (), pid_str); - - if (bjnp_open_tcp (dn) != 0) - { - return SANE_STATUS_INVAL; - } - - return SANE_STATUS_GOOD; -} - -/** Deactivate BJNP device connection - * - * @paran dn device number - */ - -SANE_Status -sanei_bjnp_deactivate (SANE_Int dn) -{ - PDBG (bjnp_dbg (LOG_INFO, "sanei_bjnp_deactivate (%d)\n", dn)); - if ( device[dn].tcp_socket != -1) - { - bjnp_finish_job (dn); - close (device[dn].tcp_socket); - device[dn].tcp_socket = -1; - } - return SANE_STATUS_GOOD; -} - -/** Set the timeout for interrupt reads. - * we do not use it for bulk reads! - * @param timeout the new timeout in ms - */ -extern void -sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout) -{ - if (timeout < device[devno].bjnp_min_timeout) - { - PDBG (bjnp_dbg (LOG_INFO, "bjnp_set_timeout to %d, but using minimum value %d\n", - timeout, device[devno].bjnp_min_timeout)); - timeout = device[devno].bjnp_min_timeout; - } else { - PDBG (bjnp_dbg (LOG_INFO, "bjnp_set_timeout to %d\n", - timeout)); - } - - device[devno].bjnp_timeout = timeout; -} - -/** Initiate a bulk transfer read. - * - * Read up to size bytes from the device to buffer. After the read, size - * contains the number of bytes actually read. - * - * @param dn device number - * @param buffer buffer to store read data in - * @param size size of the data - * - * @return - * - SANE_STATUS_GOOD - on succes - * - SANE_STATUS_EOF - if zero bytes have been read - * - SANE_STATUS_IO_ERROR - if an error occured during the read - * - SANE_STATUS_INVAL - on every other error - * - */ - -extern SANE_Status -sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size) -{ - SANE_Status result; - SANE_Status error; - size_t recvd; - size_t read_size; - size_t read_size_max; - size_t requested; - - PDBG (bjnp_dbg - (LOG_INFO, "bjnp_read_bulk(dn=%d, bufferptr=%lx, 0x%lx = %ld)\n", dn, - (long) buffer, (unsigned long) *size, (unsigned long) *size)); - - recvd = 0; - requested = *size; - - PDBG (bjnp_dbg - (LOG_DEBUG, "bjnp_read_bulk: 0x%lx = %ld bytes available at start\n", - (unsigned long) device[dn].scanner_data_left, - (unsigned long) device[dn].scanner_data_left ) ); - - while ( (recvd < requested) && !( device[dn].last_block && (device[dn].scanner_data_left == 0)) ) - { - PDBG (bjnp_dbg - (LOG_DEBUG, - "bjnp_read_bulk: Already received 0x%lx = %ld bytes, backend requested 0x%lx = %ld bytes\n", - (unsigned long) recvd, (unsigned long) recvd, - (unsigned long) requested, (unsigned long)requested )); - - /* Check first if there is data in flight from the scanner */ - - if (device[dn].scanner_data_left == 0) - { - /* There is no data in flight from the scanner, send new read request */ - - PDBG (bjnp_dbg (LOG_DEBUG, - "bjnp_read_bulk: No (more) scanner data available, requesting more( blocksize = %ld = %lx\n", - (long int) device[dn].blocksize, (long int) device[dn].blocksize )); - - if ((error = bjnp_send_read_request (dn)) != SANE_STATUS_GOOD) - { - *size = recvd; - return SANE_STATUS_IO_ERROR; - } - if ( ( error = bjnp_recv_header (dn, &(device[dn].scanner_data_left) ) ) != SANE_STATUS_GOOD) - { - *size = recvd; - return SANE_STATUS_IO_ERROR; - } - /* correct blocksize if applicable */ - - device[dn].blocksize = MAX (device[dn].blocksize, device[dn].scanner_data_left); - - if ( device[dn].scanner_data_left < device[dn].blocksize) - { - /* the scanner will not react at all to a read request, when no more data is available */ - /* we now determine end of data by comparing the payload size to the maximun blocksize */ - /* this block is shorter than blocksize, so after this block we are done */ - - device[dn].last_block = 1; - } - } - - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: In flight: 0x%lx = %ld bytes available\n", - (unsigned long) device[dn].scanner_data_left, - (unsigned long) device[dn].scanner_data_left)); - - /* read as many bytes as needed and available */ - - read_size_max = MIN( device[dn].scanner_data_left, (requested - recvd) ); - read_size = read_size_max; - - PDBG (bjnp_dbg - (LOG_DEBUG, - "bjnp_read_bulk: Try to read 0x%lx = %ld (of max 0x%lx = %ld) bytes\n", - (unsigned long) read_size_max, - (unsigned long) read_size_max, - (unsigned long) device[dn].scanner_data_left, - (unsigned long) device[dn].scanner_data_left) ); - - result = bjnp_recv_data (dn, buffer , recvd, &read_size); - if (result != SANE_STATUS_GOOD) - { - *size = recvd; - return SANE_STATUS_IO_ERROR; - } - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: Expected at most %ld bytes, received this time: %ld\n", - read_size_max, read_size) ); - - device[dn].scanner_data_left = device[dn].scanner_data_left - read_size; - recvd = recvd + read_size; - } - - PDBG (bjnp_dbg (LOG_DEBUG, "bjnp_read_bulk: %s: Returning %ld bytes, backend expexts %ld\n", - (recvd == *size)? "OK": "NOTICE",recvd, *size ) ); - *size = recvd; - if ( *size == 0 ) - return SANE_STATUS_EOF; - return SANE_STATUS_GOOD; -} - -/** Initiate a bulk transfer write. - * - * Write up to size bytes from buffer to the device. After the write size - * contains the number of bytes actually written. - * - * @param dn device number - * @param buffer buffer to write to device - * @param size size of the data - * - * @return - * - SANE_STATUS_GOOD - on succes - * - SANE_STATUS_IO_ERROR - if an error occured during the write - * - SANE_STATUS_INVAL - on every other error - */ - -extern SANE_Status -sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size) -{ - ssize_t sent; - size_t recvd; - uint32_t buf; - size_t payload_size; - - /* Write received data to scanner */ - - sent = bjnp_write (dn, buffer, *size); - if (sent < 0) - return SANE_STATUS_IO_ERROR; - if (sent != (int) *size) - { - PDBG (bjnp_dbg - (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Sent only %ld bytes to scanner, expected %ld!!\n", - (unsigned long) sent, (unsigned long) *size)); - return SANE_STATUS_IO_ERROR; - } - - if (bjnp_recv_header (dn, &payload_size) != SANE_STATUS_GOOD) - { - PDBG (bjnp_dbg (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Could not read response to command!\n")); - return SANE_STATUS_IO_ERROR; - } - - if (payload_size != 4) - { - PDBG (bjnp_dbg (LOG_CRIT, - "sanei_bjnp_write_bulk: ERROR - Scanner length of write confirmation = 0x%lx bytes = %ld, expected %d!!\n", - (unsigned long) payload_size, - (unsigned long) payload_size, 4)); - return SANE_STATUS_IO_ERROR; - } - recvd = payload_size; - if ((bjnp_recv_data (dn, (unsigned char *) &buf, 0, &recvd) != - SANE_STATUS_GOOD) || (recvd != payload_size)) - { - PDBG (bjnp_dbg (LOG_CRIT, - "sanei_bjnp_write_bulk: ERROR - Could not read length of data confirmed by device\n")); - return SANE_STATUS_IO_ERROR; - } - recvd = ntohl (buf); - if (recvd != *size) - { - PDBG (bjnp_dbg - (LOG_CRIT, "sanei_bjnp_write_bulk: ERROR - Scanner confirmed %ld bytes, expected %ld!!\n", - (unsigned long) recvd, (unsigned long) *size)); - return SANE_STATUS_IO_ERROR; - } - /* we can expect data from the scanner */ - - device[dn].last_block = 0; - - return SANE_STATUS_GOOD; -} - -/** Initiate a interrupt transfer read. - * - * Read up to size bytes from the interrupt endpoint from the device to - * buffer. After the read, size contains the number of bytes actually read. - * - * @param dn device number - * @param buffer buffer to store read data in - * @param size size of the data - * - * @return - * - SANE_STATUS_GOOD - on succes - * - SANE_STATUS_EOF - if zero bytes have been read - * - SANE_STATUS_IO_ERROR - if an error occured during the read - * - SANE_STATUS_INVAL - on every other error - * - */ - -extern SANE_Status -sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size) -{ -#ifndef PIXMA_BJNP_USE_STATUS - PDBG (bjnp_dbg - (LOG_INFO, "bjnp_read_int(%d, bufferptr, 0x%lx = %ld):\n", dn, - (unsigned long) *size, (unsigned long) *size)); - - memset (buffer, 0, *size); - sleep (1); - return SANE_STATUS_IO_ERROR; -#else - - char hostname[256]; - int resp_len; - int timeout; - int seconds; - - PDBG (bjnp_dbg - (LOG_INFO, "bjnp_read_int(%d, bufferptr, 0x%lx = %ld):\n", dn, - (unsigned long) *size, (unsigned long) *size)); - - memset (buffer, 0, *size); - - gethostname (hostname, 32); - hostname[32] = '\0'; - - - switch (device[dn].polling_status) - { - case BJNP_POLL_STOPPED: - - /* establish dialog */ - - if ( (bjnp_poll_scanner (dn, 0, hostname, getusername (), buffer, *size ) != 0) || - (bjnp_poll_scanner (dn, 1, hostname, getusername (), buffer, *size ) != 0) ) - { - PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: WARNING - Failed to setup read_intr dialog with device!\n")); - device[dn].dialog = 0; - device[dn].status_key = 0; - return SANE_STATUS_IO_ERROR; - } - device[dn].polling_status = BJNP_POLL_STARTED; - - /* fall through to BJNP_POLL_STARTED */ - - case BJNP_POLL_STARTED: - /* we use only seonds accuracy between poll attempts */ - timeout = device[dn].bjnp_timeout /1000; - - do - { - if ( (resp_len = bjnp_poll_scanner (dn, 2, hostname, getusername (), buffer, *size ) ) < 0 ) - { - PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: Restarting polling dialog!\n")); - device[dn].polling_status = BJNP_POLL_STOPPED; - *size = 0; - return SANE_STATUS_EOF; - } - *size = (size_t) resp_len; - if ( resp_len > 0 ) - { - device[dn].polling_status = BJNP_POLL_STATUS_RECEIVED; - return SANE_STATUS_GOOD; - } - seconds = timeout > 2 ? 2 : timeout; - sleep(seconds); - timeout = timeout - seconds; - } while ( timeout > 0 ) ; - break; - case BJNP_POLL_STATUS_RECEIVED: - if ( (resp_len = bjnp_poll_scanner (dn, 5, hostname, getusername (), buffer, *size ) ) < 0 ) - { - PDBG (bjnp_dbg (LOG_NOTICE, "bjnp_read_int: Restarting polling dialog!\n")); - device[dn].polling_status = BJNP_POLL_STOPPED; - *size = 0; - break; - } - } - return SANE_STATUS_EOF; -#endif -} diff --git a/backend/pixma_bjnp.h b/backend/pixma_bjnp.h deleted file mode 100644 index a27082c..0000000 --- a/backend/pixma_bjnp.h +++ /dev/null @@ -1,203 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2008 by Louis Lagendijk - based on sane_usb.h: - Copyright (C) 2003, 2005 Rene Rebe (sanei_read_int,sanei_set_timeout) - Copyright (C) 2001, 2002 Henning Meier-Geinitz - - This file is part of the SANE package. - - SANE 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. - - SANE 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 sane; see the file COPYING. If not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. -*/ -/** @file sanei_bjnp.h - * This file provides a generic BJNP interface. - */ - -#ifndef sanei_bjnp_h -#define sanei_bjnp_h - -#include "../include/sane/config.h" -#include "../include/sane/sane.h" -#include "pixma.h" - -#ifdef HAVE_STDLIB_H -#include /* for size_t */ -#endif - -/** Initialize sanei_bjnp. - * - * Call this before any other sanei_bjnp function. - */ -extern void sanei_bjnp_init (void); - -/** Find scanners responding to a BJNP broadcast. - * - * The function sanei_bjnp_attach is called for every device which has - * been found. - * Serial is the address of the scanner in human readable form of max - * SERIAL_MAX characters - * @param conf_devices list of pre-configures device URI's to attach - * @param attach attach function - * @param pixma_devices device informatio needed by attach function - * - * @return SANE_STATUS_GOOD - on success (even if no scanner was found) - */ - -#define SERIAL_MAX 16 - -extern SANE_Status -sanei_bjnp_find_devices (const char **conf_devices, - SANE_Status (*attach_bjnp) - (SANE_String_Const devname, - SANE_String_Const makemodel, - SANE_String_Const serial, - const struct pixma_config_t * - const pixma_devices[]), - const struct pixma_config_t *const pixma_devices[]); - -/** Open a BJNP device. - * - * The device is opened by its name devname and the device number is - * returned in dn on success. - * - * Device names consist of an URI - * Where: - * method = bjnp - * hostname = resolvable name or IP-address - * port = 8612 for a bjnp scanner, 8610 for a mfnp device - * An example could look like this: bjnp://host.domain:8612 - * - * @param devname name of the device to open - * @param dn device number - * - * @return - * - SANE_STATUS_GOOD - on success - * - SANE_STATUS_ACCESS_DENIED - if the file couldn't be accessed due to - * permissions - * - SANE_STATUS_INVAL - on every other error - */ -extern SANE_Status sanei_bjnp_open (SANE_String_Const devname, SANE_Int * dn); - -/** Close a BJNP device. - * - * @param dn device number - */ - -extern void sanei_bjnp_close (SANE_Int dn); - -/** Activate a BJNP device connection - * - * @param dn device number - */ - -extern SANE_Status sanei_bjnp_activate (SANE_Int dn); - -/** De-activate a BJNP device connection - * - * @param dn device number - */ - -extern SANE_Status sanei_bjnp_deactivate (SANE_Int dn); - -/** Set the libbjnp timeout for bulk and interrupt reads. - * - * @param devno device number - * @param timeout the new timeout in ms - */ -extern void sanei_bjnp_set_timeout (SANE_Int devno, SANE_Int timeout); - -/** Check if sanei_bjnp_set_timeout() is available. - */ -#define HAVE_SANEI_BJNP_SET_TIMEOUT - -/** Initiate a bulk transfer read. - * - * Read up to size bytes from the device to buffer. After the read, size - * contains the number of bytes actually read. - * - * @param dn device number - * @param buffer buffer to store read data in - * @param size size of the data - * - * @return - * - SANE_STATUS_GOOD - on succes - * - SANE_STATUS_EOF - if zero bytes have been read - * - SANE_STATUS_IO_ERROR - if an error occured during the read - * - SANE_STATUS_INVAL - on every other error - * - */ -extern SANE_Status -sanei_bjnp_read_bulk (SANE_Int dn, SANE_Byte * buffer, size_t * size); - -/** Initiate a bulk transfer write. - * - * Write up to size bytes from buffer to the device. After the write size - * contains the number of bytes actually written. - * - * @param dn device number - * @param buffer buffer to write to device - * @param size size of the data - * - * @return - * - SANE_STATUS_GOOD - on succes - * - SANE_STATUS_IO_ERROR - if an error occured during the write - * - SANE_STATUS_INVAL - on every other error - */ -extern SANE_Status -sanei_bjnp_write_bulk (SANE_Int dn, const SANE_Byte * buffer, size_t * size); - -/** Initiate a interrupt transfer read. - * - * Read up to size bytes from the interrupt endpoint from the device to - * buffer. After the read, size contains the number of bytes actually read. - * - * @param dn device number - * @param buffer buffer to store read data in - * @param size size of the data - * - * @return - * - SANE_STATUS_GOOD - on succes - * - SANE_STATUS_EOF - if zero bytes have been read - * - SANE_STATUS_IO_ERROR - if an error occured during the read - * - SANE_STATUS_INVAL - on every other error - * - */ - -extern SANE_Status -sanei_bjnp_read_int (SANE_Int dn, SANE_Byte * buffer, size_t * size); - -/*------------------------------------------------------*/ -#endif /* sanei_bjnp_h */ diff --git a/backend/pixma_bjnp_private.h b/backend/pixma_bjnp_private.h deleted file mode 100644 index 84f5c3f..0000000 --- a/backend/pixma_bjnp_private.h +++ /dev/null @@ -1,382 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2008 by Louis Lagendijk - - This file is part of the SANE package. - - Data structures and definitions for - bjnp backend for the Common UNIX Printing System (CUPS). - - These coded instructions, statements, and computer programs are the - property of Louis Lagendijk and are protected by Federal copyright - law. Distribution and use rights are outlined in the file "LICENSE.txt" - "LICENSE" which should have been included with this file. If this - file is missing or damaged, see the license at "http://www.cups.org/". - - This file is subject to the Apple OS-Developed Software exception. - - SANE 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. - - SANE 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 sane; see the file COPYING. If not, write to the Free - Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, 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. -*/ - -/* - * BJNP definitions - */ - -/* selection of options */ -/* This works now, disable when it gives you problems */ -#define PIXMA_BJNP_USE_STATUS 1 - -/* sizes */ - -#define BJNP_PRINTBUF_MAX 1400 /* size of printbuffer */ -#define BJNP_CMD_MAX 2048 /* size of BJNP response buffer */ -#define BJNP_RESP_MAX 2048 /* size of BJNP response buffer */ -#define BJNP_SOCK_MAX 256 /* maximum number of open sockets */ -#define BJNP_MODEL_MAX 64 /* max allowed size for make&model */ -#define BJNP_STATUS_MAX 256 /* max size for status string */ -#define BJNP_IEEE1284_MAX 1024 /* max. allowed size of IEEE1284 id */ -#define BJNP_METHOD_MAX 16 /* max length of method */ -#define BJNP_HOST_MAX 128 /* max length of hostname or address */ -#define BJNP_PORT_MAX 64 /* max length of port string */ -#define BJNP_ARGS_MAX 128 /* max length of argument string */ -#define BJNP_SERIAL_MAX 16 /* maximum length of serial number */ -#define BJNP_NO_DEVICES 16 /* max number of open devices */ -#define BJNP_SCAN_BUF_MAX 65536 /* size of scanner data intermediate buffer */ -#define BJNP_BLOCKSIZE_START 512 /* startsize for last block detection */ - -/* timers */ -#define BJNP_BROADCAST_INTERVAL 10 /* ms between broadcasts */ -#define BJNP_BC_RESPONSE_TIMEOUT 500 /* waiting time for broadc. responses */ -#define BJNP_TIMEOUT_DEFAULT 10000 /* minimum tiemout value for network operations */ -#define BJNP_USLEEP_MS 1000 /* sleep for 1 msec */ - -/* retries */ -#define BJNP_MAX_SELECT_ATTEMPTS 3 /* max nr of retries on select (EINTR) */ -#define BJNP_MAX_BROADCAST_ATTEMPTS 2 /* number of broadcast packets to be sent */ -#define BJNP_UDP_RETRY_MAX 3 /* max nt of retries on a udp command */ - -#define bjnp_dbg DBG -#include "../include/sane/sanei_debug.h" - -/* loglevel definitions */ - -#define LOG_CRIT 0 -#define LOG_NOTICE 1 -#define LOG_INFO 2 -#define LOG_DEBUG 3 -#define LOG_DEBUG2 4 -#define LOG_DEBUG3 5 - -#define BJNP_RESTART_POLL -1 - -/*************************************/ -/* BJNP protocol related definitions */ -/*************************************/ - -/* port numbers */ -typedef enum bjnp_port_e -{ - MFNP_PORT_SCAN = 8610, - BJNP_PORT_PRINT = 8611, - BJNP_PORT_SCAN = 8612, - BJNP_PORT_3 = 8613, - BJNP_PORT_4 = 8614 -} bjnp_port_t; - -typedef enum -{ - PROTOCOL_BJNP = 0, - PROTOCOL_MFNP = 1, - PROTOCOL_NONE =2 -} bjnp_protocol_t; - -typedef struct -{ - bjnp_protocol_t protocol_version; - int default_port; - char * proto_string; - char * method_string; -} bjnp_protocol_defs_t; - -bjnp_protocol_defs_t bjnp_protocol_defs[] = -{ - {PROTOCOL_BJNP, BJNP_PORT_SCAN,"BJNP", "bjnp"}, - {PROTOCOL_MFNP, MFNP_PORT_SCAN,"MFNP", "mfnp"}, - {PROTOCOL_NONE, -1, NULL, NULL} -}; - -/* commands */ -typedef enum bjnp_cmd_e -{ - CMD_UDP_DISCOVER = 0x01, /* discover if service type is listening at this port */ - CMD_UDP_START_SCAN = 0x02, /* start scan pressed, sent from scanner to 224.0.0.1 */ - CMD_UDP_JOB_DETAILS = 0x10, /* send print/ scanner job owner details */ - CMD_UDP_CLOSE = 0x11, /* request connection closure */ - CMD_UDP_GET_STATUS = 0x20, /* get printer status */ - CMD_TCP_REQ = 0x20, /* read data from device */ - CMD_TCP_SEND = 0x21, /* send data to device */ - CMD_UDP_GET_ID = 0x30, /* get printer identity */ - CMD_UDP_POLL = 0x32 /* poll scanner for button status */ -} bjnp_cmd_t; - -/* command type */ - -typedef enum uint8_t -{ - BJNP_CMD_PRINT = 0x1, /* printer command */ - BJNP_CMD_SCAN = 0x2, /* scanner command */ - BJNP_RES_PRINT = 0x81, /* printer response */ - BJNP_RES_SCAN = 0x82 /* scanner response */ -} bjnp_cmd_type_t; - -/***************************/ -/* BJNP protocol structure */ -/***************************/ - -/* The common protocol header */ - -struct __attribute__ ((__packed__)) BJNP_command -{ - char BJNP_id[4]; /* string: BJNP */ - uint8_t dev_type; /* 1 = printer, 2 = scanner */ - /* responses have MSB set */ - uint8_t cmd_code; /* command code/response code */ - int16_t unknown1; /* unknown, always 0? */ - int16_t seq_no; /* sequence number */ - uint16_t session_id; /* session id for printing */ - uint32_t payload_len; /* length of command buffer */ -}; - -/* Layout of the init response buffer */ - -struct __attribute__ ((__packed__)) DISCOVER_RESPONSE -{ - struct BJNP_command response; /* reponse header */ - char unknown1[4]; /* 00 01 08 00 */ - char mac_len; /* length of mac address */ - char addr_len; /* length of address field */ - unsigned char mac_addr[6]; /* printers mac address */ - union { - struct __attribute__ ((__packed__)) { - unsigned char ipv4_addr[4]; - } ipv4; - struct __attribute__ ((__packed__)) { - unsigned char ipv6_addr_1[16]; - unsigned char ipv6_addr_2[16]; - } ipv6; - } addresses; -}; - -/* layout of payload for the JOB_DETAILS command */ - -struct __attribute__ ((__packed__)) JOB_DETAILS -{ - struct BJNP_command cmd; /* command header */ - char unknown[8]; /* don't know what these are for */ - char hostname[64]; /* hostname of sender */ - char username[64]; /* username */ - char jobtitle[256]; /* job title */ -}; - -/* layout of the poll command, not everything is complete */ - -struct __attribute__ ((__packed__)) POLL_DETAILS -{ - struct BJNP_command cmd; /* command header */ - uint16_t type; /* 0, 1, 2 or 5 */ - /* 05 = reset status */ - union { - struct __attribute__ ((__packed__)) { - char empty0[78]; /* type 0 has only 0 */ - } type0; /* length = 80 */ - - struct __attribute__ ((__packed__)) { - char empty1[6]; /* 0 */ - char user_host[64]; /* unicode user hostname */ - uint64_t emtpy2; /* 0 */ - } type1; /* length = 80 */ - - struct __attribute__ ((__packed__)) { - uint16_t empty_1; /* 00 00 */ - uint32_t dialog; /* constant dialog id, from previous response */ - char user_host[64]; /* unicode user hostname */ - uint32_t unknown_1; /* 00 00 00 14 */ - uint32_t empty_2[5]; /* only 0 */ - uint32_t unknown_2; /* 00 00 00 10 */ - char ascii_date[16]; /* YYYYMMDDHHMMSS only for type 2 */ - } type2; /* length = 116 */ - - struct __attribute__ ((__packed__)) { - uint16_t empty_1; /* 00 00 */ - uint32_t dialog; /* constant dialog id, from previous response */ - char user_host[64]; /* unicode user hostname */ - uint32_t unknown_1; /* 00 00 00 14 */ - uint32_t key; /* copied from key field in status msg */ - uint32_t unknown_3[5]; /* only 0 */ - } type5; /* length = 100 */ - - } extensions; -}; - -/* the poll response layout */ - -struct __attribute__ ((__packed__)) POLL_RESPONSE -{ - struct BJNP_command cmd; /* command header */ - - unsigned char result[4]; /* unknown stuff, result[2] = 80 -> status is available*/ - /* result[8] is dialog, size? */ - uint32_t dialog; /* to be returned in next request */ - uint32_t unknown_2; /* returns the 00 00 00 14 from unknown_2 in request */ - uint32_t key; /* to be returned in type 5 status reset */ - unsigned char status[20]; /* interrupt status */ -}; - -/* Layout of ID and status responses */ - -struct __attribute__ ((__packed__)) IDENTITY -{ - struct BJNP_command cmd; - union __attribute__ ((__packed__)) - { - struct __attribute__ ((__packed__)) payload_s - { - uint16_t id_len; /* length of identity */ - char id[BJNP_IEEE1284_MAX]; /* identity */ - } bjnp; - struct __attribute__ ((__packed__)) mfnp - { - char id[BJNP_IEEE1284_MAX]; - } mfnp; - } payload; -}; - - -/* response to TCP print command */ - -struct __attribute__ ((__packed__)) SCAN_BUF -{ - struct BJNP_command cmd; - char scan_data[65536]; -}; - -/**************************/ -/* Local enum definitions */ -/**************************/ - -typedef enum bjnp_paper_status_e -{ - BJNP_PAPER_UNKNOWN = -1, - BJNP_PAPER_OK = 0, - BJNP_PAPER_OUT = 1 -} bjnp_paper_status_t; - -typedef enum -{ - BJNP_STATUS_GOOD, - BJNP_STATUS_INVAL, - BJNP_STATUS_ALREADY_ALLOCATED -} BJNP_Status; - -/* button polling */ - -typedef enum -{ - BJNP_POLL_STOPPED = 0, - BJNP_POLL_STARTED = 1, - BJNP_POLL_STATUS_RECEIVED = 2 -} BJNP_polling_status_e; - -typedef union -{ - struct sockaddr_storage storage; - struct sockaddr addr; - struct sockaddr_in ipv4; - struct sockaddr_in6 ipv6; -} bjnp_sockaddr_t; - -typedef enum -{ - BJNP_ADDRESS_IS_LINK_LOCAL = 0, - BJNP_ADDRESS_IS_GLOBAL = 1, - BJNP_ADDRESS_HAS_FQDN = 2 -} bjnp_address_type_t; - - -/* - * Device information for opened devices - */ - -typedef struct device_s -{ - int open; /* connection to scanner is opened */ - - /* protocol version */ - int protocol; - char *protocol_string; - - /* sockets */ - - int tcp_socket; /* open tcp socket for communcation to scannner */ - int16_t serial; /* sequence number of command */ - - /* communication state */ - - int session_id; /* session id used in bjnp protocol for TCP packets */ - int last_cmd; /* last command sent */ - - /* TCP bulk read state information */ - - size_t blocksize; /* size of (TCP) blocks returned by the scanner */ - size_t scanner_data_left; /* TCP data left from last read request */ - char last_block; /* last TCP read command was shorter than blocksize */ - - /* device information */ - char mac_address[BJNP_HOST_MAX]; - /* mac-address, used as device serial no */ - bjnp_sockaddr_t * addr; /* ip-address of the scanner */ - int address_level; /* link local, public or has a FQDN */ - int bjnp_timeout; /* timeout (msec) for next poll command */ - int bjnp_min_timeout; /* device specific min timeout */ - -#ifdef PIXMA_BJNP_USE_STATUS - /* polling state information */ - - char polling_status; /* status polling ongoing */ - uint32_t dialog; /* poll dialog */ - uint32_t status_key; /* key of last received status message */ -#endif -} bjnp_device_t; 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 - 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 -#include -#include /* pow(C90) */ - -#include /* gettimeofday(4.3BSD) */ -#include /* 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(jout_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); -} diff --git a/backend/pixma_common.h b/backend/pixma_common.h deleted file mode 100644 index c0ed4ba..0000000 --- a/backend/pixma_common.h +++ /dev/null @@ -1,232 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2011-2019 Rolf Bensch - 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. - */ -#ifndef PIXMA_COMMON_H -#define PIXMA_COMMON_H - - -#include /* time_t */ -#include "pixma.h" - - -/*! \defgroup subdriver Subdriver Interface - * \brief Subdriver interface. */ - -/*! \defgroup debug Debug utilities - * \brief Debug utilities. */ - -#ifdef NDEBUG -# define PDBG(x) do {} while(0) -# define PASSERT(x) do {} while(0) -#else -# define PDBG(x) x -# define PASSERT(x) do { \ - if (!(x)) \ - pixma_dbg(1, "ASSERT failed:%s:%d: " \ - #x "\n", __FILE__, __LINE__); \ - } while(0) -#endif - - -#define PIXMA_STATUS_OK 0x0606 -#define PIXMA_STATUS_FAILED 0x1515 -#define PIXMA_STATUS_BUSY 0x1414 - -#define PIXMA_MAX_ID_LEN 30 - -/* These may have been defined elsewhere */ -#ifndef MIN -#define MIN(x,y) (((x) < (y)) ? (x):(y)) -#endif -#ifndef MAX -#define MAX(x,y) (((x) < (y)) ? (y):(x)) -#endif -#define ALIGN_SUP(x,n) (((x) + (n) - 1) / (n) * (n)) -#define ALIGN_INF(x,n) (((x) / (n)) * (n)) - -struct pixma_io_t; - -struct pixma_limits_t -{ - unsigned xdpi, ydpi; - unsigned width, height; -}; - -struct pixma_cmdbuf_t -{ - unsigned cmd_header_len, res_header_len, cmd_len_field_ofs; - unsigned expected_reslen, cmdlen; - int reslen; - unsigned size; - uint8_t *buf; -}; - -struct pixma_imagebuf_t -{ - uint8_t *wptr, *wend; - const uint8_t *rptr, *rend; -}; - -struct pixma_t -{ - pixma_t *next; - struct pixma_io_t *io; - const pixma_scan_ops_t *ops; - pixma_scan_param_t *param; - const pixma_config_t *cfg; - char id[PIXMA_MAX_ID_LEN + 1]; - int cancel; /* NOTE: It can be set in a signal handler. */ - uint32_t events; - void *subdriver; /* can be used by model driver. */ - int rec_tmo; /* receive timeout [s] */ - - /* private */ - uint64_t cur_image_size; - pixma_imagebuf_t imagebuf; - unsigned scanning:1; - unsigned underrun:1; -}; - -/** \addtogroup subdriver - * @{ */ -/** Scan operations for subdriver. */ -struct pixma_scan_ops_t -{ - /** Allocate a data structure for the subdriver. It is called after the - * core driver connected to the scanner. The subdriver should reset the - * scanner to a known state in this function. */ - int (*open) (pixma_t *); - - /** Free resources allocated by the subdriver. Don't forget to send abort - * command to the scanner if it is scanning. */ - void (*close) (pixma_t *); - - /** Setup the scanner for scan parameters defined in \a s->param. */ - int (*scan) (pixma_t * s); - - /** Fill a buffer with image data. The subdriver has two choices: - * -# Fill the buffer pointed by ib->wptr directly and leave - * ib->rptr and ib->rend untouched. The length of the buffer is - * ib->wend - ib->wptr. It must update ib->wptr accordingly. - * -# Update ib->rptr and ib->rend to point to the beginning and - * the end of the internal buffer resp. The length of the buffer - * is ib->rend - ib->rptr. This function is called again if - * and only if pixma_read_image() has copied the whole buffer. - * - * The subdriver must wait until there is at least one byte to read or - * return 0 for the end of image. */ - int (*fill_buffer) (pixma_t *, pixma_imagebuf_t * ib); - - /** Cancel the scan operation if necessary and free resources allocated in - * scan(). */ - void (*finish_scan) (pixma_t *); - - /** [Optional] Wait for a user's event, e.g. button event. \a timeout is - * in milliseconds. If an event occured before it's timed out, flags in - * \a s->events should be set accordingly. - * \see PIXMA_EV_* */ - void (*wait_event) (pixma_t * s, int timeout); - - /** Check the scan parameters. The parameters can be adjusted if they are - * out of range, e.g. width > max_width. */ - int (*check_param) (pixma_t *, pixma_scan_param_t *); - - /** Read the device status. \see pixma_get_device_status() */ - int (*get_status) (pixma_t *, pixma_device_status_t *); -}; - - -/** \name Funtions for read and write big-endian integer values */ -/**@{*/ -void pixma_set_be16 (uint16_t x, uint8_t * buf); -void pixma_set_be32 (uint32_t x, uint8_t * buf); -uint16_t pixma_get_be16 (const uint8_t * buf); -uint32_t pixma_get_be32 (const uint8_t * buf); -/**@}*/ - -/** \name Utility functions */ -/**@{*/ -uint8_t pixma_sum_bytes (const void *data, unsigned len); -int pixma_check_dpi (unsigned dpi, unsigned max); -void pixma_sleep (unsigned long usec); -void pixma_get_time (time_t * sec, uint32_t * usec); -uint8_t * pixma_r_to_ir (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c); -uint8_t * pixma_rgb_to_gray (uint8_t * gptr, uint8_t * sptr, unsigned w, unsigned c); -uint8_t * pixma_binarize_line(pixma_scan_param_t *, uint8_t * dst, uint8_t * src, unsigned width, unsigned c); -/**@}*/ - -/** \name Command related functions */ -/**@{*/ -int pixma_cmd_transaction (pixma_t *, const void *cmd, unsigned cmdlen, - void *data, unsigned expected_len); -int pixma_check_result (pixma_cmdbuf_t *); -uint8_t *pixma_newcmd (pixma_cmdbuf_t *, unsigned cmd, - unsigned dataout, unsigned datain); -int pixma_exec (pixma_t *, pixma_cmdbuf_t *); -int pixma_exec_short_cmd (pixma_t *, pixma_cmdbuf_t *, unsigned cmd); -int pixma_map_status_errno (unsigned status); -/**@}*/ - -#define pixma_fill_checksum(start, end) do { \ - *(end) = -pixma_sum_bytes(start, (end)-(start)); \ -} while(0) - -/** @} end of group subdriver */ - -/** \addtogroup debug - * @{ */ -void pixma_set_debug_level (int level); -#ifndef NDEBUG -void pixma_hexdump (int level, const void *d_, unsigned len); - -/* len: length of data or error code. - size: if >= 0, force to print 'size' bytes. - max: maximum number of bytes to print(-1 means no limit). */ -void pixma_dump (int level, const char *type, const void *data, int len, - int size, int max); -# define DEBUG_DECLARE_ONLY -# include "../include/sane/sanei_debug.h" -#endif /* NDEBUG */ -/** @} end of group debug */ - -#endif diff --git a/backend/pixma_imageclass.c b/backend/pixma_imageclass.c deleted file mode 100644 index 9301bc6..0000000 --- a/backend/pixma_imageclass.c +++ /dev/null @@ -1,979 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2011-2019 Rolf Bensch - Copyright (C) 2007-2009 Nicolas Martin, - Copyright (C) 2008 Dennis Lou, dlou 99 at yahoo dot com - - 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. - */ - -/* - * imageCLASS backend based on pixma_mp730.c - */ - -#include "../include/sane/config.h" - -#include -#include -#include - -#include "pixma_rename.h" -#include "pixma_common.h" -#include "pixma_io.h" - - -#ifdef __GNUC__ -# define UNUSED(v) (void) v -#else -# define UNUSED(v) -#endif - -#define IMAGE_BLOCK_SIZE (0x80000) -#define MAX_CHUNK_SIZE (0x1000) -#define MIN_CHUNK_SIZE (0x0200) -#define CMDBUF_SIZE 512 - -#define MF4100_PID 0x26a3 -#define MF4600_PID 0x26b0 -#define MF4010_PID 0x26b4 -#define MF4200_PID 0x26b5 -#define MF4360_PID 0x26ec -#define D480_PID 0x26ed -#define MF4320_PID 0x26ee -#define D420_PID 0x26ef -#define MF3200_PID 0x2684 -#define MF6500_PID 0x2686 -/* generation 2 scanners (>=0x2707) */ -#define MF8300_PID 0x2708 -#define MF4500_PID 0x2736 -#define MF4410_PID 0x2737 -#define D550_PID 0x2738 -#define MF3010_PID 0x2759 -#define MF4570_PID 0x275a -#define MF4800_PID 0x2773 -#define MF4700_PID 0x2774 -#define MF8200_PID 0x2779 -/* the following are all untested */ -#define MF5630_PID 0x264e -#define MF5650_PID 0x264f -#define MF8100_PID 0x2659 -#define MF5880_PID 0x26f9 -#define MF6680_PID 0x26fa -#define MF8030_PID 0x2707 -#define IR1133_PID 0x2742 -#define MF5900_PID 0x2743 -#define D530_PID 0x2775 -#define MF8500_PID 0x277a -#define MF6100_PID 0x278e -#define MF820_PID 0x27a6 -#define MF220_PID 0x27a8 -#define MF210_PID 0x27a9 -#define MF620_PID 0x27b4 -#define MF410_PID 0x27c0 -#define MF510_PID 0x27c2 -#define MF230_PID 0x27d1 -#define MF240_PID 0x27d2 -#define MF630_PID 0x27e1 -#define MF634_PID 0x27e2 -#define MF730_PID 0x27e4 -#define MF731_PID 0x27e5 -#define D570_PID 0x27e8 -#define MF110_PID 0x27ed -#define MF520_PID 0x27f0 -#define MF420_PID 0x27f1 -#define MF260_PID 0x27f4 -#define MF740_PID 0x27fb -#define MF640_PID 0x27fe - - -enum iclass_state_t -{ - state_idle, - state_warmup, /* MF4200 always warm/calibrated; others? */ - state_scanning, - state_finished -}; - -enum iclass_cmd_t -{ - cmd_start_session = 0xdb20, - cmd_select_source = 0xdd20, - cmd_scan_param = 0xde20, - cmd_status = 0xf320, - cmd_abort_session = 0xef20, - cmd_read_image = 0xd420, - cmd_read_image2 = 0xd460, /* New multifunctionals, such as MF4410 */ - cmd_error_info = 0xff20, - - cmd_activate = 0xcf60 -}; - -typedef struct iclass_t -{ - enum iclass_state_t state; - pixma_cmdbuf_t cb; - unsigned raw_width; - uint8_t current_status[12]; - - uint8_t *buf, *blkptr, *lineptr; - unsigned buf_len, blk_len; - - unsigned last_block; - - uint8_t generation; /* New multifunctionals are (generation == 2) */ - - uint8_t adf_state; /* handle adf scanning */ -} iclass_t; - - -static int is_scanning_from_adf (pixma_t * s) -{ - return (s->param->source == PIXMA_SOURCE_ADF - || s->param->source == PIXMA_SOURCE_ADFDUP); -} - -static int is_scanning_from_adfdup (pixma_t * s) -{ - return (s->param->source == PIXMA_SOURCE_ADFDUP); -} - -static void iclass_finish_scan (pixma_t * s); - -/* checksumming is sometimes different than pixmas */ -static int -iclass_exec (pixma_t * s, pixma_cmdbuf_t * cb, char invcksum) -{ - if (cb->cmdlen > cb->cmd_header_len) - pixma_fill_checksum (cb->buf + cb->cmd_header_len, - cb->buf + cb->cmdlen - 2); - cb->buf[cb->cmdlen - 1] = invcksum ? -cb->buf[cb->cmdlen - 2] : 0; - cb->reslen = - pixma_cmd_transaction (s, cb->buf, cb->cmdlen, cb->buf, - cb->expected_reslen); - return pixma_check_result (cb); -} - -static int -has_paper (pixma_t * s) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - return ((mf->current_status[1] & 0x0f) == 0 /* allow 0x10 as ADF paper OK */ - || mf->current_status[1] == 81); /* allow 0x51 as ADF paper OK */ -} - -static int -abort_session (pixma_t * s) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mf->cb, cmd_abort_session); -} - -static int -query_status (pixma_t * s) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mf->cb, cmd_status, 0, 12); - error = pixma_exec (s, &mf->cb); - if (error >= 0) - { - memcpy (mf->current_status, data, 12); - /*DBG (3, "Current status: paper=0x%02x cal=%u lamp=%u\n", - data[1], data[8], data[7]);*/ - PDBG (pixma_dbg (3, "Current status: paper=0x%02x cal=%u lamp=%u\n", - data[1], data[8], data[7])); - } - return error; -} - -static int -activate (pixma_t * s, uint8_t x) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - uint8_t *data = pixma_newcmd (&mf->cb, cmd_activate, 10, 0); - data[0] = 1; - data[3] = x; - switch (s->cfg->pid) - { - case MF4200_PID: - case MF4600_PID: - case MF6500_PID: - case D480_PID: - case D420_PID: - case MF4360_PID: - case MF4100_PID: - case MF8300_PID: - return iclass_exec (s, &mf->cb, 1); - break; - default: - return pixma_exec (s, &mf->cb); - } -} - -static int -start_session (pixma_t * s) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mf->cb, cmd_start_session); -} - -static int -select_source (pixma_t * s) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - uint8_t *data = pixma_newcmd (&mf->cb, cmd_select_source, 10, 0); - data[0] = (is_scanning_from_adf(s)) ? 2 : 1; - /* special settings for MF6100 */ - data[5] = is_scanning_from_adfdup(s) ? 3 : ((s->cfg->pid == MF6100_PID && s->param->source == PIXMA_SOURCE_ADF) ? 1 : 0); - switch (s->cfg->pid) - { - case MF4200_PID: - case MF4600_PID: - case MF6500_PID: - case D480_PID: - case D420_PID: - case MF4360_PID: - case MF4100_PID: - case MF8300_PID: - return iclass_exec (s, &mf->cb, 0); - break; - default: - return pixma_exec (s, &mf->cb); - } -} - -static int -send_scan_param (pixma_t * s) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - uint8_t *data; - - data = pixma_newcmd (&mf->cb, cmd_scan_param, 0x2e, 0); - pixma_set_be16 (s->param->xdpi | 0x1000, data + 0x04); - pixma_set_be16 (s->param->ydpi | 0x1000, data + 0x06); - pixma_set_be32 (s->param->x, data + 0x08); - pixma_set_be32 (s->param->y, data + 0x0c); - pixma_set_be32 (mf->raw_width, data + 0x10); - pixma_set_be32 (s->param->h, data + 0x14); - data[0x18] = (s->param->channels == 1) ? 0x04 : 0x08; - data[0x19] = s->param->channels * ((s->param->depth == 1) ? 8 : s->param->depth); /* bits per pixel */ - data[0x1f] = 0x7f; - data[0x20] = 0xff; - data[0x23] = 0x81; - switch (s->cfg->pid) - { - case MF4200_PID: - case MF4600_PID: - case MF6500_PID: - case D480_PID: - case D420_PID: - case MF4360_PID: - case MF4100_PID: - case MF8300_PID: - return iclass_exec (s, &mf->cb, 0); - break; - default: - return pixma_exec (s, &mf->cb); - } -} - -static int -request_image_block (pixma_t * s, unsigned flag, uint8_t * info, - unsigned * size, uint8_t * data, unsigned * datalen) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - int error; - unsigned expected_len; - const int hlen = 2 + 6; - - memset (mf->cb.buf, 0, 11); - /* generation 2 scanners use cmd_read_image2. - * MF6100, ... are exceptions */ - pixma_set_be16 (((mf->generation >= 2 - && s->cfg->pid != MF6100_PID) ? cmd_read_image2 : cmd_read_image), mf->cb.buf); - mf->cb.buf[8] = flag; - mf->cb.buf[10] = 0x06; - expected_len = (mf->generation >= 2 || - s->cfg->pid == MF4600_PID || - s->cfg->pid == MF6500_PID || - s->cfg->pid == MF8030_PID) ? 512 : hlen; - mf->cb.reslen = pixma_cmd_transaction (s, mf->cb.buf, 11, mf->cb.buf, expected_len); - if (mf->cb.reslen >= hlen) - { - *info = mf->cb.buf[2]; - *size = pixma_get_be16 (mf->cb.buf + 6); /* 16bit size */ - error = 0; - - if (mf->generation >= 2 || - s->cfg->pid == MF4600_PID || - s->cfg->pid == MF6500_PID || - s->cfg->pid == MF8030_PID) - { /* 32bit size */ - *datalen = mf->cb.reslen - hlen; - *size = (*datalen + hlen == 512) ? pixma_get_be32 (mf->cb.buf + 4) - *datalen : *size; - memcpy (data, mf->cb.buf + hlen, *datalen); - } - PDBG (pixma_dbg (11, "*request_image_block***** size = %u *****\n", *size)); - } - else - { - error = PIXMA_EPROTO; - } - return error; -} - -static int -read_image_block (pixma_t * s, uint8_t * data, unsigned size) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - int error; - unsigned maxchunksize, chunksize, count = 0; - - maxchunksize = MAX_CHUNK_SIZE * ((mf->generation >= 2 || - s->cfg->pid == MF4600_PID || - s->cfg->pid == MF6500_PID || - s->cfg->pid == MF8030_PID) ? 4 : 1); - while (size) - { - if (size >= maxchunksize) - chunksize = maxchunksize; - else if (size < MIN_CHUNK_SIZE) - chunksize = size; - else - chunksize = size - (size % MIN_CHUNK_SIZE); - error = pixma_read (s->io, data, chunksize); - if (error < 0) - return count; - count += error; - data += error; - size -= error; - } - return count; -} - -static int -read_error_info (pixma_t * s, void *buf, unsigned size) -{ - unsigned len = 16; - iclass_t *mf = (iclass_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mf->cb, cmd_error_info, 0, len); - switch (s->cfg->pid) - { - case MF4200_PID: - case MF4600_PID: - case MF6500_PID: - case D480_PID: - case D420_PID: - case MF4360_PID: - case MF4100_PID: - case MF8300_PID: - error = iclass_exec (s, &mf->cb, 0); - break; - default: - error = pixma_exec (s, &mf->cb); - } - if (error < 0) - return error; - if (buf && len < size) - { - size = len; - /* NOTE: I've absolutely no idea what the returned data mean. */ - memcpy (buf, data, size); - error = len; - } - return error; -} - -static int -handle_interrupt (pixma_t * s, int timeout) -{ - uint8_t buf[16]; - int len; - - len = pixma_wait_interrupt (s->io, buf, sizeof (buf), timeout); - if (len == PIXMA_ETIMEDOUT) - return 0; - if (len < 0) - return len; - if (len != 16) - { - PDBG (pixma_dbg - (1, "WARNING:unexpected interrupt packet length %d\n", len)); - return PIXMA_EPROTO; - } - if (buf[12] & 0x40) - query_status (s); - if (buf[15] & 1) - s->events = PIXMA_EV_BUTTON1; - return 1; -} - -static int -step1 (pixma_t * s) -{ - int error; - int rec_tmo; - iclass_t *mf = (iclass_t *) s->subdriver; - - /* don't wait full timeout for 1st command */ - rec_tmo = s->rec_tmo; /* save globel timeout */ - s->rec_tmo = 2; /* set timeout to 2 seconds */ - error = query_status (s); - s->rec_tmo = rec_tmo; /* restore global timeout */ - if (error < 0) - { - PDBG (pixma_dbg (1, "WARNING: Resend first USB command after timeout!\n")); - error = query_status (s); - } - if (error < 0) - return error; - - /* wait for inserted paper */ - if (s->param->adf_wait != 0 && is_scanning_from_adf(s)) - { - int tmo = s->param->adf_wait; - - while (!has_paper (s) && --tmo >= 0 && !s->param->frontend_cancel) - { - if ((error = query_status (s)) < 0) - return error; - pixma_sleep (1000000); - PDBG (pixma_dbg(2, "No paper in ADF. Timed out in %d sec.\n", tmo)); - } - /* canceled from frontend */ - if (s->param->frontend_cancel) - { - return PIXMA_ECANCELED; - } - } - /* no paper inserted - * => abort session */ - if (is_scanning_from_adf(s) && !has_paper (s)) - { - return PIXMA_ENO_PAPER; - } - /* activate only seen for generation 1 scanners */ - if (mf->generation == 1) - { - if (error >= 0) - error = activate (s, 0); - if (error >= 0) - error = activate (s, 4); - } - return error; -} - -/* line in=rrr... ggg... bbb... line out=rgbrgbrgb... */ -static void -pack_rgb (const uint8_t * src, unsigned nlines, unsigned w, uint8_t * dst) -{ - unsigned w2, stride; - - w2 = 2 * w; - stride = 3 * w; - for (; nlines != 0; nlines--) - { - unsigned x; - for (x = 0; x != w; x++) - { - *dst++ = src[x + 0]; - *dst++ = src[x + w]; - *dst++ = src[x + w2]; - } - src += stride; - } -} - -static int -iclass_open (pixma_t * s) -{ - iclass_t *mf; - uint8_t *buf; - - mf = (iclass_t *) calloc (1, sizeof (*mf)); - if (!mf) - return PIXMA_ENOMEM; - - buf = (uint8_t *) malloc (CMDBUF_SIZE); - if (!buf) - { - free (mf); - return PIXMA_ENOMEM; - } - - s->subdriver = mf; - mf->state = state_idle; - - mf->cb.buf = buf; - mf->cb.size = CMDBUF_SIZE; - mf->cb.res_header_len = 2; - mf->cb.cmd_header_len = 10; - mf->cb.cmd_len_field_ofs = 7; - - /* adf scanning */ - mf->adf_state = state_idle; - - /* set generation = 2 for new multifunctionals */ - mf->generation = (s->cfg->pid >= MF8030_PID) ? 2 : 1; - PDBG (pixma_dbg (3, "*iclass_open***** This is a generation %d scanner. *****\n", mf->generation)); - - PDBG (pixma_dbg (3, "Trying to clear the interrupt buffer...\n")); - if (handle_interrupt (s, 200) == 0) - { - PDBG (pixma_dbg (3, " no packets in buffer\n")); - } - return 0; -} - -static void -iclass_close (pixma_t * s) -{ - iclass_t *mf = (iclass_t *) s->subdriver; - - iclass_finish_scan (s); - free (mf->cb.buf); - free (mf->buf); - free (mf); - s->subdriver = NULL; -} - -static int -iclass_check_param (pixma_t * s, pixma_scan_param_t * sp) -{ - UNUSED (s); - - /* PDBG (pixma_dbg (4, "*iclass_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, line_size=%" PRIu64 " , h=%u*****\n", - sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->line_size, sp->h)); */ - - sp->depth = 8; - sp->software_lineart = 0; - if (sp->mode == PIXMA_SCAN_MODE_LINEART) - { - sp->software_lineart = 1; - sp->channels = 1; - sp->depth = 1; - } - - if (sp->software_lineart == 1) - { - unsigned w_max; - - /* for software lineart line_size and w must be a multiple of 8 */ - sp->line_size = ALIGN_SUP (sp->w, 8) * sp->channels; - sp->w = ALIGN_SUP (sp->w, 8); - - /* do not exceed the scanner capability */ - w_max = s->cfg->width * s->cfg->xdpi / 75; - w_max -= w_max % 32; - if (sp->w > w_max) - sp->w = w_max; - } - else - sp->line_size = ALIGN_SUP (sp->w, 32) * sp->channels; - - /* Some exceptions here for particular devices */ - /* Those devices can scan up to Legal 14" with ADF, but A4 11.7" in flatbed */ - /* PIXMA_CAP_ADF also works for PIXMA_CAP_ADFDUP */ - if ((s->cfg->cap & PIXMA_CAP_ADF) && sp->source == PIXMA_SOURCE_FLATBED) - sp->h = MIN (sp->h, 877 * sp->xdpi / 75); - - /* PDBG (pixma_dbg (4, "*iclass_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, line_size=%" PRIu64 " , h=%u*****\n", - sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->line_size, sp->h)); */ - - return 0; -} - -static int -iclass_scan (pixma_t * s) -{ - int error, n; - iclass_t *mf = (iclass_t *) s->subdriver; - uint8_t *buf, ignore; - unsigned buf_len, ignore2; - - if (mf->state != state_idle) - return PIXMA_EBUSY; - - /* clear interrupt packets buffer */ - while (handle_interrupt (s, 0) > 0) - { - } - - mf->raw_width = ALIGN_SUP (s->param->w, 32); - PDBG (pixma_dbg (3, "raw_width = %u\n", mf->raw_width)); - - n = IMAGE_BLOCK_SIZE / s->param->line_size + 1; - buf_len = (n + 1) * s->param->line_size + IMAGE_BLOCK_SIZE; - if (buf_len > mf->buf_len) - { - buf = (uint8_t *) realloc (mf->buf, buf_len); - if (!buf) - return PIXMA_ENOMEM; - mf->buf = buf; - mf->buf_len = buf_len; - } - mf->lineptr = mf->buf; - mf->blkptr = mf->buf + n * s->param->line_size; - mf->blk_len = 0; - - error = step1 (s); - if (error >= 0 - && (s->param->adf_pageid == 0 || mf->generation == 1 || mf->adf_state == state_idle)) - { /* single sheet or first sheet from ADF */ - PDBG (pixma_dbg (3, "*iclass_scan***** start scanning *****\n")); - error = start_session (s); - if (error >= 0) - mf->state = state_scanning; - if (error >= 0) - error = select_source (s); - } - else if (error >= 0) - { /* next sheet from ADF */ - PDBG (pixma_dbg (3, "*iclass_scan***** scan next sheet from ADF *****\n")); - mf->state = state_scanning; - } - if (error >= 0) - error = send_scan_param (s); - if (error >= 0) - error = request_image_block (s, 0, &ignore, &ignore2, &ignore, &ignore2); - if (error < 0) - { - iclass_finish_scan (s); - return error; - } - mf->last_block = 0; - - /* ADF scanning active */ - if (is_scanning_from_adf (s)) - mf->adf_state = state_scanning; - return 0; -} - - -static int -iclass_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) -{ - int error, n; - iclass_t *mf = (iclass_t *) s->subdriver; - unsigned block_size, lines_size, lineart_lines_size, first_block_size; - uint8_t info; - -/* - * 1. send a block request cmd (d4 20 00... 04 00 06) - * 2. examine the response for block size and/or end-of-scan flag - * 3. read the block one chunk at a time - * 4. repeat until have enough to process >=1 lines - */ - do - { - do - { - if (s->cancel) - return PIXMA_ECANCELED; - if (mf->last_block) - { - /* end of image */ - mf->state = state_finished; - return 0; - } - - first_block_size = 0; - error = request_image_block (s, 4, &info, &block_size, - mf->blkptr + mf->blk_len, &first_block_size); - /* add current block to remainder of previous */ - mf->blk_len += first_block_size; - if (error < 0) - { - /* NOTE: seen in traffic logs but don't know the meaning. */ - read_error_info (s, NULL, 0); - if (error == PIXMA_ECANCELED) - return error; - } - - /* info: 0x28 = end; 0x38 = end + ADF empty */ - mf->last_block = info & 0x38; - if ((info & ~0x38) != 0) - { - PDBG (pixma_dbg (1, "WARNING: Unexpected result header\n")); - PDBG (pixma_hexdump (1, &info, 1)); - } - - if (block_size == 0) - { - /* no image data at this moment. */ - /*pixma_sleep(100000); *//* FIXME: too short, too long? */ - handle_interrupt (s, 100); - } - } - while (block_size == 0 && first_block_size == 0); - - error = read_image_block (s, mf->blkptr + mf->blk_len, block_size); - block_size = error; - if (error < 0) - return error; - - /* add current block to remainder of previous */ - mf->blk_len += block_size; - /* n = number of full lines (rows) we have in the buffer. */ - n = mf->blk_len / ((s->param->mode == PIXMA_SCAN_MODE_LINEART) ? mf->raw_width : s->param->line_size); - if (n != 0) - { - /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** Processing with n=%d, w=%i, line_size=%" PRIu64 ", raw_width=%u ***** \n", - n, s->param->w, s->param->line_size, mf->raw_width)); */ - /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** scan_mode=%d, lineptr=%" PRIu64 ", blkptr=%" PRIu64 " \n", - s->param->mode, (uint64_t)mf->lineptr, (uint64_t)mf->blkptr)); */ - - /* gray to lineart convert - * mf->lineptr : image line - * mf->blkptr : scanned image block as grayscale - * s->param->w : image width - * s->param->line_size : scanned image width */ - if (s->param->mode == PIXMA_SCAN_MODE_LINEART) - { - int i; - uint8_t *sptr, *dptr; - - /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** Processing lineart *****\n")); */ - - /* process ALL lines */ - sptr = mf->blkptr; - dptr = mf->lineptr; - for (i = 0; i < n; i++, sptr += mf->raw_width) - dptr = pixma_binarize_line (s->param, dptr, sptr, s->param->line_size, 1); - } - else if (s->param->channels != 1 && - mf->generation == 1 && - s->cfg->pid != MF4600_PID && - s->cfg->pid != MF6500_PID && - s->cfg->pid != MF8030_PID) - { - /* color and not MF46xx or MF65xx */ - pack_rgb (mf->blkptr, n, mf->raw_width, mf->lineptr); - } - else - { - /* grayscale */ - memcpy (mf->lineptr, mf->blkptr, n * s->param->line_size); - } - /* cull remainder and shift left */ - lineart_lines_size = n * s->param->line_size / 8; - lines_size = n * ((s->param->mode == PIXMA_SCAN_MODE_LINEART) ? mf->raw_width : s->param->line_size); - mf->blk_len -= lines_size; - memcpy (mf->blkptr, mf->blkptr + lines_size, mf->blk_len); - } - } - while (n == 0); - - /* output full lines, keep partial lines for next block - * ib->rptr : start of image buffer - * ib->rend : end of image buffer */ - ib->rptr = mf->lineptr; - ib->rend = mf->lineptr + (s->param->mode == PIXMA_SCAN_MODE_LINEART ? lineart_lines_size : lines_size); - /* PDBG (pixma_dbg (4, "*iclass_fill_buffer***** rptr=%" PRIu64 ", rend=%" PRIu64 ", diff=%ld \n", - (uint64_t)ib->rptr, (uint64_t)ib->rend, ib->rend - ib->rptr)); */ - return ib->rend - ib->rptr; -} - -static void -iclass_finish_scan (pixma_t * s) -{ - int error; - iclass_t *mf = (iclass_t *) s->subdriver; - - switch (mf->state) - { - /* fall through */ - case state_warmup: - case state_scanning: - error = abort_session (s); - if (error < 0) - PDBG (pixma_dbg - (1, "WARNING:abort_session() failed %s\n", - pixma_strerror (error))); - /* fall through */ - case state_finished: - query_status (s); - query_status (s); - if (mf->generation == 1) - { /* activate only seen for generation 1 scanners */ - activate (s, 0); - query_status (s); - } - /* generation = 1: - * 0x28 = last block (no multi page scan) - * generation >= 2: - * 0x38 = last block and ADF empty (generation >= 2) - * 0x28 = last block and Paper in ADF (multi page scan) - * some generation 2 scanners don't use 0x38 for ADF empty => check status */ - if (mf->last_block==0x38 /* generation 2 scanner ADF empty */ - || (mf->generation == 1 && mf->last_block == 0x28) /* generation 1 scanner last block */ - || (mf->generation >= 2 && !has_paper(s))) /* check status: no paper in ADF */ - { - /* ADFDUP scan: wait for 8sec to throw last page out of ADF feeder */ - if (is_scanning_from_adfdup(s)) - { - PDBG (pixma_dbg (4, "*iclass_finish_scan***** sleep for 8s *****\n")); - pixma_sleep(8000000); /* sleep for 8s */ - query_status (s); - } - PDBG (pixma_dbg (3, "*iclass_finish_scan***** abort session *****\n")); - abort_session (s); - mf->adf_state = state_idle; - mf->last_block = 0; - } - else - PDBG (pixma_dbg (3, "*iclass_finish_scan***** wait for next page from ADF *****\n")); - - mf->state = state_idle; - /* fall through */ - case state_idle: - break; - } -} - -static void -iclass_wait_event (pixma_t * s, int timeout) -{ - /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for - * instance. */ - while (s->events == 0 && handle_interrupt (s, timeout) > 0) - { - } -} - -static int -iclass_get_status (pixma_t * s, pixma_device_status_t * status) -{ - int error; - - error = query_status (s); - if (error < 0) - return error; - status->hardware = PIXMA_HARDWARE_OK; - status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; - return 0; -} - - -static const pixma_scan_ops_t pixma_iclass_ops = { - iclass_open, - iclass_close, - iclass_scan, - iclass_fill_buffer, - iclass_finish_scan, - iclass_wait_event, - iclass_check_param, - iclass_get_status -}; - -#define DEV(name, model, pid, dpi, adftpu_max_dpi, w, h, cap) { \ - name, /* name */ \ - model, /* model */ \ - 0x04a9, pid, /* vid pid */ \ - 1, /* iface */ \ - &pixma_iclass_ops, /* ops */ \ - dpi, dpi, /* xdpi, ydpi */ \ - 0, /* adftpu_min_dpi not used in this subdriver */ \ - adftpu_max_dpi, /* adftpu_max_dpi */ \ - 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ - w, h, /* width, height */ \ - PIXMA_CAP_LINEART| /* all scanners have software lineart */ \ - PIXMA_CAP_ADF_WAIT| /* adf wait for all ADF and ADFDUP scanners */ \ - PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ -} -const pixma_config_t pixma_iclass_devices[] = { - DEV ("Canon imageCLASS MF4270", "MF4270", MF4200_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS MF4150", "MF4100", MF4100_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS MF4690", "MF4690", MF4600_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS D420", "D420", D420_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), - DEV ("Canon imageCLASS D480", "D480", D480_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), - DEV ("Canon imageCLASS MF4360", "MF4360", MF4360_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), - DEV ("Canon imageCLASS MF4320", "MF4320", MF4320_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS MF4010", "MF4010", MF4010_PID, 600, 0, 640, 877, 0), - DEV ("Canon imageCLASS MF3240", "MF3240", MF3200_PID, 600, 0, 640, 877, 0), - DEV ("Canon imageClass MF6500", "MF6500", MF6500_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS MF4410", "MF4410", MF4410_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS D550", "D550", D550_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), - DEV ("Canon i-SENSYS MF4500 Series", "MF4500", MF4500_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon i-SENSYS MF3010", "MF3010", MF3010_PID, 600, 0, 640, 877, 0), - DEV ("Canon i-SENSYS MF4700 Series", "MF4700", MF4700_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), - DEV ("Canon i-SENSYS MF4800 Series", "MF4800", MF4800_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS MF4570dw", "MF4570dw", MF4570_PID, 600, 0, 640, 877, 0), - DEV ("Canon i-SENSYS MF8200C Series", "MF8200C", MF8200_PID, 600, 300, 640, 1050, PIXMA_CAP_ADF), - DEV ("Canon i-SENSYS MF8300 Series", "MF8300", MF8300_PID, 600, 0, 640, 1050, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS D530", "D530", D530_PID, 600, 0, 640, 877, 0), - /* FIXME: the following capabilities all need updating/verifying */ - DEV ("Canon imageCLASS MF5630", "MF5630", MF5630_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon laserBase MF5650", "MF5650", MF5650_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon imageCLASS MF8170c", "MF8170c", MF8100_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon imageClass MF8030", "MF8030", MF8030_PID, 600, 0, 640, 877, PIXMA_CAP_ADF), - DEV ("Canon i-SENSYS MF5880dn", "MF5880", MF5880_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF6680dn", "MF6680", MF6680_PID, 600, 0, 640, 877, PIXMA_CAP_ADFDUP), - DEV ("Canon imageRUNNER 1133", "iR1133", IR1133_PID, 600, 0, 637, 877, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ - DEV ("Canon i-SENSYS MF5900 Series", "MF5900", MF5900_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF8500C Series", "MF8500C", MF8500_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF6100 Series", "MF6100", MF6100_PID, 600, 300, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon imageClass MF810/820", "MF810/820", MF820_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF220 Series", "MF220", MF220_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ - DEV ("Canon i-SENSYS MF210 Series", "MF210", MF210_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */ - DEV ("Canon i-SENSYS MF620 Series", "MF620", MF620_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), - DEV ("Canon i-SENSYS MF410 Series", "MF410", MF410_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* max. w = 216mm */ - DEV ("Canon i-SENSYS MF510 Series", "MF510", MF510_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF230 Series", "MF230", MF230_PID, 600, 0, 637, 1050, PIXMA_CAP_ADF), /* max. w = 216mm */ - DEV ("Canon i-SENSYS MF240 Series", "MF240", MF240_PID, 600, 300, 634, 1050, PIXMA_CAP_ADF), /* max. w = 215mm, */ - /* TODO: fix black stripes for 216mm @ 600dpi */ - DEV ("Canon i-SENSYS MF630 Series", "MF630", MF630_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF730 Series", "MF730", MF730_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF731C", "MF731", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon imageCLASS MF634C", "MF632C/634C", MF634_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon imageCLASS MF733C", "MF731C/733C", MF731_PID, 600, 0, 637, 1050, PIXMA_CAP_ADFDUP), /* however, we need this for ethernet/wifi */ - DEV ("Canon imageCLASS D570", "D570", D570_PID, 600, 0, 640, 877, 0), - DEV ("Canon i-SENSYS MF110 Series", "MF110", MF110_PID, 600, 0, 640, 1050, 0), - DEV ("Canon i-SENSYS MF520 Series", "MF520", MF520_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF420 Series", "MF420", MF420_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF260 Series", "MF260", MF260_PID, 600, 0, 640, 1050, 0), - DEV ("Canon i-SENSYS MF740 Series", "MF740", MF740_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV ("Canon i-SENSYS MF640 Series", "MF640", MF640_PID, 600, 0, 640, 1050, PIXMA_CAP_ADFDUP), - DEV (NULL, NULL, 0, 0, 0, 0, 0, 0) -}; diff --git a/backend/pixma_io.h b/backend/pixma_io.h deleted file mode 100644 index 29bb38d..0000000 --- a/backend/pixma_io.h +++ /dev/null @@ -1,186 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - 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. - */ -#ifndef PIXMA_IO_H -#define PIXMA_IO_H - -/* TODO: move to pixma_common.h, to reduce the number of files */ - -/*! - * \defgroup IO IO interface - * \brief The IO interface. - * - * Return value of functions that return \c int if not otherwise specified: - * - >= if succeeded - * - < 0 if failed (e.g. \c PIXMA_ETIMEDOUT) - * . - * @{ - */ - -/** Timeout for pixma_read() in milliseconds */ -#define PIXMA_BULKIN_TIMEOUT 1000 -/** Timeout for pixma_write() in milliseconds */ -#define PIXMA_BULKOUT_TIMEOUT 1000 - - -struct pixma_io_t; -struct pixma_config_t; - -/** IO handle */ -typedef struct pixma_io_t pixma_io_t; - - -/** Initialize IO module. It must be called before any other functions in this - * module. - * \return 0 on success or - * - \c PIXMA_ENOMEM - * - \c PIXMA_EACCES - * - \c PIXMA_EIO */ -int pixma_io_init (void); - -/** Shutdown all connections and free resources allocated in this module. */ -void pixma_io_cleanup (void); - -/** Find devices currently connected to the computer. - * \c devnr passed to functions - * - pixma_get_device_config() - * - pixma_get_device_id() - * - pixma_connect() - * . - * should be less than the number of devices returned by this function. - * \param[in] pixma_devices A \c NULL terminated array of pointers to - * array of pixma_config_t which is terminated by setting - * pixma_config_t::name to \c NULL. - * \return Number of devices found */ -unsigned pixma_collect_devices (const char ** conf_devices, - const struct pixma_config_t *const - pixma_devices[]); - -/** Get device configuration. */ -const struct pixma_config_t *pixma_get_device_config (unsigned devnr); - -/** Get a unique ID of the device \a devnr. */ -const char *pixma_get_device_id (unsigned devnr); - -/** Connect to the device and claim the scanner interface. - * \param[in] devnr - * \param[out] handle - * \return 0 on success or - * - \c PIXMA_ENODEV the device is gone from the system. - * - \c PIXMA_EINVAL \a devnr is invalid. - * - \c PIXMA_EBUSY - * - \c PIXMA_EACCES - * - \c PIXMA_ENOMEM - * - \c PIXMA_EIO */ -int pixma_connect (unsigned devnr, pixma_io_t ** handle); - -/** Release the scanner interface and disconnect from the device. */ -void pixma_disconnect (pixma_io_t *); - -/** Activate connection to scanner */ -int pixma_activate (pixma_io_t *); - -/** De-activate connection to scanner */ -int pixma_deactivate (pixma_io_t *); - -/** Reset the USB interface. \warning Use with care! */ -int pixma_reset_device (pixma_io_t *); - -/** Write data to the device. This function may not be interrupted by signals. - * It will return iff - * - \a len bytes have been successfully written or - * - an error (inclusive timeout) occured. - * . - * \note Calling pixma_write(io, buf, n1) and pixma(io, buf+n1, n2) may - * not be the same as pixma_write(io, buf, n1+n2) if n1 is not - * multiple of the maximum packet size of the endpoint. - * \param[in] cmd Data - * \param[in] len Length of data - * \return Number of bytes successfully written (always = \a len) or - * - \c PIXMA_ETIMEDOUT - * - \c PIXMA_EIO - * - \c PIXMA_ENOMEM - * \see #PIXMA_BULKOUT_TIMEOUT */ -int pixma_write (pixma_io_t *, const void *cmd, unsigned len); - -/** Read data from the device. This function may not be interrupted by signals. - * It will return iff - * - \a size bytes have been successfully read, - * - a short packet has been read or - * - an error (inclusive timeout) occured. - * . - * \param[out] buf - * \param[in] size of the buffer - * \return Number of bytes successfully read. A return value of zero means that - * a zero length USB packet was received. Or - * - \c PIXMA_ETIMEDOUT - * - \c PIXMA_EIO - * - \c PIXMA_ENOMEM - * \see #PIXMA_BULKIN_TIMEOUT */ -int pixma_read (pixma_io_t *, void *buf, unsigned size); - -/** Wait for an interrupt. This function can be interrupted by signals. - * \a size should be less than or equal to the maximum packet size. - * \param[out] buf - * \param[in] size of the buffer - * \param[in] timeout in milliseconds; if < 0, wait forever. - * \return Number of bytes successfully read or - * - \c PIXMA_ETIMEDOUT - * - \c PIXMA_EIO - * - \c PIXMA_ENOMEM - * - \c PIXMA_ECANCELED if it was interrupted by a signal. */ -int pixma_wait_interrupt (pixma_io_t *, void *buf, unsigned size, - int timeout); - -/** Enable or disable background interrupt monitoring. - * Background mode is enabled by default. - * \param[in] background if not zero, a URB is submitted in background - * for interrupt endpoint. - * \return 0 on success or - * - \c PIXMA_ENOTSUP - * - \c PIXMA_EIO - * - \c PIXMA_ENOMEM */ -int pixma_set_interrupt_mode (pixma_io_t *, int background); - -/** @} end of IO group */ - -#endif diff --git a/backend/pixma_io_sanei.c b/backend/pixma_io_sanei.c deleted file mode 100644 index 4710cf4..0000000 --- a/backend/pixma_io_sanei.c +++ /dev/null @@ -1,593 +0,0 @@ -/* SANE - Scanner Access Now Easy. - * For limitations, see function sanei_usb_get_vendor_product(). - - Copyright (C) 2011-2019 Rolf Bensch - 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 -#include /* INT_MAX */ - -#include "pixma_rename.h" -#include "pixma_common.h" -#include "pixma_io.h" -#include "pixma_bjnp.h" - -#include "../include/sane/sanei_usb.h" - - -#ifdef __GNUC__ -# define UNUSED(v) (void) v -#else -# define UNUSED(v) -#endif - -/* MAC OS X does not support timeouts in darwin/libusb interrupt reads - * This is a very basic turnaround for MAC OS X - * Button scan will not work with this wrapper */ -#ifdef __APPLE__ -# define sanei_usb_read_int sanei_usb_read_bulk -#endif - - -struct pixma_io_t -{ - pixma_io_t *next; - int interface; - SANE_Int dev; -}; - -typedef struct scanner_info_t -{ - struct scanner_info_t *next; - char *devname; - int interface; - const pixma_config_t *cfg; - char serial[PIXMA_MAX_ID_LEN + 1]; /* "xxxxyyyy_zzzzzzz..." - x = vid, y = pid, z = serial */ -} scanner_info_t; - -#define INT_USB 0 -#define INT_BJNP 1 - -static scanner_info_t *first_scanner = NULL; -static pixma_io_t *first_io = NULL; -static unsigned nscanners; - - -static scanner_info_t * -get_scanner_info (unsigned devnr) -{ - scanner_info_t *si; - for (si = first_scanner; si && devnr != 0; --devnr, si = si->next) - { - } - return si; -} - -static const struct pixma_config_t *lookup_scanner(const char *makemodel, - const struct pixma_config_t *const pixma_devices[]) -{ - int i; - const struct pixma_config_t *cfg; - char *match; - - for (i = 0; pixma_devices[i]; i++) - { - /* loop through the device classes (mp150, mp730 etc) */ - for (cfg = pixma_devices[i]; cfg->name; cfg++) - { - /* loop through devices in class */ - if ((match = strcasestr (makemodel, cfg->model)) != NULL) - { - /* possible match found, make sure it is not a partial match */ - /* MP600 and MP600R are different models! */ - /* some models contain ranges, so check for a '-' too */ - - if ((match[strlen(cfg->model)] == ' ') || - (match[strlen(cfg->model)] == '\0') || - (match[strlen(cfg->model)] == '-')) - { - pixma_dbg (3, "Scanner model found: Name %s(%s) matches %s\n", cfg->model, cfg->name, makemodel); - return cfg; - } - } - pixma_dbg (20, "Scanner model %s(%s) not found, giving up! %s\n", cfg->model, cfg->name, makemodel); - } - } - return NULL; -} - -static SANE_Status -attach (SANE_String_Const devname) -{ - scanner_info_t *si; - - si = (scanner_info_t *) calloc (1, sizeof (*si)); - if (!si) - return SANE_STATUS_NO_MEM; - si->devname = strdup (devname); - if (!si->devname) - return SANE_STATUS_NO_MEM; - si -> interface = INT_USB; - si->next = first_scanner; - first_scanner = si; - nscanners++; - return SANE_STATUS_GOOD; -} - - -static SANE_Status -attach_bjnp (SANE_String_Const devname, SANE_String_Const makemodel, - SANE_String_Const serial, - const struct pixma_config_t *const pixma_devices[]) -{ - scanner_info_t *si; - const pixma_config_t *cfg; - SANE_Status error; - - si = (scanner_info_t *) calloc (1, sizeof (*si)); - if (!si) - return SANE_STATUS_NO_MEM; - si->devname = strdup (devname); - if (!si->devname) - return SANE_STATUS_NO_MEM; - if ((cfg = lookup_scanner(makemodel, pixma_devices)) == (struct pixma_config_t *)NULL) - error = SANE_STATUS_INVAL; - else - { - si->cfg = cfg; - sprintf(si->serial, "%s_%s", cfg->model, serial); - si -> interface = INT_BJNP; - si->next = first_scanner; - first_scanner = si; - nscanners++; - error = SANE_STATUS_GOOD; - } - return error; -} - -static void -clear_scanner_list (void) -{ - scanner_info_t *si = first_scanner; - while (si) - { - scanner_info_t *temp = si; - free (si->devname); - si = si->next; - free (temp); - } - nscanners = 0; - first_scanner = NULL; -} - -static SANE_Status -get_descriptor (SANE_Int dn, SANE_Int type, SANE_Int descidx, - SANE_Int index, SANE_Int length, SANE_Byte * data) -{ - return sanei_usb_control_msg (dn, 0x80, USB_REQ_GET_DESCRIPTOR, - ((type & 0xff) << 8) | (descidx & 0xff), - index, length, data); -} - -static SANE_Status -get_string_descriptor (SANE_Int dn, SANE_Int index, SANE_Int lang, - SANE_Int length, SANE_Byte * data) -{ - return get_descriptor (dn, USB_DT_STRING, index, lang, length, data); -} - -static void -u16tohex (uint16_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 >> 12) & 0xf]; - str[1] = hdigit[(x >> 8) & 0xf]; - str[2] = hdigit[(x >> 4) & 0xf]; - str[3] = hdigit[x & 0xf]; - str[4] = '\0'; -} - -static void -read_serial_number (scanner_info_t * si) -{ - uint8_t unicode[2 * (PIXMA_MAX_ID_LEN - 9) + 2]; - uint8_t ddesc[18]; - int iSerialNumber; - SANE_Int usb; - char *serial = si->serial; - - u16tohex (si->cfg->vid, serial); - u16tohex (si->cfg->pid, serial + 4); - - if (SANE_STATUS_GOOD != sanei_usb_open (si->devname, &usb)) - return; - if (get_descriptor (usb, USB_DT_DEVICE, 0, 0, 18, ddesc) - != SANE_STATUS_GOOD) - goto done; - iSerialNumber = ddesc[16]; - if (iSerialNumber != 0) - { - int i, len; - SANE_Status status; - - /*int iSerialNumber = ddesc[16];*/ - /* Read the first language code. Assumed that there is at least one. */ - if (get_string_descriptor (usb, 0, 0, 4, unicode) != SANE_STATUS_GOOD) - goto done; - /* Read the serial number string. */ - status = get_string_descriptor (usb, iSerialNumber, - unicode[3] * 256 + unicode[2], - sizeof (unicode), unicode); - if (status != SANE_STATUS_GOOD) - goto done; - /* Assumed charset: Latin1 */ - len = unicode[0]; - if (len > (int) sizeof (unicode)) - { - len = sizeof (unicode); - PDBG (pixma_dbg (1, "WARNING:Truncated serial number\n")); - } - serial[8] = '_'; - for (i = 2; i < len; i += 2) - { - serial[9 + i / 2 - 1] = unicode[i]; - } - serial[9 + i / 2 - 1] = '\0'; - } - else - { - PDBG (pixma_dbg (1, "WARNING:No serial number\n")); - } -done: - sanei_usb_close (usb); -} - -static int -map_error (SANE_Status ss) -{ - switch (ss) - { - case SANE_STATUS_GOOD: - return 0; - case SANE_STATUS_UNSUPPORTED: - return PIXMA_ENODEV; - case SANE_STATUS_DEVICE_BUSY: - return PIXMA_EBUSY; - case SANE_STATUS_INVAL: - return PIXMA_EINVAL; - case SANE_STATUS_IO_ERROR: - return PIXMA_EIO; - case SANE_STATUS_NO_MEM: - return PIXMA_ENOMEM; - case SANE_STATUS_ACCESS_DENIED: - return PIXMA_EACCES; - case SANE_STATUS_CANCELLED: - return PIXMA_ECANCELED; - case SANE_STATUS_JAMMED: - return PIXMA_EPAPER_JAMMED; - case SANE_STATUS_COVER_OPEN: - return PIXMA_ECOVER_OPEN; - case SANE_STATUS_NO_DOCS: - return PIXMA_ENO_PAPER; - case SANE_STATUS_EOF: - return PIXMA_EOF; -#ifdef SANE_STATUS_HW_LOCKED - case SANE_STATUS_HW_LOCKED: /* unused by pixma */ -#endif -#ifdef SANE_STATUS_WARMING_UP - case SANE_STATUS_WARMING_UP: /* unused by pixma */ -#endif - break; - } - PDBG (pixma_dbg (1, "BUG:Unmapped SANE Status code %d\n", ss)); - return PIXMA_EIO; /* should not happen */ -} - - -int -pixma_io_init (void) -{ - sanei_usb_init (); - sanei_bjnp_init(); - nscanners = 0; - return 0; -} - -void -pixma_io_cleanup (void) -{ - while (first_io) - pixma_disconnect (first_io); - clear_scanner_list (); -} - -unsigned -pixma_collect_devices (const char **conf_devices, - const struct pixma_config_t *const pixma_devices[]) -{ - unsigned i, j; - struct scanner_info_t *si; - const struct pixma_config_t *cfg; - - clear_scanner_list (); - j = 0; - for (i = 0; pixma_devices[i]; i++) - { - for (cfg = pixma_devices[i]; cfg->name; cfg++) - { - sanei_usb_find_devices (cfg->vid, cfg->pid, attach); - si = first_scanner; - while (j < nscanners) - { - PDBG (pixma_dbg (3, "pixma_collect_devices() found %s at %s\n", - cfg->name, si->devname)); - si->cfg = cfg; - read_serial_number (si); - si = si->next; - j++; - } - } - } - sanei_bjnp_find_devices(conf_devices, attach_bjnp, pixma_devices); - si = first_scanner; - while (j < nscanners) - { - PDBG (pixma_dbg (3, "pixma_collect_devices() found %s at %s\n", - si->cfg->name, si->devname)); - si = si->next; - j++; - - } - return nscanners; -} - -const pixma_config_t * -pixma_get_device_config (unsigned devnr) -{ - const scanner_info_t *si = get_scanner_info (devnr); - return (si) ? si->cfg : NULL; -} - -const char * -pixma_get_device_id (unsigned devnr) -{ - const scanner_info_t *si = get_scanner_info (devnr); - return (si) ? si->serial : NULL; -} - -int -pixma_connect (unsigned devnr, pixma_io_t ** handle) -{ - pixma_io_t *io; - SANE_Int dev; - const scanner_info_t *si; - int error; - - *handle = NULL; - si = get_scanner_info (devnr); - if (!si) - return PIXMA_EINVAL; - if (si-> interface == INT_BJNP) - error = map_error (sanei_bjnp_open (si->devname, &dev)); - else - error = map_error (sanei_usb_open (si->devname, &dev)); - - if (error < 0) - return error; - io = (pixma_io_t *) calloc (1, sizeof (*io)); - if (!io) - { - if (si -> interface == INT_BJNP) - sanei_bjnp_close (dev); - else - sanei_usb_close (dev); - return PIXMA_ENOMEM; - } - io->next = first_io; - first_io = io; - io->dev = dev; - io->interface = si->interface; - *handle = io; - return 0; -} - - -void -pixma_disconnect (pixma_io_t * io) -{ - pixma_io_t **p; - - if (!io) - return; - for (p = &first_io; *p && *p != io; p = &((*p)->next)) - { - } - PASSERT (*p); - if (!(*p)) - return; - if (io-> interface == INT_BJNP) - sanei_bjnp_close (io->dev); - else - sanei_usb_close (io->dev); - *p = io->next; - free (io); -} - -int pixma_activate (pixma_io_t * io) -{ - int error; - if (io->interface == INT_BJNP) - { - error = map_error(sanei_bjnp_activate (io->dev)); - } - else - /* noop for USB interface */ - error = 0; - return error; -} - -int pixma_deactivate (pixma_io_t * io) -{ - int error; - if (io->interface == INT_BJNP) - { - error = map_error(sanei_bjnp_deactivate (io->dev)); - } - else - /* noop for USB interface */ - error = 0; - return error; - -} - -int -pixma_reset_device (pixma_io_t * io) -{ - UNUSED (io); - return PIXMA_ENOTSUP; -} - -int -pixma_write (pixma_io_t * io, const void *cmd, unsigned len) -{ - size_t count = len; - int error; - - if (io->interface == INT_BJNP) - { - sanei_bjnp_set_timeout (io->dev, PIXMA_BULKOUT_TIMEOUT); - error = map_error (sanei_bjnp_write_bulk (io->dev, cmd, &count)); - } - else - { -#ifdef HAVE_SANEI_USB_SET_TIMEOUT - sanei_usb_set_timeout (PIXMA_BULKOUT_TIMEOUT); -#endif - error = map_error (sanei_usb_write_bulk (io->dev, cmd, &count)); - } - if (error == PIXMA_EIO) - error = PIXMA_ETIMEDOUT; /* FIXME: SANE doesn't have ETIMEDOUT!! */ - if (count != len) - { - PDBG (pixma_dbg (1, "WARNING:pixma_write(): count(%u) != len(%u)\n", - (unsigned) count, len)); - error = PIXMA_EIO; - } - if (error >= 0) - error = count; - PDBG (pixma_dump (10, "OUT ", cmd, error, len, 128)); - return error; -} - -int -pixma_read (pixma_io_t * io, void *buf, unsigned size) -{ - size_t count = size; - int error; - - if (io-> interface == INT_BJNP) - { - sanei_bjnp_set_timeout (io->dev, PIXMA_BULKIN_TIMEOUT); - error = map_error (sanei_bjnp_read_bulk (io->dev, buf, &count)); - } - else - { -#ifdef HAVE_SANEI_USB_SET_TIMEOUT - sanei_usb_set_timeout (PIXMA_BULKIN_TIMEOUT); -#endif - error = map_error (sanei_usb_read_bulk (io->dev, buf, &count)); - } - - if (error == PIXMA_EIO) - error = PIXMA_ETIMEDOUT; /* FIXME: SANE doesn't have ETIMEDOUT!! */ - if (error >= 0) - error = count; - PDBG (pixma_dump (10, "IN ", buf, error, -1, 128)); - return error; -} - -int -pixma_wait_interrupt (pixma_io_t * io, void *buf, unsigned size, int timeout) -{ - size_t count = size; - int error; - - /* FIXME: What is the meaning of "timeout" in sanei_usb? */ - if (timeout < 0) - timeout = INT_MAX; - else if (timeout < 100) - timeout = 100; - if (io-> interface == INT_BJNP) - { - sanei_bjnp_set_timeout (io->dev, timeout); - error = map_error (sanei_bjnp_read_int (io->dev, buf, &count)); - } - else - { -#ifdef HAVE_SANEI_USB_SET_TIMEOUT - sanei_usb_set_timeout (timeout); -#endif - error = map_error (sanei_usb_read_int (io->dev, buf, &count)); - } - if (error == PIXMA_EIO || - (io->interface == INT_BJNP && error == PIXMA_EOF)) /* EOF is a bjnp timeout error! */ - error = PIXMA_ETIMEDOUT; /* FIXME: SANE doesn't have ETIMEDOUT!! */ - if (error == 0) - error = count; - if (error != PIXMA_ETIMEDOUT) - PDBG (pixma_dump (10, "INTR", buf, error, -1, -1)); - return error; -} - -int -pixma_set_interrupt_mode (pixma_io_t * s, int background) -{ - UNUSED (s); - return (background) ? PIXMA_ENOTSUP : 0; -} diff --git a/backend/pixma_mp150.c b/backend/pixma_mp150.c deleted file mode 100644 index 5f0a4ac..0000000 --- a/backend/pixma_mp150.c +++ /dev/null @@ -1,2013 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2011-2019 Rolf Bensch - Copyright (C) 2007-2009 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. - */ -/* test cases - 1. short USB packet (must be no -ETIMEDOUT) - 2. cancel using button on the printer (look for abort command) - 3. start scan while busy (status 0x1414) - 4. cancel using ctrl-c (must send abort command) - */ - -#define TPU_48 /* uncomment to activate TPU scan at 48 bits */ -/*#define DEBUG_TPU_48*/ /* uncomment to debug 48 bits TPU on a non TPU device */ -/*#define DEBUG_TPU_24*/ /* uncomment to debug 24 bits TPU on a non TPU device */ - -#include "../include/sane/config.h" - -#include -#include -#include -#include /* localtime(C90) */ - -#include "pixma_rename.h" -#include "pixma_common.h" -#include "pixma_io.h" - -/* Some macro code to enhance readability */ -#define RET_IF_ERR(x) do { \ - if ((error = (x)) < 0) \ - return error; \ - } while(0) - -#define WAIT_INTERRUPT(x) do { \ - error = handle_interrupt (s, x); \ - if (s->cancel) \ - return PIXMA_ECANCELED; \ - if (error != PIXMA_ECANCELED && error < 0) \ - return error; \ - } while(0) - -#ifdef __GNUC__ -# define UNUSED(v) (void) v -#else -# define UNUSED(v) -#endif - -/* Size of the command buffer should be multiple of wMaxPacketLength and - greater than 4096+24. - 4096 = size of gamma table. 24 = header + checksum */ -#define IMAGE_BLOCK_SIZE (512*1024) -#define CMDBUF_SIZE (4096 + 24) -#define DEFAULT_GAMMA 2.0 /***** Gamma different from 1.0 is potentially impacting color profile generation *****/ -#define UNKNOWN_PID 0xffff - - -#define CANON_VID 0x04a9 - -/* Generation 1 */ -#define MP150_PID 0x1709 -#define MP170_PID 0x170a -#define MP450_PID 0x170b -#define MP500_PID 0x170c -#define MP530_PID 0x1712 -#define MP800_PID 0x170d -#define MP800R_PID 0x170e -#define MP830_PID 0x1713 - -/* Generation 2 */ -#define MP160_PID 0x1714 -#define MP180_PID 0x1715 -#define MP460_PID 0x1716 -#define MP510_PID 0x1717 -#define MP600_PID 0x1718 -#define MP600R_PID 0x1719 - -#define MP140_PID 0x172b - -/* Generation 3 */ -/* PIXMA 2007 vintage */ -#define MX7600_PID 0x171c -#define MP210_PID 0x1721 -#define MP220_PID 0x1722 -#define MP470_PID 0x1723 -#define MP520_PID 0x1724 -#define MP610_PID 0x1725 -#define MX300_PID 0x1727 -#define MX310_PID 0x1728 -#define MX700_PID 0x1729 -#define MX850_PID 0x172c - -/* PIXMA 2008 vintage */ -#define MP630_PID 0x172e -#define MP620_PID 0x172f -#define MP540_PID 0x1730 -#define MP480_PID 0x1731 -#define MP240_PID 0x1732 -#define MP260_PID 0x1733 -#define MP190_PID 0x1734 - -/* PIXMA 2009 vintage */ -#define MX860_PID 0x1735 -#define MX320_PID 0x1736 /* untested */ -#define MX330_PID 0x1737 - -/* Generation 4 */ -#define MP250_PID 0x173a -#define MP270_PID 0x173b -#define MP490_PID 0x173c -#define MP550_PID 0x173d -#define MP560_PID 0x173e -#define MP640_PID 0x173f - -/* PIXMA 2010 vintage */ -#define MX340_PID 0x1741 -#define MX350_PID 0x1742 -#define MX870_PID 0x1743 - -/* 2010 new devices (untested) */ -#define MP280_PID 0x1746 -#define MP495_PID 0x1747 -#define MG5100_PID 0x1748 -#define MG5200_PID 0x1749 -#define MG6100_PID 0x174a - -/* PIXMA 2011 vintage */ -#define MX360_PID 0x174d -#define MX410_PID 0x174e -#define MX420_PID 0x174f -#define MX880_PID 0x1750 - -/* Generation 5 */ -/* 2011 new devices (untested) */ -#define MG2100_PID 0x1751 -#define MG3100_PID 0x1752 -#define MG4100_PID 0x1753 -#define MG5300_PID 0x1754 -#define MG6200_PID 0x1755 -#define MP493_PID 0x1757 -#define E500_PID 0x1758 - -/* 2012 new devices (untested) */ -#define MX370_PID 0x1759 -#define MX430_PID 0x175B -#define MX510_PID 0x175C -#define MX710_PID 0x175D -#define MX890_PID 0x175E -#define E600_PID 0x175A -#define MG4200_PID 0x1763 - -/* 2013 new devices */ -#define MP230_PID 0x175F -#define MG6300_PID 0x1765 - -/* 2013 new devices (untested) */ -#define MG2200_PID 0x1760 -#define E510_PID 0x1761 -#define MG3200_PID 0x1762 -#define MG5400_PID 0x1764 -#define MX390_PID 0x1766 -#define E610_PID 0x1767 -#define MX450_PID 0x1768 -#define MX520_PID 0x1769 -#define MX720_PID 0x176a -#define MX920_PID 0x176b -#define MG2400_PID 0x176c -#define MG2500_PID 0x176d -#define MG3500_PID 0x176e -#define MG6500_PID 0x176f -#define MG6400_PID 0x1770 -#define MG5500_PID 0x1771 -#define MG7100_PID 0x1772 - -/* 2014 new devices (untested) */ -#define MX470_PID 0x1774 -#define MX530_PID 0x1775 -#define MB5000_PID 0x1776 -#define MB5300_PID 0x1777 -#define MB2000_PID 0x1778 -#define MB2300_PID 0x1779 -#define E400_PID 0x177a -#define E560_PID 0x177b -#define MG7500_PID 0x177c -#define MG6600_PID 0x177e -#define MG5600_PID 0x177f -#define MG2900_PID 0x1780 -#define E460_PID 0x1788 - -/* 2015 new devices (untested) */ -#define MX490_PID 0x1787 -#define E480_PID 0x1789 -#define MG3600_PID 0x178a -#define MG7700_PID 0x178b -#define MG6900_PID 0x178c -#define MG6800_PID 0x178d -#define MG5700_PID 0x178e - -/* 2016 new devices (untested) */ -#define MB2700_PID 0x1792 -#define MB2100_PID 0x1793 -#define G3000_PID 0x1794 -#define G2000_PID 0x1795 -#define TS9000_PID 0x179f -#define TS8000_PID 0x1800 -#define TS6000_PID 0x1801 -#define TS5000_PID 0x1802 -#define MG3000_PID 0x180b -#define E470_PID 0x180c -#define E410_PID 0x181e - -/* 2017 new devices (untested) */ -#define G4000_PID 0x181d -#define TS6100_PID 0x1822 -#define TS5100_PID 0x1825 -#define TS3100_PID 0x1827 -#define E3100_PID 0x1828 - -/* 2018 new devices (untested) */ -#define MB5400_PID 0x178f -#define MB5100_PID 0x1790 -#define TS9100_PID 0x1820 -#define TR8500_PID 0x1823 -#define TR7500_PID 0x1824 -#define TS9500_PID 0x185c -#define LIDE400_PID 0x1912 /* tested */ -#define LIDE300_PID 0x1913 /* tested */ - -/* 2019 new devices (untested) */ -#define TS8100_PID 0x1821 -#define G3010_PID 0x183b -#define G4010_PID 0x183d -#define TS9180_PID 0x183e -#define TS8180_PID 0x183f -#define TS6180_PID 0x1840 -#define TR8580_PID 0x1841 -#define TS8130_PID 0x1842 -#define TS6130_PID 0x1843 -#define TR8530_PID 0x1844 -#define TR7530_PID 0x1845 -#define XK50_PID 0x1846 -#define XK70_PID 0x1847 -#define TR4500_PID 0x1854 -#define E4200_PID 0x1855 -#define TS6200_PID 0x1856 -#define TS6280_PID 0x1857 -#define TS6230_PID 0x1858 -#define TS8200_PID 0x1859 -#define TS8280_PID 0x185a -#define TS8230_PID 0x185b -#define TS9580_PID 0x185d -#define TR9530_PID 0x185e -#define XK80_PID 0x1873 - -/* Generation 4 XML messages that encapsulates the Pixma protocol messages */ -#define XML_START_1 \ -"\ -\ -StartJob\ -00000001\ -1" - -#define XML_START_2 \ -"\ -\ -VendorCmd\ -00000001\ -ModeShift1\ -" - -#define XML_END \ -"\ -\ -EndJob\ -00000001\ -" - -#define XML_OK "OK" - -enum mp150_state_t -{ - state_idle, - state_warmup, - state_scanning, - state_transfering, - state_finished -}; - -enum mp150_cmd_t -{ - cmd_start_session = 0xdb20, - cmd_select_source = 0xdd20, - cmd_gamma = 0xee20, - cmd_scan_param = 0xde20, - cmd_status = 0xf320, - cmd_abort_session = 0xef20, - cmd_time = 0xeb80, - cmd_read_image = 0xd420, - cmd_error_info = 0xff20, - - cmd_start_calibrate_ccd_3 = 0xd520, - cmd_end_calibrate_ccd_3 = 0xd720, - cmd_scan_param_3 = 0xd820, - cmd_scan_start_3 = 0xd920, - cmd_status_3 = 0xda20, - cmd_get_tpu_info_3 = 0xf520, - cmd_set_tpu_info_3 = 0xea20, - - cmd_e920 = 0xe920 /* seen in MP800 */ -}; - -typedef struct mp150_t -{ - enum mp150_state_t state; - pixma_cmdbuf_t cb; - uint8_t *imgbuf; - uint8_t current_status[16]; - unsigned last_block; - uint8_t generation; - /* for Generation 3 and CCD shift */ - uint8_t *linebuf; - uint8_t *data_left_ofs; - unsigned data_left_len; - int shift[3]; - unsigned color_shift; - unsigned stripe_shift; - uint8_t tpu_datalen; - uint8_t tpu_data[0x40]; - uint8_t adf_state; /* handle adf scanning */ -} mp150_t; - -/* - STAT: 0x0606 = ok, - 0x1515 = failed (PIXMA_ECANCELED), - 0x1414 = busy (PIXMA_EBUSY) - - Transaction scheme - 1. command_header/data | result_header - 2. command_header | result_header/data - 3. command_header | result_header/image_data - - - data has checksum in the last byte. - - image_data has no checksum. - - data and image_data begins in the same USB packet as - command_header or result_header. - - command format #1: - u16be cmd - u8[6] 0 - u8[4] 0 - u32be PLEN parameter length - u8[PLEN-1] parameter - u8 parameter check sum - result: - u16be STAT - u8 0 - u8 0 or 0x21 if STAT == 0x1414 - u8[4] 0 - - command format #2: - u16be cmd - u8[6] 0 - u8[4] 0 - u32be RLEN result length - result: - u16be STAT - u8[6] 0 - u8[RLEN-1] result - u8 result check sum - - command format #3: (only used by read_image_block) - u16be 0xd420 - u8[6] 0 - u8[4] 0 - u32be max. block size + 8 - result: - u16be STAT - u8[6] 0 - u8 block info bitfield: 0x8 = end of scan, 0x10 = no more paper, 0x20 = no more data - u8[3] 0 - u32be ILEN image data size - u8[ILEN] image data - */ - -static void mp150_finish_scan (pixma_t * s); - -static int -is_scanning_from_adf (pixma_t * s) -{ - return (s->param->source == PIXMA_SOURCE_ADF - || s->param->source == PIXMA_SOURCE_ADFDUP); -} - -static int -is_scanning_from_adfdup (pixma_t * s) -{ - return (s->param->source == PIXMA_SOURCE_ADFDUP); -} - -static int -is_scanning_jpeg (pixma_t *s) -{ - return s->param->mode_jpeg; -} - -static int -is_scanning_from_tpu (pixma_t * s) -{ - return (s->param->source == PIXMA_SOURCE_TPU); -} - -static int -send_xml_dialog (pixma_t * s, const char * xml_message) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - int datalen; - - datalen = pixma_cmd_transaction (s, xml_message, strlen (xml_message), - mp->cb.buf, 1024); - if (datalen < 0) - return datalen; - - mp->cb.buf[datalen] = 0; - - PDBG (pixma_dbg (10, "XML message sent to scanner:\n%s\n", xml_message)); - PDBG (pixma_dbg (10, "XML response back from scanner:\n%s\n", mp->cb.buf)); - - return (strcasestr ((const char *) mp->cb.buf, XML_OK) != NULL); -} - -static void -new_cmd_tpu_msg (pixma_t *s, pixma_cmdbuf_t * cb, uint16_t cmd) -{ - pixma_newcmd (cb, cmd, 0, 0); - cb->buf[3] = (is_scanning_from_tpu (s)) ? 0x01 : 0x00; -} - -static int -start_session (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - - new_cmd_tpu_msg (s, &mp->cb, cmd_start_session); - return pixma_exec (s, &mp->cb); -} - -static int -start_scan_3 (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - - new_cmd_tpu_msg (s, &mp->cb, cmd_scan_start_3); - return pixma_exec (s, &mp->cb); -} - -static int -send_cmd_start_calibrate_ccd_3 (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - - pixma_newcmd (&mp->cb, cmd_start_calibrate_ccd_3, 0, 0); - mp->cb.buf[3] = 0x01; - return pixma_exec (s, &mp->cb); -} - -static int -is_calibrated (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - if (mp->generation >= 3) - { - return ((mp->current_status[0] & 0x01) == 1 || (mp->current_status[0] & 0x02) == 2); - } - if (mp->generation == 1) - { - return (mp->current_status[8] == 1); - } - else - { - return (mp->current_status[9] == 1); - } -} - -static int -has_paper (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - - if (is_scanning_from_adfdup (s)) - return (mp->current_status[1] == 0 || mp->current_status[2] == 0); - else - return (mp->current_status[1] == 0); -} - -static void -drain_bulk_in (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - while (pixma_read (s->io, mp->imgbuf, IMAGE_BLOCK_SIZE) >= 0); -} - -static int -abort_session (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - mp->adf_state = state_idle; /* reset adf scanning */ - return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); -} - -static int -send_cmd_e920 (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_e920); -} - -static int -select_source (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - uint8_t *data; - - data = pixma_newcmd (&mp->cb, cmd_select_source, 12, 0); - data[5] = ((mp->generation == 2) ? 1 : 0); - switch (s->param->source) - { - case PIXMA_SOURCE_FLATBED: - data[0] = 1; - data[1] = 1; - break; - - case PIXMA_SOURCE_ADF: - data[0] = 2; - data[5] = 1; - data[6] = 1; - break; - - case PIXMA_SOURCE_ADFDUP: - data[0] = 2; - data[5] = 3; - data[6] = 3; - break; - - case PIXMA_SOURCE_TPU: - data[0] = 4; - data[1] = 2; - break; - } - return pixma_exec (s, &mp->cb); -} - -static int -send_get_tpu_info_3 (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mp->cb, cmd_get_tpu_info_3, 0, 0x34); - RET_IF_ERR (pixma_exec (s, &mp->cb)); - memcpy (mp->tpu_data, data, 0x34); - return error; -} - -static int -send_set_tpu_info (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - uint8_t *data; - - if (mp->tpu_datalen == 0) - return 0; - data = pixma_newcmd (&mp->cb, cmd_set_tpu_info_3, 0x34, 0); - memcpy (data, mp->tpu_data, 0x34); - return pixma_exec (s, &mp->cb); -} - -static int -send_gamma_table (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - const uint8_t *lut = s->param->gamma_table; - uint8_t *data; - - if (mp->generation == 1) - { - data = pixma_newcmd (&mp->cb, cmd_gamma, 4096 + 8, 0); - data[0] = (s->param->channels == 3) ? 0x10 : 0x01; - pixma_set_be16 (0x1004, data + 2); - if (lut) - memcpy (data + 4, lut, 4096); - else - pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 4096); - } - else - { - /* FIXME: Gamma table for 2nd generation: 1024 * uint16_le */ - data = pixma_newcmd (&mp->cb, cmd_gamma, 2048 + 8, 0); - data[0] = 0x10; - pixma_set_be16 (0x0804, data + 2); - if (lut) - { - int i; - for (i = 0; i < 1024; i++) - { - int j = (i << 2) + (i >> 8); - data[4 + 2 * i + 0] = lut[j]; - data[4 + 2 * i + 1] = lut[j]; - } - } - else - { - int i; - pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 2048); - for (i = 0; i < 1024; i++) - { - int j = (i << 1) + (i >> 9); - data[4 + 2 * i + 0] = data[4 + j]; - data[4 + 2 * i + 1] = data[4 + j]; - } - } - } - return pixma_exec (s, &mp->cb); -} - -static unsigned -calc_raw_width (const mp150_t * mp, const pixma_scan_param_t * param) -{ - unsigned raw_width; - /* NOTE: Actually, we can send arbitary width to MP150. Lines returned - are always padded to multiple of 4 or 12 pixels. Is this valid for - other models, too? */ - if (mp->generation >= 2) - { - raw_width = ALIGN_SUP (param->w + param->xs, 32); - /* PDBG (pixma_dbg (4, "*calc_raw_width***** width %i extended by %i and rounded to %i *****\n", param->w, param->xs, raw_width)); */ - } - else if (param->channels == 1) - { - raw_width = ALIGN_SUP (param->w + param->xs, 12); - } - else - { - raw_width = ALIGN_SUP (param->w + param->xs, 4); - } - return raw_width; -} - -static int -has_ccd_sensor (pixma_t * s) -{ - return ((s->cfg->cap & PIXMA_CAP_CCD) != 0); -} - -static int -is_ccd_grayscale (pixma_t * s) -{ - return (has_ccd_sensor (s) && (s->param->channels == 1) && !s->param->software_lineart); -} - -static int -is_ccd_lineart (pixma_t * s) -{ - return (has_ccd_sensor (s) && s->param->software_lineart); -} - -/* CCD sensors don't have neither a Grayscale mode nor a Lineart mode, - * but use color mode instead */ -static unsigned -get_cis_ccd_line_size (pixma_t * s) -{ - return ((s->param->wx ? s->param->line_size / s->param->w * s->param->wx - : s->param->line_size) * ((is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 3 : 1)); -} - -static unsigned -calc_shifting (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - - /* If stripes shift needed (CCD devices), how many pixels shift */ - mp->stripe_shift = 0; - /* If color plane shift (CCD devices), how many pixels shift */ - mp->color_shift = mp->shift[0] = mp->shift[1] = mp->shift[2] = 0; - - switch (s->cfg->pid) - { - case MP800_PID: - case MP800R_PID: - case MP830_PID: - if (s->param->xdpi == 2400) - { - if (is_scanning_from_tpu(s)) - mp->stripe_shift = 6; - else - mp->stripe_shift = 3; - } - if (s->param->ydpi > 75) - { - mp->color_shift = s->param->ydpi / ((s->param->ydpi < 1200) ? 150 : 75); - - if (is_scanning_from_tpu (s)) - mp->color_shift = s->param->ydpi / 75; - - /* If you're trying to decipher this color-shifting code, - the following line is where the magic is revealed. */ - mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); - if (is_scanning_from_adf (s)) - { /* ADF */ - mp->shift[0] = 0; - mp->shift[2] = 2 * mp->shift[1]; - } - else - { /* Flatbed or TPU */ - mp->shift[0] = 2 * mp->shift[1]; - mp->shift[2] = 0; - } - } - break; - - default: /* Default, and all CIS devices */ - break; - } - return (2 * mp->color_shift + mp->stripe_shift); -} - -static int -send_scan_param (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - uint8_t *data; - unsigned raw_width = calc_raw_width (mp, s->param); - unsigned h = MIN (s->param->h + calc_shifting (s), - s->cfg->height * s->param->ydpi / 75); - - /* TPU scan does not support lineart */ - if (is_scanning_from_tpu (s) && is_ccd_lineart (s)) - { - return PIXMA_ENOTSUP; - } - - if (mp->generation <= 2) - { - /*PDBG (pixma_dbg (4, "*send_scan_param gen. 1-2 ***** Setting: xdpi=%hi ydpi=%hi x=%i y=%i w=%i ***** \n", - s->param->xdpi,s->param->ydpi,(s->param->x)-(s->param->xs),s->param->y,raw_width));*/ - data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x30, 0); - pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x04); - pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x06); - pixma_set_be32 (s->param->x, data + 0x08); - if (mp->generation == 2) - pixma_set_be32 (s->param->x - s->param->xs, data + 0x08); - pixma_set_be32 (s->param->y, data + 0x0c); - pixma_set_be32 (raw_width, data + 0x10); - pixma_set_be32 (h, data + 0x14); - data[0x18] = ((s->param->channels != 1) || is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 0x08 : 0x04; - data[0x19] = ((s->param->software_lineart) ? 8 : s->param->depth) - * ((is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 3 : s->param->channels); /* bits per pixel */ - data[0x1a] = (is_scanning_from_tpu (s) ? 1 : 0); - data[0x20] = 0xff; - data[0x23] = 0x81; - data[0x26] = 0x02; - data[0x27] = 0x01; - } - else - { - data = pixma_newcmd (&mp->cb, cmd_scan_param_3, 0x38, 0); - data[0x00] = (is_scanning_from_adf (s)) ? 0x02 : 0x01; - data[0x01] = 0x01; - if (is_scanning_from_tpu (s)) - { - data[0x00] = 0x04; - data[0x01] = 0x02; - data[0x1e] = 0x02; - } - data[0x02] = 0x01; - if (is_scanning_from_adfdup (s)) - { - data[0x02] = 0x03; - data[0x03] = 0x03; - } - if (is_scanning_jpeg (s)) - { - data[0x03] = 0x01; - } - else - { - data[0x05] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ - } - pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x08); - pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x0a); - /*PDBG (pixma_dbg (4, "*send_scan_param gen. 3+ ***** Setting: xdpi=%hi ydpi=%hi x=%i y=%i w=%i ***** \n", - s->param->xdpi,s->param->ydpi,(s->param->x)-(s->param->xs),s->param->y,raw_width));*/ - pixma_set_be32 (s->param->x - s->param->xs, data + 0x0c); - pixma_set_be32 (s->param->y, data + 0x10); - pixma_set_be32 (raw_width, data + 0x14); - pixma_set_be32 (h, data + 0x18); - data[0x1c] = ((s->param->channels != 1) || is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 0x08 : 0x04; - -#ifdef DEBUG_TPU_48 - data[0x1d] = 24; -#else - data[0x1d] = (is_scanning_from_tpu (s)) ? 48 - : (((s->param->software_lineart) ? 8 : s->param->depth) - * ((is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 3 : s->param->channels)); /* bits per pixel */ -#endif - - data[0x1f] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ - data[0x20] = 0xff; - if (is_scanning_jpeg (s)) - { - data[0x21] = 0x83; - } - else - { - data[0x21] = 0x81; - } - data[0x23] = 0x02; - data[0x24] = 0x01; - - switch (s->cfg->pid) - { - case MG5300_PID: - /* unknown values (perhaps counter) for MG5300 series---values must be 0x30-0x39: decimal 0-9 */ - data[0x26] = 0x32; /* using example values from a real scan here */ - data[0x27] = 0x31; - data[0x28] = 0x34; - data[0x29] = 0x35; - break; - - default: - break; - } - - data[0x30] = 0x01; - } - return pixma_exec (s, &mp->cb); -} - -static int -query_status_3 (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - uint8_t *data; - int error, status_len; - - status_len = 8; - data = pixma_newcmd (&mp->cb, cmd_status_3, 0, status_len); - RET_IF_ERR (pixma_exec (s, &mp->cb)); - memcpy (mp->current_status, data, status_len); - return error; -} - -static int -query_status (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - uint8_t *data; - int error, status_len; - - status_len = (mp->generation == 1) ? 12 : 16; - data = pixma_newcmd (&mp->cb, cmd_status, 0, status_len); - RET_IF_ERR (pixma_exec (s, &mp->cb)); - memcpy (mp->current_status, data, status_len); - PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u busy=%u\n", - data[1], data[8], data[7], data[9])); - return error; -} - -#if 0 -static int -send_time (pixma_t * s) -{ - /* Why does a scanner need a time? */ - time_t now; - struct tm *t; - uint8_t *data; - mp150_t *mp = (mp150_t *) s->subdriver; - - data = pixma_newcmd (&mp->cb, cmd_time, 20, 0); - pixma_get_time (&now, NULL); - t = localtime (&now); - snprintf ((char *) data, 16, - "%02d/%02d/%02d %02d:%02d", - t->tm_year % 100, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min); - PDBG (pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); - return pixma_exec (s, &mp->cb); -} -#endif - -/* TODO: Simplify this function. Read the whole data packet in one shot. */ -static int -read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) -{ - uint8_t cmd[16]; - mp150_t *mp = (mp150_t *) s->subdriver; - const int hlen = 8 + 8; - int error, datalen; - - memset (cmd, 0, sizeof (cmd)); - pixma_set_be16 (cmd_read_image, cmd); - if ((mp->last_block & 0x20) == 0) - pixma_set_be32 ((IMAGE_BLOCK_SIZE / 65536) * 65536 + 8, cmd + 0xc); - else - pixma_set_be32 (32 + 8, cmd + 0xc); - - mp->state = state_transfering; - mp->cb.reslen = - pixma_cmd_transaction (s, cmd, sizeof (cmd), mp->cb.buf, 512); - datalen = mp->cb.reslen; - if (datalen < 0) - return datalen; - - memcpy (header, mp->cb.buf, hlen); - - if (datalen >= hlen) - { - datalen -= hlen; - memcpy (data, mp->cb.buf + hlen, datalen); - data += datalen; - if (mp->cb.reslen == 512) - { - error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen); - RET_IF_ERR (error); - datalen += error; - } - } - - mp->state = state_scanning; - mp->cb.expected_reslen = 0; - RET_IF_ERR (pixma_check_result (&mp->cb)); - if (mp->cb.reslen < hlen) - return PIXMA_EPROTO; - return datalen; -} - -static int -read_error_info (pixma_t * s, void *buf, unsigned size) -{ - unsigned len = 16; - mp150_t *mp = (mp150_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); - RET_IF_ERR (pixma_exec (s, &mp->cb)); - if (buf && len < size) - { - size = len; - /* NOTE: I've absolutely no idea what the returned data mean. */ - memcpy (buf, data, size); - error = len; - } - return error; -} - -/* -handle_interrupt() waits until it receives an interrupt packet or times out. -It calls send_time() and query_status() if necessary. Therefore, make sure -that handle_interrupt() is only called from a safe context for send_time() -and query_status(). - - Returns: - 0 timed out - 1 an interrupt packet received - PIXMA_ECANCELED interrupted by signal - <0 error -*/ -static int -handle_interrupt (pixma_t * s, int timeout) -{ - uint8_t buf[64]; - int len; - - len = pixma_wait_interrupt (s->io, buf, sizeof (buf), timeout); - if (len == PIXMA_ETIMEDOUT) - return 0; - if (len < 0) - return len; - if (len%16) /* len must be a multiple of 16 bytes */ - { - PDBG (pixma_dbg - (1, "WARNING:unexpected interrupt packet length %d\n", len)); - return PIXMA_EPROTO; - } - - /* s->event = 0x0brroott - * b: button - * oo: original - * tt: target - * rr: scan resolution - * poll event with 'scanimage -A' */ - if (s->cfg->pid == MG5300_PID - || s->cfg->pid == MG5400_PID - || s->cfg->pid == MG6200_PID - || s->cfg->pid == MG6300_PID - || s->cfg->pid == MX520_PID - || s->cfg->pid == MX720_PID - || s->cfg->pid == MX920_PID - || s->cfg->pid == MB2300_PID - || s->cfg->pid == MB5000_PID) - /* button no. in buf[7] - * size in buf[10] 01=A4; 02=Letter; 08=10x15; 09=13x18; 0b=auto - * format in buf[11] 01=JPEG; 02=TIFF; 03=PDF; 04=Kompakt-PDF - * dpi in buf[12] 01=75; 02=150; 03=300; 04=600 - * target = format; original = size; scan-resolution = dpi */ - { - if (buf[7] & 1) - s->events = PIXMA_EV_BUTTON1 | buf[11] | buf[10]<<8 | buf[12]<<16; /* color scan */ - if (buf[7] & 2) - s->events = PIXMA_EV_BUTTON2 | buf[11] | buf[10]<<8 | buf[12]<<16; /* b/w scan */ - } - else if (s->cfg->pid == LIDE300_PID - || s->cfg->pid == LIDE400_PID) - /* unknown value in buf[4] - * target in buf[0x13] - * always set button-1 */ - { - if (buf[0x13]) - s->events = PIXMA_EV_BUTTON1 | buf[0x13]; - } - else - /* button no. in buf[0] - * original in buf[0] - * target in buf[1] */ - { - /* More than one event can be reported at the same time. */ - if (buf[3] & 1) - /* FIXME: This function makes trouble with a lot of scanners - send_time (s); - */ - PDBG (pixma_dbg (1, "WARNING:send_time() disabled!\n")); - if (buf[9] & 2) - query_status (s); - if (buf[0] & 2) - s->events = PIXMA_EV_BUTTON2 | buf[1] | ((buf[0] & 0xf0) << 4); /* b/w scan */ - if (buf[0] & 1) - s->events = PIXMA_EV_BUTTON1 | buf[1] | ((buf[0] & 0xf0) << 4); /* color scan */ - } - return 1; -} - -static int -init_ccd_lamp_3 (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - uint8_t *data; - int error, status_len, tmo; - - status_len = 8; - RET_IF_ERR (query_status (s)); - RET_IF_ERR (query_status (s)); - RET_IF_ERR (send_cmd_start_calibrate_ccd_3 (s)); - RET_IF_ERR (query_status (s)); - tmo = 20; /* like Windows driver, CCD lamp adjustment */ - while (--tmo >= 0) - { - data = pixma_newcmd (&mp->cb, cmd_end_calibrate_ccd_3, 0, status_len); - RET_IF_ERR (pixma_exec (s, &mp->cb)); - memcpy (mp->current_status, data, status_len); - PDBG (pixma_dbg (3, "Lamp status: %u , timeout in: %u\n", data[0], tmo)); - if (mp->current_status[0] == 3 || !is_scanning_from_tpu (s)) - break; - WAIT_INTERRUPT (1000); - } - return error; -} - -static int -wait_until_ready (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - int error, tmo = 120; /* some scanners need a long timeout */ - - RET_IF_ERR ((mp->generation >= 3) ? query_status_3 (s) - : query_status (s)); - while (!is_calibrated (s)) - { - WAIT_INTERRUPT (1000); - if (mp->generation >= 3) - RET_IF_ERR (query_status_3 (s)); - else if (s->cfg->pid == MP600_PID || - s->cfg->pid == MP600R_PID || - s->cfg->pid == MP800R_PID) - RET_IF_ERR (query_status (s)); - if (--tmo == 0) - { - PDBG (pixma_dbg (1, "WARNING:Timed out in wait_until_ready()\n")); - PDBG (query_status (s)); - return PIXMA_ETIMEDOUT; - } - } - return 0; -} - -static uint8_t * -shift_colors (uint8_t * dptr, uint8_t * sptr, - unsigned w, unsigned dpi, unsigned pid, unsigned c, - int * colshft, unsigned strshft) -{ - unsigned i, sr, sg, sb, st; - UNUSED(dpi); - UNUSED(pid); - sr = colshft[0]; sg = colshft[1]; sb = colshft[2]; - for (i = 0; i < w; i++) - { - /* stripes shift for MP800, MP800R at 2400 dpi */ - st = (i % 2 == 0) ? strshft : 0; - - *sptr++ = *(dptr++ + sr + st); - if (c == 6) *sptr++ = *(dptr++ + sr + st); - *sptr++ = *(dptr++ + sg + st); - if (c == 6) *sptr++ = *(dptr++ + sg + st); - *sptr++ = *(dptr++ + sb + st); - if (c == 6) *sptr++ = *(dptr++ + sb + st); - } - return dptr; -} - -static void -reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, unsigned n, - unsigned m, unsigned w, unsigned line_size) -{ - unsigned i; - - for (i = 0; i < w; i++) - { - memcpy (linebuf + c * (n * (i % m) + i / m), sptr + c * i, c); - } - memcpy (sptr, linebuf, line_size); -} - -#ifndef TPU_48 -static unsigned -pack_48_24_bpc (uint8_t * sptr, unsigned n) -{ - unsigned i; - uint8_t *cptr, lsb; - static uint8_t offset = 0; - - cptr = sptr; - if (n % 2 != 0) - PDBG (pixma_dbg (3, "WARNING: misaligned image.\n")); - for (i = 0; i < n; i += 2) - { - /* offset = 1 + (offset % 3); */ - lsb = *sptr++; - *cptr++ = ((*sptr++) << offset) | lsb >> (8 - offset); - } - return (n / 2); -} -#endif - -/* This function deals both with PIXMA CCD sensors producing shifted color - * planes images, Grayscale CCD scan and Generation >= 3 high dpi images. - * Each complete line in mp->imgbuf is processed for shifting CCD sensor - * color planes, reordering pixels above 600 dpi for Generation >= 3, and - * converting to Grayscale for CCD sensors. */ -static unsigned -post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - unsigned c, lines, line_size, n, m, cw, cx; - uint8_t *sptr, *dptr, *gptr, *cptr; - - if (s->param->mode_jpeg) - { - /* No post-processing, send raw JPEG data to main */ - ib->rptr = mp->imgbuf; - ib->rend = mp->data_left_ofs; - return 0; /* # of non processed bytes */ - } - - - c = ((is_ccd_grayscale (s) || is_ccd_lineart (s)) ? 3 : s->param->channels) - * ((s->param->software_lineart) ? 8 : s->param->depth) / 8; - cw = c * s->param->w; - cx = c * s->param->xs; - - if (mp->generation >= 3) - n = s->param->xdpi / 600; - else /* FIXME: maybe need different values for CIS and CCD sensors */ - n = s->param->xdpi / 2400; - - if (s->cfg->pid == MP600_PID || s->cfg->pid == MP600R_PID) - n = s->param->xdpi / 1200; - - m = (n > 0) ? s->param->wx / n : 1; - sptr = dptr = gptr = cptr = mp->imgbuf; - line_size = get_cis_ccd_line_size (s); - /*PDBG (pixma_dbg (4, "*post_process_image_data***** ----- Set n=%u, m=%u, line_size=%u ----- ***** \n", n, m, line_size));*/ - - lines = (mp->data_left_ofs - mp->imgbuf) / line_size; - /*PDBG (pixma_dbg (4, "*post_process_image_data***** lines = %i > 2 * mp->color_shift + mp->stripe_shift = %i ***** \n", - lines, 2 * mp->color_shift + mp->stripe_shift));*/ - if (lines > 2 * mp->color_shift + mp->stripe_shift) - { - unsigned i; - - lines -= 2 * mp->color_shift + mp->stripe_shift; - for (i = 0; i < lines; i++, sptr += line_size) - { - /* Color plane and stripes shift needed by e.g. CCD */ - /*PDBG (pixma_dbg (4, "*post_process_image_data***** Processing with c=%u, n=%u, m=%u, w=%i, line_size=%u ***** \n", - c, n, m, s->param->wx, line_size));*/ - if (s->cfg->pid != MG5300_PID && s->cfg->pid != MG6300_PID && c >= 3) - dptr = shift_colors (dptr, sptr, - s->param->wx, s->param->xdpi, s->cfg->pid, c, - mp->shift, mp->stripe_shift); - - /* special image format for *most* devices at high dpi. - * MP220, MX360 and generation 5 scanners are exceptions */ - if (n > 0 - && s->cfg->pid != MP220_PID - && s->cfg->pid != MP490_PID - && s->cfg->pid != MX360_PID - && (mp->generation < 5 - /* generation 5 scanners *with* special image format */ - || s->cfg->pid == MG2200_PID - || s->cfg->pid == MG3200_PID - || s->cfg->pid == MG4200_PID - || s->cfg->pid == MG5600_PID - || s->cfg->pid == MG5700_PID - || s->cfg->pid == MG6200_PID - || s->cfg->pid == MP230_PID - || s->cfg->pid == MX470_PID - || s->cfg->pid == MX510_PID - || s->cfg->pid == MX520_PID)) - reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, line_size); - - /* Crop line to selected borders */ - memmove(cptr, sptr + cx, cw); - - /* Color / Gray to Lineart convert */ - if (s->param->software_lineart) - cptr = gptr = pixma_binarize_line (s->param, gptr, cptr, s->param->w, c); - /* Color to Grayscale convert for CCD sensor */ - else if (is_ccd_grayscale (s)) - cptr = gptr = pixma_rgb_to_gray (gptr, cptr, s->param->w, c); - else - cptr += cw; - } - } - ib->rptr = mp->imgbuf; - ib->rend = cptr; - return mp->data_left_ofs - sptr; /* # of non processed bytes */ -} - -static int -mp150_open (pixma_t * s) -{ - mp150_t *mp; - uint8_t *buf; - - mp = (mp150_t *) calloc (1, sizeof (*mp)); - if (!mp) - return PIXMA_ENOMEM; - - buf = (uint8_t *) malloc (CMDBUF_SIZE + IMAGE_BLOCK_SIZE); - if (!buf) - { - free (mp); - return PIXMA_ENOMEM; - } - - s->subdriver = mp; - mp->state = state_idle; - - mp->cb.buf = buf; - mp->cb.size = CMDBUF_SIZE; - mp->cb.res_header_len = 8; - mp->cb.cmd_header_len = 16; - mp->cb.cmd_len_field_ofs = 14; - - mp->imgbuf = buf + CMDBUF_SIZE; - - /* General rules for setting Pixma protocol generation # */ - mp->generation = (s->cfg->pid >= MP160_PID) ? 2 : 1; - - if (s->cfg->pid >= MX7600_PID) - mp->generation = 3; - - if (s->cfg->pid >= MP250_PID) - mp->generation = 4; - - if (s->cfg->pid >= MG2100_PID) /* this scanners generation doesn't need */ - mp->generation = 5; /* special image conversion @ high dpi */ - - /* And exceptions to be added here */ - if (s->cfg->pid == MP140_PID) - mp->generation = 2; - - PDBG (pixma_dbg (3, "*mp150_open***** This is a generation %d scanner. *****\n", mp->generation)); - - /* TPU info data setup */ - mp->tpu_datalen = 0; - - /* adf scanning */ - mp->adf_state = state_idle; - - if (mp->generation < 4) - { - query_status (s); - handle_interrupt (s, 200); - if (mp->generation == 3 && has_ccd_sensor (s)) - send_cmd_start_calibrate_ccd_3 (s); - } - return 0; -} - -static void -mp150_close (pixma_t * s) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - - mp150_finish_scan (s); - free (mp->cb.buf); - free (mp); - s->subdriver = NULL; -} - -static int -mp150_check_param (pixma_t * s, pixma_scan_param_t * sp) -{ - mp150_t *mp = (mp150_t *) s->subdriver; - - /* PDBG (pixma_dbg (4, "*mp150_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", - sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */ - - /* MP150 only supports 8 bit per channel in color and grayscale mode */ - if (sp->depth != 1) - { - sp->software_lineart = 0; - sp->depth = 8; -#ifdef TPU_48 -#ifndef DEBUG_TPU_48 - if (sp->source == PIXMA_SOURCE_TPU) -#endif - sp->depth = 16; /* TPU in 16 bits mode */ -#endif - } - else - { - /* software lineart */ - sp->software_lineart = 1; - sp->depth = 1; - sp->channels = 1; - } - - /* for software lineart w must be a multiple of 8 */ - if (sp->software_lineart == 1 && sp->w % 8) - { - unsigned w_max; - - sp->w += 8 - (sp->w % 8); - - /* do not exceed the scanner capability */ - w_max = s->cfg->width * s->cfg->xdpi / 75; - w_max -= w_max % 8; - if (sp->w > w_max) - sp->w = w_max; - } - - if (mp->generation >= 2) - { - /* mod 32 and expansion of the X scan limits */ - /*PDBG (pixma_dbg (4, "*mp150_check_param***** ----- Initially: x=%i, y=%i, w=%i, h=%i *****\n", sp->x, sp->y, sp->w, sp->h));*/ - sp->xs = (sp->x) % 32; - } - else - sp->xs = 0; - /*PDBG (pixma_dbg (4, "*mp150_check_param***** Selected origin, origin shift: %i, %i *****\n", sp->x, sp->xs));*/ - sp->wx = calc_raw_width (mp, sp); - sp->line_size = sp->w * sp->channels * (((sp->software_lineart) ? 8 : sp->depth) / 8); /* bytes per line per color after cropping */ - /*PDBG (pixma_dbg (4, "*mp150_check_param***** Final scan width and line-size: %i, %i *****\n", sp->wx, sp->line_size));*/ - - /* Some exceptions here for particular devices */ - /* Those devices can scan up to legal 14" with ADF, but A4 11.7" in flatbed */ - /* PIXMA_CAP_ADF also works for PIXMA_CAP_ADFDUP */ - if ((s->cfg->cap & PIXMA_CAP_ADF) && sp->source == PIXMA_SOURCE_FLATBED) - sp->h = MIN (sp->h, 877 * sp->xdpi / 75); - - if (sp->source == PIXMA_SOURCE_TPU - || s->cfg->pid == LIDE300_PID - || s->cfg->pid == LIDE400_PID) - { - uint8_t k; - - /* TPU mode: lowest res is 150 or 300 dpi */ - if (mp->generation >= 3) - k = MAX (sp->xdpi, 300) / sp->xdpi; - else - k = MAX (sp->xdpi, 150) / sp->xdpi; - sp->x *= k; - sp->xs *= k; - sp->y *= k; - sp->w *= k; - sp->wx *= k; - sp->h *= k; - sp->xdpi *= k; - sp->ydpi = sp->xdpi; - } - - if (sp->source == PIXMA_SOURCE_ADF || sp->source == PIXMA_SOURCE_ADFDUP) - { - uint8_t k = 1; - - /* ADF/ADF duplex mode: max scan res is 600 dpi, at least for generation 4+ */ - if (mp->generation >= 4) - k = sp->xdpi / MIN (sp->xdpi, 600); - sp->x /= k; - sp->xs /= k; - sp->y /= k; - sp->w /= k; - sp->wx /= k; - sp->h /= k; - sp->xdpi /= k; - sp->ydpi = sp->xdpi; - } - - sp->mode_jpeg = (s->cfg->cap & PIXMA_CAP_ADF_JPEG) && - (sp->source == PIXMA_SOURCE_ADF || - sp->source == PIXMA_SOURCE_ADFDUP); - - /*PDBG (pixma_dbg (4, "*mp150_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", - sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx));*/ - return 0; -} - -static int -mp150_scan (pixma_t * s) -{ - int error = 0, tmo; - mp150_t *mp = (mp150_t *) s->subdriver; - - if (mp->state != state_idle) - return PIXMA_EBUSY; - - /* no paper inserted after first adf page => abort session */ - if (s->param->adf_pageid && is_scanning_from_adf(s) && mp->adf_state == state_idle) - { - return PIXMA_ENO_PAPER; - } - - /* Generation 4+: send XML dialog */ - /* adf: first page or idle */ - if (mp->generation >= 4 && mp->adf_state == state_idle) - { - if (!send_xml_dialog (s, XML_START_1)) - return PIXMA_EPROTO; - if (!send_xml_dialog (s, XML_START_2)) - return PIXMA_EPROTO; - } - - /* clear interrupt packets buffer */ - while (handle_interrupt (s, 0) > 0) - { - } - - /* FIXME: Duplex ADF: check paper status only before odd pages (1,3,5,...). */ - if (is_scanning_from_adf (s)) - { - if ((error = query_status (s)) < 0) - return error; - - /* wait for inserted paper - * timeout: 10 sec */ - tmo = 10; - while (!has_paper (s) && --tmo >= 0) - { - if ((error = query_status (s)) < 0) - return error; - WAIT_INTERRUPT (1000); - PDBG (pixma_dbg - (2, "No paper in ADF. Timed out in %d sec.\n", tmo)); - } - - /* no paper inserted - * => abort session */ - if (!has_paper (s)) - { - PDBG (pixma_dbg (4, "*mp150_scan***** no paper in ADF *****\n")); - error = abort_session (s); - if (error < 0) - return error; - - /* Generation 4+: send XML dialog */ - /* adf: first page or idle */ - if (mp->generation >= 4 && mp->adf_state == state_idle) - { - if (!send_xml_dialog (s, XML_END)) - return PIXMA_EPROTO; - } - - return PIXMA_ENO_PAPER; - } - } - - if (has_ccd_sensor (s) && (mp->generation <= 2)) - { - error = send_cmd_e920 (s); - switch (error) - { - case PIXMA_ECANCELED: - case PIXMA_EBUSY: - PDBG (pixma_dbg (2, "cmd e920 or d520 returned %s\n", - pixma_strerror (error))); - /* fall through */ - case 0: - query_status (s); - break; - default: - PDBG (pixma_dbg (1, "WARNING:cmd e920 or d520 failed %s\n", - pixma_strerror (error))); - return error; - } - tmo = 3; /* like Windows driver, CCD calibration ? */ - while (--tmo >= 0) - { - WAIT_INTERRUPT (1000); - PDBG (pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo)); - } - /* pixma_sleep(2000000); */ - } - - tmo = 10; - /* adf: first page or idle */ - if (mp->generation <= 2 || mp->adf_state == state_idle) - { /* single sheet or first sheet from ADF */ - PDBG (pixma_dbg (4, "*mp150_scan***** start scanning *****\n")); - error = start_session (s); - while (error == PIXMA_EBUSY && --tmo >= 0) - { - if (s->cancel) - { - error = PIXMA_ECANCELED; - break; - } - PDBG (pixma_dbg - (2, "Scanner is busy. Timed out in %d sec.\n", tmo + 1)); - pixma_sleep (1000000); - error = start_session (s); - } - if (error == PIXMA_EBUSY || error == PIXMA_ETIMEDOUT) - { - /* The scanner maybe hangs. We try to empty output buffer of the - * scanner and issue the cancel command. */ - PDBG (pixma_dbg (2, "Scanner hangs? Sending abort_session command.\n")); - drain_bulk_in (s); - abort_session (s); - pixma_sleep (500000); - error = start_session (s); - } - if ((error >= 0) || (mp->generation >= 3)) - mp->state = state_warmup; - if ((error >= 0) && (mp->generation <= 2)) - error = select_source (s); - if ((error >= 0) && (mp->generation >= 3) && has_ccd_sensor (s)) - error = init_ccd_lamp_3 (s); - if ((error >= 0) && !is_scanning_from_tpu (s) && !is_scanning_jpeg (s)) - { - int i; - - for (i = (mp->generation >= 3) ? 3 : 1 ; i > 0 && error >= 0; i--) - error = send_gamma_table (s); - } - else if (error >= 0) /* in TPU mode, for gen 1, 2, and 3 */ - error = send_set_tpu_info (s); - } - else /* ADF pageid != 0 and gen3 or above */ - { /* next sheet from ADF */ - PDBG (pixma_dbg (4, "*mp150_scan***** scan next sheet from ADF *****\n")); - pixma_sleep (1000000); - } - if ((error >= 0) || (mp->generation >= 3)) - mp->state = state_warmup; - if (error >= 0) - error = send_scan_param (s); - if ((error >= 0) && (mp->generation >= 3)) - error = start_scan_3 (s); - if (error < 0) - { - mp->last_block = 0x38; /* Force abort session if ADF scan */ - mp150_finish_scan (s); - return error; - } - - /* ADF scanning active */ - if (is_scanning_from_adf (s)) - mp->adf_state = state_scanning; - return 0; -} - -static int -mp150_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) -{ - int error; - mp150_t *mp = (mp150_t *) s->subdriver; - unsigned block_size, bytes_received, proc_buf_size, line_size; - uint8_t header[16]; - - if (mp->state == state_warmup) - { - RET_IF_ERR (wait_until_ready (s)); - pixma_sleep (1000000); /* No need to sleep, actually, but Window's driver - * sleep 1.5 sec. */ - mp->state = state_scanning; - mp->last_block = 0; - - line_size = get_cis_ccd_line_size (s); - proc_buf_size = (2 * calc_shifting (s) + 2) * line_size; - mp->cb.buf = realloc (mp->cb.buf, - CMDBUF_SIZE + IMAGE_BLOCK_SIZE + proc_buf_size); - if (!mp->cb.buf) - return PIXMA_ENOMEM; - mp->linebuf = mp->cb.buf + CMDBUF_SIZE; - mp->imgbuf = mp->data_left_ofs = mp->linebuf + line_size; - mp->data_left_len = 0; - } - - do - { - if (s->cancel) - { - PDBG (pixma_dbg (4, "*mp150_fill_buffer***** s->cancel *****\n")); - return PIXMA_ECANCELED; - } - if ((mp->last_block & 0x28) == 0x28) - { /* end of image */ - PDBG (pixma_dbg (4, "*mp150_fill_buffer***** end of image *****\n")); - mp->state = state_finished; - return 0; - } - /*PDBG (pixma_dbg (4, "*mp150_fill_buffer***** moving %u bytes into buffer *****\n", mp->data_left_len));*/ - memmove (mp->imgbuf, mp->data_left_ofs, mp->data_left_len); - error = read_image_block (s, header, mp->imgbuf + mp->data_left_len); - if (error < 0) - { - PDBG (pixma_dbg (4, "*mp150_fill_buffer***** scanner error (%d): end scan *****\n", error)); - mp->last_block = 0x38; /* end scan in mp150_finish_scan() */ - if (error == PIXMA_ECANCELED) - { - /* NOTE: I see this in traffic logs but I don't know its meaning. */ - read_error_info (s, NULL, 0); - } - return error; - } - - bytes_received = error; - /*PDBG (pixma_dbg (4, "*mp150_fill_buffer***** %u bytes received by read_image_block *****\n", bytes_received));*/ - block_size = pixma_get_be32 (header + 12); - mp->last_block = header[8] & 0x38; - if ((header[8] & ~0x38) != 0) - { - PDBG (pixma_dbg (1, "WARNING: Unexpected result header\n")); - PDBG (pixma_hexdump (1, header, 16)); - } - PASSERT (bytes_received == block_size); - - if (block_size == 0) - { /* no image data at this moment. */ - pixma_sleep (10000); - } - /* For TPU at 48 bits/pixel to output at 24 bits/pixel */ -#ifndef DEBUG_TPU_48 -#ifndef TPU_48 -#ifndef DEBUG_TPU_24 - if (is_scanning_from_tpu (s)) -#endif - bytes_received = pack_48_24_bpc (mp->imgbuf + mp->data_left_len, bytes_received); -#endif -#endif - /* Post-process the image data */ - mp->data_left_ofs = mp->imgbuf + mp->data_left_len + bytes_received; - mp->data_left_len = post_process_image_data (s, ib); - mp->data_left_ofs -= mp->data_left_len; - } - while (ib->rend == ib->rptr); - - return ib->rend - ib->rptr; -} - -static void -mp150_finish_scan (pixma_t * s) -{ - int error; - mp150_t *mp = (mp150_t *) s->subdriver; - - switch (mp->state) - { - case state_transfering: - drain_bulk_in (s); - /* fall through */ - case state_scanning: - case state_warmup: - case state_finished: - /* Send the get TPU info message */ - if (is_scanning_from_tpu (s) && mp->tpu_datalen == 0) - send_get_tpu_info_3 (s); - /* FIXME: to process several pages ADF scan, must not send - * abort_session and start_session between pages (last_block=0x28) */ - if (mp->generation <= 2 || !is_scanning_from_adf (s) || mp->last_block == 0x38) - { - PDBG (pixma_dbg (4, "*mp150_finish_scan***** abort session *****\n")); - error = abort_session (s); /* FIXME: it probably doesn't work in duplex mode! */ - if (error < 0) - PDBG (pixma_dbg (1, "WARNING:abort_session() failed %d\n", error)); - - /* Generation 4+: send XML end of scan dialog */ - if (mp->generation >= 4) - { - if (!send_xml_dialog (s, XML_END)) - PDBG (pixma_dbg (1, "WARNING:XML_END dialog failed \n")); - } - } - else - PDBG (pixma_dbg (4, "*mp150_finish_scan***** wait for next page from ADF *****\n")); - - mp->state = state_idle; - /* fall through */ - case state_idle: - break; - } -} - -static void -mp150_wait_event (pixma_t * s, int timeout) -{ - /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for - * instance. */ - while (s->events == 0 && handle_interrupt (s, timeout) > 0) - { - } -} - -static int -mp150_get_status (pixma_t * s, pixma_device_status_t * status) -{ - int error; - - RET_IF_ERR (query_status (s)); - status->hardware = PIXMA_HARDWARE_OK; - status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; - status->cal = - (is_calibrated (s)) ? PIXMA_CALIBRATION_OK : PIXMA_CALIBRATION_OFF; - return 0; -} - -static const pixma_scan_ops_t pixma_mp150_ops = { - mp150_open, - mp150_close, - mp150_scan, - mp150_fill_buffer, - mp150_finish_scan, - mp150_wait_event, - mp150_check_param, - mp150_get_status -}; - -#define DEVICE(name, model, pid, dpi, adftpu_min_dpi, adftpu_max_dpi, w, h, cap) { \ - name, /* name */ \ - model, /* model */ \ - CANON_VID, pid, /* vid pid */ \ - 0, /* iface */ \ - &pixma_mp150_ops, /* ops */ \ - dpi, 2*(dpi), /* xdpi, ydpi */ \ - adftpu_min_dpi, adftpu_max_dpi, /* adftpu_min_dpi, adftpu_max_dpi */ \ - 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ - w, h, /* width, height */ \ - PIXMA_CAP_EASY_RGB| \ - PIXMA_CAP_GRAY| /* CIS with native grayscale and CCD with software grayscale */ \ - PIXMA_CAP_LINEART| /* all scanners with software lineart */ \ - PIXMA_CAP_GAMMA_TABLE|PIXMA_CAP_EVENTS|cap \ -} - -#define END_OF_DEVICE_LIST DEVICE(NULL, NULL, 0, 0, 0, 0, 0, 0, 0) - -const pixma_config_t pixma_mp150_devices[] = { - /* Generation 1: CIS */ - DEVICE ("Canon PIXMA MP150", "MP150", MP150_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP170", "MP170", MP170_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP450", "MP450", MP450_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP500", "MP500", MP500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP530", "MP530", MP530_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - - /* Generation 1: CCD */ - DEVICE ("Canon PIXMA MP800", "MP800", MP800_PID, 2400, 150, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - DEVICE ("Canon PIXMA MP800R", "MP800R", MP800R_PID, 2400, 150, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - DEVICE ("Canon PIXMA MP830", "MP830", MP830_PID, 2400, 150, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_ADFDUP), - - /* Generation 2: CIS */ - DEVICE ("Canon PIXMA MP140", "MP140", MP140_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP160", "MP160", MP160_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP180", "MP180", MP180_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP460", "MP460", MP460_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP510", "MP510", MP510_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP600", "MP600", MP600_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP600R", "MP600R", MP600R_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Generation 3: CIS */ - DEVICE ("Canon PIXMA MP210", "MP210", MP210_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP220", "MP220", MP220_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP470", "MP470", MP470_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP520", "MP520", MP520_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP610", "MP610", MP610_PID, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), - - DEVICE ("Canon PIXMA MX300", "MX300", MX300_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MX310", "MX310", MX310_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX700", "MX700", MX700_PID, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX850", "MX850", MX850_PID, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon PIXMA MX7600", "MX7600", MX7600_PID, 4800, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - - DEVICE ("Canon PIXMA MP630", "MP630", MP630_PID, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP620", "MP620", MP620_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP540", "MP540", MP540_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP480", "MP480", MP480_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP240", "MP240", MP240_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP260", "MP260", MP260_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP190", "MP190", MP190_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* PIXMA 2009 vintage */ - DEVICE ("Canon PIXMA MX320", "MX320", MX320_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX330", "MX330", MX330_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX860", "MX860", MX860_PID, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), -/* width and height adjusted to flatbed size 21.8 x 30.2 cm^2 respective - * Not sure if anything's going wrong here, leaving as is - DEVICE ("Canon PIXMA MX860", "MX860", MX860_PID, 2400, 0, 0, 638, 880, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP),*/ - - /* PIXMA 2010 vintage */ - DEVICE ("Canon PIXMA MX340", "MX340", MX340_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX350", "MX350", MX350_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX870", "MX870", MX870_PID, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - - /* PIXMA 2011 vintage */ - DEVICE ("Canon PIXMA MX360", "MX360", MX360_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX410", "MX410", MX410_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX420", "MX420", MX420_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX880 Series", "MX880", MX880_PID, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - - /* Generation 4: CIS */ - DEVICE ("Canon PIXMA MP640", "MP640", MP640_PID, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP560", "MP560", MP560_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP550", "MP550", MP550_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP490", "MP490", MP490_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP250", "MP250", MP250_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP270", "MP270", MP270_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2010) Generation 4 CIS/CCD */ - DEVICE ("Canon PIXMA MP280", "MP280", MP280_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), /* TODO: 1200dpi doesn't work yet */ - DEVICE ("Canon PIXMA MP495", "MP495", MP495_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG5100", "MG5100", MG5100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG5200", "MG5200", MG5200_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG6100", "MG6100", MG6100_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2011) Generation 5 CIS/CCD */ - DEVICE ("Canon PIXMA MG2100", "MG2100", MG2100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG3100", "MG3100", MG3100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG4100", "MG4100", MG4100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG5300", "MG5300", MG5300_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG6200", "MG6200", MG6200_PID, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MP493", "MP493", MP493_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA E500", "E500", E500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2012) Generation 5 CIS */ - DEVICE ("Canon PIXMA MX370 Series", "MX370", MX370_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX430 Series", "MX430", MX430_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX510 Series", "MX510", MX510_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX710 Series", "MX710", MX710_PID, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon PIXMA MX890 Series", "MX890", MX890_PID, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon PIXMA E600 Series", "E600", E600_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MG4200", "MG4200", MG4200_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2013) Generation 5 CIS */ - DEVICE ("Canon PIXMA E510", "E510", E510_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA E610", "E610", E610_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MP230", "MP230", MP230_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG2200 Series", "MG2200", MG2200_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG3200 Series", "MG3200", MG3200_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG5400 Series", "MG5400", MG5400_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG6300 Series", "MG6300", MG6300_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MX390 Series", "MX390", MX390_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX450 Series", "MX450", MX450_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX520 Series", "MX520", MX520_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX720 Series", "MX720", MX720_PID, 2400, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon PIXMA MX920 Series", "MX920", MX920_PID, 2400, 0, 600, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon PIXMA MG2400 Series", "MG2400", MG2400_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG2500 Series", "MG2500", MG2500_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG3500 Series", "MG3500", MG3500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG5500 Series", "MG5500", MG5500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG6400 Series", "MG6400", MG6400_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG6500 Series", "MG6500", MG6500_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG7100 Series", "MG7100", MG7100_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2014) Generation 5 CIS */ - DEVICE ("Canon PIXMA MX470 Series", "MX470", MX470_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MX530 Series", "MX530", MX530_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon MAXIFY MB5000 Series", "MB5000", MB5000_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon MAXIFY MB5300 Series", "MB5300", MB5300_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon MAXIFY MB2000 Series", "MB2000", MB2000_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon MAXIFY MB2100 Series", "MB2100", MB2100_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), - DEVICE ("Canon MAXIFY MB2300 Series", "MB2300", MB2300_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon MAXIFY MB2700 Series", "MB2700", MB2700_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF | PIXMA_CAP_ADF_JPEG), - DEVICE ("Canon PIXMA E400", "E400", E400_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA E560", "E560", E560_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG7500 Series", "MG7500", MG7500_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG6600 Series", "MG6600", MG6600_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG5600 Series", "MG5600", MG5600_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG2900 Series", "MG2900", MG2900_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA E460 Series", "E460", E460_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2015) Generation 5 CIS */ - DEVICE ("Canon PIXMA MX490 Series", "MX490", MX490_PID, 600, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA E480 Series", "E480", E480_PID, 600, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MG3600 Series", "MG3600", MG3600_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG7700 Series", "MG7700", MG7700_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG6900 Series", "MG6900", MG6900_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG6800 Series", "MG6800", MG6800_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG5700 Series", "MG5700", MG5700_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2016) Generation 5 CIS */ - DEVICE ("Canon PIXMA G3000", "G3000", G3000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA G2000", "G2000", G2000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS9000 Series", "TS9000", TS9000_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS8000 Series", "TS8000", TS8000_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS6000 Series", "TS6000", TS6000_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS5000 Series", "TS5000", TS5000_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA MG3000 Series", "MG3000", MG3000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA E470 Series", "E470", E470_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA E410 Series", "E410", E410_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2017) Generation 5 CIS */ - DEVICE ("Canon PIXMA G4000", "G4000", G4000_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS6100 Series", "TS6100", TS6100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS5100 Series", "TS5100", TS5100_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS3100 Series", "TS3100", TS3100_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA E3100 Series", "E3100", E3100_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2018) Generation 5 CIS */ - DEVICE ("Canon MAXIFY MB5400 Series", "MB5400", MB5400_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon MAXIFY MB5100 Series", "MB5100", MB5100_PID, 1200, 0, 0, 638, 1050, PIXMA_CAP_CIS | PIXMA_CAP_ADFDUP), - DEVICE ("Canon PIXMA TS9100 Series", "TS9100", TS9100_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TR8500 Series", "TR8500", TR8500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA TR7500 Series", "TR7500", TR7500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA TS9500 Series", "TS9500", TS9500_PID, 1200, 0, 600, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("CanoScan LiDE 400", "LIDE400", LIDE400_PID, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("CanoScan LiDE 300", "LIDE300", LIDE300_PID, 4800, 0, 0, 638, 877, PIXMA_CAP_CIS), - - /* Latest devices (2019) Generation 5 CIS */ - DEVICE ("Canon PIXMA TS8100 Series", "TS8100", TS8100_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA G3010 Series", "G3010", G3010_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA G4010 Series", "G4010", G4010_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA TS9180 Series", "TS9180", TS9180_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS8180 Series", "TS8180", TS8180_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS6180 Series", "TS6180", TS6180_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TR8580 Series", "TR8580", TR8580_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA TS8130 Series", "TS8130", TS8130_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS6130 Series", "TS6130", TS6130_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TR8530 Series", "TR8530", TR8530_PID, 2400, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA TR7530 Series", "TR7530", TR7530_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXUS XK50 Series", "XK50", XK50_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXUS XK70 Series", "XK70", XK70_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TR4500 Series", "TR4500", TR4500_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA E4200 Series", "E4200", E4200_PID, 600, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA TS6200 Series", "TS6200", TS6200_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS6280 Series", "TS6280", TS6280_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS6230 Series", "TS6230", TS6230_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS8200 Series", "TS8200", TS8200_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS8280 Series", "TS8280", TS8280_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS8230 Series", "TS8230", TS8230_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - DEVICE ("Canon PIXMA TS9580 Series", "TS9580", TS9580_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA TR9530 Series", "TR9530", TR9530_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS | PIXMA_CAP_ADF), - DEVICE ("Canon PIXUS XK80 Series", "XK80", XK80_PID, 1200, 0, 0, 638, 877, PIXMA_CAP_CIS), - - END_OF_DEVICE_LIST -}; diff --git a/backend/pixma_mp730.c b/backend/pixma_mp730.c deleted file mode 100644 index c801daa..0000000 --- a/backend/pixma_mp730.c +++ /dev/null @@ -1,848 +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 -#include /* localtime(C90) */ - -#include "pixma_rename.h" -#include "pixma_common.h" -#include "pixma_io.h" - - -#ifdef __GNUC__ -# define UNUSED(v) (void) v -#else -# define UNUSED(v) -#endif - -#define IMAGE_BLOCK_SIZE (0xc000) -#define CMDBUF_SIZE 512 - -#define MP10_PID 0x261f - -#define MP730_PID 0x262f -#define MP700_PID 0x2630 - -#define MP5_PID 0x2635 /* untested */ - -#define MP360_PID 0x263c -#define MP370_PID 0x263d -#define MP390_PID 0x263e -#define MP375R_PID 0x263f /* untested */ - -#define MP740_PID 0x264c /* Untested */ -#define MP710_PID 0x264d - -#define MF5730_PID 0x265d /* Untested */ -#define MF5750_PID 0x265e /* Untested */ -#define MF5770_PID 0x265f -#define MF3110_PID 0x2660 - -#define IR1020_PID 0x26e6 - -enum mp730_state_t -{ - state_idle, - state_warmup, - state_scanning, - state_transfering, - state_finished -}; - -enum mp730_cmd_t -{ - cmd_start_session = 0xdb20, - cmd_select_source = 0xdd20, - cmd_gamma = 0xee20, - cmd_scan_param = 0xde20, - cmd_status = 0xf320, - cmd_abort_session = 0xef20, - cmd_time = 0xeb80, - cmd_read_image = 0xd420, - cmd_error_info = 0xff20, - - cmd_activate = 0xcf60, - cmd_calibrate = 0xe920 -}; - -typedef struct mp730_t -{ - enum mp730_state_t state; - pixma_cmdbuf_t cb; - unsigned raw_width; - uint8_t current_status[12]; - - uint8_t *buf, *imgbuf, *lbuf; - unsigned imgbuf_len; - - unsigned last_block:1; -} mp730_t; - - -static void mp730_finish_scan (pixma_t * s); - -static int -has_paper (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - return (mp->current_status[1] == 0); -} - -static void -drain_bulk_in (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - while (pixma_read (s->io, mp->imgbuf, IMAGE_BLOCK_SIZE) >= 0); -} - -static int -abort_session (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); -} - -static int -query_status (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mp->cb, cmd_status, 0, 12); - error = pixma_exec (s, &mp->cb); - if (error >= 0) - { - memcpy (mp->current_status, data, 12); - PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u\n", - data[1], data[8], data[7])); - } - return error; -} - -static int -activate (pixma_t * s, uint8_t x) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - uint8_t *data = pixma_newcmd (&mp->cb, cmd_activate, 10, 0); - data[0] = 1; - data[3] = x; - return pixma_exec (s, &mp->cb); -} - -static int -start_session (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_start_session); -} - -static int -select_source (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - uint8_t *data = pixma_newcmd (&mp->cb, cmd_select_source, 10, 0); - switch (s->param->source) - { - case PIXMA_SOURCE_ADF: - data[0] = 2; - break; - - case PIXMA_SOURCE_ADFDUP: - data[0] = 2; - data[5] = 3; - break; - - default: - data[0] = 1; - break; - } - return pixma_exec (s, &mp->cb); -} - -static int -send_scan_param (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - uint8_t *data; - - data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x2e, 0); - pixma_set_be16 (s->param->xdpi | 0x1000, data + 0x04); - pixma_set_be16 (s->param->ydpi | 0x1000, data + 0x06); - pixma_set_be32 (s->param->x, data + 0x08); - pixma_set_be32 (s->param->y, data + 0x0c); - pixma_set_be32 (mp->raw_width, data + 0x10); - pixma_set_be32 (s->param->h, data + 0x14); - - if (s->param->channels == 1) - { - if (s->param->depth == 1) - data[0x18] = 0x01; - else - data[0x18] = 0x04; - } - else - data[0x18] = 0x08; - - data[0x19] = s->param->channels * s->param->depth; /* bits per pixel, for lineart should be 0x01 */ - data[0x1e] = (s->param->depth == 1) ? 0x80 : 0x00; /* modify for lineart: 0x80 NEW */ - data[0x1f] = (s->param->depth == 1) ? 0x80 : 0x7f; /* modify for lineart: 0x80 */ - data[0x20] = (s->param->depth == 1) ? 0x01 : 0xff; /* modify for lineart: 0x01 */ - data[0x23] = 0x81; - - return pixma_exec (s, &mp->cb); -} - -static int -calibrate (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_calibrate); -} - -static int -read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) -{ - static const uint8_t cmd[10] = /* 0xd420 cmd */ - { 0xd4, 0x20, 0, 0, 0, 0, 0, IMAGE_BLOCK_SIZE / 256, 4, 0 }; - mp730_t *mp = (mp730_t *) s->subdriver; - const int hlen = 2 + 4; - int error, datalen; - - mp->state = state_transfering; - mp->cb.reslen = - pixma_cmd_transaction (s, cmd, sizeof (cmd), mp->cb.buf, 512); - datalen = mp->cb.reslen; - if (datalen < 0) - return datalen; - - memcpy (header, mp->cb.buf, hlen); - if (datalen >= hlen) - { - datalen -= hlen; - memcpy (data, mp->cb.buf + hlen, datalen); - data += datalen; - if (mp->cb.reslen == 512) - { - error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen); - if (error < 0) - return error; - datalen += error; - } - } - - mp->state = state_scanning; - mp->cb.expected_reslen = 0; - error = pixma_check_result (&mp->cb); - if (error < 0) - return error; - if (mp->cb.reslen < hlen) - return PIXMA_EPROTO; - return datalen; -} - -static int -send_time (pixma_t * s) -{ - /* Why does a scanner need a time? */ - time_t now; - struct tm *t; - uint8_t *data; - mp730_t *mp = (mp730_t *) s->subdriver; - - data = pixma_newcmd (&mp->cb, cmd_time, 20, 0); - pixma_get_time (&now, NULL); - t = localtime (&now); - snprintf ((char *) data, 16, - "%02d/%02d/%02d %02d:%02d", - t->tm_year % 100, t->tm_mon + 1, t->tm_mday, - t->tm_hour, t->tm_min); - PDBG (pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); - return pixma_exec (s, &mp->cb); -} - -static int -handle_interrupt (pixma_t * s, int timeout) -{ - uint8_t buf[16]; - int len; - - len = pixma_wait_interrupt (s->io, buf, sizeof (buf), timeout); - if (len == PIXMA_ETIMEDOUT) - return 0; - if (len < 0) - return len; - switch (s->cfg->pid) - { - case MP360_PID: - case MP370_PID: - case MP375R_PID: - case MP390_PID: - case MF5730_PID: - case MF5750_PID: - case MF5770_PID: - case MF3110_PID: - case IR1020_PID: - if (len != 16) - { - PDBG (pixma_dbg - (1, "WARNING:unexpected interrupt packet length %d\n", len)); - return PIXMA_EPROTO; - } - if (buf[12] & 0x40) - query_status (s); - if (buf[10] & 0x40) - send_time (s); - /* FIXME: following is unverified! */ - if (buf[15] & 1) - s->events = PIXMA_EV_BUTTON2; /* b/w scan */ - if (buf[15] & 2) - s->events = PIXMA_EV_BUTTON1; /* color scan */ - break; - - case MP5_PID: - case MP10_PID: - case MP700_PID: - case MP730_PID: - case MP710_PID: - case MP740_PID: - if (len != 8) - { - PDBG (pixma_dbg - (1, "WARNING:unexpected interrupt packet length %d\n", len)); - return PIXMA_EPROTO; - } - if (buf[7] & 0x10) - s->events = PIXMA_EV_BUTTON1; - if (buf[5] & 8) - send_time (s); - break; - - default: - PDBG (pixma_dbg (1, "WARNING:unknown interrupt, please report!\n")); - PDBG (pixma_hexdump (1, buf, len)); - } - return 1; -} - -static int -has_ccd_sensor (pixma_t * s) -{ - return (s->cfg->pid == MP360_PID || - s->cfg->pid == MP370_PID || - s->cfg->pid == MP375R_PID || - s->cfg->pid == MP390_PID || - s->cfg->pid == MF5730_PID || - s->cfg->pid == MF5750_PID || - s->cfg->pid == MF5770_PID); -} - -static int -read_error_info (pixma_t * s, void *buf, unsigned size) -{ - unsigned len = 16; - mp730_t *mp = (mp730_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); - error = pixma_exec (s, &mp->cb); - if (error < 0) - return error; - if (buf && len < size) - { - size = len; - /* NOTE: I've absolutely no idea what the returned data mean. */ - memcpy (buf, data, size); - error = len; - } - return error; -} - -static int -step1 (pixma_t * s) -{ - int error; - - error = query_status (s); - if (error < 0) - return error; - if ((s->param->source == PIXMA_SOURCE_ADF - || s->param->source == PIXMA_SOURCE_ADFDUP) - && !has_paper (s)) - return PIXMA_ENO_PAPER; - if (has_ccd_sensor (s)) - { - switch (s->cfg->pid) - { - case MF5730_PID: - case MF5750_PID: - case MF5770_PID: - /* MF57x0: Wait 10 sec before starting for 1st page only */ - if (s->param->adf_pageid == 0) - { - int tmo = 10; /* like Windows driver, 10 sec CCD calibration ? */ - while (--tmo >= 0) - { - error = handle_interrupt (s, 1000); \ - if (s->cancel) \ - return PIXMA_ECANCELED; \ - if (error != PIXMA_ECANCELED && error < 0) \ - return error; - PDBG (pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo)); - } - } - break; - - default: - break; - } - - activate (s, 0); - error = calibrate (s); - - switch (s->cfg->pid) - { - case MF5730_PID: - case MF5750_PID: - case MF5770_PID: - /* MF57x0: calibration returns PIXMA_STATUS_FAILED */ - if (error == PIXMA_ECANCELED) - error = read_error_info (s, NULL, 0); - break; - - default: - break; - } - - // ignore result from calibrate() - // don't interrupt @ PIXMA_STATUS_BUSY - error = 0; - } - if (error >= 0) - error = activate (s, 0); - if (error >= 0) - error = activate (s, 4); - return error; -} - -static void -pack_rgb (const uint8_t * src, unsigned nlines, unsigned w, uint8_t * dst) -{ - unsigned w2, stride; - - w2 = 2 * w; - stride = 3 * w; - for (; nlines != 0; nlines--) - { - unsigned x; - for (x = 0; x != w; x++) - { - *dst++ = src[x + 0]; - *dst++ = src[x + w]; - *dst++ = src[x + w2]; - } - src += stride; - } -} - -static int -mp730_open (pixma_t * s) -{ - mp730_t *mp; - uint8_t *buf; - - mp = (mp730_t *) calloc (1, sizeof (*mp)); - if (!mp) - return PIXMA_ENOMEM; - - buf = (uint8_t *) malloc (CMDBUF_SIZE); - if (!buf) - { - free (mp); - return PIXMA_ENOMEM; - } - - s->subdriver = mp; - mp->state = state_idle; - - mp->cb.buf = buf; - mp->cb.size = CMDBUF_SIZE; - mp->cb.res_header_len = 2; - mp->cb.cmd_header_len = 10; - mp->cb.cmd_len_field_ofs = 7; - - PDBG (pixma_dbg (3, "Trying to clear the interrupt buffer...\n")); - if (handle_interrupt (s, 200) == 0) - { - PDBG (pixma_dbg (3, " no packets in buffer\n")); - } - return 0; -} - -static void -mp730_close (pixma_t * s) -{ - mp730_t *mp = (mp730_t *) s->subdriver; - - mp730_finish_scan (s); - free (mp->cb.buf); - free (mp->buf); - free (mp); - s->subdriver = NULL; -} - -static unsigned -calc_raw_width (pixma_t * s, const pixma_scan_param_t * sp) -{ - unsigned raw_width; - /* FIXME: Does MP730 need the alignment? */ - /* TODO test: MP710/740 */ - if (sp->channels == 1) - { - if (sp->depth == 8) /* grayscale */ - { - if (s->cfg->pid == MP5_PID || - s->cfg->pid == MP10_PID || - s->cfg->pid == MP700_PID || - s->cfg->pid == MP730_PID || - s->cfg->pid == MP360_PID || - s->cfg->pid == MP370_PID || - s->cfg->pid == MP375R_PID || - s->cfg->pid == MP390_PID || - s->cfg->pid == IR1020_PID) - raw_width = ALIGN_SUP (sp->w, 4); - else - raw_width = ALIGN_SUP (sp->w, 12); - } - else /* depth = 1 : LINEART */ - raw_width = ALIGN_SUP (sp->w, 16); - } - else - raw_width = ALIGN_SUP (sp->w, 4); - return raw_width; -} - -static int -mp730_check_param (pixma_t * s, pixma_scan_param_t * sp) -{ - uint8_t k = 1; - - /* check if channels is 3, or if depth is 1 then channels also 1 else set depth to 8 */ - if ((sp->channels==3) || !(sp->channels==1 && sp->depth==1)) - { - sp->depth=8; - } - /* for MP5, MP10, MP360/370, MP700/730 in grayscale & lineart modes, max scan res is 600 dpi */ - if (s->cfg->pid == MP5_PID || - s->cfg->pid == MP10_PID || - s->cfg->pid == MP700_PID || - s->cfg->pid == MP730_PID || - s->cfg->pid == MP360_PID || - s->cfg->pid == MP370_PID || - s->cfg->pid == MP375R_PID || - s->cfg->pid == MP390_PID) - { - if (sp->channels == 1) - k = sp->xdpi / MIN (sp->xdpi, 600); - } - - sp->x /= k; - sp->y /= k; - sp->h /= k; - sp->xdpi /= k; - sp->ydpi = sp->xdpi; - - sp->w = calc_raw_width (s, sp); - sp->w /= k; - sp->line_size = (calc_raw_width (s, sp) * sp->channels * sp->depth) / 8; - - return 0; -} - -static int -mp730_scan (pixma_t * s) -{ - int error, n; - mp730_t *mp = (mp730_t *) s->subdriver; - uint8_t *buf; - - if (mp->state != state_idle) - return PIXMA_EBUSY; - - /* clear interrupt packets buffer */ - while (handle_interrupt (s, 0) > 0) - { - } - - mp->raw_width = calc_raw_width (s, s->param); - PDBG (pixma_dbg (3, "raw_width = %u\n", mp->raw_width)); - - n = IMAGE_BLOCK_SIZE / s->param->line_size + 1; - buf = (uint8_t *) malloc ((n + 1) * s->param->line_size + IMAGE_BLOCK_SIZE); - if (!buf) - return PIXMA_ENOMEM; - mp->buf = buf; - mp->lbuf = buf; - mp->imgbuf = buf + n * s->param->line_size; - mp->imgbuf_len = 0; - - error = step1 (s); - if (error >= 0) - error = start_session (s); - if (error >= 0) - mp->state = state_scanning; - if (error >= 0) - error = select_source (s); - if (error >= 0) - error = send_scan_param (s); - if (error < 0) - { - mp730_finish_scan (s); - return error; - } - mp->last_block = 0; - return 0; -} - -static int -mp730_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) -{ - int error, n; - mp730_t *mp = (mp730_t *) s->subdriver; - unsigned block_size, bytes_received; - uint8_t header[16]; - - do - { - do - { - if (s->cancel) - return PIXMA_ECANCELED; - if (mp->last_block) /* end of image */ - return 0; - - error = read_image_block (s, header, mp->imgbuf + mp->imgbuf_len); - if (error < 0) - return error; - - bytes_received = error; - block_size = pixma_get_be16 (header + 4); - mp->last_block = ((header[2] & 0x28) == 0x28); - if (mp->last_block) - { /* end of image */ - mp->state = state_finished; - } - if ((header[2] & ~0x38) != 0) - { - PDBG (pixma_dbg (1, "WARNING: Unexpected result header\n")); - PDBG (pixma_hexdump (1, header, 16)); - } - PASSERT (bytes_received == block_size); - - if (block_size == 0) - { - /* no image data at this moment. */ - /*pixma_sleep(100000); *//* FIXME: too short, too long? */ - handle_interrupt (s, 100); - } - } - while (block_size == 0); - - /* TODO: simplify! */ - mp->imgbuf_len += bytes_received; - n = mp->imgbuf_len / s->param->line_size; - /* n = number of full lines (rows) we have in the buffer. */ - if (n != 0) - { - if (s->param->channels != 1 && - s->cfg->pid != MF5730_PID && - s->cfg->pid != MF5750_PID && - s->cfg->pid != MF5770_PID && - s->cfg->pid != MF3110_PID && - s->cfg->pid != IR1020_PID) - { - /* color, and not an MF57x0 nor MF3110 */ - pack_rgb (mp->imgbuf, n, mp->raw_width, mp->lbuf); - } - else - /* grayscale/lineart or MF57x0 or MF3110 */ - memcpy (mp->lbuf, mp->imgbuf, n * s->param->line_size); - - block_size = n * s->param->line_size; - mp->imgbuf_len -= block_size; - memcpy (mp->imgbuf, mp->imgbuf + block_size, mp->imgbuf_len); - } - } - while (n == 0); - - ib->rptr = mp->lbuf; - ib->rend = mp->lbuf + block_size; - return ib->rend - ib->rptr; -} - -static void -mp730_finish_scan (pixma_t * s) -{ - int error, aborted = 0; - mp730_t *mp = (mp730_t *) s->subdriver; - - switch (mp->state) - { - case state_transfering: - drain_bulk_in (s); - /* fall through */ - case state_scanning: - case state_warmup: - aborted = 1; - error = abort_session (s); - if (error < 0) - PDBG (pixma_dbg - (1, "WARNING:abort_session() failed %s\n", - pixma_strerror (error))); - /* fall through */ - case state_finished: - query_status (s); - query_status (s); - activate (s, 0); - - // MF57x0 devices don't require abort_session() after the last page - if (!aborted && - (s->param->source == PIXMA_SOURCE_ADF || - s->param->source == PIXMA_SOURCE_ADFDUP) && - has_paper (s) && - (s->cfg->pid == MF5730_PID || - s->cfg->pid == MF5750_PID || - s->cfg->pid == MF5770_PID || - s->cfg->pid == IR1020_PID)) - { - error = abort_session (s); - if (error < 0) - PDBG (pixma_dbg - (1, "WARNING:abort_session() failed %s\n", - pixma_strerror (error))); - } - - mp->buf = mp->lbuf = mp->imgbuf = NULL; - mp->state = state_idle; - /* fall through */ - case state_idle: - break; - } -} - -static void -mp730_wait_event (pixma_t * s, int timeout) -{ - /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for - * instance. */ - while (s->events == 0 && handle_interrupt (s, timeout) > 0) - { - } -} - -static int -mp730_get_status (pixma_t * s, pixma_device_status_t * status) -{ - int error; - - error = query_status (s); - if (error < 0) - return error; - status->hardware = PIXMA_HARDWARE_OK; - status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; - return 0; -} - - -static const pixma_scan_ops_t pixma_mp730_ops = { - mp730_open, - mp730_close, - mp730_scan, - mp730_fill_buffer, - mp730_finish_scan, - mp730_wait_event, - mp730_check_param, - mp730_get_status -}; - -/* TODO: implement adftpu_min_dpi & adftpu_max_dpi for grayscale & lineart */ -#define DEVICE(name, model, pid, dpi, w, h, cap) { \ - name, /* name */ \ - model, /* model */ \ - 0x04a9, pid, /* vid pid */ \ - 1, /* iface */ \ - &pixma_mp730_ops, /* ops */ \ - dpi, dpi, /* xdpi, ydpi */ \ - 0, 0, /* adftpu_min_dpi & adftpu_max_dpi not used in this subdriver */ \ - 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ - w, h, /* width, height */ \ - PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ -} -const pixma_config_t pixma_mp730_devices[] = { -/* TODO: check area limits */ - DEVICE ("PIXUS MP5/SmartBase MPC190/imageCLASS MPC190","MP5", MP5_PID, 600, 636, 868, PIXMA_CAP_LINEART),/* color scan can do 600x1200 */ - DEVICE ("PIXUS MP10/SmartBase MPC200/imageCLASS MPC200","MP10", MP10_PID, 600, 636, 868, PIXMA_CAP_LINEART),/* color scan can do 600x1200 */ - DEVICE ("PIXMA MP360", "MP360", MP360_PID, 1200, 636, 868, PIXMA_CAP_LINEART), - DEVICE ("PIXMA MP370", "MP370", MP370_PID, 1200, 636, 868, PIXMA_CAP_LINEART), - DEVICE ("PIXMA MP375R", "MP375R", MP375R_PID, 1200, 636, 868, PIXMA_CAP_LINEART), - DEVICE ("PIXMA MP390", "MP390", MP390_PID, 1200, 636, 868, PIXMA_CAP_LINEART), - DEVICE ("PIXMA MP700", "MP700", MP700_PID, 1200, 638, 877 /*1035 */ , PIXMA_CAP_LINEART), - DEVICE ("PIXMA MP710", "MP710", MP710_PID, 1200, 637, 868, PIXMA_CAP_LINEART), - DEVICE ("PIXMA MP730", "MP730", MP730_PID, 1200, 637, 868, PIXMA_CAP_ADF | PIXMA_CAP_LINEART), - DEVICE ("PIXMA MP740", "MP740", MP740_PID, 1200, 637, 868, PIXMA_CAP_ADF | PIXMA_CAP_LINEART), - - DEVICE ("Canon imageCLASS MF5730", "MF5730", MF5730_PID, 1200, 636, 868, PIXMA_CAP_ADF), - DEVICE ("Canon imageCLASS MF5750", "MF5750", MF5750_PID, 1200, 636, 868, PIXMA_CAP_ADF), - DEVICE ("Canon imageCLASS MF5770", "MF5770", MF5770_PID, 1200, 636, 868, PIXMA_CAP_ADF), - DEVICE ("Canon imageCLASS MF3110", "MF3110", MF3110_PID, 600, 636, 868, 0), - - DEVICE ("Canon iR 1020/1024/1025", "iR1020", IR1020_PID, 600, 636, 868, PIXMA_CAP_ADFDUP), - - DEVICE (NULL, NULL, 0, 0, 0, 0, 0) -}; diff --git a/backend/pixma_mp750.c b/backend/pixma_mp750.c deleted file mode 100644 index 5bd6ef0..0000000 --- a/backend/pixma_mp750.c +++ /dev/null @@ -1,970 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2011-2019 Rolf Bensch - 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. - */ - -/**************************************************************************** - * Credits should go to Martin Schewe (http://pixma.schewe.com) who analysed - * the protocol of MP750. - ****************************************************************************/ - -#include "../include/sane/config.h" - -#include -#include - -#include "pixma_rename.h" -#include "pixma_common.h" -#include "pixma_io.h" - -/* TODO: remove lines marked with SIM. They are inserted so that I can test - the subdriver with the simulator. WY */ - -#ifdef __GNUC__ -# define UNUSED(v) (void) v -#else -# define UNUSED(v) -#endif - -#define IMAGE_BLOCK_SIZE 0xc000 -#define CMDBUF_SIZE 512 -#define HAS_PAPER(s) (s[1] == 0) -#define IS_WARMING_UP(s) (s[7] != 3) -#define IS_CALIBRATED(s) (s[8] == 0xf) - -#define MP750_PID 0x1706 -#define MP760_PID 0x1708 -#define MP780_PID 0x1707 - - -enum mp750_state_t -{ - state_idle, - state_warmup, - state_scanning, - state_transfering, - state_finished -}; - -enum mp750_cmd_t -{ - cmd_start_session = 0xdb20, - cmd_select_source = 0xdd20, - cmd_scan_param = 0xde20, - cmd_status = 0xf320, - cmd_abort_session = 0xef20, - cmd_time = 0xeb80, - cmd_read_image = 0xd420, - - cmd_activate = 0xcf60, - cmd_calibrate = 0xe920, - cmd_error_info = 0xff20 -}; - -typedef struct mp750_t -{ - enum mp750_state_t state; - pixma_cmdbuf_t cb; - unsigned raw_width, raw_height; - uint8_t current_status[12]; - - uint8_t *buf, *rawimg, *img; - /* make new buffer for rgb_to_gray to act on */ - uint8_t *imgcol; - unsigned line_size; /* need in 2 functions */ - - unsigned rawimg_left, imgbuf_len, last_block_size, imgbuf_ofs; - int shifted_bytes; - int stripe_shift; /* for 2400dpi */ - unsigned last_block; - - unsigned monochrome:1; - unsigned needs_abort:1; -} mp750_t; - - - -static void mp750_finish_scan (pixma_t * s); -static void check_status (pixma_t * s); - -static int -has_paper (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - return HAS_PAPER (mp->current_status); -} - -static int -is_warming_up (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - return IS_WARMING_UP (mp->current_status); -} - -static int -is_calibrated (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - return IS_CALIBRATED (mp->current_status); -} - -static void -drain_bulk_in (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - while (pixma_read (s->io, mp->buf, IMAGE_BLOCK_SIZE) >= 0); -} - -static int -abort_session (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); -} - -static int -query_status (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mp->cb, cmd_status, 0, 12); - error = pixma_exec (s, &mp->cb); - if (error >= 0) - { - memcpy (mp->current_status, data, 12); - PDBG (pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u\n", - data[1], data[8], data[7])); - } - return error; -} - -static int -activate (pixma_t * s, uint8_t x) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - uint8_t *data = pixma_newcmd (&mp->cb, cmd_activate, 10, 0); - data[0] = 1; - data[3] = x; - return pixma_exec (s, &mp->cb); -} - -static int -activate_cs (pixma_t * s, uint8_t x) -{ - /*SIM*/ check_status (s); - return activate (s, x); -} - -static int -start_session (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_start_session); -} - -static int -select_source (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - uint8_t *data = pixma_newcmd (&mp->cb, cmd_select_source, 10, 0); - data[0] = (s->param->source == PIXMA_SOURCE_ADF) ? 2 : 1; - data[1] = 1; - return pixma_exec (s, &mp->cb); -} - -static int -has_ccd_sensor (pixma_t * s) -{ - return ((s->cfg->cap & PIXMA_CAP_CCD) != 0); -} - -static int -is_ccd_grayscale (pixma_t * s) -{ - return (has_ccd_sensor (s) && (s->param->channels == 1)); -} - -/* CCD sensors don't have a Grayscale mode, but use color mode instead */ -static unsigned -get_cis_ccd_line_size (pixma_t * s) -{ - return (s->param->wx ? s->param->line_size / s->param->w * s->param->wx - : s->param->line_size) * ((is_ccd_grayscale (s)) ? 3 : 1); -} - -static int -send_scan_param (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - uint8_t *data; - - data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x2e, 0); - pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x04); - pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x06); - pixma_set_be32 (s->param->x, data + 0x08); - pixma_set_be32 (s->param->y, data + 0x0c); - pixma_set_be32 (mp->raw_width, data + 0x10); - pixma_set_be32 (mp->raw_height, data + 0x14); - data[0x18] = 8; /* 8 = color, 4 = grayscale(?) */ - /* GH: No, there is no grayscale for CCD devices, Windows shows same */ - data[0x19] = s->param->depth * ((is_ccd_grayscale (s)) ? 3 : s->param->channels); /* bits per pixel */ - data[0x20] = 0xff; - data[0x23] = 0x81; - data[0x26] = 0x02; - data[0x27] = 0x01; - data[0x29] = mp->monochrome ? 0 : 1; - - return pixma_exec (s, &mp->cb); -} - -static int -calibrate (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_calibrate); -} - -static int -calibrate_cs (pixma_t * s) -{ - /*SIM*/ check_status (s); - return calibrate (s); -} - -static int -request_image_block_ex (pixma_t * s, unsigned *size, uint8_t * info, - unsigned flag) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - int error; - - memset (mp->cb.buf, 0, 10); - pixma_set_be16 (cmd_read_image, mp->cb.buf); - mp->cb.buf[7] = *size >> 8; - mp->cb.buf[8] = 4 | flag; - mp->cb.reslen = pixma_cmd_transaction (s, mp->cb.buf, 10, mp->cb.buf, 6); - mp->cb.expected_reslen = 0; - error = pixma_check_result (&mp->cb); - if (error >= 0) - { - if (mp->cb.reslen == 6) - { - *info = mp->cb.buf[2]; - *size = pixma_get_be16 (mp->cb.buf + 4); - } - else - { - error = PIXMA_EPROTO; - } - } - return error; -} - -static int -request_image_block (pixma_t * s, unsigned *size, uint8_t * info) -{ - return request_image_block_ex (s, size, info, 0); -} - -static int -request_image_block2 (pixma_t * s, uint8_t * info) -{ - unsigned temp = 0; - return request_image_block_ex (s, &temp, info, 0x20); -} - -static int -read_image_block (pixma_t * s, uint8_t * data) -{ - int count, temp; - - count = pixma_read (s->io, data, IMAGE_BLOCK_SIZE); - if (count < 0) - return count; - if (count == IMAGE_BLOCK_SIZE) - { - int error = pixma_read (s->io, &temp, 0); - if (error < 0) - { - PDBG (pixma_dbg - (1, "WARNING: reading zero-length packet failed %d\n", error)); - } - } - return count; -} - -static int -read_error_info (pixma_t * s, void *buf, unsigned size) -{ - unsigned len = 16; - mp750_t *mp = (mp750_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); - error = pixma_exec (s, &mp->cb); - if (error >= 0 && buf) - { - if (len < size) - size = len; - /* NOTE: I've absolutely no idea what the returned data mean. */ - memcpy (buf, data, size); - error = len; - } - return error; -} - -static int -send_time (pixma_t * s) -{ - /* TODO: implement send_time() */ - UNUSED (s); - PDBG (pixma_dbg (3, "send_time() is not yet implemented.\n")); - return 0; -} - -static int -handle_interrupt (pixma_t * s, int timeout) -{ - int error; - uint8_t intr[16]; - - error = pixma_wait_interrupt (s->io, intr, sizeof (intr), timeout); - if (error == PIXMA_ETIMEDOUT) - return 0; - if (error < 0) - return error; - if (error != 16) - { - PDBG (pixma_dbg (1, "WARNING: unexpected interrupt packet length %d\n", - error)); - return PIXMA_EPROTO; - } - - if (intr[10] & 0x40) - send_time (s); - if (intr[12] & 0x40) - query_status (s); - if (intr[15] & 1) - s->events = PIXMA_EV_BUTTON2; /* b/w scan */ - if (intr[15] & 2) - s->events = PIXMA_EV_BUTTON1; /* color scan */ - return 1; -} - -static void -check_status (pixma_t * s) -{ - while (handle_interrupt (s, 0) > 0); -} - -static int -step1 (pixma_t * s) -{ - int error, tmo; - - error = activate (s, 0); - if (error < 0) - return error; - error = query_status (s); - if (error < 0) - return error; - if (s->param->source == PIXMA_SOURCE_ADF && !has_paper (s)) - return PIXMA_ENO_PAPER; - error = activate_cs (s, 0); - /*SIM*/ if (error < 0) - return error; - error = activate_cs (s, 0x20); - if (error < 0) - return error; - - tmo = 60; - error = calibrate_cs (s); - while (error == PIXMA_EBUSY && --tmo >= 0) - { - if (s->cancel) - return PIXMA_ECANCELED; - PDBG (pixma_dbg - (2, "Scanner is busy. Timed out in %d sec.\n", tmo + 1)); - pixma_sleep (1000000); - error = calibrate_cs (s); - } - return error; -} - -static void -shift_rgb (const uint8_t * src, unsigned pixels, - int sr, int sg, int sb, int stripe_shift, - int line_size, uint8_t * dst) -{ - unsigned st; - - for (; pixels != 0; pixels--) - { - st = (pixels % 2 == 0) ? -2 * stripe_shift * line_size : 0; - *(dst++ + sr + st) = *src++; - *(dst++ + sg + st) = *src++; - *(dst++ + sb + st) = *src++; - } -} - -static uint8_t * -rgb_to_gray (uint8_t * gptr, const uint8_t * cptr, unsigned pixels, unsigned c) -{ - unsigned i, j, g; - - /* gptr: destination gray scale buffer */ - /* cptr: source color scale buffer */ - /* c: 3 for 3-channel single-byte data, 6 for double-byte data */ - - for (i=0; i < pixels; i++) - { - for (j = 0, g = 0; j < 3; j++) - { - g += *cptr++; - if (c == 6) g += (*cptr++ << 8); - } - g /= 3; - *gptr++ = g; - if (c == 6) *gptr++ = (g >> 8); - } - return gptr; -} - -static int -calc_component_shifting (pixma_t * s) -{ - switch (s->cfg->pid) - { - case MP760_PID: - switch (s->param->ydpi) - { - case 300: - return 3; - case 600: - return 6; - default: - return s->param->ydpi / 75; - } - /* never reached */ - break; - - case MP750_PID: - case MP780_PID: - default: - return 2 * s->param->ydpi / 75; - } -} - -static void -workaround_first_command (pixma_t * s) -{ - /* FIXME: Send a dummy command because the device doesn't response to the - first command that is sent directly after the USB interface has been - set up. Why? USB isn't set up properly? */ - uint8_t cmd[10]; - int error; - - if (s->cfg->pid == MP750_PID) - return; /* MP750 doesn't have this problem(?) */ - - PDBG (pixma_dbg - (1, - "Work-around for the problem: device doesn't response to the first command.\n")); - memset (cmd, 0, sizeof (cmd)); - pixma_set_be16 (cmd_calibrate, cmd); - error = pixma_write (s->io, cmd, 10); - if (error != 10) - { - if (error < 0) - { - PDBG (pixma_dbg - (1, " Sending a dummy command failed: %s\n", - pixma_strerror (error))); - } - else - { - PDBG (pixma_dbg - (1, " Sending a dummy command failed: count = %d\n", error)); - } - return; - } - error = pixma_read (s->io, cmd, sizeof (cmd)); - if (error >= 0) - { - PDBG (pixma_dbg - (1, " Got %d bytes response from a dummy command.\n", error)); - } - else - { - PDBG (pixma_dbg - (1, " Reading response of a dummy command failed: %s\n", - pixma_strerror (error))); - } -} - -static int -mp750_open (pixma_t * s) -{ - mp750_t *mp; - uint8_t *buf; - - mp = (mp750_t *) calloc (1, sizeof (*mp)); - if (!mp) - return PIXMA_ENOMEM; - - buf = (uint8_t *) malloc (CMDBUF_SIZE); - if (!buf) - { - free (mp); - return PIXMA_ENOMEM; - } - - s->subdriver = mp; - mp->state = state_idle; - - /* ofs: 0 1 2 3 4 5 6 7 8 9 - cmd: cmd1 cmd2 00 00 00 00 00 00 00 00 - data length-^^^^^ => cmd_len_field_ofs - |--------- cmd_header_len --------| - - res: res1 res2 - |---------| res_header_len - */ - mp->cb.buf = buf; - mp->cb.size = CMDBUF_SIZE; - mp->cb.res_header_len = 2; - mp->cb.cmd_header_len = 10; - mp->cb.cmd_len_field_ofs = 7; - - handle_interrupt (s, 200); - workaround_first_command (s); - return 0; -} - -static void -mp750_close (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - - mp750_finish_scan (s); - free (mp->cb.buf); - free (mp); - s->subdriver = NULL; -} - -static int -mp750_check_param (pixma_t * s, pixma_scan_param_t * sp) -{ - unsigned raw_width; - - UNUSED (s); - - sp->depth = 8; /* FIXME: Does MP750 supports other depth? */ - - /* GH: my implementation */ - /* if ((sp->channels == 3) || (is_ccd_grayscale (s))) - raw_width = ALIGN_SUP (sp->w, 4); - else - raw_width = ALIGN_SUP (sp->w, 12);*/ - - /* the above code gives segmentation fault?!? why... it seems to work in the mp750_scan function */ - raw_width = ALIGN_SUP (sp->w, 4); - - /*sp->line_size = raw_width * sp->channels;*/ - sp->line_size = raw_width * sp->channels * (sp->depth / 8); /* no cropping? */ - return 0; -} - -static int -mp750_scan (pixma_t * s) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - int error; - uint8_t *buf; - unsigned size, dpi, spare; - - dpi = s->param->ydpi; - /* add a stripe shift for 2400dpi */ - mp->stripe_shift = (dpi == 2400) ? 4 : 0; - - if (mp->state != state_idle) - return PIXMA_EBUSY; - - /* clear interrupt packets buffer */ - while (handle_interrupt (s, 0) > 0) - { - } - - /* if (s->param->channels == 1) - mp->raw_width = ALIGN_SUP (s->param->w, 12); - else - mp->raw_width = ALIGN_SUP (s->param->w, 4);*/ - - /* change to use CCD grayscale mode --- why does this give segmentation error at runtime in mp750_check_param? */ - if ((s->param->channels == 3) || (is_ccd_grayscale (s))) - mp->raw_width = ALIGN_SUP (s->param->w, 4); - else - mp->raw_width = ALIGN_SUP (s->param->w, 12); - /* not sure about MP750, but there is no need for aligning at 12 for the MP760/770, MP780/790 since always use CCD color mode */ - - /* modify for stripe shift */ - spare = 2 * calc_component_shifting (s) + 2 * mp->stripe_shift; /* FIXME: or maybe (2*... + 1)? */ - mp->raw_height = s->param->h + spare; - PDBG (pixma_dbg (3, "raw_width=%u raw_height=%u dpi=%u\n", - mp->raw_width, mp->raw_height, dpi)); - - /* PDBG (pixma_dbg (4, "line_size=%"PRIu64"\n",s->param->line_size)); */ - - mp->line_size = get_cis_ccd_line_size (s); /* scanner hardware line_size multiplied by 3 for CCD grayscale */ - - size = 8 + 2 * IMAGE_BLOCK_SIZE + spare * mp->line_size; - buf = (uint8_t *) malloc (size); - if (!buf) - return PIXMA_ENOMEM; - mp->buf = buf; - mp->rawimg = buf; - mp->imgbuf_ofs = spare * mp->line_size; - mp->imgcol = mp->rawimg + IMAGE_BLOCK_SIZE + 8; /* added to make rgb->gray */ - mp->img = mp->rawimg + IMAGE_BLOCK_SIZE + 8; - mp->imgbuf_len = IMAGE_BLOCK_SIZE + mp->imgbuf_ofs; - mp->rawimg_left = 0; - mp->last_block_size = 0; - mp->shifted_bytes = -(int) mp->imgbuf_ofs; - - error = step1 (s); - if (error >= 0) - error = start_session (s); - if (error >= 0) - mp->state = state_warmup; - if (error >= 0) - error = select_source (s); - if (error >= 0) - error = send_scan_param (s); - if (error < 0) - { - mp750_finish_scan (s); - return error; - } - return 0; -} - - -static int -mp750_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) -{ - mp750_t *mp = (mp750_t *) s->subdriver; - int error; - uint8_t info; - unsigned block_size, bytes_received, n; - int shift[3], base_shift; - int c; - - c = ((is_ccd_grayscale (s)) ? 3 : s->param->channels) * s->param->depth / 8; /* single-byte or double-byte data */ - - if (mp->state == state_warmup) - { - int tmo = 60; - - query_status (s); - check_status (s); - /*SIM*/ while (!is_calibrated (s) && --tmo >= 0) - { - if (s->cancel) - return PIXMA_ECANCELED; - if (handle_interrupt (s, 1000) > 0) - { - block_size = 0; - error = request_image_block (s, &block_size, &info); - /*SIM*/ if (error < 0) - return error; - } - } - if (tmo < 0) - { - PDBG (pixma_dbg (1, "WARNING: Timed out waiting for calibration\n")); - return PIXMA_ETIMEDOUT; - } - pixma_sleep (100000); - query_status (s); - if (is_warming_up (s) || !is_calibrated (s)) - { - PDBG (pixma_dbg (1, "WARNING: Wrong status: wup=%d cal=%d\n", - is_warming_up (s), is_calibrated (s))); - return PIXMA_EPROTO; - } - block_size = 0; - request_image_block (s, &block_size, &info); - /*SIM*/ mp->state = state_scanning; - mp->last_block = 0; - } - - /* TODO: Move to other place, values are constant. */ - base_shift = calc_component_shifting (s) * mp->line_size; - if (s->param->source == PIXMA_SOURCE_ADF) - { - shift[0] = 0; - shift[1] = -base_shift; - shift[2] = -2 * base_shift; - } - else - { - shift[0] = -2 * base_shift; - shift[1] = -base_shift; - shift[2] = 0; - } - - do - { - if (mp->last_block_size > 0) - { - block_size = mp->imgbuf_len - mp->last_block_size; - memcpy (mp->img, mp->img + mp->last_block_size, block_size); - } - - do - { - if (s->cancel) - return PIXMA_ECANCELED; - if (mp->last_block) - { - /* end of image */ - info = mp->last_block; - if (info != 0x38) - { - query_status (s); - /*SIM*/ while ((info & 0x28) != 0x28) - { - pixma_sleep (10000); - error = request_image_block2 (s, &info); - if (s->cancel) - return PIXMA_ECANCELED; /* FIXME: Is it safe to cancel here? */ - if (error < 0) - return error; - } - } - mp->needs_abort = (info != 0x38); - mp->last_block = info; - mp->state = state_finished; - return 0; - } - - check_status (s); - /*SIM*/ while (handle_interrupt (s, 1) > 0); - /*SIM*/ block_size = IMAGE_BLOCK_SIZE; - error = request_image_block (s, &block_size, &info); - if (error < 0) - { - if (error == PIXMA_ECANCELED) - read_error_info (s, NULL, 0); - return error; - } - mp->last_block = info; - if ((info & ~0x38) != 0) - { - PDBG (pixma_dbg (1, "WARNING: Unknown info byte %x\n", info)); - } - if (block_size == 0) - { - /* no image data at this moment. */ - pixma_sleep (10000); - } - } - while (block_size == 0); - - error = read_image_block (s, mp->rawimg + mp->rawimg_left); - if (error < 0) - { - mp->state = state_transfering; - return error; - } - bytes_received = error; - PASSERT (bytes_received == block_size); - - /* TODO: simplify! */ - mp->rawimg_left += bytes_received; - n = mp->rawimg_left / 3; - /* n = number of pixels in the buffer? */ - - /* Color to Grayscale converion for CCD sensor */ - if (is_ccd_grayscale (s)) { - shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, - mp->imgcol + mp->imgbuf_ofs); - /* dst: img, src: imgcol */ - rgb_to_gray (mp->img, mp->imgcol, n, c); /* cropping occurs later? */ - PDBG (pixma_dbg (4, "*fill_buffer: did grayscale conversion \n")); - } - /* Color image processing */ - else { - shift_rgb (mp->rawimg, n, shift[0], shift[1], shift[2], mp->stripe_shift, mp->line_size, - mp->img + mp->imgbuf_ofs); - PDBG (pixma_dbg (4, "*fill_buffer: no grayscale conversion---keep color \n")); - } - - /* entering remaining unprocessed bytes after last complete pixel into mp->rawimg buffer -- no influence on mp->img */ - n *= 3; - mp->shifted_bytes += n; - mp->rawimg_left -= n; /* rawimg_left = 0, 1 or 2 bytes left in the buffer. */ - mp->last_block_size = n; - memcpy (mp->rawimg, mp->rawimg + n, mp->rawimg_left); - - } - while (mp->shifted_bytes <= 0); - - if ((unsigned) mp->shifted_bytes < mp->last_block_size) - { - if (is_ccd_grayscale (s)) - ib->rptr = mp->img + mp->last_block_size/3 - mp->shifted_bytes/3; /* testing---works OK */ - else - ib->rptr = mp->img + mp->last_block_size - mp->shifted_bytes; - } - else - ib->rptr = mp->img; - if (is_ccd_grayscale (s)) - ib->rend = mp->img + mp->last_block_size/3; /* testing---works OK */ - else - ib->rend = mp->img + mp->last_block_size; - return ib->rend - ib->rptr; -} - -static void -mp750_finish_scan (pixma_t * s) -{ - int error; - mp750_t *mp = (mp750_t *) s->subdriver; - - switch (mp->state) - { - case state_transfering: - drain_bulk_in (s); - /* fall through */ - case state_scanning: - case state_warmup: - error = abort_session (s); - if (error == PIXMA_ECANCELED) - read_error_info (s, NULL, 0); - /* fall through */ - case state_finished: - if (s->param->source == PIXMA_SOURCE_FLATBED) - { - /*SIM*/ query_status (s); - if (abort_session (s) == PIXMA_ECANCELED) - { - read_error_info (s, NULL, 0); - query_status (s); - } - } - query_status (s); - /*SIM*/ activate (s, 0); - if (mp->needs_abort) - { - mp->needs_abort = 0; - abort_session (s); - } - free (mp->buf); - mp->buf = mp->rawimg = NULL; - mp->state = state_idle; - /* fall through */ - case state_idle: - break; - } -} - -static void -mp750_wait_event (pixma_t * s, int timeout) -{ - /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for - * instance. */ - while (s->events == 0 && handle_interrupt (s, timeout) > 0) - { - } -} - -static int -mp750_get_status (pixma_t * s, pixma_device_status_t * status) -{ - int error; - - error = query_status (s); - if (error < 0) - return error; - status->hardware = PIXMA_HARDWARE_OK; - status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; - status->cal = - (is_calibrated (s)) ? PIXMA_CALIBRATION_OK : PIXMA_CALIBRATION_OFF; - status->lamp = (is_warming_up (s)) ? PIXMA_LAMP_WARMING_UP : PIXMA_LAMP_OK; - return 0; -} - - -static const pixma_scan_ops_t pixma_mp750_ops = { - mp750_open, - mp750_close, - mp750_scan, - mp750_fill_buffer, - mp750_finish_scan, - mp750_wait_event, - mp750_check_param, - mp750_get_status -}; - -#define DEVICE(name, model, pid, dpi, cap) { \ - name, /* name */ \ - model, /* model */ \ - 0x04a9, pid, /* vid pid */ \ - 0, /* iface */ \ - &pixma_mp750_ops, /* ops */ \ - dpi, 2*(dpi), /* xdpi, ydpi */ \ - 0, 0, /* adftpu_min_dpi & adftpu_max_dpi not used in this subdriver */ \ - 0, 0, /* tpuir_min_dpi & tpuir_max_dpi not used in this subdriver */ \ - 637, 877, /* width, height */ \ - PIXMA_CAP_GRAY|PIXMA_CAP_EVENTS|cap \ -} - -const pixma_config_t pixma_mp750_devices[] = { - DEVICE ("Canon PIXMA MP750", "MP750", MP750_PID, 2400, PIXMA_CAP_CCD | PIXMA_CAP_ADF), - DEVICE ("Canon PIXMA MP760/770", "MP760/770", MP760_PID, 2400, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - DEVICE ("Canon PIXMA MP780/790", "MP780/790", MP780_PID, 2400, PIXMA_CAP_CCD | PIXMA_CAP_ADF), - DEVICE (NULL, NULL, 0, 0, 0) -}; diff --git a/backend/pixma_mp810.c b/backend/pixma_mp810.c deleted file mode 100644 index 5d81e3f..0000000 --- a/backend/pixma_mp810.c +++ /dev/null @@ -1,2388 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - Copyright (C) 2011-2019 Rolf Bensch - Copyright (C) 2007-2009 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. - */ -/* test cases - 1. short USB packet (must be no -ETIMEDOUT) - 2. cancel using button on the printer (look for abort command) - 3. start scan while busy (status 0x1414) - 4. cancel using ctrl-c (must send abort command) - */ - -#define TPU_48 /* uncomment to activate TPU scan at 48 bits */ -/*#define DEBUG_TPU_48*//* uncomment to debug 48 bits TPU on a non TPU device */ -/*#define DEBUG_TPU_24*//* uncomment to debug 24 bits TPU on a non TPU device */ - -/*#define TPUIR_USE_RGB*/ /* uncomment to use RGB channels and convert them to gray; otherwise use R channel only */ - -#include "../include/sane/config.h" - -#include -#include -#include -#include /* localtime(C90) */ - -#include "pixma_rename.h" -#include "pixma_common.h" -#include "pixma_io.h" - -/* Some macro code to enhance readability */ -#define RET_IF_ERR(x) do { \ - if ((error = (x)) < 0) \ - return error; \ - } while(0) - -#define WAIT_INTERRUPT(x) do { \ - error = handle_interrupt (s, x); \ - if (s->cancel) \ - return PIXMA_ECANCELED; \ - if (error != PIXMA_ECANCELED && error < 0) \ - return error; \ - } while(0) - -#ifdef __GNUC__ -# define UNUSED(v) (void) v -#else -# define UNUSED(v) -#endif - -/* Size of the command buffer should be multiple of wMaxPacketLength and - greater than 4096+24. - 4096 = size of gamma table. 24 = header + checksum */ -#define IMAGE_BLOCK_SIZE (512*1024) -#define CMDBUF_SIZE (4096 + 24) -#define DEFAULT_GAMMA 2.0 /***** Gamma different from 1.0 is potentially impacting color profile generation *****/ -#define UNKNOWN_PID 0xffff - -#define CANON_VID 0x04a9 - -/* Generation 2 */ -#define MP810_PID 0x171a -#define MP960_PID 0x171b - -/* Generation 3 */ -/* PIXMA 2007 vintage */ -#define MP970_PID 0x1726 - -/* Flatbed scanner CCD (2007) */ -#define CS8800F_PID 0x1901 - -/* PIXMA 2008 vintage */ -#define MP980_PID 0x172d - -/* Generation 4 */ -#define MP990_PID 0x1740 - -/* Flatbed scanner CCD (2010) */ -#define CS9000F_PID 0x1908 - -/* 2010 new device (untested) */ -#define MG8100_PID 0x174b /* CCD */ - -/* 2011 new device (untested) */ -#define MG8200_PID 0x1756 /* CCD */ - -/* 2013 new device */ -#define CS9000F_MII_PID 0x190d - -/* Generation 4 XML messages that encapsulates the Pixma protocol messages */ -#define XML_START_1 \ -"\ -\ -StartJob\ -00000001\ -1" - -#define XML_START_2 \ -"\ -\ -VendorCmd\ -00000001\ -ModeShift1\ -" - -#define XML_END \ -"\ -\ -EndJob\ -00000001\ -" - -#define XML_OK "OK" - -enum mp810_state_t -{ - state_idle, - state_warmup, - state_scanning, - state_transfering, - state_finished -}; - -enum mp810_cmd_t -{ - cmd_start_session = 0xdb20, - cmd_select_source = 0xdd20, - cmd_gamma = 0xee20, - cmd_scan_param = 0xde20, - cmd_status = 0xf320, - cmd_abort_session = 0xef20, - cmd_time = 0xeb80, - cmd_read_image = 0xd420, - cmd_error_info = 0xff20, - - cmd_start_calibrate_ccd_3 = 0xd520, - cmd_end_calibrate_ccd_3 = 0xd720, - cmd_scan_param_3 = 0xd820, - cmd_scan_start_3 = 0xd920, - cmd_status_3 = 0xda20, - cmd_get_tpu_info_3 = 0xf520, - cmd_set_tpu_info_3 = 0xea20, - - cmd_e920 = 0xe920 /* seen in MP800 */ -}; - -typedef struct mp810_t -{ - enum mp810_state_t state; - pixma_cmdbuf_t cb; - uint8_t *imgbuf; - uint8_t current_status[16]; - unsigned last_block; - uint8_t generation; - /* for Generation 3 and CCD shift */ - uint8_t *linebuf; - uint8_t *data_left_ofs; - unsigned data_left_len; - int shift[3]; - unsigned color_shift; - unsigned stripe_shift; - unsigned stripe_shift2; /* added for MP810, MP960 at 4800dpi & 9000F at 9600dpi */ - unsigned jumplines; /* added for MP810, MP960 at 4800dpi & 9000F at 9600dpi */ - uint8_t tpu_datalen; - uint8_t tpu_data[0x40]; -} mp810_t; - -/* - STAT: 0x0606 = ok, - 0x1515 = failed (PIXMA_ECANCELED), - 0x1414 = busy (PIXMA_EBUSY) - - Transaction scheme - 1. command_header/data | result_header - 2. command_header | result_header/data - 3. command_header | result_header/image_data - - - data has checksum in the last byte. - - image_data has no checksum. - - data and image_data begins in the same USB packet as - command_header or result_header. - - command format #1: - u16be cmd - u8[6] 0 - u8[4] 0 - u32be PLEN parameter length - u8[PLEN-1] parameter - u8 parameter check sum - result: - u16be STAT - u8 0 - u8 0 or 0x21 if STAT == 0x1414 - u8[4] 0 - - command format #2: - u16be cmd - u8[6] 0 - u8[4] 0 - u32be RLEN result length - result: - u16be STAT - u8[6] 0 - u8[RLEN-1] result - u8 result check sum - - command format #3: (only used by read_image_block) - u16be 0xd420 - u8[6] 0 - u8[4] 0 - u32be max. block size + 8 - result: - u16be STAT - u8[6] 0 - u8 block info bitfield: 0x8 = end of scan, 0x10 = no more paper, 0x20 = no more data - u8[3] 0 - u32be ILEN image data size - u8[ILEN] image data - */ - -static void mp810_finish_scan (pixma_t * s); - -static int is_scanning_from_adf (pixma_t * s) -{ - return (s->param->source == PIXMA_SOURCE_ADF - || s->param->source == PIXMA_SOURCE_ADFDUP); -} - -static int is_scanning_from_adfdup (pixma_t * s) -{ - return (s->param->source == PIXMA_SOURCE_ADFDUP); -} - -static int is_scanning_from_tpu (pixma_t * s) -{ - return (s->param->source == PIXMA_SOURCE_TPU); -} - -static int send_xml_dialog (pixma_t * s, const char * xml_message) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - int datalen; - - datalen = pixma_cmd_transaction (s, xml_message, strlen (xml_message), - mp->cb.buf, 1024); - if (datalen < 0) - return datalen; - - mp->cb.buf[datalen] = 0; - - PDBG(pixma_dbg (10, "XML message sent to scanner:\n%s\n", xml_message)); - PDBG(pixma_dbg (10, "XML response back from scanner:\n%s\n", mp->cb.buf)); - - return (strcasestr ((const char *) mp->cb.buf, XML_OK) != NULL); -} - -static void new_cmd_tpu_msg (pixma_t *s, pixma_cmdbuf_t * cb, uint16_t cmd) -{ - pixma_newcmd (cb, cmd, 0, 0); - cb->buf[3] = (is_scanning_from_tpu (s)) ? 0x01 : 0x00; -} - -static int start_session (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - - new_cmd_tpu_msg (s, &mp->cb, cmd_start_session); - return pixma_exec (s, &mp->cb); -} - -static int start_scan_3 (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - - new_cmd_tpu_msg (s, &mp->cb, cmd_scan_start_3); - return pixma_exec (s, &mp->cb); -} - -static int send_cmd_start_calibrate_ccd_3 (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - - pixma_newcmd (&mp->cb, cmd_start_calibrate_ccd_3, 0, 0); - mp->cb.buf[3] = 0x01; - return pixma_exec (s, &mp->cb); -} - -static int is_calibrated (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - if (mp->generation >= 3) - { - return ((mp->current_status[0] & 0x01) == 1); - } - if (mp->generation == 1) - { - return (mp->current_status[8] == 1); - } - else - { - return (mp->current_status[9] == 1); - } -} - -static int has_paper (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - - if (is_scanning_from_adfdup (s)) - return (mp->current_status[1] == 0 || mp->current_status[2] == 0); - else - return (mp->current_status[1] == 0); -} - -static void drain_bulk_in (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - while (pixma_read (s->io, mp->imgbuf, IMAGE_BLOCK_SIZE) >= 0) - ; -} - -static int abort_session (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_abort_session); -} - -static int send_cmd_e920 (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - return pixma_exec_short_cmd (s, &mp->cb, cmd_e920); -} - -static int select_source (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - uint8_t *data; - - data = pixma_newcmd (&mp->cb, cmd_select_source, 12, 0); - data[5] = ((mp->generation == 2) ? 1 : 0); - switch (s->param->source) - { - case PIXMA_SOURCE_FLATBED: - data[0] = 1; - data[1] = 1; - break; - - case PIXMA_SOURCE_ADF: - data[0] = 2; - data[5] = 1; - data[6] = 1; - break; - - case PIXMA_SOURCE_ADFDUP: - data[0] = 2; - data[5] = 3; - data[6] = 3; - break; - - case PIXMA_SOURCE_TPU: - data[0] = 4; - data[1] = 2; - break; - } - return pixma_exec (s, &mp->cb); -} - -static int send_get_tpu_info_3 (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mp->cb, cmd_get_tpu_info_3, 0, 0x34); - RET_IF_ERR(pixma_exec (s, &mp->cb)); - memcpy (mp->tpu_data, data, 0x34); - return error; -} - -static int send_set_tpu_info (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - uint8_t *data; - - if (mp->tpu_datalen == 0) - return 0; - data = pixma_newcmd (&mp->cb, cmd_set_tpu_info_3, 0x34, 0); - memcpy (data, mp->tpu_data, 0x34); - return pixma_exec (s, &mp->cb); -} - -static int send_gamma_table (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - const uint8_t *lut = s->param->gamma_table; - uint8_t *data; - - if (mp->generation == 1) - { - data = pixma_newcmd (&mp->cb, cmd_gamma, 4096 + 8, 0); - data[0] = (s->param->channels == 3) ? 0x10 : 0x01; - pixma_set_be16 (0x1004, data + 2); - if (lut) - memcpy (data + 4, lut, 4096); - else - pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 4096); - } - else - { - /* FIXME: Gamma table for 2nd generation: 1024 * uint16_le */ - data = pixma_newcmd (&mp->cb, cmd_gamma, 2048 + 8, 0); - data[0] = 0x10; - pixma_set_be16 (0x0804, data + 2); - if (lut) - { - int i; - for (i = 0; i < 1024; i++) - { - int j = (i << 2) + (i >> 8); - data[4 + 2 * i + 0] = lut[j]; - data[4 + 2 * i + 1] = lut[j]; - } - } - else - { - int i; - pixma_fill_gamma_table (DEFAULT_GAMMA, data + 4, 2048); - for (i = 0; i < 1024; i++) - { - int j = (i << 1) + (i >> 9); - data[4 + 2 * i + 0] = data[4 + j]; - data[4 + 2 * i + 1] = data[4 + j]; - } - } - } - return pixma_exec (s, &mp->cb); -} - -static unsigned calc_raw_width (const mp810_t * mp, - const pixma_scan_param_t * param) -{ - unsigned raw_width; - /* NOTE: Actually, we can send arbitary width to MP810. Lines returned - are always padded to multiple of 4 or 12 pixels. Is this valid for - other models, too? */ - if (mp->generation >= 2) - { - raw_width = ALIGN_SUP (param->w + param->xs, 32); - /* PDBG (pixma_dbg (4, "*calc_raw_width***** width %u extended by %u and rounded to %u *****\n", param->w, param->xs, raw_width)); */ - } - else if (param->channels == 1) - { - raw_width = ALIGN_SUP (param->w + param->xs, 12); - } - else - { - raw_width = ALIGN_SUP (param->w + param->xs, 4); - } - return raw_width; -} - -static int has_ccd_sensor (pixma_t * s) -{ - return ((s->cfg->cap & PIXMA_CAP_CCD) != 0); -} - -#if 0 -static int is_color (pixma_t * s) -{ - return (s->param->mode == PIXMA_SCAN_MODE_COLOR); -} - -static int is_color_48 (pixma_t * s) -{ - return (s->param->mode == PIXMA_SCAN_MODE_COLOR_48); -} - -static int is_color_negative (pixma_t * s) -{ - return (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_COLOR); -} - -static int is_color_all (pixma_t * s) -{ - return (is_color (s) || is_color_48 (s) || is_color_negative (s)); -} -#endif - -static int is_gray (pixma_t * s) -{ - return (s->param->mode == PIXMA_SCAN_MODE_GRAY); -} - -static int is_gray_16 (pixma_t * s) -{ - return (s->param->mode == PIXMA_SCAN_MODE_GRAY_16); -} - -static int is_gray_negative (pixma_t * s) -{ - return (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_GRAY); -} - -static int is_gray_all (pixma_t * s) -{ - return (is_gray (s) || is_gray_16 (s) || is_gray_negative (s)); -} - -static int is_lineart (pixma_t * s) -{ - return (s->param->mode == PIXMA_SCAN_MODE_LINEART); -} - -static int is_tpuir (pixma_t * s) -{ - return (s->param->mode == PIXMA_SCAN_MODE_TPUIR); -} - -/* CCD sensors don't have neither a Grayscale mode nor a Lineart mode, - * but use color mode instead */ -static unsigned get_cis_ccd_line_size (pixma_t * s) -{ - return (( - s->param->wx ? s->param->line_size / s->param->w * s->param->wx - : s->param->line_size) - * ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : 1)); -} - -static unsigned calc_shifting (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - - /* If stripes shift needed (CCD devices), how many pixels shift */ - mp->stripe_shift = 0; - mp->stripe_shift2 = 0; - mp->jumplines = 0; - - switch (s->cfg->pid) - { - case MP970_PID: /* MP970 at 4800 dpi */ - case CS8800F_PID: /* CanoScan 8800F at 4800 dpi */ - if (s->param->xdpi == 4800) - { - if (is_scanning_from_tpu (s)) - mp->stripe_shift = 6; - else - mp->stripe_shift = 3; - } - break; - - case CS9000F_PID: /* CanoScan 9000F at 4800 dpi */ - case CS9000F_MII_PID: - if (s->param->xdpi == 4800) - { - if (is_scanning_from_tpu (s)) - mp->stripe_shift = 6; /* should work for CS9000F same as manual */ - else - mp->stripe_shift = 3; - } - if (s->param->xdpi == 9600) - { - if (is_scanning_from_tpu (s)) - { - /* need to double up for TPU */ - mp->stripe_shift = 6; /* for 1st set of 4 images */ - /* unfortunately there are 2 stripe shifts */ - mp->stripe_shift2 = 6; /* for 2nd set of 4 images */ - mp->jumplines = 32; /* try 33 or 34 */ - } - /* there is no 9600dpi support in flatbed mode */ - } - break; - - case MP960_PID: - if (s->param->xdpi == 2400) - { - if (is_scanning_from_tpu (s)) - mp->stripe_shift = 6; - else - mp->stripe_shift = 3; - } - if (s->param->xdpi == 4800) - { - if (is_scanning_from_tpu (s)) - { - mp->stripe_shift = 6; - mp->stripe_shift2 = 6; - } - else - { - mp->stripe_shift = 3; - mp->stripe_shift2 = 3; - } - mp->jumplines = 33; /* better than 32 or 34 : applies to flatbed & TPU */ - } - break; - - case MP810_PID: - if (s->param->xdpi == 2400) - { - if (is_scanning_from_tpu (s)) - mp->stripe_shift = 6; - else - mp->stripe_shift = 3; - } - if (s->param->xdpi == 4800) - { - if (is_scanning_from_tpu (s)) - { - mp->stripe_shift = 6; - mp->stripe_shift2 = 6; - } - else - { - mp->stripe_shift = 3; - mp->stripe_shift2 = 3; - } - mp->jumplines = 33; /* better than 32 or 34 : applies to flatbed & TPU */ - } - break; - - case MP990_PID: - if (s->param->xdpi == 4800) - { - if (is_scanning_from_tpu (s)) - { - mp->stripe_shift = 6; - mp->stripe_shift2 = 6; - } - else - { - mp->stripe_shift = 3; - mp->stripe_shift2 = 3; - } - mp->jumplines = 34; /* better than 32 or 34 : applies to flatbed & TPU */ - } - break; - - default: /* Default, and all CIS devices */ - break; - } - /* If color plane shift (CCD devices), how many pixels shift */ - mp->color_shift = mp->shift[0] = mp->shift[1] = mp->shift[2] = 0; - if (s->param->ydpi > 75) - { - switch (s->cfg->pid) - { - case MP970_PID: - case CS8800F_PID: /* CanoScan 8800F */ - mp->color_shift = s->param->ydpi / 50; - mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); - mp->shift[0] = 0; - mp->shift[2] = 2 * mp->shift[1]; - break; - - case CS9000F_PID: /* CanoScan 9000F */ - case CS9000F_MII_PID: - mp->color_shift = s->param->ydpi / 30; - mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); - mp->shift[0] = 0; - mp->shift[2] = 2 * mp->shift[1]; - break; - - case MP980_PID: - case MP990_PID: - case MG8200_PID: - if (s->param->ydpi > 150) - { - mp->color_shift = s->param->ydpi / 75; - mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); - mp->shift[0] = 0; - mp->shift[2] = 2 * mp->shift[1]; - } - break; - - case MP810_PID: - case MP960_PID: - mp->color_shift = s->param->ydpi / 50; - if (is_scanning_from_tpu (s)) - mp->color_shift = s->param->ydpi / 50; - mp->shift[1] = mp->color_shift * get_cis_ccd_line_size (s); - mp->shift[0] = 2 * mp->shift[1]; - mp->shift[2] = 0; - break; - - default: - break; - } - } - /* special settings for 16 bit flatbed mode @ 75 dpi - * minimum of 150 dpi is used yet */ - /* else if (!is_scanning_from_tpu (s)) - { - switch (s->cfg->pid) - { - case CS9000F_PID: - case CS9000F_MII_PID: - if (is_color_48 (s) || is_gray_16 (s)) - { - mp->color_shift = 5; - mp->shift[1] = 0; - mp->shift[0] = 0; - mp->shift[2] = 0; - } - break; - } - } */ - /* PDBG (pixma_dbg (4, "*calc_shifing***** color_shift = %u, stripe_shift = %u, jumplines = %u *****\n", - mp->color_shift, mp->stripe_shift, mp->jumplines)); */ - return (2 * mp->color_shift + mp->stripe_shift + mp->jumplines); /* note impact of stripe shift2 later if needed! */ -} - -static int send_scan_param (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - uint8_t *data; - unsigned raw_width = calc_raw_width (mp, s->param); - unsigned h, h1, h2, shifting; - - /* TPU scan does not support lineart */ - if (is_scanning_from_tpu (s) && is_lineart (s)) - { - return PIXMA_ENOTSUP; - } - - shifting = calc_shifting (s); - h1 = s->param->h + shifting; /* add lines for color shifting */ - /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 1 %u \n", h1 )); */ - if (mp->generation >= 4) /* use most global condition */ - { - /* tested for MP960, 9000F */ - /* add lines for color shifting */ - /* otherwise you cannot scan all lines defined for flatbed mode */ - /* this shouldn't affect TPU mode */ - h2 = s->cfg->height * s->param->ydpi / 75 + shifting; - /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 2 %u = %u max. lines for scanner + %u lines for color shifting \n", h2, s->cfg->height * s->param->ydpi / 75, shifting )); */ - } - else - { - /* TODO: Check for other scanners. */ - h2 = s->cfg->height * s->param->ydpi / 75; /* this might be causing problems for generation 1 devices */ - /* PDBG (pixma_dbg (4, "* send_scan_param: height calc (choose lesser) 2 %u \n", h2 )); */ - } - h = MIN (h1, h2); - - if (mp->generation <= 2) - { - data = pixma_newcmd (&mp->cb, cmd_scan_param, 0x30, 0); - pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x04); - pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x06); - pixma_set_be32 (s->param->x, data + 0x08); - if (mp->generation == 2) - pixma_set_be32 (s->param->x - s->param->xs, data + 0x08); - pixma_set_be32 (s->param->y, data + 0x0c); - pixma_set_be32 (raw_width, data + 0x10); - pixma_set_be32 (h, data + 0x14); - data[0x18] = - ((s->param->channels != 1) || is_gray_all (s) || is_lineart (s)) ? - 0x08 : 0x04; - data[0x19] = ((s->param->software_lineart) ? 8 : s->param->depth) - * ((is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels); /* bits per pixel */ - data[0x1a] = (is_scanning_from_tpu (s) ? 1 : 0); - data[0x20] = 0xff; - data[0x23] = 0x81; - data[0x26] = 0x02; - data[0x27] = 0x01; - } - else - { - /* scan parameters: - * ================ - * - * byte | # of | mode | value / description - * | bytes | | - * -----+-------+---------+--------------------------- - * 0x00 | 1 | default | 0x01 - * | | adf | 0x02 - * | | tpu | 0x04 - * | | tpuir | cs9000f: 0x03 - * -----+-------+---------+--------------------------- - * 0x01 | 1 | default | 0x00 - * | | tpu | 0x02 - * -----+-------+---------+--------------------------- - * 0x02 | 1 | default | 0x01 - * | | adfdup | 0x03 - * -----+-------+---------+--------------------------- - * 0x03 | 1 | default | 0x00 - * | | adfdup | 0x03 - * -----+-------+---------+--------------------------- - * 0x04 | 1 | all | 0x00 - * -----+-------+---------+--------------------------- - * 0x05 | 1 | all | 0x01: This one also seen at 0. Don't know yet what's used for. - * -----+-------+---------+--------------------------- - * ... | 1 | all | 0x00 - * -----+-------+---------+--------------------------- - * 0x08 | 2 | all | xdpi | 0x8000 - * -----+-------+---------+--------------------------- - * 0x0a | 2 | all | ydpi | 0x8000: Must be the same as xdpi. - * -----+-------+---------+--------------------------- - * 0x0c | 4 | all | x position of start pixel - * -----+-------+---------+--------------------------- - * 0x10 | 4 | all | y position of start pixel - * -----+-------+---------+--------------------------- - * 0x14 | 4 | all | # of pixels in 1 line - * -----+-------+---------+--------------------------- - * 0x18 | 4 | all | # of scan lines - * -----+-------+---------+--------------------------- - * 0x1c | 1 | all | 0x08 - * | | | 0x04 = relict from cis scanners? - * -----+-------+---------+--------------------------- - * 0x1d | 1 | all | # of bits per pixel - * -----+-------+---------+--------------------------- - * 0x1e | 1 | default | 0x00: paper - * | | tpu | 0x01: positives - * | | tpu | 0x02: negatives - * | | tpuir | 0x01: positives - * -----+-------+---------+--------------------------- - * 0x1f | 1 | all | 0x01 - * | | | cs9000f: 0x00: Not sure if that is because of positives. - * -----+-------+---------+--------------------------- - * 0x20 | 1 | all | 0xff - * -----+-------+---------+--------------------------- - * 0x21 | 1 | all | 0x81 - * -----+-------+---------+--------------------------- - * 0x22 | 1 | all | 0x00 - * -----+-------+---------+--------------------------- - * 0x23 | 1 | all | 0x02 - * -----+-------+---------+--------------------------- - * 0x24 | 1 | all | 0x01 - * -----+-------+---------+--------------------------- - * 0x25 | 1 | default | 0x00; cs8800f: 0x01 - * | | tpu | 0x00; cs9000f, mg8200, mp990: 0x01 - * | | tpuir | cs9000f: 0x00 - * -----+-------+---------+--------------------------- - * ... | 1 | all | 0x00 - * -----+-------+---------+--------------------------- - * 0x30 | 1 | all | 0x01 - * - */ - - data = pixma_newcmd (&mp->cb, cmd_scan_param_3, 0x38, 0); - data[0x00] = is_scanning_from_adf (s) ? 0x02 : 0x01; - data[0x01] = 0x01; - if (is_scanning_from_tpu (s)) - { - data[0x00] = is_tpuir (s) ? 0x03 : 0x04; - data[0x01] = 0x02; - data[0x1e] = 0x02; /* NB: CanoScan 8800F: 0x02->negatives, 0x01->positives, paper->0x00 */ - } - data[0x02] = 0x01; - if (is_scanning_from_adfdup (s)) - { - data[0x02] = 0x03; - data[0x03] = 0x03; - } - if (s->cfg->pid != MG8200_PID) - data[0x05] = 0x01; /* This one also seen at 0. Don't know yet what's used for */ - /* the scanner controls the scan */ - /* no software control needed */ - pixma_set_be16 (s->param->xdpi | 0x8000, data + 0x08); - pixma_set_be16 (s->param->ydpi | 0x8000, data + 0x0a); - /*PDBG (pixma_dbg (4, "*send_scan_param***** Setting: xdpi=%hi ydpi=%hi x=%u y=%u w=%u h=%u ***** \n", - s->param->xdpi,s->param->ydpi,(s->param->x)-(s->param->xs),s->param->y,raw_width,h));*/ - pixma_set_be32 (s->param->x - s->param->xs, data + 0x0c); - pixma_set_be32 (s->param->y, data + 0x10); - pixma_set_be32 (raw_width, data + 0x14); - pixma_set_be32 (h, data + 0x18); - data[0x1c] = ((s->param->channels != 1) || is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 0x08 : 0x04; - -#ifdef DEBUG_TPU_48 - data[0x1d] = 24; -#else - data[0x1d] = (is_scanning_from_tpu (s)) ? 48 - : (((s->param->software_lineart) ? 8 : s->param->depth) - * ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels)); /* bits per pixel */ -#endif - - data[0x1f] = 0x01; /* for 9000F this appears to be 0x00, not sure if that is because of positives */ - - if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID || s->cfg->pid == MG8200_PID) - { - data[0x1f] = 0x00; - } - - data[0x20] = 0xff; - data[0x21] = 0x81; - data[0x23] = 0x02; - data[0x24] = 0x01; - - /* MG8200 & MP990 addition */ - if (s->cfg->pid == MG8200_PID || s->cfg->pid == MP990_PID) - { - if (is_scanning_from_tpu (s)) - { - data[0x25] = 0x01; - } - } - - /* CS8800F & CS9000F addition */ - if (s->cfg->pid == CS8800F_PID || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) - { - if (is_scanning_from_tpu (s)) - { /* TPU */ - /* 0x02->negatives, 0x01->positives, paper->0x00 - * no paper in TPU mode */ - if (s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_COLOR - || s->param->mode == PIXMA_SCAN_MODE_NEGATIVE_GRAY) - { - PDBG( - pixma_dbg (4, "*send_scan_param***** TPU scan negatives *****\n")); - data[0x1e] = 0x02; - } - else - { - PDBG( - pixma_dbg (4, "*send_scan_param***** TPU scan positives *****\n")); - data[0x1e] = 0x01; - } - /* CS8800F: 0x00 for TPU color management */ - if (s->cfg->pid == CS8800F_PID) - data[0x25] = 0x00; - /* CS9000F: 0x01 for TPU */ - if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) - data[0x25] = 0x01; - if (s->param->mode == PIXMA_SCAN_MODE_TPUIR) - data[0x25] = 0x00; - } - else - { /* flatbed and ADF */ - /* paper->0x00 */ - data[0x1e] = 0x00; - /* CS8800F: 0x01 normally */ - if (s->cfg->pid == CS8800F_PID) - data[0x25] = 0x01; - /* CS9000F: 0x00 normally */ - if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) - data[0x25] = 0x00; - } - } - - data[0x30] = 0x01; - } - return pixma_exec (s, &mp->cb); -} - -static int query_status_3 (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - uint8_t *data; - int error, status_len; - - status_len = 8; - data = pixma_newcmd (&mp->cb, cmd_status_3, 0, status_len); - RET_IF_ERR(pixma_exec (s, &mp->cb)); - memcpy (mp->current_status, data, status_len); - return error; -} - -static int query_status (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - uint8_t *data; - int error, status_len; - - status_len = (mp->generation == 1) ? 12 : 16; - data = pixma_newcmd (&mp->cb, cmd_status, 0, status_len); - RET_IF_ERR(pixma_exec (s, &mp->cb)); - memcpy (mp->current_status, data, status_len); - PDBG( - pixma_dbg (3, "Current status: paper=%u cal=%u lamp=%u busy=%u\n", data[1], data[8], data[7], data[9])); - return error; -} - -#if 0 -static int send_time (pixma_t * s) -{ - /* Why does a scanner need a time? */ - time_t now; - struct tm *t; - uint8_t *data; - mp810_t *mp = (mp810_t *) s->subdriver; - - data = pixma_newcmd (&mp->cb, cmd_time, 20, 0); - pixma_get_time (&now, NULL); - t = localtime (&now); - snprintf ((char *) data, 16, "%02d/%02d/%02d %02d:%02d", t->tm_year % 100, - t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min); - PDBG(pixma_dbg (3, "Sending time: '%s'\n", (char *) data)); - return pixma_exec (s, &mp->cb); -} -#endif - -/* TODO: Simplify this function. Read the whole data packet in one shot. */ -static int read_image_block (pixma_t * s, uint8_t * header, uint8_t * data) -{ - uint8_t cmd[16]; - mp810_t *mp = (mp810_t *) s->subdriver; - const int hlen = 8 + 8; - int error, datalen; - - memset (cmd, 0, sizeof(cmd)); - /* PDBG (pixma_dbg (4, "* read_image_block: last_block\n", mp->last_block)); */ - pixma_set_be16 (cmd_read_image, cmd); - if ((mp->last_block & 0x20) == 0) - pixma_set_be32 ((IMAGE_BLOCK_SIZE / 65536) * 65536 + 8, cmd + 0xc); - else - pixma_set_be32 (32 + 8, cmd + 0xc); - - mp->state = state_transfering; - mp->cb.reslen = pixma_cmd_transaction (s, cmd, sizeof(cmd), mp->cb.buf, 512); /* read 1st 512 bytes of image block */ - datalen = mp->cb.reslen; - if (datalen < 0) - return datalen; - - memcpy (header, mp->cb.buf, hlen); - /* PDBG (pixma_dbg (4, "* read_image_block: datalen %i\n", datalen)); */ - /* PDBG (pixma_dbg (4, "* read_image_block: hlen %i\n", hlen)); */ - if (datalen >= hlen) - { - datalen -= hlen; - memcpy (data, mp->cb.buf + hlen, datalen); - data += datalen; - if (mp->cb.reslen == 512) - { /* read the rest of the image block */ - error = pixma_read (s->io, data, IMAGE_BLOCK_SIZE - 512 + hlen); - RET_IF_ERR(error); - datalen += error; - } - } - - mp->state = state_scanning; - mp->cb.expected_reslen = 0; - RET_IF_ERR(pixma_check_result (&mp->cb)); - if (mp->cb.reslen < hlen) - return PIXMA_EPROTO; - return datalen; -} - -static int read_error_info (pixma_t * s, void *buf, unsigned size) -{ - unsigned len = 16; - mp810_t *mp = (mp810_t *) s->subdriver; - uint8_t *data; - int error; - - data = pixma_newcmd (&mp->cb, cmd_error_info, 0, len); - RET_IF_ERR(pixma_exec (s, &mp->cb)); - if (buf && len < size) - { - size = len; - /* NOTE: I've absolutely no idea what the returned data mean. */ - memcpy (buf, data, size); - error = len; - } - return error; -} - -/* - handle_interrupt() waits until it receives an interrupt packet or times out. - It calls send_time() and query_status() if necessary. Therefore, make sure - that handle_interrupt() is only called from a safe context for send_time() - and query_status(). - - Returns: - 0 timed out - 1 an interrupt packet received - PIXMA_ECANCELED interrupted by signal - <0 error - */ -static int handle_interrupt (pixma_t * s, int timeout) -{ - uint8_t buf[64]; /* check max. packet size with 'lsusb -v' for "EP 9 IN" */ - int len; - - len = pixma_wait_interrupt (s->io, buf, sizeof(buf), timeout); - if (len == PIXMA_ETIMEDOUT) - return 0; - if (len < 0) - return len; - if (len%16) /* len must be a multiple of 16 bytes */ - { - PDBG(pixma_dbg (1, "WARNING:unexpected interrupt packet length %d\n", len)); - return PIXMA_EPROTO; - } - - /* s->event = 0x0brroott - * b: button - * oo: original - * tt: target - * rr: scan resolution - * poll event with 'scanimage -A' */ - if (s->cfg->pid == MG8200_PID) - /* button no. in buf[7] - * size in buf[10] 01=A4; 02=Letter; 08=10x15; 09=13x18; 0b=auto - * format in buf[11] 01=JPEG; 02=TIFF; 03=PDF; 04=Kompakt-PDF - * dpi in buf[12] 01=75; 02=150; 03=300; 04=600 - * target = format; original = size; scan-resolution = dpi */ - { - if (buf[7] & 1) - s->events = PIXMA_EV_BUTTON1 | buf[11] | buf[10]<<8 | buf[12]<<16; /* color scan */ - if (buf[7] & 2) - s->events = PIXMA_EV_BUTTON2 | buf[11] | buf[10]<<8 | buf[12]<<16; /* b/w scan */ - } - else if (s->cfg->pid == CS8800F_PID - || s->cfg->pid == CS9000F_PID - || s->cfg->pid == CS9000F_MII_PID) - /* button no. in buf[1] - * target = button no. - * "Finish PDF" is Button-2, all others are Button-1 */ - { - if ((s->cfg->pid == CS8800F_PID && buf[1] == 0x70) - || (s->cfg->pid != CS8800F_PID && buf[1] == 0x50)) - s->events = PIXMA_EV_BUTTON2 | buf[1] >> 4; /* button 2 = cancel / end scan */ - else - s->events = PIXMA_EV_BUTTON1 | buf[1] >> 4; /* button 1 = start scan */ - } - else - /* button no. in buf[0] - * original in buf[0] - * target in buf[1] */ - { - /* More than one event can be reported at the same time. */ - if (buf[3] & 1) - /* FIXME: This function makes trouble with a lot of scanners - send_time (s); - */ - PDBG (pixma_dbg (1, "WARNING:send_time() disabled!\n")); - if (buf[9] & 2) - query_status (s); - - if (buf[0] & 2) - s->events = PIXMA_EV_BUTTON2 | buf[1] | ((buf[0] & 0xf0) << 4); /* b/w scan */ - if (buf[0] & 1) - s->events = PIXMA_EV_BUTTON1 | buf[1] | ((buf[0] & 0xf0) << 4); /* color scan */ - } - return 1; -} - -static int init_ccd_lamp_3 (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - uint8_t *data; - int error, status_len, tmo; - - status_len = 8; - RET_IF_ERR(query_status (s)); - RET_IF_ERR(query_status (s)); - RET_IF_ERR(send_cmd_start_calibrate_ccd_3 (s)); - RET_IF_ERR(query_status (s)); - tmo = 20; /* like Windows driver, CCD lamp adjustment */ - while (--tmo >= 0) - { - data = pixma_newcmd (&mp->cb, cmd_end_calibrate_ccd_3, 0, status_len); - RET_IF_ERR(pixma_exec (s, &mp->cb)); - memcpy (mp->current_status, data, status_len); - PDBG(pixma_dbg (3, "Lamp status: %u , timeout in: %u\n", data[0], tmo)); - if (mp->current_status[0] == 3 || !is_scanning_from_tpu (s)) - break; - WAIT_INTERRUPT(1000); - } - return error; -} - -static int wait_until_ready (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - int error, tmo = 60; - - RET_IF_ERR((mp->generation >= 3) ? query_status_3 (s) : query_status (s)); - while (!is_calibrated (s)) - { - WAIT_INTERRUPT(1000); - if (mp->generation >= 3) - RET_IF_ERR(query_status_3 (s)); - if (--tmo == 0) - { - PDBG(pixma_dbg (1, "WARNING: Timed out in wait_until_ready()\n")); - PDBG(query_status (s)); - return PIXMA_ETIMEDOUT; - } - } - return 0; -} - -/* the RGB images are shifted by # of lines */ -/* the R image is shifted by colshift[0] */ -/* the G image is shifted by colshift[1] */ -/* the B image is shifted by colshift[2] */ -/* usually one of the RGB images must not be shifted */ -/* which one depends on the scanner */ -/* some scanners have an additional stripe shift */ -/* e.g. colshift[0]=0, colshift[1]=1, colshift[2]=2 */ -/* R image is OK: RGBRGBRGB... */ -/* ^^ ^^ ^^ */ -/* || || || */ -/* shift G image: RG|RG|RG|... */ -/* | | | */ -/* shift B image: RGBRGBRGB... */ -/* this doesn't affect the G and B images */ -/* G image will become the R image in the next run */ -/* B image will become the G image in the next run */ -/* the next line will become the B image in the next run */ -static uint8_t * -shift_colors (uint8_t * dptr, uint8_t * sptr, unsigned w, unsigned dpi, - unsigned pid, unsigned c, int * colshft, unsigned strshft) -{ - unsigned i, sr, sg, sb, st; - UNUSED(dpi); - UNUSED(pid); - sr = colshft[0]; - sg = colshft[1]; - sb = colshft[2]; - - /* PDBG (pixma_dbg (4, "*shift_colors***** c=%u, w=%i, sr=%u, sg=%u, sb=%u, strshft=%u ***** \n", - c, w, sr, sg, sb, strshft)); */ - - for (i = 0; i < w; i++) - { - /* stripes shift for MP970 at 4800 dpi, MP810 at 2400 dpi */ - st = (i % 2 == 0) ? strshft : 0; - - *sptr++ = *(dptr++ + sr + st); - if (c == 6) - *sptr++ = *(dptr++ + sr + st); - *sptr++ = *(dptr++ + sg + st); - if (c == 6) - *sptr++ = *(dptr++ + sg + st); - *sptr++ = *(dptr++ + sb + st); - if (c == 6) - *sptr++ = *(dptr++ + sb + st); - } - - return dptr; -} - -static uint8_t * -shift_colorsCS9000 (uint8_t * dptr, uint8_t * sptr, unsigned w, unsigned dpi, - unsigned pid, unsigned c, int * colshft, unsigned strshft, - unsigned strshft2, unsigned jump) - -{ - unsigned i, sr, sg, sb, st, st2; - UNUSED(dpi); - UNUSED(pid); - sr = colshft[0]; - sg = colshft[1]; - sb = colshft[2]; - - for (i = 0; i < w; i++) - { - if (i < (w / 2)) - { - /* stripes shift for 1st 4 images for Canoscan 9000F at 9600dpi */ - st = (i % 2 == 0) ? strshft : 0; - *sptr++ = *(dptr++ + sr + st); - if (c == 6) - *sptr++ = *(dptr++ + sr + st); - *sptr++ = *(dptr++ + sg + st); - if (c == 6) - *sptr++ = *(dptr++ + sg + st); - *sptr++ = *(dptr++ + sb + st); - if (c == 6) - *sptr++ = *(dptr++ + sb + st); - } - if (i >= (w / 2)) - { - /* stripes shift for 2nd 4 images for Canoscan 9000F at 9600dpi */ - st2 = (i % 2 == 0) ? strshft2 : 0; - *sptr++ = *(dptr++ + sr + jump + st2); - if (c == 6) - *sptr++ = *(dptr++ + sr + jump + st2); - *sptr++ = *(dptr++ + sg + jump + st2); - if (c == 6) - *sptr++ = *(dptr++ + sg + jump + st2); - *sptr++ = *(dptr++ + sb + jump + st2); - if (c == 6) - *sptr++ = *(dptr++ + sb + jump + st2); - } - } - return dptr; -} - -static uint8_t * -shift_colorsCS9000_4800 (uint8_t * dptr, uint8_t * sptr, unsigned w, - unsigned dpi, unsigned pid, unsigned c, int * colshft, - unsigned strshft, unsigned strshft2, unsigned jump) - -{ - unsigned i, sr, sg, sb, st2; - UNUSED(dpi); - UNUSED(pid); - UNUSED(strshft); - sr = colshft[0]; - sg = colshft[1]; - sb = colshft[2]; - - for (i = 0; i < w; i++) - { - /* stripes shift for 2nd 4 images - * for Canoscan 9000F with 16 bit flatbed scans at 4800dpi */ - st2 = (i % 2 == 0) ? strshft2 : 0; - *sptr++ = *(dptr++ + sr + jump + st2); - if (c == 6) - *sptr++ = *(dptr++ + sr + jump + st2); - *sptr++ = *(dptr++ + sg + jump + st2); - if (c == 6) - *sptr++ = *(dptr++ + sg + jump + st2); - *sptr++ = *(dptr++ + sb + jump + st2); - if (c == 6) - *sptr++ = *(dptr++ + sb + jump + st2); - } - return dptr; -} - -/* under some conditions some scanners have sub images in one line */ -/* e.g. doubled image, line size = 8 */ -/* line before reordering: px1 px3 px5 px7 px2 px4 px6 px8 */ -/* line after reordering: px1 px2 px3 px4 px5 px6 px7 px8 */ -static void reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, - unsigned n, unsigned m, unsigned w, - unsigned line_size) -{ - unsigned i; - - for (i = 0; i < w; i++) - { /* process complete line */ - memcpy (linebuf + c * (n * (i % m) + i / m), sptr + c * i, c); - } - memcpy (sptr, linebuf, line_size); -} - -/* special reorder matrix for mp960 */ -static void mp960_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, - unsigned n, unsigned m, unsigned w, - unsigned line_size) -{ - unsigned i, i2; - - /* try and copy 2 px at once */ - for (i = 0; i < w; i++) - { /* process complete line */ - i2 = i % 2; - if (i < w / 2) - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m)), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m)), sptr + c * i, c); - } - else - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 1), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 1), sptr + c * i, c); - } - } - - memcpy (sptr, linebuf, line_size); -} - -/* special reorder matrix for mp970 */ -static void mp970_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, unsigned c, - unsigned w, unsigned line_size) -{ - unsigned i, i8; - - for (i = 0; i < w; i++) - { /* process complete line */ - i8 = i % 8; - memcpy (linebuf + c * (i + i8 - ((i8 > 3) ? 7 : 0)), sptr + c * i, c); - } - memcpy (sptr, linebuf, line_size); -} - -/* special reorder matrix for CS9000F */ -static void cs9000f_initial_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, - unsigned c, unsigned n, unsigned m, - unsigned w, unsigned line_size) -{ - unsigned i, i2; - - /* try and copy 2 px at once */ - for (i = 0; i < w; i++) - { /* process complete line */ - i2 = i % 2; - if (i < w / 8) - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m)), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m)), sptr + c * i, c); - } - else if (i >= w / 8 && i < w / 4) - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 1), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 1), sptr + c * i, c); - } - else if (i >= w / 4 && i < 3 * w / 8) - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 2), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 2), sptr + c * i, c); - } - else if (i >= 3 * w / 8 && i < w / 2) - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 3), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 3), sptr + c * i, c); - } - else if (i >= w / 2 && i < 5 * w / 8) - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 4), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 4), sptr + c * i, c); - } - else if (i >= 5 * w / 8 && i < 3 * w / 4) - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 5), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 5), sptr + c * i, c); - } - else if (i >= 3 * w / 4 && i < 7 * w / 8) - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 6), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 6), sptr + c * i, c); - } - else - { - if (i2 == 0) - memcpy (linebuf + c * (n * ((i) % m) + ((i) / m) + 7), sptr + c * i, c); - else - memcpy (linebuf + c * (n * ((i - 1) % m) + 1 + ((i) / m) + 7), sptr + c * i, c); - } - } - - memcpy (sptr, linebuf, line_size); -} - -/* CS9000F 9600dpi reorder: actually 4800dpi since each pixel is doubled */ -/* need to rearrange each sequence of 16 pairs of pixels as follows: */ -/* start px : 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 */ -/* before : p1a p1b p1c p1d p2a p2b p2c p2d p3a p3b p3c p3d p4a p4b p4c p4d */ -/* after : p1a p3a p1b p3b p1c p3c p1d p3d p2a p4a p2b p4b p2c p4c p2d p4d */ -/* start px : 0 16 2 18 4 20 6 22 8 24 10 26 12 28 14 30 */ -/* change : * * * * * * * * * * * * * * */ -/* no change: * * */ -/* so the 1st and the 3rd set are interleaved, followed by the 2nd and 4th sets interleaved */ -static void cs9000f_second_reorder_pixels (uint8_t * linebuf, uint8_t * sptr, - unsigned c, unsigned w, - unsigned line_size) -{ - unsigned i, i8; - static const int shifts[8] = - { 2, 4, 6, 8, -8, -6, -4, -2 }; - - for (i = 0; i < w; i += 2) - { /* process complete line */ - i8 = (i >> 1) & 0x7; - /* Copy 2 pixels at once */ - memcpy (linebuf + c * (i + shifts[i8]), sptr + c * i, c * 2); - } - - memcpy (sptr, linebuf, line_size); -} - -#ifndef TPU_48 -static unsigned -pack_48_24_bpc (uint8_t * sptr, unsigned n) -{ - unsigned i; - uint8_t *cptr, lsb; - static uint8_t offset = 0; - - cptr = sptr; - if (n % 2 != 0) - PDBG (pixma_dbg (3, "WARNING: misaligned image.\n")); - for (i = 0; i < n; i += 2) - { - /* offset = 1 + (offset % 3); */ - lsb = *sptr++; - *cptr++ = ((*sptr++) << offset) | lsb >> (8 - offset); - } - return (n / 2); -} -#endif - -/* This function deals both with PIXMA CCD sensors producing shifted color - * planes images, Grayscale CCD scan and Generation >= 3 high dpi images. - * Each complete line in mp->imgbuf is processed for shifting CCD sensor - * color planes, reordering pixels above 600 dpi for Generation >= 3, and - * converting to Grayscale for CCD sensors. */ -static unsigned post_process_image_data (pixma_t * s, pixma_imagebuf_t * ib) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - unsigned c, lines, line_size, n, m, cw, cx, reducelines; - uint8_t *sptr, *dptr, *gptr, *cptr; - unsigned /*color_shift, stripe_shift, stripe_shift2,*/ jumplines /*, height*/; - int test; - - /* For testers: */ - /* set this to 1 in order to get unprocessed images next to one another at 9600dpi */ - /* other resolutions should not be affected */ - /* set this to 2 if you want to see the same with jumplines=0 */ - test = 0; - jumplines = 0; - - c = ((is_tpuir (s) || is_gray_all (s) || is_lineart (s)) ? 3 : s->param->channels) - * ((s->param->software_lineart) ? 8 : s->param->depth) / 8; - cw = c * s->param->w; - cx = c * s->param->xs; - - /* PDBG (pixma_dbg (4, "*post_process_image_data***** c = %u, cw = %u, cx = %u *****\n", c, cw, cx)); */ - - if (mp->generation >= 3) - n = s->param->xdpi / 600; - else - /* FIXME: maybe need different values for CIS and CCD sensors */ - n = s->param->xdpi / 2400; - - /* Some exceptions to global rules here */ - if (s->cfg->pid == MP970_PID || s->cfg->pid == MP990_PID || s->cfg->pid == MG8200_PID - || s->cfg->pid == CS8800F_PID || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) - n = MIN (n, 4); - - /* exception for 9600dpi on Canoscan 9000F */ - if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) - { - n = 8; - if (test > 0) - n = 1; /* test if 8 images are next to one another */ - } - - /* test if 2 images are next to one another */ - if ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800) && (test > 0)) - { - n = 1; - } - - m = (n > 0) ? s->param->wx / n : 1; - - sptr = dptr = gptr = cptr = mp->imgbuf; - line_size = get_cis_ccd_line_size (s); - /* PDBG (pixma_dbg (4, "*post_process_image_data***** ----- Set n=%u, m=%u, line_size=%u ----- ***** \n", n, m, line_size)); */ - /* PDBG (pixma_dbg (4, "*post_process_image_data***** ----- spr=dpr=%u, linebuf=%u ----- ***** \n", sptr, mp->linebuf)); */ - - lines = (mp->data_left_ofs - mp->imgbuf) / line_size; - /* PDBG (pixma_dbg (4, "*post_process_image_data***** lines = %i > 2 * mp->color_shift + mp->stripe_shift = %i ***** \n", - lines, 2 * mp->color_shift + mp->stripe_shift)); */ - /* PDBG (pixma_dbg (4, "*post_process_image_data***** mp->color_shift = %u, mp->stripe_shift = %u, , mp->stripe_shift2 = %u ***** \n", - mp->color_shift, mp->stripe_shift, mp->stripe_shift2)); */ - - /*color_shift = mp->color_shift;*/ - /*stripe_shift = mp->stripe_shift;*/ - /*stripe_shift2 = mp->stripe_shift2;*/ - jumplines = mp->jumplines; - - /* height not needed here! */ - /* removed to avoid confusion */ - /* height = MIN (s->param->h + calc_shifting (s), - s->cfg->height * s->param->ydpi / 75); */ - - /* have to test if rounding down is OK or not -- currently 0.5 lines is rounded down */ - /* note stripe shifts doubled already in definitions */ - if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600) && (test > 0)) - { - /* using test==2 you can check in GIMP the required offset, and - use the below line (uncommented) and replace XXX with that - number, and then compile again with test set to 1. */ - - jumplines = 32; - if (test == 2) - jumplines = 0; - } - - /* mp960 test */ - if ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800) && (test > 0)) - { - jumplines = 32; - if (test == 2) - jumplines = 0; - } - - reducelines = ((2 * mp->color_shift + mp->stripe_shift) + jumplines); - /* PDBG (pixma_dbg (4, "*post_process_image_data: lines %u, reducelines %u \n", lines, reducelines)); */ - if (lines > reducelines) - { /* (line - reducelines) of image lines can be converted */ - unsigned i; - - lines -= reducelines; - - for (i = 0; i < lines; i++, sptr += line_size) - { /* convert only full image lines */ - /* Color plane and stripes shift needed by e.g. CCD */ - /* PDBG (pixma_dbg (4, "*post_process_image_data***** Processing with c=%u, n=%u, m=%u, w=%i, line_size=%u ***** \n", - c, n, m, s->param->wx, line_size)); */ - if (c >= 3) - { - if (((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) - || ((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800)) - || ((s->cfg->pid == MP810_PID) && (s->param->xdpi == 4800))) - { - dptr = shift_colorsCS9000 (dptr, sptr, s->param->wx, s->param->xdpi, - s->cfg->pid, c, mp->shift, - mp->stripe_shift, mp->stripe_shift2, - jumplines * line_size); - } - - else if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) /* 9000F: 16 bit flatbed scan at 4800dpi */ - && ((s->param->mode == PIXMA_SCAN_MODE_COLOR_48) - || (s->param->mode == PIXMA_SCAN_MODE_GRAY_16)) - && (s->param->xdpi == 4800) - && (s->param->source == PIXMA_SOURCE_FLATBED)) - dptr = shift_colorsCS9000_4800 (dptr, sptr, s->param->wx, - s->param->xdpi, s->cfg->pid, c, - mp->shift, mp->stripe_shift, - mp->stripe_shift2, - jumplines * line_size); - - else - /* all except 9000F at 9600dpi */ - dptr = shift_colors (dptr, sptr, s->param->wx, s->param->xdpi, - s->cfg->pid, c, mp->shift, mp->stripe_shift); - } - - /*PDBG (pixma_dbg (4, "*post_process_image_data***** test = %i *****\n", test)); */ - - /*--comment out all between this line and the one below for 9000F tests at 9600dpi or MP960 at 4800dpi ------*/ - /* if ( 0 ) */ - if ((((s->cfg->pid != CS9000F_PID && s->cfg->pid != CS9000F_MII_PID) || (s->param->xdpi < 9600)) - && ((s->cfg->pid != MP960_PID) || (s->param->xdpi < 4800)) - && ((s->cfg->pid != MP810_PID) || (s->param->xdpi < 4800))) - || (test == 0)) - { - /* PDBG (pixma_dbg (4, "*post_process_image_data***** MUST GET HERE WHEN TEST == 0 *****\n")); */ - - if (!((s->cfg->pid == MP810_PID) && (s->param->xdpi == 4800)) - && !((s->cfg->pid == MP960_PID) && (s->param->xdpi == 4800)) - && !((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600))) - { /* for both flatbed & TPU */ - /* PDBG (pixma_dbg (4, "*post_process_image_data***** reordering pixels normal n = %i *****\n", n)); */ - reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, line_size); - } - - if ((s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) && (s->param->xdpi == 9600)) - { - /* PDBG (pixma_dbg (4, "*post_process_image_data***** cs900f_initial_reorder_pixels n = %i *****\n", n)); */ - /* this combines pixels from 8 images 2px at a time from left to right: 1122334455667788... */ - cs9000f_initial_reorder_pixels (mp->linebuf, sptr, c, n, m, - s->param->wx, line_size); - /* final interleaving */ - cs9000f_second_reorder_pixels (mp->linebuf, sptr, c, s->param->wx, - line_size); - } - - /* comment: special image format for MP960 in flatbed mode - at 4800dpi. It is actually 2400dpi, with each pixel - doubled. The TPU mode has proper pixel ordering */ - if ((((s->cfg->pid == MP960_PID) || (s->cfg->pid == MP810_PID)) && (s->param->xdpi == 4800)) - && (n > 0)) - { - /* for both flatbed & TPU */ - /* PDBG (pixma_dbg (4, "*post_process_image_data***** flatbed mp960_reordering pixels n = %i *****\n", n)); */ - mp960_reorder_pixels (mp->linebuf, sptr, c, n, m, s->param->wx, - line_size); - } - - /* comment: MP970, CS8800F, CS9000F specific reordering for 4800 dpi */ - if ((s->cfg->pid == MP970_PID || s->cfg->pid == CS8800F_PID - || s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID - || s->cfg->pid == MP990_PID) && (s->param->xdpi == 4800)) - { - /*PDBG (pixma_dbg (4, "*post_process_image_data***** mp970_reordering pixels n = %i *****\n", n)); */ - mp970_reorder_pixels (mp->linebuf, sptr, c, s->param->wx, line_size); - } - - } - /*-------------------------------------------------------*/ - - /* PDBG (pixma_dbg (4, "*post_process_image_data: sptr=%u, dptr=%u \n", sptr, dptr)); */ - - /* Crop line to selected borders */ - memmove (cptr, sptr + cx, cw); - /* PDBG (pixma_dbg (4, "*post_process_image_data***** crop line: cx=%u, cw=%u ***** \n", cx, cw)); */ - - /* Color to Lineart convert for CCD sensor */ - if (is_lineart (s)) - cptr = gptr = pixma_binarize_line (s->param, gptr, cptr, s->param->w, c); -#ifndef TPUIR_USE_RGB - /* save IR only for CCD sensor */ - else if (is_tpuir (s)) - cptr = gptr = pixma_r_to_ir (gptr, cptr, s->param->w, c); - /* Color to Grayscale convert for CCD sensor */ - else if (is_gray_all (s)) -#else - /* IR *and* Color to Grayscale convert for CCD sensor */ - else if (is_tpuir (s) || is_gray_all (s)) -#endif - cptr = gptr = pixma_rgb_to_gray (gptr, cptr, s->param->w, c); - else - cptr += cw; - } - /* PDBG (pixma_dbg (4, "*post_process_image_data: sptr=%u, dptr=%u \n", sptr, dptr)); */ - } - ib->rptr = mp->imgbuf; - ib->rend = cptr; - return mp->data_left_ofs - sptr; /* # of non processed bytes */ - /* contains shift color data for new lines */ - /* and already received data for the next line */ -} - -static int mp810_open (pixma_t * s) -{ - mp810_t *mp; - uint8_t *buf; - - mp = (mp810_t *) calloc (1, sizeof(*mp)); - if (!mp) - return PIXMA_ENOMEM; - - buf = (uint8_t *) malloc (CMDBUF_SIZE + IMAGE_BLOCK_SIZE); - if (!buf) - { - free (mp); - return PIXMA_ENOMEM; - } - - s->subdriver = mp; - mp->state = state_idle; - - mp->cb.buf = buf; - mp->cb.size = CMDBUF_SIZE; - mp->cb.res_header_len = 8; - mp->cb.cmd_header_len = 16; - mp->cb.cmd_len_field_ofs = 14; - - mp->imgbuf = buf + CMDBUF_SIZE; - - /* General rules for setting Pixma protocol generation # */ - mp->generation = (s->cfg->pid >= MP810_PID) ? 2 : 1; /* no generation 1 devices anyway, but keep similar to pixma_mp150.c file */ - - if (s->cfg->pid >= MP970_PID) - mp->generation = 3; - - if (s->cfg->pid >= MP990_PID) - mp->generation = 4; - - /* And exceptions to be added here */ - if (s->cfg->pid == CS8800F_PID) - mp->generation = 3; - - if (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID) - mp->generation = 4; - - /* TPU info data setup */ - mp->tpu_datalen = 0; - - if (mp->generation < 4) - { - /* Canoscan 8800F ignores commands if not initialized */ - if (s->cfg->pid == CS8800F_PID) - abort_session (s); - else - { - query_status (s); - handle_interrupt (s, 200); - if (mp->generation == 3 && has_ccd_sensor (s)) - send_cmd_start_calibrate_ccd_3 (s); - } - } - return 0; -} - -static void mp810_close (pixma_t * s) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - - mp810_finish_scan (s); - free (mp->cb.buf); - free (mp); - s->subdriver = NULL; -} - -static int mp810_check_param (pixma_t * s, pixma_scan_param_t * sp) -{ - mp810_t *mp = (mp810_t *) s->subdriver; - unsigned w_max; - - /* PDBG (pixma_dbg (4, "*mp810_check_param***** Initially: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", - sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */ - - sp->channels = 3; - sp->software_lineart = 0; - switch (sp->mode) - { - /* standard scan modes - * 8 bit per channel in color and grayscale mode - * 16 bit per channel with TPU */ - case PIXMA_SCAN_MODE_GRAY: - case PIXMA_SCAN_MODE_NEGATIVE_GRAY: - case PIXMA_SCAN_MODE_TPUIR: - sp->channels = 1; - /* fall through */ - case PIXMA_SCAN_MODE_COLOR: - case PIXMA_SCAN_MODE_NEGATIVE_COLOR: - sp->depth = 8; -#ifdef TPU_48 -#ifndef DEBUG_TPU_48 - if (sp->source == PIXMA_SOURCE_TPU) -#endif - sp->depth = 16; /* TPU in 16 bits mode */ -#endif - break; - /* extended scan modes for 48 bit flatbed scanners - * 16 bit per channel in color and grayscale mode */ - case PIXMA_SCAN_MODE_GRAY_16: - sp->channels = 1; - sp->depth = 16; - break; - case PIXMA_SCAN_MODE_COLOR_48: - sp->channels = 3; - sp->depth = 16; - break; - /* software lineart - * 1 bit per channel */ - case PIXMA_SCAN_MODE_LINEART: - sp->software_lineart = 1; - sp->channels = 1; - sp->depth = 1; - break; - } - - /* for software lineart w must be a multiple of 8 - * I don't know why is_lineart(s) doesn't work here */ - if (sp->software_lineart == 1 && sp->w % 8) - { - sp->w += 8 - (sp->w % 8); - - /* do not exceed the scanner capability */ - w_max = s->cfg->width * s->cfg->xdpi / 75; - w_max -= w_max % 8; - if (sp->w > w_max) - sp->w = w_max; - } - - if (sp->source == PIXMA_SOURCE_TPU && !sp->tpu_offset_added) - { - unsigned fixed_offset_y; /* TPU offsets for CanoScan 8800F, or other CCD at 300dpi. */ - unsigned max_y; /* max TPU height for CS9000F at 75 dpi */ - - /* CanoScan 8800F and others adding an offset depending on resolution */ - /* CS9000F and others maximum TPU height */ - switch (s->cfg->pid) - { - case CS8800F_PID: - fixed_offset_y = 140; - max_y = MIN (740, s->cfg->height); - break; - case CS9000F_PID: - case CS9000F_MII_PID: - fixed_offset_y = 146; - max_y = MIN (740, s->cfg->height); - break; - default: - fixed_offset_y = 0; - max_y = s->cfg->height; - break; - } - - /* cropping y and h to scanable area */ - max_y *= (sp->ydpi) / 75; - sp->y = MIN(sp->y, max_y); - sp->h = MIN(sp->h, max_y - sp->y); - /* PDBG (pixma_dbg (4, "*mp810_check_param***** Cropping: y=%u, h=%u *****\n", - sp->y, sp->h)); */ - if (!sp->h) - return SANE_STATUS_INVAL; /* no lines */ - - /* Convert the offsets from 300dpi to actual resolution */ - fixed_offset_y = fixed_offset_y * (sp->xdpi) / 300; - - /* In TPU mode, the CS9000F appears to always subtract 146 from the - vertical starting position, but clamps its at 0. Therefore vertical - offsets 0 through 146 (@300 dpi) get all mapped onto the same - physical starting position: line 0. Then, starting from 147, the - offsets get mapped onto successive physical lines: - y line - 0 -> 0 - 1 -> 0 - 2 -> 0 - ... - 146 -> 0 - 147 -> 1 - 148 -> 2 - ... - Since a preview scan is typically made starting from y = 0, but - partial image scans usually start at y >> 147, this results in a - discontinuity in the y to line mapping, resulting in wrong offsets. - To prevent this, we must always add (at least) 146 to the y - offset before it is sent to the scanner. The scanner will then - map y = 0 (146) to the first line, y = 1 (147) to the second line, - and so on. Any distance that is then measured on the preview scan, - can be translated without any discontinuity. - - However, there is one complication: during a preview scan, which - normally covers the whole scan area of the scanner, we should _not_ - add the offset because it will result in a reduced number of lines - being returned (the scan height is clamped in - pixma_check_scan_param()). Since the frontend has no way of telling - that the scan area has been reduced, it would derive an incorrect - effective scan resolution, and any position calculations based on - this would therefore be inaccurate. - - To prevent this, we don't add the offset in case y = 0, which is - typically the case during a preview scan (the scanner effectively - adds the offset for us, see above). In that way we keep the - linearity and we don't affect the scan area during previews. - */ - - if (sp->y > 0) - sp->y += fixed_offset_y; - - /* Prevent repeated corrections as check_param may be called multiple times */ - sp->tpu_offset_added = 1; - } - - if (mp->generation >= 2) - { - /* mod 32 and expansion of the X scan limits */ - /* PDBG (pixma_dbg (4, "*mp810_check_param***** (gen>=2) xs=mod32 ----- Initially: x=%u, y=%u, w=%u, h=%u *****\n", sp->x, sp->y, sp->w, sp->h)); */ - sp->xs = (sp->x) % 32; - } - else - { - sp->xs = 0; - /* PDBG (pixma_dbg (4, "*mp810_check_param***** (else) xs=0 Selected origin, origin shift: %u, %u *****\n", sp->x, sp->xs)); */ - } - sp->wx = calc_raw_width (mp, sp); - sp->line_size = sp->w * sp->channels * (((sp->software_lineart) ? 8 : sp->depth) / 8); /* bytes per line per color after cropping */ - /* PDBG (pixma_dbg (4, "*mp810_check_param***** (else) Final scan width and line-size: %u, %"PRIu64" *****\n", sp->wx, sp->line_size)); */ - - /* highest res is 600, 2400, 4800 or 9600 dpi */ - { - uint8_t k; - - if ((sp->source == PIXMA_SOURCE_ADF || sp->source == PIXMA_SOURCE_ADFDUP) - && mp->generation >= 4) - /* ADF/ADF duplex mode: max scan res is 600 dpi, at least for generation 4 */ - k = sp->xdpi / MIN (sp->xdpi, 600); - else if (sp->source == PIXMA_SOURCE_TPU && sp->mode == PIXMA_SCAN_MODE_TPUIR) - /* TPUIR mode: max scan res is 2400 dpi */ - k = sp->xdpi / MIN (sp->xdpi, 2400); - else if (sp->source == PIXMA_SOURCE_TPU && (s->cfg->pid == CS9000F_PID || s->cfg->pid == CS9000F_MII_PID)) - /* CS9000F in TPU mode */ - k = sp->xdpi / MIN (sp->xdpi, 9600); - else - /* default */ - k = sp->xdpi / MIN (sp->xdpi, 4800); - - sp->x /= k; - sp->xs /= k; - sp->y /= k; - sp->w /= k; - sp->wx /= k; - sp->h /= k; - sp->xdpi /= k; - sp->ydpi = sp->xdpi; - } - - /* lowest res is 75, 150, 300 or 600 dpi */ - { - uint8_t k; - - if (sp->source == PIXMA_SOURCE_TPU && sp->mode == PIXMA_SCAN_MODE_TPUIR) - /* TPUIR mode */ - k = MAX (sp->xdpi, 600) / sp->xdpi; - else if (sp->source == PIXMA_SOURCE_TPU - && ((mp->generation >= 3) || (s->cfg->pid == MP810_PID) || (s->cfg->pid == MP960_PID))) - /* TPU mode for generation 3+ scanners - * MP810, MP960 appear to have a 200dpi mode for low-res scans, not 150 dpi */ - k = MAX (sp->xdpi, 300) / sp->xdpi; - else if (sp->source == PIXMA_SOURCE_TPU - || sp->mode == PIXMA_SCAN_MODE_COLOR_48 || sp->mode == PIXMA_SCAN_MODE_GRAY_16) - /* TPU mode and 16 bit flatbed scans - * TODO: either the frontend (xsane) cannot handle 48 bit flatbed scans @ 75 dpi (prescan) - * or there is a bug in this subdriver */ - k = MAX (sp->xdpi, 150) / sp->xdpi; - else - /* default */ - k = MAX (sp->xdpi, 75) / sp->xdpi; - - sp->x *= k; - sp->xs *= k; - sp->y *= k; - sp->w *= k; - sp->wx *= k; - sp->h *= k; - sp->xdpi *= k; - sp->ydpi = sp->xdpi; - } - - /* PDBG (pixma_dbg (4, "*mp810_check_param***** Finally: channels=%u, depth=%u, x=%u, y=%u, w=%u, h=%u, xs=%u, wx=%u *****\n", - sp->channels, sp->depth, sp->x, sp->y, sp->w, sp->h, sp->xs, sp->wx)); */ - - return 0; -} - -static int mp810_scan (pixma_t * s) -{ - int error = 0, tmo; - mp810_t *mp = (mp810_t *) s->subdriver; - - if (mp->state != state_idle) - return PIXMA_EBUSY; - - /* Generation 4: send XML dialog */ - if (mp->generation == 4 && s->param->adf_pageid == 0) - { - if (!send_xml_dialog (s, XML_START_1)) - return PIXMA_EPROTO; - if (!send_xml_dialog (s, XML_START_2)) - return PIXMA_EPROTO; - } - - /* clear interrupt packets buffer */ - while (handle_interrupt (s, 0) > 0) - { - } - - /* FIXME: Duplex ADF: check paper status only before odd pages (1,3,5,...). */ - if (is_scanning_from_adf (s)) - { - if ((error = query_status (s)) < 0) - return error; - tmo = 10; - while (!has_paper (s) && --tmo >= 0) - { - WAIT_INTERRUPT(1000); - PDBG(pixma_dbg (2, "No paper in ADF. Timed out in %d sec.\n", tmo)); - } - if (!has_paper (s)) - return PIXMA_ENO_PAPER; - } - - if (has_ccd_sensor (s) && (mp->generation <= 2)) - { - error = send_cmd_e920 (s); - switch (error) - { - case PIXMA_ECANCELED: - case PIXMA_EBUSY: - PDBG(pixma_dbg (2, "cmd e920 or d520 returned %s\n", pixma_strerror (error))); - /* fall through */ - case 0: - query_status (s); - break; - default: - PDBG(pixma_dbg (1, "WARNING: cmd e920 or d520 failed %s\n", pixma_strerror (error))); - return error; - } - tmo = 3; /* like Windows driver, CCD calibration ? */ - while (--tmo >= 0) - { - WAIT_INTERRUPT(1000); - PDBG(pixma_dbg (2, "CCD Calibration ends in %d sec.\n", tmo)); - } - /* pixma_sleep(2000000); */ - } - - tmo = 10; - if (s->param->adf_pageid == 0 || mp->generation <= 2) - { - error = start_session (s); - while (error == PIXMA_EBUSY && --tmo >= 0) - { - if (s->cancel) - { - error = PIXMA_ECANCELED; - break; - } - PDBG(pixma_dbg (2, "Scanner is busy. Timed out in %d sec.\n", tmo + 1)); - pixma_sleep (1000000); - error = start_session (s); - } - if (error == PIXMA_EBUSY || error == PIXMA_ETIMEDOUT) - { - /* The scanner maybe hangs. We try to empty output buffer of the - * scanner and issue the cancel command. */ - PDBG(pixma_dbg (2, "Scanner hangs? Sending abort_session command.\n")); - drain_bulk_in (s); - abort_session (s); - pixma_sleep (500000); - error = start_session (s); - } - if ((error >= 0) || (mp->generation >= 3)) - mp->state = state_warmup; - if ((error >= 0) && (mp->generation <= 2)) - error = select_source (s); - if ((error >= 0) && (mp->generation >= 3) && has_ccd_sensor (s)) - error = init_ccd_lamp_3 (s); - if ((error >= 0) && !is_scanning_from_tpu (s)) - { - int i; - /* FIXME: 48 bit flatbed scans don't need gamma tables - * the code below doesn't run */ - /*if (is_color_48 (s) || is_gray_16 (s)) - error = 0; - else*/ - for (i = (mp->generation >= 3) ? 3 : 1; i > 0 && error >= 0; i--) - error = send_gamma_table (s); - } - else if (error >= 0) /* in TPU mode, for gen 1, 2, and 3 */ - error = send_set_tpu_info (s); - } - else - /* ADF pageid != 0 and gen3 or above */ - pixma_sleep (1000000); - - if ((error >= 0) || (mp->generation >= 3)) - mp->state = state_warmup; - if (error >= 0) - error = send_scan_param (s); - if ((error >= 0) && (mp->generation >= 3)) - error = start_scan_3 (s); - if (error < 0) - { - mp->last_block = 0x38; /* Force abort session if ADF scan */ - mp810_finish_scan (s); - return error; - } - return 0; -} - -static int mp810_fill_buffer (pixma_t * s, pixma_imagebuf_t * ib) -{ - int error; - mp810_t *mp = (mp810_t *) s->subdriver; - unsigned block_size, bytes_received, proc_buf_size, line_size; - uint8_t header[16]; - - if (mp->state == state_warmup) - { /* prepare read image data */ - /* PDBG (pixma_dbg (4, "**mp810_fill_buffer***** warmup *****\n")); */ - - RET_IF_ERR(wait_until_ready (s)); - pixma_sleep (1000000); /* No need to sleep, actually, but Window's driver - * sleep 1.5 sec. */ - mp->state = state_scanning; - mp->last_block = 0; - - line_size = get_cis_ccd_line_size (s); - proc_buf_size = (2 * calc_shifting (s) + 2) * line_size; - mp->cb.buf = realloc (mp->cb.buf, CMDBUF_SIZE + IMAGE_BLOCK_SIZE + proc_buf_size); - if (!mp->cb.buf) - return PIXMA_ENOMEM; - mp->linebuf = mp->cb.buf + CMDBUF_SIZE; - mp->imgbuf = mp->data_left_ofs = mp->linebuf + line_size; - mp->data_left_len = 0; - } - - do - { /* read complete image data from the scanner */ - if (s->cancel) - return PIXMA_ECANCELED; - if ((mp->last_block & 0x28) == 0x28) - { /* end of image */ - mp->state = state_finished; - /* PDBG (pixma_dbg (4, "**mp810_fill_buffer***** end of image *****\n")); */ - return 0; - } - /* PDBG (pixma_dbg (4, "*mp810_fill_buffer***** moving %u bytes into buffer *****\n", mp->data_left_len)); */ - memmove (mp->imgbuf, mp->data_left_ofs, mp->data_left_len); - error = read_image_block (s, header, mp->imgbuf + mp->data_left_len); - if (error < 0) - { - if (error == PIXMA_ECANCELED) - { - /* NOTE: I see this in traffic logs but I don't know its meaning. */ - read_error_info (s, NULL, 0); - } - return error; - } - - bytes_received = error; - /*PDBG (pixma_dbg (4, "*mp810_fill_buffer***** %u bytes received by read_image_block *****\n", bytes_received));*/ - block_size = pixma_get_be32 (header + 12); - mp->last_block = header[8] & 0x38; - if ((header[8] & ~0x38) != 0) - { - PDBG(pixma_dbg (1, "WARNING: Unexpected result header\n")); - PDBG(pixma_hexdump (1, header, 16)); - } - PASSERT(bytes_received == block_size); - - if (block_size == 0) - { /* no image data at this moment. */ - pixma_sleep (10000); - } - /* For TPU at 48 bits/pixel to output at 24 bits/pixel */ -#ifndef DEBUG_TPU_48 -#ifndef TPU_48 - PDBG (pixma_dbg (1, "WARNING: 9000F using 24 instead of 48 bit processing \n")); -#ifndef DEBUG_TPU_24 - if (is_scanning_from_tpu (s)) -#endif - bytes_received = pack_48_24_bpc (mp->imgbuf + mp->data_left_len, bytes_received); -#endif -#endif - /* Post-process the image data */ - mp->data_left_ofs = mp->imgbuf + mp->data_left_len + bytes_received; - mp->data_left_len = post_process_image_data (s, ib); - mp->data_left_ofs -= mp->data_left_len; - /* PDBG (pixma_dbg (4, "* mp810_fill_buffer: data_left_len %u \n", mp->data_left_len)); */ - /* PDBG (pixma_dbg (4, "* mp810_fill_buffer: data_left_ofs %u \n", mp->data_left_ofs)); */ - } - while (ib->rend == ib->rptr); - - return ib->rend - ib->rptr; -} - -static void mp810_finish_scan (pixma_t * s) -{ - int error; - mp810_t *mp = (mp810_t *) s->subdriver; - - switch (mp->state) - { - case state_transfering: - drain_bulk_in (s); - /* fall through */ - case state_scanning: - case state_warmup: - case state_finished: - /* Send the get TPU info message */ - if (is_scanning_from_tpu (s) && mp->tpu_datalen == 0) - send_get_tpu_info_3 (s); - /* FIXME: to process several pages ADF scan, must not send - * abort_session and start_session between pages (last_block=0x28) */ - if (mp->generation <= 2 || !is_scanning_from_adf (s) - || mp->last_block == 0x38) - { - error = abort_session (s); /* FIXME: it probably doesn't work in duplex mode! */ - if (error < 0) - PDBG(pixma_dbg (1, "WARNING:abort_session() failed %d\n", error)); - - /* Generation 4: send XML end of scan dialog */ - if (mp->generation == 4) - { - if (!send_xml_dialog (s, XML_END)) - PDBG(pixma_dbg (1, "WARNING:XML_END dialog failed \n")); - } - } - mp->state = state_idle; - /* fall through */ - case state_idle: - break; - } -} - -static void mp810_wait_event (pixma_t * s, int timeout) -{ - /* FIXME: timeout is not correct. See usbGetCompleteUrbNoIntr() for - * instance. */ - while (s->events == 0 && handle_interrupt (s, timeout) > 0) - { - } -} - -static int mp810_get_status (pixma_t * s, pixma_device_status_t * status) -{ - int error; - - RET_IF_ERR(query_status (s)); - status->hardware = PIXMA_HARDWARE_OK; - status->adf = (has_paper (s)) ? PIXMA_ADF_OK : PIXMA_ADF_NO_PAPER; - status->cal = - (is_calibrated (s)) ? PIXMA_CALIBRATION_OK : PIXMA_CALIBRATION_OFF; - return 0; -} - -static const pixma_scan_ops_t pixma_mp810_ops = -{ - mp810_open, - mp810_close, - mp810_scan, - mp810_fill_buffer, - mp810_finish_scan, - mp810_wait_event, - mp810_check_param, - mp810_get_status -}; - -#define DEVICE(name, model, pid, dpi, adftpu_min_dpi, adftpu_max_dpi, tpuir_min_dpi, tpuir_max_dpi, w, h, cap) { \ - name, /* name */ \ - model, /* model */ \ - CANON_VID, pid, /* vid pid */ \ - 0, /* iface */ \ - &pixma_mp810_ops, /* ops */ \ - dpi, 2*(dpi), /* xdpi, ydpi */ \ - adftpu_min_dpi, adftpu_max_dpi, /* adftpu_min_dpi, adftpu_max_dpi */ \ - tpuir_min_dpi, tpuir_max_dpi, /* tpuir_min_dpi, tpuir_max_dpi */ \ - w, h, /* width, height */ \ - PIXMA_CAP_EASY_RGB| \ - PIXMA_CAP_GRAY| /* all scanners with software grayscale */ \ - PIXMA_CAP_LINEART| /* all scanners with software lineart */ \ - PIXMA_CAP_GAMMA_TABLE|PIXMA_CAP_EVENTS|cap \ -} - -#define END_OF_DEVICE_LIST DEVICE(NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0) - -const pixma_config_t pixma_mp810_devices[] = -{ - /* Generation 2: CCD */ - DEVICE ("Canon PIXMA MP810", "MP810", MP810_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - DEVICE ("Canon PIXMA MP960", "MP960", MP960_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - - /* Generation 3 CCD not managed as Generation 2 */ - DEVICE ("Canon Pixma MP970", "MP970", MP970_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - - /* Flatbed scanner CCD (2007) */ - DEVICE ("Canoscan 8800F", "8800F", CS8800F_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT), - - /* PIXMA 2008 vintage CCD */ - DEVICE ("Canon MP980 series", "MP980", MP980_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - - /* Generation 4 CCD */ - DEVICE ("Canon MP990 series", "MP990", MP990_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - - /* Flatbed scanner (2010) */ - DEVICE ("Canoscan 9000F", "9000F", CS9000F_PID, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPUIR /*| PIXMA_CAP_NEGATIVE*/ | PIXMA_CAP_48BIT), - - /* Latest devices (2010) Generation 4 CCD untested */ - DEVICE ("Canon PIXMA MG8100", "MG8100", MG8100_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - - /* Latest devices (2011) Generation 4 CCD untested */ - DEVICE ("Canon PIXMA MG8200", "MG8200", MG8200_PID, 4800, 300, 0, 0, 0, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPU), - - /* Flatbed scanner (2013) */ - DEVICE ("Canoscan 9000F Mark II", "9000FMarkII", CS9000F_MII_PID, 4800, 300, 9600, 600, 2400, 638, 877, PIXMA_CAP_CCD | PIXMA_CAP_TPUIR | PIXMA_CAP_48BIT), - - END_OF_DEVICE_LIST -}; diff --git a/backend/pixma_rename.h b/backend/pixma_rename.h deleted file mode 100644 index ce68ed3..0000000 --- a/backend/pixma_rename.h +++ /dev/null @@ -1,105 +0,0 @@ -/* SANE - Scanner Access Now Easy. - - 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. - */ -#ifndef PIXMA_RENAME_H -#define PIXMA_RENAME_H - - -#undef BACKEND_NAME -#define BACKEND_NAME pixma - -#define pixma_cancel sanei_pixma_cancel -#define pixma_check_dpi sanei_pixma_check_dpi -#define pixma_check_result sanei_pixma_check_result -#define pixma_check_scan_param sanei_pixma_check_scan_param -#define pixma_cleanup sanei_pixma_cleanup -#define pixma_close sanei_pixma_close -#define pixma_cmd_transaction sanei_pixma_cmd_transaction -#define pixma_collect_devices sanei_pixma_collect_devices -#define pixma_connect sanei_pixma_connect -#define pixma_dbg DBG -#define pixma_disconnect sanei_pixma_disconnect -#define pixma_dump sanei_pixma_dump -#define pixma_enable_background sanei_pixma_enable_background -#define pixma_exec sanei_pixma_exec -#define pixma_exec_short_cmd sanei_pixma_exec_short_cmd -#define pixma_fill_gamma_table sanei_pixma_fill_gamma_table -#define pixma_find_scanners sanei_pixma_find_scanners -#define pixma_get_be16 sanei_pixma_get_be16 -#define pixma_get_be32 sanei_pixma_get_be32 -#define pixma_get_config sanei_pixma_get_config -#define pixma_get_device_config sanei_pixma_get_device_config -#define pixma_get_device_id sanei_pixma_get_device_id -#define pixma_get_device_model sanei_pixma_get_device_model -#define pixma_get_device_status sanei_pixma_get_device_status -#define pixma_get_string sanei_pixma_get_string -#define pixma_get_time sanei_pixma_get_time -#define pixma_hexdump sanei_pixma_hexdump -#define pixma_init sanei_pixma_init -#define pixma_io_cleanup sanei_pixma_io_cleanup -#define pixma_io_init sanei_pixma_io_init -#define pixma_map_status_errno sanei_pixma_map_status_errno -#define pixma_mp150_devices sanei_pixma_mp150_devices -#define pixma_mp730_devices sanei_pixma_mp730_devices -#define pixma_mp750_devices sanei_pixma_mp750_devices -#define pixma_mp810_devices sanei_pixma_mp810_devices -#define pixma_iclass_devices sanei_pixma_iclass_devices -#define pixma_newcmd sanei_pixma_newcmd -#define pixma_open sanei_pixma_open -#define pixma_print_supported_devices sanei_pixma_print_supported_devices -#define pixma_read_image sanei_pixma_read_image -#define pixma_read sanei_pixma_read -#define pixma_reset_device sanei_pixma_reset_device -#define pixma_scan sanei_pixma_scan -#define pixma_set_be16 sanei_pixma_set_be16 -#define pixma_set_be32 sanei_pixma_set_be32 -#define pixma_set_debug_level sanei_pixma_set_debug_level -#define pixma_set_interrupt_mode sanei_pixma_set_interrupt_mode -#define pixma_sleep sanei_pixma_sleep -#define pixma_strerror sanei_pixma_strerror -#define pixma_sum_bytes sanei_pixma_sum_bytes -#define pixma_wait_event sanei_pixma_wait_event -#define pixma_wait_interrupt sanei_pixma_wait_interrupt -#define pixma_write sanei_pixma_write - - -#endif diff --git a/backend/pixma_sane_options.c b/backend/pixma_sane_options.c deleted file mode 100644 index 6e6abfc..0000000 --- a/backend/pixma_sane_options.c +++ /dev/null @@ -1,362 +0,0 @@ -/* Automatically generated from pixma_sane.c */ -static const SANE_Range constraint_gamma_table = - { 0,255,0 }; -static const SANE_Range constraint_gamma = - { SANE_FIX(0.3),SANE_FIX(5),SANE_FIX(0) }; -static const SANE_Range constraint_threshold = - { 0,100,1 }; -static const SANE_Range constraint_threshold_curve = - { 0,127,1 }; -static const SANE_Range constraint_adf_wait = - { 0,3600,1 }; - - -static -int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list) -{ - int i; - for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {} - return i; -} - -static -int build_option_descriptors(struct pixma_sane_t *ss) -{ - SANE_Option_Descriptor *sod; - option_descriptor_t *opt; - - memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX)); - - opt = &(OPT_IN_CTX[opt_opt_num_opts]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_TITLE_NUM_OPTIONS; - sod->desc = SANE_DESC_NUM_OPTIONS; - sod->name = ""; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_DETECT; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_opt_num_opts].info = 0; - opt->def.w = opt_last; - opt->val.w = opt_last; - - opt = &(OPT_IN_CTX[opt__group_1]); - sod = &opt->sod; - sod->type = SANE_TYPE_GROUP; - sod->title = SANE_I18N("Scan mode"); - sod->desc = sod->title; - - opt = &(OPT_IN_CTX[opt_resolution]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_TITLE_SCAN_RESOLUTION; - sod->desc = SANE_DESC_SCAN_RESOLUTION; - sod->name = "resolution"; - sod->unit = SANE_UNIT_DPI; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; - sod->constraint_type = SANE_CONSTRAINT_WORD_LIST; - sod->constraint.word_list = ss->dpi_list; - OPT_IN_CTX[opt_resolution].info = SANE_INFO_RELOAD_PARAMS; - opt->def.w = 75; - opt->val.w = 75; - - opt = &(OPT_IN_CTX[opt_mode]); - sod = &opt->sod; - sod->type = SANE_TYPE_STRING; - sod->title = SANE_TITLE_SCAN_MODE; - sod->desc = SANE_DESC_SCAN_MODE; - sod->name = "mode"; - sod->unit = SANE_UNIT_NONE; - sod->size = 31; - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; - sod->constraint_type = SANE_CONSTRAINT_STRING_LIST; - sod->constraint.string_list = ss->mode_list; - OPT_IN_CTX[opt_mode].info = SANE_INFO_RELOAD_PARAMS; - opt->def.s = SANE_VALUE_SCAN_MODE_COLOR; - opt->val.w = find_string_in_list(opt->def.s, sod->constraint.string_list); - - opt = &(OPT_IN_CTX[opt_source]); - sod = &opt->sod; - sod->type = SANE_TYPE_STRING; - sod->title = SANE_TITLE_SCAN_SOURCE; - sod->desc = SANE_I18N("Selects the scan source (such as a document-feeder). Set source before mode and resolution. Resets mode and resolution to auto values."); - sod->name = "source"; - sod->unit = SANE_UNIT_NONE; - sod->size = 31; - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT; - sod->constraint_type = SANE_CONSTRAINT_STRING_LIST; - sod->constraint.string_list = ss->source_list; - OPT_IN_CTX[opt_source].info = 0; - opt->def.s = SANE_I18N("Flatbed"); - opt->val.w = find_string_in_list(opt->def.s, sod->constraint.string_list); - - opt = &(OPT_IN_CTX[opt_button_controlled]); - sod = &opt->sod; - sod->type = SANE_TYPE_BOOL; - sod->title = SANE_I18N("Button-controlled scan"); - sod->desc = SANE_I18N("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."); - sod->name = "button-controlled"; - sod->unit = SANE_UNIT_NONE; - sod->size = sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_INACTIVE; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_button_controlled].info = 0; - opt->def.w = SANE_FALSE; - opt->val.w = SANE_FALSE; - - opt = &(OPT_IN_CTX[opt__group_2]); - sod = &opt->sod; - sod->type = SANE_TYPE_GROUP; - sod->title = SANE_I18N("Gamma"); - sod->desc = sod->title; - - opt = &(OPT_IN_CTX[opt_custom_gamma]); - sod = &opt->sod; - sod->type = SANE_TYPE_BOOL; - sod->title = SANE_TITLE_CUSTOM_GAMMA; - sod->desc = SANE_DESC_CUSTOM_GAMMA; - sod->name = "custom-gamma"; - sod->unit = SANE_UNIT_NONE; - sod->size = sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_custom_gamma].info = 0; - opt->def.w = SANE_TRUE; - opt->val.w = SANE_TRUE; - - opt = &(OPT_IN_CTX[opt_gamma_table]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_TITLE_GAMMA_VECTOR; - sod->desc = SANE_DESC_GAMMA_VECTOR; - sod->name = "gamma-table"; - sod->unit = SANE_UNIT_NONE; - sod->size = 4096 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &constraint_gamma_table; - OPT_IN_CTX[opt_gamma_table].info = 0; - - opt = &(OPT_IN_CTX[opt_gamma]); - sod = &opt->sod; - sod->type = SANE_TYPE_FIXED; - sod->title = SANE_I18N("Gamma function exponent"); - sod->desc = SANE_I18N("Changes intensity of midtones"); - sod->name = "gamma"; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &constraint_gamma; - OPT_IN_CTX[opt_gamma].info = 0; - opt->def.w = SANE_FIX(AUTO_GAMMA); - opt->val.w = SANE_FIX(AUTO_GAMMA); - - opt = &(OPT_IN_CTX[opt__group_3]); - sod = &opt->sod; - sod->type = SANE_TYPE_GROUP; - sod->title = SANE_I18N("Geometry"); - sod->desc = sod->title; - - opt = &(OPT_IN_CTX[opt_tl_x]); - sod = &opt->sod; - sod->type = SANE_TYPE_FIXED; - sod->title = SANE_TITLE_SCAN_TL_X; - sod->desc = SANE_DESC_SCAN_TL_X; - sod->name = "tl-x"; - sod->unit = SANE_UNIT_MM; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &ss->xrange; - OPT_IN_CTX[opt_tl_x].info = SANE_INFO_RELOAD_PARAMS; - opt->def.w = SANE_FIX(0); - opt->val.w = SANE_FIX(0); - - opt = &(OPT_IN_CTX[opt_tl_y]); - sod = &opt->sod; - sod->type = SANE_TYPE_FIXED; - sod->title = SANE_TITLE_SCAN_TL_Y; - sod->desc = SANE_DESC_SCAN_TL_Y; - sod->name = "tl-y"; - sod->unit = SANE_UNIT_MM; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &ss->yrange; - OPT_IN_CTX[opt_tl_y].info = SANE_INFO_RELOAD_PARAMS; - opt->def.w = SANE_FIX(0); - opt->val.w = SANE_FIX(0); - - opt = &(OPT_IN_CTX[opt_br_x]); - sod = &opt->sod; - sod->type = SANE_TYPE_FIXED; - sod->title = SANE_TITLE_SCAN_BR_X; - sod->desc = SANE_DESC_SCAN_BR_X; - sod->name = "br-x"; - sod->unit = SANE_UNIT_MM; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &ss->xrange; - OPT_IN_CTX[opt_br_x].info = SANE_INFO_RELOAD_PARAMS; - opt->def.w = sod->constraint.range->max; - opt->val.w = sod->constraint.range->max; - - opt = &(OPT_IN_CTX[opt_br_y]); - sod = &opt->sod; - sod->type = SANE_TYPE_FIXED; - sod->title = SANE_TITLE_SCAN_BR_Y; - sod->desc = SANE_DESC_SCAN_BR_Y; - sod->name = "br-y"; - sod->unit = SANE_UNIT_MM; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &ss->yrange; - OPT_IN_CTX[opt_br_y].info = SANE_INFO_RELOAD_PARAMS; - opt->def.w = sod->constraint.range->max; - opt->val.w = sod->constraint.range->max; - - opt = &(OPT_IN_CTX[opt__group_4]); - sod = &opt->sod; - sod->type = SANE_TYPE_GROUP; - sod->title = SANE_I18N("Buttons"); - sod->desc = sod->title; - - opt = &(OPT_IN_CTX[opt_button_update]); - sod = &opt->sod; - sod->type = SANE_TYPE_BUTTON; - sod->title = SANE_I18N("Update button state"); - sod->desc = sod->title; - sod->name = "button-update"; - sod->unit = SANE_UNIT_NONE; - sod->size = 0; - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_button_update].info = 0; - - opt = &(OPT_IN_CTX[opt_button_1]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_I18N("Button 1"); - sod->desc = sod->title; - sod->name = "button-1"; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_button_1].info = 0; - opt->def.w = 0; - opt->val.w = 0; - - opt = &(OPT_IN_CTX[opt_button_2]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_I18N("Button 2"); - sod->desc = sod->title; - sod->name = "button-2"; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_button_2].info = 0; - opt->def.w = 0; - opt->val.w = 0; - - opt = &(OPT_IN_CTX[opt_original]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_I18N("Type of original to scan"); - sod->desc = sod->title; - sod->name = "original"; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_original].info = 0; - opt->def.w = 0; - opt->val.w = 0; - - opt = &(OPT_IN_CTX[opt_target]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_I18N("Target operation type"); - sod->desc = sod->title; - sod->name = "target"; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_target].info = 0; - opt->def.w = 0; - opt->val.w = 0; - - opt = &(OPT_IN_CTX[opt_scan_resolution]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_I18N("Scan resolution"); - sod->desc = sod->title; - sod->name = "scan-resolution"; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_DETECT|SANE_CAP_ADVANCED; - sod->constraint_type = SANE_CONSTRAINT_NONE; - OPT_IN_CTX[opt_scan_resolution].info = 0; - opt->def.w = 0; - opt->val.w = 0; - - opt = &(OPT_IN_CTX[opt__group_5]); - sod = &opt->sod; - sod->type = SANE_TYPE_GROUP; - sod->title = SANE_I18N("Extras"); - sod->desc = sod->title; - - opt = &(OPT_IN_CTX[opt_threshold]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_TITLE_THRESHOLD; - sod->desc = SANE_DESC_THRESHOLD; - sod->name = "threshold"; - sod->unit = SANE_UNIT_PERCENT; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &constraint_threshold; - OPT_IN_CTX[opt_threshold].info = 0; - opt->def.w = 50; - opt->val.w = 50; - - opt = &(OPT_IN_CTX[opt_threshold_curve]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_I18N("Threshold curve"); - sod->desc = SANE_I18N("Dynamic threshold curve, from light to dark, normally 50-65"); - sod->name = "threshold-curve"; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &constraint_threshold_curve; - OPT_IN_CTX[opt_threshold_curve].info = 0; - - opt = &(OPT_IN_CTX[opt_adf_wait]); - sod = &opt->sod; - sod->type = SANE_TYPE_INT; - sod->title = SANE_I18N("ADF Waiting Time"); - sod->desc = SANE_I18N("When set, the scanner searches the waiting time in seconds for a new document inserted into the automatic document feeder."); - sod->name = "adf-wait"; - sod->unit = SANE_UNIT_NONE; - sod->size = 1 * sizeof(SANE_Word); - sod->cap = SANE_CAP_SOFT_SELECT|SANE_CAP_SOFT_DETECT|SANE_CAP_AUTOMATIC|SANE_CAP_INACTIVE; - sod->constraint_type = SANE_CONSTRAINT_RANGE; - sod->constraint.range = &constraint_adf_wait; - OPT_IN_CTX[opt_adf_wait].info = 0; - opt->def.w = 0; - opt->val.w = 0; - - return 0; - -} diff --git a/backend/pixma_sane_options.h b/backend/pixma_sane_options.h deleted file mode 100644 index 1472f1f..0000000 --- a/backend/pixma_sane_options.h +++ /dev/null @@ -1,51 +0,0 @@ -/* Automatically generated from pixma_sane.c */ - -typedef union { - SANE_Word w; - SANE_Int i; - SANE_Bool b; - SANE_Fixed f; - SANE_String s; - void *ptr; -} option_value_t; - -typedef enum { - opt_opt_num_opts, - opt__group_1, - opt_resolution, - opt_mode, - opt_source, - opt_button_controlled, - opt__group_2, - opt_custom_gamma, - opt_gamma_table, - opt_gamma, - opt__group_3, - opt_tl_x, - opt_tl_y, - opt_br_x, - opt_br_y, - opt__group_4, - opt_button_update, - opt_button_1, - opt_button_2, - opt_original, - opt_target, - opt_scan_resolution, - opt__group_5, - opt_threshold, - opt_threshold_curve, - opt_adf_wait, - opt_last -} option_t; - - -typedef struct { - SANE_Option_Descriptor sod; - option_value_t val,def; - SANE_Word info; -} option_descriptor_t; - - -struct pixma_sane_t; -static int build_option_descriptors(struct pixma_sane_t *ss); diff --git a/backend/plustek-pp_motor.c b/backend/plustek-pp_motor.c index 7f4b1ac..c48710e 100644 --- a/backend/plustek-pp_motor.c +++ b/backend/plustek-pp_motor.c @@ -1912,6 +1912,7 @@ static void motorP96SetupRunTable( pScanData ps ) case 3: if (*(p.pb + 2)) bColor = 1; + // fall through case 2: if (*(p.pb + 1)) bColor++; diff --git a/backend/plustek-usb.c b/backend/plustek-usb.c index 5c6fbeb..107bf9e 100644 --- a/backend/plustek-usb.c +++ b/backend/plustek-usb.c @@ -193,6 +193,7 @@ usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor ) int i; ScanParam sParam; u_short tmp = 0; + int ret = 0; DBG( _DBG_INFO, "usb_initDev(%d,0x%04x,%i)\n", idx, vendor, dev->initialized ); @@ -305,11 +306,16 @@ usb_initDev( Plustek_Device *dev, int idx, int handle, int vendor ) } ptr = getenv ("HOME"); - if( NULL == ptr ) { - sprintf( tmp_str2, "/tmp/%s", tmp_str1 ); - } else { - sprintf( tmp_str2, "%s/.sane/%s", ptr, tmp_str1 ); + ret = ( NULL == ptr )? + snprintf( tmp_str2, sizeof(tmp_str2), "/tmp/%s", tmp_str1 ): + snprintf( tmp_str2, sizeof(tmp_str2), "%s/.sane/%s", ptr, tmp_str1 ); + + if ((ret < 0) || (ret > (int)sizeof(tmp_str2))) { + DBG( _DBG_WARNING, + "Failed to generate calibration file path. Default substituted.\n" ); + snprintf(tmp_str2, sizeof(tmp_str2), "/tmp/plustek-default"); } + dev->calFile = strdup( tmp_str2 ); DBG( _DBG_INFO, "Calibration file-names set to:\n" ); DBG( _DBG_INFO, ">%s-coarse.cal<\n", dev->calFile ); diff --git a/backend/plustek-usbcal.c b/backend/plustek-usbcal.c index 3b9d93a..84a4105 100644 --- a/backend/plustek-usbcal.c +++ b/backend/plustek-usbcal.c @@ -306,7 +306,7 @@ cano_AdjustLightsource( Plustek_Device *dev ) min_rgb.Blue = hw->blue_lamp_on; if((dev->adj.rlampoff != -1) && - (dev->adj.glampoff != -1) && (dev->adj.rlampoff != -1)) { + (dev->adj.glampoff != -1) && (dev->adj.blampoff != -1)) { DBG( _DBG_INFO, "- function skipped, using frontend values!\n" ); return SANE_TRUE; } diff --git a/backend/plustek.c b/backend/plustek.c index e1d9e09..eaddbd3 100644 --- a/backend/plustek.c +++ b/backend/plustek.c @@ -1085,14 +1085,14 @@ init_options( Plustek_Scanner *s ) /* scanner buttons */ for( i = OPT_BUTTON_0; i <= OPT_BUTTON_LAST; i++ ) { - char name [12]; - char title [128]; + char buf [128]; - sprintf (name, "button %d", i - OPT_BUTTON_0); - sprintf (title, "Scanner button %d", i - OPT_BUTTON_0); + snprintf (buf, sizeof(buf), "button %d", i - OPT_BUTTON_0); + s->opt[i].name = strdup(buf); + + snprintf (buf, sizeof(buf), "Scanner button %d", i - OPT_BUTTON_0); + s->opt[i].title = strdup(buf); - s->opt[i].name = strdup(name); - s->opt[i].title = strdup(title); s->opt[i].desc = SANE_I18N("This option reflects the status " "of the scanner buttons."); s->opt[i].type = SANE_TYPE_BOOL; @@ -1916,6 +1916,7 @@ sane_control_option( SANE_Handle handle, SANE_Int option, case OPT_BUTTON_0: if(!s->calibrating) usb_UpdateButtonStatus(s); + // fall through case OPT_BUTTON_1: case OPT_BUTTON_2: case OPT_BUTTON_3: diff --git a/backend/plustek_pp.c b/backend/plustek_pp.c index 551cf27..fdcc6b6 100644 --- a/backend/plustek_pp.c +++ b/backend/plustek_pp.c @@ -1625,7 +1625,7 @@ SANE_Status sane_control_option( SANE_Handle handle, SANE_Int option, *info |= SANE_INFO_RELOAD_OPTIONS | SANE_INFO_RELOAD_PARAMS; } - /* fall through to OPT_HALFTONE */ + // fall through case OPT_HALFTONE: s->val[option].w = optval - s->opt[option].constraint.string_list; break; diff --git a/backend/ricoh.c b/backend/ricoh.c index 58b3a53..fbe5c58 100644 --- a/backend/ricoh.c +++ b/backend/ricoh.c @@ -222,12 +222,14 @@ attach (const char *devnam, Ricoh_Device ** devp) dev->sane.name = strdup (devnam); dev->sane.vendor = "RICOH"; - str = malloc (sizeof(ibuf.product) + sizeof(ibuf.revision) + 1); + + size_t prod_rev_size = sizeof(ibuf.product) + sizeof(ibuf.revision) + 1; + str = malloc (prod_rev_size); if (str) { - str[0] = '\0'; - strncat (str, (char *)ibuf.product, sizeof(ibuf.product)); - strncat (str, (char *)ibuf.revision, sizeof(ibuf.revision)); + snprintf (str, prod_rev_size, "%.*s%.*s", + (int) sizeof(ibuf.product), (const char *) ibuf.product, + (int) sizeof(ibuf.revision), (const char *) ibuf.revision); } dev->sane.model = str; dev->sane.type = "flatbed scanner"; diff --git a/backend/ricoh2.c b/backend/ricoh2.c index 8aa938e..f719268 100644 --- a/backend/ricoh2.c +++ b/backend/ricoh2.c @@ -1,6 +1,6 @@ /* sane - Scanner Access Now Easy. - Copyright (C) 2018 Stanislav Yuzvinsky + Copyright (C) 2018, 2019 Stanislav Yuzvinsky Based on the work done by viruxx This file is part of the SANE package. @@ -113,9 +113,10 @@ typedef struct Ricoh2_device_info { Ricoh2_device_info; static Ricoh2_device_info supported_devices[] = { - { 0x042c, "Aficio SP100SU" }, - { 0x0438, "Aficio SG3100SNw" }, - { 0x0448, "Aficio SP111SU" } + { 0x042c, "Aficio SP-100SU" }, + { 0x0438, "Aficio SG-3100SNw" }, + { 0x0439, "Aficio SG-3110SFNw" }, + { 0x0448, "Aficio SP-111SU/SP-112SU" } }; static SANE_String_Const mode_list[] = { diff --git a/backend/ricoh2_buffer.c b/backend/ricoh2_buffer.c index b8d7d90..e79a7f3 100644 --- a/backend/ricoh2_buffer.c +++ b/backend/ricoh2_buffer.c @@ -46,7 +46,12 @@ #include #include + +#if defined(__APPLE__) && defined(__MACH__) +#include +#else #include +#endif #include "../include/sane/sanei_debug.h" diff --git a/backend/s9036.c b/backend/s9036.c index aa18df7..4124b7b 100644 --- a/backend/s9036.c +++ b/backend/s9036.c @@ -1022,6 +1022,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_BR_Y: if (info) *info |= SANE_INFO_RELOAD_PARAMS; + // fall through case OPT_BRIGHT_ADJUST: case OPT_CONTR_ADJUST: s->val[option] = *(SANE_Word *) val; diff --git a/backend/sane_strstatus.c b/backend/sane_strstatus.c index 1fc2220..c76d305 100644 --- a/backend/sane_strstatus.c +++ b/backend/sane_strstatus.c @@ -62,7 +62,7 @@ sane_strstatus (SANE_Status status) return SANE_I18N("Operation not supported"); case SANE_STATUS_CANCELLED: - return SANE_I18N("Operation was cancelled"); + return SANE_I18N("Operation was canceled"); case SANE_STATUS_DEVICE_BUSY: return SANE_I18N("Device busy"); diff --git a/backend/scripts/pixma_gen_options.py b/backend/scripts/pixma_gen_options.py deleted file mode 100755 index c4c75e0..0000000 --- a/backend/scripts/pixma_gen_options.py +++ /dev/null @@ -1,389 +0,0 @@ -#!/usr/bin/env python - -import sys,os,re - -class Error(Exception): - pass - - -class ParseError(Error): - def __init__(self, errline): - Error.__init__(self, errline) - - -class Struct: - pass - - -def createCNameMap(): - t = '' - for i in range(256): - if ((ord('A') <= i) and (i <= ord('Z'))) or \ - ((ord('a') <= i) and (i <= ord('z'))) or \ - ((ord('0') <= i) and (i <= ord('9'))): - t += chr(i) - else: - t += '_' - return t - - -def seekBegin(f): - while True: - line = f.readline() - if not line: - return False - if line.startswith('BEGIN SANE_Option_Descriptor'): - return True - - -def parseVerbatim(o, line): - words = line.split(None, 1) - if (len(words) < 2) or (words[1][0] != '@'): - return False - o[words[0]] = words[1] - return True - - -def parseLine_type(o, line): - words = line.split(None, 2) - otype = words[1] - o['type'] = 'SANE_TYPE_' + otype.upper() - if otype == 'group': - g.ngroups += 1 - oname = '_group_%d' % g.ngroups - o['size'] = 0 - else: - temp = words[2] - idx = temp.find('[') - if idx == -1: - oname = temp - o['size'] = 1 - else: - oname = temp[0:idx] - o['size'] = int(temp[idx+1:-1]) - o['name'] = oname - - -def parseLine_title(o, line): - o['title'] = line.split(None, 1)[1] - - -def parseLine_desc(o, line): - o['desc'] = line.split(None, 1)[1] - - -def parseLine_unit(o, line): - o['unit'] = 'SANE_UNIT_' + line.split(None, 1)[1].upper() - - -def parseLine_default(o, line): - o['default'] = line.split(None, 1)[1] - - -def parseLine_cap(o, line): - words = line.split() - o['cap'] = ['SANE_CAP_' + s.upper() for s in words[1:]] - - -def parseLine_constraint(o, line): - c = line.split(None,1)[1] - if c[0] == '{': - o['constraint'] = c[1:-1].split('|') - elif c[0] == '(': - o['constraint'] = tuple(c[1:-1].split(',')) - else: - sys.stderr.write('Ignored: %s\n' % line) - - -def parseLine_info(o, line): - words = line.split() - o['info'] = ['SANE_INFO_' + s.upper() for s in words[1:]] - -def parseLine_rem(o, line): - pass - -def normalize(o): - if 'cname' not in o: - cname = o['name'].translate(cnameMap) - o['cname'] = cname - else: - cname = o['cname'] - o['cname_opt'] = 'opt_' + cname - o['cname_con'] = 'constraint_' + cname - if 'title' not in o: - o['title'] = 'NO TITLE' - if 'desc' not in o: - o['desc'] = '@sod->title' % o - if 'unit' not in o: - o['unit'] = 'SANE_UNIT_NONE' - if 'constraint_type' not in o: - if 'constraint' not in o: - ct = 'SANE_CONSTRAINT_NONE' - elif isinstance(o['constraint'], list): - if o['type'] == 'SANE_TYPE_STRING': - ct = 'SANE_CONSTRAINT_STRING_LIST' - else: - ct = 'SANE_CONSTRAINT_WORD_LIST' - elif isinstance(o['constraint'], tuple): - ct = 'SANE_CONSTRAINT_RANGE' - elif isinstance(o['constraint'], str): - oc = o['constraint'] - if oc.startswith('@range'): - ct = 'SANE_CONSTRAINT_RANGE' - elif oc.startswith('@word_list'): - ct = 'SANE_CONSTRAINT_WORD_LIST' - elif oc.startswith('@string_list'): - ct = 'SANE_CONSTRAINT_STRING_LIST' - o['constraint_type'] = ct - return o - - -def parseFile(f): - if not seekBegin(f): - return None - options = [ { - 'name' : '', - 'cname' : 'opt_num_opts', - 'title' : '@SANE_TITLE_NUM_OPTIONS', - 'desc' : '@SANE_DESC_NUM_OPTIONS', - 'type' : 'SANE_TYPE_INT', - 'unit' : 'SANE_UNIT_NONE', - 'size' : 1, - 'cap' : ['SANE_CAP_SOFT_DETECT'], - 'constraint_type' : 'SANE_CONSTRAINT_NONE', - 'default' : '@w = ' + opt_prefix + 'last' - } ] - o = {} - while True: - line = f.readline() - if not line: - break - line = line.strip() - if not line: - continue - token = line.split(None, 1)[0].lower() - if token == 'end': - break - if token == 'type': - if 'name' in o: - options.append(o) - o = {} - funcName = 'parseLine_' + token - if funcName in globals(): - if not parseVerbatim(o, line): - func = globals()[funcName] - func(o, line) - else: - sys.stderr.write('Skip: %s\n' % line) - if 'name' in o: - options.append(o) - return [normalize(o) for o in options] - - -def genHeader(options): - print """ -typedef union { - SANE_Word w; - SANE_Int i; - SANE_Bool b; - SANE_Fixed f; - SANE_String s; - void *ptr; -} option_value_t; -""" - print 'typedef enum {' - for o in options: - print ' %(cname_opt)s,' % o - print ' ' + opt_prefix + 'last' - print '} option_t;' - print """ - -typedef struct { - SANE_Option_Descriptor sod; - option_value_t val,def; - SANE_Word info; -} option_descriptor_t; - - -struct pixma_sane_t; -static int build_option_descriptors(struct pixma_sane_t *ss); -""" - - -def genMinMaxRange(n, t, r): - if t == 'SANE_TYPE_FIXED': - r = ['SANE_FIX(%s)' % x for x in r] - print 'static const SANE_Range ' + n + ' = ' - print ' { ' + r[0] + ',' + r[1] + ',' + r[2] + ' };' - - -def genList(n, t, l): - if t == 'SANE_TYPE_INT': - etype = 'SANE_Word' - l = [str(len(l))] + l - elif t == 'SANE_TYPE_FIXED': - etype = 'SANE_Word' - l = [str(len(l))] + ['SANE_FIX(%s)' % x for x in l] - elif t == 'SANE_TYPE_STRING': - etype = 'SANE_String_Const' - l = ['SANE_I18N("%s")' % x for x in l] + ['NULL'] - print 'static const %s %s[%d] = {' % (etype, n, len(l)) - for x in l[0:-1]: - print '\t' + x + ',' - print '\t' + l[-1] + ' };' - - -def genConstraints(options): - for o in options: - if 'constraint' not in o: continue - c = o['constraint'] - oname = o['cname_con'] - otype = o['type'] - if isinstance(c, tuple): - genMinMaxRange(oname, otype, c) - elif isinstance(c, list): - genList(oname, otype, c) - print - -def buildCodeVerbatim(o): - for f in ('name', 'title', 'desc', 'type', 'unit', 'size', 'cap', - 'constraint_type', 'constraint', 'default'): - if (f not in o): continue - temp = o[f] - if (not isinstance(temp,str)) or \ - (len(temp) < 1) or (temp[0] != '@'): - continue - o['code_' + f] = temp[1:] - -def ccode(o): - buildCodeVerbatim(o) - if 'code_name' not in o: - o['code_name'] = '"' + o['name'] + '"' - for f in ('title', 'desc'): - cf = 'code_' + f - if cf in o: continue - o[cf] = 'SANE_I18N("' + o[f] + '")' - - for f in ('type', 'unit', 'constraint_type'): - cf = 'code_' + f - if cf in o: continue - o[cf] = o[f] - - if 'code_size' not in o: - otype = o['type'] - osize = o['size'] - if otype == 'SANE_TYPE_STRING': - code = str(osize + 1) - elif otype == 'SANE_TYPE_INT' or otype == 'SANE_TYPE_FIXED': - code = str(osize) + ' * sizeof(SANE_Word)' - elif otype == 'SANE_TYPE_BUTTON': - code = '0' - else: - code = 'sizeof(SANE_Word)' - o['code_size'] = code - - if ('code_cap' not in o) and ('cap' in o): - o['code_cap'] = reduce(lambda a,b: a+'|'+b, o['cap']) - else: - o['code_cap'] = '0' - - if ('code_info' not in o) and ('info' in o): - o['code_info'] = reduce(lambda a,b: a+'|'+b, o['info']) - else: - o['code_info'] = '0' - - if ('code_default' not in o) and ('default' in o): - odefault = o['default'] - otype = o['type'] - if odefault == '_MIN': - rhs = 'w = sod->constraint.range->min' - elif odefault == '_MAX': - rhs = 'w = sod->constraint.range->max' - elif otype in ('SANE_TYPE_INT', 'SANE_TYPE_BOOL'): - rhs = 'w = %(default)s' - elif otype == 'SANE_TYPE_FIXED': - rhs = 'w = SANE_FIX(%(default)s)' - elif otype == 'SANE_TYPE_STRING': - rhs = 's = SANE_I18N("%(default)s")' - o['code_default'] = rhs % o - if 'code_default' in o: - code = ' opt->def.%(code_default)s;\n' - if o['constraint_type'] != 'SANE_CONSTRAINT_STRING_LIST': - code += ' opt->val.%(code_default)s;\n' - else: - code += ' opt->val.w = find_string_in_list' \ - '(opt->def.s, sod->constraint.string_list);\n' - o['full_code_default'] = code % o - else: - o['full_code_default'] = '' - - if ('code_constraint' not in o) and ('constraint' in o): - ct = o['constraint_type'] - idx = len('SANE_CONSTRAINT_') - ctype = ct[idx:].lower() - if ctype == 'range': - rhs = '&%(cname_con)s' % o - else: - rhs = '%(cname_con)s' % o - o['code_constraint'] = ctype + ' = ' + rhs - if 'code_constraint' in o: - code = ' sod->constraint.%(code_constraint)s;\n' - o['full_code_constraint'] = code % o - else: - o['full_code_constraint'] = '' - - return o - -def genBuildOptions(options): - print """ -static -int find_string_in_list(SANE_String_Const str, const SANE_String_Const *list) -{ - int i; - for (i = 0; list[i] && strcmp(str, list[i]) != 0; i++) {} - return i; -} - -static -int build_option_descriptors(struct pixma_sane_t *ss) -{ - SANE_Option_Descriptor *sod; - option_descriptor_t *opt; - - memset(OPT_IN_CTX, 0, sizeof(OPT_IN_CTX));""" - - for o in options: - o = ccode(o) - otype = o['type'] - code = '\n opt = &(OPT_IN_CTX[%(cname_opt)s]);\n' \ - ' sod = &opt->sod;\n' \ - ' sod->type = %(code_type)s;\n' \ - ' sod->title = %(code_title)s;\n' \ - ' sod->desc = %(code_desc)s;\n' - if otype != 'SANE_TYPE_GROUP': - code += ' sod->name = %(code_name)s;\n' \ - ' sod->unit = %(code_unit)s;\n' \ - ' sod->size = %(code_size)s;\n' \ - ' sod->cap = %(code_cap)s;\n' \ - ' sod->constraint_type = %(code_constraint_type)s;\n' \ - '%(full_code_constraint)s' \ - ' OPT_IN_CTX[%(cname_opt)s].info = %(code_info)s;\n' \ - '%(full_code_default)s' - sys.stdout.write(code % o) - print - print ' return 0;\n' - print '}' - print - -g = Struct() -g.ngroups = 0 -opt_prefix = 'opt_' -con_prefix = 'constraint_' -cnameMap = createCNameMap() -options = parseFile(sys.stdin) -print "/* Automatically generated from pixma_sane.c */" -if (len(sys.argv) == 2) and (sys.argv[1] == 'h'): - genHeader(options) -else: - genConstraints(options) - genBuildOptions(options) diff --git a/backend/sharp.c b/backend/sharp.c index b2807d7..701b179 100644 --- a/backend/sharp.c +++ b/backend/sharp.c @@ -2825,6 +2825,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, case OPT_BR_Y: if (info && s->val[option].w != *(SANE_Word *) val) *info |= SANE_INFO_RELOAD_PARAMS; + // fall through case OPT_NUM_OPTS: case OPT_THRESHOLD: /* xxx theoretically, we could use OPT_THRESHOLD in diff --git a/backend/sm3600.c b/backend/sm3600.c index 6e411c3..8f8adfc 100644 --- a/backend/sm3600.c +++ b/backend/sm3600.c @@ -609,14 +609,14 @@ sane_control_option (SANE_Handle handle, SANE_Int iOpt, { case optResolution: case optTLX: case optTLY: case optBRX: case optBRY: - if (pnInfo) (*pnInfo) |= SANE_INFO_RELOAD_PARAMS; - /* fall through side effect free */ + if (pnInfo) (*pnInfo) |= SANE_INFO_RELOAD_PARAMS; + // fall through + case optPreview: + case optGrayPreview: #ifdef SM3600_SUPPORT_EXPOSURE case optBrightness: case optContrast: #endif - case optPreview: - case optGrayPreview: this->aoptVal[iOpt].w = *(SANE_Word*)pVal; break; case optMode: diff --git a/backend/snapscan-options.c b/backend/snapscan-options.c index 3ef85ae..999b312 100644 --- a/backend/snapscan-options.c +++ b/backend/snapscan-options.c @@ -927,7 +927,7 @@ static void init_options (SnapScan_Scanner * ps) po[OPT_ADVANCED_GROUP].constraint_type = SANE_CONSTRAINT_NONE; po[OPT_RGB_LPR].name = "rgb-lpr"; - po[OPT_RGB_LPR].title = SANE_I18N("Colour lines per read"); + po[OPT_RGB_LPR].title = SANE_I18N("Color lines per read"); po[OPT_RGB_LPR].desc = lpr_desc; po[OPT_RGB_LPR].type = SANE_TYPE_INT; po[OPT_RGB_LPR].unit = SANE_UNIT_NONE; @@ -939,7 +939,7 @@ static void init_options (SnapScan_Scanner * ps) ps->rgb_lpr = def_rgb_lpr; po[OPT_GS_LPR].name = "gs-lpr"; - po[OPT_GS_LPR].title = SANE_I18N("Greyscale lines per read"); + po[OPT_GS_LPR].title = SANE_I18N("Grayscale lines per read"); po[OPT_GS_LPR].desc = lpr_desc; po[OPT_GS_LPR].type = SANE_TYPE_INT; po[OPT_GS_LPR].unit = SANE_UNIT_NONE; diff --git a/backend/stv680.c b/backend/stv680.c index 8d2fda3..473def0 100644 --- a/backend/stv680.c +++ b/backend/stv680.c @@ -1189,8 +1189,8 @@ stv680_fill_image (Stv680_Vidcam * dev) } #define MSG_MAXLEN 45 -#define CHAR_HEIGHT 11 -#define CHAR_WIDTH 6 +#define TEXT_CHAR_HEIGHT 11 +#define TEXT_CHAR_WIDTH 6 #define CHAR_START 4 static SANE_Status @@ -1216,14 +1216,14 @@ stv680_add_text (SANE_Byte * image, int width, int height, char *txt) len = strftime (line, MSG_MAXLEN, fmttxt, tm); - for (y = 0; y < CHAR_HEIGHT; y++) + for (y = 0; y < TEXT_CHAR_HEIGHT; y++) { - ptr = image + 3 * width * (height - CHAR_HEIGHT - 2 + y) + 12; + ptr = image + 3 * width * (height - TEXT_CHAR_HEIGHT - 2 + y) + 12; for (x = 0; x < len; x++) { - f = fontdata[line[x] * CHAR_HEIGHT + y]; - for (i = CHAR_WIDTH - 1; i >= 0; i--) + f = fontdata[line[x] * TEXT_CHAR_HEIGHT + y]; + for (i = TEXT_CHAR_WIDTH - 1; i >= 0; i--) { if (f & (CHAR_START << i)) { diff --git a/backend/umax_pp.c b/backend/umax_pp.c index b1121ef..16adbe3 100644 --- a/backend/umax_pp.c +++ b/backend/umax_pp.c @@ -103,10 +103,6 @@ * 129 if you want to know which parameters are unused */ -/* history: - * see Changelog - */ - #define UMAX_PP_BUILD 2301 #define UMAX_PP_STATE "release" @@ -206,34 +202,28 @@ umax_pp_attach (SANEI_Config * config, const char *devname) SANE_Status status = SANE_STATUS_GOOD; int ret, prt = 0, mdl; char model[32]; - char name[64]; - char *val; - - memset (name, 0, 64); + const char *name = NULL; + const char *val; - if ((strlen (devname) < 3)) + if (!devname || (strlen (devname) < 3)) return SANE_STATUS_INVAL; sanei_umax_pp_setastra (atoi((SANE_Char *) config->values[CFG_ASTRA])); /* if the name begins with a slash, it's a device, else it's an addr */ - if (devname != NULL) + if ((devname[0] == '/')) { - if ((devname[0] == '/')) - { - strncpy (name, devname, 64); - } + name = devname; + } + else + { + if ((devname[0] == '0') + && ((devname[1] == 'x') || (devname[1] == 'X'))) + prt = strtol (devname + 2, NULL, 16); else - { - if ((devname[0] == '0') - && ((devname[1] == 'x') || (devname[1] == 'X'))) - prt = strtol (devname + 2, NULL, 16); - else - prt = atoi (devname); - } + prt = atoi (devname); } - for (i = 0; i < num_devices; i++) { if (devname[0] == '/') @@ -295,7 +285,7 @@ umax_pp_attach (SANEI_Config * config, const char *devname) devname); return SANE_STATUS_IO_ERROR; } - sprintf (model, "Astra %dP", mdl); + snprintf (model, sizeof(model), "Astra %dP", mdl); dev = malloc (sizeof (Umax_PP_Descriptor) * (num_devices + 1)); @@ -319,12 +309,12 @@ umax_pp_attach (SANEI_Config * config, const char *devname) num_devices++; /* if there are user provided values, use them */ - val=(SANE_Char *) config->values[CFG_NAME]; + val=(const SANE_Char *) config->values[CFG_NAME]; if(strlen(val)==0) dev->sane.name = strdup (devname); else dev->sane.name = strdup (val); - val=(SANE_Char *) config->values[CFG_VENDOR]; + val=(const SANE_Char *) config->values[CFG_VENDOR]; if(strlen(val)==0) dev->sane.vendor = strdup ("UMAX"); else @@ -351,11 +341,11 @@ umax_pp_attach (SANEI_Config * config, const char *devname) dev->max_h_size = 2550; dev->max_v_size = 3500; } - val=(SANE_Char *) config->values[CFG_MODEL]; + val=(const SANE_Char *) config->values[CFG_MODEL]; if(strlen(val)==0) - dev->sane.model = strdup (model); + dev->sane.model = strdup (model); else - dev->sane.model = strdup (val); + dev->sane.model = strdup (val); DBG (3, "umax_pp_attach: device %s attached\n", devname); @@ -1462,6 +1452,7 @@ sane_control_option (SANE_Handle handle, SANE_Int option, if (info) *info |= SANE_INFO_RELOAD_PARAMS; + // fall through case OPT_GRAY_GAIN: case OPT_GREEN_GAIN: case OPT_RED_GAIN: diff --git a/backend/umax_pp_low.c b/backend/umax_pp_low.c index c5d9a93..ddcf3da 100644 --- a/backend/umax_pp_low.c +++ b/backend/umax_pp_low.c @@ -924,7 +924,7 @@ sanei_parport_find_device (void) int -sanei_umax_pp_initPort (int port, char *name) +sanei_umax_pp_initPort (int port, const char *name) { #ifndef IO_SUPPORT_MISSING # ifdef HAVE_LINUX_PPDEV_H @@ -1027,26 +1027,20 @@ sanei_umax_pp_initPort (int port, char *name) } else { - sprintf (strmodes, "\n"); - if (modes & PARPORT_MODE_PCSPP) - sprintf (strmodes, "%s\t\tPARPORT_MODE_PCSPP\n", - strmodes); - if (modes & PARPORT_MODE_TRISTATE) - sprintf (strmodes, "%s\t\tPARPORT_MODE_TRISTATE\n", - strmodes); - if (modes & PARPORT_MODE_EPP) - sprintf (strmodes, "%s\t\tPARPORT_MODE_EPP\n", strmodes); + snprintf(strmodes, sizeof(strmodes), + "\n%s%s%s%s%s%s", + (modes & PARPORT_MODE_PCSPP)? "\t\tPARPORT_MODE_PCSPP\n": "", + (modes & PARPORT_MODE_TRISTATE)? "\t\tPARPORT_MODE_TRISTATE\n": "", + (modes & PARPORT_MODE_EPP)? "\t\tPARPORT_MODE_EPP\n": "", + (modes & PARPORT_MODE_ECP)? "\t\tPARPORT_MODE_ECP\n": "", + (modes & PARPORT_MODE_COMPAT)? "\t\tPARPORT_MODE_COMPAT\n": "", + (modes & PARPORT_MODE_DMA)? "\t\tPARPORT_MODE_DMA\n": ""); + if (modes & PARPORT_MODE_ECP) { - sprintf (strmodes, "%s\t\tPARPORT_MODE_ECP\n", - strmodes); gECP = 1; } - if (modes & PARPORT_MODE_COMPAT) - sprintf (strmodes, "%s\t\tPARPORT_MODE_COMPAT\n", - strmodes); - if (modes & PARPORT_MODE_DMA) - sprintf (strmodes, "%s\t\tPARPORT_MODE_DMA\n", strmodes); + DBG (32, "parport modes: %X\n", modes); DBG (32, "parport modes: %s\n", strmodes); if (!(modes & PARPORT_MODE_EPP) @@ -10239,7 +10233,7 @@ moveToOrigin (void) end[0] = 0x19; end[1] = 0xD5; end[4] = 0x1B; - + // fall through case 1220: case 2000: w = 300; @@ -11226,6 +11220,7 @@ sanei_umax_pp_startScan (int x, int y, int width, int height, int dpi, } else y += 80; + // fall through default: y += 8; break; diff --git a/backend/umax_pp_low.h b/backend/umax_pp_low.h index 5e986c0..253ef6a 100644 --- a/backend/umax_pp_low.h +++ b/backend/umax_pp_low.h @@ -46,7 +46,7 @@ /*****************************************************************************/ /* set port to 'idle state' and get iopl */ /*****************************************************************************/ -extern int sanei_umax_pp_initPort (int port, char *name); +extern int sanei_umax_pp_initPort (int port, const char *name); extern int sanei_umax_pp_initScanner (int recover); extern int sanei_umax_pp_initTransport (int recover); extern int sanei_umax_pp_endSession (void); diff --git a/backend/umax_pp_mid.c b/backend/umax_pp_mid.c index 5f9fd5e..4b16745 100644 --- a/backend/umax_pp_mid.c +++ b/backend/umax_pp_mid.c @@ -199,7 +199,7 @@ sanei_umax_pp_model (int port, int *model) } int -sanei_umax_pp_attach (int port, char *name) +sanei_umax_pp_attach (int port, const char *name) { int recover = 0; diff --git a/backend/umax_pp_mid.h b/backend/umax_pp_mid.h index 5903a45..97d1366 100644 --- a/backend/umax_pp_mid.h +++ b/backend/umax_pp_mid.h @@ -74,7 +74,7 @@ */ -extern int sanei_umax_pp_attach (int port, char *name); +extern int sanei_umax_pp_attach (int port, const char *name); /* recognizes 1220P from 2000P diff --git a/backend/xerox_mfp.c b/backend/xerox_mfp.c index b7fcbee..f5fd70e 100644 --- a/backend/xerox_mfp.c +++ b/backend/xerox_mfp.c @@ -95,6 +95,9 @@ static char *str_cmd(int cmd) #define MAX_DUMP 70 const char *encTmpFileName = "/tmp/stmp_enc.tmp"; +/* + * Decode jpeg from `infilename` into dev->decData of dev->decDataSize size. + */ static int decompress(struct device __sane_unused__ *dev, const char __sane_unused__ *infilename) { @@ -131,6 +134,7 @@ static int decompress(struct device __sane_unused__ *dev, height = cinfo.output_height; pixel_size = cinfo.output_components; bmp_size = width * height * pixel_size; + assert(bmp_size <= POST_DATASIZE); dev->decDataSize = bmp_size; row_stride = width * pixel_size; @@ -152,32 +156,30 @@ static int decompress(struct device __sane_unused__ *dev, #endif } +/* copy from decoded jpeg image (dev->decData) into user's buffer (pDest) */ +/* returns 0 if there is no data to copy */ static int copy_decompress_data(struct device *dev, unsigned char *pDest, int maxlen, int *destLen) { int data_size = 0; - size_t result = 0, retVal = 0; - - if (0 == dev->decDataSize) { - *destLen = 0; - return retVal; - } + if (destLen) + *destLen = 0; + if (!dev->decDataSize) + return 0; data_size = dev->decDataSize - dev->currentDecDataIndex; - if (data_size > maxlen) { + if (data_size > maxlen) data_size = maxlen; + if (data_size && pDest) { + memcpy(pDest, dev->decData + dev->currentDecDataIndex, data_size); + if (destLen) + *destLen = data_size; + dev->currentDecDataIndex += data_size; } - memcpy(pDest, dev->decData+dev->currentDecDataIndex, data_size); - result = data_size; - *destLen = result; - dev->currentDecDataIndex += result; - retVal = result; - if (dev->decDataSize == dev->currentDecDataIndex) { dev->currentDecDataIndex = 0; dev->decDataSize = 0; } - - return retVal; + return 1; } static int decompress_tempfile(struct device *dev) @@ -209,6 +211,8 @@ static int isSupportedDevice(struct device __sane_unused__ *dev) if (dev->compressionTypes & (1 << 6)) { /* blacklist malfunctioning device(s) */ if (!strncmp(dev->sane.model, "SCX-4500W", 9) || + !strncmp(dev->sane.model, "C460", 4) || + !!strstr(dev->sane.model, "CLX-3170") || !strncmp(dev->sane.model, "M288x", 5)) return 0; return 1; @@ -1293,9 +1297,10 @@ sane_read(SANE_Handle h, SANE_Byte *buf, SANE_Int maxlen, SANE_Int *lenp) dev->decDataSize > 0) { int diff = dev->total_img_size - dev->total_out_size; int bufLen = (diff < maxlen) ? diff : maxlen; - if (0 < diff && - 0 < copy_decompress_data(dev, buf, bufLen, lenp)) { - dev->total_out_size += *lenp; + if (diff && + copy_decompress_data(dev, buf, bufLen, lenp)) { + if (lenp) + dev->total_out_size += *lenp; return SANE_STATUS_GOOD; } } @@ -1459,6 +1464,7 @@ sane_start(SANE_Handle h) if (!dev->data && !(dev->data = malloc(DATASIZE))) return ret_cancel(dev, SANE_STATUS_NO_MEM); + /* this is for jpeg mode only */ if (!dev->decData && !(dev->decData = malloc(POST_DATASIZE))) return ret_cancel(dev, SANE_STATUS_NO_MEM); diff --git a/backend/xerox_mfp.h b/backend/xerox_mfp.h index 3d93f06..d85fe14 100644 --- a/backend/xerox_mfp.h +++ b/backend/xerox_mfp.h @@ -74,8 +74,8 @@ struct device { #define DATATAIL(dev) ((dev->dataoff + dev->datalen) & DATAMASK) #define DATAROOM(dev) dataroom(dev) -#define POST_DATASIZE 0xFFFFFF - SANE_Byte *decData; +#define POST_DATASIZE 0xFFFFFF /* 16777215 bytes */ + SANE_Byte *decData; /* static buffer of POST_DATASIZE bytes */ int decDataSize; int currentDecDataIndex; /* data from CMD_INQUIRY: */ -- cgit v1.2.3